on master help sign in
benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs+7−8
since splitsnapshots
unifiedsplit
@@ -33,7 +33,6 @@ import qualified Streamly.Data.Stream as Stream
33import qualified Streamly.Data.Fold as Fold
33import qualified Streamly.Data.Fold as Fold
34import qualified Streamly.FileSystem.Handle as FH
34import qualified Streamly.FileSystem.Handle as FH
35import qualified Streamly.Internal.Data.Array as A
35import qualified Streamly.Internal.Data.Array as A
36−import qualified Streamly.Internal.Data.Array as AT
37import qualified Streamly.Internal.Data.Fold as FL
36import qualified Streamly.Internal.Data.Fold as FL
38import qualified Streamly.Internal.Data.Stream as IP
37import qualified Streamly.Internal.Data.Stream as IP
39import qualified Streamly.Internal.FileSystem.Handle as IFH
38import qualified Streamly.Internal.FileSystem.Handle as IFH
@@ -48,7 +47,7 @@ import Streamly.Benchmark.Common.Handle
48#ifdef INSPECTION
47#ifdef INSPECTION
49import Streamly.Internal.Data.Stream (Step(..), FoldMany)
48import Streamly.Internal.Data.Stream (Step(..), FoldMany)
50
49
51−import qualified Streamly.Internal.Data.MutArray as MA
50+import qualified Streamly.Internal.Data.MutArray as MutArray
52import qualified Streamly.Internal.Data.Stream as D
51import qualified Streamly.Internal.Data.Stream as D
53import qualified Streamly.Internal.Data.Unfold as IUF
52import qualified Streamly.Internal.Data.Unfold as IUF
54
53
@@ -69,7 +68,7 @@ readLast = S.fold Fold.last . S.unfold FH.reader
69inspect $ hasNoTypeClasses 'readLast
68inspect $ hasNoTypeClasses 'readLast
70inspect $ 'readLast `hasNoType` ''Step -- S.unfold
69inspect $ 'readLast `hasNoType` ''Step -- S.unfold
71inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
70inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
72−inspect $ 'readLast `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
71+inspect $ 'readLast `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
73#endif
72#endif
74
73
75-- assert that flattenArrays constructors are not present
74-- assert that flattenArrays constructors are not present
@@ -81,7 +80,7 @@ readCountBytes = S.fold Fold.length . S.unfold FH.reader
81inspect $ hasNoTypeClasses 'readCountBytes
80inspect $ hasNoTypeClasses 'readCountBytes
82inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
81inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
83inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
82inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
84−inspect $ 'readCountBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
83+inspect $ 'readCountBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
85#endif
84#endif
86
85
87-- | Count the number of lines in a file.
86-- | Count the number of lines in a file.
@@ -96,7 +95,7 @@ readCountLines =
96inspect $ hasNoTypeClasses 'readCountLines
95inspect $ hasNoTypeClasses 'readCountLines
97inspect $ 'readCountLines `hasNoType` ''Step
96inspect $ 'readCountLines `hasNoType` ''Step
98inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
97inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
99−inspect $ 'readCountLines `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
98+inspect $ 'readCountLines `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
100#endif
99#endif
101
100
102-- | Count the number of words in a file.
101-- | Count the number of words in a file.
@@ -120,7 +119,7 @@ readSumBytes = S.fold Fold.sum . S.unfold FH.reader
120inspect $ hasNoTypeClasses 'readSumBytes
119inspect $ hasNoTypeClasses 'readSumBytes
121inspect $ 'readSumBytes `hasNoType` ''Step
120inspect $ 'readSumBytes `hasNoType` ''Step
122inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
121inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
123−inspect $ 'readSumBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
122+inspect $ 'readSumBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
124#endif
123#endif
125
124
126-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
125-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
@@ -236,13 +235,13 @@ groupsOf :: Int -> Handle -> IO Int
236groupsOf n inh =
235groupsOf n inh =
237 -- writeNUnsafe gives 2.5x boost here over writeN.
236 -- writeNUnsafe gives 2.5x boost here over writeN.
238 S.fold Fold.length
237 S.fold Fold.length
239− $ IP.groupsOf n (AT.writeNUnsafe n) (S.unfold FH.reader inh)
238+ $ IP.groupsOf n (A.writeNUnsafe n) (S.unfold FH.reader inh)
240
239
241#ifdef INSPECTION
240#ifdef INSPECTION
242inspect $ hasNoTypeClasses 'groupsOf
241inspect $ hasNoTypeClasses 'groupsOf
243inspect $ 'groupsOf `hasNoType` ''Step
242inspect $ 'groupsOf `hasNoType` ''Step
244inspect $ 'groupsOf `hasNoType` ''FoldMany
243inspect $ 'groupsOf `hasNoType` ''FoldMany
245−inspect $ 'groupsOf `hasNoType` ''AT.ArrayUnsafe -- AT.writeNUnsafe
244+inspect $ 'groupsOf `hasNoType` ''MutArray.ArrayUnsafe -- AT.writeNUnsafe
246 -- FH.read/A.read
245 -- FH.read/A.read
247inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
246inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
248#endif
247#endif
benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs+8−9
@@ -42,8 +42,7 @@ import Streamly.Internal.Data.Stream (Step(..))
42
42
43import qualified Streamly.Internal.Data.Stream as D
43import qualified Streamly.Internal.Data.Stream as D
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
45−import qualified Streamly.Internal.Data.MutArray.Stream as MAS
45+import qualified Streamly.Internal.Data.MutArray as MutArray
46−import qualified Streamly.Internal.Data.Array as AT
47
46
48import Test.Inspection
47import Test.Inspection
49#endif
48#endif
@@ -83,7 +82,7 @@ copyStream inh outh = S.fold (FH.write outh) (S.unfold FH.reader inh)
83inspect $ hasNoTypeClasses 'copyStream
82inspect $ hasNoTypeClasses 'copyStream
84inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
83inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
85inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
84inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
86−inspect $ 'copyStream `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
85+inspect $ 'copyStream `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
87 -- FH.read/A.read
86 -- FH.read/A.read
88inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
87inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
89#endif
88#endif
@@ -109,8 +108,8 @@ readFromBytesNull inh devNull = IFH.putBytes devNull $ S.unfold FH.reader inh
109#ifdef INSPECTION
108#ifdef INSPECTION
110inspect $ hasNoTypeClasses 'readFromBytesNull
109inspect $ hasNoTypeClasses 'readFromBytesNull
111inspect $ 'readFromBytesNull `hasNoType` ''Step
110inspect $ 'readFromBytesNull `hasNoType` ''Step
112−inspect $ 'readFromBytesNull `hasNoType` ''MAS.SpliceState
111+inspect $ 'readFromBytesNull `hasNoType` ''MutArray.SpliceState
113−inspect $ 'readFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
112+inspect $ 'readFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
114inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
113inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
115#endif
114#endif
116
115
@@ -123,8 +122,8 @@ readWithFromBytesNull inh devNull =
123#ifdef INSPECTION
122#ifdef INSPECTION
124inspect $ hasNoTypeClasses 'readWithFromBytesNull
123inspect $ hasNoTypeClasses 'readWithFromBytesNull
125inspect $ 'readWithFromBytesNull `hasNoType` ''Step
124inspect $ 'readWithFromBytesNull `hasNoType` ''Step
126−inspect $ 'readWithFromBytesNull `hasNoType` ''MAS.SpliceState
125+inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.SpliceState
127−inspect $ 'readWithFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
126+inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
128inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
127inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
129#endif
128#endif
130
129
@@ -171,7 +170,7 @@ writeReadWith inh devNull = IUF.fold fld unf (defaultChunkSize, inh)
171inspect $ hasNoTypeClasses 'writeReadWith
170inspect $ hasNoTypeClasses 'writeReadWith
172inspect $ 'writeReadWith `hasNoType` ''Step
171inspect $ 'writeReadWith `hasNoType` ''Step
173inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
172inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
174−inspect $ 'writeReadWith `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
173+inspect $ 'writeReadWith `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
175 -- FH.read/A.read
174 -- FH.read/A.read
176#endif
175#endif
177
176
@@ -188,7 +187,7 @@ writeRead inh devNull = IUF.fold fld unf inh
188inspect $ hasNoTypeClasses 'writeRead
187inspect $ hasNoTypeClasses 'writeRead
189inspect $ 'writeRead `hasNoType` ''Step
188inspect $ 'writeRead `hasNoType` ''Step
190inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
189inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
191−inspect $ 'writeRead `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
190+inspect $ 'writeRead `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
192 -- FH.read/A.read
191 -- FH.read/A.read
193#endif
192#endif
194
193
benchmark/Streamly/Benchmark/Unicode/Stream.hs+4−3
@@ -45,9 +45,10 @@ import Streamly.Benchmark.Common.Handle
45#ifdef INSPECTION
45#ifdef INSPECTION
46import Streamly.Internal.Data.MutByteArray (Unbox)
46import Streamly.Internal.Data.MutByteArray (Unbox)
47import Streamly.Internal.Data.Stream (Step(..))
47import Streamly.Internal.Data.Stream (Step(..))
48+import qualified Streamly.Internal.Data.Array as Array
49+import qualified Streamly.Internal.Data.MutArray as MutArray
48import qualified Streamly.Internal.Data.Fold as Fold
50import qualified Streamly.Internal.Data.Fold as Fold
49import qualified Streamly.Internal.Data.Tuple.Strict as Strict
51import qualified Streamly.Internal.Data.Tuple.Strict as Strict
50−import qualified Streamly.Internal.Data.Array as Array
51
52
52import Test.Inspection
53import Test.Inspection
53#endif
54#endif
@@ -223,7 +224,7 @@ inspect $ 'copyStreamLatin1' `hasNoType` ''Step
223inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
224inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
224
225
225inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
226inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
226−inspect $ 'copyStreamLatin1' `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
227+inspect $ 'copyStreamLatin1' `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
227 -- Handle.read/Array.read
228 -- Handle.read/Array.read
228inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
229inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
229#endif
230#endif
@@ -244,7 +245,7 @@ inspect $ 'copyStreamLatin1 `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.m
244
245
245inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
246inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
246inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
247inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
247−inspect $ 'copyStreamLatin1 `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
248+inspect $ 'copyStreamLatin1 `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
248 -- Handle.read/Array.read
249 -- Handle.read/Array.read
249inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
250inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
250#endif
251#endif
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 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+3−1
@@ -1,10 +1,12 @@
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
7 differently sized constructors.
7 differently sized constructors.
8+* lpackArraysChunksOf, compact, writeChunksWith, putChunksWith now take the
9+ buffer size in number of array elements instead of bytes.
8
10
9## 0.2.1 (Dec 2023)
11## 0.2.1 (Dec 2023)
10
12
core/src/DocTestDataArray.hs+3
@@ -11,9 +11,12 @@
11
11
12>>> import qualified Streamly.Data.Array as Array
12>>> import qualified Streamly.Data.Array as Array
13>>> import qualified Streamly.Data.Fold as Fold
13>>> import qualified Streamly.Data.Fold as Fold
14+>>> import qualified Streamly.Data.ParserK as ParserK
14>>> import qualified Streamly.Data.Stream as Stream
15>>> import qualified Streamly.Data.Stream as Stream
16+>>> import qualified Streamly.Data.StreamK as StreamK
15
17
16For APIs that have not been released yet.
18For APIs that have not been released yet.
17
19
18>>> import qualified Streamly.Internal.Data.Array as Array
20>>> import qualified Streamly.Internal.Data.Array as Array
21+>>> import qualified Streamly.Internal.Data.Stream as Stream
19-}
22-}
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+530−91
@@ -2,7 +2,6 @@
2-- |
2-- |
3-- Module : Streamly.Internal.Data.Array
3-- Module : Streamly.Internal.Data.Array
4-- Copyright : (c) 2019 Composewell Technologies
4-- Copyright : (c) 2019 Composewell Technologies
5−--
6-- License : BSD3
5-- License : BSD3
7-- Maintainer : streamly@composewell.com
6-- Maintainer : streamly@composewell.com
8-- Stability : experimental
7-- Stability : experimental
@@ -23,30 +22,27 @@ module Streamly.Internal.Data.Array
23 -- Monadic Folds
22 -- Monadic Folds
24 , writeLastN
23 , writeLastN
25
24
26− -- * Unfolds
27− , reader
28− , readerUnsafe
29− , producer -- experimental
30−
31 -- * Random Access
25 -- * Random Access
32 -- , (!!)
26 -- , (!!)
33 , getIndex
27 , getIndex
34 , getIndexRev
28 , getIndexRev
35− , last -- XXX getIndexLast?
29+ , last -- XXX getLastIndex?
36− , getIndices
37− , getIndicesFromThenTo
38 -- , getIndicesFrom -- read from a given position to the end of file
30 -- , getIndicesFrom -- read from a given position to the end of file
39 -- , getIndicesUpto -- read from beginning up to the given position
31 -- , getIndicesUpto -- read from beginning up to the given position
40 -- , getIndicesFromTo
32 -- , getIndicesFromTo
41 -- , getIndicesFromRev -- read from a given position to the beginning of file
33 -- , getIndicesFromRev -- read from a given position to the beginning of file
42 -- , getIndicesUptoRev -- read from end to the given position in file
34 -- , getIndicesUptoRev -- read from end to the given position in file
35+ , indexReader
36+ , indexReaderFromThenTo
43
37
44 -- * Size
38 -- * Size
45 , null
39 , null
46
40
47 -- * Search
41 -- * Search
48 , binarySearch
42 , binarySearch
49− , findIndicesOf -- see splitOn, rename to indicesOf
43+ , findIndicesOf
44+ -- getIndicesOf
45+ , indexFinder -- see splitOn
50 -- , findIndexOf
46 -- , findIndexOf
51 -- , find
47 -- , find
52
48
@@ -70,6 +66,24 @@ module Streamly.Internal.Data.Array
70 , streamFold
66 , streamFold
71 , fold
67 , fold
72
68
69+ -- * Stream of Arrays
70+
71+ -- XXX these are probably not very useful to have in this module as we can
72+ -- express these idiomatically using streams.
73+ , interpose
74+ , interposeSuffix
75+ , intercalateSuffix
76+
77+ , compactLE
78+ , pinnedCompactLE
79+ , compactOnByte
80+ , compactOnByteSuffix
81+
82+ , foldBreakChunks
83+ , foldChunks
84+ , foldBreakChunksK
85+ , parseBreakChunksK
86+
73 -- * Serialization
87 -- * Serialization
74 , encodeAs
88 , encodeAs
75 , serialize
89 , serialize
@@ -79,6 +93,7 @@ module Streamly.Internal.Data.Array
79 -- * Deprecated
93 -- * Deprecated
80 , genSlicesFromLen
94 , genSlicesFromLen
81 , getSlicesFromLen
95 , getSlicesFromLen
96+ , getIndices
82 )
97 )
83where
98where
84
99
@@ -87,35 +102,42 @@ where
87#include "ArrayMacros.h"
102#include "ArrayMacros.h"
88
103
89import Control.Monad.IO.Class (MonadIO(..))
104import Control.Monad.IO.Class (MonadIO(..))
105+-- import Data.Bifunctor (first)
106+-- import Data.Either (fromRight)
90import Data.Functor.Identity (Identity)
107import Data.Functor.Identity (Identity)
91import Data.Proxy (Proxy(..))
108import Data.Proxy (Proxy(..))
92import Data.Word (Word8)
109import Data.Word (Word8)
93import Foreign.C.String (CString)
110import Foreign.C.String (CString)
94import Foreign.Ptr (castPtr)
111import Foreign.Ptr (castPtr)
95import Foreign.Storable (Storable)
112import Foreign.Storable (Storable)
113+import GHC.Types (SPEC(..))
96import Streamly.Internal.Data.Unbox (Unbox(..))
114import Streamly.Internal.Data.Unbox (Unbox(..))
97import Prelude hiding (length, null, last, map, (!!), read, concat)
115import Prelude hiding (length, null, last, map, (!!), read, concat)
98
116
99−import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
117+import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..), MutByteArray)
100import Streamly.Internal.Data.Serialize.Type (Serialize)
118import Streamly.Internal.Data.Serialize.Type (Serialize)
101import Streamly.Internal.Data.Fold.Type (Fold(..))
119import Streamly.Internal.Data.Fold.Type (Fold(..))
102−import Streamly.Internal.Data.Producer.Type (Producer(..))
120+import Streamly.Internal.Data.Parser (Parser(..), Initial(..), ParseError(..))
103−import Streamly.Internal.Data.Stream (Stream)
121+import Streamly.Internal.Data.Stream (Stream(..))
122+import Streamly.Internal.Data.StreamK (StreamK)
123+import Streamly.Internal.Data.SVar.Type (adaptState, defState)
104−import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
124+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3Fused'(..))
105import Streamly.Internal.Data.Unfold.Type (Unfold(..))
125import Streamly.Internal.Data.Unfold.Type (Unfold(..))
106import Streamly.Internal.System.IO (unsafeInlineIO)
126import Streamly.Internal.System.IO (unsafeInlineIO)
107
127
128+import qualified Streamly.Internal.Data.Fold.Type as Fold
108import qualified Streamly.Internal.Data.Serialize.Type as Serialize
129import qualified Streamly.Internal.Data.Serialize.Type as Serialize
109import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
130import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
110import qualified Streamly.Internal.Data.MutArray as MA
131import qualified Streamly.Internal.Data.MutArray as MA
111−import qualified Streamly.Internal.Data.Array.Type as A
112import qualified Streamly.Internal.Data.Fold as FL
132import qualified Streamly.Internal.Data.Fold as FL
113−import qualified Streamly.Internal.Data.Producer.Type as Producer
114−import qualified Streamly.Internal.Data.Producer as Producer
115import qualified Streamly.Internal.Data.Ring as RB
133import qualified Streamly.Internal.Data.Ring as RB
134+import qualified Streamly.Internal.Data.Parser as Parser
135+-- import qualified Streamly.Internal.Data.ParserK as ParserK
116import qualified Streamly.Internal.Data.Stream as D
136import qualified Streamly.Internal.Data.Stream as D
117import qualified Streamly.Internal.Data.Stream as Stream
137import qualified Streamly.Internal.Data.Stream as Stream
138+import qualified Streamly.Internal.Data.StreamK as StreamK
118import qualified Streamly.Internal.Data.Unfold as Unfold
139import qualified Streamly.Internal.Data.Unfold as Unfold
140+import qualified Prelude
119
141
120import Streamly.Internal.Data.Array.Type
142import Streamly.Internal.Data.Array.Type
121
143
@@ -148,49 +170,6 @@ import Streamly.Internal.Data.Array.Type
148-- Elimination
170-- Elimination
149-------------------------------------------------------------------------------
171-------------------------------------------------------------------------------
150
172
151−{-# INLINE_NORMAL producer #-}
152−producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
153−producer =
154− Producer.translate A.unsafeThaw A.unsafeFreeze
155− $ MA.producerWith (return . unsafeInlineIO)
156−
157−-- | Unfold an array into a stream.
158−--
159−{-# INLINE_NORMAL reader #-}
160−reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
161−reader = Producer.simplify producer
162−
163−-- | Unfold an array into a stream, does not check the end of the array, the
164−-- user is responsible for terminating the stream within the array bounds. For
165−-- high performance application where the end condition can be determined by
166−-- a terminating fold.
167−--
168−-- Written in the hope that it may be faster than "read", however, in the case
169−-- for which this was written, "read" proves to be faster even though the core
170−-- generated with unsafeRead looks simpler.
171−--
172−-- /Pre-release/
173−--
174−{-# INLINE_NORMAL readerUnsafe #-}
175−readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
176−readerUnsafe = Unfold step inject
177− where
178−
179− inject (Array contents start end) =
180− return (ArrayUnsafe contents end start)
181−
182− {-# INLINE_LATE step #-}
183− step (ArrayUnsafe contents end p) = do
184− -- unsafeInlineIO allows us to run this in Identity monad for pure
185− -- toList/foldr case which makes them much faster due to not
186− -- accumulating the list and fusing better with the pure consumers.
187− --
188− -- This should be safe as the array contents are guaranteed to be
189− -- evaluated/written to before we peek at them.
190− let !x = unsafeInlineIO $ peekAt p contents
191− let !p1 = INDEX_NEXT(p,a)
192− return $ D.Yield x (ArrayUnsafe contents end p1)
193−
194-- |
173-- |
195--
174--
196-- >>> null arr = Array.byteLength arr == 0
175-- >>> null arr = Array.byteLength arr == 0
@@ -198,7 +177,7 @@ readerUnsafe = Unfold step inject
198-- /Pre-release/
177-- /Pre-release/
199{-# INLINE null #-}
178{-# INLINE null #-}
200null :: Array a -> Bool
179null :: Array a -> Bool
201−null arr = A.byteLength arr == 0
180+null arr = byteLength arr == 0
202
181
203-- | Like 'getIndex' but indexes the array in reverse from the end.
182-- | Like 'getIndex' but indexes the array in reverse from the end.
204--
183--
@@ -226,6 +205,8 @@ last = getIndexRev 0
226-- Folds with Array as the container
205-- Folds with Array as the container
227-------------------------------------------------------------------------------
206-------------------------------------------------------------------------------
228
207
208+-- XXX We should generate this from Ring.
209+
229-- | @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
230-- stream to an 'Array'.
211-- stream to an 'Array'.
231--
212--
@@ -234,7 +215,7 @@ writeLastN ::
234 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
215 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
235writeLastN n
216writeLastN n
236 | n <= 0 = fmap (const mempty) FL.drain
217 | n <= 0 = fmap (const mempty) FL.drain
237− | otherwise = A.unsafeFreeze <$> Fold step initial done done
218+ | otherwise = unsafeFreeze <$> Fold step initial done done
238
219
239 where
220 where
240
221
@@ -247,11 +228,9 @@ writeLastN n
247 in fmap f $ liftIO $ RB.new n
228 in fmap f $ liftIO $ RB.new n
248
229
249 done (Tuple3Fused' rb rh i) = do
230 done (Tuple3Fused' rb rh i) = do
250− arr <- liftIO $ MA.new n
231+ arr <- MA.new n
251− foldFunc i rh snoc' arr rb
252−
253− -- XXX We should write a read unfold for ring.
232+ -- XXX We should write a read unfold for ring.
254− snoc' b a = liftIO $ MA.snocUnsafe b a
233+ foldFunc i rh MA.snocUnsafe arr rb
255
234
256 foldFunc i
235 foldFunc i
257 | i < n = RB.unsafeFoldRingM
236 | i < n = RB.unsafeFoldRingM
@@ -277,19 +256,26 @@ binarySearch = undefined
277-- compared to streams by using SIMD instructions.
256-- compared to streams by using SIMD instructions.
278-- We can also return a bit array instead.
257-- We can also return a bit array instead.
279
258
259+-- Can use SIMD.
260+
280-- | Perform a linear search to find all the indices where a given element is
261-- | Perform a linear search to find all the indices where a given element is
281-- present in an array.
262-- present in an array.
282--
263--
283-- /Unimplemented/
264-- /Unimplemented/
284−findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
265+indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
285−findIndicesOf = undefined
266+indexFinder = undefined
267+
268+-- |
269+-- /Unimplemented/
270+findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
271+findIndicesOf p = Stream.unfold (indexFinder p)
286
272
287{-
273{-
288findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
274findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
289−findIndexOf p = Unfold.fold Fold.one . Stream.unfold (findIndicesOf p)
275+findIndexOf p = Unfold.fold Fold.one . Stream.unfold (indexFinder p)
290
276
291find :: (a -> Bool) -> Array a -> Bool
277find :: (a -> Bool) -> Array a -> Bool
292−find = Unfold.fold Fold.null . Stream.unfold (findIndicesOf p)
278+find = Unfold.fold Fold.null . Stream.unfold (indexFinder p)
293-}
279-}
294
280
295-------------------------------------------------------------------------------
281-------------------------------------------------------------------------------
@@ -331,7 +317,7 @@ splitOn :: (Monad m, Unbox a) =>
331 (a -> Bool) -> Array a -> Stream m (Array a)
317 (a -> Bool) -> Array a -> Stream m (Array a)
332splitOn predicate arr =
318splitOn predicate arr =
333 fmap (\(i, len) -> getSliceUnsafe i len arr)
319 fmap (\(i, len) -> getSliceUnsafe i len arr)
334− $ D.indexOnSuffix predicate (A.read arr)
320+ $ D.indexOnSuffix predicate (read arr)
335
321
336{-# INLINE sliceIndexerFromLen #-}
322{-# INLINE sliceIndexerFromLen #-}
337sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
323sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
@@ -339,9 +325,10 @@ sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
339 -> Int -- ^ length of the slice
325 -> Int -- ^ length of the slice
340 -> Unfold m (Array a) (Int, Int)
326 -> Unfold m (Array a) (Int, Int)
341sliceIndexerFromLen from len =
327sliceIndexerFromLen from len =
342− Unfold.lmap A.unsafeThaw (MA.sliceIndexerFromLen from len)
328+ Unfold.lmap unsafeThaw (MA.sliceIndexerFromLen from len)
343
329
344{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
330{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
331+{-# INLINE genSlicesFromLen #-}
345genSlicesFromLen :: forall m a. (Monad m, Unbox a)
332genSlicesFromLen :: forall m a. (Monad m, Unbox a)
346 => Int -- ^ from index
333 => Int -- ^ from index
347 -> Int -- ^ length of the slice
334 -> Int -- ^ length of the slice
@@ -359,10 +346,11 @@ slicerFromLen :: forall m a. (Monad m, Unbox a)
359 -> Int -- ^ length of the slice
346 -> Int -- ^ length of the slice
360 -> Unfold m (Array a) (Array a)
347 -> Unfold m (Array a) (Array a)
361slicerFromLen from len =
348slicerFromLen from len =
362− fmap A.unsafeFreeze
349+ fmap unsafeFreeze
363− $ Unfold.lmap A.unsafeThaw (MA.slicerFromLen from len)
350+ $ Unfold.lmap unsafeThaw (MA.slicerFromLen from len)
364
351
365{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
352{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
353+{-# INLINE getSlicesFromLen #-}
366getSlicesFromLen :: forall m a. (Monad m, Unbox a)
354getSlicesFromLen :: forall m a. (Monad m, Unbox a)
367 => Int -- ^ from index
355 => Int -- ^ from index
368 -> Int -- ^ length of the slice
356 -> Int -- ^ length of the slice
@@ -397,19 +385,25 @@ getIndex i arr =
397-- @
385-- @
398-- read =
386-- read =
399-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
387-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
400−-- in Unfold.lmap f (getIndices arr)
388+-- in Unfold.lmap f (indexReader arr)
401--
389--
402-- readRev =
390-- readRev =
403-- let i = length arr - 1
391-- let i = length arr - 1
404−-- in Unfold.lmap f (getIndicesFromThenTo i (i - 1) 0)
392+-- in Unfold.lmap f (indexReaderFromThenTo i (i - 1) 0)
405-- @
393-- @
406--
394--
407-- /Pre-release/
395-- /Pre-release/
396+{-# INLINE indexReader #-}
397+indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
398+indexReader m =
399+ let unf = MA.indexReaderWith (return . unsafeInlineIO) m
400+ in Unfold.lmap unsafeThaw unf
401+
402+-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
403+{-# DEPRECATED getIndices "Please use getIndices instead." #-}
408{-# INLINE getIndices #-}
404{-# INLINE getIndices #-}
409getIndices :: (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
410−getIndices m =
406+getIndices = indexReader
411− let unf = MA.getIndicesWith (return . unsafeInlineIO) m
412− in Unfold.lmap A.unsafeThaw unf
413
407
414-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
408-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
415-- element is the array value from the index @from@ and the successive elements
409-- element is the array value from the index @from@ and the successive elements
@@ -425,9 +419,9 @@ getIndices m =
425-- @
419-- @
426--
420--
427-- /Unimplemented/
421-- /Unimplemented/
428−{-# INLINE getIndicesFromThenTo #-}
422+{-# INLINE indexReaderFromThenTo #-}
429−getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
423+indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
430−getIndicesFromThenTo = undefined
424+indexReaderFromThenTo = undefined
431
425
432-------------------------------------------------------------------------------
426-------------------------------------------------------------------------------
433-- Transform via stream operations
427-- Transform via stream operations
@@ -444,7 +438,7 @@ getIndicesFromThenTo = undefined
444{-# INLINE runPipe #-}
438{-# INLINE runPipe #-}
445runPipe :: (MonadIO m, Unbox a, Unbox b)
439runPipe :: (MonadIO m, Unbox a, Unbox b)
446 => Pipe m a b -> Array a -> m (Array b)
440 => Pipe m a b -> Array a -> m (Array b)
447−runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
441+runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
448-}
442-}
449
443
450-- XXX For transformations that cannot change the number of elements e.g. "map"
444-- XXX For transformations that cannot change the number of elements e.g. "map"
@@ -458,7 +452,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
458streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
452streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
459 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
453 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
460streamTransform f arr =
454streamTransform f arr =
461− Stream.fold (A.writeWith (length arr)) $ f (A.read arr)
455+ Stream.fold (createWith (length arr)) $ f (read arr)
462
456
463-------------------------------------------------------------------------------
457-------------------------------------------------------------------------------
464-- Casts
458-- Casts
@@ -492,7 +486,7 @@ asBytes = castUnsafe
492--
486--
493cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
487cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
494cast arr =
488cast arr =
495− let len = A.byteLength arr
489+ let len = byteLength arr
496 r = len `mod` SIZE_OF(b)
490 r = len `mod` SIZE_OF(b)
497 in if r /= 0
491 in if r /= 0
498 then Nothing
492 then Nothing
@@ -510,9 +504,9 @@ cast arr =
510--
504--
511asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
505asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
512asCStringUnsafe arr act = do
506asCStringUnsafe arr act = do
513− let arr1 = asBytes arr <> A.fromList [0]
507+ let arr1 = asBytes arr <> fromList [0]
514− -- asPtrUnsafe makes sure the array is pinned
508+ -- unsafePinnedAsPtr makes sure the array is pinned
515− asPtrUnsafe arr1 $ \ptr -> act (castPtr ptr)
509+ unsafePinnedAsPtr arr1 $ \ptr -> act (castPtr ptr)
516
510
517-------------------------------------------------------------------------------
511-------------------------------------------------------------------------------
518-- Folds
512-- Folds
@@ -525,14 +519,14 @@ asCStringUnsafe arr act = do
525-- /Pre-release/
519-- /Pre-release/
526{-# INLINE fold #-}
520{-# INLINE fold #-}
527fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
521fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
528−fold f arr = Stream.fold f (A.read arr)
522+fold f arr = Stream.fold f (read arr)
529
523
530-- | Fold an array using a stream fold operation.
524-- | Fold an array using a stream fold operation.
531--
525--
532-- /Pre-release/
526-- /Pre-release/
533{-# INLINE streamFold #-}
527{-# INLINE streamFold #-}
534streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
528streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
535−streamFold f arr = f (A.read arr)
529+streamFold f arr = f (read arr)
536
530
537--------------------------------------------------------------------------------
531--------------------------------------------------------------------------------
538-- Serialization
532-- Serialization
@@ -577,3 +571,448 @@ deserialize arr@(Array {..}) = unsafeInlineIO $ do
577 Serialize.deserializeAt arrStart arrContents (arrStart + lenArr)
571 Serialize.deserializeAt arrStart arrContents (arrStart + lenArr)
578 assertM(off == arrStart + lenArr)
572 assertM(off == arrStart + lenArr)
579 pure val
573 pure val
574+
575+-------------------------------------------------------------------------------
576+-- Streams of Arrays
577+-------------------------------------------------------------------------------
578+
579+-- TODO: efficiently compare two streams of arrays. Two streams can have chunks
580+-- of different sizes, we can handle that in the stream comparison abstraction.
581+-- This could be useful e.g. to fast compare whether two files differ.
582+
583+-- | Insert the given element between arrays and flatten.
584+--
585+-- >>> interpose x = Stream.interpose x Array.reader
586+--
587+{-# INLINE interpose #-}
588+interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
589+interpose x = D.interpose x reader
590+
591+data FlattenState s =
592+ OuterLoop s
593+ | InnerLoop s !MutByteArray !Int !Int
594+
595+-- | Insert the given element after each array and flatten. This is similar to
596+-- unlines.
597+--
598+-- >>> interposeSuffix x = Stream.interposeSuffix x Array.reader
599+--
600+{-# INLINE_NORMAL interposeSuffix #-}
601+interposeSuffix :: forall m a. (Monad m, Unbox a)
602+ => a -> Stream m (Array a) -> Stream m a
603+-- This does not require MonadIO constraint.
604+-- interposeSuffix x = D.interposeSuffix x reader
605+interposeSuffix sep (D.Stream step state) = D.Stream step' (OuterLoop state)
606+
607+ where
608+
609+ {-# INLINE_LATE step' #-}
610+ step' gst (OuterLoop st) = do
611+ r <- step (adaptState gst) st
612+ return $ case r of
613+ D.Yield Array{..} s ->
614+ D.Skip (InnerLoop s arrContents arrStart arrEnd)
615+ D.Skip s -> D.Skip (OuterLoop s)
616+ D.Stop -> D.Stop
617+
618+ step' _ (InnerLoop st _ p end) | p == end =
619+ return $ D.Yield sep $ OuterLoop st
620+
621+ step' _ (InnerLoop st contents p end) = do
622+ x <- pure $ unsafeInlineIO $ peekAt p contents
623+ return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
624+
625+-- | Insert the given array after each array and flatten.
626+--
627+-- >>> intercalateSuffix = Stream.intercalateSuffix Array.reader
628+--
629+{-# INLINE intercalateSuffix #-}
630+intercalateSuffix :: (Monad m, Unbox a)
631+ => Array a -> Stream m (Array a) -> Stream m a
632+intercalateSuffix = D.intercalateSuffix reader
633+
634+-- | @compactLE n@ coalesces adjacent arrays in the input stream
635+-- only if the combined size would be less than or equal to n.
636+--
637+-- Generates unpinned arrays irrespective of the pinning status of input
638+-- arrays.
639+{-# INLINE_NORMAL compactLE #-}
640+compactLE :: (MonadIO m, Unbox a)
641+ => Int -> Stream m (Array a) -> Stream m (Array a)
642+compactLE n stream =
643+ D.map unsafeFreeze $ MA.compactLE n $ D.map unsafeThaw stream
644+
645+-- | Pinned version of 'compactLE'.
646+{-# INLINE_NORMAL pinnedCompactLE #-}
647+pinnedCompactLE :: (MonadIO m, Unbox a)
648+ => Int -> Stream m (Array a) -> Stream m (Array a)
649+pinnedCompactLE n stream =
650+ D.map unsafeFreeze $ MA.pinnedCompactLE n $ D.map unsafeThaw stream
651+
652+-- | Split a stream of arrays on a given separator byte, dropping the separator
653+-- and coalescing all the arrays between two separators into a single array.
654+--
655+{-# INLINE compactOnByte #-}
656+compactOnByte
657+ :: (MonadIO m)
658+ => Word8
659+ -> Stream m (Array Word8)
660+ -> Stream m (Array Word8)
661+compactOnByte byte =
662+ fmap unsafeFreeze . MA.compactOnByte byte . fmap unsafeThaw
663+
664+-- | Like 'compactOnByte' considers the separator in suffix position instead of
665+-- infix position.
666+{-# INLINE compactOnByteSuffix #-}
667+compactOnByteSuffix
668+ :: (MonadIO m)
669+ => Word8
670+ -> Stream m (Array Word8)
671+ -> Stream m (Array Word8)
672+compactOnByteSuffix byte =
673+ fmap unsafeFreeze . MA.compactOnByteSuffix byte . fmap unsafeThaw
674+
675+-------------------------------------------------------------------------------
676+-- Folding Streams of Arrays
677+-------------------------------------------------------------------------------
678+
679+-- XXX This should not be used for breaking a stream as the D.cons used in
680+-- reconstructing the stream could be very bad for performance. This can only
681+-- be useful in folding without breaking.
682+{-# INLINE_NORMAL foldBreakChunks #-}
683+foldBreakChunks :: forall m a b. (MonadIO m, Unbox a) =>
684+ Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
685+foldBreakChunks (Fold fstep initial _ final) stream@(Stream step state) = do
686+ res <- initial
687+ case res of
688+ Fold.Partial fs -> go SPEC state fs
689+ Fold.Done fb -> return $! (fb, stream)
690+
691+ where
692+
693+ {-# INLINE go #-}
694+ go !_ st !fs = do
695+ r <- step defState st
696+ case r of
697+ Stream.Yield (Array contents start end) s ->
698+ let fp = Tuple' end contents
699+ in goArray SPEC s fp start fs
700+ Stream.Skip s -> go SPEC s fs
701+ Stream.Stop -> do
702+ b <- final fs
703+ return (b, D.nil)
704+
705+ goArray !_ s (Tuple' end _) !cur !fs
706+ | cur == end = do
707+ go SPEC s fs
708+ goArray !_ st fp@(Tuple' end contents) !cur !fs = do
709+ x <- liftIO $ peekAt cur contents
710+ res <- fstep fs x
711+ let next = INDEX_NEXT(cur,a)
712+ case res of
713+ Fold.Done b -> do
714+ let arr = Array contents next end
715+ return $! (b, D.cons arr (D.Stream step st))
716+ Fold.Partial fs1 -> goArray SPEC st fp next fs1
717+
718+-- This may be more robust wrt fusion compared to unfoldMany?
719+
720+-- | Fold a stream of arrays using a 'Fold'. This is equivalent to the
721+-- following:
722+--
723+-- >>> foldChunks f = Stream.fold f . Stream.unfoldMany Array.reader
724+--
725+foldChunks :: (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m b
726+foldChunks f s = fmap fst (foldBreakChunks f s)
727+-- foldStream f = Stream.fold f . Stream.unfoldMany reader
728+
729+-- | Fold a stream of arrays using a 'Fold' and return the remaining stream.
730+--
731+-- The following alternative to this function allows composing the fold using
732+-- the parser Monad:
733+--
734+-- @
735+-- foldBreakStreamK f s =
736+-- fmap (first (fromRight undefined))
737+-- $ StreamK.parseBreakChunks (ParserK.adaptC (Parser.fromFold f)) s
738+-- @
739+--
740+-- We can compare perf and remove this one or define it in terms of that.
741+--
742+foldBreakChunksK :: forall m a b. (MonadIO m, Unbox a) =>
743+ Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
744+{-
745+foldBreakChunksK f s =
746+ fmap (first (fromRight undefined))
747+ $ StreamK.parseBreakChunks (ParserK.adaptC (Parser.fromFold f)) s
748+-}
749+foldBreakChunksK (Fold fstep initial _ final) stream = do
750+ res <- initial
751+ case res of
752+ Fold.Partial fs -> go fs stream
753+ Fold.Done fb -> return (fb, stream)
754+
755+ where
756+
757+ {-# INLINE go #-}
758+ go !fs st = do
759+ let stop = (, StreamK.nil) <$> final fs
760+ single a = yieldk a StreamK.nil
761+ yieldk (Array contents start end) r =
762+ let fp = Tuple' end contents
763+ in goArray fs r fp start
764+ in StreamK.foldStream defState yieldk single stop st
765+
766+ goArray !fs st (Tuple' end _) !cur
767+ | cur == end = do
768+ go fs st
769+ goArray !fs st fp@(Tuple' end contents) !cur = do
770+ x <- liftIO $ peekAt cur contents
771+ res <- fstep fs x
772+ let next = INDEX_NEXT(cur,a)
773+ case res of
774+ Fold.Done b -> do
775+ let arr = Array contents next end
776+ return $! (b, StreamK.cons arr st)
777+ Fold.Partial fs1 -> goArray fs1 st fp next
778+
779+{-
780+-- This can be generalized to any type provided it can be unfolded to a stream
781+-- and it can be combined using a semigroup operation.
782+--
783+{-# INLINE_NORMAL parseBreakD #-}
784+parseBreakD ::
785+ forall m a b. (MonadIO m, MonadThrow m, Unbox a)
786+ => PRD.Parser a m b
787+ -> D.Stream m (Array.Array a)
788+ -> m (b, D.Stream m (Array.Array a))
789+parseBreakD
790+ (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
791+
792+ res <- initial
793+ case res of
794+ PRD.IPartial s -> go SPEC state (List []) s
795+ PRD.IDone b -> return (b, stream)
796+ PRD.IError err -> throwM $ ParseError err
797+
798+ where
799+
800+ -- "backBuf" contains last few items in the stream that we may have to
801+ -- backtrack to.
802+ --
803+ -- XXX currently we are using a dumb list based approach for backtracking
804+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
805+ -- That will allow us more efficient random back and forth movement.
806+ go !_ st backBuf !pst = do
807+ r <- step defState st
808+ case r of
809+ D.Yield (Array contents start end) s ->
810+ gobuf SPEC s backBuf
811+ (Tuple' end contents) start pst
812+ D.Skip s -> go SPEC s backBuf pst
813+ D.Stop -> do
814+ b <- extract pst
815+ return (b, D.nil)
816+
817+ -- Use strictness on "cur" to keep it unboxed
818+ gobuf !_ s backBuf (Tuple' end _) !cur !pst
819+ | cur == end = do
820+ go SPEC s backBuf pst
821+ gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
822+ x <- liftIO $ peekByteIndex contents cur
823+ pRes <- pstep pst x
824+ let next = INDEX_NEXT(cur,a)
825+ case pRes of
826+ PR.Partial 0 pst1 ->
827+ gobuf SPEC s (List []) fp next pst1
828+ PR.Partial n pst1 -> do
829+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
830+ let src0 = Prelude.take n (x:getList backBuf)
831+ arr0 = A.fromListN n (Prelude.reverse src0)
832+ arr1 = Array contents next end
833+ src = arr0 <> arr1
834+ let !(Array cont1 start end1) = src
835+ fp1 = Tuple' end1 cont1
836+ gobuf SPEC s (List []) fp1 start pst1
837+ PR.Continue 0 pst1 ->
838+ gobuf SPEC s (List (x:getList backBuf)) fp next pst1
839+ PR.Continue n pst1 -> do
840+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
841+ let (src0, buf1) = splitAt n (x:getList backBuf)
842+ arr0 = A.fromListN n (Prelude.reverse src0)
843+ arr1 = Array contents next end
844+ src = arr0 <> arr1
845+ let !(Array cont1 start end1) = src
846+ fp1 = Tuple' end1 cont1
847+ gobuf SPEC s (List buf1) fp1 start pst1
848+ PR.Done 0 b -> do
849+ let arr = Array contents next end
850+ return (b, D.cons arr (D.Stream step s))
851+ PR.Done n b -> do
852+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
853+ let src0 = Prelude.take n (x:getList backBuf)
854+ -- XXX create the array in reverse instead
855+ arr0 = A.fromListN n (Prelude.reverse src0)
856+ arr1 = Array contents next end
857+ -- XXX Use StreamK to avoid adding arbitrary layers of
858+ -- constructors every time.
859+ str = D.cons arr0 (D.cons arr1 (D.Stream step s))
860+ return (b, str)
861+ PR.Error err -> throwM $ ParseError err
862+-}
863+
864+-- | Parse an array stream using the supplied 'Parser'. Returns the parse
865+-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
866+--
867+-- The following alternative to this function allows composing the parser using
868+-- the parser Monad:
869+--
870+-- >>> parseBreakStreamK p = StreamK.parseBreakChunks (ParserK.adaptC p)
871+--
872+-- We can compare perf and remove this one or define it in terms of that.
873+--
874+-- /Internal/
875+--
876+{-# INLINE_NORMAL parseBreakChunksK #-}
877+parseBreakChunksK ::
878+ forall m a b. (MonadIO m, Unbox a)
879+ => Parser a m b
880+ -> StreamK m (Array a)
881+ -> m (Either ParseError b, StreamK m (Array a))
882+-- parseBreakStreamK p = StreamK.parseBreakChunks (ParserK.adaptC p)
883+parseBreakChunksK (Parser pstep initial extract) stream = do
884+ res <- initial
885+ case res of
886+ IPartial s -> go s stream []
887+ IDone b -> return (Right b, stream)
888+ IError err -> return (Left (ParseError err), stream)
889+
890+ where
891+
892+ -- "backBuf" contains last few items in the stream that we may have to
893+ -- backtrack to.
894+ --
895+ -- XXX currently we are using a dumb list based approach for backtracking
896+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
897+ -- That will allow us more efficient random back and forth movement.
898+ go !pst st backBuf = do
899+ let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
900+ single a = yieldk a StreamK.nil
901+ yieldk arr r = goArray pst backBuf r arr
902+ in StreamK.foldStream defState yieldk single stop st
903+
904+ -- Use strictness on "cur" to keep it unboxed
905+ goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
906+ goArray !pst backBuf st (Array contents cur end) = do
907+ x <- liftIO $ peekAt cur contents
908+ pRes <- pstep pst x
909+ let next = INDEX_NEXT(cur,a)
910+ case pRes of
911+ Parser.Partial 0 s ->
912+ goArray s [] st (Array contents next end)
913+ Parser.Partial n s -> do
914+ assert (n <= Prelude.length (x:backBuf)) (return ())
915+ let src0 = Prelude.take n (x:backBuf)
916+ arr0 = fromListN n (Prelude.reverse src0)
917+ arr1 = Array contents next end
918+ src = arr0 <> arr1
919+ goArray s [] st src
920+ Parser.Continue 0 s ->
921+ goArray s (x:backBuf) st (Array contents next end)
922+ Parser.Continue n s -> do
923+ assert (n <= Prelude.length (x:backBuf)) (return ())
924+ let (src0, buf1) = Prelude.splitAt n (x:backBuf)
925+ arr0 = fromListN n (Prelude.reverse src0)
926+ arr1 = Array contents next end
927+ src = arr0 <> arr1
928+ goArray s buf1 st src
929+ Parser.Done 0 b -> do
930+ let arr = Array contents next end
931+ return (Right b, StreamK.cons arr st)
932+ Parser.Done n b -> do
933+ assert (n <= Prelude.length (x:backBuf)) (return ())
934+ let src0 = Prelude.take n (x:backBuf)
935+ -- XXX Use fromListRevN once implemented
936+ -- arr0 = A.fromListRevN n src0
937+ arr0 = fromListN n (Prelude.reverse src0)
938+ arr1 = Array contents next end
939+ str = StreamK.cons arr0 (StreamK.cons arr1 st)
940+ return (Right b, str)
941+ Parser.Error err -> do
942+ let n = Prelude.length backBuf
943+ arr0 = fromListN n (Prelude.reverse backBuf)
944+ arr1 = Array contents cur end
945+ str = StreamK.cons arr0 (StreamK.cons arr1 stream)
946+ return (Left (ParseError err), str)
947+
948+ -- This is a simplified goArray
949+ goExtract !pst backBuf (Array _ cur end)
950+ | cur == end = goStop pst backBuf
951+ goExtract !pst backBuf (Array contents cur end) = do
952+ x <- liftIO $ peekAt cur contents
953+ pRes <- pstep pst x
954+ let next = INDEX_NEXT(cur,a)
955+ case pRes of
956+ Parser.Partial 0 s ->
957+ goExtract s [] (Array contents next end)
958+ Parser.Partial n s -> do
959+ assert (n <= Prelude.length (x:backBuf)) (return ())
960+ let src0 = Prelude.take n (x:backBuf)
961+ arr0 = fromListN n (Prelude.reverse src0)
962+ arr1 = Array contents next end
963+ src = arr0 <> arr1
964+ goExtract s [] src
965+ Parser.Continue 0 s ->
966+ goExtract s backBuf (Array contents next end)
967+ Parser.Continue n s -> do
968+ assert (n <= Prelude.length (x:backBuf)) (return ())
969+ let (src0, buf1) = Prelude.splitAt n (x:backBuf)
970+ arr0 = fromListN n (Prelude.reverse src0)
971+ arr1 = Array contents next end
972+ src = arr0 <> arr1
973+ goExtract s buf1 src
974+ Parser.Done 0 b -> do
975+ let arr = Array contents next end
976+ return (Right b, StreamK.fromPure arr)
977+ Parser.Done n b -> do
978+ assert (n <= Prelude.length backBuf) (return ())
979+ let src0 = Prelude.take n backBuf
980+ -- XXX Use fromListRevN once implemented
981+ -- arr0 = A.fromListRevN n src0
982+ arr0 = fromListN n (Prelude.reverse src0)
983+ arr1 = Array contents next end
984+ str = StreamK.cons arr0 (StreamK.fromPure arr1)
985+ return (Right b, str)
986+ Parser.Error err -> do
987+ let n = Prelude.length backBuf
988+ arr0 = fromListN n (Prelude.reverse backBuf)
989+ arr1 = Array contents cur end
990+ str = StreamK.cons arr0 (StreamK.cons arr1 stream)
991+ return (Left (ParseError err), str)
992+
993+ -- This is a simplified goExtract
994+ {-# INLINE goStop #-}
995+ goStop !pst backBuf = do
996+ pRes <- extract pst
997+ case pRes of
998+ Parser.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
999+ Parser.Continue 0 s ->
1000+ goStop s backBuf
1001+ Parser.Continue n s -> do
1002+ assert (n <= Prelude.length backBuf) (return ())
1003+ let (src0, buf1) = Prelude.splitAt n backBuf
1004+ arr = fromListN n (Prelude.reverse src0)
1005+ goExtract s buf1 arr
1006+ Parser.Done 0 b ->
1007+ return (Right b, StreamK.nil)
1008+ Parser.Done n b -> do
1009+ assert (n <= Prelude.length backBuf) (return ())
1010+ let src0 = Prelude.take n backBuf
1011+ -- XXX Use fromListRevN once implemented
1012+ -- arr0 = A.fromListRevN n src0
1013+ arr0 = fromListN n (Prelude.reverse src0)
1014+ return (Right b, StreamK.fromPure arr0)
1015+ Parser.Error err -> do
1016+ let n = Prelude.length backBuf
1017+ arr0 = fromListN n (Prelude.reverse backBuf)
1018+ return (Left (ParseError err), StreamK.fromPure arr0)
core/src/Streamly/Internal/Data/Array/Generic.hs+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/Stream.hs+15−475
@@ -12,6 +12,7 @@
12-- keep this as a separate module and release it.
12-- keep this as a separate module and release it.
13--
13--
14module Streamly.Internal.Data.Array.Stream
14module Streamly.Internal.Data.Array.Stream
15+{-# DEPRECATED "Please use \"Streamly.Internal.Data.Array\" instead." #-}
15 (
16 (
16 -- * Creation
17 -- * Creation
17 Array.chunksOf
18 Array.chunksOf
@@ -19,13 +20,13 @@ module Streamly.Internal.Data.Array.Stream
19 , Array.bufferChunks
20 , Array.bufferChunks
20
21
21 -- * Flattening to elements
22 -- * Flattening to elements
22− , concat
23+ , Array.concat
23 , Array.flattenArrays
24 , Array.flattenArrays
24− , concatRev
25+ , Array.concatRev
25 , Array.flattenArraysRev
26 , Array.flattenArraysRev
26− , interpose
27+ , Array.interpose
27− , interposeSuffix
28+ , Array.interposeSuffix
28− , intercalateSuffix
29+ , Array.intercalateSuffix
29 , unlines
30 , unlines
30
31
31 -- * Elimination
32 -- * Elimination
@@ -90,20 +91,14 @@ import Prelude hiding (null, last, (!!), read, concat, unlines)
90
91
91import Streamly.Data.Fold (Fold)
92import Streamly.Data.Fold (Fold)
92import Streamly.Internal.Data.Array.Type (Array(..))
93import Streamly.Internal.Data.Array.Type (Array(..))
93−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
94import Streamly.Internal.Data.Fold.Chunked (ChunkFold(..))
94import Streamly.Internal.Data.Fold.Chunked (ChunkFold(..))
95import Streamly.Internal.Data.Parser (ParseError(..))
95import Streamly.Internal.Data.Parser (ParseError(..))
96import Streamly.Internal.Data.Stream (Stream)
96import Streamly.Internal.Data.Stream (Stream)
97import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
97import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
98import Streamly.Internal.Data.SVar.Type (adaptState, defState)
98import Streamly.Internal.Data.SVar.Type (adaptState, defState)
99−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
100
99
101−import qualified Streamly.Data.Fold as FL
102import qualified Streamly.Internal.Data.Array as A
100import qualified Streamly.Internal.Data.Array as A
103import qualified Streamly.Internal.Data.Array as Array
101import qualified Streamly.Internal.Data.Array as Array
104−import qualified Streamly.Internal.Data.MutArray.Type as MA
105−import qualified Streamly.Internal.Data.MutArray.Stream as AS
106−import qualified Streamly.Internal.Data.Fold.Type as FL (Fold(..), Step(..))
107import qualified Streamly.Internal.Data.Parser as PR
102import qualified Streamly.Internal.Data.Parser as PR
108import qualified Streamly.Internal.Data.Parser as PRD
103import qualified Streamly.Internal.Data.Parser as PRD
109 (Parser(..), Initial(..))
104 (Parser(..), Initial(..))
@@ -114,110 +109,19 @@ import qualified Streamly.Internal.Data.StreamK as K
114-- XXX Since these are immutable arrays MonadIO constraint can be removed from
109-- XXX Since these are immutable arrays MonadIO constraint can be removed from
115-- most places.
110-- most places.
116
111
117−-------------------------------------------------------------------------------
118−-- Append
119−-------------------------------------------------------------------------------
120−
121−-- XXX efficiently compare two streams of arrays. Two streams can have chunks
122−-- of different sizes, we can handle that in the stream comparison abstraction.
123−-- This could be useful e.g. to fast compare whether two files differ.
124−
125−-- | Convert a stream of arrays into a stream of their elements.
126−--
127−-- Same as the following:
128−--
129−-- > concat = Stream.unfoldMany Array.read
130−--
131−-- @since 0.7.0
132−{-# INLINE concat #-}
133−concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
134−-- concat m = fromStreamD $ A.flattenArrays (toStreamD m)
135−-- concat m = fromStreamD $ D.concatMap A.toStreamD (toStreamD m)
136−concat = D.unfoldMany A.reader
137−
138−-- | Convert a stream of arrays into a stream of their elements reversing the
139−-- contents of each array before flattening.
140−--
141−-- > concatRev = Stream.unfoldMany Array.readerRev
142−--
143−-- @since 0.7.0
144−{-# INLINE concatRev #-}
145−concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
146−-- concatRev m = fromStreamD $ A.flattenArraysRev (toStreamD m)
147−concatRev = D.unfoldMany A.readerRev
148−
149-------------------------------------------------------------------------------
112-------------------------------------------------------------------------------
150-- Intersperse and append
113-- Intersperse and append
151-------------------------------------------------------------------------------
114-------------------------------------------------------------------------------
152
115
153−-- | Flatten a stream of arrays after inserting the given element between
154−-- arrays.
155−--
156−-- /Pre-release/
157−{-# INLINE interpose #-}
158−interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
159−interpose x = D.interpose x A.reader
160−
161−{-# INLINE intercalateSuffix #-}
162−intercalateSuffix :: (Monad m, Unbox a)
163− => Array a -> Stream m (Array a) -> Stream m a
164−intercalateSuffix = D.intercalateSuffix A.reader
165−
166−-- | Flatten a stream of arrays appending the given element after each
167−-- array.
168−--
169−-- @since 0.7.0
170−{-# INLINE interposeSuffix #-}
171−interposeSuffix :: (Monad m, Unbox a)
172− => a -> Stream m (Array a) -> Stream m a
173−-- interposeSuffix x = fromStreamD . A.unlines x . toStreamD
174−interposeSuffix x = D.interposeSuffix x A.reader
175−
176−data FlattenState s =
177− OuterLoop s
178− | InnerLoop s !MutByteArray !Int !Int
179−
180−-- XXX This is a special case of interposeSuffix, can be removed.
181−-- XXX Remove monadIO constraint
182{-# INLINE_NORMAL unlines #-}
116{-# INLINE_NORMAL unlines #-}
183unlines :: forall m a. (MonadIO m, Unbox a)
117unlines :: forall m a. (MonadIO m, Unbox a)
184 => a -> D.Stream m (Array a) -> D.Stream m a
118 => a -> D.Stream m (Array a) -> D.Stream m a
185−unlines sep (D.Stream step state) = D.Stream step' (OuterLoop state)
119+unlines = Array.interposeSuffix
186− where
187− {-# INLINE_LATE step' #-}
188− step' gst (OuterLoop st) = do
189− r <- step (adaptState gst) st
190− return $ case r of
191− D.Yield Array{..} s ->
192− D.Skip (InnerLoop s arrContents arrStart arrEnd)
193− D.Skip s -> D.Skip (OuterLoop s)
194− D.Stop -> D.Stop
195−
196− step' _ (InnerLoop st _ p end) | p == end =
197− return $ D.Yield sep $ OuterLoop st
198−
199− step' _ (InnerLoop st contents p end) = do
200− x <- liftIO $ peekByteIndex p contents
201− return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
202
120
203-------------------------------------------------------------------------------
121-------------------------------------------------------------------------------
204-- Compact
122-- Compact
205-------------------------------------------------------------------------------
123-------------------------------------------------------------------------------
206
124
207−-- XXX These would not be needed once we implement compactLEFold, see
208−-- module Streamly.Internal.Data.Stream.MutChunked
209−--
210−-- XXX Note that this thaws immutable arrays for appending, that may be
211−-- problematic if multiple users do the same thing, however, immutable arrays
212−-- would usually have no capacity to append, therefore, a copy will be forced
213−-- anyway. Confirm this. We can forcefully trim the array capacity before thaw
214−-- to ensure this.
215−{-# INLINE_NORMAL packArraysChunksOf #-}
216−packArraysChunksOf :: (MonadIO m, Unbox a)
217− => Int -> D.Stream m (Array a) -> D.Stream m (Array a)
218−packArraysChunksOf n str =
219− D.map A.unsafeFreeze $ AS.packArraysChunksOf n $ D.map A.unsafeThaw str
220−
221-- XXX instead of writing two different versions of this operation, we should
125-- XXX instead of writing two different versions of this operation, we should
222-- write it as a pipe.
126-- write it as a pipe.
223--
127--
@@ -225,8 +129,7 @@ packArraysChunksOf n str =
225{-# INLINE_NORMAL lpackArraysChunksOf #-}
129{-# INLINE_NORMAL lpackArraysChunksOf #-}
226lpackArraysChunksOf :: (MonadIO m, Unbox a)
130lpackArraysChunksOf :: (MonadIO m, Unbox a)
227 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
131 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
228−lpackArraysChunksOf n fld =
132+lpackArraysChunksOf = Array.lCompactGE
229− FL.lmap A.unsafeThaw $ AS.lpackArraysChunksOf n (FL.lmap A.unsafeFreeze fld)
230
133
231-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
134-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
232-- maximum specified size in bytes.
135-- maximum specified size in bytes.
@@ -235,7 +138,7 @@ lpackArraysChunksOf n fld =
235{-# INLINE compact #-}
138{-# INLINE compact #-}
236compact :: (MonadIO m, Unbox a)
139compact :: (MonadIO m, Unbox a)
237 => Int -> Stream m (Array a) -> Stream m (Array a)
140 => Int -> Stream m (Array a) -> Stream m (Array a)
238−compact = packArraysChunksOf
141+compact = Array.compactLE
239
142
240-- | Given a stream of arrays, splice them all together to generate a single
143-- | Given a stream of arrays, splice them all together to generate a single
241-- array. The stream must be /finite/.
144-- array. The stream must be /finite/.
@@ -243,71 +146,12 @@ compact = packArraysChunksOf
243-- @since 0.7.0
146-- @since 0.7.0
244{-# INLINE toArray #-}
147{-# INLINE toArray #-}
245toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
148toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
246−toArray s =
149+toArray = Array.fromChunks
247− fmap A.unsafeFreeze $ MA.fromChunksRealloced (fmap A.unsafeThaw s)
248
150
249-------------------------------------------------------------------------------
151-------------------------------------------------------------------------------
250-- Split
152-- Split
251-------------------------------------------------------------------------------
153-------------------------------------------------------------------------------
252
154
253−data SplitState s arr
254− = Initial s
255− | Buffering s arr
256− | Splitting s arr
257− | Yielding arr (SplitState s arr)
258− | Finishing
259−
260−-- | Split a stream of arrays on a given separator byte, dropping the separator
261−-- and coalescing all the arrays between two separators into a single array.
262−--
263−-- @since 0.7.0
264−{-# INLINE_NORMAL _splitOn #-}
265−_splitOn
266− :: MonadIO m
267− => Word8
268− -> D.Stream m (Array Word8)
269− -> D.Stream m (Array Word8)
270−_splitOn byte (D.Stream step state) = D.Stream step' (Initial state)
271−
272− where
273−
274− {-# INLINE_LATE step' #-}
275− step' gst (Initial st) = do
276− r <- step gst st
277− case r of
278− D.Yield arr s -> do
279− (arr1, marr2) <- A.breakOn byte arr
280− return $ case marr2 of
281− Nothing -> D.Skip (Buffering s arr1)
282− Just arr2 -> D.Skip (Yielding arr1 (Splitting s arr2))
283− D.Skip s -> return $ D.Skip (Initial s)
284− D.Stop -> return D.Stop
285−
286− step' gst (Buffering st buf) = do
287− r <- step gst st
288− case r of
289− D.Yield arr s -> do
290− (arr1, marr2) <- A.breakOn byte arr
291− -- XXX Should use MutArray.splice
292− buf' <- A.splice buf arr1
293− return $ case marr2 of
294− Nothing -> D.Skip (Buffering s buf')
295− Just x -> D.Skip (Yielding buf' (Splitting s x))
296− D.Skip s -> return $ D.Skip (Buffering s buf)
297− D.Stop -> return $
298− if A.byteLength buf == 0
299− then D.Stop
300− else D.Skip (Yielding buf Finishing)
301−
302− step' _ (Splitting st buf) = do
303− (arr1, marr2) <- A.breakOn byte buf
304− return $ case marr2 of
305− Nothing -> D.Skip $ Buffering st arr1
306− Just arr2 -> D.Skip $ Yielding arr1 (Splitting st arr2)
307−
308− step' _ (Yielding arr next) = return $ D.Yield arr next
309− step' _ Finishing = return D.Stop
310−
311-- XXX Remove MonadIO constraint.
155-- XXX Remove MonadIO constraint.
312-- | Split a stream of arrays on a given separator byte, dropping the separator
156-- | Split a stream of arrays on a given separator byte, dropping the separator
313-- and coalescing all the arrays between two separators into a single array.
157-- and coalescing all the arrays between two separators into a single array.
@@ -319,11 +163,7 @@ splitOn
319 => Word8
163 => Word8
320 -> Stream m (Array Word8)
164 -> Stream m (Array Word8)
321 -> Stream m (Array Word8)
165 -> Stream m (Array Word8)
322−splitOn byte =
166+splitOn = Array.compactOnByte
323− fmap A.unsafeFreeze
324− -- XXX use spliceExp and rightSize?
325− . D.splitInnerBy (MA.breakOn byte) MA.splice
326− . fmap A.unsafeThaw
327
167
328{-# INLINE splitOnSuffix #-}
168{-# INLINE splitOnSuffix #-}
329splitOnSuffix
169splitOnSuffix
@@ -331,13 +171,7 @@ splitOnSuffix
331 => Word8
171 => Word8
332 -> Stream m (Array Word8)
172 -> Stream m (Array Word8)
333 -> Stream m (Array Word8)
173 -> Stream m (Array Word8)
334−-- splitOn byte s = fromStreamD $ A.splitOn byte $ toStreamD s
335−splitOnSuffix byte =
174+splitOnSuffix = Array.compactOnByteSuffix
336− fmap A.unsafeFreeze
337− -- XXX use spliceExp and rightSize?
338− . D.splitInnerBySuffix
339− (\arr -> MA.byteLength arr == 0) (MA.breakOn byte) MA.splice
340− . fmap A.unsafeThaw
341
175
342-------------------------------------------------------------------------------
176-------------------------------------------------------------------------------
343-- Elimination - Running folds
177-- Elimination - Running folds
@@ -346,71 +180,7 @@ splitOnSuffix byte =
346{-# INLINE_NORMAL foldBreakD #-}
180{-# INLINE_NORMAL foldBreakD #-}
347foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
181foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
348 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
182 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
349−foldBreakD (FL.Fold fstep initial _ final) stream@(D.Stream step state) = do
183+foldBreakD = Array.foldBreakChunks
350− res <- initial
351− case res of
352− FL.Partial fs -> go SPEC state fs
353− FL.Done fb -> return $! (fb, stream)
354−
355− where
356−
357− {-# INLINE go #-}
358− go !_ st !fs = do
359− r <- step defState st
360− case r of
361− D.Yield (Array contents start end) s ->
362− let fp = Tuple' end contents
363− in goArray SPEC s fp start fs
364− D.Skip s -> go SPEC s fs
365− D.Stop -> do
366− b <- final fs
367− return (b, D.nil)
368−
369− goArray !_ s (Tuple' end _) !cur !fs
370− | cur == end = do
371− go SPEC s fs
372− goArray !_ st fp@(Tuple' end contents) !cur !fs = do
373− x <- liftIO $ peekByteIndex cur contents
374− res <- fstep fs x
375− let next = INDEX_NEXT(cur,a)
376− case res of
377− FL.Done b -> do
378− let arr = Array contents next end
379− return $! (b, D.cons arr (D.Stream step st))
380− FL.Partial fs1 -> goArray SPEC st fp next fs1
381−
382−{-# INLINE_NORMAL foldBreakK #-}
383−foldBreakK :: forall m a b. (MonadIO m, Unbox a) =>
384− Fold m a b -> K.StreamK m (Array a) -> m (b, K.StreamK m (Array a))
385−foldBreakK (FL.Fold fstep initial _ final) stream = do
386− res <- initial
387− case res of
388− FL.Partial fs -> go fs stream
389− FL.Done fb -> return (fb, stream)
390−
391− where
392−
393− {-# INLINE go #-}
394− go !fs st = do
395− let stop = (, K.nil) <$> final fs
396− single a = yieldk a K.nil
397− yieldk (Array contents start end) r =
398− let fp = Tuple' end contents
399− in goArray fs r fp start
400− in K.foldStream defState yieldk single stop st
401−
402− goArray !fs st (Tuple' end _) !cur
403− | cur == end = do
404− go fs st
405− goArray !fs st fp@(Tuple' end contents) !cur = do
406− x <- liftIO $ peekByteIndex cur contents
407− res <- fstep fs x
408− let next = INDEX_NEXT(cur,a)
409− case res of
410− FL.Done b -> do
411− let arr = Array contents next end
412− return $! (b, K.cons arr st)
413− FL.Partial fs1 -> goArray fs1 st fp next
414
184
415-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
185-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
416-- and the unconsumed stream.
186-- and the unconsumed stream.
@@ -436,7 +206,7 @@ foldBreak ::
436 => Fold m a b
206 => Fold m a b
437 -> StreamK m (A.Array a)
207 -> StreamK m (A.Array a)
438 -> m (b, StreamK m (A.Array a))
208 -> m (b, StreamK m (A.Array a))
439−foldBreak = foldBreakK
209+foldBreak = Array.foldBreakChunksK
440--
210--
441-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
211-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
442--
212--
@@ -500,236 +270,6 @@ splitAtArrayListRev n ls
500{-# ANN type List NoSpecConstr #-}
270{-# ANN type List NoSpecConstr #-}
501newtype List a = List {getList :: [a]}
271newtype List a = List {getList :: [a]}
502
272
503−{-
504−-- This can be generalized to any type provided it can be unfolded to a stream
505−-- and it can be combined using a semigroup operation.
506−--
507−-- XXX This should be written using CPS (as parseK) if we want it to scale wrt
508−-- to the number of times it can be called on the same stream.
509−{-# INLINE_NORMAL parseBreakD #-}
510−parseBreakD ::
511− forall m a b. (MonadIO m, MonadThrow m, Unbox a)
512− => PRD.Parser a m b
513− -> D.Stream m (Array.Array a)
514− -> m (b, D.Stream m (Array.Array a))
515−parseBreakD
516− (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
517−
518− res <- initial
519− case res of
520− PRD.IPartial s -> go SPEC state (List []) s
521− PRD.IDone b -> return (b, stream)
522− PRD.IError err -> throwM $ ParseError err
523−
524− where
525−
526− -- "backBuf" contains last few items in the stream that we may have to
527− -- backtrack to.
528− --
529− -- XXX currently we are using a dumb list based approach for backtracking
530− -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
531− -- That will allow us more efficient random back and forth movement.
532− go !_ st backBuf !pst = do
533− r <- step defState st
534− case r of
535− D.Yield (Array contents start end) s ->
536− gobuf SPEC s backBuf
537− (Tuple' end contents) start pst
538− D.Skip s -> go SPEC s backBuf pst
539− D.Stop -> do
540− b <- extract pst
541− return (b, D.nil)
542−
543− -- Use strictness on "cur" to keep it unboxed
544− gobuf !_ s backBuf (Tuple' end _) !cur !pst
545− | cur == end = do
546− go SPEC s backBuf pst
547− gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
548− x <- liftIO $ peekByteIndex contents cur
549− pRes <- pstep pst x
550− let next = INDEX_NEXT(cur,a)
551− case pRes of
552− PR.Partial 0 pst1 ->
553− gobuf SPEC s (List []) fp next pst1
554− PR.Partial n pst1 -> do
555− assert (n <= Prelude.length (x:getList backBuf)) (return ())
556− let src0 = Prelude.take n (x:getList backBuf)
557− arr0 = A.fromListN n (Prelude.reverse src0)
558− arr1 = Array contents next end
559− src = arr0 <> arr1
560− let !(Array cont1 start end1) = src
561− fp1 = Tuple' end1 cont1
562− gobuf SPEC s (List []) fp1 start pst1
563− PR.Continue 0 pst1 ->
564− gobuf SPEC s (List (x:getList backBuf)) fp next pst1
565− PR.Continue n pst1 -> do
566− assert (n <= Prelude.length (x:getList backBuf)) (return ())
567− let (src0, buf1) = splitAt n (x:getList backBuf)
568− arr0 = A.fromListN n (Prelude.reverse src0)
569− arr1 = Array contents next end
570− src = arr0 <> arr1
571− let !(Array cont1 start end1) = src
572− fp1 = Tuple' end1 cont1
573− gobuf SPEC s (List buf1) fp1 start pst1
574− PR.Done 0 b -> do
575− let arr = Array contents next end
576− return (b, D.cons arr (D.Stream step s))
577− PR.Done n b -> do
578− assert (n <= Prelude.length (x:getList backBuf)) (return ())
579− let src0 = Prelude.take n (x:getList backBuf)
580− -- XXX create the array in reverse instead
581− arr0 = A.fromListN n (Prelude.reverse src0)
582− arr1 = Array contents next end
583− -- XXX Use StreamK to avoid adding arbitrary layers of
584− -- constructors every time.
585− str = D.cons arr0 (D.cons arr1 (D.Stream step s))
586− return (b, str)
587− PR.Error err -> throwM $ ParseError err
588−-}
589−
590−{-# INLINE_NORMAL parseBreakK #-}
591−parseBreakK ::
592− forall m a b. (MonadIO m, Unbox a)
593− => PRD.Parser a m b
594− -> K.StreamK m (Array.Array a)
595− -> m (Either ParseError b, K.StreamK m (Array.Array a))
596−parseBreakK (PRD.Parser pstep initial extract) stream = do
597− res <- initial
598− case res of
599− PRD.IPartial s -> go s stream []
600− PRD.IDone b -> return (Right b, stream)
601− PRD.IError err -> return (Left (ParseError err), stream)
602−
603− where
604−
605− -- "backBuf" contains last few items in the stream that we may have to
606− -- backtrack to.
607− --
608− -- XXX currently we are using a dumb list based approach for backtracking
609− -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
610− -- That will allow us more efficient random back and forth movement.
611− go !pst st backBuf = do
612− let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
613− single a = yieldk a K.nil
614− yieldk arr r = goArray pst backBuf r arr
615− in K.foldStream defState yieldk single stop st
616−
617− -- Use strictness on "cur" to keep it unboxed
618− goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
619− goArray !pst backBuf st (Array contents cur end) = do
620− x <- liftIO $ peekByteIndex cur contents
621− pRes <- pstep pst x
622− let next = INDEX_NEXT(cur,a)
623− case pRes of
624− PR.Partial 0 s ->
625− goArray s [] st (Array contents next end)
626− PR.Partial n s -> do
627− assert (n <= Prelude.length (x:backBuf)) (return ())
628− let src0 = Prelude.take n (x:backBuf)
629− arr0 = A.fromListN n (Prelude.reverse src0)
630− arr1 = Array contents next end
631− src = arr0 <> arr1
632− goArray s [] st src
633− PR.Continue 0 s ->
634− goArray s (x:backBuf) st (Array contents next end)
635− PR.Continue n s -> do
636− assert (n <= Prelude.length (x:backBuf)) (return ())
637− let (src0, buf1) = splitAt n (x:backBuf)
638− arr0 = A.fromListN n (Prelude.reverse src0)
639− arr1 = Array contents next end
640− src = arr0 <> arr1
641− goArray s buf1 st src
642− PR.Done 0 b -> do
643− let arr = Array contents next end
644− return (Right b, K.cons arr st)
645− PR.Done n b -> do
646− assert (n <= Prelude.length (x:backBuf)) (return ())
647− let src0 = Prelude.take n (x:backBuf)
648− -- XXX Use fromListRevN once implemented
649− -- arr0 = A.fromListRevN n src0
650− arr0 = A.fromListN n (Prelude.reverse src0)
651− arr1 = Array contents next end
652− str = K.cons arr0 (K.cons arr1 st)
653− return (Right b, str)
654− PR.Error err -> do
655− let n = Prelude.length backBuf
656− arr0 = A.fromListN n (Prelude.reverse backBuf)
657− arr1 = Array contents cur end
658− str = K.cons arr0 (K.cons arr1 stream)
659− return (Left (ParseError err), str)
660−
661− -- This is a simplified goArray
662− goExtract !pst backBuf (Array _ cur end)
663− | cur == end = goStop pst backBuf
664− goExtract !pst backBuf (Array contents cur end) = do
665− x <- liftIO $ peekByteIndex cur contents
666− pRes <- pstep pst x
667− let next = INDEX_NEXT(cur,a)
668− case pRes of
669− PR.Partial 0 s ->
670− goExtract s [] (Array contents next end)
671− PR.Partial n s -> do
672− assert (n <= Prelude.length (x:backBuf)) (return ())
673− let src0 = Prelude.take n (x:backBuf)
674− arr0 = A.fromListN n (Prelude.reverse src0)
675− arr1 = Array contents next end
676− src = arr0 <> arr1
677− goExtract s [] src
678− PR.Continue 0 s ->
679− goExtract s backBuf (Array contents next end)
680− PR.Continue n s -> do
681− assert (n <= Prelude.length (x:backBuf)) (return ())
682− let (src0, buf1) = splitAt n (x:backBuf)
683− arr0 = A.fromListN n (Prelude.reverse src0)
684− arr1 = Array contents next end
685− src = arr0 <> arr1
686− goExtract s buf1 src
687− PR.Done 0 b -> do
688− let arr = Array contents next end
689− return (Right b, K.fromPure arr)
690− PR.Done n b -> do
691− assert (n <= Prelude.length backBuf) (return ())
692− let src0 = Prelude.take n backBuf
693− -- XXX Use fromListRevN once implemented
694− -- arr0 = A.fromListRevN n src0
695− arr0 = A.fromListN n (Prelude.reverse src0)
696− arr1 = Array contents next end
697− str = K.cons arr0 (K.fromPure arr1)
698− return (Right b, str)
699− PR.Error err -> do
700− let n = Prelude.length backBuf
701− arr0 = A.fromListN n (Prelude.reverse backBuf)
702− arr1 = Array contents cur end
703− str = K.cons arr0 (K.cons arr1 stream)
704− return (Left (ParseError err), str)
705−
706− -- This is a simplified goExtract
707− {-# INLINE goStop #-}
708− goStop !pst backBuf = do
709− pRes <- extract pst
710− case pRes of
711− PR.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
712− PR.Continue 0 s ->
713− goStop s backBuf
714− PR.Continue n s -> do
715− assert (n <= Prelude.length backBuf) (return ())
716− let (src0, buf1) = splitAt n backBuf
717− arr = A.fromListN n (Prelude.reverse src0)
718− goExtract s buf1 arr
719− PR.Done 0 b ->
720− return (Right b, K.nil)
721− PR.Done n b -> do
722− assert (n <= Prelude.length backBuf) (return ())
723− let src0 = Prelude.take n backBuf
724− -- XXX Use fromListRevN once implemented
725− -- arr0 = A.fromListRevN n src0
726− arr0 = A.fromListN n (Prelude.reverse src0)
727− return (Right b, K.fromPure arr0)
728− PR.Error err -> do
729− let n = Prelude.length backBuf
730− arr0 = A.fromListN n (Prelude.reverse backBuf)
731− return (Left (ParseError err), K.fromPure arr0)
732−
733-- | Parse an array stream using the supplied 'Parser'. Returns the parse
273-- | Parse an array stream using the supplied 'Parser'. Returns the parse
734-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
274-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
735--
275--
@@ -753,7 +293,7 @@ parseBreak ::
753parseBreak p s =
293parseBreak p s =
754 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
294 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
755-}
295-}
756−parseBreak = parseBreakK
296+parseBreak = Array.parseBreakChunksK
757-- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
297-- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
758
298
759-------------------------------------------------------------------------------
299-------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Array/Type.hs+328−86
@@ -1,8 +1,11 @@
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
5−--
6-- License : BSD3-3-Clause
9-- License : BSD3-3-Clause
7-- Maintainer : streamly@composewell.com
10-- Maintainer : streamly@composewell.com
8-- Stability : experimental
11-- Stability : experimental
@@ -10,33 +13,57 @@
10--
13--
11-- See notes in "Streamly.Internal.Data.MutArray.Type"
14-- See notes in "Streamly.Internal.Data.MutArray.Type"
12--
15--
16+
13module Streamly.Internal.Data.Array.Type
17module Streamly.Internal.Data.Array.Type
14 (
18 (
15 -- ** Type
19 -- ** Type
16 -- $arrayNotes
20 -- $arrayNotes
17 Array (..)
21 Array (..)
18− , asPtrUnsafe
19− , nil
20
22
21− -- ** Freezing and Thawing
23+ -- ** Conversion
24+ -- *** Mutable and Immutable
22 , unsafeFreeze
25 , unsafeFreeze
23 , unsafeFreezeWithShrink
26 , unsafeFreezeWithShrink
24 , unsafeThaw
27 , unsafeThaw
25
28
26− -- ** Pinning and Unpinning
29+ -- *** Pinned and Unpinned
27 , pin
30 , pin
28 , unpin
31 , unpin
29 , isPinned
32 , isPinned
30
33
34+ -- *** Casting
35+ , unsafePinnedAsPtr
36+
31 -- ** Construction
37 -- ** Construction
32− , splice
38+ , empty
33
39
34− , fromList
40+ -- *** Cloning
35− , pinnedFromList
41+ -- XXX Why would we clone an immutable array?
42+ , clone
43+ , pinnedClone
44+
45+ -- *** Slicing
46+ -- | Get a subarray without copying
47+ , splitAt
48+ , breakOn -- XXX requires MonadIO
49+
50+ -- *** Stream Folds
51+ , unsafeMakePure
52+ , createOf
53+ , pinnedCreateOf
54+ , unsafeCreateOf
55+ , unsafePinnedCreateOf
56+ , create
57+ , pinnedCreate
58+ , createWith
59+
60+ -- *** From containers
36 , fromListN
61 , fromListN
37 , pinnedFromListN
62 , pinnedFromListN
38− , fromListRev
63+ , fromList
64+ , pinnedFromList
39 , fromListRevN
65 , fromListRevN
66+ , fromListRev
40 , fromStreamN
67 , fromStreamN
41 , fromStream
68 , fromStream
42 , fromPureStreamN
69 , fromPureStreamN
@@ -44,54 +71,68 @@ module Streamly.Internal.Data.Array.Type
44 , fromByteStr#
71 , fromByteStr#
45 , fromByteStr
72 , fromByteStr
46 , fromPtrN
73 , fromPtrN
74+ , fromChunks
47 , fromChunksK
75 , fromChunksK
48
76
49− -- ** Split
77+ -- ** Reading
50− , breakOn
51− , splitAt
52−
53− -- ** Cloning arrays
54− , clone
55− , pinnedClone
56−
57− -- ** Elimination
58− , unsafeIndexIO
59− , getIndexUnsafe
60− , byteLength
61− , length
62
78
63− , foldl'
79+ -- *** Indexing
64− , foldr
80+ , unsafeIndexIO -- XXX unsafeGetIndexIO
81+ , getIndexUnsafe -- XXX unsafeGetIndex
65
82
66− , toStreamK
83+ -- *** To Streams
67− , toStreamKRev
68 , read
84 , read
69 , readRev
85 , readRev
70− , readerRev
86+ , toStreamK
87+ , toStreamKRev
88+
89+ -- *** To Containers
71 , toList
90 , toList
72
91
73− -- ** Folds
92+ -- *** Unfolds
74− , writeWith
93+ , producer -- experimental
75− , writeN
94+ , readerUnsafe
76− , pinnedWriteN
95+ , reader
77− , writeNUnsafe
96+ , readerRev
78− , pinnedWriteNUnsafe
97+
79− , MA.ArrayUnsafe (..)
98+ -- *** Size
80− , pinnedWriteNAligned
99+ , length
81− , write
100+ , byteLength
82− , pinnedWrite
101+
83− , unsafeMakePure
102+ -- ** Folding
103+ , foldl'
104+ , foldr
84 , byteCmp
105 , byteCmp
85 , byteEq
106 , byteEq
86
107
108+ -- ** Appending
109+ , splice -- XXX requires MonadIO
110+
87 -- ** Streams of arrays
111 -- ** Streams of arrays
112+ -- *** Chunk
113+ -- | Group a stream into arrays.
88 , chunksOf
114 , chunksOf
89 , pinnedChunksOf
115 , pinnedChunksOf
90 , buildChunks
116 , buildChunks
91− , concatChunks
117+
92− , concatChunksRev
118+ -- *** Split
119+ -- | Split an array into slices.
120+
121+ -- *** Concat
122+ -- | Append the arrays in a stream to form a stream of elements.
123+ , concat
124+ , concatRev
125+
126+ -- *** Compact
127+ -- | Append the arrays in a stream to form a stream of larger arrays.
128+ , fCompactGE
129+ , fPinnedCompactGE
130+ , lCompactGE
131+ , lPinnedCompactGE
132+ , compactGE
93
133
94 -- ** Deprecated
134 -- ** Deprecated
135+ , asPtrUnsafe
95 , unsafeIndex
136 , unsafeIndex
96 , bufferChunks
137 , bufferChunks
97 , flattenArrays
138 , flattenArrays
@@ -103,6 +144,15 @@ module Streamly.Internal.Data.Array.Type
103 , toStreamDRev
144 , toStreamDRev
104 , toStream
145 , toStream
105 , toStreamRev
146 , toStreamRev
147+ , nil
148+ , writeWith
149+ , writeN
150+ , pinnedWriteN
151+ , writeNUnsafe
152+ , pinnedWriteNUnsafe
153+ , pinnedWriteNAligned
154+ , write
155+ , pinnedWrite
106 )
156 )
107where
157where
108
158
@@ -121,6 +171,7 @@ import GHC.Exts (IsList, IsString(..), Addr#)
121
171
122import GHC.IO (unsafePerformIO)
172import GHC.IO (unsafePerformIO)
123import GHC.Ptr (Ptr(..))
173import GHC.Ptr (Ptr(..))
174+import Streamly.Internal.Data.Producer.Type (Producer(..))
124import Streamly.Internal.Data.MutArray.Type (MutArray(..))
175import Streamly.Internal.Data.MutArray.Type (MutArray(..))
125import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
176import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
126import Streamly.Internal.Data.Fold.Type (Fold(..))
177import Streamly.Internal.Data.Fold.Type (Fold(..))
@@ -130,13 +181,15 @@ import Streamly.Internal.Data.Unbox (Unbox(..))
130import Streamly.Internal.Data.Unfold.Type (Unfold(..))
181import Streamly.Internal.Data.Unfold.Type (Unfold(..))
131import Text.Read (readPrec)
182import Text.Read (readPrec)
132
183
133−import Prelude hiding (Foldable(..), read, unlines, splitAt)
184+import Prelude hiding (Foldable(..), concat, read, unlines, splitAt)
134
185
135import qualified GHC.Exts as Exts
186import qualified GHC.Exts as Exts
187+import qualified Streamly.Internal.Data.Fold.Type as Fold
136import qualified Streamly.Internal.Data.MutArray.Type as MA
188import qualified Streamly.Internal.Data.MutArray.Type as MA
137import qualified Streamly.Internal.Data.Stream.Type as D
189import qualified Streamly.Internal.Data.Stream.Type as D
138import qualified Streamly.Internal.Data.StreamK.Type as K
190import qualified Streamly.Internal.Data.StreamK.Type as K
139import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
191import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
192+import qualified Streamly.Internal.Data.Producer as Producer
140import qualified Streamly.Internal.Data.Unfold.Type as Unfold
193import qualified Streamly.Internal.Data.Unfold.Type as Unfold
141import qualified Text.ParserCombinators.ReadPrec as ReadPrec
194import qualified Text.ParserCombinators.ReadPrec as ReadPrec
142
195
@@ -190,15 +243,20 @@ data Array a =
190
243
191-- | Use an @Array a@ as @Ptr a@.
244-- | Use an @Array a@ as @Ptr a@.
192--
245--
193−-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
246+-- See 'MA.unsafePinnedAsPtr' in the Mutable array module for more details.
194--
247--
195-- /Unsafe/
248-- /Unsafe/
196--
249--
197-- /Pre-release/
250-- /Pre-release/
198--
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." #-}
199{-# INLINE asPtrUnsafe #-}
257{-# INLINE asPtrUnsafe #-}
200asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
258asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
201−asPtrUnsafe arr = MA.asPtrUnsafe (unsafeThaw arr)
259+asPtrUnsafe = unsafePinnedAsPtr
202
260
203-------------------------------------------------------------------------------
261-------------------------------------------------------------------------------
204-- Freezing and Thawing
262-- Freezing and Thawing
@@ -414,37 +472,100 @@ pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
414 => Int -> D.Stream m a -> D.Stream m (Array a)
472 => Int -> D.Stream m a -> D.Stream m (Array a)
415pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
473pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
416
474
417−-- | Use the "reader" unfold instead.
475+-- | Convert a stream of arrays into a stream of their elements.
418−--
419−-- @concatChunks = unfoldMany reader@
420--
476--
421−-- We can try this if there are any fusion issues in the unfold.
477+-- >>> concat = Stream.unfoldMany Array.reader
422--
478--
423−{-# INLINE_NORMAL concatChunks #-}
479+{-# INLINE_NORMAL concat #-}
424−concatChunks :: forall m a. (MonadIO m, Unbox a)
425− => D.Stream m (Array a) -> D.Stream m a
480+concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
426−concatChunks = MA.concatChunks . D.map unsafeThaw
481+-- XXX this requires MonadIO whereas the unfoldMany version does not
482+concat = MA.concatWith (pure . unsafeInlineIO) . D.map unsafeThaw
483+-- concat = D.unfoldMany reader
427
484
428{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
485{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
486+{-# INLINE flattenArrays #-}
429flattenArrays :: forall m a. (MonadIO m, Unbox a)
487flattenArrays :: forall m a. (MonadIO m, Unbox a)
430 => D.Stream m (Array a) -> D.Stream m a
488 => D.Stream m (Array a) -> D.Stream m a
431−flattenArrays = concatChunks
489+flattenArrays = concat
432
490
433−-- | Use the "readerRev" unfold instead.
491+-- | Convert a stream of arrays into a stream of their elements reversing the
434−--
492+-- contents of each array before flattening.
435−-- @concatChunksRev = unfoldMany readerRev@
436--
493--
437−-- We can try this if there are any fusion issues in the unfold.
494+-- >>> concatRev = Stream.unfoldMany Array.readerRev
438--
495--
439−{-# INLINE_NORMAL concatChunksRev #-}
496+{-# INLINE_NORMAL concatRev #-}
440−concatChunksRev :: forall m a. (MonadIO m, Unbox a)
497+concatRev :: forall m a. (Monad m, Unbox a)
441 => D.Stream m (Array a) -> D.Stream m a
498 => D.Stream m (Array a) -> D.Stream m a
442−concatChunksRev = MA.concatChunksRev . D.map unsafeThaw
499+-- XXX this requires MonadIO whereas the unfoldMany version does not
500+concatRev = MA.concatRevWith (pure . unsafeInlineIO) . D.map unsafeThaw
501+-- concatRev = D.unfoldMany readerRev
443
502
444{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
503{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
504+{-# INLINE flattenArraysRev #-}
445flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
505flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
446 => D.Stream m (Array a) -> D.Stream m a
506 => D.Stream m (Array a) -> D.Stream m a
447−flattenArraysRev = concatChunksRev
507+flattenArraysRev = concatRev
508+
509+-------------------------------------------------------------------------------
510+-- Compact
511+-------------------------------------------------------------------------------
512+
513+-- XXX Note that this thaws immutable arrays for appending, that may be
514+-- problematic if multiple users do the same thing, however, thawed immutable
515+-- arrays would have no capacity to append, therefore, a copy will be forced
516+-- anyway.
517+
518+-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
519+-- until the size becomes greater than or equal to n.
520+--
521+-- Generates unpinned arrays irrespective of the pinning status of input
522+-- arrays.
523+{-# INLINE_NORMAL fCompactGE #-}
524+fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
525+fCompactGE n = fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fCompactGE n
526+
527+-- | PInned version of 'fCompactGE'.
528+{-# INLINE_NORMAL fPinnedCompactGE #-}
529+fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
530+fPinnedCompactGE n =
531+ fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fPinnedCompactGE n
532+
533+-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
534+-- the size becomes greater than or equal to @n@.
535+--
536+-- >>> compactGE n = Stream.foldMany (Array.fCompactGE n)
537+--
538+-- Generates unpinned arrays irrespective of the pinning status of input
539+-- arrays.
540+{-# INLINE compactGE #-}
541+compactGE ::
542+ (MonadIO m, Unbox a)
543+ => Int -> Stream m (Array a) -> Stream m (Array a)
544+compactGE n stream =
545+ D.map unsafeFreeze $ MA.compactGE n $ D.map unsafeThaw stream
546+
547+-- | Like 'compactGE' but for transforming folds instead of stream.
548+--
549+-- >>> lCompactGE n = Fold.many (Array.fCompactGE n)
550+--
551+-- Generates unpinned arrays irrespective of the pinning status of input
552+-- arrays.
553+{-# INLINE_NORMAL lCompactGE #-}
554+lCompactGE :: (MonadIO m, Unbox a)
555+ => Int -> Fold m (Array a) () -> Fold m (Array a) ()
556+lCompactGE n fld =
557+ Fold.lmap unsafeThaw $ MA.lCompactGE n (Fold.lmap unsafeFreeze fld)
558+
559+-- | Pinned version of 'lCompactGE'.
560+{-# INLINE_NORMAL lPinnedCompactGE #-}
561+lPinnedCompactGE :: (MonadIO m, Unbox a)
562+ => Int -> Fold m (Array a) () -> Fold m (Array a) ()
563+lPinnedCompactGE n fld =
564+ Fold.lmap unsafeThaw $ MA.lPinnedCompactGE n (Fold.lmap unsafeFreeze fld)
565+
566+-------------------------------------------------------------------------------
567+-- Splitting
568+-------------------------------------------------------------------------------
448
569
449-- Drops the separator byte
570-- Drops the separator byte
450{-# INLINE breakOn #-}
571{-# INLINE breakOn #-}
@@ -488,6 +609,49 @@ byteLength = MA.byteLength . unsafeThaw
488length :: Unbox a => Array a -> Int
609length :: Unbox a => Array a -> Int
489length arr = MA.length (unsafeThaw arr)
610length arr = MA.length (unsafeThaw arr)
490
611
612+{-# INLINE_NORMAL producer #-}
613+producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
614+producer =
615+ Producer.translate unsafeThaw unsafeFreeze
616+ $ MA.producerWith (return . unsafeInlineIO)
617+
618+-- | Unfold an array into a stream.
619+--
620+{-# INLINE_NORMAL reader #-}
621+reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
622+reader = Producer.simplify producer
623+
624+-- | Unfold an array into a stream, does not check the end of the array, the
625+-- user is responsible for terminating the stream within the array bounds. For
626+-- high performance application where the end condition can be determined by
627+-- a terminating fold.
628+--
629+-- Written in the hope that it may be faster than "read", however, in the case
630+-- for which this was written, "read" proves to be faster even though the core
631+-- generated with unsafeRead looks simpler.
632+--
633+-- /Pre-release/
634+--
635+{-# INLINE_NORMAL readerUnsafe #-}
636+readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
637+readerUnsafe = Unfold step inject
638+ where
639+
640+ inject (Array contents start end) =
641+ return (MA.ArrayUnsafe contents end start)
642+
643+ {-# INLINE_LATE step #-}
644+ step (MA.ArrayUnsafe contents end p) = do
645+ -- unsafeInlineIO allows us to run this in Identity monad for pure
646+ -- toList/foldr case which makes them much faster due to not
647+ -- accumulating the list and fusing better with the pure consumers.
648+ --
649+ -- This should be safe as the array contents are guaranteed to be
650+ -- evaluated/written to before we peek at them.
651+ let !x = unsafeInlineIO $ peekAt p contents
652+ let !p1 = INDEX_NEXT(p,a)
653+ return $ D.Yield x (MA.ArrayUnsafe contents end p1)
654+
491-- | Unfold an array into a stream in reverse order.
655-- | Unfold an array into a stream in reverse order.
492--
656--
493{-# INLINE_NORMAL readerRev #-}
657{-# INLINE_NORMAL readerRev #-}
@@ -593,17 +757,28 @@ toList s = build (\c n -> toListFB c n s)
593-- Folds
757-- Folds
594-------------------------------------------------------------------------------
758-------------------------------------------------------------------------------
595
759
596−-- | @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
597-- 'Array'.
761-- 'Array'.
598--
762--
599−{-# 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 #-}
600writeN :: 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)
601−writeN = fmap unsafeFreeze . MA.writeN
771+writeN = createOf
602
772
603−-- | 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." #-}
604−{-# INLINE_NORMAL pinnedWriteN #-}
779+{-# INLINE pinnedWriteN #-}
605pinnedWriteN :: 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)
606−pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
781+pinnedWriteN = pinnedCreateOf
607
782
608-- | @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
609-- stream to an 'Array' aligned to the given size.
784-- stream to an 'Array' aligned to the given size.
@@ -611,44 +786,74 @@ pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
611-- /Pre-release/
786-- /Pre-release/
612--
787--
613{-# INLINE_NORMAL pinnedWriteNAligned #-}
788{-# INLINE_NORMAL pinnedWriteNAligned #-}
789+{-# DEPRECATED pinnedWriteNAligned "To be removed." #-}
614pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
790pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
615 => Int -> Int -> Fold m a (Array a)
791 => Int -> Int -> Fold m a (Array a)
616pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
792pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
617
793
618−-- | 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
619-- 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
620-- corrupt the memory and crash. This function exists mainly because any
796-- corrupt the memory and crash. This function exists mainly because any
621-- conditional in the step function blocks fusion causing 10x performance
797-- conditional in the step function blocks fusion causing 10x performance
622-- slowdown.
798-- slowdown.
623--
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." #-}
624−{-# INLINE_NORMAL writeNUnsafe #-}
806+{-# INLINE writeNUnsafe #-}
625writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
807writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
626 => Int -> Fold m a (Array a)
808 => Int -> Fold m a (Array a)
627−writeNUnsafe n = unsafeFreeze <$> MA.writeNUnsafe n
809+writeNUnsafe = unsafeCreateOf
628
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
815+
816+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
629−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
817+{-# INLINE pinnedWriteNUnsafe #-}
630pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
818pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
631 => Int -> Fold m a (Array a)
819 => Int -> Fold m a (Array a)
632−pinnedWriteNUnsafe n = unsafeFreeze <$> MA.pinnedWriteNUnsafe n
820+pinnedWriteNUnsafe = unsafePinnedCreateOf
821+
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
633
827
828+{-# DEPRECATED writeWith "Please use createWith instead." #-}
634−{-# INLINE_NORMAL writeWith #-}
829+{-# INLINE writeWith #-}
635writeWith :: forall m a. (MonadIO m, Unbox a)
830writeWith :: forall m a. (MonadIO m, Unbox a)
636 => Int -> Fold m a (Array a)
831 => Int -> Fold m a (Array a)
637−-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
832+writeWith = createWith
638−writeWith elemCount = unsafeFreeze <$> MA.writeWith elemCount
639
833
640-- | Fold the whole input to a single array.
834-- | Fold the whole input to a single array.
641--
835--
642-- /Caution! Do not use this on infinite streams./
836-- /Caution! Do not use this on infinite streams./
643--
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." #-}
644{-# INLINE write #-}
844{-# INLINE write #-}
645write :: 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)
846+write = create
847+
848+-- | Like 'create' but creates a pinned array.
849+{-# INLINE pinnedCreate #-}
850+pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
646−write = fmap unsafeFreeze MA.write
851+pinnedCreate = fmap unsafeFreeze MA.pinnedCreate
647
852
648−-- | Like 'write' but creates a pinned array.
853+{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
649{-# INLINE pinnedWrite #-}
854{-# INLINE pinnedWrite #-}
650pinnedWrite :: 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)
651−pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
856+pinnedWrite = pinnedCreate
652
857
653-- | 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
654-- the previous invocation of step due to state passing, finally extract
859-- the previous invocation of step due to state passing, finally extract
@@ -696,13 +901,19 @@ fromPureStream x = unsafePerformIO $ fmap (unsafeFreeze) (MA.fromPureStream x)
696-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
901-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
697-- fromPureStream = fromList . runIdentity . D.toList
902-- fromPureStream = fromList . runIdentity . D.toList
698
903
904+-- XXX This should be monadic.
905+
699-- | Copy an immutable 'Ptr Word8' sequence into an array.
906-- | Copy an immutable 'Ptr Word8' sequence into an array.
700--
907--
701-- /Unsafe:/ The caller is responsible for safe addressing.
908-- /Unsafe:/ The caller is responsible for safe addressing.
702--
909--
910+-- Note that this should be evaluated strictly to ensure that we do not hold
911+-- the reference to the pointer in a lazy thunk.
703fromPtrN :: Int -> Ptr Word8 -> Array Word8
912fromPtrN :: Int -> Ptr Word8 -> Array Word8
704fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
913fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
705
914
915+-- XXX This should be monadic.
916+
706-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
917-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
707--
918--
708-- /Unsafe:/ The caller is responsible for safe addressing.
919-- /Unsafe:/ The caller is responsible for safe addressing.
@@ -713,9 +924,15 @@ fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
713-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
924-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
714-- [1,2,3]
925-- [1,2,3]
715--
926--
927+-- Note that this should be evaluated strictly to ensure that we do not hold
928+-- the reference to the pointer in a lazy thunk.
716fromByteStr# :: Addr# -> Array Word8
929fromByteStr# :: Addr# -> Array Word8
717fromByteStr# addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromByteStr# addr)
930fromByteStr# addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromByteStr# addr)
718
931
932+-- XXX This should be monadic.
933+
934+-- | Note that this should be evaluated strictly to ensure that we do not hold
935+-- the reference to the pointer in a lazy thunk.
719fromByteStr :: Ptr Word8 -> Array Word8
936fromByteStr :: Ptr Word8 -> Array Word8
720fromByteStr (Ptr addr#) = fromByteStr# addr#
937fromByteStr (Ptr addr#) = fromByteStr# addr#
721
938
@@ -725,14 +942,29 @@ fromByteStr (Ptr addr#) = fromByteStr# addr#
725-- that is double the size of the array stream.
942-- that is double the size of the array stream.
726--
943--
727{-# INLINE fromChunksK #-}
944{-# INLINE fromChunksK #-}
728−fromChunksK :: (Unbox a, MonadIO m) => StreamK m (Array a) -> m (Array a)
945+fromChunksK :: (MonadIO m, Unbox a) => StreamK m (Array a) -> m (Array a)
729fromChunksK stream =
946fromChunksK stream =
947+ -- We buffer the entire stream and then allocate the target array of the
948+ -- same size, thus requiring double the memory.
730 fmap unsafeFreeze $ MA.fromChunksK $ fmap unsafeThaw stream
949 fmap unsafeFreeze $ MA.fromChunksK $ fmap unsafeThaw stream
731
950
732{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
951{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
733fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (Array a) -> m (Array a)
952fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (Array a) -> m (Array a)
734fromArrayStreamK = fromChunksK
953fromArrayStreamK = fromChunksK
735
954
955+-- | Given a stream of arrays, splice them all together to generate a single
956+-- array. The stream must be /finite/.
957+--
958+{-# INLINE fromChunks #-}
959+fromChunks :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
960+fromChunks s =
961+ -- XXX Check which implementation is better
962+ -- This may also require double the memory as we double the space every
963+ -- time, when copying the last array we may have reallocated almost double
964+ -- the space required before we right size it.
965+ fmap unsafeFreeze $ MA.fromChunksRealloced (fmap unsafeThaw s)
966+ -- fromChunkStreamK $ D.toStreamK s
967+
736-------------------------------------------------------------------------------
968-------------------------------------------------------------------------------
737-- Instances
969-- Instances
738-------------------------------------------------------------------------------
970-------------------------------------------------------------------------------
@@ -775,6 +1007,7 @@ instance Unbox a => IsList (Array a) where
775{-# INLINE byteCmp #-}
1007{-# INLINE byteCmp #-}
776byteCmp :: Array a -> Array a -> Ordering
1008byteCmp :: Array a -> Array a -> Ordering
777byteCmp arr1 arr2 =
1009byteCmp arr1 arr2 =
1010+ -- unsafePerformIO?
778 unsafeInlineIO $! unsafeThaw arr1 `MA.byteCmp` unsafeThaw arr2
1011 unsafeInlineIO $! unsafeThaw arr1 `MA.byteCmp` unsafeThaw arr2
779
1012
780-- | Byte equality of two arrays.
1013-- | Byte equality of two arrays.
@@ -796,20 +1029,21 @@ MK_EQ_INSTANCE(Char)
796MK_EQ_INSTANCE(Word8)
1029MK_EQ_INSTANCE(Word8)
797MK_EQ_INSTANCE(Word16)
1030MK_EQ_INSTANCE(Word16)
798MK_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.
799MK_EQ_INSTANCE(Word64)
1035MK_EQ_INSTANCE(Word64)
800MK_EQ_INSTANCE(Int)
1036MK_EQ_INSTANCE(Int)
801MK_EQ_INSTANCE(Int8)
1037MK_EQ_INSTANCE(Int8)
802MK_EQ_INSTANCE(Int16)
1038MK_EQ_INSTANCE(Int16)
803MK_EQ_INSTANCE(Int32)
1039MK_EQ_INSTANCE(Int32)
1040+
1041+-- XXX The Int64 default instance should be as fast.
804MK_EQ_INSTANCE(Int64)
1042MK_EQ_INSTANCE(Int64)
805
1043
806−-- | If the type allows a byte-by-byte comparison (see 'byteCmp') this instance
1044+-- | If the type allows a byte-by-byte comparison this instance can be
807−-- can be overlapped by a more specific instance that uses a byte comparison.
1045+-- overlapped by a more specific instance that uses 'byteCmp'. Byte comparison
808−-- Byte comparison can be significantly faster.
1046+-- can be significantly faster.
809−--
810−-- For example:
811−--
812−-- >>> (==) = byteCmp
813--
1047--
814instance {-# OVERLAPPABLE #-} (Unbox a, Eq a) => Eq (Array a) where
1048instance {-# OVERLAPPABLE #-} (Unbox a, Eq a) => Eq (Array a) where
815 {-# INLINE (==) #-}
1049 {-# INLINE (==) #-}
@@ -894,12 +1128,20 @@ instance Foldable Array where
894instance Unbox a => Semigroup (Array a) where
1128instance Unbox a => Semigroup (Array a) where
895 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
1129 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
896
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." #-}
897nil ::
1139nil ::
898#ifdef DEVBUILD
1140#ifdef DEVBUILD
899 Unbox a =>
1141 Unbox a =>
900#endif
1142#endif
901 Array a
1143 Array a
902−nil = Array Unboxed.nil 0 0
1144+nil = empty
903
1145
904instance Unbox a => Monoid (Array a) where
1146instance Unbox a => Monoid (Array a) where
905 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+128
@@ -13,6 +13,10 @@ module Streamly.Internal.Data.MutArray
13 -- * MutArray module
13 -- * MutArray module
14 , sliceIndexerFromLen
14 , sliceIndexerFromLen
15 , slicerFromLen
15 , slicerFromLen
16+ , compactLE
17+ , pinnedCompactLE
18+ , compactOnByte
19+ , compactOnByteSuffix
16 -- * Unboxed IORef
20 -- * Unboxed IORef
17 , module Streamly.Internal.Data.IORef.Unboxed
21 , module Streamly.Internal.Data.IORef.Unboxed
18
22
@@ -24,9 +28,16 @@ where
24
28
25#include "inline.hs"
29#include "inline.hs"
26
30
31+import Control.Monad.IO.Class (MonadIO(..))
32+import Data.Word (Word8)
33+import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
34+import Streamly.Internal.Data.Stream.Type (Stream)
27import Streamly.Internal.Data.Unbox (Unbox)
35import Streamly.Internal.Data.Unbox (Unbox)
28import Streamly.Internal.Data.Unfold.Type (Unfold(..))
36import Streamly.Internal.Data.Unfold.Type (Unfold(..))
29
37
38+import qualified Streamly.Internal.Data.Stream.Type as Stream
39+import qualified Streamly.Internal.Data.Stream.Nesting as Stream
40+-- import qualified Streamly.Internal.Data.Stream.Transform as Stream
30import qualified Streamly.Internal.Data.Unfold as Unfold
41import qualified Streamly.Internal.Data.Unfold as Unfold
31
42
32import Prelude hiding (foldr, length, read, splitAt)
43import Prelude hiding (foldr, length, read, splitAt)
@@ -77,3 +88,120 @@ getSlicesFromLen :: forall m a. (Monad m, Unbox a)
77 -> Int -- ^ length of the slice
88 -> Int -- ^ length of the slice
78 -> Unfold m (MutArray a) (MutArray a)
89 -> Unfold m (MutArray a) (MutArray a)
79getSlicesFromLen = slicerFromLen
90getSlicesFromLen = slicerFromLen
91+
92+-------------------------------------------------------------------------------
93+-- Compacting Streams of Arrays
94+-------------------------------------------------------------------------------
95+
96+-- | @compactLE maxElems@ coalesces adjacent arrays in the input stream
97+-- only if the combined size would be less than or equal to @maxElems@
98+-- elements. Note that it won't split an array if the original array is already
99+-- larger than maxElems.
100+--
101+-- @maxElems@ must be greater than 0.
102+--
103+-- Generates unpinned arrays irrespective of the pinning status of input
104+-- arrays.
105+{-# INLINE compactLE #-}
106+compactLE :: (MonadIO m, Unbox a) =>
107+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
108+-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
109+-- to implement it.
110+compactLE = compactLeAs Unpinned
111+-- The parser version turns out to be a little bit slower.
112+-- compactLE n = Stream.catRights . Stream.parseManyD (pCompactLE n)
113+
114+-- | Pinned version of 'compactLE'.
115+{-# INLINE pinnedCompactLE #-}
116+pinnedCompactLE :: forall m a. (MonadIO m, Unbox a)
117+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
118+pinnedCompactLE = compactLeAs Pinned
119+-- pinnedCompactLE n = Stream.catRights . Stream.parseManyD (pPinnedCompactLE n)
120+
121+data SplitState s arr
122+ = Initial s
123+ | Buffering s arr
124+ | Splitting s arr
125+ | Yielding arr (SplitState s arr)
126+ | Finishing
127+
128+-- | Split a stream of arrays on a given separator byte, dropping the separator
129+-- and coalescing all the arrays between two separators into a single array.
130+--
131+{-# INLINE_NORMAL _compactOnByteCustom #-}
132+_compactOnByteCustom
133+ :: MonadIO m
134+ => Word8
135+ -> Stream m (MutArray Word8)
136+ -> Stream m (MutArray Word8)
137+_compactOnByteCustom byte (Stream.Stream step state) =
138+ Stream.Stream step' (Initial state)
139+
140+ where
141+
142+ {-# INLINE_LATE step' #-}
143+ step' gst (Initial st) = do
144+ r <- step gst st
145+ case r of
146+ Stream.Yield arr s -> do
147+ (arr1, marr2) <- breakOn byte arr
148+ return $ case marr2 of
149+ Nothing -> Stream.Skip (Buffering s arr1)
150+ Just arr2 -> Stream.Skip (Yielding arr1 (Splitting s arr2))
151+ Stream.Skip s -> return $ Stream.Skip (Initial s)
152+ Stream.Stop -> return Stream.Stop
153+
154+ step' gst (Buffering st buf) = do
155+ r <- step gst st
156+ case r of
157+ Stream.Yield arr s -> do
158+ (arr1, marr2) <- breakOn byte arr
159+ -- XXX Use spliceExp instead and then rightSize?
160+ buf1 <- splice buf arr1
161+ return $ case marr2 of
162+ Nothing -> Stream.Skip (Buffering s buf1)
163+ Just x -> Stream.Skip (Yielding buf1 (Splitting s x))
164+ Stream.Skip s -> return $ Stream.Skip (Buffering s buf)
165+ Stream.Stop -> return $
166+ if byteLength buf == 0
167+ then Stream.Stop
168+ else Stream.Skip (Yielding buf Finishing)
169+
170+ step' _ (Splitting st buf) = do
171+ (arr1, marr2) <- breakOn byte buf
172+ return $ case marr2 of
173+ Nothing -> Stream.Skip $ Buffering st arr1
174+ Just arr2 -> Stream.Skip $ Yielding arr1 (Splitting st arr2)
175+
176+ step' _ (Yielding arr next) = return $ Stream.Yield arr next
177+ step' _ Finishing = return Stream.Stop
178+
179+-- XXX implement predicate based version of this
180+-- XXX Naming of predicate based vs custom version
181+
182+-- | Split a stream of arrays on a given separator byte, dropping the separator
183+-- and coalescing all the arrays between two separators into a single array.
184+--
185+{-# INLINE compactOnByte #-}
186+compactOnByte
187+ :: (MonadIO m)
188+ => Word8
189+ -> Stream m (MutArray Word8)
190+ -> Stream m (MutArray Word8)
191+-- XXX compare perf of custom vs idiomatic version
192+-- compactOnByte = _compactOnByteCustom
193+-- XXX use spliceExp and rightSize?
194+compactOnByte byte = Stream.splitInnerBy (breakOn byte) splice
195+
196+-- | Like 'compactOnByte' considers the separator in suffix position instead of
197+-- infix position.
198+{-# INLINE compactOnByteSuffix #-}
199+compactOnByteSuffix
200+ :: (MonadIO m)
201+ => Word8
202+ -> Stream m (MutArray Word8)
203+ -> Stream m (MutArray Word8)
204+compactOnByteSuffix byte =
205+ -- XXX use spliceExp and rightSize?
206+ Stream.splitInnerBySuffix
207+ (\arr -> byteLength arr == 0) (breakOn byte) splice
core/src/Streamly/Internal/Data/MutArray/Generic.hs+65−30
@@ -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-- |
@@ -318,7 +331,7 @@ putIndices arr = FL.foldlM' step (return ())
318
331
319 where
332 where
320
333
321− step () (i, x) = liftIO (putIndex i arr x)
334+ step () (i, x) = putIndex i arr x
322
335
323-- | Modify a given index of an array using a modifier function without checking
336-- | Modify a given index of an array using a modifier function without checking
324-- the bounds.
337-- the bounds.
@@ -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,59 +619,81 @@ 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− liftIO $ new elemCount
663+ new elemCount
640
664
641 step arr@(MutArray _ start end bound) x
665 step arr@(MutArray _ start end bound) x
642 | end == bound = do
666 | end == bound = do
643 let oldSize = end - start
667 let oldSize = end - start
644 newSize = max (oldSize * 2) 1
668 newSize = max (oldSize * 2) 1
645− arr1 <- liftIO $ realloc newSize arr
669+ arr1 <- realloc newSize arr
646 snocUnsafe arr1 x
670 snocUnsafe arr1 x
647 step arr x = snocUnsafe arr x
671 step arr x = snocUnsafe arr x
648
672
649− -- extract = liftIO . 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@
@@ -683,7 +718,7 @@ fromList xs = fromStream $ D.fromList xs
683{-# INLINABLE fromPureStream #-}
718{-# INLINABLE fromPureStream #-}
684fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
719fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
685fromPureStream xs =
720fromPureStream xs =
686− liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
721+ D.fold write $ D.morphInner (return . runIdentity) xs
687
722
688-------------------------------------------------------------------------------
723-------------------------------------------------------------------------------
689-- Chunking
724-- Chunking
@@ -815,7 +850,7 @@ putSliceUnsafe src srcStart dst dstStart len = liftIO $ do
815
850
816{-# INLINE clone #-}
851{-# INLINE clone #-}
817clone :: MonadIO m => MutArray a -> m (MutArray a)
852clone :: MonadIO m => MutArray a -> m (MutArray a)
818−clone src = liftIO $ do
853+clone src = do
819 let len = arrLen src
854 let len = arrLen src
820 dst <- new len
855 dst <- new len
821 putSliceUnsafe src 0 dst 0 len
856 putSliceUnsafe src 0 dst 0 len
core/src/Streamly/Internal/Data/MutArray/Stream.hs+11−195
@@ -12,6 +12,7 @@
12-- keep this as a separate module and release it.
12-- keep this as a separate module and release it.
13--
13--
14module Streamly.Internal.Data.MutArray.Stream
14module Streamly.Internal.Data.MutArray.Stream
15+{-# DEPRECATED "Please use \"Streamly.Internal.Data.MutArray\" instead." #-}
15 (
16 (
16 -- * Generation
17 -- * Generation
17 MArray.chunksOf
18 MArray.chunksOf
@@ -21,7 +22,7 @@ module Streamly.Internal.Data.MutArray.Stream
21
22
22 -- * Compaction
23 -- * Compaction
23 , packArraysChunksOf
24 , packArraysChunksOf
24− , SpliceState (..)
25+ , MArray.SpliceState (..)
25 , lpackArraysChunksOf
26 , lpackArraysChunksOf
26 , compact -- chunksCompact
27 , compact -- chunksCompact
27 , compactLE
28 , compactLE
@@ -35,19 +36,12 @@ module Streamly.Internal.Data.MutArray.Stream
35 )
36 )
36where
37where
37
38
38−#include "inline.hs"
39−#include "ArrayMacros.h"
40−
41import Control.Monad.IO.Class (MonadIO(..))
39import Control.Monad.IO.Class (MonadIO(..))
42−import Control.Monad (when)
43−import Data.Bifunctor (first)
44−import Data.Proxy (Proxy(..))
45−import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
40+import Streamly.Internal.Data.Unbox (Unbox)
46import Streamly.Internal.Data.MutArray.Type (MutArray(..))
41import Streamly.Internal.Data.MutArray.Type (MutArray(..))
47import Streamly.Internal.Data.Fold.Type (Fold(..))
42import Streamly.Internal.Data.Fold.Type (Fold(..))
48import Streamly.Internal.Data.Parser (ParseError)
43import Streamly.Internal.Data.Parser (ParseError)
49import Streamly.Internal.Data.Stream.Type (Stream)
44import Streamly.Internal.Data.Stream.Type (Stream)
50−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
51
45
52import qualified Streamly.Internal.Data.MutArray as MArray
46import qualified Streamly.Internal.Data.MutArray as MArray
53import qualified Streamly.Internal.Data.Fold.Type as FL
47import qualified Streamly.Internal.Data.Fold.Type as FL
@@ -58,12 +52,6 @@ import qualified Streamly.Internal.Data.Stream as D
58-- Compact
52-- Compact
59-------------------------------------------------------------------------------
53-------------------------------------------------------------------------------
60
54
61−data SpliceState s arr
62− = SpliceInitial s
63− | SpliceBuffering s arr
64− | SpliceYielding arr (SpliceState s arr)
65− | SpliceFinish
66−
67-- XXX This can be removed once compactLEFold/compactLE are implemented.
55-- XXX This can be removed once compactLEFold/compactLE are implemented.
68--
56--
69-- | This mutates the first array (if it has space) to append values from the
57-- | This mutates the first array (if it has space) to append values from the
@@ -78,117 +66,18 @@ data SpliceState s arr
78-- actual array size may be less than the specified chunk size.
66-- actual array size may be less than the specified chunk size.
79--
67--
80-- @since 0.7.0
68-- @since 0.7.0
81−{-# INLINE_NORMAL packArraysChunksOf #-}
69+{-# INLINE packArraysChunksOf #-}
82packArraysChunksOf :: (MonadIO m, Unbox a)
70packArraysChunksOf :: (MonadIO m, Unbox a)
83 => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
71 => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
84−packArraysChunksOf n (D.Stream step state) =
72+packArraysChunksOf = MArray.compactLE
85− D.Stream step' (SpliceInitial state)
86−
87− where
88−
89− {-# INLINE_LATE step' #-}
90− step' gst (SpliceInitial st) = do
91− when (n <= 0) $
92− -- XXX we can pass the module string from the higher level API
93− error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
94− ++ "arrays [" ++ show n ++ "] must be a natural number"
95− r <- step gst st
96− case r of
97− D.Yield arr s -> return $
98− let len = MArray.byteLength arr
99− in if len >= n
100− then D.Skip (SpliceYielding arr (SpliceInitial s))
101− else D.Skip (SpliceBuffering s arr)
102− D.Skip s -> return $ D.Skip (SpliceInitial s)
103− D.Stop -> return D.Stop
104−
105− step' gst (SpliceBuffering st buf) = do
106− r <- step gst st
107− case r of
108− D.Yield arr s -> do
109− let len = MArray.byteLength buf + MArray.byteLength arr
110− if len > n
111− then return $
112− D.Skip (SpliceYielding buf (SpliceBuffering s arr))
113− else do
114− buf' <- if MArray.byteCapacity buf < n
115− then liftIO $ MArray.realloc n buf
116− else return buf
117− buf'' <- MArray.spliceUnsafe buf' arr
118− return $ D.Skip (SpliceBuffering s buf'')
119− D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
120− D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
121−
122− step' _ SpliceFinish = return D.Stop
123−
124− step' _ (SpliceYielding arr next) = return $ D.Yield arr next
125
73
126-- XXX Remove this once compactLEFold is implemented
74-- XXX Remove this once compactLEFold is implemented
127-- lpackArraysChunksOf = Fold.many compactLEFold
75-- lpackArraysChunksOf = Fold.many compactLEFold
128--
76--
129−{-# INLINE_NORMAL lpackArraysChunksOf #-}
77+{-# INLINE lpackArraysChunksOf #-}
130lpackArraysChunksOf :: (MonadIO m, Unbox a)
78lpackArraysChunksOf :: (MonadIO m, Unbox a)
131 => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
79 => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
132−lpackArraysChunksOf n (Fold step1 initial1 _ final1) =
80+lpackArraysChunksOf = MArray.lCompactGE
133− Fold step initial extract final
134−
135− where
136−
137− initial = do
138− when (n <= 0) $
139− -- XXX we can pass the module string from the higher level API
140− error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
141− ++ "arrays [" ++ show n ++ "] must be a natural number"
142−
143− r <- initial1
144− return $ first (Tuple' Nothing) r
145−
146− step (Tuple' Nothing r1) arr =
147− let len = MArray.byteLength arr
148− in if len >= n
149− then do
150− r <- step1 r1 arr
151− case r of
152− FL.Done _ -> return $ FL.Done ()
153− FL.Partial s -> do
154− _ <- final1 s
155− res <- initial1
156− return $ first (Tuple' Nothing) res
157− else return $ FL.Partial $ Tuple' (Just arr) r1
158−
159− step (Tuple' (Just buf) r1) arr = do
160− let len = MArray.byteLength buf + MArray.byteLength arr
161− buf' <- if MArray.byteCapacity buf < len
162− then liftIO $ MArray.realloc (max n len) buf
163− else return buf
164− buf'' <- MArray.spliceUnsafe buf' arr
165−
166− -- XXX this is common in both the equations of step
167− if len >= n
168− then do
169− r <- step1 r1 buf''
170− case r of
171− FL.Done _ -> return $ FL.Done ()
172− FL.Partial s -> do
173− _ <- final1 s
174− res <- initial1
175− return $ first (Tuple' Nothing) res
176− else return $ FL.Partial $ Tuple' (Just buf'') r1
177−
178− -- XXX Several folds do extract >=> final, therefore, we need to make final
179− -- return "m b" rather than using extract post it if we want extract to be
180− -- partial.
181− --
182− -- extract forces the pending buffer to be sent to the fold which is not
183− -- what we want.
184− extract _ = error "lpackArraysChunksOf: not designed for scanning"
185−
186− final (Tuple' Nothing r1) = final1 r1
187− final (Tuple' (Just buf) r1) = do
188− r <- step1 r1 buf
189− case r of
190− FL.Partial rr -> final1 rr
191− FL.Done _ -> return ()
192
81
193-- XXX Same as compactLE, to be removed once that is implemented.
82-- XXX Same as compactLE, to be removed once that is implemented.
194--
83--
@@ -208,48 +97,11 @@ compact = packArraysChunksOf
208-- actual array size may be less than the specified chunk size.
97-- actual array size may be less than the specified chunk size.
209--
98--
210-- /Internal/
99-- /Internal/
211−{-# INLINE_NORMAL compactLEParserD #-}
100+{-# INLINE compactLEParserD #-}
212compactLEParserD ::
101compactLEParserD ::
213 forall m a. (MonadIO m, Unbox a)
102 forall m a. (MonadIO m, Unbox a)
214 => Int -> ParserD.Parser (MutArray a) m (MutArray a)
103 => Int -> ParserD.Parser (MutArray a) m (MutArray a)
215−compactLEParserD n = ParserD.Parser step initial extract
104+compactLEParserD = MArray.pCompactLE
216−
217− where
218−
219− nBytes = n * SIZE_OF(a)
220−
221− initial =
222− return
223− $ if n <= 0
224− then error
225− $ functionPath
226− ++ ": the size of arrays ["
227− ++ show n ++ "] must be a natural number"
228− else ParserD.IPartial Nothing
229−
230− step Nothing arr =
231− return
232− $ let len = MArray.byteLength arr
233− in if len >= nBytes
234− then ParserD.Done 0 arr
235− else ParserD.Partial 0 (Just arr)
236− step (Just buf) arr =
237− let len = MArray.byteLength buf + MArray.byteLength arr
238− in if len > nBytes
239− then return $ ParserD.Done 1 buf
240− else do
241− buf1 <-
242− if MArray.byteCapacity buf < nBytes
243− then liftIO $ MArray.realloc nBytes buf
244− else return buf
245− buf2 <- MArray.spliceUnsafe buf1 arr
246− return $ ParserD.Partial 0 (Just buf2)
247−
248− extract Nothing = return $ ParserD.Done 0 MArray.nil
249− extract (Just buf) = return $ ParserD.Done 0 buf
250−
251− functionPath =
252− "Streamly.Internal.Data.Stream.MutChunked.compactLEParserD"
253
105
254-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
106-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
255-- minimum specified size. Note that if all the arrays in the stream together
107-- minimum specified size. Note that if all the arrays in the stream together
@@ -258,47 +110,11 @@ compactLEParserD n = ParserD.Parser step initial extract
258-- the specified size we stop coalescing further.
110-- the specified size we stop coalescing further.
259--
111--
260-- /Internal/
112-- /Internal/
261−{-# INLINE_NORMAL compactGEFold #-}
113+{-# INLINE compactGEFold #-}
262compactGEFold ::
114compactGEFold ::
263 forall m a. (MonadIO m, Unbox a)
115 forall m a. (MonadIO m, Unbox a)
264 => Int -> FL.Fold m (MutArray a) (MutArray a)
116 => Int -> FL.Fold m (MutArray a) (MutArray a)
265−compactGEFold n = Fold step initial extract extract
117+compactGEFold = MArray.fCompactGE
266−
267− where
268−
269− nBytes = n * SIZE_OF(a)
270−
271− initial =
272− return
273− $ if n < 0
274− then error
275− $ functionPath
276− ++ ": the size of arrays ["
277− ++ show n ++ "] must be a natural number"
278− else FL.Partial Nothing
279−
280− step Nothing arr =
281− return
282− $ let len = MArray.byteLength arr
283− in if len >= nBytes
284− then FL.Done arr
285− else FL.Partial (Just arr)
286− step (Just buf) arr = do
287− let len = MArray.byteLength buf + MArray.byteLength arr
288− buf1 <-
289− if MArray.byteCapacity buf < len
290− then liftIO $ MArray.realloc (max len nBytes) buf
291− else return buf
292− buf2 <- MArray.spliceUnsafe buf1 arr
293− if len >= n
294− then return $ FL.Done buf2
295− else return $ FL.Partial (Just buf2)
296−
297− extract Nothing = return MArray.nil
298− extract (Just buf) = return buf
299−
300− functionPath =
301− "Streamly.Internal.Data.Stream.MutChunked.compactGEFold"
302
118
303-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
119-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
304-- maximum specified size in bytes.
120-- maximum specified size in bytes.
core/src/Streamly/Internal/Data/MutArray/Type.hs+987−323
@@ -31,37 +31,57 @@ module Streamly.Internal.Data.MutArray.Type
31 -- ** Type
31 -- ** Type
32 -- $arrayNotes
32 -- $arrayNotes
33 MutArray (..)
33 MutArray (..)
34+
35+ -- ** Conversion
36+ -- *** Pinned and Unpinned
34 , pin
37 , pin
35 , unpin
38 , unpin
36 , isPinned
39 , isPinned
37
40
38− -- -- * Constructing and Writing
41+ -- ** Casting
42+ , cast
43+ , castUnsafe -- XXX unsafeCast
44+ , asBytes
45+ , unsafePinnedAsPtr
46+ , unsafeAsPtr
47+
39 -- ** Construction
48 -- ** Construction
40− , nil
49+ , empty
50+
51+ -- *** New
52+ -- | New arrays are always empty arrays with some reserve capacity to
53+ -- extend the length without reallocating.
54+ , emptyOf
55+ , newArrayWith -- emptyAlignedWith
56+ , pinnedEmptyOf
57+ , pinnedNewAligned -- XXX not required
58+ -- , new -- uninitialized array of specified length
59+
60+ -- *** Cloning
61+ , clone
62+ , pinnedClone
41
63
42− -- *** Uninitialized Arrays
64+ -- *** Slicing
43− , pinnedNew
65+ -- | Get a subarray without copying
44− , pinnedNewBytes
66+ , getSliceUnsafe -- XXX unsafeGetSlice
45− , pinnedNewAligned
67+ , getSlice
46− , new
68+ , splitAt -- XXX should be able to express using getSlice
47− , newArrayWith
69+ , breakOn
48
70
49− -- *** From streams
71+ -- *** Stream Folds
50 , ArrayUnsafe (..)
72 , ArrayUnsafe (..)
51− , writeNWithUnsafe
73+ , unsafeCreateOfWith
52− , writeNWith
74+ , unsafeCreateOf
53− , writeNUnsafe
75+ , unsafePinnedCreateOf
54− , pinnedWriteNUnsafe
76+ , pinnedCreateOf
55− , writeN
77+ , createOfWith
56− , pinnedWriteN
78+ , createOf
57− , pinnedWriteNAligned
79+ , revCreateOf
58−
80+
59− , writeWith
81+ , pinnedCreate
60− , write
82+ , createWith
61− , pinnedWrite
83+ , create
62−
84+ -- , revCreate
63− , writeRevN
64− -- , writeRev
65
85
66 -- *** From containers
86 -- *** From containers
67 , fromListN
87 , fromListN
@@ -77,11 +97,11 @@ module Streamly.Internal.Data.MutArray.Type
77 , fromByteStr#
97 , fromByteStr#
78 , fromPtrN
98 , fromPtrN
79 , fromChunksK
99 , fromChunksK
80− , fromChunksRealloced
100+ , fromChunksRealloced -- fromSmallChunks
81
101
82 -- ** Random writes
102 -- ** Random writes
83 , putIndex
103 , putIndex
84− , putIndexUnsafe
104+ , putIndexUnsafe -- XXX unsafePutIndex
85 , putIndices
105 , putIndices
86 -- , putFromThenTo
106 -- , putFromThenTo
87 -- , putFrom -- start writing at the given position
107 -- , putFrom -- start writing at the given position
@@ -89,77 +109,70 @@ module Streamly.Internal.Data.MutArray.Type
89 -- , putFromTo
109 -- , putFromTo
90 -- , putFromRev
110 -- , putFromRev
91 -- , putUptoRev
111 -- , putUptoRev
92− , modifyIndexUnsafe
112+ , modifyIndexUnsafe -- XXX unsafeModifyIndex
93 , modifyIndex
113 , modifyIndex
94 , modifyIndices
114 , modifyIndices
95 , modify
115 , modify
96 , swapIndices
116 , swapIndices
97 , unsafeSwapIndices
117 , unsafeSwapIndices
98
118
99− -- ** Growing and Shrinking
119+ -- ** Reading
100− -- | Arrays grow only at the end, though it is possible to grow on both sides
101− -- and therefore have a cons as well as snoc. But that will require two
102− -- bounds in the array representation.
103−
104− -- *** Appending elements
105− , snocWith
106− , snoc
107− , snocLinear
108− , snocMay
109− , snocUnsafe
110−
111− -- *** Appending streams
112− , writeAppendNUnsafe
113− , writeAppendN
114− , writeAppendWith
115− , writeAppend
116
120
117− -- ** Eliminating and Reading
121+ -- *** Indexing
118−
122+ , getIndex
119− -- *** To streams
123+ , getIndexUnsafe -- XXX unsafeGetIndex
120− , reader
124+ -- , getFromThenTo
121− , readerRevWith
125+ , getIndexRev -- getRevIndex?
122− , readerRev
126+ , indexReader
127+ , indexReaderWith
123
128
124− -- *** To containers
129+ -- *** To Streams
125− , toStreamWith
126− , toStreamRevWith
127− , toStreamKWith
128− , toStreamKRevWith
129 , read
130 , read
130 , readRev
131 , readRev
132+ , toStreamWith
133+ , toStreamRevWith
131 , toStreamK
134 , toStreamK
135+ , toStreamKWith
132 , toStreamKRev
136 , toStreamKRev
137+ , toStreamKRevWith
138+
139+ -- *** To Containers
133 , toList
140 , toList
134
141
142+ -- *** Unfolds
135 -- experimental
143 -- experimental
136 , producerWith
144 , producerWith
137 , producer
145 , producer
138
146
139− -- *** Random reads
147+ , reader
140− , getIndex
148+ , readerRevWith
141− , getIndexUnsafe
149+ , readerRev
142− , getIndices
143− , getIndicesWith
144− -- , getFromThenTo
145− , getIndexRev
146−
147− -- ** Memory Management
148− , blockSize
149− , arrayChunkBytes
150− , allocBytesToElemCount
151− , realloc
152− , resize
153− , resizeExp
154− , rightSize
155
150
156− -- ** Size
151+ -- ** Size and Capacity
152+ -- *** Size
157 , length
153 , length
158 , byteLength
154 , byteLength
155+
156+ -- *** Capacity
159 -- , capacity
157 -- , capacity
160 , byteCapacity
158 , byteCapacity
161 , bytesFree
159 , bytesFree
162
160
161+ -- *** Capacity Management
162+ , blockSize
163+ , arrayChunkBytes
164+ , allocBytesToElemCount
165+ , realloc -- this is "resize"
166+ , grow
167+ , growExp
168+ , rightSize
169+
170+ -- ** Folding
171+ , foldl'
172+ , foldr
173+ , byteCmp
174+ , byteEq
175+
163 -- ** In-place Mutation Algorithms
176 -- ** In-place Mutation Algorithms
164 , strip
177 , strip
165 , reverse
178 , reverse
@@ -170,59 +183,82 @@ module Streamly.Internal.Data.MutArray.Type
170 , mergeBy
183 , mergeBy
171 , bubble
184 , bubble
172
185
173− -- ** Casting
186+ -- ** Growing and Shrinking
174− , cast
187+ -- | Arrays grow only at the end, though it is possible to grow on both
175− , castUnsafe
188+ -- sides and therefore have a cons as well as snoc. But that will require
176− , asBytes
189+ -- both lower and upper bound in the array representation.
177− , asPtrUnsafe
178− , asUnpinnedPtrUnsafe
179
190
180− -- ** Folding
191+ -- *** Appending elements
181− , foldl'
192+ , snocWith
182− , foldr
193+ , snoc
183− , cmp
194+ , snocLinear
184− , byteCmp
195+ , snocMay
185− , byteEq
196+ , snocUnsafe -- XXX unsafeSnoc
197+
198+ -- *** Appending streams
199+ , unsafeAppendN
200+ , appendN
201+ , appendWith
202+ , append
203+
204+ -- *** Appending arrays
205+ , spliceCopy
206+ , spliceWith
207+ , splice
208+ , spliceExp
209+ , spliceUnsafe -- XXX unsafeSplice
210+ -- , putSlice
211+ -- , appendSlice
212+ -- , appendSliceFrom
213+
214+ -- ** Serialization using Unbox
215+ , pokeAppend
216+ , pokeAppendMay
217+ , pokeSkipUnsafe -- unsafePokeSkip
218+
219+ -- ** Deserialization using Unbox
220+ , peekUncons
221+ , peekUnconsUnsafe -- unsafePeekUncons
222+ , peekSkipUnsafe -- unsafePeekSkip
186
223
187− -- ** Arrays of arrays
224+ -- Arrays of arrays
188 -- We can add dimensionality parameter to the array type to get
225 -- We can add dimensionality parameter to the array type to get
189 -- multidimensional arrays. Multidimensional arrays would just be a
226 -- multidimensional arrays. Multidimensional arrays would just be a
190 -- convenience wrapper on top of single dimensional arrays.
227 -- convenience wrapper on top of single dimensional arrays.
191
228
192− -- | Operations dealing with multiple arrays, streams of arrays or
229+ -- ** Streams of Arrays
193− -- multidimensional array representations.
230+ -- *** Chunk
194−
231+ -- | Group a stream into arrays.
195− -- *** Construct from streams
196 , chunksOf
232 , chunksOf
197 , pinnedChunksOf
233 , pinnedChunksOf
198 , buildChunks
234 , buildChunks
199
235
200− -- *** Eliminate to streams
236+ -- *** Split
201− , concatChunks
237+ -- | Split an array into slices.
202− , concatChunksRev
203
238
204− -- *** Construct from arrays
205− -- get chunks without copying
206− , getSliceUnsafe
207− , getSlice
208 -- , getSlicesFromLenN
239 -- , getSlicesFromLenN
209− , splitAt -- XXX should be able to express using getSlice
210 , splitOn
240 , splitOn
211− , breakOn
241+ -- , slicesOf
212−
242+
213− -- ** Cloning arrays
243+ -- *** Concat
214− , clone
244+ -- | Append the arrays in a stream to form a stream of elements.
215− , pinnedClone
245+ , concatWith
216−
246+ , concatRevWith
217− -- ** Appending arrays
247+ , concat
218− , spliceCopy
248+ , concatRev
219− , spliceWith
249+
220− , splice
250+ -- *** Compact
221− , spliceExp
251+ -- | Append the arrays in a stream to form a stream of larger arrays.
222− , spliceUnsafe
252+ , SpliceState (..)
223− -- , putSlice
253+ , pCompactLE
224− -- , appendSlice
254+ , pPinnedCompactLE
225− -- , appendSliceFrom
255+ , compactLeAs
256+ , fCompactGE
257+ , fPinnedCompactGE
258+ , lCompactGE
259+ , lPinnedCompactGE
260+ , compactGE
261+ , compactEQ
226
262
227 -- ** Utilities
263 -- ** Utilities
228 , roundUpToPower2
264 , roundUpToPower2
@@ -231,12 +267,37 @@ module Streamly.Internal.Data.MutArray.Type
231 , c_memchr
267 , c_memchr
232
268
233 -- * Deprecated
269 -- * Deprecated
270+ , asPtrUnsafe
234 , writeChunks
271 , writeChunks
235 , flattenArrays
272 , flattenArrays
236 , flattenArraysRev
273 , flattenArraysRev
237 , fromArrayStreamK
274 , fromArrayStreamK
238 , fromStreamDN
275 , fromStreamDN
239 , fromStreamD
276 , fromStreamD
277+ , cmp
278+ , getIndices
279+ , getIndicesWith
280+ , resize
281+ , resizeExp
282+ , nil
283+ , new
284+ , pinnedNew
285+ , pinnedNewBytes
286+ , writeAppendNUnsafe
287+ , writeAppendN
288+ , writeAppendWith
289+ , writeAppend
290+ , writeNWithUnsafe
291+ , writeNWith
292+ , writeNUnsafe
293+ , pinnedWriteNUnsafe
294+ , writeN
295+ , pinnedWriteN
296+ , pinnedWriteNAligned -- XXX not required
297+ , writeWith
298+ , write
299+ , pinnedWrite
300+ , writeRevN
240 )
301 )
241where
302where
242
303
@@ -247,6 +308,7 @@ where
247
308
248import Control.Monad (when, void)
309import Control.Monad (when, void)
249import Control.Monad.IO.Class (MonadIO(..))
310import Control.Monad.IO.Class (MonadIO(..))
311+import Data.Bifunctor (first)
250import Data.Bits (shiftR, (.|.), (.&.))
312import Data.Bits (shiftR, (.|.), (.&.))
251import Data.Functor.Identity (Identity(..))
313import Data.Functor.Identity (Identity(..))
252import Data.Proxy (Proxy(..))
314import Data.Proxy (Proxy(..))
@@ -273,13 +335,17 @@ import GHC.Ptr (Ptr(..))
273import Streamly.Internal.Data.Fold.Type (Fold(..))
335import Streamly.Internal.Data.Fold.Type (Fold(..))
274import Streamly.Internal.Data.Producer.Type (Producer (..))
336import Streamly.Internal.Data.Producer.Type (Producer (..))
275import Streamly.Internal.Data.Stream.Type (Stream)
337import Streamly.Internal.Data.Stream.Type (Stream)
338+import Streamly.Internal.Data.Parser.Type (Parser (..))
276import Streamly.Internal.Data.StreamK.Type (StreamK)
339import Streamly.Internal.Data.StreamK.Type (StreamK)
277import Streamly.Internal.Data.SVar.Type (adaptState, defState)
340import Streamly.Internal.Data.SVar.Type (adaptState, defState)
341+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
278import Streamly.Internal.Data.Unfold.Type (Unfold(..))
342import Streamly.Internal.Data.Unfold.Type (Unfold(..))
279import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
343import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
280
344
281import qualified Streamly.Internal.Data.Fold.Type as FL
345import qualified Streamly.Internal.Data.Fold.Type as FL
282import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
346import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
347+import qualified Streamly.Internal.Data.Parser.Type as Parser
348+-- import qualified Streamly.Internal.Data.Fold.Type as Fold
283import qualified Streamly.Internal.Data.Producer as Producer
349import qualified Streamly.Internal.Data.Producer as Producer
284import qualified Streamly.Internal.Data.Stream.Type as D
350import qualified Streamly.Internal.Data.Stream.Type as D
285import qualified Streamly.Internal.Data.Stream.Lift as D
351import qualified Streamly.Internal.Data.Stream.Lift as D
@@ -287,7 +353,7 @@ import qualified Streamly.Internal.Data.StreamK.Type as K
287import qualified Prelude
353import qualified Prelude
288
354
289import Prelude hiding
355import Prelude hiding
290− (Foldable(..), read, unlines, splitAt, reverse, truncate)
356+ (Foldable(..), concat, read, unlines, splitAt, reverse, truncate)
291
357
292#include "DocTestDataMutArray.hs"
358#include "DocTestDataMutArray.hs"
293
359
@@ -413,6 +479,8 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
413-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
479-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
414-- allocatePinned in GHC source.
480-- allocatePinned in GHC source.
415
481
482+-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
483+
416-- | @newArrayWith allocator alignment count@ allocates a new array of zero
484-- | @newArrayWith allocator alignment count@ allocates a new array of zero
417-- length and with a capacity to hold @count@ elements, using @allocator
485-- length and with a capacity to hold @count@ elements, using @allocator
418-- size alignment@ as the memory allocator function.
486-- size alignment@ as the memory allocator function.
@@ -436,12 +504,25 @@ newArrayWith alloc alignSize count = do
436 , arrBound = size
504 , arrBound = size
437 }
505 }
438
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." #-}
439nil ::
520nil ::
440#ifdef DEVBUILD
521#ifdef DEVBUILD
441 Unbox a =>
522 Unbox a =>
442#endif
523#endif
443 MutArray a
524 MutArray a
444−nil = MutArray Unboxed.nil 0 0 0
525+nil = empty
445
526
446{-# INLINE newBytesAs #-}
527{-# INLINE newBytesAs #-}
447newBytesAs :: MonadIO m =>
528newBytesAs :: MonadIO m =>
@@ -458,12 +539,13 @@ newBytesAs ps bytes = do
458 , arrBound = bytes
539 , arrBound = bytes
459 }
540 }
460
541
461−-- | Allocates a pinned empty array that can hold 'count' items. The memory of
542+-- | Allocates a pinned empty array that with a reserved capacity of bytes.
462−-- the array is uninitialized and the allocation is aligned as per the
543+-- The memory of the array is uninitialized and the allocation is aligned as
463−-- 'Unboxed' instance of the type.
544+-- per the 'Unboxed' instance of the type.
464--
545--
465-- /Pre-release/
546-- /Pre-release/
466{-# INLINE pinnedNewBytes #-}
547{-# INLINE pinnedNewBytes #-}
548+{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
467pinnedNewBytes :: MonadIO m =>
549pinnedNewBytes :: MonadIO m =>
468#ifdef DEVBUILD
550#ifdef DEVBUILD
469 Unbox a =>
551 Unbox a =>
@@ -488,21 +570,31 @@ newAs ps =
488 (error "new: alignment is not used in unpinned arrays.")
570 (error "new: alignment is not used in unpinned arrays.")
489
571
490-- 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?
491−--
573+
492−-- | 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
493−-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
575+-- capacity without reallocation.
494−-- instance of the type.
576+{-# INLINE pinnedEmptyOf #-}
495−--
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." #-}
496{-# INLINE pinnedNew #-}
582{-# INLINE pinnedNew #-}
497pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
583pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
498−pinnedNew = newAs Pinned
584+pinnedNew = pinnedEmptyOf
499
585
500−-- | 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
501−-- of the array is uninitialized.
587+-- capacity without reallocation.
502--
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." #-}
503{-# INLINE new #-}
595{-# INLINE new #-}
504new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
596new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
505−new = newAs Unpinned
597+new = emptyOf
506
598
507-------------------------------------------------------------------------------
599-------------------------------------------------------------------------------
508-- Random writes
600-- Random writes
@@ -550,7 +642,7 @@ putIndices arr = FL.foldlM' step (return ())
550
642
551 where
643 where
552
644
553− step () (i, x) = liftIO (putIndex i arr x)
645+ step () (i, x) = putIndex i arr x
554
646
555-- | Modify a given index of an array using a modifier function.
647-- | Modify a given index of an array using a modifier function.
556--
648--
@@ -746,22 +838,19 @@ arrayChunkBytes = 1024
746roundDownTo :: Int -> Int -> Int
838roundDownTo :: Int -> Int -> Int
747roundDownTo elemSize size = size - (size `mod` elemSize)
839roundDownTo elemSize size = size - (size `mod` elemSize)
748
840
749−-- XXX See if resizing can be implemented by reading the old array as a stream
750−-- and then using writeN to the new array.
751−--
752-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
841-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
753-- Since this is not inlined Unboxed consrraint leads to dictionary passing
842-- Since this is not inlined Unboxed consrraint leads to dictionary passing
754-- which complicates some inspection tests.
843-- which complicates some inspection tests.
755--
844--
756−{-# NOINLINE reallocExplicit #-}
845+{-# NOINLINE reallocExplicitAs #-}
757−reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
846+reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
758−reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
847+reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
759 assertM(arrEnd <= arrBound)
848 assertM(arrEnd <= arrBound)
760
849
761 -- Allocate new array
850 -- Allocate new array
762 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
851 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
763 contents <-
852 contents <-
764− if Unboxed.isPinned arrContents
853+ if ps == Pinned
765 then Unboxed.pinnedNew newCapMaxInBytes
854 then Unboxed.pinnedNew newCapMaxInBytes
766 else Unboxed.new newCapMaxInBytes
855 else Unboxed.new newCapMaxInBytes
767 let !(MutByteArray mbarrFrom#) = arrContents
856 let !(MutByteArray mbarrFrom#) = arrContents
@@ -786,6 +875,10 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
786 , arrBound = newCapInBytes
875 , arrBound = newCapInBytes
787 }
876 }
788
877
878+-- XXX Should these be called reallocBytes etc?
879+-- XXX We may also need reallocAs to allocate as pinned/unpinned explicitly. In
880+-- fact clone/pinnedClone can be implemented using reallocAs.
881+
789-- | @realloc newCapacity array@ reallocates the array to the specified
882-- | @realloc newCapacity array@ reallocates the array to the specified
790-- capacity in bytes.
883-- capacity in bytes.
791--
884--
@@ -797,7 +890,12 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
797-- 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.
798{-# INLINABLE realloc #-}
891{-# INLINABLE realloc #-}
799realloc :: 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
800−realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
898+ in liftIO $ reallocExplicitAs ps (SIZE_OF(a)) bytes arr
801
899
802-- | @reallocWith label capSizer minIncrBytes array@. The label is used
900-- | @reallocWith label capSizer minIncrBytes array@. The label is used
803-- 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
@@ -820,14 +918,14 @@ reallocWith label capSizer minIncrBytes arr = do
820 where
918 where
821
919
822 badSize newSize =
920 badSize newSize =
823− concat
921+ Prelude.concat
824 [ label
922 [ label
825 , ": new array size (in bytes) is less than required size "
923 , ": new array size (in bytes) is less than required size "
826 , show newSize
924 , show newSize
827 , ". Please check the sizing function passed."
925 , ". Please check the sizing function passed."
828 ]
926 ]
829
927
830−-- | @resize newCapacity array@ changes the total capacity of the array so that
928+-- | @grow newCapacity array@ changes the total capacity of the array so that
831-- it is enough to hold the specified number of elements. Nothing is done if
929-- it is enough to hold the specified number of elements. Nothing is done if
832-- the specified capacity is less than the length of the array.
930-- the specified capacity is less than the length of the array.
833--
931--
@@ -835,34 +933,46 @@ reallocWith label capSizer minIncrBytes arr = do
835-- the block size (4K).
933-- the block size (4K).
836--
934--
837-- /Pre-release/
935-- /Pre-release/
838−{-# INLINE resize #-}
936+{-# INLINE grow #-}
839−resize :: forall m a. (MonadIO m, Unbox a) =>
937+grow :: forall m a. (MonadIO m, Unbox a) =>
840 Int -> MutArray a -> m (MutArray a)
938 Int -> MutArray a -> m (MutArray a)
841−resize nElems arr@MutArray{..} = do
939+grow nElems arr@MutArray{..} = do
842 let req = SIZE_OF(a) * nElems
940 let req = SIZE_OF(a) * nElems
843− len = arrEnd - arrStart
941+ cap = arrBound - arrStart
844− if req < len
942+ if req < cap
845 then return arr
943 then return arr
846 else realloc req arr
944 else realloc req arr
847
945
946+{-# DEPRECATED resize "Please use grow instead." #-}
947+{-# INLINE resize #-}
948+resize :: forall m a. (MonadIO m, Unbox a) =>
949+ Int -> MutArray a -> m (MutArray a)
950+resize = grow
951+
848−-- | Like 'resize' but if the byte capacity is more than 'largeObjectThreshold'
952+-- | Like 'grow' but if the requested byte capacity is more than
849−-- then it is rounded up to the closest power of 2.
953+-- 'largeObjectThreshold' then it is rounded up to the closest power of 2.
850--
954--
851-- /Pre-release/
955-- /Pre-release/
852−{-# INLINE resizeExp #-}
956+{-# INLINE growExp #-}
853−resizeExp :: forall m a. (MonadIO m, Unbox a) =>
957+growExp :: forall m a. (MonadIO m, Unbox a) =>
854 Int -> MutArray a -> m (MutArray a)
958 Int -> MutArray a -> m (MutArray a)
855−resizeExp nElems arr@MutArray{..} = do
959+growExp nElems arr@MutArray{..} = do
856 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
960 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
857 req1 =
961 req1 =
858 if req > largeObjectThreshold
962 if req > largeObjectThreshold
859 then roundUpToPower2 req
963 then roundUpToPower2 req
860 else req
964 else req
861− len = arrEnd - arrStart
965+ cap = arrBound - arrStart
862− if req1 < len
966+ if req1 < cap
863 then return arr
967 then return arr
864 else realloc req1 arr
968 else realloc req1 arr
865
969
970+{-# DEPRECATED resizeExp "Please use growExp instead." #-}
971+{-# INLINE resizeExp #-}
972+resizeExp :: forall m a. (MonadIO m, Unbox a) =>
973+ Int -> MutArray a -> m (MutArray a)
974+resizeExp = growExp
975+
866-- | Resize the allocated memory to drop any reserved free space at the end of
976-- | Resize the allocated memory to drop any reserved free space at the end of
867-- the array and reallocate it to reduce wastage.
977-- the array and reallocate it to reduce wastage.
868--
978--
@@ -927,7 +1037,7 @@ snocUnsafe arr@MutArray{..} = snocNewEnd (INDEX_NEXT(arrEnd,a)) arr
927{-# INLINE snocMay #-}
1037{-# INLINE snocMay #-}
928snocMay :: forall m a. (MonadIO m, Unbox a) =>
1038snocMay :: forall m a. (MonadIO m, Unbox a) =>
929 MutArray a -> a -> m (Maybe (MutArray a))
1039 MutArray a -> a -> m (Maybe (MutArray a))
930−snocMay arr@MutArray{..} x = liftIO $ do
1040+snocMay arr@MutArray{..} x = do
931 let newEnd = INDEX_NEXT(arrEnd,a)
1041 let newEnd = INDEX_NEXT(arrEnd,a)
932 if newEnd <= arrBound
1042 if newEnd <= arrBound
933 then Just <$> snocNewEnd newEnd arr x
1043 then Just <$> snocNewEnd newEnd arr x
@@ -941,7 +1051,7 @@ snocWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
941 -> a
1051 -> a
942 -> m (MutArray a)
1052 -> m (MutArray a)
943snocWithRealloc sizer arr x = do
1053snocWithRealloc sizer arr x = do
944− arr1 <- liftIO $ reallocWith "snocWith" sizer (SIZE_OF(a)) arr
1054+ arr1 <- reallocWith "snocWith" sizer (SIZE_OF(a)) arr
945 snocUnsafe arr1 x
1055 snocUnsafe arr1 x
946
1056
947-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
1057-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
@@ -963,7 +1073,7 @@ snocWith :: forall m a. (MonadIO m, Unbox a) =>
963 -> MutArray a
1073 -> MutArray a
964 -> a
1074 -> a
965 -> m (MutArray a)
1075 -> m (MutArray a)
966−snocWith allocSize arr x = liftIO $ do
1076+snocWith allocSize arr x = do
967 let newEnd = INDEX_NEXT(arrEnd arr,a)
1077 let newEnd = INDEX_NEXT(arrEnd arr,a)
968 if newEnd <= arrBound arr
1078 if newEnd <= arrBound arr
969 then snocNewEnd newEnd arr x
1079 then snocNewEnd newEnd arr x
@@ -1007,6 +1117,126 @@ snoc = snocWith f
1007 then oldSize * 2
1117 then oldSize * 2
1008 else roundUpToPower2 oldSize * 2
1118 else roundUpToPower2 oldSize * 2
1009
1119
1120+-------------------------------------------------------------------------------
1121+-- Serialization/Deserialization
1122+-------------------------------------------------------------------------------
1123+
1124+{-# INLINE pokeNewEnd #-}
1125+pokeNewEnd :: (MonadIO m, Unbox a) =>
1126+ Int -> MutArray Word8 -> a -> m (MutArray Word8)
1127+pokeNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1128+ assert (newEnd <= arrBound) (return ())
1129+ liftIO $ pokeAt arrEnd arrContents x
1130+ return $ arr {arrEnd = newEnd}
1131+
1132+-- | Really really unsafe, unboxes a Haskell type and appends the resulting
1133+-- bytes to the byte array, may cause silent data corruption or if you are
1134+-- lucky a segfault if the array does not have enough space to append the
1135+-- element.
1136+--
1137+-- /Internal/
1138+{-# INLINE pokeAppendUnsafe #-}
1139+pokeAppendUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1140+ MutArray Word8 -> a -> m (MutArray Word8)
1141+pokeAppendUnsafe arr@MutArray{..} = pokeNewEnd (arrEnd + SIZE_OF(a)) arr
1142+
1143+-- | Skip the specified number of bytes in the array. The data in the skipped
1144+-- region remains uninitialzed.
1145+{-# INLINE pokeSkipUnsafe #-}
1146+pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1147+pokeSkipUnsafe n arr@MutArray{..} = do
1148+ let newEnd = arrEnd + n
1149+ in assert (newEnd <= arrBound) (arr {arrEnd = newEnd})
1150+
1151+-- | Like 'pokeAppend' but does not grow the array when pre-allocated array
1152+-- capacity becomes full.
1153+--
1154+-- /Internal/
1155+{-# INLINE pokeAppendMay #-}
1156+pokeAppendMay :: forall m a. (MonadIO m, Unbox a) =>
1157+ MutArray Word8 -> a -> m (Maybe (MutArray Word8))
1158+pokeAppendMay arr@MutArray{..} x = liftIO $ do
1159+ let newEnd = arrEnd + SIZE_OF(a)
1160+ if newEnd <= arrBound
1161+ then Just <$> pokeNewEnd newEnd arr x
1162+ else return Nothing
1163+
1164+{-# NOINLINE pokeWithRealloc #-}
1165+pokeWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1166+ (Int -> Int)
1167+ -> MutArray Word8
1168+ -> a
1169+ -> m (MutArray Word8)
1170+pokeWithRealloc sizer arr x = do
1171+ arr1 <- liftIO $ reallocWith "pokeWithRealloc" sizer (SIZE_OF(a)) arr
1172+ pokeAppendUnsafe arr1 x
1173+
1174+{-# INLINE pokeAppendWith #-}
1175+pokeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1176+ (Int -> Int)
1177+ -> MutArray Word8
1178+ -> a
1179+ -> m (MutArray Word8)
1180+pokeAppendWith allocSize arr x = liftIO $ do
1181+ let newEnd = arrEnd arr + SIZE_OF(a)
1182+ if newEnd <= arrBound arr
1183+ then pokeNewEnd newEnd arr x
1184+ else pokeWithRealloc allocSize arr x
1185+
1186+-- | Unbox a Haskell type and append the resulting bytes to a mutable byte
1187+-- array. The array is grown exponentially when more space is needed.
1188+--
1189+-- Definition:
1190+--
1191+-- >>> pokeAppend arr x = MutArray.castUnsafe <$> MutArray.snoc (MutArray.castUnsafe arr) x
1192+--
1193+{-# INLINE pokeAppend #-}
1194+pokeAppend :: forall m a. (MonadIO m, Unbox a) =>
1195+ MutArray Word8 -> a -> m (MutArray Word8)
1196+pokeAppend = pokeAppendWith f
1197+
1198+ where
1199+
1200+ f oldSize =
1201+ if isPower2 oldSize
1202+ then oldSize * 2
1203+ else roundUpToPower2 oldSize * 2
1204+
1205+-- | Really really unsafe, create a Haskell value from an unboxed byte array,
1206+-- does not check if the array is big enough, may return garbage or if you are
1207+-- lucky may cause a segfault.
1208+--
1209+-- /Internal/
1210+{-# INLINE peekUnconsUnsafe #-}
1211+peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1212+ MutArray Word8 -> m (a, MutArray Word8)
1213+peekUnconsUnsafe MutArray{..} = do
1214+ let start1 = arrStart + SIZE_OF(a)
1215+ assert (start1 <= arrEnd) (return ())
1216+ liftIO $ do
1217+ r <- peekAt arrStart arrContents
1218+ return (r, MutArray arrContents start1 arrEnd arrBound)
1219+
1220+-- | Discard the specified number of bytes in the array.
1221+{-# INLINE peekSkipUnsafe #-}
1222+peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1223+peekSkipUnsafe n MutArray{..} =
1224+ let start1 = arrStart + n
1225+ in assert (start1 <= arrEnd) (MutArray arrContents start1 arrEnd arrBound)
1226+
1227+-- | Create a Haskell value from its unboxed representation from the head of a
1228+-- byte array, return the value and the remaining array.
1229+{-# INLINE peekUncons #-}
1230+peekUncons :: forall m a. (MonadIO m, Unbox a) =>
1231+ MutArray Word8 -> m (Maybe a, MutArray Word8)
1232+peekUncons arr@MutArray{..} = do
1233+ let start1 = arrStart + SIZE_OF(a)
1234+ if start1 > arrEnd
1235+ then return (Nothing, arr)
1236+ else liftIO $ do
1237+ r <- peekAt arrStart arrContents
1238+ return (Just r, MutArray arrContents start1 arrEnd arrBound)
1239+
1010-------------------------------------------------------------------------------
1240-------------------------------------------------------------------------------
1011-- Random reads
1241-- Random reads
1012-------------------------------------------------------------------------------
1242-------------------------------------------------------------------------------
@@ -1049,10 +1279,10 @@ getIndexRev i MutArray{..} = do
1049data GetIndicesState contents start end st =
1279data GetIndicesState contents start end st =
1050 GetIndicesState contents start end st
1280 GetIndicesState contents start end st
1051
1281
1052−{-# INLINE getIndicesWith #-}
1282+{-# INLINE indexReaderWith #-}
1053−getIndicesWith :: (Monad m, Unbox a) =>
1283+indexReaderWith :: (Monad m, Unbox a) =>
1054 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1284 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1055−getIndicesWith liftio (D.Stream stepi sti) = Unfold step inject
1285+indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
1056
1286
1057 where
1287 where
1058
1288
@@ -1071,14 +1301,26 @@ getIndicesWith liftio (D.Stream stepi sti) = Unfold step inject
1071 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1301 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1072 D.Stop -> return D.Stop
1302 D.Stop -> return D.Stop
1073
1303
1304+{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1305+{-# INLINE getIndicesWith #-}
1306+getIndicesWith :: (Monad m, Unbox a) =>
1307+ (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1308+getIndicesWith = indexReaderWith
1309+
1074-- | Given an unfold that generates array indices, read the elements on those
1310-- | Given an unfold that generates array indices, read the elements on those
1075-- indices from the supplied MutArray. An error is thrown if an index is out of
1311-- indices from the supplied MutArray. An error is thrown if an index is out of
1076-- bounds.
1312-- bounds.
1077--
1313--
1078-- /Pre-release/
1314-- /Pre-release/
1315+{-# INLINE indexReader #-}
1316+indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1317+indexReader = indexReaderWith liftIO
1318+
1319+-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
1320+{-# DEPRECATED getIndices "Please use indexReader instead." #-}
1079{-# INLINE getIndices #-}
1321{-# INLINE getIndices #-}
1080getIndices :: (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
1081−getIndices = getIndicesWith liftIO
1323+getIndices = indexReader
1082
1324
1083-------------------------------------------------------------------------------
1325-------------------------------------------------------------------------------
1084-- Subarrays
1326-- Subarrays
@@ -1373,7 +1615,7 @@ chunksOfAs ps n (D.Stream step state) =
1373--
1615--
1374-- Same as the following but may be more efficient:
1616-- Same as the following but may be more efficient:
1375--
1617--
1376−-- >>> chunksOf n = Stream.foldMany (MutArray.writeN n)
1618+-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1377--
1619--
1378-- /Pre-release/
1620-- /Pre-release/
1379{-# INLINE_NORMAL chunksOf #-}
1621{-# INLINE_NORMAL chunksOf #-}
@@ -1382,14 +1624,14 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
1382-- 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'
1383-- benchmark. It seems it has difficulty producing optimized code when
1625-- benchmark. It seems it has difficulty producing optimized code when
1384-- converting to StreamK. Investigate GHC optimizations.
1626-- converting to StreamK. Investigate GHC optimizations.
1385−-- chunksOf n = D.foldMany (writeN n)
1627+-- chunksOf n = D.foldMany (createOf n)
1386chunksOf = chunksOfAs Unpinned
1628chunksOf = chunksOfAs Unpinned
1387
1629
1388-- | Like 'chunksOf' but creates pinned arrays.
1630-- | Like 'chunksOf' but creates pinned arrays.
1389{-# INLINE_NORMAL pinnedChunksOf #-}
1631{-# INLINE_NORMAL pinnedChunksOf #-}
1390pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1632pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1391 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1633 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1392−-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
1634+-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1393pinnedChunksOf = chunksOfAs Pinned
1635pinnedChunksOf = chunksOfAs Pinned
1394
1636
1395-- | 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
@@ -1422,16 +1664,10 @@ data FlattenState s contents a =
1422 OuterLoop s
1664 OuterLoop s
1423 | InnerLoop s contents !Int !Int
1665 | InnerLoop s contents !Int !Int
1424
1666
1425−-- | Use the "reader" unfold instead.
1426−--
1427−-- @concatChunks = unfoldMany reader@
1428−--
1429−-- We can try this if there are any fusion issues in the unfold.
1430−--
1431−{-# INLINE_NORMAL concatChunks #-}
1667+{-# INLINE_NORMAL concatWith #-}
1432−concatChunks :: forall m a. (MonadIO m, Unbox a)
1668+concatWith :: forall m a. (Monad m, Unbox a)
1433− => 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
1434−concatChunks (D.Stream step state) = D.Stream step' (OuterLoop state)
1670+concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1435
1671
1436 where
1672 where
1437
1673
@@ -1448,24 +1684,30 @@ concatChunks (D.Stream step state) = D.Stream step' (OuterLoop state)
1448 return $ D.Skip $ OuterLoop st
1684 return $ D.Skip $ OuterLoop st
1449
1685
1450 step' _ (InnerLoop st contents p end) = do
1686 step' _ (InnerLoop st contents p end) = do
1451− x <- liftIO $ peekAt p contents
1687+ x <- liftio $ peekAt p contents
1452 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)
1453
1689
1454−{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
1455−flattenArrays :: forall m a. (MonadIO m, Unbox a)
1456− => D.Stream m (MutArray a) -> D.Stream m a
1457−flattenArrays = concatChunks
1458−
1459−-- | Use the "readerRev" unfold instead.
1690+-- | Use the "reader" unfold instead.
1460--
1691--
1461−-- @concatChunks = unfoldMany readerRev@
1692+-- @concat = unfoldMany reader@
1462--
1693--
1463-- 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.
1464--
1695--
1465−{-# INLINE_NORMAL concatChunksRev #-}
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 #-}
1466−concatChunksRev :: forall m a. (MonadIO m, Unbox a)
1703+flattenArrays :: forall m a. (MonadIO m, Unbox a)
1467 => 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
1468−concatChunksRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1710+concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1469
1711
1470 where
1712 where
1471
1713
@@ -1483,14 +1725,26 @@ concatChunksRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1483 return $ D.Skip $ OuterLoop st
1725 return $ D.Skip $ OuterLoop st
1484
1726
1485 step' _ (InnerLoop st contents p start) = do
1727 step' _ (InnerLoop st contents p start) = do
1486− x <- liftIO $ peekAt p contents
1728+ x <- liftio $ peekAt p contents
1487 let cur = INDEX_PREV(p,a)
1729 let cur = INDEX_PREV(p,a)
1488 return $ D.Yield x (InnerLoop st contents cur start)
1730 return $ D.Yield x (InnerLoop st contents cur start)
1489
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+
1490{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1743{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1744+{-# INLINE flattenArraysRev #-}
1491flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1745flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1492 => D.Stream m (MutArray a) -> D.Stream m a
1746 => D.Stream m (MutArray a) -> D.Stream m a
1493−flattenArraysRev = concatChunksRev
1747+flattenArraysRev = concatRev
1494
1748
1495-------------------------------------------------------------------------------
1749-------------------------------------------------------------------------------
1496-- Unfolds
1750-- Unfolds
@@ -1719,7 +1973,7 @@ foldr f z arr = D.foldr f z $ read arr
1719
1973
1720-- 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?
1721
1975
1722−-- | @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
1723-- array.
1977-- array.
1724--
1978--
1725-- 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
@@ -1728,13 +1982,12 @@ foldr f z arr = D.foldr f z $ read arr
1728-- 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.
1729--
1983--
1730-- /Internal/
1984-- /Internal/
1731−{-# INLINE_NORMAL writeAppendNUnsafe #-}
1985+{-# INLINE_NORMAL unsafeAppendN #-}
1732−writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1986+unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1733 Int
1987 Int
1734 -> m (MutArray a)
1988 -> m (MutArray a)
1735 -> Fold m a (MutArray a)
1989 -> Fold m a (MutArray a)
1736−writeAppendNUnsafe n action =
1737− fmap fromArrayUnsafe $ FL.foldlM' step initial
1990+unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
1738
1991
1739 where
1992 where
1740
1993
@@ -1747,7 +2000,7 @@ writeAppendNUnsafe n action =
1747 -- otherwise we lose that space.
2000 -- otherwise we lose that space.
1748 arr1 <-
2001 arr1 <-
1749 if free < needed
2002 if free < needed
1750− then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
2003+ then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1751 else return arr
2004 else return arr
1752 return $ toArrayUnsafe arr1
2005 return $ toArrayUnsafe arr1
1753
2006
@@ -1755,30 +2008,51 @@ writeAppendNUnsafe n action =
1755 liftIO $ pokeAt end contents x
2008 liftIO $ pokeAt end contents x
1756 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2009 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1757
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+
1758-- | 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
1759-- after appending @n@ elements is lost.
2020-- after appending @n@ elements is lost.
1760--
2021--
1761−-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
2022+-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1762--
2023--
1763−{-# 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 #-}
1764writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
2032writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1765 Int -> m (MutArray a) -> Fold m a (MutArray a)
2033 Int -> m (MutArray a) -> Fold m a (MutArray a)
1766−writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
2034+writeAppendN = appendN
1767
2035
1768−-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
2036+-- | @appendWith realloc action@ mutates the array generated by @action@ to
1769-- 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
1770-- 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@,
1771-- where @oldSize@ is the current size of the array in bytes.
2039-- where @oldSize@ is the current size of the array in bytes.
1772--
2040--
1773-- 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.
1774--
2042--
1775−-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
2043+-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1776--
2044--
1777-- /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." #-}
1778{-# INLINE writeAppendWith #-}
2052{-# INLINE writeAppendWith #-}
1779writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
2053writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1780 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2054 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
1781−writeAppendWith sizer = FL.foldlM' (snocWith sizer)
2055+writeAppendWith = appendWith
1782
2056
1783-- | @append action@ mutates the array generated by @action@ to append the
2057-- | @append action@ mutates the array generated by @action@ to append the
1784-- 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
@@ -1786,26 +2060,33 @@ writeAppendWith sizer = FL.foldlM' (snocWith sizer)
1786--
2060--
1787-- 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.
1788--
2062--
1789−-- >>> writeAppend = MutArray.writeAppendWith (* 2)
2063+-- >>> append = MutArray.appendWith (* 2)
1790--
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." #-}
1791{-# INLINE writeAppend #-}
2072{-# INLINE writeAppend #-}
1792writeAppend :: forall m a. (MonadIO m, Unbox a) =>
2073writeAppend :: forall m a. (MonadIO m, Unbox a) =>
1793 m (MutArray a) -> Fold m a (MutArray a)
2074 m (MutArray a) -> Fold m a (MutArray a)
1794−writeAppend = writeAppendWith (* 2)
2075+writeAppend = append
1795
2076
1796-- 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
1797-- remaining capacity. Need to check perf impact.
2078-- remaining capacity. Need to check perf impact.
1798--
2079--
1799−-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
2080+-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
1800−-- as argument.
2081+-- function as argument.
1801--
2082--
1802−-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
2083+-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1803--
2084--
1804-- /Pre-release/
2085-- /Pre-release/
1805−{-# INLINE_NORMAL writeNWithUnsafe #-}
2086+{-# INLINE_NORMAL unsafeCreateOfWith #-}
1806−writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2087+unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1807 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2088 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1808−writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2089+unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1809
2090
1810 where
2091 where
1811
2092
@@ -1816,40 +2097,64 @@ writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1816 return
2097 return
1817 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2098 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1818
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+
1819{-# INLINE_NORMAL writeNUnsafeAs #-}
2106{-# INLINE_NORMAL writeNUnsafeAs #-}
1820writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
2107writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
1821 => PinnedState -> Int -> Fold m a (MutArray a)
2108 => PinnedState -> Int -> Fold m a (MutArray a)
1822−writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
2109+writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
1823
2110
1824−-- | 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
1825-- 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
1826-- corrupt the memory and crash. This function exists mainly because any
2113-- corrupt the memory and crash. This function exists mainly because any
1827-- conditional in the step function blocks fusion causing 10x performance
2114-- conditional in the step function blocks fusion causing 10x performance
1828-- slowdown.
2115-- slowdown.
1829--
2116--
1830−-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
2117+-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
1831--
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." #-}
1832−{-# INLINE_NORMAL writeNUnsafe #-}
2125+{-# INLINE writeNUnsafe #-}
1833writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
2126writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
1834 => Int -> Fold m a (MutArray a)
2127 => Int -> Fold m a (MutArray a)
1835−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
1836
2135
1837−-- | Like 'writeNUnsafe' but creates a pinned array.
2136+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
1838−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
2137+{-# INLINE pinnedWriteNUnsafe #-}
1839pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
2138pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
1840 => Int -> Fold m a (MutArray a)
2139 => Int -> Fold m a (MutArray a)
1841−pinnedWriteNUnsafe = writeNUnsafeAs Pinned
2140+pinnedWriteNUnsafe = unsafePinnedCreateOf
1842
2141
1843−-- | @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
1844-- allocated using the @alloc@ function.
2143-- allocated using the @alloc@ function.
1845--
2144--
1846−-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
2145+-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
1847−-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
2146+-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
1848--
2147--
1849−{-# 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 #-}
1850writeNWith :: forall m a. (MonadIO m, Unbox a)
2155writeNWith :: forall m a. (MonadIO m, Unbox a)
1851 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2156 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1852−writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
2157+writeNWith = createOfWith
1853
2158
1854{-# INLINE_NORMAL writeNAs #-}
2159{-# INLINE_NORMAL writeNAs #-}
1855writeNAs ::
2160writeNAs ::
@@ -1857,28 +2162,42 @@ writeNAs ::
1857 => PinnedState
2162 => PinnedState
1858 -> Int
2163 -> Int
1859 -> Fold m a (MutArray a)
2164 -> Fold m a (MutArray a)
1860−writeNAs ps = writeNWith (newAs ps)
2165+writeNAs ps = createOfWith (newAs ps)
1861
2166
1862−-- | @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
1863-- 'MutArray'.
2168-- 'MutArray'.
1864--
2169--
1865−-- >>> writeN = MutArray.writeNWith MutArray.new
2170+-- >>> createOf = MutArray.createOfWith MutArray.new
1866−-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
2171+-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
1867−-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
2172+-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
1868--
2173--
1869−{-# 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 #-}
1870writeN :: 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)
1871−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
1872
2191
1873−-- | Like 'writeN' but creates a pinned array.
2192+{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
1874−{-# INLINE_NORMAL pinnedWriteN #-}
2193+{-# INLINE pinnedWriteN #-}
1875pinnedWriteN ::
2194pinnedWriteN ::
1876 forall m a. (MonadIO m, Unbox a)
2195 forall m a. (MonadIO m, Unbox a)
1877 => Int
2196 => Int
1878 -> Fold m a (MutArray a)
2197 -> Fold m a (MutArray a)
1879−pinnedWriteN = writeNAs Pinned
2198+pinnedWriteN = pinnedCreateOf
1880
2199
1881−-- | Like writeNWithUnsafe but writes the array in reverse order.
2200+-- | Like unsafeCreateOfWith but writes the array in reverse order.
1882--
2201--
1883-- /Internal/
2202-- /Internal/
1884{-# INLINE_NORMAL writeRevNWithUnsafe #-}
2203{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -1899,7 +2218,7 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1899 return
2218 return
1900 $ ArrayUnsafe contents ptr end
2219 $ ArrayUnsafe contents ptr end
1901
2220
1902−-- | Like writeNWith but writes the array in reverse order.
2221+-- | Like createOfWith but writes the array in reverse order.
1903--
2222--
1904-- /Internal/
2223-- /Internal/
1905{-# INLINE_NORMAL writeRevNWith #-}
2224{-# INLINE_NORMAL writeRevNWith #-}
@@ -1907,31 +2226,36 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
1907 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2226 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1908writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
2227writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
1909
2228
1910−-- | Like writeN but writes the array in reverse order.
2229+-- | Like 'createOf' but writes the array in reverse order.
1911--
2230--
1912-- /Pre-release/
2231-- /Pre-release/
1913−{-# 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 #-}
1914writeRevN :: 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)
1915−writeRevN = writeRevNWith new
2239+writeRevN = revCreateOf
1916
2240
1917-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
2241-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
1918-- input stream to a 'MutArray' aligned to the given size.
2242-- input stream to a 'MutArray' aligned to the given size.
1919--
2243--
1920−-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
2244+-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
1921−-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
2245+-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
1922--
2246--
1923-- /Pre-release/
2247-- /Pre-release/
1924--
2248--
1925{-# INLINE_NORMAL pinnedWriteNAligned #-}
2249{-# INLINE_NORMAL pinnedWriteNAligned #-}
1926pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
2250pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
1927 => Int -> Int -> Fold m a (MutArray a)
2251 => Int -> Int -> Fold m a (MutArray a)
1928−pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
2252+pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
1929
2253
1930-- XXX Buffer to a list instead?
2254-- XXX Buffer to a list instead?
1931
2255
1932-- | Buffer a stream into a stream of arrays.
2256-- | Buffer a stream into a stream of arrays.
1933--
2257--
1934−-- >>> buildChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
2258+-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
1935--
2259--
1936-- 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
1937-- array sequentially such that memory of the array is released incrementatlly.
2261-- array sequentially such that memory of the array is released incrementatlly.
@@ -1943,9 +2267,10 @@ pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
1943{-# INLINE_NORMAL buildChunks #-}
2267{-# INLINE_NORMAL buildChunks #-}
1944buildChunks :: (MonadIO m, Unbox a) =>
2268buildChunks :: (MonadIO m, Unbox a) =>
1945 Int -> Fold m a (StreamK n (MutArray a))
2269 Int -> Fold m a (StreamK n (MutArray a))
1946−buildChunks n = FL.many (writeN n) FL.toStreamK
2270+buildChunks n = FL.many (createOf n) FL.toStreamK
1947
2271
1948{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2272{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2273+{-# INLINE writeChunks #-}
1949writeChunks :: (MonadIO m, Unbox a) =>
2274writeChunks :: (MonadIO m, Unbox a) =>
1950 Int -> Fold m a (StreamK n (MutArray a))
2275 Int -> Fold m a (StreamK n (MutArray a))
1951writeChunks = buildChunks
2276writeChunks = buildChunks
@@ -1953,29 +2278,29 @@ writeChunks = buildChunks
1953{-# INLINE_NORMAL writeWithAs #-}
2278{-# INLINE_NORMAL writeWithAs #-}
1954writeWithAs :: forall m a. (MonadIO m, Unbox a)
2279writeWithAs :: forall m a. (MonadIO m, Unbox a)
1955 => PinnedState -> Int -> Fold m a (MutArray a)
2280 => PinnedState -> Int -> Fold m a (MutArray a)
1956−-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
2281+-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
1957writeWithAs ps elemCount =
2282writeWithAs ps elemCount =
1958 FL.rmapM extract $ FL.foldlM' step initial
2283 FL.rmapM extract $ FL.foldlM' step initial
1959
2284
1960 where
2285 where
1961
2286
1962 initial = do
2287 initial = do
1963− when (elemCount < 0) $ error "writeWith: elemCount is negative"
2288+ when (elemCount < 0) $ error "createWith: elemCount is negative"
1964− liftIO $ newAs ps elemCount
2289+ newAs ps elemCount
1965
2290
1966 step arr@(MutArray _ start end bound) x
2291 step arr@(MutArray _ start end bound) x
1967 | INDEX_NEXT(end,a) > bound = do
2292 | INDEX_NEXT(end,a) > bound = do
1968 let oldSize = end - start
2293 let oldSize = end - start
1969 newSize = max (oldSize * 2) 1
2294 newSize = max (oldSize * 2) 1
1970− arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
2295+ arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
1971 snocUnsafe arr1 x
2296 snocUnsafe arr1 x
1972 step arr x = snocUnsafe arr x
2297 step arr x = snocUnsafe arr x
1973
2298
1974 extract = liftIO . rightSize
2299 extract = liftIO . rightSize
1975
2300
1976−-- XXX Compare writeWith with fromStreamD which uses an array of streams
2301+-- XXX Compare createWith with fromStreamD which uses an array of streams
1977-- 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.
1978−-- If writeWith is faster then we should use that to implement
2303+-- If createWith is faster then we should use that to implement
1979-- fromStreamD.
2304-- fromStreamD.
1980--
2305--
1981-- 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
@@ -1990,39 +2315,56 @@ writeWithAs ps elemCount =
1990-- 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
1991-- malloc to compare against.
2316-- malloc to compare against.
1992
2317
1993−-- | @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
1994-- 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
1995-- every time the array needs to be grown.
2320-- every time the array needs to be grown.
1996--
2321--
1997-- /Caution! Do not use this on infinite streams./
2322-- /Caution! Do not use this on infinite streams./
1998--
2323--
1999−-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2324+-- >>> f n = MutArray.appendWith (* 2) (MutArray.emptyOf n)
2000−-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2325+-- >>> createWith n = Fold.rmapM MutArray.rightSize (f n)
2001−-- >>> writeWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
2326+-- >>> createWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
2002--
2327--
2003-- /Pre-release/
2328-- /Pre-release/
2004−{-# 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 #-}
2005writeWith :: forall m a. (MonadIO m, Unbox a)
2337writeWith :: forall m a. (MonadIO m, Unbox a)
2006 => Int -> Fold m a (MutArray a)
2338 => Int -> Fold m a (MutArray a)
2007−-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
2339+writeWith = createWith
2008−writeWith = writeWithAs Unpinned
2009
2340
2010-- | Fold the whole input to a single array.
2341-- | Fold the whole input to a single array.
2011--
2342--
2012−-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
2343+-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
2013-- rounded up to the element size.
2344-- rounded up to the element size.
2014--
2345--
2015-- /Caution! Do not use this on infinite streams./
2346-- /Caution! Do not use this on infinite streams./
2016--
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." #-}
2017{-# INLINE write #-}
2354{-# INLINE write #-}
2018write :: 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)
2019−write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2356+write = create
2020
2357
2021−-- | 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." #-}
2022{-# INLINE pinnedWrite #-}
2365{-# INLINE pinnedWrite #-}
2023pinnedWrite :: 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)
2024−pinnedWrite =
2367+pinnedWrite = pinnedCreate
2025− writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2026
2368
2027-------------------------------------------------------------------------------
2369-------------------------------------------------------------------------------
2028-- construct from streams, known size
2370-- construct from streams, known size
@@ -2032,7 +2374,7 @@ pinnedWrite =
2032fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
2374fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
2033 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
2375 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
2034fromStreamDNAs ps limit str = do
2376fromStreamDNAs ps limit str = do
2035− (arr :: MutArray a) <- liftIO $ newAs ps limit
2377+ (arr :: MutArray a) <- newAs ps limit
2036 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
2378 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
2037 return $ arr {arrEnd = end}
2379 return $ arr {arrEnd = end}
2038
2380
@@ -2042,17 +2384,18 @@ fromStreamDNAs ps limit str = do
2042 liftIO $ pokeAt ptr arrContents x
2384 liftIO $ pokeAt ptr arrContents x
2043 return $ INDEX_NEXT(ptr,a)
2385 return $ INDEX_NEXT(ptr,a)
2044
2386
2045−-- | Use the 'writeN' fold instead.
2387+-- | Use the 'createOf' fold instead.
2046--
2388--
2047−-- >>> fromStreamN n = Stream.fold (MutArray.writeN n)
2389+-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2048--
2390--
2049{-# INLINE_NORMAL fromStreamN #-}
2391{-# INLINE_NORMAL fromStreamN #-}
2050fromStreamN :: forall m a. (MonadIO m, Unbox a)
2392fromStreamN :: forall m a. (MonadIO m, Unbox a)
2051 => Int -> D.Stream m a -> m (MutArray a)
2393 => Int -> D.Stream m a -> m (MutArray a)
2052−-- fromStreamDN n = D.fold (writeN n)
2394+-- fromStreamDN n = D.fold (createOf n)
2053fromStreamN = fromStreamDNAs Unpinned
2395fromStreamN = fromStreamDNAs Unpinned
2054
2396
2055{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2397{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2398+{-# INLINE fromStreamDN #-}
2056fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2399fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2057 => Int -> D.Stream m a -> m (MutArray a)
2400 => Int -> D.Stream m a -> m (MutArray a)
2058fromStreamDN = fromStreamN
2401fromStreamDN = fromStreamN
@@ -2075,20 +2418,20 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
2075-- /Pre-release/
2418-- /Pre-release/
2076{-# INLINE fromListRevN #-}
2419{-# INLINE fromListRevN #-}
2077fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2420fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2078−fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
2421+fromListRevN n xs = D.fold (revCreateOf n) $ D.fromList xs
2079
2422
2080-- | Convert a pure stream in Identity monad to a mutable array.
2423-- | Convert a pure stream in Identity monad to a mutable array.
2081{-# INLINABLE fromPureStreamN #-}
2424{-# INLINABLE fromPureStreamN #-}
2082fromPureStreamN :: (MonadIO m, Unbox a) =>
2425fromPureStreamN :: (MonadIO m, Unbox a) =>
2083 Int -> Stream Identity a -> m (MutArray a)
2426 Int -> Stream Identity a -> m (MutArray a)
2084fromPureStreamN n xs =
2427fromPureStreamN n xs =
2085− liftIO $ D.fold (writeN n) $ D.morphInner (return . runIdentity) xs
2428+ D.fold (createOf n) $ D.morphInner (return . runIdentity) xs
2086
2429
2087-- | Convert a pure stream in Identity monad to a mutable array.
2430-- | Convert a pure stream in Identity monad to a mutable array.
2088{-# INLINABLE fromPureStream #-}
2431{-# INLINABLE fromPureStream #-}
2089fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2432fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2090fromPureStream xs =
2433fromPureStream xs =
2091− liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
2434+ D.fold create $ D.morphInner (return . runIdentity) xs
2092
2435
2093{-# INLINABLE fromPtrN #-}
2436{-# INLINABLE fromPtrN #-}
2094fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
2437fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
@@ -2097,7 +2440,7 @@ fromPtrN len addr = do
2097 -- 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
2098 -- first and then remaining Word8.
2441 -- first and then remaining Word8.
2099 arr <- new len
2442 arr <- new len
2100− _ <- asUnpinnedPtrUnsafe arr
2443+ _ <- unsafeAsPtr arr
2101 (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
2444 (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
2102 return (arr {arrEnd = len})
2445 return (arr {arrEnd = len})
2103
2446
@@ -2113,7 +2456,7 @@ fromByteStr# addr = do
2113 len <- liftIO $ c_strlen (Ptr addr)
2456 len <- liftIO $ c_strlen (Ptr addr)
2114 let lenInt = fromIntegral len
2457 let lenInt = fromIntegral len
2115 arr <- new lenInt
2458 arr <- new lenInt
2116− _ <- asUnpinnedPtrUnsafe arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2459+ _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2117 return (arr {arrEnd = lenInt})
2460 return (arr {arrEnd = lenInt})
2118
2461
2119-------------------------------------------------------------------------------
2462-------------------------------------------------------------------------------
@@ -2134,7 +2477,7 @@ fromChunksRealloced s = do
2134 arr <- D.foldlM' spliceExp (pure a) strm
2477 arr <- D.foldlM' spliceExp (pure a) strm
2135 -- Reallocation is exponential so there may be 50% empty space in
2478 -- Reallocation is exponential so there may be 50% empty space in
2136 -- worst case. One more reallocation to reclaim the space.
2479 -- worst case. One more reallocation to reclaim the space.
2137− liftIO $ rightSize arr
2480+ rightSize arr
2138 Nothing -> pure nil
2481 Nothing -> pure nil
2139
2482
2140-------------------------------------------------------------------------------
2483-------------------------------------------------------------------------------
@@ -2172,6 +2515,7 @@ fromChunksK :: (Unbox a, MonadIO m) =>
2172fromChunksK = fromChunkskAs Unpinned
2515fromChunksK = fromChunkskAs Unpinned
2173
2516
2174{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2517{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2518+{-# INLINE fromArrayStreamK #-}
2175fromArrayStreamK :: (Unbox a, MonadIO m) =>
2519fromArrayStreamK :: (Unbox a, MonadIO m) =>
2176 StreamK m (MutArray a) -> m (MutArray a)
2520 StreamK m (MutArray a) -> m (MutArray a)
2177fromArrayStreamK = fromChunksK
2521fromArrayStreamK = fromChunksK
@@ -2183,7 +2527,7 @@ fromStreamDAs ps m =
2183 arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2527 arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2184
2528
2185-- | 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
2186−-- 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
2187-- as efficient when the size is already known.
2531-- as efficient when the size is already known.
2188--
2532--
2189-- 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
@@ -2195,19 +2539,19 @@ fromStreamDAs ps m =
2195fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
2539fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
2196fromStream = fromStreamDAs Unpinned
2540fromStream = fromStreamDAs Unpinned
2197
2541
2198−-- fromStream (Stream m) = P.fold write m
2542+-- fromStream (Stream m) = P.fold create m
2199-- CAUTION: a very large number (millions) of arrays can degrade performance
2543-- CAUTION: a very large number (millions) of arrays can degrade performance
2200-- 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
2201-- all the arrays.
2545-- all the arrays.
2202--
2546--
2203−-- XXX Compare if this is faster or "fold write".
2547+-- XXX Compare if this is faster or "fold create".
2204--
2548--
2205-- | 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
2206-- 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
2207-- 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
2208-- result in an extra copy of the entire data.
2552-- result in an extra copy of the entire data.
2209--
2553--
2210−-- >>> fromStreamD = StreamD.fold MutArray.write
2554+-- >>> fromStreamD = StreamD.fold MutArray.create
2211--
2555--
2212{-# INLINE fromStreamD #-}
2556{-# INLINE fromStreamD #-}
2213{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
2557{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
@@ -2237,6 +2581,10 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
2237-- Cloning
2581-- Cloning
2238-------------------------------------------------------------------------------
2582-------------------------------------------------------------------------------
2239
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+
2240{-# INLINE cloneAs #-}
2588{-# INLINE cloneAs #-}
2241cloneAs ::
2589cloneAs ::
2242 ( MonadIO m
2590 ( MonadIO m
@@ -2246,7 +2594,7 @@ cloneAs ::
2246 )
2594 )
2247 => PinnedState -> MutArray a -> m (MutArray a)
2595 => PinnedState -> MutArray a -> m (MutArray a)
2248cloneAs ps src =
2596cloneAs ps src =
2249− liftIO $ do
2597+ do
2250 let startSrc = arrStart src
2598 let startSrc = arrStart src
2251 srcLen = arrEnd src - startSrc
2599 srcLen = arrEnd src - startSrc
2252 newArrContents <-
2600 newArrContents <-
@@ -2285,17 +2633,16 @@ spliceCopy :: forall m a. MonadIO m =>
2285 Unbox a =>
2633 Unbox a =>
2286#endif
2634#endif
2287 MutArray a -> MutArray a -> m (MutArray a)
2635 MutArray a -> MutArray a -> m (MutArray a)
2288−spliceCopy arr1 arr2 = liftIO $ do
2636+spliceCopy arr1 arr2 = do
2289 let start1 = arrStart arr1
2637 let start1 = arrStart arr1
2290 start2 = arrStart arr2
2638 start2 = arrStart arr2
2291 len1 = arrEnd arr1 - start1
2639 len1 = arrEnd arr1 - start1
2292 len2 = arrEnd arr2 - start2
2640 len2 = arrEnd arr2 - start2
2293− let newLen = len1 + len2
2641+ let len = len1 + len2
2294 newArrContents <-
2642 newArrContents <-
2295 if Unboxed.isPinned (arrContents arr1)
2643 if Unboxed.isPinned (arrContents arr1)
2296− then Unboxed.pinnedNew newLen
2644+ then liftIO $ Unboxed.pinnedNew len
2297− else Unboxed.new newLen
2645+ else liftIO $ Unboxed.new len
2298− let len = len1 + len2
2299 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2646 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2300 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2647 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2301 return $ MutArray newArrContents 0 len len
2648 return $ MutArray newArrContents 0 len len
@@ -2307,7 +2654,7 @@ spliceCopy arr1 arr2 = liftIO $ do
2307spliceUnsafe :: MonadIO m =>
2654spliceUnsafe :: MonadIO m =>
2308 MutArray a -> MutArray a -> m (MutArray a)
2655 MutArray a -> MutArray a -> m (MutArray a)
2309spliceUnsafe dst src =
2656spliceUnsafe dst src =
2310− liftIO $ do
2657+ do
2311 let startSrc = arrStart src
2658 let startSrc = arrStart src
2312 srcLen = arrEnd src - startSrc
2659 srcLen = arrEnd src - startSrc
2313 endDst = arrEnd dst
2660 endDst = arrEnd dst
@@ -2329,7 +2676,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
2329 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2676 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2330spliceWith sizer dst@(MutArray _ start end bound) src = do
2677spliceWith sizer dst@(MutArray _ start end bound) src = do
2331{-
2678{-
2332− let f = writeAppendWith (`sizer` byteLength src) (return dst)
2679+ let f = appendWith (`sizer` byteLength src) (return dst)
2333 in D.fold f (toStreamD src)
2680 in D.fold f (toStreamD src)
2334-}
2681-}
2335 assert (end <= bound) (return ())
2682 assert (end <= bound) (return ())
@@ -2345,7 +2692,7 @@ spliceWith sizer dst@(MutArray _ start end bound) src = do
2345 $ "splice: newSize is less than the total size "
2692 $ "splice: newSize is less than the total size "
2346 ++ "of arrays being appended. Please check the "
2693 ++ "of arrays being appended. Please check the "
2347 ++ "sizer function passed."
2694 ++ "sizer function passed."
2348− liftIO $ realloc newSizeInBytes dst
2695+ realloc newSizeInBytes dst
2349 else return dst
2696 else return dst
2350 spliceUnsafe dst1 src
2697 spliceUnsafe dst1 src
2351
2698
@@ -2397,7 +2744,7 @@ splitOn predicate arr =
2397{-# INLINE breakOn #-}
2744{-# INLINE breakOn #-}
2398breakOn :: MonadIO m
2745breakOn :: MonadIO m
2399 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2746 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2400−breakOn sep arr@MutArray{..} = asUnpinnedPtrUnsafe arr $ \p -> liftIO $ do
2747+breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2401 -- 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.
2402 -- Need efficient stream based primitives that work on Word64.
2749 -- Need efficient stream based primitives that work on Word64.
2403 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2750 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
@@ -2420,33 +2767,41 @@ breakOn sep arr@MutArray{..} = asUnpinnedPtrUnsafe arr $ \p -> liftIO $ do
2420 }
2767 }
2421 )
2768 )
2422
2769
2770+-- | Like 'splitAt' but does not check whether the index is valid.
2771+--
2772+{-# INLINE unsafeSplitAt #-}
2773+unsafeSplitAt :: forall a. Unbox a =>
2774+ Int -> MutArray a -> (MutArray a, MutArray a)
2775+unsafeSplitAt i MutArray{..} =
2776+ let off = i * SIZE_OF(a)
2777+ p = arrStart + off
2778+ in ( MutArray
2779+ { arrContents = arrContents
2780+ , arrStart = arrStart
2781+ , arrEnd = p
2782+ , arrBound = p
2783+ }
2784+ , MutArray
2785+ { arrContents = arrContents
2786+ , arrStart = p
2787+ , arrEnd = arrEnd
2788+ , arrBound = arrBound
2789+ }
2790+ )
2791+
2423-- | Create two slices of an array without copying the original array. The
2792-- | Create two slices of an array without copying the original array. The
2424-- specified index @i@ is the first index of the second slice.
2793-- specified index @i@ is the first index of the second slice.
2425--
2794--
2426{-# INLINE splitAt #-}
2795{-# INLINE splitAt #-}
2427splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2796splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2428−splitAt i arr@MutArray{..} =
2797+splitAt i arr =
2429 let maxIndex = length arr - 1
2798 let maxIndex = length arr - 1
2430 in if i < 0
2799 in if i < 0
2431 then error "sliceAt: negative array index"
2800 then error "sliceAt: negative array index"
2432 else if i > maxIndex
2801 else if i > maxIndex
2433 then error $ "sliceAt: specified array index " ++ show i
2802 then error $ "sliceAt: specified array index " ++ show i
2434 ++ " is beyond the maximum index " ++ show maxIndex
2803 ++ " is beyond the maximum index " ++ show maxIndex
2435− else let off = i * SIZE_OF(a)
2804+ else unsafeSplitAt i arr
2436− p = arrStart + off
2437− in ( MutArray
2438− { arrContents = arrContents
2439− , arrStart = arrStart
2440− , arrEnd = p
2441− , arrBound = p
2442− }
2443− , MutArray
2444− { arrContents = arrContents
2445− , arrStart = p
2446− , arrEnd = arrEnd
2447− , arrBound = arrBound
2448− }
2449− )
2450
2805
2451-------------------------------------------------------------------------------
2806-------------------------------------------------------------------------------
2452-- Casting
2807-- Casting
@@ -2496,9 +2851,13 @@ cast arr =
2496-- 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
2497-- it safe to pass heap-allocated objects to unsafe functions.
2852-- it safe to pass heap-allocated objects to unsafe functions.
2498
2853
2499−-- 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
2500-- 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
2501-- 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.
2502
2861
2503-- | 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
2504-- 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.
@@ -2516,16 +2875,21 @@ cast arr =
2516--
2875--
2517-- /Pre-release/
2876-- /Pre-release/
2518--
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." #-}
2519{-# INLINE asPtrUnsafe #-}
2885{-# INLINE asPtrUnsafe #-}
2520asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2886asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2521−asPtrUnsafe arr f =
2887+asPtrUnsafe = unsafePinnedAsPtr
2522− Unboxed.asPtrUnsafe
2523− (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2524
2888
2525−{-# INLINE asUnpinnedPtrUnsafe #-}
2889+{-# INLINE unsafeAsPtr #-}
2526−asUnpinnedPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2890+unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2527−asUnpinnedPtrUnsafe arr f =
2891+unsafeAsPtr arr f =
2528− Unboxed.asUnpinnedPtrUnsafe
2892+ Unboxed.unsafeAsPtr
2529 (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2893 (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2530
2894
2531-------------------------------------------------------------------------------
2895-------------------------------------------------------------------------------
@@ -2543,28 +2907,26 @@ asUnpinnedPtrUnsafe arr f =
2543-- /Pre-release/
2907-- /Pre-release/
2544{-# INLINE byteCmp #-}
2908{-# INLINE byteCmp #-}
2545byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2909byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2546−byteCmp arr1 arr2 =
2910+byteCmp arr1 arr2 = do
2547− liftIO
2548− $ do
2549− let marr1 = getMutableByteArray# (arrContents arr1)
2911+ let marr1 = getMutableByteArray# (arrContents arr1)
2550− marr2 = getMutableByteArray# (arrContents arr2)
2912+ marr2 = getMutableByteArray# (arrContents arr2)
2551− !(I# st1#) = arrStart arr1
2913+ !(I# st1#) = arrStart arr1
2552− !(I# st2#) = arrStart arr2
2914+ !(I# st2#) = arrStart arr2
2553− !(I# len#) = byteLength arr1
2915+ !(I# len#) = byteLength arr1
2554− case compare (byteLength arr1) (byteLength arr2) of
2916+ case compare (byteLength arr1) (byteLength arr2) of
2555− EQ -> do
2917+ EQ -> do
2556− r <- liftIO $ IO $ \s# ->
2918+ r <- liftIO $ IO $ \s# ->
2557− let res =
2919+ let res =
2558− I#
2920+ I#
2559− (compareByteArrays#
2921+ (compareByteArrays#
2560− (unsafeCoerce# marr1)
2922+ (unsafeCoerce# marr1)
2561− st1#
2923+ st1#
2562− (unsafeCoerce# marr2)
2924+ (unsafeCoerce# marr2)
2563− st2#
2925+ st2#
2564− len#)
2926+ len#)
2565− in (# s#, res #)
2927+ in (# s#, res #)
2566− return $ compare r 0
2928+ return $ compare r 0
2567− x -> return x
2929+ x -> return x
2568
2930
2569{-# INLINE cmp #-}
2931{-# INLINE cmp #-}
2570{-# DEPRECATED cmp "Please use byteCmp instead." #-}
2932{-# DEPRECATED cmp "Please use byteCmp instead." #-}
@@ -2581,7 +2943,309 @@ byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
2581byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2943byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2582
2944
2583-------------------------------------------------------------------------------
2945-------------------------------------------------------------------------------
2584−-- NFData
2946+-- Compact
2947+-------------------------------------------------------------------------------
2948+
2949+-- Note: LE versions avoid an extra copy compared to GE. LE parser trades
2950+-- backtracking one array in lieu of avoiding a copy. However, LE and GE both
2951+-- can leave some memory unused. They can split the last array to fit it
2952+-- exactly in the space.
2953+
2954+{-# INLINE_NORMAL pCompactLeAs #-}
2955+pCompactLeAs ::
2956+ forall m a. (MonadIO m, Unbox a)
2957+ => PinnedState -> Int -> Parser (MutArray a) m (MutArray a)
2958+pCompactLeAs ps maxElems = Parser step initial extract
2959+
2960+ where
2961+
2962+ maxBytes = maxElems * SIZE_OF(a)
2963+
2964+ functionName = "Streamly.Internal.Data.MutArray.pCompactLE"
2965+
2966+ initial =
2967+ return
2968+ $ if maxElems <= 0
2969+ then error
2970+ $ functionName
2971+ ++ ": the size of arrays ["
2972+ ++ show maxElems ++ "] must be a natural number"
2973+ else Parser.IPartial Nothing
2974+
2975+ step Nothing arr =
2976+ return
2977+ $ let len = byteLength arr
2978+ in if len >= maxBytes
2979+ then Parser.Done 0 arr
2980+ else Parser.Partial 0 (Just arr)
2981+ -- XXX Split the last array to use the space more compactly.
2982+ step (Just buf) arr =
2983+ let len = byteLength buf + byteLength arr
2984+ in if len > maxBytes
2985+ then return $ Parser.Done 1 buf
2986+ else do
2987+ buf1 <-
2988+ if byteCapacity buf < maxBytes
2989+ then liftIO $ reallocExplicitAs
2990+ ps (SIZE_OF(a)) maxBytes buf
2991+ else return buf
2992+ buf2 <- spliceUnsafe buf1 arr
2993+ return $ Parser.Partial 0 (Just buf2)
2994+
2995+ extract Nothing = return $ Parser.Done 0 nil
2996+ extract (Just buf) = return $ Parser.Done 0 buf
2997+
2998+-- | Parser @pCompactLE maxElems@ coalesces adjacent arrays in the input stream
2999+-- only if the combined size would be less than or equal to @maxElems@
3000+-- elements. Note that it won't split an array if the original array is already
3001+-- larger than maxElems.
3002+--
3003+-- @maxElems@ must be greater than 0.
3004+--
3005+-- Generates unpinned arrays irrespective of the pinning status of input
3006+-- arrays.
3007+--
3008+-- /Internal/
3009+{-# INLINE pCompactLE #-}
3010+pCompactLE ::
3011+ forall m a. (MonadIO m, Unbox a)
3012+ => Int -> Parser (MutArray a) m (MutArray a)
3013+pCompactLE = pCompactLeAs Unpinned
3014+
3015+-- | Pinned version of 'pCompactLE'.
3016+{-# INLINE pPinnedCompactLE #-}
3017+pPinnedCompactLE ::
3018+ forall m a. (MonadIO m, Unbox a)
3019+ => Int -> Parser (MutArray a) m (MutArray a)
3020+pPinnedCompactLE = pCompactLeAs Pinned
3021+
3022+data SpliceState s arr
3023+ = SpliceInitial s
3024+ | SpliceBuffering s arr
3025+ | SpliceYielding arr (SpliceState s arr)
3026+ | SpliceFinish
3027+
3028+-- This mutates the first array (if it has space) to append values from the
3029+-- second one. This would work for immutable arrays as well because an
3030+-- immutable array never has additional space so a new array is allocated
3031+-- instead of mutating it.
3032+
3033+{-# INLINE_NORMAL compactLeAs #-}
3034+compactLeAs :: forall m a. (MonadIO m, Unbox a)
3035+ => PinnedState -> Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
3036+compactLeAs ps maxElems (D.Stream step state) =
3037+ D.Stream step' (SpliceInitial state)
3038+
3039+ where
3040+
3041+ maxBytes = maxElems * SIZE_OF(a)
3042+
3043+ functionName = "Streamly.Internal.Data.MutArray.rCompactLE"
3044+
3045+ {-# INLINE_LATE step' #-}
3046+ step' gst (SpliceInitial st) = do
3047+ when (maxElems <= 0) $
3048+ -- XXX we can pass the module string from the higher level API
3049+ error $ functionName ++ ": the size of arrays [" ++ show maxElems
3050+ ++ "] must be a natural number"
3051+ r <- step gst st
3052+ case r of
3053+ D.Yield arr s -> return $
3054+ let len = byteLength arr
3055+ in if len >= maxBytes
3056+ then D.Skip (SpliceYielding arr (SpliceInitial s))
3057+ else D.Skip (SpliceBuffering s arr)
3058+ D.Skip s -> return $ D.Skip (SpliceInitial s)
3059+ D.Stop -> return D.Stop
3060+
3061+ -- XXX Split the last array to use the space more compactly.
3062+ step' gst (SpliceBuffering st buf) = do
3063+ r <- step gst st
3064+ case r of
3065+ D.Yield arr s -> do
3066+ let len = byteLength buf + byteLength arr
3067+ if len > maxBytes
3068+ then return $
3069+ D.Skip (SpliceYielding buf (SpliceBuffering s arr))
3070+ else do
3071+ buf1 <- if byteCapacity buf < maxBytes
3072+ then liftIO $ reallocExplicitAs
3073+ ps (SIZE_OF(a)) maxBytes buf
3074+ else return buf
3075+ buf2 <- spliceUnsafe buf1 arr
3076+ return $ D.Skip (SpliceBuffering s buf2)
3077+ D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
3078+ D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
3079+
3080+ step' _ SpliceFinish = return D.Stop
3081+
3082+ step' _ (SpliceYielding arr next) = return $ D.Yield arr next
3083+
3084+
3085+{-# INLINE_NORMAL fCompactGeAs #-}
3086+fCompactGeAs ::
3087+ forall m a. (MonadIO m, Unbox a)
3088+ => PinnedState -> Int -> FL.Fold m (MutArray a) (MutArray a)
3089+fCompactGeAs ps minElems = Fold step initial extract extract
3090+
3091+ where
3092+
3093+ minBytes = minElems * SIZE_OF(a)
3094+
3095+ functionName = "Streamly.Internal.Data.MutArray.fCompactGE"
3096+
3097+ initial =
3098+ return
3099+ $ if minElems < 0
3100+ then error
3101+ $ functionName
3102+ ++ ": the size of arrays ["
3103+ ++ show minElems ++ "] must be a natural number"
3104+ else FL.Partial Nothing
3105+
3106+ step Nothing arr =
3107+ return
3108+ $ let len = byteLength arr
3109+ in if len >= minBytes
3110+ then FL.Done arr
3111+ else FL.Partial (Just arr)
3112+ -- XXX Buffer arrays as a list to avoid copy and reallocations
3113+ step (Just buf) arr = do
3114+ let len = byteLength buf + byteLength arr
3115+ buf1 <-
3116+ if byteCapacity buf < len
3117+ then liftIO $ reallocExplicitAs
3118+ ps (SIZE_OF(a)) (max minBytes len) buf
3119+ else return buf
3120+ buf2 <- spliceUnsafe buf1 arr
3121+ if len >= minBytes
3122+ then return $ FL.Done buf2
3123+ else return $ FL.Partial (Just buf2)
3124+
3125+ extract Nothing = return nil
3126+ extract (Just buf) = return buf
3127+
3128+-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
3129+-- until the size becomes greater than or equal to @minElems@.
3130+--
3131+-- Generates unpinned arrays irrespective of the pinning status of input
3132+-- arrays.
3133+{-# INLINE fCompactGE #-}
3134+fCompactGE ::
3135+ forall m a. (MonadIO m, Unbox a)
3136+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3137+fCompactGE = fCompactGeAs Unpinned
3138+
3139+-- | Pinned version of 'fCompactGE'.
3140+{-# INLINE fPinnedCompactGE #-}
3141+fPinnedCompactGE ::
3142+ forall m a. (MonadIO m, Unbox a)
3143+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3144+fPinnedCompactGE = fCompactGeAs Pinned
3145+
3146+{-# INLINE_NORMAL lCompactGeAs #-}
3147+lCompactGeAs :: forall m a. (MonadIO m, Unbox a)
3148+ => PinnedState -> Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3149+-- The fold version turns out to be a little bit slower.
3150+-- lCompactGeAs ps n = FL.many (fCompactGeAs ps n)
3151+lCompactGeAs ps minElems (Fold step1 initial1 _ final1) =
3152+ Fold step initial extract final
3153+
3154+ where
3155+
3156+ minBytes = minElems * SIZE_OF(a)
3157+
3158+ functionName = "Streamly.Internal.Data.MutArray.lCompactGE"
3159+
3160+ initial = do
3161+ when (minElems <= 0) $
3162+ -- XXX we can pass the module string from the higher level API
3163+ error $ functionName ++ ": the size of arrays ["
3164+ ++ show minElems ++ "] must be a natural number"
3165+
3166+ r <- initial1
3167+ return $ first (Tuple' Nothing) r
3168+
3169+ {-# INLINE runInner #-}
3170+ runInner len acc buf =
3171+ if len >= minBytes
3172+ then do
3173+ r <- step1 acc buf
3174+ case r of
3175+ FL.Done _ -> return $ FL.Done ()
3176+ FL.Partial s -> do
3177+ _ <- final1 s
3178+ res <- initial1
3179+ return $ first (Tuple' Nothing) res
3180+ else return $ FL.Partial $ Tuple' (Just buf) acc
3181+
3182+ step (Tuple' Nothing r1) arr =
3183+ runInner (byteLength arr) r1 arr
3184+
3185+ -- XXX Buffer arrays as a list to avoid copy and reallocations
3186+ step (Tuple' (Just buf) r1) arr = do
3187+ let len = byteLength buf + byteLength arr
3188+ buf1 <- if byteCapacity buf < len
3189+ then liftIO $ reallocExplicitAs
3190+ ps (SIZE_OF(a)) (max minBytes len) buf
3191+ else return buf
3192+ buf2 <- spliceUnsafe buf1 arr
3193+ runInner len r1 buf2
3194+
3195+ -- XXX Several folds do extract >=> final, therefore, we need to make final
3196+ -- return "m b" rather than using extract post it if we want extract to be
3197+ -- partial.
3198+ --
3199+ -- extract forces the pending buffer to be sent to the fold which is not
3200+ -- what we want.
3201+ extract _ = error "lCompactGE: not designed for scanning"
3202+
3203+ final (Tuple' Nothing r1) = final1 r1
3204+ final (Tuple' (Just buf) r1) = do
3205+ r <- step1 r1 buf
3206+ case r of
3207+ FL.Partial rr -> final1 rr
3208+ FL.Done _ -> return ()
3209+
3210+-- | Like 'compactGE' but for transforming folds instead of stream.
3211+--
3212+-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
3213+--
3214+-- Generates unpinned arrays irrespective of the pinning status of input
3215+-- arrays.
3216+{-# INLINE lCompactGE #-}
3217+lCompactGE :: forall m a. (MonadIO m, Unbox a)
3218+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3219+lCompactGE = lCompactGeAs Unpinned
3220+
3221+-- | Pinned version of 'lCompactGE'.
3222+{-# INLINE lPinnedCompactGE #-}
3223+lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a)
3224+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3225+lPinnedCompactGE = lCompactGeAs Pinned
3226+
3227+-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
3228+-- the size becomes greater than or equal to @n@.
3229+--
3230+-- >>> compactGE n = Stream.foldMany (MutArray.fCompactGE n)
3231+--
3232+{-# INLINE compactGE #-}
3233+compactGE ::
3234+ (MonadIO m, Unbox a)
3235+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3236+compactGE n = D.foldMany (fCompactGE n)
3237+
3238+-- | 'compactEQ n' coalesces adajacent arrays in the input stream to
3239+-- arrays of exact size @n@.
3240+--
3241+-- /Unimplemented/
3242+{-# INLINE compactEQ #-}
3243+compactEQ :: -- (MonadIO m, Unbox a) =>
3244+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3245+compactEQ _n = undefined -- D.parseManyD (pCompactEQ n)
3246+
3247+-------------------------------------------------------------------------------
3248+-- In-place mutation algorithms
2585-------------------------------------------------------------------------------
3249-------------------------------------------------------------------------------
2586
3250
2587-- | Strip elements which match with predicate from both ends.
3251-- | Strip elements which match with predicate from both ends.
core/src/Streamly/Internal/Data/MutByteArray/Type.hs+40−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
@@ -83,6 +87,9 @@ touch :: MutByteArray -> IO ()
83touch (MutByteArray contents) =
87touch (MutByteArray contents) =
84 IO $ \s -> case touch# contents s of s' -> (# s', () #)
88 IO $ \s -> case touch# contents s of s' -> (# s', () #)
85
89
90+-- XXX Some functions in this module are "IO" and others are "m", we need to
91+-- make it consistent.
92+
86-- XXX We can provide another API for "unsafe" FFI calls passing an unlifted
93-- XXX We can provide another API for "unsafe" FFI calls passing an unlifted
87-- pointer to the FFI call. For unsafe calls we do not need to pin the array.
94-- pointer to the FFI call. For unsafe calls we do not need to pin the array.
88-- We can pass an unlifted pointer to the FFI routine to avoid GC kicking in
95-- We can pass an unlifted pointer to the FFI routine to avoid GC kicking in
@@ -111,9 +118,9 @@ touch (MutByteArray contents) =
111--
118--
112-- /Pre-release/
119-- /Pre-release/
113--
120--
114−{-# INLINE asPtrUnsafe #-}
121+{-# INLINE unsafePinnedAsPtr #-}
115−asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
122+unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
116−asPtrUnsafe arr f = do
123+unsafePinnedAsPtr arr f = do
117 contents <- liftIO $ pin arr
124 contents <- liftIO $ pin arr
118 let !ptr = Ptr (byteArrayContents#
125 let !ptr = Ptr (byteArrayContents#
119 (unsafeCoerce# (getMutableByteArray# contents)))
126 (unsafeCoerce# (getMutableByteArray# contents)))
@@ -121,10 +128,15 @@ asPtrUnsafe arr f = do
121 liftIO $ touch contents
128 liftIO $ touch contents
122 return r
129 return r
123
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+
124-- | 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.
125−{-# INLINE asUnpinnedPtrUnsafe #-}
137+{-# INLINE unsafeAsPtr #-}
126−asUnpinnedPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
138+unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
127−asUnpinnedPtrUnsafe arr f = do
139+unsafeAsPtr arr f = do
128 let !ptr = Ptr (byteArrayContents#
140 let !ptr = Ptr (byteArrayContents#
129 (unsafeCoerce# (getMutableByteArray# arr)))
141 (unsafeCoerce# (getMutableByteArray# arr)))
130 r <- f ptr
142 r <- f ptr
@@ -135,10 +147,16 @@ asUnpinnedPtrUnsafe arr f = do
135-- Creation
147-- Creation
136--------------------------------------------------------------------------------
148--------------------------------------------------------------------------------
137
149
138−{-# NOINLINE nil #-}
150+{-# NOINLINE empty #-}
151+empty :: MutByteArray
152+empty = unsafePerformIO $ new 0
153+
154+{-# DEPRECATED nil "Please use empty instead" #-}
139nil :: MutByteArray
155nil :: MutByteArray
140−nil = unsafePerformIO $ new 0
156+nil = empty
141
157
158+-- XXX add "newRounded" to round up the large size to the next page boundary
159+-- and return the allocated size.
142{-# INLINE new #-}
160{-# INLINE new #-}
143new :: Int -> IO MutByteArray
161new :: Int -> IO MutByteArray
144new nbytes | nbytes < 0 =
162new nbytes | nbytes < 0 =
@@ -152,7 +170,7 @@ new (I# nbytes) = IO $ \s ->
152{-# INLINE pinnedNew #-}
170{-# INLINE pinnedNew #-}
153pinnedNew :: Int -> IO MutByteArray
171pinnedNew :: Int -> IO MutByteArray
154pinnedNew nbytes | nbytes < 0 =
172pinnedNew nbytes | nbytes < 0 =
155− errorWithoutStackTrace "pinnedNewByteArray: size must be >= 0"
173+ errorWithoutStackTrace "pinnedNew: size must be >= 0"
156pinnedNew (I# nbytes) = IO $ \s ->
174pinnedNew (I# nbytes) = IO $ \s ->
157 case newPinnedByteArray# nbytes s of
175 case newPinnedByteArray# nbytes s of
158 (# s', mbarr# #) ->
176 (# s', mbarr# #) ->
@@ -178,6 +196,12 @@ newBytesAs Pinned = pinnedNew
178-- Copying
196-- Copying
179-------------------------------------------------------------------------------
197-------------------------------------------------------------------------------
180
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+
181-- | 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.
182-- 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
183-- 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+53−27
@@ -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--
@@ -1537,7 +1582,7 @@ reverse m = Stream step Nothing
1537{-# INLINE reverseUnbox #-}
1582{-# INLINE reverseUnbox #-}
1538reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1583reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1539reverseUnbox =
1584reverseUnbox =
1540− A.concatChunksRev -- unfoldMany A.readerRev
1585+ A.concatRev -- unfoldMany A.readerRev
1541 . fromStreamK
1586 . fromStreamK
1542 . K.reverse
1587 . K.reverse
1543 . toStreamK
1588 . toStreamK
@@ -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+4−9
@@ -103,15 +103,14 @@ 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)
109−import Streamly.Internal.Data.Unbox (Unbox)
110import Streamly.Internal.Data.Unfold.Type (Unfold(..))
109import Streamly.Internal.Data.Unfold.Type (Unfold(..))
111-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
110-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
112import Streamly.Internal.System.IO (defaultChunkSize)
111import Streamly.Internal.System.IO (defaultChunkSize)
113
112
114−import qualified Streamly.Data.Array as A
113+import qualified Streamly.Internal.Data.Array as A
115import qualified Streamly.Data.Stream as S
114import qualified Streamly.Data.Stream as S
116import qualified Streamly.Data.Unfold as UF
115import qualified Streamly.Data.Unfold as UF
117import qualified Streamly.Internal.Data.Array.Type as IA (pinnedChunksOf)
116import qualified Streamly.Internal.Data.Array.Type as IA (pinnedChunksOf)
@@ -339,10 +338,6 @@ readWithBufferOf = readerWith
339reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
338reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
340reader = UF.many A.reader (usingFile FH.chunkReader)
339reader = UF.many A.reader (usingFile FH.chunkReader)
341
340
342−{-# INLINE concatChunks #-}
343−concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
344−concatChunks = S.unfoldMany A.reader
345−
346-- | Generate a stream of bytes from a file specified by path. The stream ends
341-- | Generate a stream of bytes from a file specified by path. The stream ends
347-- when EOF is encountered. File is locked using multiple reader and single
342-- when EOF is encountered. File is locked using multiple reader and single
348-- writer locking mode.
343-- writer locking mode.
@@ -351,7 +346,7 @@ concatChunks = S.unfoldMany A.reader
351--
346--
352{-# INLINE read #-}
347{-# INLINE read #-}
353read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
348read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
354−read file = concatChunks $ withFile file ReadMode FH.readChunks
349+read file = A.concat $ withFile file ReadMode FH.readChunks
355
350
356{-# DEPRECATED toBytes "Please use 'read' instead" #-}
351{-# DEPRECATED toBytes "Please use 'read' instead" #-}
357{-# INLINE toBytes #-}
352{-# INLINE toBytes #-}
@@ -467,7 +462,7 @@ writeChunks path = Fold step initial extract final
467writeWith :: (MonadIO m, MonadCatch m)
462writeWith :: (MonadIO m, MonadCatch m)
468 => Int -> FilePath -> Fold m Word8 ()
463 => Int -> FilePath -> Fold m Word8 ()
469writeWith n path =
464writeWith n path =
470− groupsOf n (pinnedWriteNUnsafe n) (writeChunks path)
465+ groupsOf n (A.unsafePinnedCreateOf n) (writeChunks path)
471
466
472{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
467{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
473{-# INLINE writeWithBufferOf #-}
468{-# INLINE writeWithBufferOf #-}
core/src/Streamly/Internal/FileSystem/Handle.hs+21−28
@@ -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,16 +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.Internal.Data.Array.Stream (lpackArraysChunksOf)
137-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
136-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
138import Streamly.Internal.System.IO (defaultChunkSize)
137import Streamly.Internal.System.IO (defaultChunkSize)
139
138
140import qualified Streamly.Data.Fold as FL
139import qualified Streamly.Data.Fold as FL
141−import qualified Streamly.Data.Array as A
140+import qualified Streamly.Internal.Data.Array as A
142−import qualified Streamly.Internal.Data.Array.Type as A
143−import qualified Streamly.Internal.Data.Array.Stream as AS
144import qualified Streamly.Internal.Data.MutArray.Type as MArray
141import qualified Streamly.Internal.Data.MutArray.Type as MArray
145import qualified Streamly.Internal.Data.Refold.Type as Refold
142import qualified Streamly.Internal.Data.Refold.Type as Refold
146import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
143import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
@@ -169,6 +166,8 @@ import qualified Streamly.Internal.Data.StreamK.Type as K (mkStream)
169-- Array IO (Input)
166-- Array IO (Input)
170-------------------------------------------------------------------------------
167-------------------------------------------------------------------------------
171
168
169+-- XXX add an API that compacts the arrays to an exact size.
170+
172-- | 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
173-- 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
174-- 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
@@ -178,9 +177,9 @@ import qualified Streamly.Internal.Data.StreamK.Type as K (mkStream)
178{-# INLINABLE getChunk #-}
177{-# INLINABLE getChunk #-}
179getChunk :: MonadIO m => Int -> Handle -> m (Array Word8)
178getChunk :: MonadIO m => Int -> Handle -> m (Array Word8)
180getChunk size h = liftIO $ do
179getChunk size h = liftIO $ do
181− arr <- MArray.pinnedNewBytes size
180+ arr :: MArray.MutArray Word8 <- MArray.pinnedEmptyOf size
182 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
181 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
183− MArray.asPtrUnsafe arr $ \p -> do
182+ MArray.unsafePinnedAsPtr arr $ \p -> do
184 n <- hGetBufSome h p size
183 n <- hGetBufSome h p size
185 -- XXX shrink only if the diff is significant
184 -- XXX shrink only if the diff is significant
186 return $
185 return $
@@ -338,10 +337,6 @@ readerWith = UF.many A.reader chunkReaderWith
338readWithBufferOf :: MonadIO m => Unfold m (Int, Handle) Word8
337readWithBufferOf :: MonadIO m => Unfold m (Int, Handle) Word8
339readWithBufferOf = readerWith
338readWithBufferOf = readerWith
340
339
341−{-# INLINE concatChunks #-}
342−concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
343−concatChunks = S.unfoldMany A.reader
344−
345-- | @readWith bufsize handle@ reads a byte stream from a file
340-- | @readWith bufsize handle@ reads a byte stream from a file
346-- handle, reads are performed in chunks of up to @bufsize@.
341-- handle, reads are performed in chunks of up to @bufsize@.
347--
342--
@@ -350,7 +345,7 @@ concatChunks = S.unfoldMany A.reader
350-- /Pre-release/
345-- /Pre-release/
351{-# INLINE readWith #-}
346{-# INLINE readWith #-}
352readWith :: MonadIO m => Int -> Handle -> Stream m Word8
347readWith :: MonadIO m => Int -> Handle -> Stream m Word8
353−readWith size h = concatChunks $ readChunksWith size h
348+readWith size h = A.concat $ readChunksWith size h
354
349
355-- | Unfolds a file handle into a byte stream. IO requests to the device are
350-- | Unfolds a file handle into a byte stream. IO requests to the device are
356-- performed in sizes of
351-- performed in sizes of
@@ -369,7 +364,7 @@ reader = UF.many A.reader chunkReader
369-- /Pre-release/
364-- /Pre-release/
370{-# INLINE read #-}
365{-# INLINE read #-}
371read :: MonadIO m => Handle -> Stream m Word8
366read :: MonadIO m => Handle -> Stream m Word8
372−read = concatChunks . readChunks
367+read = A.concat . readChunks
373
368
374-------------------------------------------------------------------------------
369-------------------------------------------------------------------------------
375-- Writing
370-- Writing
@@ -384,12 +379,12 @@ read = concatChunks . readChunks
384{-# INLINABLE putChunk #-}
379{-# INLINABLE putChunk #-}
385putChunk :: MonadIO m => Handle -> Array a -> m ()
380putChunk :: MonadIO m => Handle -> Array a -> m ()
386putChunk _ arr | byteLength arr == 0 = return ()
381putChunk _ arr | byteLength arr == 0 = return ()
387−putChunk h arr = A.asPtrUnsafe arr $ \ptr ->
382+putChunk h arr = A.unsafePinnedAsPtr arr $ \ptr ->
388 liftIO $ hPutBuf h ptr aLen
383 liftIO $ hPutBuf h ptr aLen
389
384
390 where
385 where
391
386
392− -- XXX We should have the length passed by asPtrUnsafe itself.
387+ -- XXX We should have the length passed by unsafePinnedAsPtr itself.
393 aLen = A.byteLength arr
388 aLen = A.byteLength arr
394
389
395-------------------------------------------------------------------------------
390-------------------------------------------------------------------------------
@@ -421,7 +416,7 @@ putChunks h = S.fold (FL.drainMapM (putChunk h))
421{-# INLINE putChunksWith #-}
416{-# INLINE putChunksWith #-}
422putChunksWith :: (MonadIO m, Unbox a)
417putChunksWith :: (MonadIO m, Unbox a)
423 => Int -> Handle -> Stream m (Array a) -> m ()
418 => Int -> Handle -> Stream m (Array a) -> m ()
424−putChunksWith n h xs = putChunks h $ AS.compact n xs
419+putChunksWith n h xs = putChunks h $ A.compactLE n xs
425
420
426-- > putBytesWith n h m = Handle.putChunks h $ A.pinnedChunksOf n m
421-- > putBytesWith n h m = Handle.putChunks h $ A.pinnedChunksOf n m
427
422
@@ -461,8 +456,6 @@ writeChunks h = FL.drainMapM (putChunk h)
461chunkWriter :: MonadIO m => Refold m Handle (Array a) ()
456chunkWriter :: MonadIO m => Refold m Handle (Array a) ()
462chunkWriter = Refold.drainBy putChunk
457chunkWriter = Refold.drainBy putChunk
463
458
464−-- XXX lpackArraysChunksOf should be written idiomatically
465−
466-- | @writeChunksWith bufsize handle@ writes a stream of arrays
459-- | @writeChunksWith bufsize handle@ writes a stream of arrays
467-- to @handle@ after coalescing the adjacent arrays in chunks of @bufsize@.
460-- to @handle@ after coalescing the adjacent arrays in chunks of @bufsize@.
468-- We never split an array, if a single array is bigger than the specified size
461-- We never split an array, if a single array is bigger than the specified size
@@ -472,7 +465,7 @@ chunkWriter = Refold.drainBy putChunk
472{-# INLINE writeChunksWith #-}
465{-# INLINE writeChunksWith #-}
473writeChunksWith :: (MonadIO m, Unbox a)
466writeChunksWith :: (MonadIO m, Unbox a)
474 => Int -> Handle -> Fold m (Array a) ()
467 => Int -> Handle -> Fold m (Array a) ()
475−writeChunksWith n h = lpackArraysChunksOf n (writeChunks h)
468+writeChunksWith n h = A.lCompactGE n (writeChunks h)
476
469
477-- | Same as 'writeChunksWith'
470-- | Same as 'writeChunksWith'
478--
471--
@@ -496,11 +489,11 @@ writeChunksWithBufferOf = writeChunksWith
496-- 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
497-- of @reqSize@ and then written to the IO device.
490-- of @reqSize@ and then written to the IO device.
498--
491--
499−-- >>> 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)
500--
493--
501{-# INLINE writeWith #-}
494{-# INLINE writeWith #-}
502writeWith :: MonadIO m => Int -> Handle -> Fold m Word8 ()
495writeWith :: MonadIO m => Int -> Handle -> Fold m Word8 ()
503−writeWith n h = FL.groupsOf n (pinnedWriteNUnsafe n) (writeChunks h)
496+writeWith n h = FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks h)
504
497
505-- | Same as 'writeWith'
498-- | Same as 'writeWith'
506--
499--
@@ -518,7 +511,7 @@ writeWithBufferOf = writeWith
518writeMaybesWith :: (MonadIO m )
511writeMaybesWith :: (MonadIO m )
519 => Int -> Handle -> Fold m (Maybe Word8) ()
512 => Int -> Handle -> Fold m (Maybe Word8) ()
520writeMaybesWith n h =
513writeMaybesWith n h =
521− let writeNJusts = FL.lmap fromJust $ A.pinnedWriteN n
514+ let writeNJusts = FL.lmap fromJust $ A.pinnedCreateOf n
522 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
515 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
523 in FL.many writeOnNothing (writeChunks h)
516 in FL.many writeOnNothing (writeChunks h)
524
517
@@ -528,7 +521,7 @@ writeMaybesWith n h =
528{-# INLINE writerWith #-}
521{-# INLINE writerWith #-}
529writerWith :: MonadIO m => Int -> Refold m Handle Word8 ()
522writerWith :: MonadIO m => Int -> Refold m Handle Word8 ()
530writerWith n =
523writerWith n =
531− FL.refoldMany (FL.take n $ pinnedWriteNUnsafe n) chunkWriter
524+ FL.refoldMany (FL.take n $ A.unsafePinnedCreateOf n) chunkWriter
532
525
533-- | 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
534-- 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/FileSystem/Path.hs+36−4
@@ -36,7 +36,7 @@
36module Streamly.Internal.FileSystem.Path
36module Streamly.Internal.FileSystem.Path
37 (
37 (
38 -- * Path Types
38 -- * Path Types
39− Path
39+ Path (..)
40 , File
40 , File
41 , Dir
41 , Dir
42 , Abs
42 , Abs
@@ -82,6 +82,11 @@ module Streamly.Internal.FileSystem.Path
82 , toChars
82 , toChars
83
83
84 -- * Operations
84 -- * Operations
85+ -- Do we need to export the separator functions? They are not essential if
86+ -- operations to split and combine paths are provided. If someone wants to
87+ -- work on paths at low level then they know what they are.
88+ , primarySeparator
89+ , isSeparator
85 , extendPath
90 , extendPath
86 , extendDir
91 , extendDir
87 )
92 )
@@ -89,6 +94,7 @@ where
89
94
90import Control.Exception (Exception)
95import Control.Exception (Exception)
91import Control.Monad.Catch (MonadThrow(..))
96import Control.Monad.Catch (MonadThrow(..))
97+import Data.Char (chr)
92import Data.Functor.Identity (Identity(..))
98import Data.Functor.Identity (Identity(..))
93import Data.Word (Word8)
99import Data.Word (Word8)
94#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
100#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
@@ -151,6 +157,15 @@ instance Exception PathException
151-- | A type representing file system paths for directories or files.
157-- | A type representing file system paths for directories or files.
152newtype Path = Path (Array WORD_TYPE) -- deriving Eq
158newtype Path = Path (Array WORD_TYPE) -- deriving Eq
153
159
160+-- Show instance prints raw bytes without any decoding for rountdtripping.
161+-- Should we print this as a string instead, may be useful for ascii chars but
162+-- utf8 encoded chars may be unprintable. Better use toString if you want to
163+-- pretty print the path.
164+{-
165+instance Show Path where
166+ show (Path x) = show x
167+-}
168+
154-- XXX Do we need a type for file or dir Name as names cannot have the
169-- XXX Do we need a type for file or dir Name as names cannot have the
155-- separator char and there may be other restrictions on names? For example,
170-- separator char and there may be other restrictions on names? For example,
156-- length restriction. A file name cannot be "." or "..". We can use the types
171-- length restriction. A file name cannot be "." or "..". We can use the types
@@ -438,8 +453,25 @@ mkRelFile = undefined
438-- Operations
453-- Operations
439------------------------------------------------------------------------------
454------------------------------------------------------------------------------
440
455
441−separator :: WORD_TYPE
456+separatorWord :: WORD_TYPE
442−separator = SEPARATOR
457+separatorWord = SEPARATOR
458+
459+-- Portable definition for exporting.
460+
461+-- | Primary path separator character, @/@ on Posix and @\\@ on Windows.
462+-- Windows supports @/@ too as a separator. Please use 'isSeparator' for
463+-- testing if a char is a separator char.
464+primarySeparator :: Char
465+primarySeparator = chr (SEPARATOR)
466+
467+-- | On Posix only @/@ is a path separator but in windows it could be either
468+-- @/@ or @\\@.
469+isSeparator :: Char -> Bool
470+#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
471+isSeparator c = (c == '/') || (c == '\\')
472+#else
473+isSeparator = (== '/')
474+#endif
443
475
444-- If we append an absolute path it may fail with an error if the 'Path'
476-- If we append an absolute path it may fail with an error if the 'Path'
445-- implementation stores absolute path information (a leading separator char).
477-- implementation stores absolute path information (a leading separator char).
@@ -465,7 +497,7 @@ extendPath (Path a) (Path b) =
465 newArr = unsafePerformIO $ do
497 newArr = unsafePerformIO $ do
466 arr <- MutArray.new len
498 arr <- MutArray.new len
467 arr1 <- MutArray.spliceUnsafe arr (Array.unsafeThaw a)
499 arr1 <- MutArray.spliceUnsafe arr (Array.unsafeThaw a)
468− arr2 <- MutArray.snocUnsafe arr1 separator
500+ arr2 <- MutArray.snocUnsafe arr1 separatorWord
469 arr3 <- MutArray.spliceUnsafe arr2 (Array.unsafeThaw b)
501 arr3 <- MutArray.spliceUnsafe arr2 (Array.unsafeThaw b)
470 return (Array.unsafeFreeze arr3)
502 return (Array.unsafeFreeze arr3)
471 in Path newArr
503 in Path newArr
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/Common.hs+1−1
@@ -529,7 +529,7 @@ reverse' :: (IsStream t, MonadIO m, Unbox a) => t m a -> t m a
529-- reverse' s = fromStreamD $ D.reverse' $ toStreamD s
529-- reverse' s = fromStreamD $ D.reverse' $ toStreamD s
530reverse' =
530reverse' =
531 fromStreamD
531 fromStreamD
532− . A.concatChunksRev -- unfoldMany A.readerRev
532+ . A.concatRev -- unfoldMany A.readerRev
533 . D.fromStreamK
533 . D.fromStreamK
534 . K.reverse
534 . K.reverse
535 . D.toStreamK
535 . D.toStreamK
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+11−10
@@ -87,7 +87,6 @@ import Prelude hiding (read)
87import qualified Network.Socket as Net
87import qualified Network.Socket as Net
88
88
89import Streamly.Internal.Data.Array (Array(..))
89import Streamly.Internal.Data.Array (Array(..))
90−import Streamly.Internal.Data.Array.Stream (lpackArraysChunksOf)
91import Streamly.Data.Fold (Fold)
90import Streamly.Data.Fold (Fold)
92import Streamly.Data.Stream (Stream)
91import Streamly.Data.Stream (Stream)
93import Streamly.Internal.Data.Unfold (Unfold(..))
92import Streamly.Internal.Data.Unfold (Unfold(..))
@@ -99,10 +98,10 @@ import qualified Streamly.Data.Fold as FL
99import qualified Streamly.Data.Stream as S
98import qualified Streamly.Data.Stream as S
100import qualified Streamly.Data.Unfold as UF
99import qualified Streamly.Data.Unfold as UF
101import qualified Streamly.Internal.Data.Array as A
100import qualified Streamly.Internal.Data.Array as A
102− ( unsafeFreeze, asPtrUnsafe, byteLength, pinnedChunksOf,
101+ ( unsafeFreeze, unsafePinnedAsPtr, byteLength, pinnedChunksOf,
103− pinnedWriteN, pinnedWriteNUnsafe )
102+ pinnedCreateOf, unsafePinnedCreateOf, lCompactGE )
104import qualified Streamly.Internal.Data.MutArray as MArray
103import qualified Streamly.Internal.Data.MutArray as MArray
105− (MutArray(..), asPtrUnsafe, pinnedNewBytes)
104+ (MutArray(..), unsafePinnedAsPtr, pinnedEmptyOf)
106import qualified Streamly.Internal.Data.Stream as S (fromStreamK, Stream(..), Step(..))
105import qualified Streamly.Internal.Data.Stream as S (fromStreamK, Stream(..), Step(..))
107import qualified Streamly.Internal.Data.StreamK as K (mkStream)
106import qualified Streamly.Internal.Data.StreamK as K (mkStream)
108
107
@@ -253,6 +252,8 @@ accept tcpListenQ spec addr =
253-- Array IO (Input)
252-- Array IO (Input)
254-------------------------------------------------------------------------------
253-------------------------------------------------------------------------------
255
254
255+-- XXX add an API that compacts the arrays to an exact size.
256+
256{-# INLINABLE readArrayUptoWith #-}
257{-# INLINABLE readArrayUptoWith #-}
257readArrayUptoWith
258readArrayUptoWith
258 :: (h -> Ptr Word8 -> Int -> IO Int)
259 :: (h -> Ptr Word8 -> Int -> IO Int)
@@ -260,9 +261,9 @@ readArrayUptoWith
260 -> h
261 -> h
261 -> IO (Array Word8)
262 -> IO (Array Word8)
262readArrayUptoWith f size h = do
263readArrayUptoWith f size h = do
263− arr <- MArray.pinnedNewBytes size
264+ arr <- MArray.pinnedEmptyOf size
264 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
265 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
265− MArray.asPtrUnsafe arr $ \p -> do
266+ MArray.unsafePinnedAsPtr arr $ \p -> do
266 n <- f h p size
267 n <- f h p size
267 let v = A.unsafeFreeze
268 let v = A.unsafeFreeze
268 $ arr { MArray.arrEnd = n, MArray.arrBound = size }
269 $ arr { MArray.arrEnd = n, MArray.arrBound = size }
@@ -310,7 +311,7 @@ writeArrayWith :: Unbox a
310 -> Array a
311 -> Array a
311 -> IO ()
312 -> IO ()
312writeArrayWith _ _ arr | A.length arr == 0 = return ()
313writeArrayWith _ _ arr | A.length arr == 0 = return ()
313−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
314
315
315 where
316 where
316
317
@@ -473,7 +474,7 @@ writeChunks h = FL.drainMapM (liftIO . putChunk h)
473{-# INLINE writeChunksWith #-}
474{-# INLINE writeChunksWith #-}
474writeChunksWith :: (MonadIO m, Unbox a)
475writeChunksWith :: (MonadIO m, Unbox a)
475 => Int -> Socket -> Fold m (Array a) ()
476 => Int -> Socket -> Fold m (Array a) ()
476−writeChunksWith n h = lpackArraysChunksOf n (writeChunks h)
477+writeChunksWith n h = A.lCompactGE n (writeChunks h)
477
478
478-- | Same as 'writeChunksWith'
479-- | Same as 'writeChunksWith'
479--
480--
@@ -504,7 +505,7 @@ putBytesWith n h m = putChunks h $ A.pinnedChunksOf n m
504--
505--
505{-# INLINE writeWith #-}
506{-# INLINE writeWith #-}
506writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 ()
507writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 ()
507−writeWith n h = FL.groupsOf n (A.pinnedWriteNUnsafe n) (writeChunks h)
508+writeWith n h = FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks h)
508
509
509-- | Same as 'writeWith'
510-- | Same as 'writeWith'
510--
511--
@@ -522,7 +523,7 @@ writeWithBufferOf = writeWith
522writeMaybesWith :: (MonadIO m )
523writeMaybesWith :: (MonadIO m )
523 => Int -> Socket -> Fold m (Maybe Word8) ()
524 => Int -> Socket -> Fold m (Maybe Word8) ()
524writeMaybesWith n h =
525writeMaybesWith n h =
525− let writeNJusts = FL.lmap fromJust $ A.pinnedWriteN n
526+ let writeNJusts = FL.lmap fromJust $ A.pinnedCreateOf n
526 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
527 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
527 in FL.many writeOnNothing (writeChunks h)
528 in FL.many writeOnNothing (writeChunks h)
528
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]