on c6fa580 help sign in
.circleci/config.yml+277−73
since splitsnapshots
unifiedsplit
@@ -1,7 +1,7 @@
1version: 2.1
1version: 2.1
2
2
3#-----------------------------------------------------------------------------
3#-----------------------------------------------------------------------------
4−# packcheck-0.7.0
4+# packcheck-0.4.2
5# Packcheck global environment variables
5# Packcheck global environment variables
6#-----------------------------------------------------------------------------
6#-----------------------------------------------------------------------------
7
7
@@ -11,8 +11,6 @@ env: &env
11 # Common options
11 # Common options
12 # ------------------------------------------------------------------------
12 # ------------------------------------------------------------------------
13 # GHC_OPTIONS: "-Werror"
13 # GHC_OPTIONS: "-Werror"
14− # For updating see: https://downloads.haskell.org/~ghcup/
15− GHCUP_VERSION: 0.1.20.0
16 CABAL_REINIT_CONFIG: "y"
14 CABAL_REINIT_CONFIG: "y"
17 LC_ALL: "C.UTF-8"
15 LC_ALL: "C.UTF-8"
18
16
@@ -24,6 +22,7 @@ env: &env
24 # DISABLE_DOCS: "y"
22 # DISABLE_DOCS: "y"
25 # DISABLE_SDIST_BUILD: "y"
23 # DISABLE_SDIST_BUILD: "y"
26 # DISABLE_DIST_CHECKS: "y"
24 # DISABLE_DIST_CHECKS: "y"
25+ ENABLE_INSTALL: "y"
27
26
28 # ------------------------------------------------------------------------
27 # ------------------------------------------------------------------------
29 # stack options
28 # stack options
@@ -39,12 +38,15 @@ env: &env
39 # cabal options
38 # cabal options
40 # ------------------------------------------------------------------------
39 # ------------------------------------------------------------------------
41 CABAL_CHECK_RELAX: "y"
40 CABAL_CHECK_RELAX: "y"
41+ CABAL_NO_SANDBOX: "y"
42+ CABAL_HACKAGE_MIRROR: "hackage.haskell.org:http://hackage.fpcomplete.com"
42 CABAL_BUILD_OPTIONS: "-j1 --flag limit-build-mem"
43 CABAL_BUILD_OPTIONS: "-j1 --flag limit-build-mem"
43
44
44 # ------------------------------------------------------------------------
45 # ------------------------------------------------------------------------
45 # Where to find the required tools
46 # Where to find the required tools
46 # ------------------------------------------------------------------------
47 # ------------------------------------------------------------------------
47− PATH: /sbin:/usr/sbin:/bin:/usr/bin
48+ PATH: /opt/ghc/bin:/opt/ghcjs/bin:/sbin:/usr/sbin:/bin:/usr/bin
49+ TOOLS_DIR: /opt
48
50
49 # ------------------------------------------------------------------------
51 # ------------------------------------------------------------------------
50 # Location of packcheck.sh (the shell script invoked to perform CI tests ).
52 # Location of packcheck.sh (the shell script invoked to perform CI tests ).
@@ -57,15 +59,15 @@ env: &env
57 # If you have not committed packcheck.sh in your repo at PACKCHECK
59 # If you have not committed packcheck.sh in your repo at PACKCHECK
58 # then it is automatically pulled from this URL.
60 # then it is automatically pulled from this URL.
59 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
61 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
60− PACKCHECK_GITHUB_COMMIT: "f6cfd7b7a33b4bf6fd63cce6a3fb3d26f5031403"
62+ PACKCHECK_GITHUB_COMMIT: "a302772c8f3791c477edd1764b82f8d1f5b22fdf"
61
63
62executors:
64executors:
63 amd64-executor:
65 amd64-executor:
64 docker:
66 docker:
65− - image: ubuntu:latest
67+ - image: ubuntu:xenial
66 x86-executor:
68 x86-executor:
67 docker:
69 docker:
68− - image: i386/ubuntu:focal
70+ - image: i386/ubuntu:eoan
69
71
70#-----------------------------------------------------------------------------
72#-----------------------------------------------------------------------------
71# Common utility stuff, not to be modified usually
73# Common utility stuff, not to be modified usually
@@ -77,50 +79,38 @@ preinstall: &preinstall
77 # required for https/cache save and restore
79 # required for https/cache save and restore
78 apt-get install -y ca-certificates
80 apt-get install -y ca-certificates
79
81
80− # Alternative way of installing ghc and cabal, directly from
82+ # required to (re)generate the configure script
81− # haskell.org instead of using ghcup. NOTE: this is for Debian
82− # only and is debian release specific.
83− # gnupg is required for apt-key to work
84− #apt-get install -y gnupg
85− #apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA3CBA3FFE22B574
86− #echo "deb http://downloads.haskell.org/debian buster main" >> /etc/apt/sources.list
87− #apt-get update
88−
89− # required for outbound https for stack and for stack setup
90− apt-get install -y netbase xz-utils make
83+ apt-get install -y autoconf
91− apt-get install -y zlib1g-dev
92
84
93− # For ghcup to install ghc
85+ # For ghc and cabal-install packages from hvr's ppa
94− if test -n "$GHCUP_VERSION"
86+ # gnupg is required for apt-key to work
95− then
87+ apt-get install -y gnupg
88+ apt-get install -y apt-transport-https
89+ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA3CBA3FFE22B574
96− apt-get install -y gcc
90+ apt-get install -y software-properties-common
97− apt-get install -y g++
91+ add-apt-repository -y ppa:hvr/ghc
98− fi
92+ # echo "deb http://downloads.haskell.org/debian stretch main" >> /etc/apt/sources.list
93+ echo "deb-src http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main" >> /etc/apt/sources.list
94+ apt-get update
99
95
100− # libgmp required by ghc for linking
96+ # required for packcheck
101− apt-get install -y libgmp-dev
97+ apt-get install -y curl
102− apt-get install -y libtinfo-dev
103
98
104− # Required by cabal when git URL is specified in project file
99+ # required for circleci.
100+ apt-get install -y libcurl4-gnutls-dev
105 apt-get install -y git
101 apt-get install -y git
102+ apt-get install -y libtinfo-dev
106
103
107− # Required for and by packcheck
104+ # required for outbound https for stack and for stack setup
108− apt-get install -y curl
105+ apt-get install -y netbase xz-utils make
109
106
107+project-preinstall: &project-preinstall
108+ run: |
110 # Get packcheck if needed
109 # Get packcheck if needed
111− if test ! -e "$PACKCHECK"
110+ CURL=$(which curl)
112− then
113− if test -z "$PACKCHECK_GITHUB_COMMIT"
114− then
115− die "PACKCHECK_GITHUB_COMMIT is not specified."
116− fi
117− PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
111+ PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
118− curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1
112+ if test ! -e "$PACKCHECK"; then $CURL -sL -o "$PACKCHECK" $PACKCHECK_URL; fi;
119− chmod +x $PACKCHECK
120− elif test ! -x "$PACKCHECK"
121− then
122− chmod +x $PACKCHECK
113+ chmod +x $PACKCHECK
123− fi
124
114
125restore: &restore
115restore: &restore
126 # Needs to happen after installing ca-certificates
116 # Needs to happen after installing ca-certificates
@@ -136,71 +126,271 @@ save: &save
136 save_cache:
126 save_cache:
137 key: v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}
127 key: v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}
138 paths:
128 paths:
139− - ~/.local
140 - ~/.cabal
129 - ~/.cabal
130+ - ~/.ghc
131+ - ~/.local
141 - ~/.stack
132 - ~/.stack
142− - ~/.ghcup
143
133
144#-----------------------------------------------------------------------------
134#-----------------------------------------------------------------------------
145# Build matrix
135# Build matrix
146#-----------------------------------------------------------------------------
136#-----------------------------------------------------------------------------
147
137
148jobs:
138jobs:
149− cabal-ghc-8_6_5:
139+ cabal-ghc-8_10_4:
150 <<: *env
140 <<: *env
151 executor: amd64-executor
141 executor: amd64-executor
152 steps:
142 steps:
143+ - *preinstall
153 - checkout
144 - checkout
145+ - *project-preinstall
154 - *restore
146 - *restore
155− - *preinstall
156 - run:
147 - run:
157 environment:
148 environment:
158− GHCVER: "8.6.5"
159− CABAL_VERSION: "3.6.2.0"
160 CABAL_PROJECT: "cabal.project"
149 CABAL_PROJECT: "cabal.project"
150+ DISABLE_TEST: "yes"
151+ DISABLE_BENCH: "yes"
161 DISABLE_SDIST_BUILD: "yes"
152 DISABLE_SDIST_BUILD: "yes"
162− CABAL_BUILD_OPTIONS: "--flag debug --flag -opt"
163 command: |
153 command: |
154+ apt-get install -y ghc-8.10.4
155+ apt-get install -y cabal-install-3.4
164 bash -c "$PACKCHECK cabal"
156 bash -c "$PACKCHECK cabal"
165 - *save
157 - *save
166− cabal-ghc-9_8_1-docspec:
158+ stack-ghc-8_8:
167 <<: *env
159 <<: *env
168 executor: amd64-executor
160 executor: amd64-executor
169 steps:
161 steps:
162+ - *preinstall
170 - checkout
163 - checkout
164+ - *project-preinstall
171 - *restore
165 - *restore
166+ - run:
167+ name: GHC 8.8 + stack lts-16.12
168+ environment:
169+ BUILD: "stack"
170+ RESOLVER: "lts-16.12"
171+ SDIST_OPTIONS: "--ignore-check"
172+ STACK_BUILD_OPTIONS: "--flag streamly-benchmarks:-opt"
173+ command: |
174+ apt-get build-dep -y ghc-8.8.4
175+ apt-get install -y cabal-install-3.2
176+ bash -c "$PACKCHECK $BUILD"
177+ - *save
178+ cabal-ghc-8_6_5:
179+ <<: *env
180+ executor: amd64-executor
181+ steps:
172 - *preinstall
182 - *preinstall
183+ - checkout
184+ - *project-preinstall
185+ - *restore
186+ - run: |
187+ apt-get install -y ghc-8.6.3
188+ apt-get install -y cabal-install-2.4
189+ bash -c "$PACKCHECK cabal-v2"
190+ - *save
191+ cabal-ghc-8_4_4:
192+ <<: *env
193+ executor: x86-executor
194+ steps:
195+ - *preinstall
196+ - checkout
197+ - *project-preinstall
198+ - *restore
199+ - run:
200+ name: GHC 8.4.4 + x86 + debug
201+ environment:
202+ BUILD: "cabal-v2"
203+ GHCVER: "8.4.4"
204+ CABAL_BUILD_OPTIONS: "--flag debug --flag limit-build-mem"
205+ command: |
206+ apt-get install -y ghc-8.4.4
207+ apt-get install -y cabal-install-3.2
208+ bash -c "$PACKCHECK $BUILD"
209+ - *save
210+ cabal-ghc-8_2_2:
211+ <<: *env
212+ executor: amd64-executor
213+ steps:
214+ - *preinstall
215+ - checkout
216+ - *project-preinstall
217+ - *restore
173 - run:
218 - run:
174 environment:
219 environment:
175− GHCVER: "9.8.1"
220+ BUILD: "cabal-v2"
176− CABAL_VERSION: "3.10.1.0"
177− CABAL_PROJECT: "cabal.project.doctest"
178− DISABLE_SDIST_BUILD: "y"
179− DISABLE_TEST: "y"
221+ DISABLE_TEST: "yes"
180− DISABLE_BENCH: "y"
222+ DISABLE_BENCH: "yes"
181− DISABLE_DOCS: "y"
223+ DISABLE_DOCS: "yes"
182− ENABLE_DOCSPEC: "y"
224+ DISABLE_SDIST_BUILD: "yes"
183− DOCSPEC_URL: https://github.com/phadej/cabal-extras/releases/download/cabal-docspec-0.0.0.20210111/cabal-docspec-0.0.0.20210111.xz
225+ DISABLE_DIST_CHECKS: "yes"
184− DOCSPEC_OPTIONS: "--timeout 60 --check-properties --property-variables xs"
185 command: |
226 command: |
227+ apt-get install -y ghc-8.2.2
228+ apt-get install -y cabal-install-3.2
186− bash -c "$PACKCHECK cabal"
229+ bash -c "$PACKCHECK $BUILD"
187 - *save
230 - *save
188− hlint-trailing-spaces:
231+ cabal-ghc-8_0_2:
189 <<: *env
232 <<: *env
190 executor: amd64-executor
233 executor: amd64-executor
191 steps:
234 steps:
235+ - *preinstall
192 - checkout
236 - checkout
237+ - *project-preinstall
193 - *restore
238 - *restore
239+ - run:
240+ environment:
241+ BUILD: "cabal-v2"
242+ DISABLE_TEST: "yes"
243+ DISABLE_BENCH: "yes"
244+ DISABLE_DOCS: "yes"
245+ DISABLE_SDIST_BUILD: "yes"
246+ DISABLE_DIST_CHECKS: "yes"
247+ command: |
248+ apt-get install -y ghc-8.0.2
249+ apt-get install -y cabal-install-3.2
250+ bash -c "$PACKCHECK $BUILD"
251+ - *save
252+ cabal-ghc-7_10_3:
253+ <<: *env
254+ executor: amd64-executor
255+ steps:
194 - *preinstall
256 - *preinstall
257+ - checkout
258+ - *project-preinstall
259+ - *restore
260+ - run: |
261+ apt-get install -y ghc-7.10.3
262+ apt-get install -y cabal-install-2.4
263+ bash -c "$PACKCHECK cabal-v2"
264+ - *save
265+ stack-ghc-8_4:
266+ <<: *env
267+ executor: amd64-executor
268+ steps:
269+ - *preinstall
270+ - checkout
271+ - *project-preinstall
272+ - *restore
273+ - run: |
274+ bash -c "$PACKCHECK stack RESOLVER=lts-12"
275+ - *save
276+ stack-ghc-8_2:
277+ <<: *env
278+ executor: amd64-executor
279+ steps:
280+ - *preinstall
281+ - checkout
282+ - *project-preinstall
283+ - *restore
284+ - run: |
285+ bash -c "$PACKCHECK stack RESOLVER=lts-11"
286+ - *save
287+ cabal-ghcjs-8_4:
288+ <<: *env
289+ executor: amd64-executor
290+ steps:
291+ - *preinstall
292+ - checkout
293+ - *project-preinstall
294+ - *restore
195 - run:
295 - run:
196− name: hlint and trailing spaces
296+ name: GHCJS 8.4+no-test+no-docs
197 environment:
297 environment:
298+ BUILD: cabal-v2
299+ ENABLE_GHCJS: "yes"
300+ DISABLE_TEST: "yes"
301+ ENABLE_INSTALL: ""
302+ DISABLE_DOCS: "yes"
198 DISABLE_SDIST_BUILD: "yes"
303 DISABLE_SDIST_BUILD: "yes"
199− HLINT_VERSION: 3.6.1
304+ command: |
305+ add-apt-repository -y ppa:hvr/ghcjs
306+ add-apt-repository -y 'deb https://deb.nodesource.com/node_11.x xenial main'
307+ curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
308+ apt-get update
309+ apt-get install -y cabal-install-3.2
310+ apt-get install -y nodejs
311+ apt-get install -y ghcjs-8.4
312+ cabal user-config update -a "jobs: 1"
313+ bash -c "$PACKCHECK $BUILD"
314+ - *save
315+ coveralls-ghc-8_2_2:
316+ <<: *env
317+ executor: amd64-executor
318+ steps:
319+ - *preinstall
320+ - checkout
321+ - *project-preinstall
322+ - *restore
323+ - run:
324+ environment:
325+ BUILD: cabal
326+ COVERALLS_OPTIONS: "--repo-token=\"$REPO_TOKEN\" --coverage-mode=StrictlyFullLines --exclude-dir=test test"
327+ GHC_OPTIONS: "-DCOVERAGE_BUILD"
328+ command: |
329+ apt-get install -y ghc-8.2.2
330+ apt-get install -y cabal-install-2.4
331+ bash -c "$PACKCHECK cabal-v1"
332+ - *save
333+ coveralls-ghc-8_8_3:
334+ <<: *env
335+ executor: amd64-executor
336+ steps:
337+ - *preinstall
338+ - checkout
339+ - *project-preinstall
340+ - *restore
341+ - run:
342+ environment:
343+ BUILD: cabal-v2
344+ COVERALLS_OPTIONS: "--repo-token=\"$REPO_TOKEN\" --coverage-mode=StrictlyFullLines --exclude-dir=test"
345+ CABAL_PROJECT: "cabal.project.coverage"
346+ CABAL_BUILD_TARGETS: ""
347+ command: |
348+ apt-get install -y ghc-8.8.3
349+ apt-get install -y cabal-install-3.0
350+ bash -c "$PACKCHECK cabal-v2"
351+ no_output_timeout: 25m
352+ - *save
353+ coveralls-ghc-8_10_2:
354+ <<: *env
355+ executor: amd64-executor
356+ steps:
357+ - *preinstall
358+ - checkout
359+ - *project-preinstall
360+ - *restore
361+ - run:
362+ name: Build and test with inspection, coverage, Werror
363+ command: |
364+ apt-get install -y ghc-8.10.2
365+ apt-get install -y cabal-install-3.2
366+ # Run tests with coverage
367+ cabal update
368+ cabal user-config update -a "jobs: 1"
369+ bin/test.sh --coverage --raw
370+ # Upload results to coveralls.io
371+ PATH=$HOME/.cabal/bin:$PATH
372+ export PATH
373+ which hpc-coveralls 2>/dev/null || cabal install --project-file cabal.project.hpc-coveralls hpc-coveralls
374+ hpc-coveralls --repo-token="$REPO_TOKEN" --coverage-mode=StrictlyFullLines
375+ no_output_timeout: 25m
376+ - *save
377+ hlint-src:
378+ <<: *env
379+ executor: amd64-executor
380+ steps:
381+ - *preinstall
382+ - checkout
383+ - *project-preinstall
384+ - *restore
385+ - run:
386+ name: Hlint src
387+ environment:
388+ BUILD: hlint
200 HLINT_OPTIONS: lint
389 HLINT_OPTIONS: lint
390+ DISABLE_SDIST_BUILD: "yes"
201 HLINT_TARGETS: core/src src test benchmark
391 HLINT_TARGETS: core/src src test benchmark
202 command: |
392 command: |
203− bash -c "$PACKCHECK hlint" || exit 1
393+ bash -c "$PACKCHECK $BUILD" || exit 1
204 echo "Checking trailing spaces..."
394 echo "Checking trailing spaces..."
205 count=$(find . -name "*.hs" -exec grep -H '\ $' {} \; | tee /dev/tty | wc -l)
395 count=$(find . -name "*.hs" -exec grep -H '\ $' {} \; | tee /dev/tty | wc -l)
206 exit $count
396 exit $count
@@ -210,9 +400,23 @@ workflows:
210 version: 2
400 version: 2
211 build:
401 build:
212 jobs:
402 jobs:
213− #- cabal-ghc-8_6_5:
403+ - cabal-ghc-8_10_4:
214− # name: 8.6.5-debug-unoptimized
404+ name: GHC 8.10.4 + sdist + no-test + no-bench
405+ #- cabal-ghc-8.6.5
406+ #- cabal-ghc-8_4_4:
407+ # name: GHC 8.4.4 + x86 + debug
408+ #- cabal-ghc-8_2_2:
409+ # name: GHC 8.2.2 + no-test + no-bench + no-docs
215− - cabal-ghc-9_8_1-docspec:
410+ #- cabal-ghc-8_0_2:
216− name: ghc-9.8.1-docspec
411+ # name: GHC 8.0.2 + no-test + no-bench + no-docs
217− - hlint-trailing-spaces:
412+ #- cabal-ghc-7.10.3
218− name: hlint and trailing spaces
413+ # - cabal-ghcjs-8_4:
414+ # name: GHCJS 8.4 + no-test + no-docs
415+ #- stack-ghc-8.4
416+ #- stack-ghc-8.2
417+ #- coveralls-ghc-8.2.2
418+ #- coveralls-ghc-8.8.3
419+ #- coveralls-ghc-8_10_2:
420+ # name: GHC 8.10.2 + inspection + coverage + Werror
421+ - hlint-src:
422+ name: Hlint src + Trailing Spaces
.github/workflows/haskell.yml+91−84
@@ -13,15 +13,9 @@ jobs:
13 # packcheck environment variables
13 # packcheck environment variables
14 LC_ALL: C.UTF-8
14 LC_ALL: C.UTF-8
15 BUILD: ${{ matrix.build }}
15 BUILD: ${{ matrix.build }}
16− # For updating see: https://downloads.haskell.org/~ghcup/
17− GHCUP_VERSION: 0.1.20.0
18− DOCSPEC_URL: https://github.com/phadej/cabal-extras/releases/download/cabal-docspec-0.0.0.20210111/cabal-docspec-0.0.0.20210111.xz
19− DOCSPEC_OPTIONS: "--timeout 60 --check-properties --property-variables xs"
20− GHCUP_GHC_OPTIONS: ${{ matrix.ghcup_ghc_options }}
21 GHCVER: ${{ matrix.ghc_version }}
16 GHCVER: ${{ matrix.ghc_version }}
22 CABALVER: ${{ matrix.cabal_version }}
17 CABALVER: ${{ matrix.cabal_version }}
23 DISABLE_DOCS: ${{ matrix.disable_docs }}
18 DISABLE_DOCS: ${{ matrix.disable_docs }}
24− ENABLE_DOCSPEC: ${{ matrix.enable_docspec }}
25 DISABLE_TEST: ${{ matrix.disable_test }}
19 DISABLE_TEST: ${{ matrix.disable_test }}
26 DISABLE_BENCH: ${{ matrix.disable_bench }}
20 DISABLE_BENCH: ${{ matrix.disable_bench }}
27 DISABLE_DIST_CHECKS: ${{ matrix.disable_dist_checks }}
21 DISABLE_DIST_CHECKS: ${{ matrix.disable_dist_checks }}
@@ -45,18 +39,14 @@ jobs:
45 STACK_BUILD_OPTIONS: ${{ matrix.stack_build_options }}
39 STACK_BUILD_OPTIONS: ${{ matrix.stack_build_options }}
46
40
47 # packcheck location and revision
41 # packcheck location and revision
48− PACKCHECK: "./packcheck.sh"
42+ PACKCHECK_LOCAL_PATH: "./packcheck.sh"
49 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
43 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
50− PACKCHECK_GITHUB_COMMIT: "v0.7.0"
44+ PACKCHECK_GITHUB_COMMIT: "a302772c8f3791c477edd1764b82f8d1f5b22fdf"
51
45
52 # Pull token from "secrets" setting of the github repo
46 # Pull token from "secrets" setting of the github repo
53 COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
47 COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
54 COVERAGE: ${{ matrix.coverage }}
48 COVERAGE: ${{ matrix.coverage }}
55−
49+ DOCTEST: ${{ matrix.doctest }}
56− # hlint
57− HLINT_VERSION: 3.6.1
58− HLINT_OPTIONS: "lint"
59− HLINT_TARGETS: "core/src src test benchmark"
60
50
61 # Subdir
51 # Subdir
62 SUBDIR: ${{ matrix.subdir }}
52 SUBDIR: ${{ matrix.subdir }}
@@ -68,8 +58,8 @@ jobs:
68 matrix:
58 matrix:
69 # The order is important to optimize fail-fast.
59 # The order is important to optimize fail-fast.
70 name:
60 name:
71− - 9.8.1-Werror
61+ - 9.4.4-Werror
72− # - 9.8.1-docspec
62+ - 9.2.7-docspec
73 # - 8.10.7-coverage
63 # - 8.10.7-coverage
74
64
75 # Note: if cabal.project is not specified benchmarks and tests won't
65 # Note: if cabal.project is not specified benchmarks and tests won't
@@ -78,76 +68,53 @@ jobs:
78 include:
68 include:
79 - name: head
69 - name: head
80 ghc_version: head
70 ghc_version: head
81− # The URL may change, to find a working URL go to https://gitlab.haskell.org/ghc/ghc/-/jobs/
82− # Find a debian10/11/12 job, click on a passed/failed status, at the
83− # end of the output you will find the tar.xz name, put that tar
84− # name after "raw/", and put the job name after "job=".
85− # Also see https://github.com/mpickering/ghc-artefact-nix/blob/master/gitlab-artifact.nix
86− #
87− # May also use ghcup for installing ghc head version, use the
88− # version "LatestNightly", and the following config:
89− # ghcup config add-release-channel https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml
90− ghcup_ghc_options: "-u https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-linux-deb10-int_native-validate.tar.xz?job=x86_64-linux-deb10-int_native-validate"
91 runner: ubuntu-latest
71 runner: ubuntu-latest
92 build: cabal
72 build: cabal
93− cabal_version: 3.10.2.0
73+ cabal_version: 3.8.1.0
94 cabal_project: cabal.project.ghc-head
74 cabal_project: cabal.project.ghc-head
95 disable_sdist_build: "y"
75 disable_sdist_build: "y"
96 ignore_error: true
76 ignore_error: true
97− # Note: use linux for warning build for convenient dev testing
98− - name: 9.8.1-Werror
99− ghc_version: 9.8.1
100− runner: ubuntu-latest
101− build: cabal
102− cabal_version: 3.10.1.0
103− disable_sdist_build: "y"
104− cabal_project: cabal.project.Werror
105− ignore_error: false
106− #- name: 9.8.1-docspec
77+ - name: 9.6.1
107− # ghc_version: 9.8.1
108− # runner: ubuntu-latest
109− # build: cabal
110− # cabal_version: 3.10.1.0
111− # cabal_project: cabal.project.doctest
112− # disable_test: "y"
113− # disable_bench: "y"
114− # disable_docs: "y"
115− # enable_docspec: "y"
116− # disable_sdist_build: "y"
117− # ignore_error: false
118− - name: 9.8.1-fusion-inspection
119− ghc_version: 9.8.1
78+ ghc_version: 9.6.1
120 runner: ubuntu-latest
79 runner: ubuntu-latest
121 build: cabal
80 build: cabal
122 cabal_version: 3.10.1.0
81 cabal_version: 3.10.1.0
123 disable_sdist_build: "y"
82 disable_sdist_build: "y"
124 cabal_project: cabal.project
83 cabal_project: cabal.project
125− cabal_build_options: "--flag fusion-plugin --flag inspection"
126− ignore_error: false
84+ ignore_error: true
127− - name: 9.6.3-macos
85+ - name: 9.4.4-Werror
128− ghc_version: 9.6.3
86+ ghc_version: 9.4.4
129− runner: macos-latest
87+ runner: ubuntu-latest
130 build: cabal
88 build: cabal
131− cabal_version: 3.10.1.0
89+ cabal_version: 3.8.1.0
132 disable_sdist_build: "y"
90 disable_sdist_build: "y"
133− cabal_project: cabal.project
91+ cabal_project: cabal.project.Werror
134 ignore_error: false
92 ignore_error: false
135− - name: 9.4.7
93+ - name: 9.4.4-fusion-inspection
136− ghc_version: 9.4.7
94+ ghc_version: 9.4.4
137 runner: ubuntu-latest
95 runner: ubuntu-latest
138 build: cabal
96 build: cabal
139 cabal_version: 3.8.1.0
97 cabal_version: 3.8.1.0
140 disable_sdist_build: "y"
98 disable_sdist_build: "y"
141 cabal_project: cabal.project
99 cabal_project: cabal.project
100+ cabal_build_options: "--flag fusion-plugin --flag inspection"
142 ignore_error: false
101 ignore_error: false
143− - name: 9.2.8
102+ - name: 9.2.7
144− ghc_version: 9.2.8
103+ ghc_version: 9.2.7
145 runner: ubuntu-latest
104 runner: ubuntu-latest
146 build: cabal
105 build: cabal
147 cabal_project: cabal.project
106 cabal_project: cabal.project
148 cabal_version: 3.6.2.0
107 cabal_version: 3.6.2.0
149 disable_sdist_build: "y"
108 disable_sdist_build: "y"
150 ignore_error: false
109 ignore_error: false
110+ - name: 9.2.7-docspec
111+ ghc_version: 9.2.7
112+ runner: ubuntu-latest
113+ doctest: "y"
114+ cabal_version: 3.6.2.0
115+ cabal_project: cabal.project
116+ disable_sdist_build: "y"
117+ ignore_error: false
151 - name: 9.0.2-streamly-sdist
118 - name: 9.0.2-streamly-sdist
152 ghc_version: 9.0.2
119 ghc_version: 9.0.2
153 runner: ubuntu-latest
120 runner: ubuntu-latest
@@ -171,6 +138,14 @@ jobs:
171 stack_build_options: "--flag streamly-benchmarks:-opt"
138 stack_build_options: "--flag streamly-benchmarks:-opt"
172 cabal_version: 3.6.2.0
139 cabal_version: 3.6.2.0
173 ignore_error: false
140 ignore_error: false
141+ - name: 8.10.7-macos
142+ ghc_version: 8.10.7
143+ runner: macos-latest
144+ build: cabal
145+ cabal_version: 3.6.2.0
146+ cabal_project: cabal.project
147+ disable_sdist_build: "y"
148+ ignore_error: false
174 # - name: 8.10.7-coverage
149 # - name: 8.10.7-coverage
175 # ghc_version: 8.10.7
150 # ghc_version: 8.10.7
176 # runner: ubuntu-latest
151 # runner: ubuntu-latest
@@ -185,6 +160,15 @@ jobs:
185 cabal_project: cabal.project
160 cabal_project: cabal.project
186 disable_sdist_build: "y"
161 disable_sdist_build: "y"
187 ignore_error: false
162 ignore_error: false
163+ - name: 8.6.5-no-fusion-unoptimized
164+ ghc_version: 8.6.5
165+ runner: ubuntu-latest
166+ build: cabal
167+ cabal_version: 3.6.2.0
168+ cabal_project: cabal.project
169+ cabal_build_options: "--flag no-fusion --flag -opt"
170+ disable_sdist_build: "y"
171+ ignore_error: false
188 - name: 8.6.5-debug-unoptimized
172 - name: 8.6.5-debug-unoptimized
189 ghc_version: 8.6.5
173 ghc_version: 8.6.5
190 runner: ubuntu-latest
174 runner: ubuntu-latest
@@ -194,44 +178,66 @@ jobs:
194 cabal_build_options: "--flag debug --flag -opt"
178 cabal_build_options: "--flag debug --flag -opt"
195 disable_sdist_build: "y"
179 disable_sdist_build: "y"
196 ignore_error: false
180 ignore_error: false
197− - name: hlint
198− build: hlint
199− runner: ubuntu-latest
200− ignore_error: true
201
181
202 steps:
182 steps:
203 - uses: actions/checkout@v2
183 - uses: actions/checkout@v2
204
184
205 - uses: actions/cache@v1
185 - uses: actions/cache@v1
206− name: Cache common directories
186+ name: Cache ~/.cabal
207 with:
187 with:
208− path: |
209− ~/.local
210− ~/.cabal
188+ path: ~/.cabal
211− ~/.stack
212− ~/.ghcup
213 # Bump the key version to clear the cache
189 # Bump the key version to clear the cache
214 key: ${{ runner.os }}-${{ matrix.ghc_version }}-cabal-v2
190 key: ${{ runner.os }}-${{ matrix.ghc_version }}-cabal-v2
215
191
216 - name: Download packcheck
192 - name: Download packcheck
217 run: |
193 run: |
218− if test ! -e "$PACKCHECK"
194+ # Get packcheck if needed
219− then
195+ CURL=$(which curl)
220− if test -z "$PACKCHECK_GITHUB_COMMIT"
196+ PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
221− then
197+ if test ! -e "$PACKCHECK_LOCAL_PATH"; then $CURL -sL -o "$PACKCHECK_LOCAL_PATH" $PACKCHECK_URL; fi;
222− die "PACKCHECK_GITHUB_COMMIT is not specified."
198+ chmod +x $PACKCHECK_LOCAL_PATH
223− fi
199+
224− PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
200+ os=$(uname -s -m)
225− curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1
201+ case "$os" in
202+ "Linux x86_64") GHCUP_ARCH="x86_64-linux" ;;
203+ "Darwin x86_64") GHCUP_ARCH="x86_64-apple-darwin" ;;
204+ *) echo "Unknown OS/Arch: $os"; exit 1;;
205+ esac
206+
207+ # Check available versions here: https://downloads.haskell.org/~ghcup/
208+ GHCUP_VER=0.1.18.0
209+ $CURL -sL -o ./ghcup https://downloads.haskell.org/~ghcup/$GHCUP_VER/${GHCUP_ARCH}-ghcup-$GHCUP_VER
226− chmod +x $PACKCHECK
210+ chmod +x ./ghcup
227− elif test ! -x "$PACKCHECK"
211+ if test "$GHCVER" = "head"
228 then
212 then
229− chmod +x $PACKCHECK
213+ # The URL may change, to find a working URL go to https://gitlab.haskell.org/ghc/ghc/-/jobs/
214+ # Find a debian10 job, click on a passed/failed job, at the
215+ # end of the output you will find the tar.xz name, put that after
216+ # "raw/", and put the job name after "job=".
217+ # Also see https://github.com/mpickering/ghc-artefact-nix/blob/master/gitlab-artifact.nix
218+ ./ghcup install ghc -u https://gitlab.haskell.org/ghc/ghc/-/jobs/artifacts/master/raw/ghc-x86_64-linux-deb10-int_native-validate.tar.xz?job=x86_64-linux-deb10-int_native-validate head
219+ else
220+ ./ghcup install ghc $GHCVER
230 fi
221 fi
222+ ./ghcup install cabal $CABALVER
223+ ./ghcup set ghc $GHCVER
224+ ./ghcup set cabal $CABALVER
231
225
232 - name: Run tests
226 - name: Run tests
233 run: |
227 run: |
228+ if test -n "$DOCTEST"
229+ then
230+ mkdir -p $HOME/.cabal/bin
231+ curl -sL https://github.com/phadej/cabal-extras/releases/download/cabal-docspec-0.0.0.20210111/cabal-docspec-0.0.0.20210111.xz > cabal-docspec.xz
232+ echo '0829bd034fba901cbcfe491d98ed8b28fd54f9cb5c91fa8e1ac62dc4413c9562 cabal-docspec.xz' | sha256sum -c -
233+ xz -d < cabal-docspec.xz > $HOME/.cabal/bin/cabal-docspec
234+ rm -f cabal-docspec.xz
235+ chmod a+x $HOME/.cabal/bin/cabal-docspec
236+ cabal update
237+ cabal build --project-file cabal.project.doctest all
238+ $HOME/.cabal/bin/cabal-docspec --version
239+ $HOME/.cabal/bin/cabal-docspec --timeout 60 --check-properties --property-variables xs
234− if test -n "$COVERAGE"
240+ elif test -n "$COVERAGE"
235 then
241 then
236 # Run tests with coverage
242 # Run tests with coverage
237 cabal update
243 cabal update
@@ -244,15 +250,16 @@ jobs:
244 # XXX Uncomment this and fix it properly later
250 # XXX Uncomment this and fix it properly later
245 # hpc-coveralls --repo-token="$COVERALLS_TOKEN" --coverage-mode=StrictlyFullLines
251 # hpc-coveralls --repo-token="$COVERALLS_TOKEN" --coverage-mode=StrictlyFullLines
246 else
252 else
253+ export TOOLS_DIR=/opt
247 # /usr/local/opt/curl/bin for macOS
254 # /usr/local/opt/curl/bin for macOS
248 export PATH=$HOME/.local/bin:$HOME/.ghcup/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/opt/curl/bin
255 export PATH=$HOME/.local/bin:$HOME/.ghcup/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/opt/curl/bin
249 if test -n "$SUBDIR"
256 if test -n "$SUBDIR"
250 then
257 then
251− mv "$PACKCHECK" "$SUBDIR/packcheck.sh"
258+ mv "$PACKCHECK_LOCAL_PATH" "$SUBDIR/packcheck.sh"
252 # This is required as dist-newstyle will be created on the top level
259 # This is required as dist-newstyle will be created on the top level
253 # directory as it is considered the working dir.
260 # directory as it is considered the working dir.
254 rm cabal.project
261 rm cabal.project
255 cd "$SUBDIR"
262 cd "$SUBDIR"
256 fi
263 fi
257− bash -c "$PACKCHECK $BUILD"
264+ bash -c "$PACKCHECK_LOCAL_PATH $BUILD"
258 fi
265 fi
.hlint.ignore−5
@@ -2,9 +2,6 @@ core/src/Streamly/Internal/Data/Stream/StreamK/Type.hs
2core/src/Streamly/Internal/Data/Pipe/Type.hs
2core/src/Streamly/Internal/Data/Pipe/Type.hs
3core/src/Streamly/Internal/Unicode/Stream.hs
3core/src/Streamly/Internal/Unicode/Stream.hs
4src/Streamly/Internal/Data/SmallArray/Type.hs
4src/Streamly/Internal/Data/SmallArray/Type.hs
5−src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs
6−src/Streamly/Internal/Data/Stream/Serial.hs
7−src/Streamly/Internal/Data/Stream/Zip.hs
8test/Streamly/Test/Data/Array.hs
5test/Streamly/Test/Data/Array.hs
9test/Streamly/Test/Data/Parser.hs
6test/Streamly/Test/Data/Parser.hs
10test/Streamly/Test/Data/ParserK.hs
7test/Streamly/Test/Data/ParserK.hs
@@ -13,7 +10,6 @@ test/Streamly/Test/Data/Unfold.hs
13test/Streamly/Test/FileSystem/Event.hs
10test/Streamly/Test/FileSystem/Event.hs
14test/Streamly/Test/Prelude/Concurrent.hs
11test/Streamly/Test/Prelude/Concurrent.hs
15test/Streamly/Test/Data/Stream/Concurrent.hs
12test/Streamly/Test/Data/Stream/Concurrent.hs
16−test/lib/Streamly/Test/Prelude/Common.hs
17test/Streamly/Test/Prelude/Fold.hs
13test/Streamly/Test/Prelude/Fold.hs
18test/Streamly/Test/Prelude/Rate.hs
14test/Streamly/Test/Prelude/Rate.hs
19test/Streamly/Test/Prelude/Serial.hs
15test/Streamly/Test/Prelude/Serial.hs
@@ -31,7 +27,6 @@ benchmark/Streamly/Benchmark/Data/Stream/StreamK.hs
31benchmark/Streamly/Benchmark/Data/Unfold.hs
27benchmark/Streamly/Benchmark/Data/Unfold.hs
32benchmark/Streamly/Benchmark/FileSystem/Handle.hs
28benchmark/Streamly/Benchmark/FileSystem/Handle.hs
33benchmark/Streamly/Benchmark/Prelude/Async.hs
29benchmark/Streamly/Benchmark/Prelude/Async.hs
34−benchmark/Streamly/Benchmark/Prelude/Concurrent.hs
35benchmark/Streamly/Benchmark/Prelude/Merge.hs
30benchmark/Streamly/Benchmark/Prelude/Merge.hs
36benchmark/Streamly/Benchmark/Prelude/Parallel.hs
31benchmark/Streamly/Benchmark/Prelude/Parallel.hs
37benchmark/Streamly/Benchmark/Prelude/Rate.hs
32benchmark/Streamly/Benchmark/Prelude/Rate.hs
benchmark/NanoBenchmarks.hs+1−1
@@ -18,7 +18,7 @@ import qualified Streamly.Data.Fold as FL
18import qualified Streamly.Internal.Data.Stream as S
18import qualified Streamly.Internal.Data.Stream as S
19import qualified Streamly.Internal.Data.Stream.IsStream as Internal
19import qualified Streamly.Internal.Data.Stream.IsStream as Internal
20
20
21−import Test.Tasty.Bench
21+import Gauge
22import System.Random
22import System.Random
23
23
24maxValue :: Int
24maxValue :: Int
benchmark/Streamly/Benchmark/Data/Array/CommonImports.hs+1−1
@@ -9,7 +9,7 @@ import qualified Streamly.Data.Fold as Fold
9import qualified Streamly.Data.Stream as S
9import qualified Streamly.Data.Stream as S
10import qualified Streamly.Internal.Data.Stream as Stream
10import qualified Streamly.Internal.Data.Stream as Stream
11
11
12−import Test.Tasty.Bench
12+import Gauge
13import Streamly.Benchmark.Common hiding (benchPureSrc)
13import Streamly.Benchmark.Common hiding (benchPureSrc)
14import qualified Stream.Common as P
14import qualified Stream.Common as P
15
15
benchmark/Streamly/Benchmark/Data/Array/Stream.hs+3−3
@@ -39,7 +39,7 @@ import Prelude hiding ()
39
39
40import qualified Streamly.Data.Stream as Stream
40import qualified Streamly.Data.Stream as Stream
41import qualified Streamly.Internal.Data.Array as Array
41import qualified Streamly.Internal.Data.Array as Array
42−import qualified Streamly.Internal.Data.Array.Stream as ArrayStream
42+import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
43import qualified Streamly.Internal.Data.Fold as Fold
43import qualified Streamly.Internal.Data.Fold as Fold
44import qualified Streamly.Internal.Data.Parser as Parser
44import qualified Streamly.Internal.Data.Parser as Parser
45import qualified Streamly.Internal.Data.Stream as Stream
45import qualified Streamly.Internal.Data.Stream as Stream
@@ -47,13 +47,13 @@ import qualified Streamly.Internal.Data.StreamK as StreamK
47import qualified Streamly.Internal.FileSystem.Handle as Handle
47import qualified Streamly.Internal.FileSystem.Handle as Handle
48import qualified Streamly.Internal.Unicode.Stream as Unicode
48import qualified Streamly.Internal.Unicode.Stream as Unicode
49
49
50−import Test.Tasty.Bench hiding (env)
50+import Gauge hiding (env)
51import Streamly.Benchmark.Common
51import Streamly.Benchmark.Common
52import Streamly.Benchmark.Common.Handle
52import Streamly.Benchmark.Common.Handle
53import Control.Monad.IO.Class (MonadIO)
53import Control.Monad.IO.Class (MonadIO)
54
54
55#ifdef INSPECTION
55#ifdef INSPECTION
56−import Streamly.Internal.Data.MutByteArray (Unbox)
56+import Streamly.Internal.Data.Unbox (Unbox)
57import Streamly.Internal.Data.Stream (Step(..))
57import Streamly.Internal.Data.Stream (Step(..))
58import Test.Inspection
58import Test.Inspection
59#endif
59#endif
benchmark/Streamly/Benchmark/Data/Fold.hs+3−3
@@ -41,7 +41,7 @@ import qualified Streamly.Internal.Data.Unfold as Unfold
41import qualified Streamly.Internal.Data.Pipe as Pipe
41import qualified Streamly.Internal.Data.Pipe as Pipe
42import qualified Streamly.Internal.Data.Stream as Stream
42import qualified Streamly.Internal.Data.Stream as Stream
43
43
44−import Test.Tasty.Bench
44+import Gauge
45import Streamly.Benchmark.Common
45import Streamly.Benchmark.Common
46import Prelude hiding (all, any, take, unzip, sequence_, filter)
46import Prelude hiding (all, any, take, unzip, sequence_, filter)
47
47
@@ -269,13 +269,13 @@ unzip = Stream.fold $ FL.lmap (\a -> (a, a)) (FL.unzip FL.sum FL.length)
269{-# INLINE unzipWithFstM #-}
269{-# INLINE unzipWithFstM #-}
270unzipWithFstM :: Monad m => Stream m Int -> m (Int, Int)
270unzipWithFstM :: Monad m => Stream m Int -> m (Int, Int)
271unzipWithFstM = do
271unzipWithFstM = do
272− let f a = return (a + 1, a)
272+ let f = \a -> return (a + 1, a)
273 Stream.fold (FL.unzipWithFstM f FL.sum FL.length)
273 Stream.fold (FL.unzipWithFstM f FL.sum FL.length)
274
274
275{-# INLINE unzipWithMinM #-}
275{-# INLINE unzipWithMinM #-}
276unzipWithMinM :: Monad m => Stream m Int -> m (Int, Int)
276unzipWithMinM :: Monad m => Stream m Int -> m (Int, Int)
277unzipWithMinM = do
277unzipWithMinM = do
278− let f a = return (a + 1, a)
278+ let f = \a -> return (a + 1, a)
279 Stream.fold (FL.unzipWithMinM f FL.sum FL.length)
279 Stream.fold (FL.unzipWithMinM f FL.sum FL.length)
280
280
281-------------------------------------------------------------------------------
281-------------------------------------------------------------------------------
benchmark/Streamly/Benchmark/Data/Fold/Window.hs+1−1
@@ -13,7 +13,7 @@ import qualified Streamly.Internal.Data.Ring as Ring
13import qualified Streamly.Internal.Data.Stream as Stream
13import qualified Streamly.Internal.Data.Stream as Stream
14
14
15import Streamly.Benchmark.Common
15import Streamly.Benchmark.Common
16−import Test.Tasty.Bench
16+import Gauge
17
17
18{-# INLINE source #-}
18{-# INLINE source #-}
19source :: (Monad m, Num a, Stream.Enumerable a) =>
19source :: (Monad m, Num a, Stream.Enumerable a) =>
benchmark/Streamly/Benchmark/Data/MutArray.hs+1−1
@@ -49,7 +49,7 @@ import qualified Streamly.Internal.Data.MutArray as MArray
49import qualified Streamly.Internal.Data.Fold as Fold
49import qualified Streamly.Internal.Data.Fold as Fold
50import qualified Streamly.Internal.Data.Stream as Stream
50import qualified Streamly.Internal.Data.Stream as Stream
51
51
52−import Test.Tasty.Bench
52+import Gauge
53import Streamly.Benchmark.Common hiding (benchPureSrc)
53import Streamly.Benchmark.Common hiding (benchPureSrc)
54
54
55type Stream = MutArray
55type Stream = MutArray
benchmark/Streamly/Benchmark/Data/Parser.hs+6−7
@@ -49,7 +49,7 @@ import qualified Streamly.Data.Stream as Stream
49import qualified Streamly.Internal.Data.Producer as Producer
49import qualified Streamly.Internal.Data.Producer as Producer
50import qualified Streamly.Internal.Data.Stream as Stream
50import qualified Streamly.Internal.Data.Stream as Stream
51
51
52−import Test.Tasty.Bench hiding (env)
52+import Gauge hiding (env)
53import Streamly.Benchmark.Common
53import Streamly.Benchmark.Common
54import Streamly.Benchmark.Common.Handle
54import Streamly.Benchmark.Common.Handle
55
55
@@ -348,7 +348,7 @@ split_ value =
348-- PR.dropWhile (<= (value * 1 `div` 4)) *> PR.die "alt"
348-- PR.dropWhile (<= (value * 1 `div` 4)) *> PR.die "alt"
349{-# INLINE takeWhileFail #-}
349{-# INLINE takeWhileFail #-}
350takeWhileFail :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
350takeWhileFail :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
351−takeWhileFail predicate (Fold fstep finitial _ ffinal) =
351+takeWhileFail predicate (Fold fstep finitial fextract) =
352 Parser step initial extract
352 Parser step initial extract
353
353
354 where
354 where
@@ -369,7 +369,7 @@ takeWhileFail predicate (Fold fstep finitial _ ffinal) =
369 Fold.Done b -> Done 0 b
369 Fold.Done b -> Done 0 b
370 else return $ Error "fail"
370 else return $ Error "fail"
371
371
372− extract s = fmap (Done 0) (ffinal s)
372+ extract s = fmap (Done 0) (fextract s)
373
373
374{-# INLINE alt2 #-}
374{-# INLINE alt2 #-}
375alt2 :: Monad m
375alt2 :: Monad m
@@ -714,6 +714,8 @@ instance NFData ParseError where
714o_1_space_serial :: Int -> [Benchmark]
714o_1_space_serial :: Int -> [Benchmark]
715o_1_space_serial value =
715o_1_space_serial value =
716 [ benchIOSink value "takeBetween" $ takeBetween value
716 [ benchIOSink value "takeBetween" $ takeBetween value
717+ , benchIOSink value "takeEQ" $ takeEQ value
718+ , benchIOSink value "takeGE" $ takeGE value
717 , benchIOSink value "takeWhile" $ takeWhile value
719 , benchIOSink value "takeWhile" $ takeWhile value
718 , benchIOSink value "takeWhileP" $ takeWhileP value
720 , benchIOSink value "takeWhileP" $ takeWhileP value
719 , benchIOSink value "takeP" $ takeP value
721 , benchIOSink value "takeP" $ takeP value
@@ -810,11 +812,8 @@ o_1_space_serial_unfold bound arrays =
810o_n_heap_serial :: Int -> [Benchmark]
812o_n_heap_serial :: Int -> [Benchmark]
811o_n_heap_serial value =
813o_n_heap_serial value =
812 [
814 [
813− benchIOSink value "takeEQ" $ takeEQ value
814− , benchIOSink value "takeGE" $ takeGE value
815−
816 -- lookahead benchmark holds the entire input till end
815 -- lookahead benchmark holds the entire input till end
817− , benchIOSink value "lookAhead" $ lookAhead value
816+ benchIOSink value "lookAhead" $ lookAhead value
818
817
819 -- o-n-heap because of backtracking
818 -- o-n-heap because of backtracking
820 , benchIOSrc sourceEscapedFrames value "takeFramedByEsc_"
819 , benchIOSrc sourceEscapedFrames value "takeFramedByEsc_"
benchmark/Streamly/Benchmark/Data/ParserK.hs+6−6
@@ -48,7 +48,7 @@ import qualified Streamly.Data.Parser as PRD
48import qualified Streamly.Internal.Data.ParserK as PR
48import qualified Streamly.Internal.Data.ParserK as PR
49import qualified Streamly.Internal.Data.StreamK as StreamK
49import qualified Streamly.Internal.Data.StreamK as StreamK
50
50
51−import Test.Tasty.Bench
51+import Gauge
52import Streamly.Benchmark.Common
52import Streamly.Benchmark.Common
53
53
54-------------------------------------------------------------------------------
54-------------------------------------------------------------------------------
@@ -63,7 +63,7 @@ import Streamly.Benchmark.Common
63#define PARSE_ELEM (Array Int)
63#define PARSE_ELEM (Array Int)
64#define CONSTRAINT_IO (MonadIO m, Unbox a)
64#define CONSTRAINT_IO (MonadIO m, Unbox a)
65#define CONSTRAINT (Monad m, Unbox a)
65#define CONSTRAINT (Monad m, Unbox a)
66−#define MODULE_NAME "Data.ParserK.Chunked"
66+#define MODULE_NAME "ParserK.Chunked"
67
67
68#endif
68#endif
69
69
@@ -75,7 +75,7 @@ import Streamly.Benchmark.Common
75#define PARSE_ELEM (Array Int)
75#define PARSE_ELEM (Array Int)
76#define CONSTRAINT_IO (MonadIO m)
76#define CONSTRAINT_IO (MonadIO m)
77#define CONSTRAINT (Monad m)
77#define CONSTRAINT (Monad m)
78−#define MODULE_NAME "Data.ParserK.Chunked.Generic"
78+#define MODULE_NAME "ParserK.Chunked.Generic"
79
79
80#endif
80#endif
81
81
@@ -87,7 +87,7 @@ import Streamly.Benchmark.Common
87#define PARSE_ELEM Int
87#define PARSE_ELEM Int
88#define CONSTRAINT_IO (MonadIO m)
88#define CONSTRAINT_IO (MonadIO m)
89#define CONSTRAINT (Monad m)
89#define CONSTRAINT (Monad m)
90−#define MODULE_NAME "Data.ParserK"
90+#define MODULE_NAME "ParserK"
91
91
92#endif
92#endif
93
93
@@ -213,7 +213,7 @@ sequence_ value =
213
213
214{-# INLINE takeWhileFailD #-}
214{-# INLINE takeWhileFailD #-}
215takeWhileFailD :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
215takeWhileFailD :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
216−takeWhileFailD predicate (Fold fstep finitial _ ffinal) =
216+takeWhileFailD predicate (Fold fstep finitial fextract) =
217 Parser step initial extract
217 Parser step initial extract
218
218
219 where
219 where
@@ -234,7 +234,7 @@ takeWhileFailD predicate (Fold fstep finitial _ ffinal) =
234 Fold.Done b -> Done 0 b
234 Fold.Done b -> Done 0 b
235 else return $ Error "fail"
235 else return $ Error "fail"
236
236
237− extract s = fmap (Done 0) (ffinal s)
237+ extract s = fmap (Done 0) (fextract s)
238
238
239{-# INLINE takeWhileFail #-}
239{-# INLINE takeWhileFail #-}
240takeWhileFail :: CONSTRAINT =>
240takeWhileFail :: CONSTRAINT =>
benchmark/Streamly/Benchmark/Data/Ring/Unboxed.hs+1−1
@@ -16,7 +16,7 @@ import qualified Streamly.Internal.Data.Array as Array
16import qualified Streamly.Internal.Data.Ring as Ring
16import qualified Streamly.Internal.Data.Ring as Ring
17import qualified Data.Foldable as P
17import qualified Data.Foldable as P
18
18
19−import Test.Tasty.Bench
19+import Gauge
20import Streamly.Benchmark.Common
20import Streamly.Benchmark.Common
21
21
22import Prelude as P
22import Prelude as P
benchmark/Streamly/Benchmark/Data/Serialize.hs+49−35
@@ -1,5 +1,4 @@
1{-# LANGUAGE TemplateHaskell #-}
1{-# LANGUAGE TemplateHaskell #-}
2−{- HLINT ignore -}
3
2
4#undef FUSION_CHECK
3#undef FUSION_CHECK
5#ifdef FUSION_CHECK
4#ifdef FUSION_CHECK
@@ -19,23 +18,31 @@ module Main (main) where
19-------------------------------------------------------------------------------
18-------------------------------------------------------------------------------
20
19
21import Control.DeepSeq (NFData(..), deepseq)
20import Control.DeepSeq (NFData(..), deepseq)
22−import Control.Monad (when, void)
23import GHC.Generics (Generic)
21import GHC.Generics (Generic)
24import System.Random (randomRIO)
22import System.Random (randomRIO)
25#ifndef USE_UNBOX
23#ifndef USE_UNBOX
26import Test.QuickCheck (Arbitrary, arbitrary)
24import Test.QuickCheck (Arbitrary, arbitrary)
27#endif
25#endif
28
26
29−import Streamly.Internal.Data.MutByteArray
30−import qualified Streamly.Internal.Data.MutByteArray as MBA
31#ifdef USE_UNBOX
27#ifdef USE_UNBOX
32import Data.Proxy (Proxy(..))
28import Data.Proxy (Proxy(..))
29+import Streamly.Internal.Data.Unbox
33#else
30#else
34import Control.DeepSeq (force)
31import Control.DeepSeq (force)
35import Test.QuickCheck (oneof, generate)
32import Test.QuickCheck (oneof, generate)
33+import Streamly.Internal.Data.Unbox (newBytes, MutableByteArray)
34+import Streamly.Internal.Data.Serialize hiding (encode)
36#endif
35#endif
37
36
38−import Test.Tasty.Bench
37+#ifdef USE_TH
38+#ifdef USE_UNBOX
39+import Streamly.Internal.Data.Unbox.TH
40+#else
41+import Streamly.Internal.Data.Serialize.TH
42+#endif
43+#endif
44+
45+import Gauge
39import Streamly.Benchmark.Common
46import Streamly.Benchmark.Common
40
47
41#ifndef USE_UNBOX
48#ifndef USE_UNBOX
@@ -45,14 +52,14 @@ import Streamly.Benchmark.Data.Serialize.RecNonCompatible
45
52
46#ifdef USE_UNBOX
53#ifdef USE_UNBOX
47#define SERIALIZE_CLASS Unbox
54#define SERIALIZE_CLASS Unbox
48−#define DERIVE_CLASS(typ) $(deriveUnbox [d|instance Unbox typ|])
55+#define DERIVE_CLASS deriveUnbox
49−#define SERIALIZE_OP pokeAt
56+#define SERIALIZE_OP pokeByteIndex
50−#define DESERIALIZE_OP peekAt
57+#define DESERIALIZE_OP peekByteIndex
51#else
58#else
52#define SERIALIZE_CLASS Serialize
59#define SERIALIZE_CLASS Serialize
53−#define DERIVE_CLASS(typ) $(deriveSerialize [d|instance Serialize typ|])
60+#define DERIVE_CLASS deriveSerialize
54−#define SERIALIZE_OP serializeAt
61+#define SERIALIZE_OP serialize
55−#define DESERIALIZE_OP deserializeAt
62+#define DESERIALIZE_OP deserialize
56#endif
63#endif
57
64
58-------------------------------------------------------------------------------
65-------------------------------------------------------------------------------
@@ -65,7 +72,7 @@ data Unit = Unit
65#ifndef USE_TH
72#ifndef USE_TH
66instance SERIALIZE_CLASS Unit
73instance SERIALIZE_CLASS Unit
67#else
74#else
68−DERIVE_CLASS(Unit)
75+$(DERIVE_CLASS ''Unit)
69#endif
76#endif
70
77
71instance NFData Unit where
78instance NFData Unit where
@@ -80,7 +87,7 @@ data Sum2
80#ifndef USE_TH
87#ifndef USE_TH
81instance SERIALIZE_CLASS Sum2
88instance SERIALIZE_CLASS Sum2
82#else
89#else
83−DERIVE_CLASS(Sum2)
90+$(DERIVE_CLASS ''Sum2)
84#endif
91#endif
85
92
86instance NFData Sum2 where
93instance NFData Sum2 where
@@ -118,7 +125,7 @@ data Sum25
118#ifndef USE_TH
125#ifndef USE_TH
119instance SERIALIZE_CLASS Sum25
126instance SERIALIZE_CLASS Sum25
120#else
127#else
121−DERIVE_CLASS(Sum25)
128+$(DERIVE_CLASS ''Sum25)
122#endif
129#endif
123
130
124instance NFData Sum25 where
131instance NFData Sum25 where
@@ -157,7 +164,7 @@ data Product25
157#ifndef USE_TH
164#ifndef USE_TH
158instance SERIALIZE_CLASS Product25
165instance SERIALIZE_CLASS Product25
159#else
166#else
160−DERIVE_CLASS(Product25)
167+$(DERIVE_CLASS ''Product25)
161#endif
168#endif
162
169
163instance NFData Product25 where
170instance NFData Product25 where
@@ -237,7 +244,7 @@ data CustomDT1
237#ifndef USE_TH
244#ifndef USE_TH
238instance SERIALIZE_CLASS CustomDT1
245instance SERIALIZE_CLASS CustomDT1
239#else
246#else
240−DERIVE_CLASS(CustomDT1)
247+$(DERIVE_CLASS ''CustomDT1)
241#endif
248#endif
242
249
243instance NFData CustomDT1 where
250instance NFData CustomDT1 where
@@ -260,20 +267,19 @@ data BinTree a
260#ifndef USE_TH
267#ifndef USE_TH
261instance Serialize (BinTree a)
268instance Serialize (BinTree a)
262#else
269#else
263−$(deriveSerialize [d|instance Serialize a => Serialize (BinTree a)|])
270+$(deriveSerialize ''BinTree)
264#endif
271#endif
265
272
266instance NFData a => NFData (BinTree a) where
273instance NFData a => NFData (BinTree a) where
267 {-# INLINE rnf #-}
274 {-# INLINE rnf #-}
268 rnf (Leaf a) = rnf a `seq` ()
275 rnf (Leaf a) = rnf a `seq` ()
269− rnf (Tree l r) = rnf l `seq` rnf r
276+ rnf (Tree l r) = rnf l `seq` rnf r `seq` ()
270
277
271−-- XXX This may not terminate, or could become really large.
272instance Arbitrary a => Arbitrary (BinTree a) where
278instance Arbitrary a => Arbitrary (BinTree a) where
273 arbitrary = oneof [Leaf <$> arbitrary, Tree <$> arbitrary <*> arbitrary]
279 arbitrary = oneof [Leaf <$> arbitrary, Tree <$> arbitrary <*> arbitrary]
274
280
275mkBinTree :: (Arbitrary a) => Int -> IO (BinTree a)
281mkBinTree :: (Arbitrary a) => Int -> IO (BinTree a)
276−mkBinTree = go (generate arbitrary)
282+mkBinTree = go (generate $ arbitrary)
277
283
278 where
284 where
279
285
@@ -291,30 +297,35 @@ getSize :: forall a. SERIALIZE_CLASS a => a -> Int
291#ifdef USE_UNBOX
297#ifdef USE_UNBOX
292getSize _ = sizeOf (Proxy :: Proxy a)
298getSize _ = sizeOf (Proxy :: Proxy a)
293#else
299#else
294−getSize = addSizeTo 0
300+getSize = size 0
295#endif
301#endif
296
302
297-------------------------------------------------------------------------------
303-------------------------------------------------------------------------------
298-- Common helpers
304-- Common helpers
299-------------------------------------------------------------------------------
305-------------------------------------------------------------------------------
300
306
301−{- HLINT ignore "Eta reduce" -}
302-- Parts of "f" that are dependent on val will not be optimized out.
307-- Parts of "f" that are dependent on val will not be optimized out.
303{-# INLINE loop #-}
308{-# INLINE loop #-}
304loop :: Int -> (a -> IO b) -> a -> IO ()
309loop :: Int -> (a -> IO b) -> a -> IO ()
305loop count f val = go count val
310loop count f val = go count val
306 where
311 where
307
312
313+ go n x = do
314+ if n > 0
308− go n x = when (n > 0) $ f x >> go (n-1) x
315+ then f x >> go (n-1) x
316+ else return ()
309
317
310-- The first arg of "f" is the environment which is not threaded around in the
318-- The first arg of "f" is the environment which is not threaded around in the
311-- loop.
319-- loop.
312{-# INLINE loopWith #-}
320{-# INLINE loopWith #-}
313−loopWith :: Int -> (e -> a -> IO b) -> e -> a -> IO ()
321+loopWith :: Int -> (env -> a -> IO b) -> env -> a -> IO ()
314loopWith count f e val = go count val
322loopWith count f e val = go count val
315 where
323 where
316
324
325+ go n x = do
326+ if n > 0
317− go n x = when (n > 0) $ f e x >> go (n-1) x
327+ then f e x >> go (n-1) x
328+ else return ()
318
329
319benchSink :: NFData b => String -> Int -> (Int -> IO b) -> Benchmark
330benchSink :: NFData b => String -> Int -> (Int -> IO b) -> Benchmark
320benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
331benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
@@ -325,7 +336,7 @@ benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
325
336
326{-
337{-
327{-# INLINE pokeWithSize #-}
338{-# INLINE pokeWithSize #-}
328−pokeWithSize :: SERIALIZE_CLASS a => MutByteArray -> a -> IO ()
339+pokeWithSize :: SERIALIZE_CLASS a => MutableByteArray -> a -> IO ()
329pokeWithSize arr val = do
340pokeWithSize arr val = do
330 let n = getSize val
341 let n = getSize val
331 n `seq` SERIALIZE_OP 0 arr val >> return ()
342 n `seq` SERIALIZE_OP 0 arr val >> return ()
@@ -334,27 +345,27 @@ pokeWithSize arr val = do
334pokeTimesWithSize :: SERIALIZE_CLASS a => a -> Int -> IO ()
345pokeTimesWithSize :: SERIALIZE_CLASS a => a -> Int -> IO ()
335pokeTimesWithSize val times = do
346pokeTimesWithSize val times = do
336 let n = getSize val
347 let n = getSize val
337− arr <- MBA.new n
348+ arr <- newBytes n
338 loopWith times pokeWithSize arr val
349 loopWith times pokeWithSize arr val
339-}
350-}
340
351
341{-# INLINE poke #-}
352{-# INLINE poke #-}
342−poke :: SERIALIZE_CLASS a => MutByteArray -> a -> IO ()
353+poke :: SERIALIZE_CLASS a => MutableByteArray -> a -> IO ()
343−poke arr val = void (SERIALIZE_OP 0 arr val)
354+poke arr val = SERIALIZE_OP 0 arr val >> return ()
344
355
345{-# INLINE pokeTimes #-}
356{-# INLINE pokeTimes #-}
346pokeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
357pokeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
347pokeTimes val times = do
358pokeTimes val times = do
348 let n = getSize val
359 let n = getSize val
349− arr <- MBA.new n
360+ arr <- newBytes n
350 loopWith times poke arr val
361 loopWith times poke arr val
351
362
352{-# INLINE encode #-}
363{-# INLINE encode #-}
353encode :: SERIALIZE_CLASS a => a -> IO ()
364encode :: SERIALIZE_CLASS a => a -> IO ()
354encode val = do
365encode val = do
355 let n = getSize val
366 let n = getSize val
356− arr <- MBA.new n
367+ arr <- newBytes n
357− void (SERIALIZE_OP 0 arr val)
368+ SERIALIZE_OP 0 arr val >> return ()
358
369
359{-# INLINE encodeTimes #-}
370{-# INLINE encodeTimes #-}
360encodeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
371encodeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
@@ -362,7 +373,7 @@ encodeTimes val times = loop times encode val
362
373
363{-# INLINE peek #-}
374{-# INLINE peek #-}
364peek :: forall a. (NFData a, SERIALIZE_CLASS a) =>
375peek :: forall a. (NFData a, SERIALIZE_CLASS a) =>
365− (a, Int) -> MutByteArray -> IO ()
376+ (a, Int) -> MutableByteArray -> IO ()
366#ifdef USE_UNBOX
377#ifdef USE_UNBOX
367peek (_val, _) arr = do
378peek (_val, _) arr = do
368 (val1 :: a) <- DESERIALIZE_OP 0 arr
379 (val1 :: a) <- DESERIALIZE_OP 0 arr
@@ -389,7 +400,7 @@ peek (_val, n) arr = do
389{-# INLINE peekTimes #-}
400{-# INLINE peekTimes #-}
390peekTimes :: (NFData a, SERIALIZE_CLASS a) => Int -> a -> Int -> IO ()
401peekTimes :: (NFData a, SERIALIZE_CLASS a) => Int -> a -> Int -> IO ()
391peekTimes n val times = do
402peekTimes n val times = do
392− arr <- MBA.new n
403+ arr <- newBytes n
393 _ <- SERIALIZE_OP 0 arr val
404 _ <- SERIALIZE_OP 0 arr val
394 loopWith times peek (val, n) arr
405 loopWith times peek (val, n) arr
395
406
@@ -397,7 +408,7 @@ peekTimes n val times = do
397trip :: forall a. (NFData a, SERIALIZE_CLASS a) => a -> IO ()
408trip :: forall a. (NFData a, SERIALIZE_CLASS a) => a -> IO ()
398trip val = do
409trip val = do
399 let n = getSize val
410 let n = getSize val
400− arr <- MBA.new n
411+ arr <- newBytes n
401 _ <- SERIALIZE_OP 0 arr val
412 _ <- SERIALIZE_OP 0 arr val
402#ifdef USE_UNBOX
413#ifdef USE_UNBOX
403 (val1 :: a) <- DESERIALIZE_OP 0 arr
414 (val1 :: a) <- DESERIALIZE_OP 0 arr
@@ -560,6 +571,8 @@ main = do
560 let !len = length lInt -- evaluate the list
571 let !len = length lInt -- evaluate the list
561#endif
572#endif
562#ifndef FUSION_CHECK
573#ifndef FUSION_CHECK
574+ -- This can take too much memory/CPU, need to restrict the test
575+ -- runQC
563#ifdef USE_UNBOX
576#ifdef USE_UNBOX
564 runWithCLIOpts defaultStreamSize allBenchmarks
577 runWithCLIOpts defaultStreamSize allBenchmarks
565#else
578#else
@@ -567,6 +580,7 @@ main = do
567 `seq` runWithCLIOpts
580 `seq` runWithCLIOpts
568 defaultStreamSize
581 defaultStreamSize
569 (allBenchmarks tInt lInt recL recR)
582 (allBenchmarks tInt lInt recL recR)
583+
570#endif
584#endif
571#else
585#else
572 -- Enable FUSION_CHECK macro at the beginning of the file
586 -- Enable FUSION_CHECK macro at the beginning of the file
benchmark/Streamly/Benchmark/Data/Serialize/RecCompatible.hs+3−3
@@ -9,10 +9,10 @@ module Streamly.Benchmark.Data.Serialize.RecCompatible
9-- Imports
9-- Imports
10--------------------------------------------------------------------------------
10--------------------------------------------------------------------------------
11
11
12−import Streamly.Internal.Data.MutByteArray (Serialize)
12+import Streamly.Internal.Data.Serialize (Serialize)
13import Streamly.Benchmark.Data.Serialize.TH (genLargeRecord)
13import Streamly.Benchmark.Data.Serialize.TH (genLargeRecord)
14
14
15−import qualified Streamly.Internal.Data.MutByteArray as Serialize
15+import qualified Streamly.Internal.Data.Serialize.TH as Serialize
16
16
17--------------------------------------------------------------------------------
17--------------------------------------------------------------------------------
18-- Code
18-- Code
@@ -20,5 +20,5 @@ import qualified Streamly.Internal.Data.MutByteArray as Serialize
20
20
21$(genLargeRecord "RecCompatible" 50)
21$(genLargeRecord "RecCompatible" 50)
22$(Serialize.deriveSerializeWith
22$(Serialize.deriveSerializeWith
23− (Serialize.encodeRecordFields True)
23+ (Serialize.defaultConfig {Serialize.recordSyntaxWithHeader = True})
24 [d|instance Serialize RecCompatible|])
24 [d|instance Serialize RecCompatible|])
benchmark/Streamly/Benchmark/Data/Serialize/RecNonCompatible.hs+2−2
@@ -11,11 +11,11 @@ module Streamly.Benchmark.Data.Serialize.RecNonCompatible
11
11
12import Streamly.Benchmark.Data.Serialize.TH (genLargeRecord)
12import Streamly.Benchmark.Data.Serialize.TH (genLargeRecord)
13
13
14−import qualified Streamly.Internal.Data.MutByteArray as Serialize
14+import qualified Streamly.Internal.Data.Serialize.TH as Serialize
15
15
16--------------------------------------------------------------------------------
16--------------------------------------------------------------------------------
17-- Code
17-- Code
18--------------------------------------------------------------------------------
18--------------------------------------------------------------------------------
19
19
20$(genLargeRecord "RecNonCompatible" 50)
20$(genLargeRecord "RecNonCompatible" 50)
21−$(Serialize.deriveSerialize [d|instance Serialize.Serialize RecNonCompatible|])
21+$(Serialize.deriveSerialize ''RecNonCompatible)
benchmark/Streamly/Benchmark/Data/Serialize/TH.hs+4−4
@@ -8,7 +8,7 @@ module Streamly.Benchmark.Data.Serialize.TH (genLargeRecord) where
8
8
9import Language.Haskell.TH
9import Language.Haskell.TH
10
10
11−import Streamly.Internal.Data.MutByteArray (makeI)
11+import Streamly.Internal.Data.Serialize.TH.Bottom (makeI)
12import Control.DeepSeq (NFData(..))
12import Control.DeepSeq (NFData(..))
13
13
14--------------------------------------------------------------------------------
14--------------------------------------------------------------------------------
@@ -18,7 +18,7 @@ import Control.DeepSeq (NFData(..))
18genLargeRecord :: String -> Int -> Q [Dec]
18genLargeRecord :: String -> Int -> Q [Dec]
19genLargeRecord tyName numFields =
19genLargeRecord tyName numFields =
20 sequence
20 sequence
21− [ dataD
21+ ([ dataD
22 (pure [])
22 (pure [])
23 (mkName tyName)
23 (mkName tyName)
24 []
24 []
@@ -28,7 +28,7 @@ genLargeRecord tyName numFields =
28 , mkValueSigDec
28 , mkValueSigDec
29 , mkValueDec
29 , mkValueDec
30 , nfDataInstance tyName
30 , nfDataInstance tyName
31− ]
31+ ])
32
32
33 where
33 where
34
34
@@ -64,7 +64,7 @@ genLargeRecord tyName numFields =
64 (foldl
64 (foldl
65 (\b a -> [|$(b) $(a)|])
65 (\b a -> [|$(b) $(a)|])
66 (conE (mkName tyName))
66 (conE (mkName tyName))
67− (conE '() <$ [0 .. (numFields - 1)])))
67+ (const (conE '()) <$> [0 .. (numFields - 1)])))
68 []
68 []
69 ]
69 ]
70 mkCon nm = recC (mkName nm) (mkField <$> [0 .. (numFields - 1)])
70 mkCon nm = recC (mkName nm) (mkField <$> [0 .. (numFields - 1)])
benchmark/Streamly/Benchmark/Data/Stream/Common.hs+1−3
@@ -71,9 +71,7 @@ module Stream.Common
71 )
71 )
72where
72where
73
73
74−#if !MIN_VERSION_base(4,18,0)
75import Control.Applicative (liftA2)
74import Control.Applicative (liftA2)
76−#endif
77import Control.DeepSeq (NFData)
75import Control.DeepSeq (NFData)
78import Control.Exception (try)
76import Control.Exception (try)
79import GHC.Exception (ErrorCall)
77import GHC.Exception (ErrorCall)
@@ -104,7 +102,7 @@ import qualified Streamly.Internal.Data.Stream as StreamK
104#endif
102#endif
105#endif
103#endif
106
104
107−import Test.Tasty.Bench
105+import Gauge
108import Prelude hiding (Foldable(..), mapM, replicate)
106import Prelude hiding (Foldable(..), mapM, replicate)
109
107
110#ifdef USE_STREAMK
108#ifdef USE_STREAMK
benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs+3−3
@@ -14,14 +14,14 @@ where
14import Stream.Common
14import Stream.Common
15 (composeN, benchIO, benchIOSink, benchIOSrc, sourceUnfoldrM)
15 (composeN, benchIO, benchIOSink, benchIOSrc, sourceUnfoldrM)
16import Streamly.Data.Stream (Stream)
16import Streamly.Data.Stream (Stream)
17−import Streamly.Internal.Data.Stream.Prelude (MonadAsync, Config)
17+import Streamly.Internal.Data.Stream.Concurrent (MonadAsync, Config)
18
18
19import qualified Data.List as List
19import qualified Data.List as List
20import qualified Streamly.Data.Fold as Fold
20import qualified Streamly.Data.Fold as Fold
21import qualified Streamly.Data.Stream as Stream
21import qualified Streamly.Data.Stream as Stream
22−import qualified Streamly.Internal.Data.Stream.Prelude as Async
22+import qualified Streamly.Internal.Data.Stream.Concurrent as Async
23
23
24−import Test.Tasty.Bench
24+import Gauge
25import Prelude hiding (mapM)
25import Prelude hiding (mapM)
26import Streamly.Benchmark.Common
26import Streamly.Benchmark.Common
27
27
benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs+1−1
@@ -9,7 +9,7 @@
9import Stream.ConcurrentCommon (allBenchmarks)
9import Stream.ConcurrentCommon (allBenchmarks)
10import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
10import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
11
11
12−import qualified Streamly.Internal.Data.Stream.Prelude as Async
12+import qualified Streamly.Internal.Data.Stream.Concurrent as Async
13
13
14moduleName :: String
14moduleName :: String
15moduleName = "Data.Stream.ConcurrentEager"
15moduleName = "Data.Stream.ConcurrentEager"
benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs+1−1
@@ -9,7 +9,7 @@
9import Stream.ConcurrentCommon (allBenchmarks)
9import Stream.ConcurrentCommon (allBenchmarks)
10import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
10import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
11
11
12−import qualified Streamly.Internal.Data.Stream.Prelude as Async
12+import qualified Streamly.Internal.Data.Stream.Concurrent as Async
13
13
14moduleName :: String
14moduleName :: String
15moduleName = "Data.Stream.ConcurrentInterleaved"
15moduleName = "Data.Stream.ConcurrentInterleaved"
benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs+1−1
@@ -9,7 +9,7 @@
9import Stream.ConcurrentCommon (allBenchmarks)
9import Stream.ConcurrentCommon (allBenchmarks)
10import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
10import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize)
11
11
12−import qualified Streamly.Internal.Data.Stream.Prelude as Async
12+import qualified Streamly.Internal.Data.Stream.Concurrent as Async
13
13
14moduleName :: String
14moduleName :: String
15moduleName = "Data.Stream.ConcurrentOrdered"
15moduleName = "Data.Stream.ConcurrentOrdered"
benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs+1−3
@@ -57,7 +57,7 @@ import qualified Streamly.Internal.Data.Stream as StreamK
57#endif
57#endif
58#endif
58#endif
59
59
60−import Test.Tasty.Bench
60+import Gauge
61import Streamly.Benchmark.Common
61import Streamly.Benchmark.Common
62import Prelude hiding (length, sum, or, and, any, all, notElem, elem, (!!),
62import Prelude hiding (length, sum, or, and, any, all, notElem, elem, (!!),
63 lookup, repeat, minimum, maximum, product, last, mapM_, init)
63 lookup, repeat, minimum, maximum, product, last, mapM_, init)
@@ -132,14 +132,12 @@ foldableAny :: Int -> Int -> Bool
132foldableAny value n =
132foldableAny value n =
133 Prelude.any (> (value + 1)) (sourceUnfoldr value n :: Stream Identity Int)
133 Prelude.any (> (value + 1)) (sourceUnfoldr value n :: Stream Identity Int)
134
134
135−{- HLINT ignore "Use all"-}
136{-# INLINE foldableAnd #-}
135{-# INLINE foldableAnd #-}
137foldableAnd :: Int -> Int -> Bool
136foldableAnd :: Int -> Int -> Bool
138foldableAnd value n =
137foldableAnd value n =
139 Prelude.and $ fmap
138 Prelude.and $ fmap
140 (<= (value + 1)) (sourceUnfoldr value n :: Stream Identity Int)
139 (<= (value + 1)) (sourceUnfoldr value n :: Stream Identity Int)
141
140
142−{- HLINT ignore "Use any"-}
143{-# INLINE foldableOr #-}
141{-# INLINE foldableOr #-}
144foldableOr :: Int -> Int -> Bool
142foldableOr :: Int -> Int -> Bool
145foldableOr value n =
143foldableOr value n =
benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs+3−12
@@ -36,22 +36,21 @@ import System.IO (Handle, hClose, hPutChar)
36import qualified Streamly.FileSystem.Handle as FH
36import qualified Streamly.FileSystem.Handle as FH
37import qualified Streamly.Internal.FileSystem.Handle as IFH
37import qualified Streamly.Internal.FileSystem.Handle as IFH
38import qualified Streamly.Internal.Data.Unfold as IUF
38import qualified Streamly.Internal.Data.Unfold as IUF
39−import qualified Streamly.Internal.Data.Unfold.Prelude as IUF
39+import qualified Streamly.Internal.Data.Unfold.Exception as IUF
40
40
41#ifdef USE_PRELUDE
41#ifdef USE_PRELUDE
42import qualified Streamly.Internal.Data.Stream.IsStream as Stream
42import qualified Streamly.Internal.Data.Stream.IsStream as Stream
43#else
43#else
44import qualified Streamly.Internal.Data.Stream as Stream
44import qualified Streamly.Internal.Data.Stream as Stream
45−import qualified Streamly.Internal.Data.Stream.Prelude as Stream
45+import qualified Streamly.Internal.Data.Stream.Exception.Lifted as Stream
46#endif
46#endif
47
47
48−import Test.Tasty.Bench hiding (env)
48+import Gauge hiding (env)
49import Prelude hiding (last, length)
49import Prelude hiding (last, length)
50import Streamly.Benchmark.Common
50import Streamly.Benchmark.Common
51import Streamly.Benchmark.Common.Handle
51import Streamly.Benchmark.Common.Handle
52
52
53#ifdef INSPECTION
53#ifdef INSPECTION
54−import Control.Monad.Catch (MonadCatch)
55import Test.Inspection
54import Test.Inspection
56
55
57import qualified Streamly.Internal.Data.Stream as D
56import qualified Streamly.Internal.Data.Stream as D
@@ -287,12 +286,8 @@ readChunksOnException inh devNull =
287 in IUF.fold (IFH.writeChunks devNull) readEx inh
286 in IUF.fold (IFH.writeChunks devNull) readEx inh
288
287
289#ifdef INSPECTION
288#ifdef INSPECTION
290−#if __GLASGOW_HASKELL__ >= 906
291−inspect $ hasNoTypeClassesExcept 'readChunksOnException [''MonadCatch]
292−#else
293inspect $ hasNoTypeClasses 'readChunksOnException
289inspect $ hasNoTypeClasses 'readChunksOnException
294#endif
290#endif
295−#endif
296
291
297-- | Send the file contents to /dev/null with exception handling
292-- | Send the file contents to /dev/null with exception handling
298readChunksBracket_ :: Handle -> Handle -> IO ()
293readChunksBracket_ :: Handle -> Handle -> IO ()
@@ -301,12 +296,8 @@ readChunksBracket_ inh devNull =
301 in IUF.fold (IFH.writeChunks devNull) readEx inh
296 in IUF.fold (IFH.writeChunks devNull) readEx inh
302
297
303#ifdef INSPECTION
298#ifdef INSPECTION
304−#if __GLASGOW_HASKELL__ >= 906
305−inspect $ hasNoTypeClassesExcept 'readChunksBracket_ [''MonadCatch]
306−#else
307inspect $ hasNoTypeClasses 'readChunksBracket_
299inspect $ hasNoTypeClasses 'readChunksBracket_
308#endif
300#endif
309−#endif
310
301
311readChunksBracket :: Handle -> Handle -> IO ()
302readChunksBracket :: Handle -> Handle -> IO ()
312readChunksBracket inh devNull =
303readChunksBracket inh devNull =
benchmark/Streamly/Benchmark/Data/Stream/Expand.hs+1−9
@@ -54,7 +54,7 @@ import qualified Streamly.Internal.Data.Stream as StreamK
54#endif
54#endif
55#endif
55#endif
56
56
57−import Test.Tasty.Bench
57+import Gauge
58import Stream.Common
58import Stream.Common
59import Streamly.Benchmark.Common
59import Streamly.Benchmark.Common
60import Prelude hiding (concatMap)
60import Prelude hiding (concatMap)
@@ -198,11 +198,7 @@ concatMapPure outer inner n =
198 (fromStream $ sourceUnfoldr outer n)
198 (fromStream $ sourceUnfoldr outer n)
199
199
200#ifdef INSPECTION
200#ifdef INSPECTION
201−#if __GLASGOW_HASKELL__ >= 906
202−inspect $ hasNoTypeClassesExcept 'concatMapPure [''Applicative]
203−#else
204inspect $ hasNoTypeClasses 'concatMapPure
201inspect $ hasNoTypeClasses 'concatMapPure
205−#endif
206inspect $ 'concatMapPure `hasNoType` ''SPEC
202inspect $ 'concatMapPure `hasNoType` ''SPEC
207#endif
203#endif
208
204
@@ -215,11 +211,7 @@ concatMapRepl outer inner n =
215 (fromStream . S.replicate inner) (fromStream $ sourceUnfoldrM outer n)
211 (fromStream . S.replicate inner) (fromStream $ sourceUnfoldrM outer n)
216
212
217#ifdef INSPECTION
213#ifdef INSPECTION
218−#if __GLASGOW_HASKELL__ >= 906
219−inspect $ hasNoTypeClassesExcept 'concatMapRepl [''Applicative]
220−#else
221inspect $ hasNoTypeClasses 'concatMapRepl
214inspect $ hasNoTypeClasses 'concatMapRepl
222−#endif
223inspect $ 'concatMapRepl `hasNoType` ''SPEC
215inspect $ 'concatMapRepl `hasNoType` ''SPEC
224#endif
216#endif
225
217
benchmark/Streamly/Benchmark/Data/Stream/Generate.hs+1−1
@@ -40,7 +40,7 @@ import qualified Stream.Common as Common
40#endif
40#endif
41#endif
41#endif
42
42
43−import Test.Tasty.Bench
43+import Gauge
44import Streamly.Benchmark.Common
44import Streamly.Benchmark.Common
45import qualified Prelude
45import qualified Prelude
46
46
benchmark/Streamly/Benchmark/Data/Stream/Lift.hs+1−1
@@ -37,7 +37,7 @@ import qualified Control.Monad.State.Strict as State
37#endif
37#endif
38#endif
38#endif
39
39
40−import Test.Tasty.Bench
40+import Gauge
41import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common
42import Prelude hiding (reverse, tail)
42import Prelude hiding (reverse, tail)
43
43
benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs+2−2
@@ -48,7 +48,7 @@ import Streamly.Internal.Data.Stream (Stream)
48import qualified Streamly.Internal.Data.Stream as S
48import qualified Streamly.Internal.Data.Stream as S
49#ifndef USE_STREAMLY_CORE
49#ifndef USE_STREAMLY_CORE
50import qualified Streamly.Data.Stream.Prelude as S
50import qualified Streamly.Data.Stream.Prelude as S
51−import qualified Streamly.Internal.Data.Stream.Prelude as S
51+import qualified Streamly.Internal.Data.Stream.Time as S
52#endif
52#endif
53
53
54#ifdef USE_STREAMK
54#ifdef USE_STREAMK
@@ -61,7 +61,7 @@ import qualified Streamly.Internal.Data.Stream as K
61
61
62#endif
62#endif
63
63
64−import Test.Tasty.Bench
64+import Gauge
65import Streamly.Benchmark.Common
65import Streamly.Benchmark.Common
66import Stream.Common
66import Stream.Common
67import Prelude hiding (reverse, tail)
67import Prelude hiding (reverse, tail)
benchmark/Streamly/Benchmark/Data/Stream/Split.hs+1−1
@@ -35,7 +35,7 @@ import qualified Streamly.Internal.FileSystem.Handle as IFH
35import qualified Streamly.Internal.Unicode.Stream as IUS
35import qualified Streamly.Internal.Unicode.Stream as IUS
36import qualified Streamly.Prelude as S
36import qualified Streamly.Prelude as S
37
37
38−import Test.Tasty.Bench hiding (env)
38+import Gauge hiding (env)
39import Prelude hiding (last, length)
39import Prelude hiding (last, length)
40import Streamly.Benchmark.Common
40import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common.Handle
41import Streamly.Benchmark.Common.Handle
benchmark/Streamly/Benchmark/Data/Stream/StreamD.hs+1−3
@@ -22,12 +22,10 @@
22
22
23module Main (main) where
23module Main (main) where
24
24
25−#if !MIN_VERSION_base(4,18,0)
26import Control.Applicative (liftA2)
25import Control.Applicative (liftA2)
27−#endif
28import Control.Monad (when)
26import Control.Monad (when)
29import Data.Maybe (isJust)
27import Data.Maybe (isJust)
30−import Test.Tasty.Bench (bench, nfIO, bgroup, Benchmark, defaultMain)
28+import Gauge (bench, nfIO, bgroup, Benchmark, defaultMain)
31import System.Random (randomRIO)
29import System.Random (randomRIO)
32import Prelude hiding (tail, mapM_, foldl, last, map, mapM, concatMap, zip)
30import Prelude hiding (tail, mapM_, foldl, last, map, mapM, concatMap, zip)
33
31
benchmark/Streamly/Benchmark/Data/Stream/StreamK.hs+1−3
@@ -21,9 +21,7 @@
21
21
22module Main (main) where
22module Main (main) where
23
23
24−#if !MIN_VERSION_base(4,18,0)
25import Control.Applicative (liftA2)
24import Control.Applicative (liftA2)
26−#endif
27import Control.Monad (when)
25import Control.Monad (when)
28import Data.Maybe (isJust)
26import Data.Maybe (isJust)
29import System.Random (randomRIO)
27import System.Random (randomRIO)
@@ -37,7 +35,7 @@ import qualified Data.List as List
37
35
38import qualified Streamly.Internal.Data.StreamK as S
36import qualified Streamly.Internal.Data.StreamK as S
39
37
40−import Test.Tasty.Bench (bench, nfIO, bgroup, Benchmark, defaultMain)
38+import Gauge (bench, nfIO, bgroup, Benchmark, defaultMain)
41
39
42import Streamly.Benchmark.Common
40import Streamly.Benchmark.Common
43
41
benchmark/Streamly/Benchmark/Data/Stream/StreamKAlt.hs+2−2
@@ -23,7 +23,7 @@ import qualified Streamly.Internal.Data.StreamK.Alt as S
23-- import qualified Streamly.Internal.Data.SVar as S
23-- import qualified Streamly.Internal.Data.SVar as S
24
24
25import Streamly.Benchmark.Common
25import Streamly.Benchmark.Common
26−import Test.Tasty.Bench (bgroup, Benchmark, defaultMain)
26+import Gauge (bgroup, Benchmark, defaultMain)
27
27
28value :: Int
28value :: Int
29value = 100000
29value = 100000
@@ -452,4 +452,4 @@ o_1_space =
452 ]
452 ]
453
453
454main :: IO ()
454main :: IO ()
455−main = defaultMain [o_1_space]
455+main = defaultMain $ concat [o_1_space]
benchmark/Streamly/Benchmark/Data/Stream/ToStreamK.hs+2−2
@@ -37,7 +37,7 @@ import qualified Streamly.Internal.Data.StreamK as S
37import qualified Streamly.Internal.Data.Stream as D
37import qualified Streamly.Internal.Data.Stream as D
38import qualified Streamly.Internal.Data.Fold as Fold
38import qualified Streamly.Internal.Data.Fold as Fold
39
39
40−import Test.Tasty.Bench (bgroup, Benchmark, defaultMain)
40+import Gauge (bgroup, Benchmark, defaultMain)
41
41
42import Streamly.Benchmark.Common
42import Streamly.Benchmark.Common
43
43
@@ -120,7 +120,7 @@ fromFoldable streamLen n = S.fromFoldable [n..n+streamLen]
120{-# INLINE fromFoldableM #-}
120{-# INLINE fromFoldableM #-}
121fromFoldableM :: Monad m => Int -> Int -> Stream m Int
121fromFoldableM :: Monad m => Int -> Int -> Stream m Int
122fromFoldableM streamLen n =
122fromFoldableM streamLen n =
123− Prelude.foldr (S.consM . return) S.nil [n .. n + streamLen]
123+ Prelude.foldr S.consM S.nil (Prelude.fmap return [n..n+streamLen])
124
124
125{-
125{-
126{-# INLINABLE concatMapFoldableWith #-}
126{-# INLINABLE concatMapFoldableWith #-}
benchmark/Streamly/Benchmark/Data/Stream/Transform.hs+2−2
@@ -46,7 +46,7 @@ import Streamly.Internal.Data.Time.Units
46import Streamly.Internal.Data.Stream (Stream)
46import Streamly.Internal.Data.Stream (Stream)
47import qualified Streamly.Internal.Data.Stream as Stream
47import qualified Streamly.Internal.Data.Stream as Stream
48#ifndef USE_STREAMLY_CORE
48#ifndef USE_STREAMLY_CORE
49−import qualified Streamly.Internal.Data.Stream.Prelude as Stream
49+import qualified Streamly.Internal.Data.Stream.Time as Stream
50#endif
50#endif
51#ifdef USE_STREAMK
51#ifdef USE_STREAMK
52import Control.DeepSeq (NFData(..))
52import Control.DeepSeq (NFData(..))
@@ -58,7 +58,7 @@ import qualified Streamly.Internal.Data.StreamK as StreamK
58#endif
58#endif
59#endif
59#endif
60
60
61−import Test.Tasty.Bench
61+import Gauge
62import Stream.Common hiding (scanl')
62import Stream.Common hiding (scanl')
63import Streamly.Benchmark.Common
63import Streamly.Benchmark.Common
64import Prelude hiding (sequence, mapM)
64import Prelude hiding (sequence, mapM)
benchmark/Streamly/Benchmark/Data/Unfold.hs+2−11
@@ -31,18 +31,17 @@ import qualified Prelude
31import qualified Streamly.FileSystem.Handle as FH
31import qualified Streamly.FileSystem.Handle as FH
32import qualified Streamly.Internal.Data.Fold as FL
32import qualified Streamly.Internal.Data.Fold as FL
33import qualified Streamly.Internal.Data.Unfold as UF
33import qualified Streamly.Internal.Data.Unfold as UF
34−import qualified Streamly.Internal.Data.Unfold.Prelude as UF
34+import qualified Streamly.Internal.Data.Unfold.Exception as UF
35import qualified Streamly.Internal.Data.Stream as S
35import qualified Streamly.Internal.Data.Stream as S
36import qualified Streamly.Internal.Data.Stream as D
36import qualified Streamly.Internal.Data.Stream as D
37import qualified Streamly.Internal.Data.StreamK as K
37import qualified Streamly.Internal.Data.StreamK as K
38
38
39−import Test.Tasty.Bench hiding (env)
39+import Gauge hiding (env)
40import Prelude hiding (take, filter, zipWith, map, mapM, takeWhile)
40import Prelude hiding (take, filter, zipWith, map, mapM, takeWhile)
41import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common
42import Streamly.Benchmark.Common.Handle
42import Streamly.Benchmark.Common.Handle
43
43
44#ifdef INSPECTION
44#ifdef INSPECTION
45−import Control.Monad.Catch (MonadCatch)
46import Test.Inspection
45import Test.Inspection
47#endif
46#endif
48
47
@@ -777,11 +776,7 @@ readWriteFinally_Unfold inh devNull =
777 in S.fold (FH.write devNull) $ S.unfold readEx inh
776 in S.fold (FH.write devNull) $ S.unfold readEx inh
778
777
779#ifdef INSPECTION
778#ifdef INSPECTION
780−#if __GLASGOW_HASKELL__ >= 906
781−inspect $ hasNoTypeClassesExcept 'readWriteFinally_Unfold [''MonadCatch]
782−#else
783inspect $ hasNoTypeClasses 'readWriteFinally_Unfold
779inspect $ hasNoTypeClasses 'readWriteFinally_Unfold
784−#endif
785-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''Step
780-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''Step
786#endif
781#endif
787
782
@@ -797,11 +792,7 @@ readWriteBracket_Unfold inh devNull =
797 in S.fold (FH.write devNull) $ S.unfold readEx inh
792 in S.fold (FH.write devNull) $ S.unfold readEx inh
798
793
799#ifdef INSPECTION
794#ifdef INSPECTION
800−#if __GLASGOW_HASKELL__ >= 906
801−inspect $ hasNoTypeClassesExcept 'readWriteBracket_Unfold [''MonadCatch]
802−#else
803inspect $ hasNoTypeClasses 'readWriteBracket_Unfold
795inspect $ hasNoTypeClasses 'readWriteBracket_Unfold
804−#endif
805-- inspect $ 'readWriteBracketUnfold `hasNoType` ''Step
796-- inspect $ 'readWriteBracketUnfold `hasNoType` ''Step
806#endif
797#endif
807
798
benchmark/Streamly/Benchmark/FileSystem/Handle.hs+1−1
@@ -22,7 +22,7 @@ import Streamly.Benchmark.Common.Handle (mkHandleBenchEnv)
22import qualified Handle.ReadWrite as RW
22import qualified Handle.ReadWrite as RW
23import qualified Handle.Read as RO
23import qualified Handle.Read as RO
24
24
25−import Test.Tasty.Bench hiding (env)
25+import Gauge hiding (env)
26import Prelude hiding (last, length)
26import Prelude hiding (last, length)
27import Streamly.Benchmark.Common
27import Streamly.Benchmark.Common
28
28
benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs+9−8
@@ -33,6 +33,7 @@ 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
36import qualified Streamly.Internal.Data.Fold as FL
37import qualified Streamly.Internal.Data.Fold as FL
37import qualified Streamly.Internal.Data.Stream as IP
38import qualified Streamly.Internal.Data.Stream as IP
38import qualified Streamly.Internal.FileSystem.Handle as IFH
39import qualified Streamly.Internal.FileSystem.Handle as IFH
@@ -40,14 +41,14 @@ import qualified Streamly.Internal.Unicode.Stream as IUS
40import qualified Streamly.Data.Stream.Prelude as S
41import qualified Streamly.Data.Stream.Prelude as S
41import qualified Streamly.Unicode.Stream as SS
42import qualified Streamly.Unicode.Stream as SS
42
43
43−import Test.Tasty.Bench hiding (env)
44+import Gauge hiding (env)
44import Prelude hiding (last, length)
45import Prelude hiding (last, length)
45import Streamly.Benchmark.Common.Handle
46import Streamly.Benchmark.Common.Handle
46
47
47#ifdef INSPECTION
48#ifdef INSPECTION
48import Streamly.Internal.Data.Stream (Step(..), FoldMany)
49import Streamly.Internal.Data.Stream (Step(..), FoldMany)
49
50
50−import qualified Streamly.Internal.Data.MutArray as MutArray
51+import qualified Streamly.Internal.Data.MutArray as MA
51import qualified Streamly.Internal.Data.Stream as D
52import qualified Streamly.Internal.Data.Stream as D
52import qualified Streamly.Internal.Data.Unfold as IUF
53import qualified Streamly.Internal.Data.Unfold as IUF
53
54
@@ -68,7 +69,7 @@ readLast = S.fold Fold.last . S.unfold FH.reader
68inspect $ hasNoTypeClasses 'readLast
69inspect $ hasNoTypeClasses 'readLast
69inspect $ 'readLast `hasNoType` ''Step -- S.unfold
70inspect $ 'readLast `hasNoType` ''Step -- S.unfold
70inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
71inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
71−inspect $ 'readLast `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
72+inspect $ 'readLast `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
72#endif
73#endif
73
74
74-- assert that flattenArrays constructors are not present
75-- assert that flattenArrays constructors are not present
@@ -80,7 +81,7 @@ readCountBytes = S.fold Fold.length . S.unfold FH.reader
80inspect $ hasNoTypeClasses 'readCountBytes
81inspect $ hasNoTypeClasses 'readCountBytes
81inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
82inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
82inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
83inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
83−inspect $ 'readCountBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
84+inspect $ 'readCountBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
84#endif
85#endif
85
86
86-- | Count the number of lines in a file.
87-- | Count the number of lines in a file.
@@ -95,7 +96,7 @@ readCountLines =
95inspect $ hasNoTypeClasses 'readCountLines
96inspect $ hasNoTypeClasses 'readCountLines
96inspect $ 'readCountLines `hasNoType` ''Step
97inspect $ 'readCountLines `hasNoType` ''Step
97inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
98inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
98−inspect $ 'readCountLines `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
99+inspect $ 'readCountLines `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
99#endif
100#endif
100
101
101-- | Count the number of words in a file.
102-- | Count the number of words in a file.
@@ -119,7 +120,7 @@ readSumBytes = S.fold Fold.sum . S.unfold FH.reader
119inspect $ hasNoTypeClasses 'readSumBytes
120inspect $ hasNoTypeClasses 'readSumBytes
120inspect $ 'readSumBytes `hasNoType` ''Step
121inspect $ 'readSumBytes `hasNoType` ''Step
121inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
122inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
122−inspect $ 'readSumBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
123+inspect $ 'readSumBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
123#endif
124#endif
124
125
125-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
126-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
@@ -235,13 +236,13 @@ groupsOf :: Int -> Handle -> IO Int
235groupsOf n inh =
236groupsOf n inh =
236 -- writeNUnsafe gives 2.5x boost here over writeN.
237 -- writeNUnsafe gives 2.5x boost here over writeN.
237 S.fold Fold.length
238 S.fold Fold.length
238− $ IP.groupsOf n (A.writeNUnsafe n) (S.unfold FH.reader inh)
239+ $ IP.groupsOf n (AT.writeNUnsafe n) (S.unfold FH.reader inh)
239
240
240#ifdef INSPECTION
241#ifdef INSPECTION
241inspect $ hasNoTypeClasses 'groupsOf
242inspect $ hasNoTypeClasses 'groupsOf
242inspect $ 'groupsOf `hasNoType` ''Step
243inspect $ 'groupsOf `hasNoType` ''Step
243inspect $ 'groupsOf `hasNoType` ''FoldMany
244inspect $ 'groupsOf `hasNoType` ''FoldMany
244−inspect $ 'groupsOf `hasNoType` ''MutArray.ArrayUnsafe -- AT.writeNUnsafe
245+inspect $ 'groupsOf `hasNoType` ''AT.ArrayUnsafe -- AT.writeNUnsafe
245 -- FH.read/A.read
246 -- FH.read/A.read
246inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
247inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
247#endif
248#endif
benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs+10−9
@@ -34,7 +34,7 @@ import qualified Streamly.Internal.FileSystem.Handle as IFH
34import qualified Streamly.Data.Array as A
34import qualified Streamly.Data.Array as A
35import qualified Streamly.Data.Stream.Prelude as S
35import qualified Streamly.Data.Stream.Prelude as S
36
36
37−import Test.Tasty.Bench hiding (env)
37+import Gauge hiding (env)
38import Streamly.Benchmark.Common.Handle
38import Streamly.Benchmark.Common.Handle
39
39
40#ifdef INSPECTION
40#ifdef INSPECTION
@@ -42,7 +42,8 @@ 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 as MutArray
45+import qualified Streamly.Internal.Data.Stream.MutChunked as MAS
46+import qualified Streamly.Internal.Data.Array as AT
46
47
47import Test.Inspection
48import Test.Inspection
48#endif
49#endif
@@ -82,7 +83,7 @@ copyStream inh outh = S.fold (FH.write outh) (S.unfold FH.reader inh)
82inspect $ hasNoTypeClasses 'copyStream
83inspect $ hasNoTypeClasses 'copyStream
83inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
84inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
84inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
85inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
85−inspect $ 'copyStream `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
86+inspect $ 'copyStream `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
86 -- FH.read/A.read
87 -- FH.read/A.read
87inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
88inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
88#endif
89#endif
@@ -108,8 +109,8 @@ readFromBytesNull inh devNull = IFH.putBytes devNull $ S.unfold FH.reader inh
108#ifdef INSPECTION
109#ifdef INSPECTION
109inspect $ hasNoTypeClasses 'readFromBytesNull
110inspect $ hasNoTypeClasses 'readFromBytesNull
110inspect $ 'readFromBytesNull `hasNoType` ''Step
111inspect $ 'readFromBytesNull `hasNoType` ''Step
111−inspect $ 'readFromBytesNull `hasNoType` ''MutArray.SpliceState
112+inspect $ 'readFromBytesNull `hasNoType` ''MAS.SpliceState
112−inspect $ 'readFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
113+inspect $ 'readFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
113inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
114inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
114#endif
115#endif
115
116
@@ -122,8 +123,8 @@ readWithFromBytesNull inh devNull =
122#ifdef INSPECTION
123#ifdef INSPECTION
123inspect $ hasNoTypeClasses 'readWithFromBytesNull
124inspect $ hasNoTypeClasses 'readWithFromBytesNull
124inspect $ 'readWithFromBytesNull `hasNoType` ''Step
125inspect $ 'readWithFromBytesNull `hasNoType` ''Step
125−inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.SpliceState
126+inspect $ 'readWithFromBytesNull `hasNoType` ''MAS.SpliceState
126−inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
127+inspect $ 'readWithFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
127inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
128inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
128#endif
129#endif
129
130
@@ -170,7 +171,7 @@ writeReadWith inh devNull = IUF.fold fld unf (defaultChunkSize, inh)
170inspect $ hasNoTypeClasses 'writeReadWith
171inspect $ hasNoTypeClasses 'writeReadWith
171inspect $ 'writeReadWith `hasNoType` ''Step
172inspect $ 'writeReadWith `hasNoType` ''Step
172inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
173inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
173−inspect $ 'writeReadWith `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
174+inspect $ 'writeReadWith `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
174 -- FH.read/A.read
175 -- FH.read/A.read
175#endif
176#endif
176
177
@@ -187,7 +188,7 @@ writeRead inh devNull = IUF.fold fld unf inh
187inspect $ hasNoTypeClasses 'writeRead
188inspect $ hasNoTypeClasses 'writeRead
188inspect $ 'writeRead `hasNoType` ''Step
189inspect $ 'writeRead `hasNoType` ''Step
189inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
190inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
190−inspect $ 'writeRead `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
191+inspect $ 'writeRead `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
191 -- FH.read/A.read
192 -- FH.read/A.read
192#endif
193#endif
193
194
benchmark/Streamly/Benchmark/Prelude/Adaptive.hs+1−1
@@ -10,7 +10,7 @@
10import Control.Concurrent (threadDelay)
10import Control.Concurrent (threadDelay)
11import Control.Monad (when)
11import Control.Monad (when)
12import Control.Monad.IO.Class (liftIO)
12import Control.Monad.IO.Class (liftIO)
13−import Test.Tasty.Bench
13+import Gauge
14import Streamly.Prelude as S
14import Streamly.Prelude as S
15import System.Random (randomRIO)
15import System.Random (randomRIO)
16
16
benchmark/Streamly/Benchmark/Prelude/Ahead.hs+1−1
@@ -15,7 +15,7 @@ import qualified Streamly.Prelude as S
15import Streamly.Benchmark.Common
15import Streamly.Benchmark.Common
16import Streamly.Benchmark.Prelude
16import Streamly.Benchmark.Prelude
17
17
18−import Test.Tasty.Bench
18+import Gauge
19
19
20moduleName :: String
20moduleName :: String
21moduleName = "Prelude.Ahead"
21moduleName = "Prelude.Ahead"
benchmark/Streamly/Benchmark/Prelude/Async.hs+1−1
@@ -16,7 +16,7 @@ import qualified Streamly.Internal.Data.Stream.IsStream.Transform as Transform
16import Streamly.Benchmark.Common
16import Streamly.Benchmark.Common
17import Streamly.Benchmark.Prelude
17import Streamly.Benchmark.Prelude
18
18
19−import Test.Tasty.Bench
19+import Gauge
20
20
21moduleName :: String
21moduleName :: String
22moduleName = "Prelude.Async"
22moduleName = "Prelude.Async"
benchmark/Streamly/Benchmark/Prelude/Concurrent.hs+1−1
@@ -15,7 +15,7 @@ import Streamly.Prelude
15 , fromWAsync, parallel, fromParallel
15 , fromWAsync, parallel, fromParallel
16 )
16 )
17
17
18−import Test.Tasty.Bench
18+import Gauge
19import qualified Streamly.Prelude as S
19import qualified Streamly.Prelude as S
20
20
21-------------------------------------------------------------------------------
21-------------------------------------------------------------------------------
benchmark/Streamly/Benchmark/Prelude/Merge.hs+1−1
@@ -30,7 +30,7 @@ import qualified Streamly.Internal.Data.Stream.IsStream as Stream
30import Streamly.Benchmark.Common
30import Streamly.Benchmark.Common
31import Streamly.Benchmark.Prelude
31import Streamly.Benchmark.Prelude
32
32
33−import Test.Tasty.Bench
33+import Gauge
34
34
35#ifdef INSPECTION
35#ifdef INSPECTION
36import GHC.Types (SPEC(..))
36import GHC.Types (SPEC(..))
benchmark/Streamly/Benchmark/Prelude/Parallel.hs+1−1
@@ -22,7 +22,7 @@ import qualified Streamly.Internal.Data.Stream.IsStream as Internal
22import Streamly.Benchmark.Common
22import Streamly.Benchmark.Common
23import Streamly.Benchmark.Prelude
23import Streamly.Benchmark.Prelude
24
24
25−import Test.Tasty.Bench
25+import Gauge
26
26
27moduleName :: String
27moduleName :: String
28moduleName = "Prelude.Parallel"
28moduleName = "Prelude.Parallel"
benchmark/Streamly/Benchmark/Prelude/Rate.hs+1−1
@@ -14,7 +14,7 @@ import qualified Streamly.Prelude as S
14import Streamly.Benchmark.Common
14import Streamly.Benchmark.Common
15import Streamly.Benchmark.Prelude
15import Streamly.Benchmark.Prelude
16
16
17−import Test.Tasty.Bench
17+import Gauge
18
18
19moduleName :: String
19moduleName :: String
20moduleName = "Prelude.Rate"
20moduleName = "Prelude.Rate"
benchmark/Streamly/Benchmark/Prelude/WAsync.hs+1−1
@@ -15,7 +15,7 @@ import qualified Streamly.Prelude as S
15import Streamly.Benchmark.Common
15import Streamly.Benchmark.Common
16import Streamly.Benchmark.Prelude
16import Streamly.Benchmark.Prelude
17
17
18−import Test.Tasty.Bench
18+import Gauge
19
19
20moduleName :: String
20moduleName :: String
21moduleName = "Prelude.WAsync"
21moduleName = "Prelude.WAsync"
benchmark/Streamly/Benchmark/Prelude/WSerial.hs+1−1
@@ -29,7 +29,7 @@ import qualified Streamly.Internal.Data.Unfold as UF
29import Streamly.Benchmark.Common
29import Streamly.Benchmark.Common
30import Streamly.Benchmark.Prelude
30import Streamly.Benchmark.Prelude
31
31
32−import Test.Tasty.Bench
32+import Gauge
33
33
34#ifdef INSPECTION
34#ifdef INSPECTION
35import GHC.Types (SPEC(..))
35import GHC.Types (SPEC(..))
benchmark/Streamly/Benchmark/Prelude/ZipAsync.hs+1−1
@@ -15,7 +15,7 @@ import qualified Streamly.Prelude as S
15import Streamly.Benchmark.Common
15import Streamly.Benchmark.Common
16import Streamly.Benchmark.Prelude
16import Streamly.Benchmark.Prelude
17
17
18−import Test.Tasty.Bench
18+import Gauge
19
19
20moduleName :: String
20moduleName :: String
21moduleName = "Prelude.ZipAsync"
21moduleName = "Prelude.ZipAsync"
benchmark/Streamly/Benchmark/Prelude/ZipSerial.hs+1−1
@@ -29,7 +29,7 @@ import qualified Streamly.Prelude as S
29import Streamly.Benchmark.Common
29import Streamly.Benchmark.Common
30import Streamly.Benchmark.Prelude hiding (sourceUnfoldrM)
30import Streamly.Benchmark.Prelude hiding (sourceUnfoldrM)
31
31
32−import Test.Tasty.Bench
32+import Gauge
33
33
34#ifdef INSPECTION
34#ifdef INSPECTION
35import GHC.Types (SPEC(..))
35import GHC.Types (SPEC(..))
benchmark/Streamly/Benchmark/Unicode/Char.hs+1−1
@@ -16,7 +16,7 @@ import Control.DeepSeq (NFData(..))
16import Streamly.Internal.Data.Array (Array)
16import Streamly.Internal.Data.Array (Array)
17import System.FilePath (dropExtensions, takeFileName)
17import System.FilePath (dropExtensions, takeFileName)
18import System.FilePath.Posix ((</>))
18import System.FilePath.Posix ((</>))
19−import Test.Tasty.Bench (Benchmark, bench, bgroup, defaultMain, env, nfIO)
19+import Gauge.Main (Benchmark, bench, bgroup, defaultMain, env, nfIO)
20import Streamly.Internal.Unicode.Char
20import Streamly.Internal.Unicode.Char
21 ( NormalizationMode(NFC, NFD, NFKC, NFKD)
21 ( NormalizationMode(NFC, NFD, NFKC, NFKD)
22 , normalize
22 , normalize
benchmark/Streamly/Benchmark/Unicode/Parser.hs+1−1
@@ -31,7 +31,7 @@ import qualified Streamly.Data.Array as Array
31import qualified Streamly.Data.Stream as Stream
31import qualified Streamly.Data.Stream as Stream
32import qualified Streamly.Internal.Unicode.Parser as PRU
32import qualified Streamly.Internal.Unicode.Parser as PRU
33
33
34−import Test.Tasty.Bench hiding (env)
34+import Gauge hiding (env)
35import Streamly.Benchmark.Common
35import Streamly.Benchmark.Common
36
36
37runParser :: Int -> (Stream IO Char -> IO a) -> IO ()
37runParser :: Int -> (Stream IO Char -> IO a) -> IO ()
benchmark/Streamly/Benchmark/Unicode/Stream.hs+6−24
@@ -11,11 +11,6 @@
11{-# LANGUAGE CPP #-}
11{-# LANGUAGE CPP #-}
12{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE ScopedTypeVariables #-}
13
13
14−#undef FUSION_CHECK
15−#ifdef FUSION_CHECK
16−{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dsuppress-all #-}
17−#endif
18−
19#ifdef __HADDOCK_VERSION__
14#ifdef __HADDOCK_VERSION__
20#undef INSPECTION
15#undef INSPECTION
21#endif
16#endif
@@ -38,17 +33,16 @@ import qualified Streamly.Internal.FileSystem.Handle as Handle
38import qualified Streamly.Internal.Unicode.Array as UnicodeArr
33import qualified Streamly.Internal.Unicode.Array as UnicodeArr
39import qualified Streamly.Internal.Unicode.Stream as Unicode
34import qualified Streamly.Internal.Unicode.Stream as Unicode
40
35
41−import Test.Tasty.Bench hiding (env)
36+import Gauge hiding (env)
42import Streamly.Benchmark.Common
37import Streamly.Benchmark.Common
43import Streamly.Benchmark.Common.Handle
38import Streamly.Benchmark.Common.Handle
44
39
45#ifdef INSPECTION
40#ifdef INSPECTION
46−import Streamly.Internal.Data.MutByteArray (Unbox)
41+import Streamly.Internal.Data.Unbox (Unbox)
47import Streamly.Internal.Data.Stream (Step(..))
42import Streamly.Internal.Data.Stream (Step(..))
48−import qualified Streamly.Internal.Data.Array as Array
49−import qualified Streamly.Internal.Data.MutArray as MutArray
50import qualified Streamly.Internal.Data.Fold as Fold
43import qualified Streamly.Internal.Data.Fold as Fold
51import qualified Streamly.Internal.Data.Tuple.Strict as Strict
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
45+import qualified Streamly.Internal.Data.Array as Array
52
46
53import Test.Inspection
47import Test.Inspection
54#endif
48#endif
@@ -224,7 +218,7 @@ inspect $ 'copyStreamLatin1' `hasNoType` ''Step
224inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
218inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
225
219
226inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
220inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
227−inspect $ 'copyStreamLatin1' `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
221+inspect $ 'copyStreamLatin1' `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
228 -- Handle.read/Array.read
222 -- Handle.read/Array.read
229inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
223inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
230#endif
224#endif
@@ -245,7 +239,7 @@ inspect $ 'copyStreamLatin1 `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.m
245
239
246inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
240inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
247inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
241inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
248−inspect $ 'copyStreamLatin1 `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
242+inspect $ 'copyStreamLatin1 `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
249 -- Handle.read/Array.read
243 -- Handle.read/Array.read
250inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
244inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
251#endif
245#endif
@@ -286,8 +280,7 @@ _copyStreamUtf8'Fold :: Handle -> Handle -> IO ()
286_copyStreamUtf8'Fold inh outh =
280_copyStreamUtf8'Fold inh outh =
287 Stream.fold (Handle.write outh)
281 Stream.fold (Handle.write outh)
288 $ Unicode.encodeUtf8
282 $ Unicode.encodeUtf8
289− $ Stream.catRights
290− $ Stream.parseMany Unicode.writeCharUtf8'
283+ $ Stream.foldMany Unicode.writeCharUtf8'
291 $ Stream.unfold Handle.reader inh
284 $ Stream.unfold Handle.reader inh
292
285
293{-# NOINLINE _copyStreamUtf8Parser #-}
286{-# NOINLINE _copyStreamUtf8Parser #-}
@@ -324,7 +317,6 @@ o_1_space_decode_encode_read env =
324
317
325main :: IO ()
318main :: IO ()
326main = do
319main = do
327−#ifndef FUSION_CHECK
328 env <- mkHandleBenchEnv
320 env <- mkHandleBenchEnv
329 defaultMain (allBenchmarks env)
321 defaultMain (allBenchmarks env)
330
322
@@ -337,13 +329,3 @@ main = do
337 , o_1_space_decode_encode_read env
329 , o_1_space_decode_encode_read env
338 ]
330 ]
339 ]
331 ]
340−#else
341− -- Enable FUSION_CHECK macro at the beginning of the file
342− -- Enable one benchmark below, and run the benchmark
343− -- Check the .dump-simpl output
344− env <- mkHandleBenchEnv
345− let mkHandles (RefHandles {bigInH = inh, outputH = outh}) = Handles inh outh
346− (Handles inh outh) <- getHandles env mkHandles
347− copyStreamLatin1' inh outh
348− return ()
349−#endif
benchmark/Streamly/Benchmark/Unicode/Utf8.hs+1−1
@@ -13,7 +13,7 @@
13import Data.Char (chr)
13import Data.Char (chr)
14import Streamly.Internal.Unicode.Utf8 (Utf8)
14import Streamly.Internal.Unicode.Utf8 (Utf8)
15
15
16−import Test.Tasty.Bench hiding (env)
16+import Gauge hiding (env)
17import Streamly.Benchmark.Common
17import Streamly.Benchmark.Common
18
18
19import qualified Streamly.Internal.Unicode.Utf8 as Utf8
19import qualified Streamly.Internal.Unicode.Utf8 as Utf8
benchmark/bench-runner/Main.hs+4−32
@@ -16,11 +16,9 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
16 benchName = drop 4 benchName0
16 benchName = drop 4 benchName0
17
17
18 general
18 general
19− -- GHC-9.6 requires 32M heap vs 16M for GHC-9.4
20− | "o-1-sp" `isInfixOf` benchName = "-K36K -M32M"
19+ | "o-1-sp" `isInfixOf` benchName = "-K36K -M16M"
21 | "o-n-h" `isInfixOf` benchName = "-K36K -M32M"
20 | "o-n-h" `isInfixOf` benchName = "-K36K -M32M"
22− -- GHC-9.6 requires 32M heap vs 16M for GHC-9.4
23− | "o-n-st" `isInfixOf` benchName = "-K1M -M32M"
21+ | "o-n-st" `isInfixOf` benchName = "-K1M -M16M"
24 | "o-n-sp" `isInfixOf` benchName = "-K1M -M32M"
22 | "o-n-sp" `isInfixOf` benchName = "-K1M -M32M"
25 | otherwise = ""
23 | otherwise = ""
26
24
@@ -29,17 +27,6 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
29 | otherwise = ""
27 | otherwise = ""
30
28
31 benchSpecific
29 benchSpecific
32− -- GHC-9.6 requires 64M, earlier it was 16M
33− | "Data.Fold/o-n-heap.key-value.toHashMapIO (max buckets) sum" == benchName =
34− "-M64M"
35−
36− -- This is required only for the --long case because we allocate all
37− -- the arrays upfront. depends on the size of the stream.
38− | "Data.Parser/o-1-space" `isPrefixOf` benchName =
39− "-M128M"
40−
41− -----------------------------------------------------------------------
42−
43 | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = "-M256M"
30 | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = "-M256M"
44 | "Prelude.Parallel/o-n-heap.monad-outer-product."
31 | "Prelude.Parallel/o-n-heap.monad-outer-product."
45 `isPrefixOf` benchName = "-M256M"
32 `isPrefixOf` benchName = "-M256M"
@@ -70,12 +57,6 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
70 -- GHC 9.4.4 requires 4M
57 -- GHC 9.4.4 requires 4M
71 | "Data.Stream.StreamDK/o-n-space.traversable."
58 | "Data.Stream.StreamDK/o-n-space.traversable."
72 `isPrefixOf` benchName = "-K4M"
59 `isPrefixOf` benchName = "-K4M"
73− -- GHC-9.6 requires 64M, earlier it was 32M
74− | "Data.Stream.StreamDK/o-n-heap.buffered.readsPrec pure streams" == benchName =
75− "-M64M"
76− -- GHC-9.6 requires 64M, earlier it was 32M
77− | "Data.Stream.StreamDK/o-n-heap.buffered.showPrec Haskell lists" == benchName =
78− "-M64M"
79
60
80 -----------------------------------------------------------------------
61 -----------------------------------------------------------------------
81
62
@@ -93,13 +74,6 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
93 | "Data.Stream/o-n-space.iterated."
74 | "Data.Stream/o-n-space.iterated."
94 `isPrefixOf` benchName = "-K4M"
75 `isPrefixOf` benchName = "-K4M"
95
76
96− -- GHC-9.6 requires 64M, earlier it was 32M
97− | "Data.Stream/o-n-heap.buffered.showPrec Haskell lists" == benchName =
98− "-M64M"
99− -- GHC-9.6 requires 64M, earlier it was 32M
100− | "Data.Stream/o-n-heap.buffered.readsPrec pure streams" == benchName =
101− "-M64M"
102−
103 | "Data.Stream.ConcurrentEager/o-n-heap.monad-outer-product.toNullAp"
77 | "Data.Stream.ConcurrentEager/o-n-heap.monad-outer-product.toNullAp"
104 `isPrefixOf` benchName = "-M1024M"
78 `isPrefixOf` benchName = "-M1024M"
105 | "Data.Stream.ConcurrentEager/o-1-space."
79 | "Data.Stream.ConcurrentEager/o-1-space."
@@ -112,12 +86,10 @@ rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
112
86
113 | "Data.Array" `isPrefixOf` benchName
87 | "Data.Array" `isPrefixOf` benchName
114 && "/o-1-space.generation.read" `isSuffixOf` benchName = "-M32M"
88 && "/o-1-space.generation.read" `isSuffixOf` benchName = "-M32M"
115− -- XXX GHC 9.6 onwards needs 64M, earlier it was 32M
116 | "Data.Array" `isPrefixOf` benchName
89 | "Data.Array" `isPrefixOf` benchName
117− && "/o-1-space.generation.show" `isSuffixOf` benchName = "-M64M"
90+ && "/o-1-space.generation.show" `isSuffixOf` benchName = "-M32M"
118− -- XXX GHC 9.6 onwards needs 64M, earlier it was 32M
119 | "Data.Array.Generic/o-1-space.transformationX4.map"
91 | "Data.Array.Generic/o-1-space.transformationX4.map"
120− `isPrefixOf` benchName = "-M64M"
92+ `isPrefixOf` benchName = "-M32M"
121
93
122 -- XXX For --long option, need to check why so much heap is required.
94 -- XXX For --long option, need to check why so much heap is required.
123 -- Note, if we remove the chunked stream module we need to keep the
95 -- Note, if we remove the chunked stream module we need to keep the
benchmark/lib/Streamly/Benchmark/Common.hs+1−1
@@ -56,7 +56,7 @@ import System.Random (randomRIO)
56import qualified Streamly.Internal.Data.Fold as Fold
56import qualified Streamly.Internal.Data.Fold as Fold
57import qualified Streamly.Internal.Data.Stream as S
57import qualified Streamly.Internal.Data.Stream as S
58
58
59−import Test.Tasty.Bench
59+import Gauge
60
60
61-------------------------------------------------------------------------------
61-------------------------------------------------------------------------------
62-- Benchmark Prefixes
62-- Benchmark Prefixes
benchmark/lib/Streamly/Benchmark/Common/Handle.hs+1−3
@@ -30,8 +30,6 @@ module Streamly.Benchmark.Common.Handle
30 , isSpace
30 , isSpace
31 , isSp
31 , isSp
32 , mkHandleBenchEnv
32 , mkHandleBenchEnv
33− , Handles(..)
34− , getHandles
35 )
33 )
36where
34where
37
35
@@ -48,7 +46,7 @@ import System.Process (callCommand)
48
46
49import Data.IORef
47import Data.IORef
50import Prelude hiding (last, length)
48import Prelude hiding (last, length)
51−import Test.Tasty.Bench hiding (env)
49+import Gauge hiding (env)
52
50
53
51
54scratchDir :: String
52scratchDir :: String
benchmark/lib/Streamly/Benchmark/Prelude.hs+1−1
@@ -82,7 +82,7 @@ import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
82import qualified Streamly.Internal.Data.Pipe as Pipe
82import qualified Streamly.Internal.Data.Pipe as Pipe
83import qualified Streamly.Internal.Data.Stream.Serial as Serial
83import qualified Streamly.Internal.Data.Stream.Serial as Serial
84
84
85−import Test.Tasty.Bench
85+import Gauge
86import Streamly.Internal.Data.Time.Units
86import Streamly.Internal.Data.Time.Units
87
87
88-- Common polymorphic stream APIs used across multiple stream modules
88-- Common polymorphic stream APIs used across multiple stream modules
benchmark/streamly-benchmarks.cabal+26−16
@@ -54,6 +54,11 @@ flag opt
54 manual: True
54 manual: True
55 default: True
55 default: True
56
56
57+flag use-gauge
58+ description: Use gauge instead of tasty-bench for benchmarking
59+ manual: True
60+ default: False
61+
57flag use-streamly-core
62flag use-streamly-core
58 description: Benchmark only core package
63 description: Benchmark only core package
59 manual: True
64 manual: True
@@ -140,10 +145,6 @@ common compile-options
140 -Wno-missing-kind-signatures
145 -Wno-missing-kind-signatures
141 -Wno-operator-whitespace
146 -Wno-operator-whitespace
142
147
143− if impl(ghc >= 9.8)
144− ghc-options:
145− -Wno-missing-role-annotations
146−
147 if flag(has-llvm)
148 if flag(has-llvm)
148 ghc-options: -fllvm
149 ghc-options: -fllvm
149
150
@@ -175,34 +176,43 @@ common bench-depends
175 -- Core libraries shipped with ghc, the min and max
176 -- Core libraries shipped with ghc, the min and max
176 -- constraints of these libraries should match with
177 -- constraints of these libraries should match with
177 -- the GHC versions we support
178 -- the GHC versions we support
178− base >= 4.9 && < 4.20
179+ base >= 4.9 && < 4.19
179− , deepseq >= 1.4.1 && < 1.6
180+ , deepseq >= 1.4.1 && < 1.5
180 , mtl >= 2.2 && < 2.3.2
181 , mtl >= 2.2 && < 2.3.2
181
182
182 -- other libraries
183 -- other libraries
183− , exceptions >= 0.8 && < 0.11
184 , random >= 1.0 && < 2.0
184 , random >= 1.0 && < 2.0
185 , transformers >= 0.4 && < 0.7
185 , transformers >= 0.4 && < 0.7
186− , containers >= 0.5 && < 0.8
186+ , containers >= 0.5 && < 0.7
187 , hashable >= 1.3 && < 1.5
187 , hashable >= 1.3 && < 1.5
188 , unordered-containers >= 0.2 && < 0.3
188 , unordered-containers >= 0.2 && < 0.3
189 , process >= 1.4 && < 1.7
189 , process >= 1.4 && < 1.7
190 , directory >= 1.2.2 && < 1.4
190 , directory >= 1.2.2 && < 1.4
191− , filepath >= 1.4.1 && < 1.6
191+ , filepath >= 1.4.1 && < 1.5
192− , ghc-prim >= 0.4 && < 0.12
192+ , ghc-prim >= 0.4 && < 0.11
193− , tasty-bench >= 0.3 && < 0.4
194− , tasty >= 1.4.1 && < 1.6
195− , streamly-core
196
193
197− if !flag(use-streamly-core)
194+ if flag(use-streamly-core)
195+ build-depends: streamly-core
196+ else
198 build-depends: streamly
197 build-depends: streamly
198+ , streamly-core
199+
200+ if flag(use-gauge)
201+ build-depends: gauge >= 0.2.4 && < 0.3
202+ else
203+ build-depends: tasty-bench >= 0.3 && < 0.4
204+ , tasty >= 1.4.1 && < 1.5
205+ mixins: tasty-bench
206+ (Test.Tasty.Bench as Gauge
207+ , Test.Tasty.Bench as Gauge.Main
208+ )
199
209
200 if flag(fusion-plugin) && !impl(ghcjs) && !impl(ghc < 8.6)
210 if flag(fusion-plugin) && !impl(ghcjs) && !impl(ghc < 8.6)
201 build-depends:
211 build-depends:
202 fusion-plugin >= 0.2 && < 0.3
212 fusion-plugin >= 0.2 && < 0.3
203 if flag(inspection)
213 if flag(inspection)
204− build-depends: template-haskell >= 2.14 && < 2.22
214+ build-depends: template-haskell >= 2.14 && < 2.21
205− , inspection-testing >= 0.4 && < 0.6
215+ , inspection-testing >= 0.4 && < 0.5
206 -- Array uses a Storable constraint in dev build making several inspection
216 -- Array uses a Storable constraint in dev build making several inspection
207 -- tests fail
217 -- tests fail
208 if flag(dev) && flag(inspection)
218 if flag(dev) && flag(inspection)
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.1.
3+# Generated by GNU Autoconf 2.71 for streamly 0.10.0.
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.1'
613+PACKAGE_VERSION='0.10.0'
614−PACKAGE_STRING='streamly 0.10.1'
614+PACKAGE_STRING='streamly 0.10.0'
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.1 to adapt to many kinds of systems.
1227+\`configure' configures streamly 0.10.0 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.1:";;
1289+ short | recursive ) echo "Configuration of streamly 0.10.0:";;
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.1
1375+streamly configure 0.10.0
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.1, which was
1503+It was created by streamly $as_me 0.10.0, 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.1, which was
3803+This file was extended by streamly $as_me 0.10.0, 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.1
3859+streamly config.status 0.10.0
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.1], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
6+AC_INIT([streamly], [0.10.0], [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.2.
3+# Generated by GNU Autoconf 2.71 for streamly-core 0.2.0.
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.2'
613+PACKAGE_VERSION='0.2.0'
614−PACKAGE_STRING='streamly-core 0.2.2'
614+PACKAGE_STRING='streamly-core 0.2.0'
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.2 to adapt to many kinds of systems.
1259+\`configure' configures streamly-core 0.2.0 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.2:";;
1321+ short | recursive ) echo "Configuration of streamly-core 0.2.0:";;
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.2
1407+streamly-core configure 0.2.0
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.2, which was
1625+It was created by streamly-core $as_me 0.2.0, 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.2, which was
3835+This file was extended by streamly-core $as_me 0.2.0, 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.2
3891+streamly-core config.status 0.2.0
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.2], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
6+AC_INIT([streamly-core], [0.2.0], [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.1.0-0.2.0.txtdeleted−1471
@@ -1,1471 +0,0 @@
1−---------------------------------
2−API Annotations
3−---------------------------------
4−
5−[A] : Added
6−[R] : Removed
7−[C] : Changed
8−[O] : Old definition
9−[N] : New definition
10−[D] : Deprecated
11−
12−---------------------------------
13−API diff
14−---------------------------------
15−
16−[C] Streamly.Unicode.Parser
17− [A] double :: Monad m => Parser Char m Double
18−[C] Streamly.FileSystem.Handle
19− [A] readWith :: MonadIO m => Int -> Handle -> Stream m Word8
20− [A] readChunksWith :: MonadIO m => Int -> Handle -> Stream m (Array Word8)
21−[C] Streamly.FileSystem.Dir
22− [C] readEither
23− [O] readEither :: MonadIO m => FilePath -> Stream m (Either FilePath FilePath)
24− [N] readEither :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Either FilePath FilePath)
25− [C] read
26− [O] read :: MonadIO m => FilePath -> Stream m FilePath
27− [N] read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
28−[C] Streamly.Data.Unfold
29− [A] class Enum a => Enumerable a
30− [A] second :: b -> Unfold m (a, b) c -> Unfold m a c
31− [A] first :: a -> Unfold m (a, b) c -> Unfold m b c
32− [A] enumerateFromTo :: (Enumerable a, Monad m) => Unfold m (a, a) a
33− [A] enumerateFromThenTo :: (Enumerable a, Monad m) => Unfold m (a, a, a) a
34− [A] enumerateFromThen :: (Enumerable a, Monad m) => Unfold m (a, a) a
35− [A] enumerateFrom :: (Enumerable a, Monad m) => Unfold m a a
36−[C] Streamly.Data.StreamK
37− [C] parseChunks
38− [O] parseChunks :: (Monad m, Unbox a) => ParserK a m b -> StreamK m (Array a) -> m (Either ParseError b)
39− [N] parseChunks :: (Monad m, Unbox a) => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b)
40− [C] parseBreakChunks
41− [O] parseBreakChunks :: (Monad m, Unbox a) => ParserK a m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
42− [N] parseBreakChunks :: (Monad m, Unbox a) => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
43− [A] parseBreak :: forall m a b. Monad m => ParserK a m b -> StreamK m a -> m (Either ParseError b, StreamK m a)
44− [A] parse :: Monad m => ParserK a m b -> StreamK m a -> m (Either ParseError b)
45− [A] handle :: (MonadCatch m, Exception e) => (e -> m (StreamK m a)) -> StreamK m a -> StreamK m a
46− [A] bracketIO :: (MonadIO m, MonadCatch m) => IO b -> (b -> IO c) -> (b -> StreamK m a) -> StreamK m a
47−[C] Streamly.Data.Stream
48− [A] wordsBy :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
49− [A] splitOn :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
50− [C] handle
51− [O] handle :: (MonadCatch m, Exception e) => (e -> Stream m a) -> Stream m a -> Stream m a
52− [N] handle :: (MonadCatch m, Exception e) => (e -> m (Stream m a)) -> Stream m a -> Stream m a
53− [A] groupsOf :: Monad m => Int -> Fold m a b -> Stream m a -> Stream m b
54−[C] Streamly.Data.ParserK
55− [D] fromParser :: (MonadIO m, Unbox a) => Parser a m b -> ParserK (Array a) m b
56− [D] fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
57− [A] adaptCG :: Monad m => Parser a m b -> ParserK (Array a) m b
58− [A] adaptC :: (Monad m, Unbox a) => Parser a m b -> ParserK (Array a) m b
59− [A] adapt :: Monad m => Parser a m b -> ParserK a m b
60−[C] Streamly.Data.Parser
61− [A] groupByRollingEither :: Monad m => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
62− [A] groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
63−[A] Streamly.Data.MutByteArray
64− [A] class Unbox a
65− [A] class Serialize a
66− [A] SerializeConfig
67− [A] MutByteArray
68− [A] unpin :: MutByteArray -> IO MutByteArray
69− [A] sizeOf :: (Unbox a, SizeOfRep (Rep a)) => Proxy a -> Int
70− [A] serializeAt :: Serialize a => Int -> MutByteArray -> a -> IO Int
71− [A] pokeAt :: (Unbox a, Generic a, PokeRep (Rep a)) => Int -> MutByteArray -> a -> IO ()
72− [A] pinnedNew :: Int -> IO MutByteArray
73− [A] pin :: MutByteArray -> IO MutByteArray
74− [A] peekAt :: (Unbox a, Generic a, PeekRep (Rep a)) => Int -> MutByteArray -> IO a
75− [A] new :: Int -> IO MutByteArray
76− [A] isPinned :: MutByteArray -> Bool
77− [A] inlineSerializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
78− [A] inlineDeserializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
79− [A] inlineAddSizeTo :: Maybe Inline -> SerializeConfig -> SerializeConfig
80− [A] deserializeAt :: Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
81− [A] deriveUnbox :: Q [Dec] -> Q [Dec]
82− [A] deriveSerializeWith :: (SerializeConfig -> SerializeConfig) -> Q [Dec] -> Q [Dec]
83− [A] deriveSerialize :: Q [Dec] -> Q [Dec]
84− [A] addSizeTo :: Serialize a => Int -> a -> Int
85−[C] Streamly.Data.MutArray.Generic
86− [A] write :: MonadIO m => Fold m a (MutArray a)
87− [A] readRev :: MonadIO m => MutArray a -> Stream m a
88− [A] read :: MonadIO m => MutArray a -> Stream m a
89− [A] putIndexUnsafe :: forall m a. MonadIO m => Int -> MutArray a -> a -> m ()
90− [A] modifyIndexUnsafe :: MonadIO m => Int -> MutArray a -> (a -> (a, b)) -> m b
91− [A] length :: MutArray a -> Int
92− [A] getIndexUnsafe :: MonadIO m => Int -> MutArray a -> m a
93− [C] getIndex
94− [O] getIndex :: MonadIO m => Int -> MutArray a -> m a
95− [N] getIndex :: MonadIO m => Int -> MutArray a -> m (Maybe a)
96− [A] fromListN :: MonadIO m => Int -> [a] -> m (MutArray a)
97− [A] fromList :: MonadIO m => [a] -> m (MutArray a)
98−[C] Streamly.Data.MutArray
99− [A] unpin :: MutArray a -> IO (MutArray a)
100− [A] readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> Stream m a
101− [A] read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> Stream m a
102− [A] putIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m ()
103− [D] pokeByteIndex :: Unbox a => Int -> MutByteArray -> a -> IO ()
104− [A] pokeAt :: (Unbox a, Generic a, PokeRep (Rep a)) => Int -> MutByteArray -> a -> IO ()
105− [A] pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
106− [A] pin :: MutArray a -> IO (MutArray a)
107− [D] peekByteIndex :: Unbox a => Int -> MutByteArray -> IO a
108− [A] peekAt :: (Unbox a, Generic a, PeekRep (Rep a)) => Int -> MutByteArray -> IO a
109− [D] newPinned :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
110− [A] modifyIndexUnsafe :: forall m a b. (MonadIO m, Unbox a) => Int -> MutArray a -> (a -> (a, b)) -> m b
111− [A] modifyIndex :: forall m a b. (MonadIO m, Unbox a) => Int -> MutArray a -> (a -> (a, b)) -> m b
112− [A] modify :: forall m a. (MonadIO m, Unbox a) => MutArray a -> (a -> a) -> m ()
113− [A] isPinned :: MutArray a -> Bool
114− [A] getIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
115− [C] getIndex
116− [O] getIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
117− [N] getIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (Maybe a)
118−[C] Streamly.Data.Array.Generic
119− [A] toList :: Array a -> [a]
120− [A] getIndex :: Int -> Array a -> Maybe a
121−[C] Streamly.Data.Array
122− [A] unpin :: Array a -> IO (Array a)
123− [D] pokeByteIndex :: Unbox a => Int -> MutByteArray -> a -> IO ()
124− [A] pokeAt :: (Unbox a, Generic a, PokeRep (Rep a)) => Int -> MutByteArray -> a -> IO ()
125− [A] pin :: Array a -> IO (Array a)
126− [D] peekByteIndex :: Unbox a => Int -> MutByteArray -> IO a
127− [A] peekAt :: (Unbox a, Generic a, PeekRep (Rep a)) => Int -> MutByteArray -> IO a
128− [A] isPinned :: Array a -> Bool
129−[C] Streamly.Console.Stdio
130−
131−---------------------------------
132−Internal API diff
133−---------------------------------
134−
135−[C] Streamly.Internal.Unicode.Stream
136− [C] writeCharUtf8'
137− [O] writeCharUtf8' :: Monad m => Fold m Word8 Char
138− [N] writeCharUtf8' :: Monad m => Parser Word8 m Char
139−[C] Streamly.Internal.Unicode.Parser
140− [A] number :: Monad m => Parser Char m (Integer, Int)
141− [A] mkDouble :: Integer -> Int -> Double
142− [A] doubleParser :: Monad m => Parser Char m (Int, Int)
143− [C] double
144− [O] double :: Parser Char m Double
145− [N] double :: Monad m => Parser Char m Double
146−[R] Streamly.Internal.Serialize.ToBytes
147−[R] Streamly.Internal.Serialize.FromBytes
148−[C] Streamly.Internal.FileSystem.File
149− [A] writeAppendWith :: (MonadIO m, MonadCatch m) => Int -> FilePath -> Stream m Word8 -> m ()
150− [A] writeAppendChunks :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Array a) -> m ()
151− [A] writeAppendArray :: FilePath -> Array a -> IO ()
152− [A] writeAppend :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8 -> m ()
153− [R] appendWith :: (MonadIO m, MonadCatch m) => Int -> FilePath -> Stream m Word8 -> m ()
154− [R] appendChunks :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Array a) -> m ()
155− [R] appendArray :: FilePath -> Array a -> IO ()
156− [R] append :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8 -> m ()
157−[C] Streamly.Internal.FileSystem.Dir
158− [C] reader
159− [O] reader :: MonadIO m => Unfold m FilePath FilePath
160− [N] reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath FilePath
161− [C] readFiles
162− [O] readFiles :: MonadIO m => FilePath -> Stream m FilePath
163− [N] readFiles :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
164− [C] readEitherPaths
165− [O] readEitherPaths :: MonadIO m => FilePath -> Stream m (Either FilePath FilePath)
166− [N] readEitherPaths :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Either FilePath FilePath)
167− [C] readEither
168− [O] readEither :: MonadIO m => FilePath -> Stream m (Either FilePath FilePath)
169− [N] readEither :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Either FilePath FilePath)
170− [C] readDirs
171− [O] readDirs :: MonadIO m => FilePath -> Stream m FilePath
172− [N] readDirs :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
173− [C] read
174− [O] read :: MonadIO m => FilePath -> Stream m FilePath
175− [N] read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m FilePath
176− [C] fileReader
177− [O] fileReader :: MonadIO m => Unfold m FilePath FilePath
178− [N] fileReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath FilePath
179− [C] eitherReaderPaths
180− [O] eitherReaderPaths :: MonadIO m => Unfold m FilePath (Either FilePath FilePath)
181− [N] eitherReaderPaths :: (MonadIO m, MonadCatch m) => Unfold m FilePath (Either FilePath FilePath)
182− [C] eitherReader
183− [O] eitherReader :: MonadIO m => Unfold m FilePath (Either FilePath FilePath)
184− [N] eitherReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath (Either FilePath FilePath)
185− [C] dirReader
186− [O] dirReader :: MonadIO m => Unfold m FilePath FilePath
187− [N] dirReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath FilePath
188−[R] Streamly.Internal.Data.Unfold.Type
189−[R] Streamly.Internal.Data.Unfold.Enumeration
190−[C] Streamly.Internal.Data.Unfold
191− [C] Unfold
192− [A] Unfold :: (s -> m (Step s b)) -> (a -> m s) -> Unfold m a b
193− [A] takeWhileMWithInput :: Monad m => (a -> b -> m Bool) -> Unfold m a b -> Unfold m a b
194− [A] manyInterleave :: Monad m => Unfold m a b -> Unfold m c a -> Unfold m c b
195− [A] enumerateFromStepIntegral :: (Monad m, Integral a) => Unfold m (a, a) a
196− [A] crossApplySnd :: Unfold m a b -> Unfold m a c -> Unfold m a c
197− [A] crossApplyFst :: Unfold m a b -> Unfold m a c -> Unfold m a b
198− [A] concatMap :: Monad m => (b -> Unfold m a c) -> Unfold m a b -> Unfold m a c
199−[R] Streamly.Internal.Data.Unboxed
200−[C] Streamly.Internal.Data.Time.Units
201− [R] Streamly.Internal.Data.Unboxed.Unbox
202− [A] Streamly.Internal.Data.Unbox.Unbox
203− [A] instance Streamly.Internal.Data.Unbox.Unbox Streamly.Internal.Data.Time.Units.NanoSecond64
204− [A] instance Streamly.Internal.Data.Unbox.Unbox Streamly.Internal.Data.Time.Units.MilliSecond64
205− [A] instance Streamly.Internal.Data.Unbox.Unbox Streamly.Internal.Data.Time.Units.MicroSecond64
206−[R] Streamly.Internal.Data.Time.Clock.Type
207−[A] Streamly.Internal.Data.StreamK
208− [A] CrossStreamK
209− [A] (FixityR,6)
210− [A] (FixityR,6)
211− [A] (FixityR,6)
212− [A] (FixityR,5)
213− [A] (FixityR,5)
214− [A] (FixityR,6)
215− [A] (FixityR,5)
216− [A] StreamK
217− [A] MkStream :: (forall r. State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> m r) -> StreamK m a
218− [A] zipWithM :: Monad m => (a -> b -> m c) -> StreamK m a -> StreamK m b -> StreamK m c
219− [A] zipWith :: Monad m => (a -> b -> c) -> StreamK m a -> StreamK m b -> StreamK m c
220− [A] unfoldrMWith :: Monad m => (m a -> StreamK m a -> StreamK m a) -> (b -> m (Maybe (a, b))) -> b -> StreamK m a
221− [A] unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> StreamK m a
222− [A] unfoldr :: (b -> Maybe (a, b)) -> b -> StreamK m a
223− [A] uncons :: Applicative m => StreamK m a -> m (Maybe (a, StreamK m a))
224− [A] unShare :: StreamK m a -> StreamK m a
225− [A] unCross :: CrossStreamK m a -> StreamK m a
226− [A] toStream :: Applicative m => StreamK m a -> Stream m a
227− [A] toList :: Monad m => StreamK m a -> m [a]
228− [A] the :: (Eq a, Monad m) => StreamK m a -> m (Maybe a)
229− [A] takeWhile :: (a -> Bool) -> StreamK m a -> StreamK m a
230− [A] take :: Int -> StreamK m a -> StreamK m a
231− [A] tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
232− [A] sortBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> StreamK m a
233− [A] sequence :: Monad m => StreamK m (m a) -> StreamK m a
234− [A] scanlx' :: (x -> a -> x) -> x -> (x -> b) -> StreamK m a -> StreamK m b
235− [A] scanl' :: (b -> a -> b) -> b -> StreamK m a -> StreamK m b
236− [A] reverse :: StreamK m a -> StreamK m a
237− [A] replicateMWith :: (m a -> StreamK m a -> StreamK m a) -> Int -> m a -> StreamK m a
238− [A] replicateM :: Monad m => Int -> m a -> StreamK m a
239− [A] replicate :: Int -> a -> StreamK m a
240− [A] repeatMWith :: (m a -> t m a -> t m a) -> m a -> t m a
241− [A] repeatM :: Monad m => m a -> StreamK m a
242− [A] repeat :: a -> StreamK m a
243− [A] parseDBreak :: Monad m => Parser a m b -> StreamK m a -> m (Either ParseError b, StreamK m a)
244− [A] parseD :: Monad m => Parser a m b -> StreamK m a -> m (Either ParseError b)
245− [A] parseChunksGeneric :: Monad m => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b)
246− [A] parseChunks :: (Monad m, Unbox a) => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b)
247− [A] parseBreakChunksGeneric :: forall m a b. Monad m => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
248− [A] parseBreakChunks :: (Monad m, Unbox a) => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
249− [A] parseBreak :: forall m a b. Monad m => ParserK a m b -> StreamK m a -> m (Either ParseError b, StreamK m a)
250− [A] parse :: Monad m => ParserK a m b -> StreamK m a -> m (Either ParseError b)
251− [A] null :: Monad m => StreamK m a -> m Bool
252− [A] notElem :: (Monad m, Eq a) => a -> StreamK m a -> m Bool
253− [A] nilM :: Applicative m => m b -> StreamK m a
254− [A] nil :: StreamK m a
255− [A] mkStream :: (forall r. State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> m r) -> StreamK m a
256− [A] mkCross :: StreamK m a -> CrossStreamK m a
257− [A] minimumBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> m (Maybe a)
258− [A] minimum :: (Monad m, Ord a) => StreamK m a -> m (Maybe a)
259− [A] mfix :: Monad m => (m a -> StreamK m a) -> StreamK m a
260− [A] mergeMapWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> (a -> StreamK m b) -> StreamK m a -> StreamK m b
261− [A] mergeIterateWith :: (StreamK m a -> StreamK m a -> StreamK m a) -> (a -> StreamK m a) -> StreamK m a -> StreamK m a
262− [A] mergeByM :: Monad m => (a -> a -> m Ordering) -> StreamK m a -> StreamK m a -> StreamK m a
263− [A] mergeBy :: (a -> a -> Ordering) -> StreamK m a -> StreamK m a -> StreamK m a
264− [A] maximumBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> m (Maybe a)
265− [A] maximum :: (Monad m, Ord a) => StreamK m a -> m (Maybe a)
266− [A] mapMaybe :: (a -> Maybe b) -> StreamK m a -> StreamK m b
267− [A] mapM_ :: Monad m => (a -> m b) -> StreamK m a -> m ()
268− [A] mapMWith :: (m b -> StreamK m b -> StreamK m b) -> (a -> m b) -> StreamK m a -> StreamK m b
269− [A] mapMSerial :: Monad m => (a -> m b) -> StreamK m a -> StreamK m b
270− [A] mapM :: Monad m => (a -> m b) -> StreamK m a -> StreamK m b
271− [A] map :: (a -> b) -> StreamK m a -> StreamK m b
272− [A] lookup :: (Monad m, Eq a) => a -> StreamK m (a, b) -> m (Maybe b)
273− [A] liftInner :: (Monad m, MonadTrans t, Monad (t m)) => StreamK m a -> StreamK (t m) a
274− [A] last :: Monad m => StreamK m a -> m (Maybe a)
275− [A] iterateMWith :: Monad m => (m a -> StreamK m a -> StreamK m a) -> (a -> m a) -> m a -> StreamK m a
276− [A] iterateM :: Monad m => (a -> m a) -> m a -> StreamK m a
277− [A] iterate :: (a -> a) -> a -> StreamK m a
278− [A] intersperseM :: Monad m => m a -> StreamK m a -> StreamK m a
279− [A] intersperse :: Monad m => a -> StreamK m a -> StreamK m a
280− [A] interleaveMin :: StreamK m a -> StreamK m a -> StreamK m a
281− [A] interleaveFst :: StreamK m a -> StreamK m a -> StreamK m a
282− [A] interleave :: StreamK m a -> StreamK m a -> StreamK m a
283− [A] insertBy :: (a -> a -> Ordering) -> a -> StreamK m a -> StreamK m a
284− [A] init :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
285− [A] hoist :: (Monad m, Monad n) => (forall x. m x -> n x) -> StreamK m a -> StreamK n a
286− [A] head :: Monad m => StreamK m a -> m (Maybe a)
287− [A] handle :: (MonadCatch m, Exception e) => (e -> m (StreamK m a)) -> StreamK m a -> StreamK m a
288− [A] fromYieldK :: YieldK m a -> StreamK m a
289− [A] fromStream :: Monad m => Stream m a -> StreamK m a
290− [A] fromStopK :: StopK m -> StreamK m a
291− [A] fromPure :: a -> StreamK m a
292− [A] fromList :: [a] -> StreamK m a
293− [A] fromIndicesMWith :: (m a -> StreamK m a -> StreamK m a) -> (Int -> m a) -> StreamK m a
294− [A] fromIndicesM :: Monad m => (Int -> m a) -> StreamK m a
295− [A] fromIndices :: (Int -> a) -> StreamK m a
296− [A] fromFoldableM :: (Foldable f, Monad m) => f (m a) -> StreamK m a
297− [A] fromFoldable :: Foldable f => f a -> StreamK m a
298− [A] fromEffect :: Monad m => m a -> StreamK m a
299− [A] foldrT :: (Monad m, Monad (s m), MonadTrans s) => (a -> s m b -> s m b) -> s m b -> StreamK m a -> s m b
300− [A] foldrSShared :: (a -> StreamK m b -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b
301− [A] foldrSM :: Monad m => (m a -> StreamK m b -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b
302− [A] foldrS :: (a -> StreamK m b -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b
303− [A] foldrM :: (a -> m b -> m b) -> m b -> StreamK m a -> m b
304− [A] foldr1 :: Monad m => (a -> a -> a) -> StreamK m a -> m (Maybe a)
305− [A] foldr :: Monad m => (a -> b -> b) -> b -> StreamK m a -> m b
306− [A] foldlx' :: forall m a b x. Monad m => (x -> a -> x) -> x -> (x -> b) -> StreamK m a -> m b
307− [A] foldlT :: (Monad m, Monad (s m), MonadTrans s) => (s m b -> a -> s m b) -> s m b -> StreamK m a -> s m b
308− [A] foldlS :: (StreamK m b -> a -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b
309− [A] foldlMx' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> StreamK m a -> m b
310− [A] foldlM' :: Monad m => (b -> a -> m b) -> m b -> StreamK m a -> m b
311− [A] foldl' :: Monad m => (b -> a -> b) -> b -> StreamK m a -> m b
312− [A] foldStreamShared :: State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> StreamK m a -> m r
313− [A] foldStream :: State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> StreamK m a -> m r
314− [A] foldEither :: Monad m => Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a))
315− [A] foldConcat :: Monad m => Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
316− [A] foldBreak :: Monad m => Fold m a b -> StreamK m a -> m (b, StreamK m a)
317− [A] fold :: Monad m => Fold m a b -> StreamK m a -> m b
318− [A] findM :: Monad m => (a -> m Bool) -> StreamK m a -> m (Maybe a)
319− [A] findIndices :: (a -> Bool) -> StreamK m a -> StreamK m Int
320− [A] find :: Monad m => (a -> Bool) -> StreamK m a -> m (Maybe a)
321− [A] filter :: (a -> Bool) -> StreamK m a -> StreamK m a
322− [A] evalStateT :: Monad m => m s -> StreamK (StateT s m) a -> StreamK m a
323− [A] elem :: (Monad m, Eq a) => a -> StreamK m a -> m Bool
324− [A] dropWhile :: (a -> Bool) -> StreamK m a -> StreamK m a
325− [A] drop :: Int -> StreamK m a -> StreamK m a
326− [A] drain :: Monad m => StreamK m a -> m ()
327− [A] deleteBy :: (a -> a -> Bool) -> a -> StreamK m a -> StreamK m a
328− [A] crossWith :: Monad m => (a -> b -> c) -> StreamK m a -> StreamK m b -> StreamK m c
329− [A] crossApplyWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> StreamK m (a -> b) -> StreamK m a -> StreamK m b
330− [A] crossApplySnd :: StreamK m a -> StreamK m b -> StreamK m b
331− [A] crossApplyFst :: StreamK m a -> StreamK m b -> StreamK m a
332− [A] crossApply :: StreamK m (a -> b) -> StreamK m a -> StreamK m b
333− [A] cross :: Monad m => StreamK m a -> StreamK m b -> StreamK m (a, b)
334− [A] consMBy :: Monad m => (StreamK m a -> StreamK m a -> StreamK m a) -> m a -> StreamK m a -> StreamK m a
335− [A] consM :: Monad m => m a -> StreamK m a -> StreamK m a
336− [A] consK :: YieldK m a -> StreamK m a -> StreamK m a
337− [A] cons :: a -> StreamK m a -> StreamK m a
338− [A] conjoin :: Monad m => StreamK m a -> StreamK m a -> StreamK m a
339− [A] concatMapWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> (a -> StreamK m b) -> StreamK m a -> StreamK m b
340− [A] concatMapEffect :: Monad m => (b -> StreamK m a) -> m b -> StreamK m a
341− [A] concatMap :: (a -> StreamK m b) -> StreamK m a -> StreamK m b
342− [A] concatIterateWith :: (StreamK m a -> StreamK m a -> StreamK m a) -> (a -> StreamK m a) -> StreamK m a -> StreamK m a
343− [A] concatIterateScanWith :: Monad m => (StreamK m a -> StreamK m a -> StreamK m a) -> (b -> a -> m (b, StreamK m a)) -> m b -> StreamK m a -> StreamK m a
344− [A] concatIterateLeftsWith :: b ~ Either a c => (StreamK m b -> StreamK m b -> StreamK m b) -> (a -> StreamK m b) -> StreamK m b -> StreamK m b
345− [A] concatEffect :: Monad m => m (StreamK m a) -> StreamK m a
346− [A] buildSM :: Monad m => ((m a -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a) -> StreamK m a
347− [A] buildS :: ((a -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a) -> StreamK m a
348− [A] buildM :: Monad m => (forall r. (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> m r) -> StreamK m a
349− [A] build :: forall m a. (forall b. (a -> b -> b) -> b -> b) -> StreamK m a
350− [A] bracketIO :: (MonadIO m, MonadCatch m) => IO b -> (b -> IO c) -> (b -> StreamK m a) -> StreamK m a
351− [A] bindWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> StreamK m a -> (a -> StreamK m b) -> StreamK m b
352− [A] before :: Monad m => m b -> StreamK m a -> StreamK m a
353− [A] augmentSM :: Monad m => ((m a -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a
354− [A] augmentS :: ((a -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a
355− [A] append :: StreamK m a -> StreamK m a -> StreamK m a
356− [A] any :: Monad m => (a -> Bool) -> StreamK m a -> m Bool
357− [A] all :: Monad m => (a -> Bool) -> StreamK m a -> m Bool
358− [A] (.:) :: a -> StreamK m a -> StreamK m a
359− [A] (!!) :: Monad m => StreamK m a -> Int -> m (Maybe a)
360−[R] Streamly.Internal.Data.Stream.StreamK.Type
361−[R] Streamly.Internal.Data.Stream.StreamK.Transformer
362−[R] Streamly.Internal.Data.Stream.StreamK
363−[R] Streamly.Internal.Data.Stream.StreamD.Type
364−[R] Streamly.Internal.Data.Stream.StreamD.Transformer
365−[R] Streamly.Internal.Data.Stream.StreamD.Transform
366−[R] Streamly.Internal.Data.Stream.StreamD.Top
367−[R] Streamly.Internal.Data.Stream.StreamD.Step
368−[R] Streamly.Internal.Data.Stream.StreamD.Nesting
369−[R] Streamly.Internal.Data.Stream.StreamD.Lift
370−[R] Streamly.Internal.Data.Stream.StreamD.Generate
371−[R] Streamly.Internal.Data.Stream.StreamD.Exception
372−[R] Streamly.Internal.Data.Stream.StreamD.Eliminate
373−[R] Streamly.Internal.Data.Stream.StreamD.Container
374−[D] Streamly.Internal.Data.Stream.StreamD
375−[R] Streamly.Internal.Data.Stream.Common
376−[R] Streamly.Internal.Data.Stream.Chunked
377−[C] Streamly.Internal.Data.Stream
378− [A] class Enum a => Enumerable a
379− [A] Stream
380− [A] UnStream :: (State StreamK m a -> s -> m (Step s a)) -> s -> Stream m a
381− [A] Step
382− [A] Yield :: a -> s -> Step s a
383− [A] Stop :: Step s a
384− [A] Skip :: s -> Step s a
385− [A] InterleaveState
386− [A] InterleaveSecondOnly :: s2 -> InterleaveState s1 s2
387− [A] InterleaveSecond :: s1 -> s2 -> InterleaveState s1 s2
388− [A] InterleaveFirstOnly :: s1 -> InterleaveState s1 s2
389− [A] InterleaveFirst :: s1 -> s2 -> InterleaveState s1 s2
390− [A] FoldManyPost
391− [A] FoldManyPostYield :: b -> FoldManyPost s fs b a -> FoldManyPost s fs b a
392− [A] FoldManyPostStart :: s -> FoldManyPost s fs b a
393− [A] FoldManyPostLoop :: s -> fs -> FoldManyPost s fs b a
394− [A] FoldManyPostDone :: FoldManyPost s fs b a
395− [A] FoldMany
396− [A] FoldManyYield :: b -> FoldMany s fs b a -> FoldMany s fs b a
397− [A] FoldManyStart :: s -> FoldMany s fs b a
398− [A] FoldManyLoop :: s -> fs -> FoldMany s fs b a
399− [A] FoldManyFirst :: fs -> s -> FoldMany s fs b a
400− [A] FoldManyDone :: FoldMany s fs b a
401− [A] CrossStream
402− [A] ConcatUnfoldInterleaveState
403− [A] ConcatUnfoldInterleaveOuter :: o -> [i] -> ConcatUnfoldInterleaveState o i
404− [A] ConcatUnfoldInterleaveInnerR :: [i] -> [i] -> ConcatUnfoldInterleaveState o i
405− [A] ConcatUnfoldInterleaveInnerL :: [i] -> [i] -> ConcatUnfoldInterleaveState o i
406− [A] ConcatUnfoldInterleaveInner :: o -> [i] -> ConcatUnfoldInterleaveState o i
407− [A] ConcatMapUState
408− [A] ConcatMapUOuter :: o -> ConcatMapUState o i
409− [A] ConcatMapUInner :: o -> i -> ConcatMapUState o i
410− [A] AppendState
411− [A] AppendSecond :: s2 -> AppendState s1 s2
412− [A] AppendFirst :: s1 -> AppendState s1 s2
413− [A] pattern Stream :: (State StreamK m a -> s -> m (Step s a)) -> s -> Stream m a
414− [A] zipWithM :: Monad m => (a -> b -> m c) -> Stream m a -> Stream m b -> Stream m c
415− [A] zipWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
416− [A] wordsBy :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
417− [A] with :: Monad m => (Stream m a -> Stream m (s, a)) -> (((s, a) -> b) -> Stream m (s, a) -> Stream m (s, a)) -> ((s, a) -> b) -> Stream m a -> Stream m a
418− [A] usingStateT :: Monad m => m s -> (Stream (StateT s m) a -> Stream (StateT s m) a) -> Stream m a -> Stream m a
419− [A] usingReaderT :: Monad m => m r -> (Stream (ReaderT r m) a -> Stream (ReaderT r m) a) -> Stream m a -> Stream m a
420− [A] uniqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Stream m a
421− [A] uniq :: (Eq a, Monad m) => Stream m a -> Stream m a
422− [A] unionWithStreamGenericBy :: MonadIO m => (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
423− [A] unionWithStreamAscBy :: (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
424− [A] unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> Stream m a
425− [A] unfoldr :: Monad m => (s -> Maybe (a, s)) -> s -> Stream m a
426− [A] unfoldRoundRobin :: Monad m => Unfold m a b -> Stream m a -> Stream m b
427− [A] unfoldMany :: Monad m => Unfold m a b -> Stream m a -> Stream m b
428− [A] unfoldIterateDfs :: Monad m => Unfold m a a -> Stream m a -> Stream m a
429− [A] unfoldIterateBfsRev :: Monad m => Unfold m a a -> Stream m a -> Stream m a
430− [A] unfoldIterateBfs :: Monad m => Unfold m a a -> Stream m a -> Stream m a
431− [A] unfoldInterleave :: Monad m => Unfold m a b -> Stream m a -> Stream m b
432− [A] unfold :: Applicative m => Unfold m a b -> a -> Stream m b
433− [A] uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
434− [A] unCross :: CrossStream m a -> Stream m a
435− [A] transform :: Monad m => Pipe m a b -> Stream m a -> Stream m b
436− [A] trace_ :: Monad m => m b -> Stream m a -> Stream m a
437− [A] trace :: Monad m => (a -> m b) -> Stream m a -> Stream m a
438− [A] toStreamK :: Monad m => Stream m a -> StreamK m a
439− [A] toListRev :: Monad m => Stream m a -> m [a]
440− [A] toList :: Monad m => Stream m a -> m [a]
441− [A] timestamped :: MonadIO m => Stream m a -> Stream m (AbsTime, a)
442− [A] timestampWith :: MonadIO m => Double -> Stream m a -> Stream m (AbsTime, a)
443− [A] timesWith :: MonadIO m => Double -> Stream m (AbsTime, RelTime64)
444− [A] times :: MonadIO m => Stream m (AbsTime, RelTime64)
445− [A] timeout :: AbsTime -> t m ()
446− [A] timeIndexed :: MonadIO m => Stream m a -> Stream m (RelTime64, a)
447− [A] timeIndexWith :: MonadIO m => Double -> Stream m a -> Stream m (RelTime64, a)
448− [A] the :: (Eq a, Monad m) => Stream m a -> m (Maybe a)
449− [A] tapOffsetEvery :: Monad m => Int -> Int -> Fold m a b -> Stream m a -> Stream m a
450− [A] tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
451− [A] takeWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
452− [A] takeWhileLast :: (a -> Bool) -> Stream m a -> Stream m a
453− [A] takeWhileAround :: (a -> Bool) -> Stream m a -> Stream m a
454− [A] takeWhile :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
455− [A] takeEndByM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
456− [A] takeEndBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
457− [A] take :: Applicative m => Int -> Stream m a -> Stream m a
458− [A] tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
459− [A] stripSuffixUnbox :: (MonadIO m, Eq a, Unbox a) => Stream m a -> Stream m a -> m (Maybe (Stream m a))
460− [A] stripSuffix :: (Monad m, Eq a) => Stream m a -> Stream m a -> m (Maybe (Stream m a))
461− [A] stripPrefix :: (Monad m, Eq a) => Stream m a -> Stream m a -> m (Maybe (Stream m a))
462− [A] strideFromThen :: Monad m => Int -> Int -> Stream m a -> Stream m a
463− [A] splitOnSuffixSeqAny :: [Array a] -> Fold m a b -> Stream m a -> Stream m b
464− [A] splitOnSuffixSeq :: forall m a b. (MonadIO m, Storable a, Unbox a, Enum a, Eq a) => Bool -> Array a -> Fold m a b -> Stream m a -> Stream m b
465− [A] splitOnSeq :: forall m a b. (MonadIO m, Storable a, Unbox a, Enum a, Eq a) => Array a -> Fold m a b -> Stream m a -> Stream m b
466− [A] splitOnPrefix :: (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
467− [A] splitOnAny :: [Array a] -> Fold m a b -> Stream m a -> Stream m b
468− [A] splitOn :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
469− [A] 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)
470− [A] splitInnerBy :: Monad m => (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
471− [A] slicesBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
472− [A] sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
473− [A] sequence :: Monad m => Stream m (m a) -> Stream m a
474− [A] scanlx' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream m a -> Stream m b
475− [A] scanlMx' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream m a -> Stream m b
476− [A] scanlMAfter' :: Monad m => (b -> a -> m b) -> m b -> (b -> m b) -> Stream m a -> Stream m b
477− [A] scanlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> Stream m b
478− [A] scanlM :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> Stream m b
479− [A] scanl1M' :: Monad m => (a -> a -> m a) -> Stream m a -> Stream m a
480− [A] scanl1M :: Monad m => (a -> a -> m a) -> Stream m a -> Stream m a
481− [A] scanl1' :: Monad m => (a -> a -> a) -> Stream m a -> Stream m a
482− [A] scanl1 :: Monad m => (a -> a -> a) -> Stream m a -> Stream m a
483− [A] scanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
484− [A] scanl :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
485− [A] scanMaybe :: Monad m => Fold m a (Maybe b) -> Stream m a -> Stream m b
486− [A] scanMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
487− [A] scan :: Monad m => Fold m a b -> Stream m a -> Stream m b
488− [A] runStateT :: Monad m => m s -> Stream (StateT s m) a -> Stream m (s, a)
489− [A] runReaderT :: Monad m => m s -> Stream (ReaderT s m) a -> Stream m a
490− [A] runInnerWithState :: Monad m => (forall b. s -> t m b -> m (b, s)) -> m s -> Stream (t m) a -> Stream m (s, a)
491− [A] runInnerWith :: Monad m => (forall b. t m b -> m b) -> Stream (t m) a -> Stream m a
492− [A] roundRobin :: Monad m => Stream m a -> Stream m a -> Stream m a
493− [A] rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Stream m a -> Stream m b
494− [A] rollingMap2 :: Monad m => (a -> a -> b) -> Stream m a -> Stream m b
495− [A] rollingMap :: Monad m => (Maybe a -> a -> b) -> Stream m a -> Stream m b
496− [A] reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
497− [A] reverse :: Monad m => Stream m a -> Stream m a
498− [A] replicateM :: Monad m => Int -> m a -> Stream m a
499− [A] replicate :: Monad m => Int -> a -> Stream m a
500− [A] repeated :: Stream m a -> Stream m a
501− [A] repeatM :: Monad m => m a -> Stream m a
502− [A] repeat :: Monad m => a -> Stream m a
503− [A] relTimesWith :: MonadIO m => Double -> Stream m RelTime64
504− [A] relTimes :: MonadIO m => Stream m RelTime64
505− [A] refoldMany :: Monad m => Refold m x a b -> m x -> Stream m a -> Stream m b
506− [A] refoldIterateM :: Monad m => Refold m b a b -> m b -> Stream m a -> Stream m b
507− [A] reduceIterateBfs :: Monad m => (a -> a -> m a) -> Stream m a -> m (Maybe a)
508− [A] reassembleBy :: Fold m a b -> (a -> a -> Int) -> Stream m a -> Stream m b
509− [A] prune :: (a -> Bool) -> Stream m a -> Stream m a
510− [A] prescanlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> Stream m b
511− [A] prescanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
512− [A] postscanlx' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream m a -> Stream m b
513− [A] postscanlMx' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream m a -> Stream m b
514− [A] postscanlMAfter' :: Monad m => (b -> a -> m b) -> m b -> (b -> m b) -> Stream m a -> Stream m b
515− [A] postscanlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> Stream m b
516− [A] postscanlM :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> Stream m b
517− [A] postscanl' :: Monad m => (a -> b -> a) -> a -> Stream m b -> Stream m a
518− [A] postscanl :: Monad m => (a -> b -> a) -> a -> Stream m b -> Stream m a
519− [A] postscan :: Monad m => Fold m a b -> Stream m a -> Stream m b
520− [A] parseSequence :: Stream m (Parser a m b) -> Stream m a -> Stream m b
521− [A] parseManyTill :: Parser a m b -> Parser a m x -> Stream m a -> Stream m b
522− [A] parseManyD :: Monad m => Parser a m b -> Stream m a -> Stream m (Either ParseError b)
523− [A] parseMany :: Monad m => Parser a m b -> Stream m a -> Stream m (Either ParseError b)
524− [A] parseIterateD :: Monad m => (b -> Parser a m b) -> b -> Stream m a -> Stream m (Either ParseError b)
525− [A] parseIterate :: Monad m => (b -> Parser a m b) -> b -> Stream m a -> Stream m (Either ParseError b)
526− [A] parseD :: Monad m => Parser a m b -> Stream m a -> m (Either ParseError b)
527− [A] parseBreakD :: Monad m => Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
528− [A] parseBreak :: Monad m => Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
529− [A] parse :: Monad m => Parser a m b -> Stream m a -> m (Either ParseError b)
530− [A] onException :: MonadCatch m => m b -> Stream m a -> Stream m a
531− [A] null :: Monad m => Stream m a -> m Bool
532− [A] nub :: (Monad m, Ord a) => Stream m a -> Stream m a
533− [A] notElem :: (Monad m, Eq a) => a -> Stream m a -> m Bool
534− [A] nilM :: Applicative m => m b -> Stream m a
535− [A] nil :: Applicative m => Stream m a
536− [A] morphInner :: Monad n => (forall x. m x -> n x) -> Stream m a -> Stream n a
537− [A] mkCross :: Stream m a -> CrossStream m a
538− [A] minimumBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> m (Maybe a)
539− [A] minimum :: (Monad m, Ord a) => Stream m a -> m (Maybe a)
540− [A] mergeMinBy :: (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a
541− [A] mergeFstBy :: (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a
542− [A] mergeByM :: Monad m => (a -> a -> m Ordering) -> Stream m a -> Stream m a -> Stream m a
543− [A] mergeBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
544− [A] maximumBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> m (Maybe a)
545− [A] maximum :: (Monad m, Ord a) => Stream m a -> m (Maybe a)
546− [A] mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Stream m a -> Stream m b
547− [A] mapMaybe :: Monad m => (a -> Maybe b) -> Stream m a -> Stream m b
548− [A] mapM_ :: Monad m => (a -> m b) -> Stream m a -> m ()
549− [A] mapM :: Monad m => (a -> m b) -> Stream m a -> Stream m b
550− [A] map :: Monad m => (a -> b) -> Stream m a -> Stream m b
551− [A] lookup :: (Monad m, Eq a) => a -> Stream m (a, b) -> m (Maybe b)
552− [A] liftInnerWith :: Monad (t m) => (forall b. m b -> t m b) -> Stream m a -> Stream (t m) a
553− [A] liftInner :: (Monad m, MonadTrans t, Monad (t m)) => Stream m a -> Stream (t m) a
554− [A] last :: Monad m => Stream m a -> m (Maybe a)
555− [A] joinOuterGeneric :: MonadIO m => (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (Maybe a, Maybe b)
556− [A] joinOuterAscBy :: (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (Maybe a, Maybe b)
557− [A] joinOuter :: (Ord k, MonadIO m) => Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
558− [A] joinLeftGeneric :: Monad m => (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
559− [A] joinLeftAscBy :: (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
560− [A] joinLeft :: (Ord k, Monad m) => Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
561− [A] joinInnerGeneric :: Monad m => (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
562− [A] joinInnerAscBy :: (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
563− [A] joinInner :: (Monad m, Ord k) => Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
564− [A] iterateM :: Monad m => (a -> m a) -> m a -> Stream m a
565− [A] iterate :: Monad m => (a -> a) -> a -> Stream m a
566− [A] isSuffixOfUnbox :: (MonadIO m, Eq a, Unbox a) => Stream m a -> Stream m a -> m Bool
567− [A] isSuffixOf :: (Monad m, Eq a) => Stream m a -> Stream m a -> m Bool
568− [A] isSubsequenceOf :: (Monad m, Eq a) => Stream m a -> Stream m a -> m Bool
569− [A] isPrefixOf :: (Monad m, Eq a) => Stream m a -> Stream m a -> m Bool
570− [A] isInfixOf :: (MonadIO m, Eq a, Enum a, Storable a, Unbox a) => Stream m a -> Stream m a -> m Bool
571− [A] intersperseM_ :: Monad m => m b -> Stream m a -> Stream m a
572− [A] intersperseMWith :: Int -> m a -> Stream m a -> Stream m a
573− [A] intersperseMSuffix_ :: Monad m => m b -> Stream m a -> Stream m a
574− [A] intersperseMSuffixWith :: forall m a. Monad m => Int -> m a -> Stream m a -> Stream m a
575− [A] intersperseMSuffix :: forall m a. Monad m => m a -> Stream m a -> Stream m a
576− [A] intersperseMPrefix_ :: Monad m => m b -> Stream m a -> Stream m a
577− [A] intersperseM :: Monad m => m a -> Stream m a -> Stream m a
578− [A] intersperse :: Monad m => a -> Stream m a -> Stream m a
579− [A] intersectBySorted :: Monad m => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
580− [A] interposeSuffixM :: Monad m => m c -> Unfold m b c -> Stream m b -> Stream m c
581− [A] interposeSuffix :: Monad m => c -> Unfold m b c -> Stream m b -> Stream m c
582− [A] interposeM :: Monad m => m c -> Unfold m b c -> Stream m b -> Stream m c
583− [A] interpose :: Monad m => c -> Unfold m b c -> Stream m b -> Stream m c
584− [A] interleaveMin :: Monad m => Stream m a -> Stream m a -> Stream m a
585− [A] interleaveFstSuffix :: Monad m => Stream m a -> Stream m a -> Stream m a
586− [A] interleaveFst :: Monad m => Stream m a -> Stream m a -> Stream m a
587− [A] interleave :: Monad m => Stream m a -> Stream m a -> Stream m a
588− [A] intercalateSuffix :: Monad m => Unfold m b c -> b -> Stream m b -> Stream m c
589− [A] intercalate :: Monad m => Unfold m b c -> b -> Stream m b -> Stream m c
590− [A] insertBy :: Monad m => (a -> a -> Ordering) -> a -> Stream m a -> Stream m a
591− [A] indexedR :: Monad m => Int -> Stream m a -> Stream m (Int, a)
592− [A] indexed :: Monad m => Stream m a -> Stream m (Int, a)
593− [A] headElse :: Monad m => a -> Stream m a -> m a
594− [A] head :: Monad m => Stream m a -> m (Maybe a)
595− [A] handle :: (MonadCatch m, Exception e) => (e -> m (Stream m a)) -> Stream m a -> Stream m a
596− [A] groupsWhile :: Monad m => (a -> a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
597− [A] groupsRollingBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
598− [A] groupsOf :: Monad m => Int -> Fold m a b -> Stream m a -> Stream m b
599− [A] gintercalateSuffix :: Monad m => Unfold m a c -> Stream m a -> Unfold m b c -> Stream m b -> Stream m c
600− [A] gintercalate :: Monad m => Unfold m a c -> Stream m a -> Unfold m b c -> Stream m b -> Stream m c
601− [A] ghandle :: (MonadCatch m, Exception e) => (e -> Stream m a -> m (Stream m a)) -> Stream m a -> Stream m a
602− [A] generateM :: Monad m => Int -> (Int -> m a) -> Stream m a
603− [A] generate :: Monad m => Int -> (Int -> a) -> Stream m a
604− [A] generalizeInner :: Monad m => Stream Identity a -> Stream m a
605− [A] gbracket_ :: Monad m => m c -> (c -> m d) -> (c -> e -> Stream m b -> m (Stream m b)) -> (forall s. m s -> m (Either e s)) -> (c -> Stream m b) -> Stream m b
606− [A] gbracket :: MonadIO m => IO c -> (c -> IO d1) -> (c -> e -> Stream m b -> IO (Stream m b)) -> (c -> IO d2) -> (forall s. m s -> m (Either e s)) -> (c -> Stream m b) -> Stream m b
607− [A] fromStreamK :: Applicative m => StreamK m a -> Stream m a
608− [A] fromPure :: Applicative m => a -> Stream m a
609− [A] fromPtrN :: (Monad m, Storable a) => Int -> Ptr a -> Stream m a
610− [A] fromPtr :: forall m a. (Monad m, Storable a) => Ptr a -> Stream m a
611− [A] fromListM :: Monad m => [m a] -> Stream m a
612− [A] fromList :: Applicative m => [a] -> Stream m a
613− [A] fromIndicesM :: Monad m => (Int -> m a) -> Stream m a
614− [A] fromIndices :: Monad m => (Int -> a) -> Stream m a
615− [A] fromFoldableM :: (Monad m, Foldable f) => f (m a) -> Stream m a
616− [A] fromFoldable :: (Monad m, Foldable f) => f a -> Stream m a
617− [A] fromEffect :: Applicative m => m a -> Stream m a
618− [A] fromByteStr# :: Monad m => Addr# -> Stream m Word8
619− [A] foldrT :: (Monad m, Monad (t m), MonadTrans t) => (a -> t m b -> t m b) -> t m b -> Stream m a -> t m b
620− [A] foldrS :: Monad m => (a -> Stream m b -> Stream m b) -> Stream m b -> Stream m a -> Stream m b
621− [A] foldrMx :: Monad m => (a -> m x -> m x) -> m x -> (m x -> m b) -> Stream m a -> m b
622− [A] foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
623− [A] foldr1 :: Monad m => (a -> a -> a) -> Stream m a -> m (Maybe a)
624− [A] foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
625− [A] foldlx' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream m a -> m b
626− [A] foldlT :: (Monad m, Monad (s m), MonadTrans s) => (s m b -> a -> s m b) -> s m b -> Stream m a -> s m b
627− [A] foldlS :: Monad m => (Stream m b -> a -> Stream m b) -> Stream m b -> Stream m a -> Stream m b
628− [A] foldlMx' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Stream m a -> m b
629− [A] foldlM' :: Monad m => (b -> a -> m b) -> m b -> Stream m a -> m b
630− [A] foldl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> m b
631− [A] foldSequence :: Stream m (Fold m a b) -> Stream m a -> Stream m b
632− [A] foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
633− [A] foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
634− [A] foldIterateM :: Monad m => (b -> m (Fold m a b)) -> m b -> Stream m a -> Stream m b
635− [A] foldIterateBfs :: Fold m a (Either a a) -> Stream m a -> m (Maybe a)
636− [A] foldEither :: Monad m => Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
637− [A] foldBreak :: Monad m => Fold m a b -> Stream m a -> m (b, Stream m a)
638− [A] foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
639− [A] foldAdd :: Monad m => Fold m a b -> Stream m a -> m (Fold m a b)
640− [A] fold :: Monad m => Fold m a b -> Stream m a -> m b
641− [A] findM :: Monad m => (a -> m Bool) -> Stream m a -> m (Maybe a)
642− [A] findIndices :: Monad m => (a -> Bool) -> Stream m a -> Stream m Int
643− [A] find :: Monad m => (a -> Bool) -> Stream m a -> m (Maybe a)
644− [A] finallyUnsafe :: MonadCatch m => m b -> Stream m a -> Stream m a
645− [A] finallyIO :: (MonadIO m, MonadCatch m) => IO b -> Stream m a -> Stream m a
646− [A] filterM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
647− [A] filterInStreamGenericBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
648− [A] filterInStreamAscBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
649− [A] filter :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
650− [A] evalStateT :: Monad m => m s -> Stream (StateT s m) a -> Stream m a
651− [A] eqBy :: Monad m => (a -> b -> Bool) -> Stream m a -> Stream m b -> m Bool
652− [A] enumerateTo :: (Monad m, Bounded a, Enumerable a) => a -> Stream m a
653− [A] enumerateFromToSmall :: (Monad m, Enum a) => a -> a -> Stream m a
654− [A] enumerateFromToIntegral :: (Monad m, Integral a) => a -> a -> Stream m a
655− [A] enumerateFromToFractional :: (Monad m, Fractional a, Ord a) => a -> a -> Stream m a
656− [A] enumerateFromTo :: (Enumerable a, Monad m) => a -> a -> Stream m a
657− [A] enumerateFromThenToSmall :: (Monad m, Enum a) => a -> a -> a -> Stream m a
658− [A] enumerateFromThenToIntegral :: (Monad m, Integral a) => a -> a -> a -> Stream m a
659− [A] enumerateFromThenToFractional :: (Monad m, Fractional a, Ord a) => a -> a -> a -> Stream m a
660− [A] enumerateFromThenTo :: (Enumerable a, Monad m) => a -> a -> a -> Stream m a
661− [A] enumerateFromThenSmallBounded :: (Monad m, Enumerable a, Bounded a) => a -> a -> Stream m a
662− [A] enumerateFromThenNum :: (Monad m, Num a) => a -> a -> Stream m a
663− [A] enumerateFromThenIntegral :: (Monad m, Integral a, Bounded a) => a -> a -> Stream m a
664− [A] enumerateFromThenFractional :: (Monad m, Fractional a) => a -> a -> Stream m a
665− [A] enumerateFromThen :: (Enumerable a, Monad m) => a -> a -> Stream m a
666− [A] enumerateFromStepNum :: (Monad m, Num a) => a -> a -> Stream m a
667− [A] enumerateFromStepIntegral :: (Integral a, Monad m) => a -> a -> Stream m a
668− [A] enumerateFromNum :: (Monad m, Num a) => a -> Stream m a
669− [A] enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => a -> Stream m a
670− [A] enumerateFromFractional :: (Monad m, Fractional a) => a -> Stream m a
671− [A] enumerateFromBounded :: (Monad m, Enumerable a, Bounded a) => a -> Stream m a
672− [A] enumerateFrom :: (Enumerable a, Monad m) => a -> Stream m a
673− [A] enumerate :: (Monad m, Bounded a, Enumerable a) => Stream m a
674− [A] elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
675− [A] elem :: (Monad m, Eq a) => a -> Stream m a -> m Bool
676− [A] durations :: Double -> t m RelTime64
677− [A] dropWhileM :: Monad m => (a -> m Bool) -> Stream m a -> Stream m a
678− [A] dropWhileLast :: (a -> Bool) -> Stream m a -> Stream m a
679− [A] dropWhileAround :: (a -> Bool) -> Stream m a -> Stream m a
680− [A] dropWhile :: Monad m => (a -> Bool) -> Stream m a -> Stream m a
681− [A] dropSuffix :: Stream m a -> Stream m a -> Stream m a
682− [A] dropPrefix :: Stream m a -> Stream m a -> Stream m a
683− [A] dropLast :: Int -> Stream m a -> Stream m a
684− [A] dropInfix :: Stream m a -> Stream m a -> Stream m a
685− [A] drop :: Monad m => Int -> Stream m a -> Stream m a
686− [A] drain :: Monad m => Stream m a -> m ()
687− [A] deleteInStreamGenericBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
688− [A] deleteInStreamAscBy :: (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
689− [A] deleteBy :: Monad m => (a -> a -> Bool) -> a -> Stream m a -> Stream m a
690− [A] delayPre :: MonadIO m => Double -> Stream m a -> Stream m a
691− [A] delayPost :: MonadIO m => Double -> Stream m a -> Stream m a
692− [A] delay :: MonadIO m => Double -> Stream m a -> Stream m a
693− [A] crossWith :: Monad m => (a -> b -> c) -> Stream m a -> Stream m b -> Stream m c
694− [A] crossApplySnd :: Functor f => Stream f a -> Stream f b -> Stream f b
695− [A] crossApplyFst :: Functor f => Stream f a -> Stream f b -> Stream f a
696− [A] crossApply :: Functor f => Stream f (a -> b) -> Stream f a -> Stream f b
697− [A] cross :: Monad m => Stream m a -> Stream m b -> Stream m (a, b)
698− [A] consM :: Applicative m => m a -> Stream m a -> Stream m a
699− [A] cons :: Applicative m => a -> Stream m a -> Stream m a
700− [A] concatMapM :: Monad m => (a -> m (Stream m b)) -> Stream m a -> Stream m b
701− [A] concatMap :: Monad m => (a -> Stream m b) -> Stream m a -> Stream m b
702− [A] concatIterateScan :: Monad m => (b -> a -> m b) -> (b -> m (Maybe (b, Stream m a))) -> b -> Stream m a
703− [A] concatIterateDfs :: Monad m => (a -> Maybe (Stream m a)) -> Stream m a -> Stream m a
704− [A] concatIterateBfsRev :: Monad m => (a -> Maybe (Stream m a)) -> Stream m a -> Stream m a
705− [A] concatIterateBfs :: Monad m => (a -> Maybe (Stream m a)) -> Stream m a -> Stream m a
706− [A] concatEffect :: Monad m => m (Stream m a) -> Stream m a
707− [A] concat :: Monad m => Stream m (Stream m a) -> Stream m a
708− [A] cmpBy :: Monad m => (a -> b -> Ordering) -> Stream m a -> Stream m b -> m Ordering
709− [A] catRights :: Monad m => Stream m (Either a b) -> Stream m b
710− [A] catMaybes :: Monad m => Stream m (Maybe a) -> Stream m a
711− [A] catLefts :: Monad m => Stream m (Either a b) -> Stream m a
712− [A] catEithers :: Monad m => Stream m (Either a a) -> Stream m a
713− [A] bracketUnsafe :: MonadCatch m => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
714− [A] bracketIO3 :: (MonadIO m, MonadCatch m) => IO b -> (b -> IO c) -> (b -> IO d) -> (b -> IO e) -> (b -> Stream m a) -> Stream m a
715− [A] bracketIO :: (MonadIO m, MonadCatch m) => IO b -> (b -> IO c) -> (b -> Stream m a) -> Stream m a
716− [A] before :: Monad m => m b -> Stream m a -> Stream m a
717− [A] append :: Monad m => Stream m a -> Stream m a -> Stream m a
718− [A] any :: Monad m => (a -> Bool) -> Stream m a -> m Bool
719− [A] all :: Monad m => (a -> Bool) -> Stream m a -> m Bool
720− [A] afterUnsafe :: Monad m => m b -> Stream m a -> Stream m a
721− [A] afterIO :: MonadIO m => IO b -> Stream m a -> Stream m a
722− [A] absTimesWith :: MonadIO m => Double -> Stream m AbsTime
723− [A] absTimes :: MonadIO m => Stream m AbsTime
724− [A] (!!) :: Monad m => Stream m a -> Int -> m (Maybe a)
725−[R] Streamly.Internal.Data.Ring.Unboxed
726−[A] Streamly.Internal.Data.Ring.Generic
727− [A] Ring
728− [A] [ringMax] :: Ring a -> !Int
729− [A] [ringHead] :: Ring a -> !Int
730− [A] [ringArr] :: Ring a -> MutArray a
731− [A] Ring :: MutArray a -> !Int -> !Int -> Ring a
732− [A] writeLastN :: MonadIO m => Int -> Fold m a (Ring a)
733− [A] unsafeInsertRingWith :: Ring a -> a -> IO Int
734− [A] toStreamWith :: Int -> Ring a -> Stream m a
735− [A] toMutArray :: MonadIO m => Int -> Int -> Ring a -> m (MutArray a)
736− [A] seek :: MonadIO m => Int -> Ring a -> m (Ring a)
737− [A] createRing :: MonadIO m => Int -> m (Ring a)
738− [A] copyToMutArray :: MonadIO m => Int -> Int -> Ring a -> m (MutArray a)
739−[C] Streamly.Internal.Data.Ring
740− [C] Ring
741− [A] [ringStart] :: Ring a -> {-# UNPACK #-} !ForeignPtr a
742− [R] [ringMax] :: Ring a -> !Int
743− [R] [ringHead] :: Ring a -> !Int
744− [A] [ringBound] :: Ring a -> {-# UNPACK #-} !Ptr a
745− [R] [ringArr] :: Ring a -> MutArray a
746− [C] Ring
747− [O] Ring :: MutArray a -> !Int -> !Int -> Ring a
748− [N] Ring :: {-# UNPACK #-} !ForeignPtr a -> {-# UNPACK #-} !Ptr a -> Ring a
749− [A] GHC.Show.Show
750− [A] instance (GHC.Show.Show a, GHC.Show.Show b, GHC.Show.Show c, GHC.Show.Show d) => GHC.Show.Show (Streamly.Internal.Data.Ring.Tuple4' a b c d)
751− [A] writeN :: Int -> Fold m a (Ring a)
752− [R] writeLastN :: MonadIO m => Int -> Fold m a (Ring a)
753− [R] unsafeInsertRingWith :: Ring a -> a -> IO Int
754− [A] unsafeInsert :: Storable a => Ring a -> Ptr a -> a -> IO (Ptr a)
755− [A] unsafeFoldRingNM :: forall m a b. (MonadIO m, Storable a) => Int -> Ptr a -> (b -> a -> m b) -> b -> Ring a -> m b
756− [A] unsafeFoldRingM :: forall m a b. (MonadIO m, Storable a) => Ptr a -> (b -> a -> m b) -> b -> Ring a -> m b
757− [A] unsafeFoldRingFullM :: forall m a b. (MonadIO m, Storable a) => Ptr a -> (b -> a -> m b) -> b -> Ring a -> m b
758− [A] unsafeFoldRing :: forall a b. Storable a => Ptr a -> (b -> a -> b) -> b -> Ring a -> b
759− [A] unsafeEqArrayN :: Ring a -> Ptr a -> Array a -> Int -> Bool
760− [A] unsafeEqArray :: Ring a -> Ptr a -> Array a -> Bool
761− [R] toStreamWith :: Int -> Ring a -> Stream m a
762− [R] toMutArray :: MonadIO m => Int -> Int -> Ring a -> m (MutArray a)
763− [A] startOf :: Ring a -> Ptr a
764− [A] slidingWindowWith :: forall m a b. (MonadIO m, Storable a, Unbox a) => Int -> Fold m ((a, Maybe a), m (MutArray a)) b -> Fold m a b
765− [A] slidingWindow :: forall m a b. (MonadIO m, Storable a, Unbox a) => Int -> Fold m (a, Maybe a) b -> Fold m a b
766− [A] slide :: Ring a -> a -> m (Ring a)
767− [R] seek :: MonadIO m => Int -> Ring a -> m (Ring a)
768− [A] ringsOf :: Int -> Stream m a -> Stream m (MutArray a)
769− [A] readRev :: Unfold m (MutArray a) a
770− [A] read :: forall m a. (MonadIO m, Storable a) => Unfold m (Ring a, Ptr a, Int) a
771− [A] putIndex :: Ring a -> Int -> a -> m ()
772− [A] newRing :: Int -> m (Ring a)
773− [A] new :: forall a. Storable a => Int -> IO (Ring a, Ptr a)
774− [A] moveBy :: forall a. Storable a => Int -> Ring a -> Ptr a -> Ptr a
775− [A] modifyIndex :: Ring a -> Int -> (a -> (a, b)) -> m b
776− [A] length :: Ring a -> Int
777− [A] getIndexUnsafe :: Ring a -> Int -> m a
778− [A] getIndexRev :: Ring a -> Int -> m a
779− [A] getIndex :: Ring a -> Int -> m a
780− [A] fromArray :: MutArray a -> Ring a
781− [R] createRing :: MonadIO m => Int -> m (Ring a)
782− [A] castUnsafe :: Ring a -> Ring b
783− [A] cast :: forall a b. Storable b => Ring a -> Maybe (Ring b)
784− [A] bytesFree :: Ring a -> Int
785− [A] byteLength :: Ring a -> Int
786− [A] byteCapacity :: Ring a -> Int
787− [A] asBytes :: Ring a -> Ring Word8
788− [A] advance :: forall a. Storable a => Ring a -> Ptr a -> Ptr a
789−[R] Streamly.Internal.Data.Producer.Type
790−[R] Streamly.Internal.Data.Producer.Source
791−[C] Streamly.Internal.Data.Producer
792− [A] Source
793− [A] unread :: [b] -> Source a b -> Source a b
794− [A] translate :: Functor m => (a -> c) -> (c -> a) -> Producer m c b -> Producer m a b
795− [A] source :: Maybe a -> Source a b
796− [A] producer :: Monad m => Producer m a b -> Producer m (Source a b) b
797− [A] parseManyD :: Monad m => Parser a m b -> Producer m (Source x a) a -> Producer m (Source x a) (Either ParseError b)
798− [A] parseMany :: Monad m => Parser a m b -> Producer m (Source x a) a -> Producer m (Source x a) (Either ParseError b)
799− [A] parse :: Monad m => Parser a m b -> Producer m (Source s a) a -> Source s a -> m (Either ParseError b, Source s a)
800− [A] lmap :: (a -> a) -> Producer m a b -> Producer m a b
801− [A] isEmpty :: Source a b -> Bool
802−[R] Streamly.Internal.Data.Pipe.Type
803−[C] Streamly.Internal.Data.Pipe
804− [A] Step
805− [A] Yield :: a -> s -> Step s a
806− [A] Continue :: s -> Step s a
807− [A] PipeState
808− [A] Produce :: s2 -> PipeState s1 s2
809− [A] Consume :: s1 -> PipeState s1 s2
810− [C] Pipe
811− [A] Pipe :: (s1 -> a -> m (Step (PipeState s1 s2) b)) -> (s2 -> m (Step (PipeState s1 s2) b)) -> s1 -> Pipe m a b
812−[A] Streamly.Internal.Data.ParserK
813− [A] Step
814− [A] Partial :: !Int -> (Input a -> m (Step a m r)) -> Step a m r
815− [A] Error :: !Int -> String -> Step a m r
816− [A] Done :: !Int -> r -> Step a m r
817− [A] Continue :: !Int -> (Input a -> m (Step a m r)) -> Step a m r
818− [A] ParseResult
819− [A] Success :: !Int -> !b -> ParseResult b
820− [A] Failure :: !Int -> !String -> ParseResult b
821− [A] Input
822− [A] None :: Input a
823− [A] Chunk :: a -> Input a
824− [A] ParserK
825− [A] [runParser] :: ParserK a m b -> forall r. (ParseResult b -> Int -> Input a -> m (Step a m r)) -> Int -> Int -> Input a -> m (Step a m r)
826− [A] MkParser :: (forall r. (ParseResult b -> Int -> Input a -> m (Step a m r)) -> Int -> Int -> Input a -> m (Step a m r)) -> ParserK a m b
827− [A] fromPure :: b -> ParserK a m b
828− [A] fromEffect :: Monad m => m b -> ParserK a m b
829− [A] die :: String -> ParserK a m b
830− [A] adaptCG :: Monad m => Parser a m b -> ParserK (Array a) m b
831− [A] adaptC :: (Monad m, Unbox a) => Parser a m b -> ParserK (Array a) m b
832− [A] adapt :: Monad m => Parser a m b -> ParserK a m b
833−[R] Streamly.Internal.Data.Parser.ParserK.Type
834−[R] Streamly.Internal.Data.Parser.ParserD.Type
835−[R] Streamly.Internal.Data.Parser.ParserD.Tee
836−[R] Streamly.Internal.Data.Parser.ParserD
837−[C] Streamly.Internal.Data.Parser
838− [A] Step
839− [A] Partial :: !Int -> !s -> Step s b
840− [A] Error :: !String -> Step s b
841− [A] Done :: !Int -> !b -> Step s b
842− [A] Continue :: !Int -> !s -> Step s b
843− [A] Parser
844− [A] Parser :: (s -> a -> m (Step s b)) -> m (Initial s b) -> (s -> m (Step s b)) -> Parser a m b
845− [A] Initial
846− [A] IPartial :: !s -> Initial s b
847− [A] IError :: !String -> Initial s b
848− [A] IDone :: !b -> Initial s b
849− [A] GHC.Show.Show
850− [A] instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Streamly.Internal.Data.Parser.Tuple'Fused a b)
851− [A] ParseError
852− [A] ParseError :: String -> ParseError
853− [A] zipWithM :: Monad m => (a -> b -> m c) -> Stream m a -> Fold m c x -> Parser b m x
854− [A] zip :: Monad m => Stream m a -> Fold m (a, b) x -> Parser b m x
855− [A] wordWithQuotes :: (Monad m, Eq a) => Bool -> (a -> a -> Maybe a) -> a -> (a -> Maybe a) -> (a -> Bool) -> Fold m a b -> Parser a m b
856− [A] wordProcessQuotes :: (Monad m, Eq a) => a -> (a -> Maybe a) -> (a -> Bool) -> Fold m a b -> Parser a m b
857− [A] wordKeepQuotes :: (Monad m, Eq a) => a -> (a -> Maybe a) -> (a -> Bool) -> Fold m a b -> Parser a m b
858− [A] wordFramedBy :: Monad m => (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
859− [A] wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
860− [A] toFold :: Monad m => Parser a m b -> Fold m a b
861− [A] takeWhileP :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
862− [A] takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
863− [A] takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
864− [A] takeStartBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
865− [A] takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
866− [A] takeP :: Monad m => Int -> Parser a m b -> Parser a m b
867− [A] takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
868− [A] takeFramedBy_ :: Monad m => (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
869− [A] takeFramedByGeneric :: Monad m => Maybe (a -> Bool) -> Maybe (a -> Bool) -> Maybe (a -> Bool) -> Fold m a b -> Parser a m b
870− [A] takeFramedByEsc_ :: Monad m => (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
871− [A] takeEndBy_ :: (a -> Bool) -> Parser a m b -> Parser a m b
872− [A] takeEndByEsc :: Monad m => (a -> Bool) -> (a -> Bool) -> Parser a m b -> Parser a m b
873− [A] takeEndBy :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
874− [A] takeEitherSepBy :: (a -> Bool) -> Fold m (Either a b) c -> Parser a m c
875− [A] takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
876− [A] takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
877− [A] subsequenceBy :: (a -> a -> Bool) -> Stream m a -> Parser a m ()
878− [A] streamEqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Parser a m ()
879− [A] split_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
880− [A] splitWith :: Monad m => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
881− [A] splitSome :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
882− [A] splitManyPost :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
883− [A] splitMany :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
884− [A] spanByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (b, c)
885− [A] spanBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (b, c)
886− [A] span :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (b, c)
887− [A] some :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
888− [A] sequence :: Monad m => Stream m (Parser a m b) -> Fold m b c -> Parser a m c
889− [A] sepByAll :: Monad m => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
890− [A] sepBy1 :: Monad m => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
891− [A] sepBy :: Monad m => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
892− [A] satisfy :: Monad m => (a -> Bool) -> Parser a m a
893− [A] sampleFromthen :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
894− [A] roundRobin :: t (Parser a m b) -> Fold m b c -> Parser a m c
895− [A] rmapM :: Monad m => (b -> m c) -> Parser a m b -> Parser a m c
896− [A] retryMaxTotal :: Int -> Parser a m b -> Fold m b c -> Parser a m c
897− [A] retryMaxSuccessive :: Int -> Parser a m b -> Fold m b c -> Parser a m c
898− [A] retry :: Parser a m b -> Parser a m b
899− [A] postscan :: Fold m a b -> Parser b m c -> Parser a m c
900− [A] peek :: Monad m => Parser a m a
901− [A] oneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
902− [A] oneNotEq :: (Monad m, Eq a) => a -> Parser a m a
903− [A] oneEq :: (Monad m, Eq a) => a -> Parser a m a
904− [A] one :: Monad m => Parser a m a
905− [A] noneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
906− [A] noErrorUnsafeSplit_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
907− [A] noErrorUnsafeSplitWith :: Monad m => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
908− [A] noErrorUnsafeConcatMap :: Monad m => (b -> Parser a m c) -> Parser a m b -> Parser a m c
909− [A] maybe :: Monad m => (a -> Maybe b) -> Parser a m b
910− [A] manyTillP :: Parser a m b -> Parser a m x -> Parser b m c -> Parser a m c
911− [A] manyTill :: Monad m => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
912− [A] manyThen :: Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
913− [A] manyP :: Parser a m b -> Parser b m c -> Parser a m c
914− [A] many :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
915− [A] makeIndexFilter :: (Fold m (s, a) b -> Parser a m b) -> (((s, a) -> Bool) -> Fold m (s, a) b -> Fold m (s, a) b) -> ((s, a) -> Bool) -> Fold m a b -> Parser a m b
916− [A] lookAhead :: Monad m => Parser a m b -> Parser a m b
917− [A] lmapM :: Monad m => (a -> m b) -> Parser b m r -> Parser a m r
918− [A] lmap :: (a -> b) -> Parser b m r -> Parser a m r
919− [A] listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser a m [a]
920− [A] listEq :: (Monad m, Eq a) => [a] -> Parser a m [a]
921− [A] indexed :: forall m a b. Monad m => Fold m (Int, a) b -> Parser a m b
922− [A] groupByRollingEither :: Monad m => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
923− [A] groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
924− [A] groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
925− [A] fromPure :: Monad m => b -> Parser a m b
926− [A] fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
927− [A] fromFold :: Monad m => Fold m a b -> Parser a m b
928− [A] fromEffect :: Monad m => m b -> Parser a m b
929− [A] filter :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
930− [A] extractStep :: Monad m => (s -> m (Step s1 b)) -> Step s b -> m (Step s1 b)
931− [A] eof :: Monad m => Parser a m ()
932− [A] either :: Monad m => (a -> Either String b) -> Parser a m b
933− [A] dropWhile :: Monad m => (a -> Bool) -> Parser a m ()
934− [A] dieM :: Monad m => m String -> Parser a m b
935− [A] die :: Monad m => String -> Parser a m b
936− [A] deintercalateAll :: Monad m => Parser a m x -> Parser a m y -> Fold m (Either x y) z -> Parser a m z
937− [A] deintercalate1 :: Monad m => Parser a m x -> Parser a m y -> Fold m (Either x y) z -> Parser a m z
938− [A] deintercalate :: Monad m => Parser a m x -> Parser a m y -> Fold m (Either x y) z -> Parser a m z
939− [A] countBetween :: Int -> Int -> Parser a m b -> Fold m b c -> Parser a m c
940− [A] count :: Int -> Parser a m b -> Fold m b c -> Parser a m c
941− [A] concatMap :: Monad m => (b -> Parser a m c) -> Parser a m b -> Parser a m c
942− [A] blockWithQuotes :: (Monad m, Eq a) => (a -> Bool) -> (a -> Bool) -> a -> a -> Fold m a b -> Parser a m b
943− [A] bimapOverrideCount :: Int -> (s -> s1) -> (b -> b1) -> Step s b -> Step s1 b1
944− [A] alt :: Monad m => Parser x m a -> Parser x m a -> Parser x m a
945−[A] Streamly.Internal.Data.MutByteArray
946− [A] class Unbox a
947− [A] class SizeOfRep (f :: Type -> Type)
948− [A] class Serialize a
949− [A] TypeOfType
950− [A] UnitType :: Name -> TypeOfType
951− [A] TheType :: SimpleDataCon -> TypeOfType
952− [A] MultiType :: [SimpleDataCon] -> TypeOfType
953− [A] SimpleDataCon
954− [A] SimpleDataCon :: Name -> [Field] -> SimpleDataCon
955− [A] SerializeConfig
956− [A] [cfgRecordSyntaxWithHeader] :: SerializeConfig -> Bool
957− [A] [cfgInlineSize] :: SerializeConfig -> Maybe Inline
958− [A] [cfgInlineSerialize] :: SerializeConfig -> Maybe Inline
959− [A] [cfgInlineDeserialize] :: SerializeConfig -> Maybe Inline
960− [A] [cfgConstructorTagAsString] :: SerializeConfig -> Bool
961− [A] SerializeConfig :: Maybe Inline -> Maybe Inline -> Maybe Inline -> Bool -> Bool -> SerializeConfig
962− [A] PinnedState
963− [A] Unpinned :: PinnedState
964− [A] Pinned :: PinnedState
965− [A] MutByteArray
966− [A] MutByteArray :: MutableByteArray# RealWorld -> MutByteArray
967− [A] DataType
968− [A] [dtTvs] :: DataType -> [Name]
969− [A] [dtName] :: DataType -> Name
970− [A] [dtCxt] :: DataType -> Cxt
971− [A] [dtCons] :: DataType -> [DataCon]
972− [A] DataType :: Name -> [Name] -> Cxt -> [DataCon] -> DataType
973− [A] DataCon
974− [A] [dcTvs] :: DataCon -> [Name]
975− [A] [dcName] :: DataCon -> Name
976− [A] [dcFields] :: DataCon -> [(Maybe Name, Type)]
977− [A] [dcCxt] :: DataCon -> Cxt
978− [A] DataCon :: Name -> [Name] -> Cxt -> [(Maybe Name, Type)] -> DataCon
979− [A] BoundedPtr
980− [A] BoundedPtr :: MutByteArray -> Int -> Int -> BoundedPtr
981− [A] Streamly.Internal.Data.Serialize.Type.Serialize
982− [A] instance Streamly.Internal.Data.Serialize.Type.Serialize Streamly.Internal.Data.MutByteArray.LiftedInteger
983− [A] instance Streamly.Internal.Data.Serialize.Type.Serialize GHC.Num.Integer.Integer
984− [A] instance Streamly.Internal.Data.Serialize.Type.Serialize a => Streamly.Internal.Data.Serialize.Type.Serialize (GHC.Maybe.Maybe a)
985− [A] instance Streamly.Internal.Data.Serialize.Type.Serialize (Data.Proxy.Proxy a)
986− [A] instance (Streamly.Internal.Data.Serialize.Type.Serialize a, Streamly.Internal.Data.Serialize.Type.Serialize b) => Streamly.Internal.Data.Serialize.Type.Serialize (Data.Either.Either a b)
987− [A] Peeker
988− [A] Peeker :: Builder BoundedPtr IO a -> Peeker a
989− [A] type Field = (Maybe Name, Type)
990− [A] xorCmp :: [Word8] -> Name -> Name -> Q Exp
991− [A] wListToString :: [Word8] -> String
992− [A] w8_int :: Word8 -> Int
993− [A] w32_int :: Word32 -> Int
994− [A] unpin :: MutByteArray -> IO MutByteArray
995− [A] typeOfType :: Type -> [DataCon] -> TypeOfType
996− [A] skipByte :: Peeker ()
997− [A] sizeOfRep :: SizeOfRep f => f x -> Int
998− [A] sizeOfMutableByteArray :: MutByteArray -> IO Int
999− [A] sizeOf :: (Unbox a, SizeOfRep (Rep a)) => Proxy a -> Int
1000− [A] simplifyDataCon :: DataCon -> SimpleDataCon
1001− [A] serializeW8List :: Name -> Name -> [Word8] -> Q Exp
1002− [A] serializeConfig :: SerializeConfig
1003− [A] serializeAt :: Serialize a => Int -> MutByteArray -> a -> IO Int
1004− [A] runPeeker :: Peeker a -> BoundedPtr -> IO a
1005− [A] reifyDataType :: Name -> Q DataType
1006− [A] readUnsafe :: Unbox a => Peeker a
1007− [A] read :: Unbox a => Peeker a
1008− [A] putSliceUnsafe :: MonadIO m => MutByteArray -> Int -> MutByteArray -> Int -> Int -> m ()
1009− [A] pokeRep :: PokeRep f => f a -> BoundedPtr -> IO BoundedPtr
1010− [A] pokeBoundedPtrUnsafe :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
1011− [A] pokeBoundedPtr :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
1012− [A] pokeAt :: (Unbox a, Generic a, PokeRep (Rep a)) => Int -> MutByteArray -> a -> IO ()
1013− [A] pinnedNewAlignedBytes :: Int -> Int -> IO MutByteArray
1014− [A] pinnedNew :: Int -> IO MutByteArray
1015− [A] pinnedCloneSliceUnsafe :: MonadIO m => Int -> Int -> MutByteArray -> m MutByteArray
1016− [A] pin :: MutByteArray -> IO MutByteArray
1017− [A] peekRep :: PeekRep f => Peeker (f x)
1018− [A] peekAt :: (Unbox a, Generic a, PeekRep (Rep a)) => Int -> MutByteArray -> IO a
1019− [A] openConstructor :: Name -> Int -> Q Pat
1020− [A] nil :: MutByteArray
1021− [A] newBytesAs :: PinnedState -> Int -> IO MutByteArray
1022− [A] new :: Int -> IO MutByteArray
1023− [A] mkSerializeExprFields :: Name -> [Field] -> Q Exp
1024− [A] mkRecSizeOfExpr :: SimpleDataCon -> Q Exp
1025− [A] mkRecSerializeExpr :: Name -> SimpleDataCon -> Q Exp
1026− [A] mkRecDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
1027− [A] mkFieldName :: Int -> Name
1028− [A] mkDeserializeKeysDec :: Name -> Name -> SimpleDataCon -> Q [Dec]
1029− [A] mkDeserializeExprOne :: Name -> SimpleDataCon -> Q Exp
1030− [A] matchConstructor :: Name -> Int -> Q Exp -> Q Match
1031− [A] makeN :: Int -> Name
1032− [A] makeI :: Int -> Name
1033− [A] makeA :: Int -> Name
1034− [A] litProxy :: Unbox a => Proxy a -> Q Exp
1035− [A] litIntegral :: Integral a => a -> Q Exp
1036− [A] isUnitType :: [DataCon] -> Bool
1037− [A] isRecordSyntax :: SimpleDataCon -> Bool
1038− [A] isPinned :: MutByteArray -> Bool
1039− [A] int_w8 :: Int -> Word8
1040− [A] int_w32 :: Int -> Word32
1041− [A] inlineSerializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
1042− [A] inlineDeserializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
1043− [A] inlineAddSizeTo :: Maybe Inline -> SerializeConfig -> SerializeConfig
1044− [A] getMutableByteArray# :: MutByteArray -> MutableByteArray# RealWorld
1045− [A] genericSizeOf :: forall a. SizeOfRep (Rep a) => Proxy a -> Int
1046− [A] genericPokeByteIndex :: (Generic a, PokeRep (Rep a)) => MutByteArray -> Int -> a -> IO ()
1047− [A] genericPeekByteIndex :: (Generic a, PeekRep (Rep a)) => MutByteArray -> Int -> IO a
1048− [A] errorUnsupported :: String -> a
1049− [A] errorUnimplemented :: a
1050− [A] encodeRecordFields :: Bool -> SerializeConfig -> SerializeConfig
1051− [A] encodeConstrNames :: Bool -> SerializeConfig -> SerializeConfig
1052− [A] deserializeAt :: Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
1053− [A] deriveUnbox :: Q [Dec] -> Q [Dec]
1054− [A] deriveSerializeWith :: (SerializeConfig -> SerializeConfig) -> Q [Dec] -> Q [Dec]
1055− [A] deriveSerialize :: Q [Dec] -> Q [Dec]
1056− [A] conUpdateFuncDec :: Name -> [Field] -> Q [Dec]
1057− [A] cloneSliceUnsafeAs :: MonadIO m => PinnedState -> Int -> Int -> MutByteArray -> m MutByteArray
1058− [A] cloneSliceUnsafe :: MonadIO m => Int -> Int -> MutByteArray -> m MutByteArray
1059− [A] c2w :: Char -> Word8
1060− [A] asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
1061− [A] addSizeTo :: Serialize a => Int -> a -> Int
1062− [A] _x :: Name
1063− [A] _val :: Name
1064− [A] _tag :: Name
1065− [A] _initialOffset :: Name
1066− [A] _endOffset :: Name
1067− [A] _arr :: Name
1068− [A] _acc :: Name
1069−[A] Streamly.Internal.Data.MutArray.Stream
1070− [A] SpliceState
1071− [A] SpliceYielding :: arr -> SpliceState s arr -> SpliceState s arr
1072− [A] SpliceInitial :: s -> SpliceState s arr
1073− [A] SpliceFinish :: SpliceState s arr
1074− [A] SpliceBuffering :: s -> arr -> SpliceState s arr
1075− [A] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
1076− [A] splitOn :: (MonadIO m, Unbox a) => (a -> Bool) -> MutArray a -> Stream m (MutArray a)
1077− [A] pinnedChunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (MutArray a)
1078− [A] packArraysChunksOf :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
1079− [A] lpackArraysChunksOf :: (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
1080− [A] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
1081− [A] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
1082− [A] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
1083− [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (Either ParseError (MutArray a))
1084− [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
1085− [A] compactEQ :: Int -> Stream m (MutArray a) -> Stream m (MutArray a)
1086− [A] compact :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
1087− [A] chunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (MutArray a)
1088−[A] Streamly.Internal.Data.MutArray.Generic
1089− [A] MutArray
1090− [A] [arrTrueLen] :: MutArray a -> {-# UNPACK #-} !Int
1091− [A] [arrStart] :: MutArray a -> {-# UNPACK #-} !Int
1092− [A] [arrLen] :: MutArray a -> {-# UNPACK #-} !Int
1093− [A] [arrContents#] :: MutArray a -> MutableArray# RealWorld a
1094− [A] MutArray :: MutableArray# RealWorld a -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> MutArray a
1095− [A] writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
1096− [A] writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
1097− [A] writeN :: MonadIO m => Int -> Fold m a (MutArray a)
1098− [A] write :: MonadIO m => Fold m a (MutArray a)
1099− [A] uninit :: MonadIO m => MutArray a -> Int -> m (MutArray a)
1100− [A] toStreamK :: MonadIO m => MutArray a -> StreamK m a
1101− [A] toList :: MonadIO m => MutArray a -> m [a]
1102− [A] strip :: MonadIO m => (a -> Bool) -> MutArray a -> m (MutArray a)
1103− [A] snocWith :: MonadIO m => (Int -> Int) -> MutArray a -> a -> m (MutArray a)
1104− [A] snocUnsafe :: MonadIO m => MutArray a -> a -> m (MutArray a)
1105− [A] snoc :: MonadIO m => MutArray a -> a -> m (MutArray a)
1106− [A] realloc :: MonadIO m => Int -> MutArray a -> m (MutArray a)
1107− [A] reader :: MonadIO m => Unfold m (MutArray a) a
1108− [A] readRev :: MonadIO m => MutArray a -> Stream m a
1109− [A] read :: MonadIO m => MutArray a -> Stream m a
1110− [A] putSliceUnsafe :: MonadIO m => MutArray a -> Int -> MutArray a -> Int -> Int -> m ()
1111− [A] putIndices :: MonadIO m => MutArray a -> Fold m (Int, a) ()
1112− [A] putIndexUnsafe :: forall m a. MonadIO m => Int -> MutArray a -> a -> m ()
1113− [A] putIndex :: MonadIO m => Int -> MutArray a -> a -> m ()
1114− [A] producerWith :: Monad m => (forall b. IO b -> m b) -> Producer m (MutArray a) a
1115− [A] producer :: MonadIO m => Producer m (MutArray a) a
1116− [A] nil :: MonadIO m => m (MutArray a)
1117− [A] new :: MonadIO m => Int -> m (MutArray a)
1118− [A] modifyIndexUnsafe :: MonadIO m => Int -> MutArray a -> (a -> (a, b)) -> m b
1119− [A] modifyIndex :: MonadIO m => Int -> MutArray a -> (a -> (a, b)) -> m b
1120− [A] length :: MutArray a -> Int
1121− [A] getSliceUnsafe :: Int -> Int -> MutArray a -> MutArray a
1122− [A] getSlice :: Int -> Int -> MutArray a -> MutArray a
1123− [A] getIndexUnsafeWith :: MonadIO m => MutableArray# RealWorld a -> Int -> m a
1124− [A] getIndexUnsafe :: MonadIO m => Int -> MutArray a -> m a
1125− [A] getIndex :: MonadIO m => Int -> MutArray a -> m (Maybe a)
1126− [A] fromStreamN :: MonadIO m => Int -> Stream m a -> m (MutArray a)
1127− [A] fromStream :: MonadIO m => Stream m a -> m (MutArray a)
1128− [A] fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
1129− [A] fromListN :: MonadIO m => Int -> [a] -> m (MutArray a)
1130− [A] fromList :: MonadIO m => [a] -> m (MutArray a)
1131− [A] eq :: (MonadIO m, Eq a) => MutArray a -> MutArray a -> m Bool
1132− [A] cmp :: (MonadIO m, Ord a) => MutArray a -> MutArray a -> m Ordering
1133− [A] clone :: MonadIO m => MutArray a -> m (MutArray a)
1134− [A] chunksOf :: forall m a. MonadIO m => Int -> Stream m a -> Stream m (MutArray a)
1135−[A] Streamly.Internal.Data.MutArray
1136− [A] MutByteArray
1137− [A] MutArray
1138− [A] [arrStart] :: MutArray a -> {-# UNPACK #-} !Int
1139− [A] [arrEnd] :: MutArray a -> {-# UNPACK #-} !Int
1140− [A] [arrContents] :: MutArray a -> {-# UNPACK #-} !MutByteArray
1141− [A] [arrBound] :: MutArray a -> {-# UNPACK #-} !Int
1142− [A] MutArray :: {-# UNPACK #-} !MutByteArray -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> MutArray a
1143− [A] IORef
1144− [A] ArrayUnsafe
1145− [A] ArrayUnsafe :: {-# UNPACK #-} !MutByteArray -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> ArrayUnsafe a
1146− [A] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1147− [A] writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1148− [A] writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1149− [A] writeNWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1150− [A] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1151− [A] writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1152− [A] writeIORef :: Unbox a => IORef a -> a -> IO ()
1153− [A] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
1154− [A] writeAppendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
1155− [A] writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
1156− [A] writeAppendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
1157− [A] writeAppend :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
1158− [A] write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1159− [A] unsafeSwapIndices :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> MutArray a -> m ()
1160− [A] unpin :: MutArray a -> IO (MutArray a)
1161− [A] toStreamKWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> StreamK m a
1162− [A] toStreamKRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> StreamK m a
1163− [A] toStreamKRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1164− [A] toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1165− [A] toStreamDWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
1166− [A] toStreamDRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
1167− [A] toList :: forall m a. (MonadIO m, Unbox a) => MutArray a -> m [a]
1168− [A] swapIndices :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> MutArray a -> m ()
1169− [A] strip :: forall a m. (Unbox a, MonadIO m) => (a -> Bool) -> MutArray a -> m (MutArray a)
1170− [A] splitOn :: (MonadIO m, Unbox a) => (a -> Bool) -> MutArray a -> Stream m (MutArray a)
1171− [A] splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
1172− [A] spliceWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
1173− [A] spliceUnsafe :: MonadIO m => MutArray a -> MutArray a -> m (MutArray a)
1174− [A] spliceExp :: (MonadIO m, Unbox a) => MutArray a -> MutArray a -> m (MutArray a)
1175− [A] spliceCopy :: forall m a. MonadIO m => MutArray a -> MutArray a -> m (MutArray a)
1176− [A] splice :: (MonadIO m, Unbox a) => MutArray a -> MutArray a -> m (MutArray a)
1177− [A] snocWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> MutArray a -> a -> m (MutArray a)
1178− [A] snocUnsafe :: forall m a. (MonadIO m, Unbox a) => MutArray a -> a -> m (MutArray a)
1179− [A] snocMay :: forall m a. (MonadIO m, Unbox a) => MutArray a -> a -> m (Maybe (MutArray a))
1180− [A] snocLinear :: forall m a. (MonadIO m, Unbox a) => MutArray a -> a -> m (MutArray a)
1181− [A] snoc :: forall m a. (MonadIO m, Unbox a) => MutArray a -> a -> m (MutArray a)
1182− [A] shuffleBy :: (a -> a -> m Bool) -> MutArray a -> MutArray a -> m ()
1183− [A] roundUpToPower2 :: Int -> Int
1184− [A] rightSize :: forall m a. (MonadIO m, Unbox a) => MutArray a -> m (MutArray a)
1185− [A] reverse :: forall m a. (MonadIO m, Unbox a) => MutArray a -> m ()
1186− [A] resizeExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
1187− [A] resize :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
1188− [A] realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
1189− [A] readerRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Unfold m (MutArray a) a
1190− [A] readerRev :: forall m a. (MonadIO m, Unbox a) => Unfold m (MutArray a) a
1191− [A] reader :: forall m a. (MonadIO m, Unbox a) => Unfold m (MutArray a) a
1192− [A] readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> Stream m a
1193− [A] readIORef :: Unbox a => IORef a -> IO a
1194− [A] read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> Stream m a
1195− [A] putIndices :: forall m a. (MonadIO m, Unbox a) => MutArray a -> Fold m (Int, a) ()
1196− [A] putIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m ()
1197− [A] putIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m ()
1198− [A] producerWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Producer m (MutArray a) a
1199− [A] producer :: forall m a. (MonadIO m, Unbox a) => Producer m (MutArray a) a
1200− [A] pollIntIORef :: (MonadIO m, Unbox a) => IORef a -> Stream m a
1201− [A] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1202− [A] pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> Fold m a (MutArray a)
1203− [A] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1204− [A] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1205− [A] pinnedNewBytes :: MonadIO m => Int -> m (MutArray a)
1206− [A] pinnedNewAligned :: (MonadIO m, Unbox a) => Int -> Int -> m (MutArray a)
1207− [A] pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
1208− [A] pinnedFromListN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
1209− [A] pinnedFromList :: (MonadIO m, Unbox a) => [a] -> m (MutArray a)
1210− [A] pinnedClone :: MonadIO m => MutArray a -> m (MutArray a)
1211− [A] pinnedChunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (MutArray a)
1212− [A] pin :: MutArray a -> IO (MutArray a)
1213− [A] permute :: MutArray a -> m Bool
1214− [A] partitionBy :: forall m a. (MonadIO m, Unbox a) => (a -> Bool) -> MutArray a -> m (MutArray a, MutArray a)
1215− [A] nil :: MutArray a
1216− [A] newIORef :: forall a. Unbox a => a -> IO (IORef a)
1217− [A] newArrayWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int -> m MutByteArray) -> Int -> Int -> m (MutArray a)
1218− [A] new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
1219− [A] modifyIndices :: forall m a. (MonadIO m, Unbox a) => MutArray a -> (Int -> a -> a) -> Fold m Int ()
1220− [A] modifyIndexUnsafe :: forall m a b. (MonadIO m, Unbox a) => Int -> MutArray a -> (a -> (a, b)) -> m b
1221− [A] modifyIndex :: forall m a b. (MonadIO m, Unbox a) => Int -> MutArray a -> (a -> (a, b)) -> m b
1222− [A] modifyIORef' :: Unbox a => IORef a -> (a -> a) -> IO ()
1223− [A] modify :: forall m a. (MonadIO m, Unbox a) => MutArray a -> (a -> a) -> m ()
1224− [A] mergeBy :: Int -> (MutArray a -> MutArray a -> m ()) -> MutArray a -> m ()
1225− [A] memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
1226− [A] memcmp :: Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
1227− [A] length :: forall a. Unbox a => MutArray a -> Int
1228− [A] isPinned :: MutArray a -> Bool
1229− [A] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
1230− [A] getSliceUnsafe :: forall a. Unbox a => Int -> Int -> MutArray a -> MutArray a
1231− [A] getSlice :: forall a. Unbox a => Int -> Int -> MutArray a -> MutArray a
1232− [A] getIndicesD :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
1233− [A] getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1234− [A] getIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1235− [A] getIndexRev :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1236− [A] getIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (Maybe a)
1237− [A] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
1238− [A] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
1239− [A] fromStreamD :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
1240− [A] fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
1241− [A] fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
1242− [A] fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
1243− [A] fromListRev :: (MonadIO m, Unbox a) => [a] -> m (MutArray a)
1244− [A] fromListN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
1245− [A] fromList :: (MonadIO m, Unbox a) => [a] -> m (MutArray a)
1246− [A] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
1247− [A] foldr :: (MonadIO m, Unbox a) => (a -> b -> b) -> b -> MutArray a -> m b
1248− [A] foldl' :: (MonadIO m, Unbox a) => (b -> a -> b) -> b -> MutArray a -> m b
1249− [A] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
1250− [A] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
1251− [A] divideBy :: Int -> (MutArray a -> m (MutArray a, MutArray a)) -> MutArray a -> m ()
1252− [A] cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
1253− [A] clone :: MonadIO m => MutArray a -> m (MutArray a)
1254− [A] chunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (MutArray a)
1255− [A] castUnsafe :: MutArray a -> MutArray b
1256− [A] cast :: forall a b. Unbox b => MutArray a -> Maybe (MutArray b)
1257− [A] c_memchr :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)
1258− [A] bytesFree :: MutArray a -> Int
1259− [A] byteLength :: MutArray a -> Int
1260− [A] byteCapacity :: MutArray a -> Int
1261− [A] bubble :: (MonadIO m, Unbox a) => (a -> a -> Ordering) -> MutArray a -> m ()
1262− [A] breakOn :: MonadIO m => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
1263− [A] blockSize :: Int
1264− [A] asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
1265− [A] asBytes :: MutArray a -> MutArray Word8
1266− [A] arrayChunkBytes :: Int
1267− [A] allocBytesToElemCount :: Unbox a => a -> Int -> Int
1268−[C] Streamly.Internal.Data.IsMap
1269− [A] mapTraverseWithKey :: (IsMap f, Applicative t) => (Key f -> a -> t b) -> f a -> t (f b)
1270−[R] Streamly.Internal.Data.IORef.Unboxed
1271−[R] Streamly.Internal.Data.Fold.Window
1272−[R] Streamly.Internal.Data.Fold.Type
1273−[R] Streamly.Internal.Data.Fold.Tee
1274−[R] Streamly.Internal.Data.Fold.Step
1275−[R] Streamly.Internal.Data.Fold.Container
1276−[D] Streamly.Internal.Data.Fold.Chunked
1277−[C] Streamly.Internal.Data.Fold
1278− [A] ManyState
1279− [C] Fold
1280− [C] Fold
1281− [O] Fold :: (s -> a -> m (Step s b)) -> m (Step s b) -> (s -> m b) -> Fold m a b
1282− [N] Fold :: (s -> a -> m (Step s b)) -> m (Step s b) -> (s -> m b) -> (s -> m b) -> Fold m a b
1283− [A] windowSumInt :: forall m a. (Monad m, Integral a) => Fold m (a, Maybe a) a
1284− [A] windowSum :: forall m a. (Monad m, Num a) => Fold m (a, Maybe a) a
1285− [A] windowRollingMapM :: Monad m => (Maybe a -> a -> m (Maybe b)) -> Fold m (a, Maybe a) (Maybe b)
1286− [A] windowRollingMap :: Monad m => (Maybe a -> a -> Maybe b) -> Fold m (a, Maybe a) (Maybe b)
1287− [A] windowRange :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe (a, a))
1288− [A] windowPowerSumFrac :: (Monad m, Floating a) => a -> Fold m (a, Maybe a) a
1289− [A] windowPowerSum :: (Monad m, Num a) => Int -> Fold m (a, Maybe a) a
1290− [A] windowMinimum :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe a)
1291− [A] windowMean :: forall m a. (Monad m, Fractional a) => Fold m (a, Maybe a) a
1292− [A] windowMaximum :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe a)
1293− [A] windowLmap :: (c -> a) -> Fold m (a, Maybe a) b -> Fold m (c, Maybe c) b
1294− [A] windowLength :: (Monad m, Num b) => Fold m (a, Maybe a) b
1295− [A] toSet :: (Monad m, Ord a) => Fold m a (Set a)
1296− [A] toMapIO :: (MonadIO m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1297− [A] toMap :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (Map k b)
1298− [A] toIntSet :: Monad m => Fold m Int IntSet
1299− [A] toContainerIO :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) => (a -> Key f) -> Fold m a b -> Fold m a (f b)
1300− [A] toContainer :: (Monad m, IsMap f, Traversable f, Ord (Key f)) => (a -> Key f) -> Fold m a b -> Fold m a (f b)
1301− [A] nubInt :: Monad m => Fold m Int (Maybe Int)
1302− [A] nub :: (Monad m, Ord a) => Fold m a (Maybe a)
1303− [A] mapMStep :: Applicative m => (a -> m b) -> Step s a -> m (Step s b)
1304− [A] kvToMap :: (Monad m, Ord k) => Fold m a b -> Fold m (k, a) (Map k b)
1305− [A] frequency :: (Monad m, Ord a) => Fold m a (Map a Int)
1306− [A] demuxToMapIO :: (MonadIO m, Ord k) => (a -> k) -> (a -> m (Fold m a b)) -> Fold m a (Map k b)
1307− [A] demuxToMap :: (Monad m, Ord k) => (a -> k) -> (a -> m (Fold m a b)) -> Fold m a (Map k b)
1308− [A] demuxToContainerIO :: (MonadIO m, IsMap f, Traversable f) => (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
1309− [A] demuxToContainer :: (Monad m, IsMap f, Traversable f) => (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
1310− [A] demuxKvToMap :: (Monad m, Ord k) => (k -> m (Fold m a b)) -> Fold m (k, a) (Map k b)
1311− [A] demuxKvToContainer :: (Monad m, IsMap f, Traversable f) => (Key f -> m (Fold m a b)) -> Fold m (Key f, a) (f b)
1312− [A] demuxIO :: (MonadIO m, Ord k) => (a -> k) -> (a -> m (Fold m a b)) -> Fold m a (m (Map k b), Maybe (k, b))
1313− [A] demuxGenericIO :: (MonadIO m, IsMap f, Traversable f) => (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (m (f b), Maybe (Key f, b))
1314− [A] demuxGeneric :: (Monad m, IsMap f, Traversable f) => (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (m (f b), Maybe (Key f, b))
1315− [A] demux :: (Monad m, Ord k) => (a -> k) -> (a -> m (Fold m a b)) -> Fold m a (m (Map k b), Maybe (k, b))
1316− [A] cumulative :: Fold m (a, Maybe a) b -> Fold m a b
1317− [A] countDistinctInt :: Monad m => Fold m Int Int
1318− [A] countDistinct :: (Monad m, Ord a) => Fold m a Int
1319− [A] classifyIO :: (MonadIO m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (m (Map k b), Maybe (k, b))
1320− [A] classifyGenericIO :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) => (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
1321− [A] classifyGeneric :: (Monad m, IsMap f, Traversable f, Ord (Key f)) => (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
1322− [A] classify :: (Monad m, Ord k) => (a -> k) -> Fold m a b -> Fold m a (m (Map k b), Maybe (k, b))
1323− [A] chainStepM :: Applicative m => (s1 -> m s2) -> (a -> m (Step s2 b)) -> Step s1 a -> m (Step s2 b)
1324−[C] Streamly.Internal.Data.Builder
1325− [C] Builder
1326− [C] Builder
1327− [O] Builder :: (s -> m (s, a)) -> Builder s m a
1328− [N] Builder :: (s -> m (a, s)) -> Builder s m a
1329−[A] Streamly.Internal.Data.Binary.Stream
1330− [A] class ToBytes a
1331− [A] word8 :: Applicative m => Word8 -> Stream m Word8
1332− [A] word64le :: Monad m => Word64 -> Stream m Word8
1333− [A] word64host :: Monad m => Word64 -> Stream m Word8
1334− [A] word64be :: Monad m => Word64 -> Stream m Word8
1335− [A] word32le :: Monad m => Word32 -> Stream m Word8
1336− [A] word32be :: Monad m => Word32 -> Stream m Word8
1337− [A] word16le :: Monad m => Word16 -> Stream m Word8
1338− [A] word16be :: Monad m => Word16 -> Stream m Word8
1339− [A] unit :: Applicative m => Stream m Word8
1340− [A] toBytes :: ToBytes a => a -> Stream m Word8
1341− [A] ordering :: Applicative m => Ordering -> Stream m Word8
1342− [A] int8 :: Applicative m => Int8 -> Stream m Word8
1343− [A] int64le :: Monad m => Int64 -> Stream m Word8
1344− [A] int64be :: Monad m => Int64 -> Stream m Word8
1345− [A] int32le :: Monad m => Int32 -> Stream m Word8
1346− [A] int32be :: Monad m => Int32 -> Stream m Word8
1347− [A] int16le :: Monad m => Int16 -> Stream m Word8
1348− [A] int16be :: Monad m => Int16 -> Stream m Word8
1349− [A] float32le :: Monad m => Float -> Stream m Word8
1350− [A] float32be :: Monad m => Float -> Stream m Word8
1351− [A] double64le :: Monad m => Double -> Stream m Word8
1352− [A] double64be :: Monad m => Double -> Stream m Word8
1353− [A] charUtf8 :: Monad m => Char -> Stream m Word8
1354− [A] charLatin1 :: Applicative m => Char -> Stream m Word8
1355− [A] bool :: Applicative m => Bool -> Stream m Word8
1356−[A] Streamly.Internal.Data.Binary.Parser
1357− [A] class FromBytes a
1358− [A] word8 :: Monad m => Parser Word8 m Word8
1359− [A] word64le :: Monad m => Parser Word8 m Word64
1360− [A] word64host :: MonadIO m => Parser Word8 m Word64
1361− [A] word64be :: Monad m => Parser Word8 m Word64
1362− [A] word32le :: Monad m => Parser Word8 m Word32
1363− [A] word32be :: Monad m => Parser Word8 m Word32
1364− [A] word16le :: Monad m => Parser Word8 m Word16
1365− [A] word16be :: Monad m => Parser Word8 m Word16
1366− [A] unit :: Monad m => Parser Word8 m ()
1367− [A] ordering :: Monad m => Parser Word8 m Ordering
1368− [A] int8 :: Monad m => Parser Word8 m Int8
1369− [A] int64le :: Monad m => Parser Word8 m Int64
1370− [A] int64be :: Monad m => Parser Word8 m Int64
1371− [A] int32le :: Monad m => Parser Word8 m Int32
1372− [A] int32be :: Monad m => Parser Word8 m Int32
1373− [A] int16le :: Monad m => Parser Word8 m Int16
1374− [A] int16be :: Monad m => Parser Word8 m Int16
1375− [A] fromBytes :: FromBytes a => Parser Word8 m a
1376− [A] float32le :: MonadIO m => Parser Word8 m Float
1377− [A] float32be :: MonadIO m => Parser Word8 m Float
1378− [A] eqWord8 :: Monad m => Word8 -> Parser Word8 m Word8
1379− [A] double64le :: MonadIO m => Parser Word8 m Double
1380− [A] double64be :: MonadIO m => Parser Word8 m Double
1381− [A] charLatin1 :: Monad m => Parser Word8 m Char
1382− [A] bool :: Monad m => Parser Word8 m Bool
1383−[R] Streamly.Internal.Data.Array.Type
1384−[A] Streamly.Internal.Data.Array.Stream
1385− [A] unlines :: forall m a. (MonadIO m, Unbox a) => a -> Stream m (Array a) -> Stream m a
1386− [A] toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
1387− [A] splitOnSuffix :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
1388− [A] splitOn :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
1389− [A] runArrayParserDBreak :: forall m a b. (MonadIO m, Unbox a) => Parser (Array a) m b -> Stream m (Array a) -> m (Either ParseError b, Stream m (Array a))
1390− [A] runArrayFoldMany :: (Monad m, Unbox a) => ChunkFold m a b -> StreamK m (Array a) -> StreamK m (Either ParseError b)
1391− [A] runArrayFoldBreak :: (MonadIO m, Unbox a) => ChunkFold m a b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
1392− [A] runArrayFold :: (MonadIO m, Unbox a) => ChunkFold m a b -> StreamK m (Array a) -> m (Either ParseError b)
1393− [A] pinnedChunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (Array a)
1394− [A] parseChunks :: (Monad m, Unbox a) => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b)
1395− [A] parseBreakChunks :: (Monad m, Unbox a) => ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
1396− [A] parseBreak :: (MonadIO m, Unbox a) => Parser a m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
1397− [A] lpackArraysChunksOf :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
1398− [A] interposeSuffix :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
1399− [A] interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
1400− [A] intercalateSuffix :: (Monad m, Unbox a) => Array a -> Stream m (Array a) -> Stream m a
1401− [A] foldBreakD :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
1402− [A] foldBreak :: (MonadIO m, Unbox a) => Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
1403− [A] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
1404− [A] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
1405− [A] concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
1406− [A] concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
1407− [A] compact :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
1408− [A] chunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (Array a)
1409− [A] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
1410−[R] Streamly.Internal.Data.Array.Mut.Type
1411−[R] Streamly.Internal.Data.Array.Mut.Stream
1412−[R] Streamly.Internal.Data.Array.Mut
1413−[R] Streamly.Internal.Data.Array.Generic.Mut.Type
1414−[C] Streamly.Internal.Data.Array.Generic
1415− [A] getIndex :: Int -> Array a -> Maybe a
1416− [A] fromPureStream :: Stream Identity a -> Array a
1417− [A] fromByteStr# :: Addr# -> Array Word8
1418− [A] chunksOf :: forall m a. MonadIO m => Int -> Stream m a -> Stream m (Array a)
1419−[C] Streamly.Internal.Data.Array
1420− [A] ArrayUnsafe
1421− [A] ArrayUnsafe :: {-# UNPACK #-} !MutByteArray -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> ArrayUnsafe a
1422− [C] Array
1423− [A] [arrStart] :: Array a -> {-# UNPACK #-} !Int
1424− [A] [arrEnd] :: Array a -> {-# UNPACK #-} !Int
1425− [A] [arrContents] :: Array a -> {-# UNPACK #-} !MutByteArray
1426− [A] Array :: {-# UNPACK #-} !MutByteArray -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> Array a
1427− [A] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
1428− [A] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
1429− [R] writeNAligned :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> Fold m a (Array a)
1430− [A] unsafeMakePure :: Monad m => Fold IO a b -> Fold m a b
1431− [A] unsafeIndexIO :: forall a. Unbox a => Int -> Array a -> IO a
1432− [D] unsafeIndex :: forall a. Unbox a => Int -> Array a -> a
1433− [A] unsafeFreezeWithShrink :: Unbox a => MutArray a -> Array a
1434− [A] unpin :: Array a -> IO (Array a)
1435− [A] toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> StreamK m a
1436− [A] toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> StreamK m a
1437− [A] toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
1438− [A] toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
1439− [A] splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
1440− [A] splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
1441− [A] serialize :: Serialize a => a -> Array Word8
1442− [A] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
1443− [A] pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> Fold m a (Array a)
1444− [A] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
1445− [A] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
1446− [A] pinnedSerialize :: Serialize a => a -> Array Word8
1447− [A] pinnedFromListN :: Unbox a => Int -> [a] -> Array a
1448− [A] pinnedFromList :: Unbox a => [a] -> Array a
1449− [A] pinnedClone :: MonadIO m => Array a -> m (Array a)
1450− [A] pinnedChunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (Array a)
1451− [A] pin :: Array a -> IO (Array a)
1452− [A] nil :: Array a
1453− [A] isPinned :: Array a -> Bool
1454− [A] getIndexUnsafe :: forall a. Unbox a => Int -> Array a -> a
1455− [A] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
1456− [A] fromStreamD :: forall m a. (MonadIO m, Unbox a) => Stream m a -> m (Array a)
1457− [A] fromPureStream :: Unbox a => Stream Identity a -> Array a
1458− [A] fromListRevN :: Unbox a => Int -> [a] -> Array a
1459− [A] fromListRev :: Unbox a => [a] -> Array a
1460− [A] fromByteStr# :: Addr# -> Array Word8
1461− [A] foldr :: Unbox a => (a -> b -> b) -> b -> Array a -> b
1462− [A] foldl' :: forall a b. Unbox a => (b -> a -> b) -> b -> Array a -> b
1463− [A] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
1464− [A] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
1465− [A] encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
1466− [A] deserialize :: Serialize a => Array Word8 -> a
1467− [A] clone :: MonadIO m => Array a -> m (Array a)
1468− [A] chunksOf :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> Stream m (Array a)
1469− [A] byteLength :: Array a -> Int
1470− [A] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
1471− [A] breakOn :: MonadIO m => Word8 -> Array Word8 -> m (Array Word8, Maybe (Array Word8))
core/docs/ApiChangelogs/0.2.0-0.2.2.txtdeleted−306
@@ -1,306 +0,0 @@
1−---------------------------------
2−API Annotations
3−---------------------------------
4−
5−[A] : Added
6−[R] : Removed
7−[C] : Changed
8−[O] : Old definition
9−[N] : New definition
10−[D] : Deprecated
11−
12−---------------------------------
13−API diff
14−---------------------------------
15−
16−[C] Streamly.Data.Stream
17− [A] (FixityR,5)
18− [A] (FixityR,5)
19−[C] Streamly.Data.MutArray.Generic
20− [A] emptyOf :: MonadIO m => Int -> m (MutArray a)
21− [A] createOf :: MonadIO m => Int -> Fold m a (MutArray a)
22− [A] create :: MonadIO m => Fold m a (MutArray a)
23−[C] Streamly.Data.MutArray
24− [A] pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
25− [A] emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
26− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
27− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
28− [A] appendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
29− [A] append :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
30−[C] Streamly.Data.Array.Generic
31− [A] createOf :: MonadIO m => Int -> Fold m a (Array a)
32− [A] create :: MonadIO m => Fold m a (Array a)
33−[C] Streamly.Data.Array
34− [A] class Serialize a
35− [A] serializeAt :: Serialize a => Int -> MutByteArray -> a -> IO Int
36− [A] pinnedSerialize :: Serialize a => a -> Array Word8
37− [A] deserializeAt :: Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
38− [A] deserialize :: Serialize a => Array Word8 -> a
39− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
40− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
41− [A] addSizeTo :: Serialize a => Int -> a -> Int
42−
43−---------------------------------
44−Internal API diff
45−---------------------------------
46−
47−[C] Streamly.Internal.Unicode.Stream
48− [A] encodeUtf16le' :: Stream m Char -> Stream m Word16
49− [A] decodeUtf16le' :: Stream m Word16 -> Stream m Char
50−[A] Streamly.Internal.FileSystem.Path
51− [A] class IsPath a
52− [A] Rel
53− [A] File
54− [A] Dir
55− [A] Abs
56− [A] Streamly.Internal.FileSystem.Path.IsPath
57− [A] instance Streamly.Internal.FileSystem.Path.IsPath Streamly.Internal.FileSystem.Path.Path
58− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel Streamly.Internal.FileSystem.Path.Path)
59− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path))
60− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path))
61− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path)
62− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path)
63− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs Streamly.Internal.FileSystem.Path.Path)
64− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path))
65− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path))
66− [A] GHC.Show.Show
67− [A] instance GHC.Show.Show Streamly.Internal.FileSystem.Path.PathException
68− [A] GHC.Exception.Type.Exception
69− [A] instance GHC.Exception.Type.Exception Streamly.Internal.FileSystem.Path.PathException
70− [A] GHC.Classes.Eq
71− [A] instance GHC.Classes.Eq Streamly.Internal.FileSystem.Path.PathException
72− [A] Path
73− [A] Path :: Array Word8 -> Path
74− [A] toString :: Path -> [Char]
75− [A] toPath :: IsPath a => a -> Path
76− [A] toChunk :: Path -> Array Word8
77− [A] toChars :: Monad m => Path -> Stream m Char
78− [A] relfile :: QuasiQuoter
79− [A] reldir :: QuasiQuoter
80− [A] rel :: QuasiQuoter
81− [A] primarySeparator :: Char
82− [A] path :: QuasiQuoter
83− [A] mkRelFile :: String -> Q Exp
84− [A] mkRelDir :: String -> Q Exp
85− [A] mkRel :: String -> Q Exp
86− [A] mkPath :: String -> Q Exp
87− [A] mkFile :: String -> Q Exp
88− [A] mkDir :: String -> Q Exp
89− [A] mkAbsFile :: String -> Q Exp
90− [A] mkAbsDir :: String -> Q Exp
91− [A] mkAbs :: String -> Q Exp
92− [A] isSeparator :: Char -> Bool
93− [A] fromString :: MonadThrow m => [Char] -> m Path
94− [A] fromPathUnsafe :: IsPath a => Path -> a
95− [A] fromPath :: (IsPath a, MonadThrow m) => Path -> m a
96− [A] fromChunkUnsafe :: Array Word8 -> Path
97− [A] fromChunk :: MonadThrow m => Array Word8 -> m Path
98− [A] fromChars :: MonadThrow m => Stream Identity Char -> m Path
99− [A] file :: QuasiQuoter
100− [A] extendPath :: Path -> Path -> Path
101− [A] extendDir :: (IsPath (a (Dir Path)), IsPath b, IsPath (a b)) => a (Dir Path) -> Rel b -> a b
102− [A] dir :: QuasiQuoter
103− [A] adaptPath :: (MonadThrow m, IsPath a, IsPath b) => a -> m b
104− [A] absfile :: QuasiQuoter
105− [A] absdir :: QuasiQuoter
106− [A] abs :: QuasiQuoter
107−[C] Streamly.Internal.Data.Stream
108− [A] (FixityR,5)
109− [A] (FixityR,5)
110− [C] splitInnerBySuffix
111− [O] splitInnerBySuffix :: (Monad m, Eq (f a), Monoid (f a)) => (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
112− [N] splitInnerBySuffix :: Monad m => (f a -> Bool) -> (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
113− [D] sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
114− [A] indexOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
115−[C] Streamly.Internal.Data.MutByteArray
116− [A] unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
117− [A] unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
118− [D] nil :: MutByteArray
119− [A] empty :: MutByteArray
120− [D] asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
121−[D] Streamly.Internal.Data.MutArray.Stream
122− [D] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
123− [D] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
124− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
125− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
126−[C] Streamly.Internal.Data.MutArray.Generic
127− [D] writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
128− [D] writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
129− [A] unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
130− [A] emptyOf :: MonadIO m => Int -> m (MutArray a)
131− [A] createWith :: MonadIO m => Int -> Fold m a (MutArray a)
132− [A] createOf :: MonadIO m => Int -> Fold m a (MutArray a)
133− [A] create :: MonadIO m => Fold m a (MutArray a)
134−[C] Streamly.Internal.Data.MutArray
135− [A] SpliceState
136− [A] SpliceYielding :: arr -> SpliceState s arr -> SpliceState s arr
137− [A] SpliceInitial :: s -> SpliceState s arr
138− [A] SpliceFinish :: SpliceState s arr
139− [A] SpliceBuffering :: s -> arr -> SpliceState s arr
140− [R] MutByteArray
141− [D] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
142− [D] writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
143− [D] writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
144− [D] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
145− [D] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
146− [D] writeAppendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
147− [D] writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
148− [A] unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
149− [A] unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
150− [A] unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
151− [A] unsafeCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
152− [A] unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
153− [A] unsafeAppendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
154− [A] toStreamWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
155− [A] toStreamRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
156− [R] toStreamDWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
157− [R] toStreamDRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
158− [A] slicerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
159− [A] sliceIndexerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
160− [A] revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
161− [D] resizeExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
162− [D] resize :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
163− [A] pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
164− [A] pokeAppendMay :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> a -> m (Maybe (MutArray Word8))
165− [A] pokeAppend :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> a -> m (MutArray Word8)
166− [D] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
167− [D] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
168− [D] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
169− [D] pinnedNewBytes :: MonadIO m => Int -> m (MutArray a)
170− [A] pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
171− [A] pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
172− [A] pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
173− [A] pinnedCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
174− [A] peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> m (a, MutArray Word8)
175− [A] peekUncons :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> m (Maybe a, MutArray Word8)
176− [A] peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
177− [A] pPinnedCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Parser (MutArray a) m (MutArray a)
178− [A] pCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Parser (MutArray a) m (MutArray a)
179− [D] nil :: MutArray a
180− [A] lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
181− [A] lCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
182− [A] indexReaderWith :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
183− [A] indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
184− [A] growExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
185− [A] grow :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
186− [D] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
187− [R] getIndicesD :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
188− [D] getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
189− [D] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
190− [A] fromStreamN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
191− [D] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
192− [D] fromStreamD :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
193− [A] fromPureStreamN :: (MonadIO m, Unbox a) => Int -> Stream Identity a -> m (MutArray a)
194− [A] fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
195− [A] fromChunksRealloced :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> m (MutArray a)
196− [A] fromChunksK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
197− [A] fromByteStr# :: MonadIO m => Addr# -> m (MutArray Word8)
198− [D] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
199− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
200− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
201− [A] fPinnedCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) (MutArray a)
202− [A] fCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) (MutArray a)
203− [A] emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
204− [A] empty :: MutArray a
205− [A] createWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
206− [A] createOfWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
207− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
208− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
209− [A] concatWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m (MutArray a) -> Stream m a
210− [A] concatRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m (MutArray a) -> Stream m a
211− [A] concatRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
212− [A] concat :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
213− [A] compactOnByteSuffix :: MonadIO m => Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
214− [A] compactOnByte :: MonadIO m => Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
215− [A] compactLeAs :: forall m a. (MonadIO m, Unbox a) => PinnedState -> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
216− [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
217− [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
218− [A] compactEQ :: Int -> Stream m (MutArray a) -> Stream m (MutArray a)
219− [D] cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
220− [A] byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
221− [A] byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
222− [A] buildChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
223− [D] asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
224− [A] appendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
225− [A] appendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
226− [A] append :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
227−[D] Streamly.Internal.Data.Array.Stream
228− [C] interposeSuffix
229− [O] interposeSuffix :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
230− [N] interposeSuffix :: forall m a. (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
231− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
232− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
233− [C] concatRev
234− [O] concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
235− [N] concatRev :: forall m a. (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
236− [D] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
237−[C] Streamly.Internal.Data.Array.Generic
238− [A] createOf :: MonadIO m => Int -> Fold m a (Array a)
239− [A] create :: MonadIO m => Fold m a (Array a)
240−[C] Streamly.Internal.Data.Array
241− [R] ArrayUnsafe
242− [D] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
243− [D] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
244− [A] unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
245− [A] unsafePinnedAsPtr :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
246− [A] unsafeCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
247− [D] toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
248− [D] toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
249− [C] splice
250− [O] splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
251− [N] splice :: MonadIO m => Array a -> Array a -> m (Array a)
252− [A] slicerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Array a)
253− [A] sliceIndexerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Int, Int)
254− [D] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
255− [D] pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> Fold m a (Array a)
256− [D] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
257− [D] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
258− [A] pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
259− [A] pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
260− [A] pinnedCompactLE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
261− [A] parseBreakChunksK :: forall m a b. (MonadIO m, Unbox a) => Parser a m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
262− [D] nil :: Array a
263− [A] lPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
264− [A] lCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
265− [A] interposeSuffix :: forall m a. (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
266− [A] interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
267− [A] intercalateSuffix :: (Monad m, Unbox a) => Array a -> Stream m (Array a) -> Stream m a
268− [A] indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
269− [A] indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
270− [A] indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
271− [D] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Array a)
272− [R] getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
273− [D] getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
274− [D] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Int, Int)
275− [D] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
276− [D] fromStreamD :: forall m a. (MonadIO m, Unbox a) => Stream m a -> m (Array a)
277− [A] fromPureStreamN :: Unbox a => Int -> Stream Identity a -> Array a
278− [A] fromPtrN :: Int -> Ptr Word8 -> Array Word8
279− [A] fromChunksK :: (MonadIO m, Unbox a) => StreamK m (Array a) -> m (Array a)
280− [A] fromChunks :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
281− [A] fromByteStr :: Ptr Word8 -> Array Word8
282− [A] foldChunks :: (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m b
283− [A] foldBreakChunksK :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
284− [A] foldBreakChunks :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
285− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
286− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
287− [C] findIndicesOf
288− [O] findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
289− [N] findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
290− [A] fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
291− [A] fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
292− [A] empty :: Array a
293− [A] createWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
294− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
295− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
296− [A] concatRev :: forall m a. (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
297− [A] concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
298− [A] compactOnByteSuffix :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
299− [A] compactOnByte :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
300− [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
301− [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
302− [A] byteEq :: Array a -> Array a -> Bool
303− [A] byteCmp :: Array a -> Array a -> Ordering
304− [A] buildChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
305− [D] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
306− [D] asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
core/docs/Changelog.md+16−58
@@ -1,73 +1,31 @@
1# Changelog
1# Changelog
2
2
3−## 0.2.2 (Jan 2024)
3+## Unreleased
4
4
5−* Add fixities `infixr 5` for `cons` and `consM` functions.
5+* Arrays are now created unpinned by default, they were created pinned
6−* Fix a bug in Array `Eq` instance when the type is a sum type with
6+ earlier. During IO operations unpinned arrays are automatically copied
7− differently sized constructors.
7+ to pinned memory. When arrays are directly passed to IO operations
8−* lpackArraysChunksOf, compact, writeChunksWith, putChunksWith now take the
8+ programmers can choose to create them pinned to avoid a copy. To
9− buffer size in number of array elements instead of bytes.
9+ create pinned arrays, use the internal APIs with the `pinned*` prefix.
10
10
11−## 0.2.1 (Dec 2023)
11+* Changed the signature of 'Streamly.Data.Stream.handle' to make the exception
12+ handler monadic.
13+* Rethrow the exception promptly in bracketIO.
12
14
13−* Make the serialization of the unit constructor deterministic.
15+### Breaking
14−* Expose `pinnedSerialize` & `deserialize` via `Streamly.Data.Array`.
15
16
16−## 0.2.0 (Nov 2023)
17−
18−See [0.1.0-0.2.0 API Changelog](https://github.com/composewell/streamly/blob/streamly-0.10.0/core/docs/ApiChangelogs/0.1.0-0.2.0.txt)
19−for a full list of API changes in this release. Only a few significant
20−changes are mentioned here.
21−
22−### Breaking Changes
23−
24−* `ParserK` in `Streamly.Data.ParserK` is not implicitly specialized
17+* `ParserK` in `Streamly.Data.ParserK` is not specialized to arrays anymore. To
25− to arrays anymore. To adapt to the new code, change `ParserK a m
18+ adapt to the new code, change `ParserK a m b` to `ParserK (Array a) m b` where
26− b` to `ParserK (Array a) m b` where the `Array` type comes from
19+ `Array` comes from `Streamly.Data.Array`.
27− `Streamly.Data.Array`. This change also affected the signatures of
28− `parseChunks` and `parseBreakChunks`.
29−* Changed the signature of 'Streamly.Data.Stream.handle' to make the
30− exception handler monadic.
31−* Behavior change: Exceptions are now rethrown promptly in `bracketIO`.
32−
33−### Enhancements
34−
35−* __Serialization__: Added a `Streamly.Data.MutByteArray` module with a
36− `Serialize` type class for fast binary serialization. The Data.Array
37− module supplies the `serialize` and `deserialize` operations for arrays.
38−* __Unpinned Arrays__: Unboxed arrays are now created unpinned by default,
39− they were created pinned earlier. During IO operations, unpinned arrays
40− are automatically copied to pinned memory. When arrays are directly
41− passed to IO operations programmers can choose to create them pinned to
42− avoid a copy. To create pinned arrays, use the internal APIs with the
43− `pinned*` prefix.
44−* StreamK now supports native exception handling routines (handle, bracketIO).
45− Earlier we had to convert it to the `Stream` type for exception handling.
46
20
47### Deprecations
21### Deprecations
48
22
49−See [0.1.0-0.2.0 API Changelog](https://github.com/composewell/streamly/blob/streamly-0.10.0/core/docs/ApiChangelogs/0.1.0-0.2.0.txt)
23+* `Streamly.Data.MutArray.newUnpinned` is renamed to
50−for a full list of deprecations.
24+ `Streamly.Data.MutArray.pinnedNew`
51−
52−### Internal API Changes
53−
54−* Fold constructor has changed, added a `final` field to support
55− finalization and cleanup of a chain of folds. The `extract` field is
56− now used only for mapping the fold internal state to fold result for
57− scanning purposes. If your fold does not require cleanup you can just use
58− your existing `extract` function as `final` as well to adapt to this change.
59−* Many low level internal modules have been removed, they are entirely
60− exported from higher level internal modules. If you were importing any
61− of the missing low level modules then import the higher level modules instead.
62−* Internal module changes:
63− * Streamly.Internal.Serialize.FromBytes -> Streamly.Internal.Data.Binary.Parser
64− * Streamly.Internal.Serialize.ToBytes -> Streamly.Internal.Data.Binary.Stream
65− * Streamly.Internal.Data.Unbox is now exported via Streamly.Internal.Data.Serialize
66− * Streamly.Internal.Data.IORef.Unboxed is now exported via Streamly.Internal.Data.Serialize
67
25
68## 0.1.0 (March 2023)
26## 0.1.0 (March 2023)
69
27
70−Also see [streamly-core-0.1.0 API Changelog](https://github.com/composewell/streamly/blob/streamly-0.10.0/core/docs/ApiChangelogs/0.1.0.txt) or
28+Also see [streamly-core-0.1.0 API Changelog](/core/docs/ApiChangelogs/0.1.0.txt) or
71https://hackage.haskell.org/package/streamly-core-0.1.0/docs/docs/ApiChangelogs/0.1.0.txt
29https://hackage.haskell.org/package/streamly-core-0.1.0/docs/docs/ApiChangelogs/0.1.0.txt
72
30
73`streamly` package is split into two packages, (1) `streamly-core` that
31`streamly` package is split into two packages, (1) `streamly-core` that
core/src/DocTestDataArray.hs−3
@@ -11,12 +11,9 @@
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
15>>> import qualified Streamly.Data.Stream as Stream
14>>> import qualified Streamly.Data.Stream as Stream
16−>>> import qualified Streamly.Data.StreamK as StreamK
17
15
18For APIs that have not been released yet.
16For APIs that have not been released yet.
19
17
20>>> import qualified Streamly.Internal.Data.Array as Array
18>>> import qualified Streamly.Internal.Data.Array as Array
21−>>> import qualified Streamly.Internal.Data.Stream as Stream
22-}
19-}
core/src/DocTestDataParserK.hsdeleted−15
@@ -1,15 +0,0 @@
1−{- $setup
2−>>> :m
3−>>> import Control.Applicative ((<|>))
4−>>> import Data.Char (isDigit, isAlpha)
5−
6−>>> import Streamly.Data.Parser (Parser)
7−>>> import Streamly.Data.ParserK (ParserK)
8−
9−>>> import qualified Streamly.Data.Parser as Parser
10−>>> import qualified Streamly.Data.ParserK as ParserK
11−
12−For APIs that have not been released yet.
13−
14−>>> import qualified Streamly.Internal.Data.ParserK as ParserK
15−-}
core/src/DocTestDataStream.hs−2
@@ -6,7 +6,6 @@
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)
10>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
9>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
11>>> import Data.Maybe (fromJust, isJust)
10>>> import Data.Maybe (fromJust, isJust)
12>>> import Data.Function (fix, (&))
11>>> import Data.Function (fix, (&))
@@ -33,7 +32,6 @@ For APIs that have not been released yet.
33>>> import qualified Streamly.Internal.Data.Fold as Fold
32>>> import qualified Streamly.Internal.Data.Fold as Fold
34>>> import qualified Streamly.Internal.Data.Parser as Parser
33>>> import qualified Streamly.Internal.Data.Parser as Parser
35>>> import qualified Streamly.Internal.Data.Stream as Stream
34>>> import qualified Streamly.Internal.Data.Stream as Stream
36−>>> import qualified Streamly.Internal.Data.StreamK as StreamK
37>>> import qualified Streamly.Internal.Data.Unfold as Unfold
35>>> import qualified Streamly.Internal.Data.Unfold as Unfold
38>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
36>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
39-}
37-}
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 (unsafeCreateOf)
11+>>> import qualified Streamly.Internal.Data.Array as Array (writeNUnsafe)
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/Console/Stdio.hs+27−1
@@ -24,7 +24,33 @@ module Streamly.Console.Stdio
24 -- * Write (stderr)
24 -- * Write (stderr)
25 , writeErr
25 , writeErr
26 , writeErrChunks
26 , writeErrChunks
27+
28+ -- * Deprecated
29+ , read
30+ , readChunks
27 )
31 )
28where
32where
29
33
34+import Control.Monad.IO.Class (MonadIO(..))
35+import Data.Word (Word8)
36+import Streamly.Internal.Data.Array.Type (Array)
37+import Streamly.Internal.Data.Unfold (Unfold)
38+
30−import Streamly.Internal.Console.Stdio
39+import Streamly.Internal.Console.Stdio hiding (read, readChunks)
40+import Prelude hiding (read)
41+
42+-- Same as 'reader'
43+--
44+-- @since 0.8.0
45+{-# DEPRECATED read "Please use 'reader' instead" #-}
46+{-# INLINE read #-}
47+read :: MonadIO m => Unfold m () Word8
48+read = reader
49+
50+-- Same as 'chunkReader'
51+--
52+-- @since 0.8.0
53+{-# DEPRECATED readChunks "Please use 'chunkReader' instead" #-}
54+{-# INLINE readChunks #-}
55+readChunks :: MonadIO m => Unfold m () (Array Word8)
56+readChunks = chunkReader
core/src/Streamly/Data/Array.hs+39−40
@@ -31,45 +31,28 @@ 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−
47 -- * Construction
34 -- * Construction
48 -- | When performance matters, the fastest way to generate an array is
35 -- | When performance matters, the fastest way to generate an array is
49− -- 'createOf'. 'IsList' and 'IsString' instances can be
36+ -- 'writeN'. 'IsList' and 'IsString' instances can be
50 -- used to conveniently construct arrays from literal values.
37 -- used to conveniently construct arrays from literal values.
51 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
38 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
52 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
39 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
53 -- 'fromList' can be used to construct an array from a string literal.
40 -- 'fromList' can be used to construct an array from a string literal.
54
41
55− -- ** From Stream
56− , createOf
57− , create
58− , writeLastN -- drop old (ring buffer)
59−
60− -- ** From List
42+ -- Pure List APIs
61 , fromListN
43 , fromListN
62 , fromList
44 , fromList
63
45
64− -- * To List
46+ -- Monadic APIs
47+ , writeN -- drop new
48+ , write -- full buffer
49+ , writeLastN -- drop old (ring buffer)
50+
51+ -- * Conversion
65 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
52 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
66 -- list.
53 -- list.
67 , toList
54 , toList
68
55
69− -- * To Stream
70− , read
71− , readRev
72−
73 -- * Unfolds
56 -- * Unfolds
74 , reader
57 , reader
75 , readerRev
58 , readerRev
@@ -83,24 +66,25 @@ module Streamly.Data.Array
83 -- , (!!)
66 -- , (!!)
84 , getIndex
67 , getIndex
85
68
86− -- * Serialization
69+ -- * Unbox Type Class
87− , pinnedSerialize
88− , deserialize
89−
90− -- * Re-exports
91 , Unbox (..)
70 , Unbox (..)
92− , Serialize(..)
71+
72+ -- * Pinning & Unpinning
73+ , pin
74+ , unpin
75+ , isPinned
93
76
94 -- * Deprecated
77 -- * Deprecated
95− , writeN -- drop new
78+ , read
96− , write -- full buffer
79+ , readRev
97 )
80 )
98where
81where
99
82
100#include "inline.hs"
83#include "inline.hs"
101
84
102−import Streamly.Internal.Data.Array
85+import Streamly.Internal.Data.Array hiding (read, readRev)
103−import Streamly.Internal.Data.MutByteArray (Unbox(..), Serialize(..))
86+import Streamly.Internal.Data.Unbox (Unbox (..))
87+import Streamly.Internal.Data.Unfold (Unfold)
104
88
105import Prelude hiding (read, length)
89import Prelude hiding (read, length)
106
90
@@ -118,7 +102,7 @@ import Prelude hiding (read, length)
118--
102--
119-- Convert array to stream, and fold the stream:
103-- Convert array to stream, and fold the stream:
120--
104--
121−-- >>> fold f arr = Array.read arr & Stream.fold f
105+-- >>> fold f arr = Stream.unfold Array.reader arr & Stream.fold f
122-- >>> fold Fold.sum (Array.fromList [1,2,3::Int])
106-- >>> fold Fold.sum (Array.fromList [1,2,3::Int])
123-- 6
107-- 6
124--
108--
@@ -126,7 +110,7 @@ import Prelude hiding (read, length)
126--
110--
127-- Convert array to stream, transform, and fold back to array:
111-- Convert array to stream, transform, and fold back to array:
128--
112--
129−-- >>> amap f arr = Array.read arr & fmap f & Stream.fold (Array.createOf (Array.length arr))
113+-- >>> amap f arr = Stream.unfold Array.reader arr & fmap f & Stream.fold Array.write
130-- >>> amap (+1) (Array.fromList [1,2,3::Int])
114-- >>> amap (+1) (Array.fromList [1,2,3::Int])
131-- fromList [2,3,4]
115-- fromList [2,3,4]
132--
116--
@@ -153,11 +137,12 @@ import Prelude hiding (read, length)
153-- See the 'fromPureStream' unreleased API to generate an array from an
137-- See the 'fromPureStream' unreleased API to generate an array from an
154-- Identity stream safely without using MonadIO constraint.
138-- Identity stream safely without using MonadIO constraint.
155--
139--
140+--
156-- Note that 'Identity' streams can be generalized to IO streams:
141-- Note that 'Identity' streams can be generalized to IO streams:
157--
142--
158−-- >>> stream = Stream.fromList [1,2,3] :: Stream Identity Int
143+-- >>> pure = Stream.fromList [1,2,3] :: Stream Identity Int
159−-- >>> pure2IO s = Stream.morphInner (return . runIdentity) s :: Stream IO Int
144+-- >>> generally = Stream.morphInner (return . runIdentity)
160−-- >>> Stream.fold Array.create (pure2IO stream)
145+-- >>> Stream.fold Array.write (generally pure :: Stream IO Int)
161-- fromList [1,2,3]
146-- fromList [1,2,3]
162--
147--
163-- == Programming Tips
148-- == Programming Tips
@@ -165,3 +150,17 @@ import Prelude hiding (read, length)
165-- This module is designed to be imported qualified:
150-- This module is designed to be imported qualified:
166--
151--
167-- >>> import qualified Streamly.Data.Array as Array
152-- >>> import qualified Streamly.Data.Array as Array
153+
154+-- | Same as 'reader'
155+--
156+{-# DEPRECATED read "Please use 'reader' instead" #-}
157+{-# INLINE_NORMAL read #-}
158+read :: (Monad m, Unbox a) => Unfold m (Array a) a
159+read = reader
160+
161+-- | Same as 'readerRev'
162+--
163+{-# DEPRECATED readRev "Please use 'readerRev' instead" #-}
164+{-# INLINE_NORMAL readRev #-}
165+readRev :: (Monad m, Unbox a) => Unfold m (Array a) a
166+readRev = readerRev
core/src/Streamly/Data/Array/Generic.hs+13−16
@@ -15,37 +15,34 @@ module Streamly.Data.Array.Generic
15 ( Array
15 ( Array
16
16
17 -- * Construction
17 -- * Construction
18− , fromListN
18+ , A.fromListN
19− , fromList
19+ , A.fromList
20
20
21 -- MonadicAPIs
21 -- MonadicAPIs
22− , createOf
22+ , A.writeN
23− , create
23+ , A.write
24
24
25 -- * Conversion
25 -- * Conversion
26− , toList
26+ , A.toList
27
27
28 -- * Streams
28 -- * Streams
29− , read
29+ , A.read
30− , readRev
30+ , A.readRev
31
31
32 -- * Unfolds
32 -- * Unfolds
33− , reader
33+ , A.reader
34 -- , A.readerRev
34 -- , A.readerRev
35
35
36 -- * Random Access
36 -- * Random Access
37− , length
37+ , A.length
38− , getIndex
38+ , A.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
47 )
43 )
48where
44where
49
45
50−import Streamly.Internal.Data.Array.Generic
46+import Streamly.Internal.Data.Array.Generic (Array)
51−import Prelude hiding (length, read)
47+
48+import qualified Streamly.Internal.Data.Array.Generic as A
core/src/Streamly/Data/Fold.hs+118−150
@@ -10,156 +10,6 @@
10-- Fast, composable stream consumers with ability to terminate, supporting
10-- Fast, composable stream consumers with ability to terminate, supporting
11-- stream fusion.
11-- stream fusion.
12--
12--
13−-- == Using Folds
14−--
15−-- This module provides elementary folds and fold combinators that can be used
16−-- to consume a stream of data and reduce it to a final value, or transform it
17−-- in a stateful manner using scans. A data stream can be reduced into a stream
18−-- of folded data elements by folding segments of the stream. Fold combinators
19−-- can be used to compose multiple folds in parallel or to create a pipeline of
20−-- folds such that the next fold consumes the result of the previous fold. To
21−-- run these folds on a stream see 'Streamly.Data.Stream.fold',
22−-- 'Streamly.Data.Stream.scan', 'Streamly.Data.Stream.postscan',
23−-- 'Streamly.Data.Stream.scanMaybe', 'Streamly.Data.Stream.foldMany' and other
24−-- operations accepting 'Fold' type as argument "Streamly.Data.Stream".
25−--
26−-- == Reducing a Stream
27−--
28−-- A 'Fold' is a consumer of a stream of values. A fold driver (such as
29−-- 'Streamly.Data.Stream.fold') initializes the fold @accumulator@, runs the
30−-- fold @step@ function in a loop, processing the input stream one element at a
31−-- time and accumulating the result. The loop continues until the fold
32−-- terminates, at which point the accumulated result is returned.
33−--
34−-- For example, a 'sum' Fold represents a stream consumer that adds the values
35−-- in the input stream:
36−--
37−-- >>> Stream.fold Fold.sum $ Stream.fromList [1..100]
38−-- 5050
39−--
40−-- Conceptually, a 'Fold' is a data type that mimics a strict left fold
41−-- ('Data.List.foldl'). The above example is similar to a left fold using
42−-- @(+)@ as the step and @0@ as the initial value of the accumulator:
43−--
44−-- >>> Data.List.foldl' (+) 0 [1..100]
45−-- 5050
46−--
47−-- 'Fold's have an early termination capability e.g. the 'one' fold terminates
48−-- after consuming one element:
49−--
50−-- >>> Stream.fold Fold.one $ Stream.fromList [1..]
51−-- Just 1
52−--
53−-- The above example is similar to the following right fold:
54−--
55−-- >>> Prelude.foldr (\x _ -> Just x) Nothing [1..]
56−-- Just 1
57−--
58−-- 'Fold's can be combined together using combinators. For example, to create a
59−-- fold that sums first two elements in a stream:
60−--
61−-- >>> sumTwo = Fold.take 2 Fold.sum
62−-- >>> Stream.fold sumTwo $ Stream.fromList [1..100]
63−-- 3
64−--
65−-- == Parallel Composition
66−--
67−-- Folds can be combined to run in parallel on the same input. For example, to
68−-- compute the average of numbers in a stream without going through the stream
69−-- twice:
70−--
71−-- >>> avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length)
72−-- >>> Stream.fold avg $ Stream.fromList [1.0..100.0]
73−-- 50.5
74−--
75−-- Folds can be combined so as to partition the input stream over multiple
76−-- folds. For example, to count even and odd numbers in a stream:
77−--
78−-- >>> split n = if even n then Left n else Right n
79−-- >>> stream = fmap split $ Stream.fromList [1..100]
80−-- >>> countEven = fmap (("Even " ++) . show) Fold.length
81−-- >>> countOdd = fmap (("Odd " ++) . show) Fold.length
82−-- >>> f = Fold.partition countEven countOdd
83−-- >>> Stream.fold f stream
84−-- ("Even 50","Odd 50")
85−--
86−-- == Sequential Composition
87−--
88−-- Terminating folds can be combined to parse the stream serially such that the
89−-- first fold consumes the input until it terminates and the second fold
90−-- consumes the rest of the input until it terminates:
91−--
92−-- >>> f = Fold.splitWith (,) (Fold.take 8 Fold.toList) (Fold.takeEndBy (== '\n') Fold.toList)
93−-- >>> Stream.fold f $ Stream.fromList "header: hello\n"
94−-- ("header: ","hello\n")
95−--
96−-- == Splitting a Stream
97−--
98−-- A 'Fold' can be applied repeatedly on a stream to transform it to a stream
99−-- of fold results. To split a stream on newlines:
100−--
101−-- >>> f = Fold.takeEndBy (== '\n') Fold.toList
102−-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.fromList "Hello there!\nHow are you\n"
103−-- ["Hello there!\n","How are you\n"]
104−--
105−-- Similarly, we can split the input of a fold too:
106−--
107−-- >>> Stream.fold (Fold.many f Fold.toList) $ Stream.fromList "Hello there!\nHow are you\n"
108−-- ["Hello there!\n","How are you\n"]
109−--
110−-- == Folds vs. Streams
111−--
112−-- We can often use streams or folds to achieve the same goal. However, streams
113−-- are more efficient in composition of producers (e.g.
114−-- 'Data.Stream.append' or 'Data.Stream.mergeBy') whereas folds are
115−-- more efficient in composition of consumers (e.g. 'splitWith', 'partition'
116−-- or 'teeWith').
117−--
118−-- Streams are producers, transformations on streams happen on the output side:
119−--
120−-- >>> :{
121−-- f stream =
122−-- Stream.filter odd stream
123−-- & fmap (+1)
124−-- & Stream.fold Fold.sum
125−-- :}
126−--
127−-- >>> f $ Stream.fromList [1..100 :: Int]
128−-- 2550
129−--
130−-- Folds are stream consumers with an input stream and an output value, stream
131−-- transformations on folds happen on the input side:
132−--
133−-- >>> :{
134−-- f =
135−-- Fold.filter odd
136−-- $ Fold.lmap (+1)
137−-- $ Fold.sum
138−-- :}
139−--
140−-- >>> Stream.fold f $ Stream.fromList [1..100 :: Int]
141−-- 2550
142−--
143−-- Notice the similiarity in the definition of @f@ in both cases, the only
144−-- difference is the composition by @&@ vs @$@ and the use @lmap@ vs @map@, the
145−-- difference is due to output vs input side transformations.
146−--
147−-- == Fusion Limitations
148−--
149−-- Folds support stream fusion for generating loops comparable to the speed of
150−-- C. However, it has some limitations. For fusion to work, the folds must be
151−-- inlined, folds must be statically known and not generated dynamically, folds
152−-- should not be passed recursively.
153−--
154−-- Another limitation is due to the quadratic complexity causing slowdown when
155−-- too many nested compositions are used. Especially, the performance of the
156−-- Applicative instance and splitting operations (e.g. 'splitWith') degrades
157−-- quadratically (O(n^2)) when combined @n@ times, roughly 8 or less sequenced
158−-- operations are fine. For these cases folds can be converted to parsers and
159−-- then used as ParserK.
160−--
161−-- == Experimental APIs
162−--
163-- Please refer to "Streamly.Internal.Data.Fold" for more functions that have
13-- Please refer to "Streamly.Internal.Data.Fold" for more functions that have
164-- not yet been released.
14-- not yet been released.
165
15
@@ -171,6 +21,9 @@ module Streamly.Data.Fold
171 --
21 --
172 -- $setup
22 -- $setup
173
23
24+ -- * Overview
25+ -- $overview
26+
174 -- * Running A Fold
27 -- * Running A Fold
175 drive
28 drive
176 -- XXX Should we have a stream returning function in fold module?
29 -- XXX Should we have a stream returning function in fold module?
@@ -405,6 +258,121 @@ import Streamly.Internal.Data.Fold
405
258
406#include "DocTestDataFold.hs"
259#include "DocTestDataFold.hs"
407
260
261+-- $overview
262+--
263+-- A 'Fold' is a consumer of a stream of values. A fold driver (such as
264+-- 'Streamly.Data.Stream.fold') initializes the fold @accumulator@, runs the
265+-- fold @step@ function in a loop, processing the input stream one element at a
266+-- time and accumulating the result. The loop continues until the fold
267+-- terminates, at which point the accumulated result is returned.
268+--
269+-- For example, a 'sum' Fold represents a stream consumer that adds the values
270+-- in the input stream:
271+--
272+-- >>> Stream.fold Fold.sum $ Stream.fromList [1..100]
273+-- 5050
274+--
275+-- Conceptually, a 'Fold' is a data type that mimics a strict left fold
276+-- ('Data.List.foldl'). The above example is similar to a left fold using
277+-- @(+)@ as the step and @0@ as the initial value of the accumulator:
278+--
279+-- >>> Data.List.foldl' (+) 0 [1..100]
280+-- 5050
281+--
282+-- 'Fold's have an early termination capability e.g. the 'one' fold terminates
283+-- after consuming one element:
284+--
285+-- >>> Stream.fold Fold.one $ Stream.fromList [1..]
286+-- Just 1
287+--
288+-- The above example is similar to the following right fold:
289+--
290+-- >>> Prelude.foldr (\x _ -> Just x) Nothing [1..]
291+-- Just 1
292+--
293+-- 'Fold's can be combined together using combinators. For example, to create a
294+-- fold that sums first two elements in a stream:
295+--
296+-- >>> sumTwo = Fold.take 2 Fold.sum
297+-- >>> Stream.fold sumTwo $ Stream.fromList [1..100]
298+-- 3
299+--
300+-- Folds can be combined to run in parallel on the same input. For example, to
301+-- compute the average of numbers in a stream without going through the stream
302+-- twice:
303+--
304+-- >>> avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length)
305+-- >>> Stream.fold avg $ Stream.fromList [1.0..100.0]
306+-- 50.5
307+--
308+-- Folds can be combined so as to partition the input stream over multiple
309+-- folds. For example, to count even and odd numbers in a stream:
310+--
311+-- >>> split n = if even n then Left n else Right n
312+-- >>> stream = fmap split $ Stream.fromList [1..100]
313+-- >>> countEven = fmap (("Even " ++) . show) Fold.length
314+-- >>> countOdd = fmap (("Odd " ++) . show) Fold.length
315+-- >>> f = Fold.partition countEven countOdd
316+-- >>> Stream.fold f stream
317+-- ("Even 50","Odd 50")
318+--
319+-- Terminating folds can be combined to parse the stream serially such that the
320+-- first fold consumes the input until it terminates and the second fold
321+-- consumes the rest of the input until it terminates:
322+--
323+-- >>> f = Fold.splitWith (,) (Fold.take 8 Fold.toList) (Fold.takeEndBy (== '\n') Fold.toList)
324+-- >>> Stream.fold f $ Stream.fromList "header: hello\n"
325+-- ("header: ","hello\n")
326+--
327+-- A 'Fold' can be applied repeatedly on a stream to transform it to a stream
328+-- of fold results. To split a stream on newlines:
329+--
330+-- >>> f = Fold.takeEndBy (== '\n') Fold.toList
331+-- >>> Stream.fold Fold.toList $ Stream.foldMany f $ Stream.fromList "Hello there!\nHow are you\n"
332+-- ["Hello there!\n","How are you\n"]
333+--
334+-- Similarly, we can split the input of a fold too:
335+--
336+-- >>> Stream.fold (Fold.many f Fold.toList) $ Stream.fromList "Hello there!\nHow are you\n"
337+-- ["Hello there!\n","How are you\n"]
338+--
339+-- = Folds vs. Streams
340+--
341+-- We can often use streams or folds to achieve the same goal. However, streams
342+-- are more efficient in composition of producers (e.g.
343+-- 'Data.Stream.append' or 'Data.Stream.mergeBy') whereas folds are
344+-- more efficient in composition of consumers (e.g. 'splitWith', 'partition'
345+-- or 'teeWith').
346+--
347+-- Streams are producers, transformations on streams happen on the output side:
348+--
349+-- >>> :{
350+-- f stream =
351+-- Stream.filter odd stream
352+-- & fmap (+1)
353+-- & Stream.fold Fold.sum
354+-- :}
355+--
356+-- >>> f $ Stream.fromList [1..100 :: Int]
357+-- 2550
358+--
359+-- Folds are stream consumers with an input stream and an output value, stream
360+-- transformations on folds happen on the input side:
361+--
362+-- >>> :{
363+-- f =
364+-- Fold.filter odd
365+-- $ Fold.lmap (+1)
366+-- $ Fold.sum
367+-- :}
368+--
369+-- >>> Stream.fold f $ Stream.fromList [1..100 :: Int]
370+-- 2550
371+--
372+-- Notice the similiarity in the definition of @f@ in both cases, the only
373+-- difference is the composition by @&@ vs @$@ and the use @lmap@ vs @map@, the
374+-- difference is due to output vs input side transformations.
375+
408--------------------------------------------------------------------------------
376--------------------------------------------------------------------------------
409-- Deprecated
377-- Deprecated
410--------------------------------------------------------------------------------
378--------------------------------------------------------------------------------
core/src/Streamly/Data/MutArray.hs+12−18
@@ -32,27 +32,22 @@ module Streamly.Data.MutArray
32 -- * Construction
32 -- * Construction
33
33
34 -- Uninitialized Arrays
34 -- Uninitialized Arrays
35− , emptyOf
35+ , new
36− , pinnedEmptyOf
36+ , pinnedNew
37
37
38 -- From containers
38 -- From containers
39 , fromListN
39 , fromListN
40 , fromList
40 , fromList
41− , createOf
41+ , writeN -- drop new
42− , create
42+ , write -- full buffer
43 -- writeLastN
43 -- writeLastN
44
44
45− -- * Pinning & Unpinning
46− , pin
47− , unpin
48− , isPinned
49−
50 -- * Appending elements
45 -- * Appending elements
51 , snoc
46 , snoc
52
47
53 -- * Appending streams
48 -- * Appending streams
54− , appendN
49+ , writeAppendN -- XXX Rename to writeSnocN?
55− , append
50+ , writeAppend -- XXX Rename to writeSnoc?
56
51
57 -- * Inplace mutation
52 -- * Inplace mutation
58 , putIndex
53 , putIndex
@@ -83,17 +78,16 @@ module Streamly.Data.MutArray
83 -- * Size
78 -- * Size
84 , length
79 , length
85
80
86− -- * Re-exports
81+ -- * Unbox Type Class
87 , Unbox (..)
82 , Unbox (..)
88
83
84+ -- * Pinning & Unpinning
85+ , pin
86+ , unpin
87+ , isPinned
88+
89 -- * Deprecated
89 -- * Deprecated
90 , newPinned
90 , newPinned
91− , new
92− , pinnedNew
93− , writeN
94− , write
95− , writeAppendN
96− , writeAppend
97 )
91 )
98where
92where
99
93
core/src/Streamly/Data/MutArray/Generic.hs+3−8
@@ -23,11 +23,11 @@ module Streamly.Data.MutArray.Generic
23 MutArray
23 MutArray
24
24
25 -- * Construction
25 -- * Construction
26− , emptyOf
26+ , new
27 , fromListN
27 , fromListN
28 , fromList
28 , fromList
29− , createOf
29+ , writeN
30− , create
30+ , write
31
31
32 -- * Appending elements
32 -- * Appending elements
33 , snoc
33 , snoc
@@ -56,11 +56,6 @@ module Streamly.Data.MutArray.Generic
56
56
57 -- * Size
57 -- * Size
58 , length
58 , length
59−
60− -- * Deprecated
61− , new
62− , writeN
63− , write
64 )
59 )
65where
60where
66
61
core/src/Streamly/Data/MutByteArray.hsdeleted−106
@@ -1,106 +0,0 @@
1−-- |
2−-- Module : Streamly.Data.MutByteArray
3−-- Copyright : (c) 2023 Composewell Technologies
4−-- License : BSD3-3-Clause
5−-- Maintainer : streamly@composewell.com
6−-- Portability : GHC
7−--
8−-- A low level byte Array type 'MutByteArray', along with type classes 'Unbox'
9−-- and 'Serialize' for fast binary serialization and deserialization of Haskell
10−-- values. Serialization, deserialization performance is similar to, and in
11−-- some cases many times better than the store package. Conceptually, the
12−-- 'Serialize' type class works in the same way as store.
13−--
14−-- Serialize instances are configurable to use constructor names (see
15−-- 'Streamly.Internal.Data.MutByteArray.encodeConstrNames'), record field names (see
16−-- 'Streamly.Internal.Data.MutByteArray.encodeRecordFields') instead of binary
17−-- encoded values. This is an experimental feature which allows JSON like
18−-- properties with faster speed. For example, you can change the order of
19−-- constructors or record fields without affecting serialized value.
20−--
21−-- Higher level unboxed array modules "Streamly.Data.Array" and
22−-- "Streamly.Data.MutArray" are built on top of this module. Unboxed arrays are
23−-- essentially serialized Haskell values. Array modules provide higher level
24−-- serialization routines like 'Streamly.Internal.Data.Array.pinnedSerialize'
25−-- and 'Streamly.Internal.Data.Array.deserialize' from the
26−-- "Streamly.Internal.Data.Array" module.
27−--
28−-- == Mutable Byte Array
29−--
30−-- 'MutByteArray' is a primitive mutable array in the IO monad. 'Unbox' and
31−-- 'Serialize' type classes use this primitive array to serialize data to and
32−-- deserialize it from. This array is used to build higher level unboxed
33−-- array types 'Streamly.Data.MutArray.MutArray' and 'Streamly.Data.Array.Array'.
34−--
35−-- == Using Unbox
36−--
37−-- The 'Unbox' type class is simple and used to serialize non-recursive fixed
38−-- size data types. This type class is primarily used to implement unboxed
39−-- arrays. Unboxed arrays are just a sequence of serialized fixed length
40−-- Haskell data types. Instances of this type class can be derived using
41−-- 'Generic' or template haskell based deriving functions provided in this
42−-- module.
43−--
44−-- Writing a data type to an array using the array creation routines in
45−-- "Streamly.Data.Array" or "Streamly.Data.MutArray" (e.g. @writeN@ or
46−-- @fromListN@), serializes the type to the array. Similarly, reading the data
47−-- type from the array deserializes it. You can also serialize and deserialize
48−-- directly to and from a 'MutByteArray', using the type class methods.
49−--
50−-- == Using Serialize
51−--
52−-- The 'Serialize' type class is a superset of the 'Unbox' type class, it can
53−-- serialize variable length data types as well e.g. Haskell lists. Use
54−-- 'deriveSerialize' to derive the instances of the type class automatically
55−-- and then use the type class methods to serialize and deserialize to and from
56−-- a 'MutByteArray'.
57−--
58−-- See 'Streamly.Internal.Data.Array.pinnedSerialize' and
59−-- 'Streamly.Internal.Data.Array.deserialize' for 'Array' type based
60−-- serialization.
61−--
62−-- == Comparing serialized values
63−--
64−-- When using the `Unbox` type class the same value may result in differing
65−-- serialized bytes because of unused uninitialized data in case of sum types.
66−-- Therefore, byte comparison of serialized values is not reliable.
67−--
68−-- However, the 'Serialize' type class guarantees that the serialized values
69−-- are always exactly the same and byte comparison of serialized is reliable.
70−--
71−module Streamly.Data.MutByteArray
72− (
73−
74− -- * Mutable Byte Array
75− -- | The standard way to read from or write to a 'MutByteArray' is by using
76− -- the 'Unbox' or 'Serialize' type class methods.
77− MutByteArray
78− , isPinned
79− , pin
80− , unpin
81− , new
82− , pinnedNew
83−
84− -- * Unbox
85− , Unbox(..)
86− , deriveUnbox
87−
88− -- * Serialize
89− , Serialize(..)
90−
91− -- ** Instance Config
92− , SerializeConfig
93− , inlineAddSizeTo
94− , inlineSerializeAt
95− , inlineDeserializeAt
96−
97− -- ** Instance Deriving
98− , deriveSerialize
99− , deriveSerializeWith
100− ) where
101−
102−--------------------------------------------------------------------------------
103−-- Imports
104−--------------------------------------------------------------------------------
105−
106−import Streamly.Internal.Data.MutByteArray
core/src/Streamly/Data/Parser.hs+60−130
@@ -7,137 +7,12 @@
7-- Stability : pre-release
7-- Stability : pre-release
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10−-- Parsers are stream consumers like folds with the following differences:
10+-- Fast, composable stream consumers with ability to terminate, backtrack and
11+-- fail, supporting stream fusion. Parsers are a natural extension of
12+-- "Streamly.Data.Fold". Parsers and folds can be interconverted.
11--
13--
12−-- * folds cannot fail but parsers can fail and backtrack.
13−-- * folds can be composed as a Tee but parsers cannot.
14−-- * folds can be used for scanning but parsers cannot.
15−-- * folds can be converted to parsers.
16−--
17−-- This module implements parsers with stream fusion which compile to efficient
18−-- loops comparable to the speed of C.
19−--
20−-- == Using Parsers
21−--
22−-- This module provides elementary parsers and parser combinators that can be
23−-- used to parse a stream of data. Additionally, all the folds from the
24−-- "Streamly.Data.Fold" module can be converted to parsers using 'fromFold'.
25−-- All the parsing functionality provided by popular parsing libraries, and
26−-- more is available. Also see "Streamly.Unicode.Parser" module for Char stream
27−-- parsers.
28−--
29−-- A data stream can be transformed to a stream of parsed data elements. Parser
30−-- combinators can be used to create a pipeline of folds or parsers such that
31−-- the next fold or parser consumes the result of the previous parser. See
32−-- 'Streamly.Data.Stream.parse' and 'Streamly.Data.Stream.parseMany' to run
33−-- these parsers on a stream.
34−--
35−-- == Parser vs ParserK
36−--
37−-- There are two functionally equivalent parsing modules,
38−-- "Streamly.Data.Parser" (this module) and "Streamly.Data.ParserK". The latter
39−-- is a CPS based wrapper over the former, and can be used for parsing in
40−-- general. "Streamly.Data.Parser" enables stream fusion and should be
41−-- preferred over "Streamly.Data.ParserK" for high performance stream parsing
42−-- use cases. However, there are a few cases where this module is not
43−-- suitable and ParserK should be used instead.
44−--
45−-- For static fusion, parser combinators have to use strict pattern matching on
46−-- arguments of type Parser. This leads to infinte loop when a parser is
47−-- defined recursively, due to strict evaluation of the recursive call. For
48−-- example, the following implementation loops infinitely because of the
49−-- recursive use of parser @p@ in the @*>@ combinator:
50−--
51−-- >>> import Streamly.Data.Parser (Parser)
52−-- >>> import qualified Streamly.Data.Fold as Fold
53−-- >>> import qualified Streamly.Data.Parser as Parser
54−-- >>> import qualified Streamly.Data.Stream as Stream
55−-- >>> import Control.Applicative ((<|>))
56−--
57−-- >>> :{
58−-- >>> p :: Monad m => Parser Char m String
59−-- >>> p = Parser.satisfy (== '(') *> p <|> Parser.fromFold Fold.toList
60−-- >>> :}
61−--
62−-- Use ParserK when recursive use is required:
63−--
64−-- >>> import Streamly.Data.ParserK (ParserK)
65−-- >>> import qualified Streamly.Data.StreamK as StreamK
66−-- >>> import qualified Streamly.Internal.Data.StreamK as StreamK (parse)
67−-- >>> import qualified Streamly.Internal.Data.ParserK as ParserK (adapt)
68−--
69−-- >>> :{
70−-- >>> p :: Monad m => ParserK Char m String
71−-- >>> p = ParserK.adapt (Parser.satisfy (== '(')) *> p <|> ParserK.adapt (Parser.fromFold Fold.toList)
72−-- >>> :}
73−--
74−-- >>> StreamK.parse p $ StreamK.fromStream $ Stream.fromList "hello"
75−-- Right "hello"
76−--
77−-- For this reason Applicative, Alternative or Monad compositions with
78−-- recursion cannot be used with the 'Parser' type. Alternative type class based
79−-- operations like 'asum' and Alternative based generic parser combinators use
80−-- recursion. Similarly, Applicative type class based operations like
81−-- 'Prelude.sequence' use recursion. Custom implementations of many such
82−-- operations are provided in this module (e.g. 'some', 'many'), and those
83−-- should be used instead.
84−--
85−-- Another limitation of Parser type is due to the quadratic complexity causing
86−-- slowdown when too many nested compositions are used. Especially Applicative,
87−-- Monad, Alternative instances, and sequenced parsing operations (e.g. nested
88−-- 'one', and 'splitWith') degrade the performance quadratically (O(n^2)) when
89−-- combined @n@ times, roughly 8 or less sequenced parsers are fine. READ THE
90−-- DOCS OF APPLICATIVE, MONAD AND ALTERNATIVE INSTANCES.
91−--
92−-- == Streaming Parsers
93−--
94−-- With 'Streamly.Data.ParserK.ParserK' you can use the generic Alternative
95−-- type class based parsers from the
96−-- <https://hackage.haskell.org/package/parser-combinators parser-combinators>
97−-- library or similar. However, we recommend that you use the equivalent
98−-- functionality from this module for better performance and for streaming
99−-- behavior.
100−--
101−-- Firstly, the combinators in this module are faster due to stream fusion.
102−-- Secondly, these are streaming in nature as the results can be passed
103−-- directly to other stream consumers (folds or parsers). The Alternative type
104−-- class based parsers would end up buffering all the results in lists before
105−-- they can be consumed.
106−--
107−-- When recursion or heavy nesting is needed use ParserK.
108−--
109−-- == Error Reporting
110−--
111−-- These parsers do not report the error context (e.g. line number or column).
112−-- This may be supported in future.
113−--
114−-- == Monad Transformer Stack
115−--
116−-- 'MonadTrans' instance is not provided. If the 'Parser' type is the top most
117−-- layer (which should be the case almost always) you can just use 'fromEffect'
118−-- to execute the lower layer monad effects.
119−--
120−-- == Parser vs ParserK Implementation
121−--
122−-- The 'Parser' type represents a stream consumer by composing state as data
123−-- which enables stream fusion. Stream fusion generates a tight loop without
124−-- any constructor allocations between the stages, providing C like performance
125−-- for the loop. Stream fusion works when multiple functions are combined in a
126−-- pipeline statically. Therefore, the operations in this module must be
127−-- inlined and must not be used recursively to allow for stream fusion.
128−--
129−-- The 'ParserK' type represents a stream consumer by composing function calls,
130−-- therefore, a function call overhead is incurred at each composition. It is
131−-- quite fast in general but may be a few times slower than a fused parser.
132−-- However, it allows for scalable dynamic composition especially parsers can
133−-- be used in recursive calls. Using the 'ParserK' type operations like
134−-- 'splitWith' provide linear (O(n)) performance with respect to the number of
135−-- compositions.
136−--
137−-- == Experimental APIs
138−--
139−-- Please refer to "Streamly.Internal.Data.Parser" for functions that have not
14+-- Please refer to "Streamly.Internal.Data.Parser" for functions that have
140−-- yet been released.
15+-- not yet been released.
141--
16--
142module Streamly.Data.Parser
17module Streamly.Data.Parser
143 (
18 (
@@ -147,6 +22,9 @@ module Streamly.Data.Parser
147 --
22 --
148 -- $setup
23 -- $setup
149
24
25+ -- * Overview
26+ -- $overview
27+
150 -- * Parser Type
28 -- * Parser Type
151 Parser
29 Parser
152
30
@@ -245,3 +123,55 @@ import Streamly.Internal.Data.Parser
245import Prelude hiding (dropWhile, takeWhile, filter)
123import Prelude hiding (dropWhile, takeWhile, filter)
246
124
247#include "DocTestDataParser.hs"
125#include "DocTestDataParser.hs"
126+
127+-- $overview
128+--
129+-- Several combinators in this module can be many times faster than CPS based
130+-- parsers because of stream fusion. For example,
131+-- 'Streamly.Internal.Data.Parser.many' combinator in this module is much
132+-- faster than the 'Control.Applicative.many' combinator of
133+-- 'Control.Applicative.Alternative' type class used by CPS based parsers.
134+--
135+-- The use of 'Alternative' type class, in parsers has another drawback.
136+-- Alternative based parsers use plain Haskell lists to collect the results. In
137+-- a strict Monad like IO, the results are necessarily buffered before they can
138+-- be consumed. This may not perform optimally in streaming applications
139+-- processing large amounts of data. Equivalent combinators in this module can
140+-- consume the results of parsing using a 'Fold' or another parser, thus
141+-- providing a scalable and composable consumer.
142+--
143+-- Note that these parsers do not report the error context (e.g. line number or
144+-- column). This may be supported in future.
145+--
146+-- mtl instances are not provided. If the 'Parser' type is the top most layer
147+-- (which should be the case almost always) you can just use 'fromEffect' to
148+-- execute the lower layer monad effects.
149+--
150+-- == Performance Notes
151+--
152+-- The 'Parser' type represents a stream consumer by composing state as data
153+-- which enables stream fusion. Stream fusion generates a tight loop without
154+-- any constructor allocations between the stages, providing C like performance
155+-- for the loop. Stream fusion works when multiple functions are combined in a
156+-- pipeline statically. Therefore, the operations in this module must be
157+-- inlined and must not be used recursively to allow for stream fusion. Note
158+-- that operations like 'sequence', and 'asum' that compose pasrers using
159+-- recursion should be avoided with these parsers. You can use these with the
160+-- 'ParserK' module instead.
161+--
162+-- Using the 'Parser' type, parsing operations like 'one', 'splitWith' etc.
163+-- degrade quadratically (O(n^2)) when combined many times. If you need to
164+-- combine these operations, say more than 8 times in a single loop, then you
165+-- should consider using the continuation style parser type 'ParserK' instead.
166+-- Also, if you need to use these operations in a recursive loop you should use
167+-- 'ParserK' instead.
168+--
169+-- The 'ParserK' type represents a stream consumer by composing function calls,
170+-- therefore, a function call overhead is incurred at each composition. It is
171+-- quite fast in general but may be a few times slower than a fused parser.
172+-- However, it allows for scalable dynamic composition especially parsers can
173+-- be used in recursive calls. Using the 'ParserK' type operations like
174+-- 'splitWith' provide linear (O(n)) performance with respect to the number of
175+-- compositions..
176+--
177+-- 'Parser' and 'ParserK' types can be interconverted.
core/src/Streamly/Data/ParserK.hs+3−89
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
2-- |
1-- |
3-- Module : Streamly.Data.ParserK
2-- Module : Streamly.Data.ParserK
4-- Copyright : (c) 2023 Composewell Technologies
3-- Copyright : (c) 2023 Composewell Technologies
@@ -7,102 +6,19 @@
7-- Stability : pre-release
6-- Stability : pre-release
8-- Portability : GHC
7-- Portability : GHC
9--
8--
10−-- See the general notes about parsing in the "Streamly.Data.Parser" module.
11−-- This module implements a using Continuation Passing Style (CPS) wrapper over
9+-- Parsers using Continuation Passing Style (CPS). See notes in
12−-- the "Streamly.Data.Parser" module. It is as fast or faster than attoparsec.
10+-- "Streamly.Data.Parser" module to know when to use this module.
13--
11--
14−-- == Parser vs ParserK
15−--
16−-- 'ParserK' is preferred over 'Streamly.Data.Parser.Parser' when extensive
17−-- applicative, alternative and monadic composition is required, or when
18−-- recursive or dynamic composition of parsers is required. The
19−-- 'Streamly.Data.Parser.Parser' type fuses statically and creates efficient
20−-- loops whereas 'ParserK' uses function call based composition and has
21−-- comparatively larger runtime overhead but it is better suited to the
22−-- specific use cases mentioned above. 'ParserK' also allows to efficient parse
23−-- a stream of arrays, it can also break the input stream into a parse result
24−-- and remaining stream so that the stream can be parsed independently in
25−-- segments.
26−--
27−-- == Using ParserK
28−--
29−-- All the parsers from the "Streamly.Data.Parser" module can be adapted to
30−-- ParserK using the 'Streamly.Data.ParserK.adaptC',
31−-- 'Streamly.Internal.Data.ParserK.adapt', and
32−-- 'Streamly.Internal.Data.ParserK.adaptCG' combinators.
33−--
34−-- 'Streamly.Data.StreamK.parseChunks' runs a parser on a stream of unboxed
12+-- To run a 'ParserK' use 'Streamly.Data.StreamK.parseChunks'.
35−-- arrays, this is the preferred and most efficient way to parse chunked input.
36−-- The more general 'Streamly.Data.StreamK.parseBreakChunks' function returns
37−-- the remaining stream as well along with the parse result. There are
38−-- 'Streamly.Internal.Data.StreamK.parseChunksGeneric',
39−-- 'Streamly.Internal.Data.StreamK.parseBreakChunksGeneric' as well to run
40−-- parsers on boxed arrays. 'Streamly.Internal.Data.StreamK.parse',
41−-- 'Streamly.Internal.Data.StreamK.parseBreak' run parsers on a stream of
42−-- individual elements instead of stream of arrays.
43−--
44−-- == Monadic Composition
45−--
46−-- Monad composition can be used for lookbehind parsers, we can dynamically
47−-- compose new parsers based on the results of the previously parsed values.
48−--
49−-- If we have to parse "a9" or "9a" but not "99" or "aa" we can use the
50−-- following non-monadic, backtracking parser:
51−--
52−-- >>> digits p1 p2 = ((:) <$> p1 <*> ((:) <$> p2 <*> pure []))
53−-- >>> :{
54−-- backtracking :: Monad m => ParserK Char m String
55−-- backtracking = ParserK.adapt $
56−-- digits (Parser.satisfy isDigit) (Parser.satisfy isAlpha)
57−-- <|>
58−-- digits (Parser.satisfy isAlpha) (Parser.satisfy isDigit)
59−-- :}
60−--
61−-- We know that if the first parse resulted in a digit at the first place then
62−-- the second parse is going to fail. However, we waste that information and
63−-- parse the first character again in the second parse only to know that it is
64−-- not an alphabetic char. By using lookbehind in a 'Monad' composition we can
65−-- avoid redundant work:
66−--
67−-- >>> data DigitOrAlpha = Digit Char | Alpha Char
68−--
69−-- >>> :{
70−-- lookbehind :: Monad m => ParserK Char m String
71−-- lookbehind = do
72−-- x1 <- ParserK.adapt $
73−-- Digit <$> Parser.satisfy isDigit
74−-- <|> Alpha <$> Parser.satisfy isAlpha
75−-- -- Note: the parse depends on what we parsed already
76−-- x2 <- ParserK.adapt $
77−-- case x1 of
78−-- Digit _ -> Parser.satisfy isAlpha
79−-- Alpha _ -> Parser.satisfy isDigit
80−-- return $ case x1 of
81−-- Digit x -> [x,x2]
82−-- Alpha x -> [x,x2]
83−-- :}
84−--
85−-- == Experimental APIs
86−--
87−-- Please refer to "Streamly.Internal.Data.ParserK" for functions that have
88−-- not yet been released.
89--
13--
90module Streamly.Data.ParserK
14module Streamly.Data.ParserK
91 (
15 (
92− -- * Setup
93− -- | To execute the code examples provided in this module in ghci, please
94− -- run the following commands first.
95− --
96− -- $setup
97−
98 -- * Parser Type
16 -- * Parser Type
99 ParserK
17 ParserK
100
18
101 -- * Parsers
19 -- * Parsers
102 -- ** Conversions
20 -- ** Conversions
103− , adapt
104 , adaptC
21 , adaptC
105− , adaptCG
106 -- , toParser
22 -- , toParser
107
23
108 -- ** Without Input
24 -- ** Without Input
@@ -125,8 +41,6 @@ import qualified Streamly.Internal.Data.Parser as ParserD
125
41
126import Streamly.Internal.Data.ParserK.Type
42import Streamly.Internal.Data.ParserK.Type
127
43
128−#include "DocTestDataParserK.hs"
129−
130{-# DEPRECATED fromFold "Please use \"ParserK.adaptC . Parser.fromFold\" instead." #-}
44{-# DEPRECATED fromFold "Please use \"ParserK.adaptC . Parser.fromFold\" instead." #-}
131{-# INLINE fromFold #-}
45{-# INLINE fromFold #-}
132fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
46fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
core/src/Streamly/Data/Serialize.hsnew file+50
@@ -0,0 +1,50 @@
1+-- |
2+-- Module : Streamly.Data.Serialize
3+-- Copyright : (c) 2023 Composewell Technologies
4+-- License : BSD3-3-Clause
5+-- Maintainer : streamly@composewell.com
6+-- Portability : GHC
7+--
8+module Streamly.Data.Serialize
9+ (
10+
11+ -- * Types
12+ MutableByteArray
13+
14+ -- * Unbox
15+ , Unbox(..)
16+ , deriveUnbox
17+ , deriveUnboxWith
18+
19+ -- * Serialize
20+ , Serialize(..)
21+ , deriveSerialize
22+ , deriveSerializeWith
23+
24+ -- * Encoding
25+ , encode
26+ , pinnedEncode
27+
28+ -- * Decoding
29+ , decode
30+ ) where
31+
32+--------------------------------------------------------------------------------
33+-- Imports
34+--------------------------------------------------------------------------------
35+
36+import Streamly.Internal.Data.Serialize
37+ ( Serialize(..)
38+ , decode
39+ , encode
40+ , pinnedEncode
41+ )
42+import Streamly.Internal.Data.Serialize.TH
43+ ( deriveSerialize
44+ , deriveSerializeWith
45+ )
46+import Streamly.Internal.Data.Unbox
47+ ( MutableByteArray
48+ , Unbox(..)
49+ )
50+import Streamly.Internal.Data.Unbox.TH (deriveUnbox, deriveUnboxWith)
core/src/Streamly/Data/Stream.hs+36−131
@@ -70,15 +70,6 @@ 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− --
82 , fromPure
73 , fromPure
83 , fromEffect
74 , fromEffect
84 , repeat
75 , repeat
@@ -221,57 +212,21 @@ module Streamly.Data.Stream
221 -- operations like mapping a function over the stream.
212 -- operations like mapping a function over the stream.
222 , foldrM
213 , foldrM
223 , foldr
214 , foldr
224− -- foldr1
225
215
226 -- ** Specific Folds
216 -- ** Specific Folds
227− -- | Streams are folded using folds in "Streamly.Data.Fold". Here are some
217+ -- | Usually you can use the folds in "Streamly.Data.Fold". However, some
228− -- idioms and equivalents of Data.List APIs using folds:
218+ -- folds that may be commonly used or may have an edge in performance in
219+ -- some cases are provided here.
220+ --
221+ -- Useful idioms:
229 --
222 --
230 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
223 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
231− -- >>> foldl1' f = Stream.fold (Fold.foldl1' f)
224+ -- >>> foldl1 f = Stream.fold (Fold.foldl1' f)
232 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
225 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
233 -- >>> drain = Stream.fold Fold.drain
226 -- >>> drain = Stream.fold Fold.drain
234 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
227 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
235 -- >>> length = Stream.fold Fold.length
228 -- >>> length = Stream.fold Fold.length
236− -- >>> genericLength = Stream.fold Fold.lengthGeneric
237 -- >>> head = Stream.fold Fold.one
229 -- >>> 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
275 , toList
230 , toList
276
231
277 -- * Mapping
232 -- * Mapping
@@ -325,15 +280,6 @@ module Streamly.Data.Stream
325 , scan
280 , scan
326 , postscan
281 , postscan
327 -- XXX postscan1 can be implemented using Monoids or Refolds.
282 -- 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
337
283
338 -- ** Specific scans
284 -- ** Specific scans
339 -- Indexing can be considered as a special type of zipping where we zip a
285 -- Indexing can be considered as a special type of zipping where we zip a
@@ -342,8 +288,6 @@ module Streamly.Data.Stream
342
288
343 -- * Insertion
289 -- * Insertion
344 -- | Add elements to the stream.
290 -- | Add elements to the stream.
345− --
346− -- >>> insert = Stream.insertBy compare
347
291
348 -- Inserting elements is a special case of interleaving/merging streams.
292 -- Inserting elements is a special case of interleaving/merging streams.
349 , insertBy
293 , insertBy
@@ -379,15 +323,12 @@ module Streamly.Data.Stream
379 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
323 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
380 -- perform stateful filtering operations in general.
324 -- perform stateful filtering operations in general.
381 --
325 --
382− -- Idioms and equivalents of Data.List APIs:
326+ -- Useful idioms:
383 --
327 --
384 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
328 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
385− -- >>> deleteBy = Stream.deleteBy -- unreleased API
386− -- >>> delete = deleteBy (==)
387 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
329 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
388 -- >>> elemIndices a = findIndices (== a)
330 -- >>> elemIndices a = findIndices (== a)
389 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
331 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
390− -- >>> partition p = Stream.fold (Fold.partition Fold.toList Fold.toList) . fmap (if p then Left else Right)
391 , scanMaybe
332 , scanMaybe
392 , take
333 , take
393 , takeWhile
334 , takeWhile
@@ -395,8 +336,6 @@ module Streamly.Data.Stream
395 , drop
336 , drop
396 , dropWhile
337 , dropWhile
397 , dropWhileM
338 , dropWhileM
398− -- XXX write to an array in reverse and then read in reverse
399− -- > dropWhileEnd = reverse . dropWhile p . reverse
400
339
401 -- XXX These are available as scans in folds. We need to check the
340 -- XXX These are available as scans in folds. We need to check the
402 -- performance though. If these are common and we need convenient stream
341 -- performance though. If these are common and we need convenient stream
@@ -433,9 +372,6 @@ module Streamly.Data.Stream
433 -- >>> s = s1 `Stream.append` s2
372 -- >>> s = s1 `Stream.append` s2
434
373
435 -- ** Appending
374 -- ** Appending
436− -- | Equivalent of Data.List append:
437− --
438− -- >>> (++) = Stream.append
439 , append
375 , append
440
376
441 -- ** Interleaving
377 -- ** Interleaving
@@ -446,14 +382,8 @@ module Streamly.Data.Stream
446 , mergeByM
382 , mergeByM
447
383
448 -- ** Zipping
384 -- ** Zipping
449− -- | Idioms and equivalents of Data.List APIs:
450− --
451− -- >>> zip = Stream.zipWith (,)
452− -- >>> unzip = Stream.fold (Fold.unzip Fold.toList Fold.toList)
453 , zipWith
385 , zipWith
454 , zipWithM
386 , zipWithM
455− -- XXX zipWith3,4,5,6,7
456− -- XXX unzip3,4,5,6,7
457 -- , ZipStream (..)
387 -- , ZipStream (..)
458
388
459 -- ** Cross Product
389 -- ** Cross Product
@@ -486,89 +416,48 @@ module Streamly.Data.Stream
486 -- One dimension loops are just a special case of nested loops. For
416 -- One dimension loops are just a special case of nested loops. For
487 -- example, 'concatMap' can degenerate to a simple map operation:
417 -- example, 'concatMap' can degenerate to a simple map operation:
488 --
418 --
489− -- >>> map f m = Stream.concatMap (\x -> Stream.fromPure (f x)) m
419+ -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
490 --
420 --
491 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
421 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
492 -- 'nil' stream:
422 -- 'nil' stream:
493 --
423 --
494− -- >>> filter p m = Stream.concatMap (\x -> if p x then Stream.fromPure x else Stream.nil) m
424+ -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
495 --
425 --
496− -- Idioms and equivalents of Data.List APIs:
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 " "
503
426
504 , concatEffect
427 , concatEffect
505 , concatMap
428 , concatMap
506 , concatMapM
429 , concatMapM
507
430
508 -- * Repeated Fold
431 -- * Repeated Fold
509− -- | Idioms and equivalents of Data.List APIs:
432+ -- | Useful idioms:
510 --
433 --
434+ -- >>> splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
435+ -- >>> splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
436+ -- >>> groupsBy eq f = Stream.parseMany (Parser.groupBy eq f)
437+ -- >>> groupsByRolling eq f = Stream.parseMany (Parser.groupByRolling eq f)
511− -- >>> groupsOf n = Stream.foldMany (Fold.take n Fold.toList)
438+ -- >>> groupsOf n f = Stream.foldMany (Fold.take n f)
512− -- >>> groupBy eq = Stream.groupsWhile eq Fold.toList
513− -- >>> groupBy eq = Stream.parseMany (Parser.groupBy eq Fold.toList)
514− -- >>> groupsByRolling eq = Stream.parseMany (Parser.groupByRolling eq Fold.toList)
515− -- >>> groups = groupBy (==)
516 , foldMany -- XXX Rename to foldRepeat
439 , foldMany -- XXX Rename to foldRepeat
517 , groupsOf
440 , groupsOf
518 , parseMany
441 , parseMany
519
442
520 -- * Splitting
443 -- * 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)
530 , splitOn
444 , splitOn
531 , wordsBy
445 , wordsBy
532
446
533 -- * Buffered Operations
447 -- * Buffered Operations
534 -- | Operations that require buffering of the stream.
448 -- | Operations that require buffering of the stream.
535 -- Reverse is essentially a left fold followed by an unfold.
449 -- 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− --
550 , reverse
450 , 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
557
451
558 -- * Multi-Stream folds
452 -- * Multi-Stream folds
559 -- | Operations that consume multiple streams at the same time.
453 -- | Operations that consume multiple streams at the same time.
560 , eqBy
454 , eqBy
561 , cmpBy
455 , cmpBy
562 , isPrefixOf
456 , isPrefixOf
563− , isInfixOf
564− -- , isSuffixOf
565− -- , isSuffixOfUnbox
566 , isSubsequenceOf
457 , isSubsequenceOf
567
458
568 -- trimming sequences
459 -- trimming sequences
569− -- , stripPrefix
460+ , stripPrefix
570− -- , stripSuffix
571− -- , stripSuffixUnbox
572
461
573 -- Exceptions and resource management depend on the "exceptions" package
462 -- Exceptions and resource management depend on the "exceptions" package
574 -- XXX We can have IO Stream operations not depending on "exceptions"
463 -- XXX We can have IO Stream operations not depending on "exceptions"
@@ -622,20 +511,25 @@ module Streamly.Data.Stream
622 , runReaderT
511 , runReaderT
623 , runStateT
512 , runStateT
624
513
625− -- XXX Arrays could be different types, therefore, this should be in
626− -- specific array module. Or maybe we should abstract over array types.
627 -- * Stream of Arrays
514 -- * Stream of Arrays
628 , Array.chunksOf
515 , Array.chunksOf
516+ , chunksSplitOn
629 )
517 )
630where
518where
631
519
520+import Control.Monad.IO.Class (MonadIO)
521+import Data.Word (Word8)
522+import Streamly.Data.Array (Array)
632import Streamly.Internal.Data.Stream
523import Streamly.Internal.Data.Stream
633import Prelude
524import Prelude
634 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
525 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
526+ foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
527+ notElem, maximum, minimum, head, last, tail, length, null,
635− mapM, sequence, reverse, iterate, foldr1, repeat, replicate,
528+ reverse, iterate, init, and, or, lookup, foldr1, (!!),
636− concatMap)
529+ scanl, scanl1, repeat, replicate, concatMap, span)
637
530
638import qualified Streamly.Internal.Data.Array.Type as Array
531import qualified Streamly.Internal.Data.Array.Type as Array
532+import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
639
533
640#include "DocTestDataStream.hs"
534#include "DocTestDataStream.hs"
641
535
@@ -744,3 +638,14 @@ import qualified Streamly.Internal.Data.Array.Type as Array
744--
638--
745-- 'Stream' and 'StreamK' types can be interconverted. See
639-- 'Stream' and 'StreamK' types can be interconverted. See
746-- "Streamly.Data.StreamK" module for conversion operations.
640-- "Streamly.Data.StreamK" module for conversion operations.
641+
642+-- | Split a stream of arrays on a given separator byte, dropping the separator
643+-- and coalescing all the arrays between two separators into a single array.
644+--
645+{-# INLINE chunksSplitOn #-}
646+chunksSplitOn
647+ :: (MonadIO m)
648+ => Word8
649+ -> Stream m (Array Word8)
650+ -> Stream m (Array Word8)
651+chunksSplitOn = ArrayStream.splitOn
core/src/Streamly/Data/StreamK.hs+1−2
@@ -95,8 +95,7 @@ module Streamly.Data.StreamK
95 -- , foldBreak
95 -- , foldBreak
96
96
97 -- ** Parsing
97 -- ** Parsing
98− , parse
99− , parseBreak
98+ -- , parseBreak
100 , parseBreakChunks
99 , parseBreakChunks
101 , parseChunks
100 , parseChunks
102
101
core/src/Streamly/Data/Unfold.hs−2
@@ -65,8 +65,6 @@ module Streamly.Data.Unfold
65 -- ** Mapping on Input
65 -- ** Mapping on Input
66 , lmap
66 , lmap
67 , lmapM
67 , lmapM
68− , first
69− , second
70
68
71 -- ** Mapping on Output
69 -- ** Mapping on Output
72 , mapM
70 , mapM
core/src/Streamly/FileSystem/Handle.hs+30−7
@@ -1,4 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+#include "inline.hs"
2
3
3-- |
4-- |
4-- Module : Streamly.FileSystem.Handle
5-- Module : Streamly.FileSystem.Handle
@@ -81,13 +82,13 @@ module Streamly.FileSystem.Handle
81 -- position of the file handle. The stream ends as soon as EOF is
82 -- position of the file handle. The stream ends as soon as EOF is
82 -- encountered.
83 -- encountered.
83
84
84− -- *** Streams
85+ -- -- *** Streams
85− , read
86+ -- , read
86− , readWith
87+ -- , readWith
87− , readChunks
88+ -- , readChunks
88− , readChunksWith
89+ -- , readChunksWith
89
90
90− -- *** Unfolds
91+ -- -- *** Unfolds
91 , reader
92 , reader
92 , readerWith
93 , readerWith
93 , chunkReader
94 , chunkReader
@@ -104,14 +105,36 @@ module Streamly.FileSystem.Handle
104 , writeChunks
105 , writeChunks
105
106
106 -- * Deprecated
107 -- * Deprecated
108+ , read
107 , readWithBufferOf
109 , readWithBufferOf
110+ , readChunks
108 , readChunksWithBufferOf
111 , readChunksWithBufferOf
109 , writeChunksWithBufferOf
112 , writeChunksWithBufferOf
110 , writeWithBufferOf
113 , writeWithBufferOf
111 )
114 )
112where
115where
113
116
117+import Control.Monad.IO.Class (MonadIO(..))
118+import Data.Word (Word8)
119+import Streamly.Internal.Data.Array.Type (Array)
120+import Streamly.Internal.Data.Unfold.Type (Unfold)
121+import System.IO (Handle)
122+
114−import Streamly.Internal.FileSystem.Handle
123+import Streamly.Internal.FileSystem.Handle hiding (read, readChunks)
115import Prelude hiding (read)
124import Prelude hiding (read)
116
125
117#include "DocTestFileSystemHandle.hs"
126#include "DocTestFileSystemHandle.hs"
127+
128+-- | Same as 'reader'
129+--
130+{-# DEPRECATED read "Please use 'reader' instead" #-}
131+{-# INLINE read #-}
132+read :: MonadIO m => Unfold m Handle Word8
133+read = reader
134+
135+-- | Same as 'chunkReader'
136+--
137+{-# DEPRECATED readChunks "Please use 'chunkReader' instead" #-}
138+{-# INLINE readChunks #-}
139+readChunks :: MonadIO m => Unfold m Handle (Array Word8)
140+readChunks = chunkReader
core/src/Streamly/Internal/Data/Array.hs+135−608
@@ -2,6 +2,7 @@
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+--
5-- License : BSD3
6-- License : BSD3
6-- Maintainer : streamly@composewell.com
7-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Stability : experimental
@@ -19,21 +20,33 @@ module Streamly.Internal.Data.Array
19 module Streamly.Internal.Data.Array.Type
20 module Streamly.Internal.Data.Array.Type
20
21
21 -- * Construction
22 -- * Construction
23+ -- Stream Folds
24+ , fromStreamN
25+ , fromStream
26+
22 -- Monadic Folds
27 -- Monadic Folds
23 , writeLastN
28 , writeLastN
24
29
30+ -- * Elimination
31+ -- ** Conversion
32+
33+ -- ** Unfolds
34+ , reader
35+ , readerUnsafe
36+ , producer -- experimental
37+
25 -- * Random Access
38 -- * Random Access
26 -- , (!!)
39 -- , (!!)
27 , getIndex
40 , getIndex
28 , getIndexRev
41 , getIndexRev
29− , last -- XXX getLastIndex?
42+ , last -- XXX getIndexLast?
43+ , getIndices
44+ , getIndicesFromThenTo
30 -- , getIndicesFrom -- read from a given position to the end of file
45 -- , getIndicesFrom -- read from a given position to the end of file
31 -- , getIndicesUpto -- read from beginning up to the given position
46 -- , getIndicesUpto -- read from beginning up to the given position
32 -- , getIndicesFromTo
47 -- , getIndicesFromTo
33 -- , getIndicesFromRev -- read from a given position to the beginning of file
48 -- , getIndicesFromRev -- read from a given position to the beginning of file
34 -- , getIndicesUptoRev -- read from end to the given position in file
49 -- , getIndicesUptoRev -- read from end to the given position in file
35− , indexReader
36− , indexReaderFromThenTo
37
50
38 -- * Size
51 -- * Size
39 , null
52 , null
@@ -41,8 +54,6 @@ module Streamly.Internal.Data.Array
41 -- * Search
54 -- * Search
42 , binarySearch
55 , binarySearch
43 , findIndicesOf
56 , findIndicesOf
44− -- getIndicesOf
45− , indexFinder -- see splitOn
46 -- , findIndexOf
57 -- , findIndexOf
47 -- , find
58 -- , find
48
59
@@ -55,89 +66,51 @@ module Streamly.Internal.Data.Array
55 -- * Subarrays
66 -- * Subarrays
56 , getSliceUnsafe
67 , getSliceUnsafe
57 -- , getSlice
68 -- , getSlice
58− , sliceIndexerFromLen
69+ , genSlicesFromLen
59− , slicerFromLen
70+ , getSlicesFromLen
60 , splitOn
71 , splitOn
61
72
62 -- * Streaming Operations
73 -- * Streaming Operations
63 , streamTransform
74 , streamTransform
64
75
65− -- * Folding
76+ -- ** Folding
66 , streamFold
77 , streamFold
67 , fold
78 , fold
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−
87− -- * Serialization
88− , encodeAs
89− , serialize
90− , pinnedSerialize
91− , deserialize
92−
93− -- * Deprecated
94− , genSlicesFromLen
95− , getSlicesFromLen
96− , getIndices
97 )
79 )
98where
80where
99
81
100−#include "assert.hs"
101#include "inline.hs"
82#include "inline.hs"
102#include "ArrayMacros.h"
83#include "ArrayMacros.h"
103
84
85+import Control.Exception (assert)
86+import Control.Monad (when)
104import Control.Monad.IO.Class (MonadIO(..))
87import Control.Monad.IO.Class (MonadIO(..))
105−-- import Data.Bifunctor (first)
106−-- import Data.Either (fromRight)
107import Data.Functor.Identity (Identity)
88import Data.Functor.Identity (Identity)
108import Data.Proxy (Proxy(..))
89import Data.Proxy (Proxy(..))
109import Data.Word (Word8)
90import Data.Word (Word8)
110import Foreign.C.String (CString)
91import Foreign.C.String (CString)
111import Foreign.Ptr (castPtr)
92import Foreign.Ptr (castPtr)
112import Foreign.Storable (Storable)
93import Foreign.Storable (Storable)
113−import GHC.Types (SPEC(..))
114import Streamly.Internal.Data.Unbox (Unbox(..))
94import Streamly.Internal.Data.Unbox (Unbox(..))
115import Prelude hiding (length, null, last, map, (!!), read, concat)
95import Prelude hiding (length, null, last, map, (!!), read, concat)
116
96
117−import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..), MutByteArray)
118−import Streamly.Internal.Data.Serialize.Type (Serialize)
119import Streamly.Internal.Data.Fold.Type (Fold(..))
97import Streamly.Internal.Data.Fold.Type (Fold(..))
120−import Streamly.Internal.Data.Parser (Parser(..), Initial(..), ParseError(..))
98+import Streamly.Internal.Data.Producer.Type (Producer(..))
121−import Streamly.Internal.Data.Stream (Stream(..))
99+import Streamly.Internal.Data.Stream (Stream)
122−import Streamly.Internal.Data.StreamK (StreamK)
123−import Streamly.Internal.Data.SVar.Type (adaptState, defState)
124−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3Fused'(..))
100+import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
125import Streamly.Internal.Data.Unfold.Type (Unfold(..))
101import Streamly.Internal.Data.Unfold.Type (Unfold(..))
126import Streamly.Internal.System.IO (unsafeInlineIO)
102import Streamly.Internal.System.IO (unsafeInlineIO)
127
103
128−import qualified Streamly.Internal.Data.Fold.Type as Fold
104+import qualified Streamly.Internal.Data.MutArray.Type as MA
129−import qualified Streamly.Internal.Data.Serialize.Type as Serialize
130−import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
131import qualified Streamly.Internal.Data.MutArray as MA
105import qualified Streamly.Internal.Data.MutArray as MA
106+import qualified Streamly.Internal.Data.Array.Type as A
132import qualified Streamly.Internal.Data.Fold as FL
107import qualified Streamly.Internal.Data.Fold as FL
108+import qualified Streamly.Internal.Data.Producer.Type as Producer
109+import qualified Streamly.Internal.Data.Producer as Producer
133import qualified Streamly.Internal.Data.Ring as RB
110import 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
136import qualified Streamly.Internal.Data.Stream as D
111import qualified Streamly.Internal.Data.Stream as D
137import qualified Streamly.Internal.Data.Stream as Stream
112import qualified Streamly.Internal.Data.Stream as Stream
138−import qualified Streamly.Internal.Data.StreamK as StreamK
139import qualified Streamly.Internal.Data.Unfold as Unfold
113import qualified Streamly.Internal.Data.Unfold as Unfold
140−import qualified Prelude
141
114
142import Streamly.Internal.Data.Array.Type
115import Streamly.Internal.Data.Array.Type
143
116
@@ -166,10 +139,82 @@ import Streamly.Internal.Data.Array.Type
166-- if we use one array for each chunk. This is still significant to add
139-- if we use one array for each chunk. This is still significant to add
167-- pressure to GC.
140-- pressure to GC.
168
141
142+-------------------------------------------------------------------------------
143+-- Construction
144+-------------------------------------------------------------------------------
145+
146+-- | Create an 'Array' from the first N elements of a stream. The array is
147+-- allocated to size N, if the stream terminates before N elements then the
148+-- array may hold less than N elements.
149+--
150+-- /Pre-release/
151+{-# INLINE fromStreamN #-}
152+fromStreamN :: (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
153+fromStreamN n m = do
154+ when (n < 0) $ error "writeN: negative write count specified"
155+ A.fromStreamDN n m
156+
157+-- | Create an 'Array' from a stream. This is useful when we want to create a
158+-- single array from a stream of unknown size. 'writeN' is at least twice
159+-- as efficient when the size is already known.
160+--
161+-- Note that if the input stream is too large memory allocation for the array
162+-- may fail. When the stream size is not known, `chunksOf` followed by
163+-- processing of indvidual arrays in the resulting stream should be preferred.
164+--
165+-- /Pre-release/
166+{-# INLINE fromStream #-}
167+fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (Array a)
168+fromStream = Stream.fold A.write
169+-- write m = A.fromStreamD $ D.fromStreamK m
170+
169-------------------------------------------------------------------------------
171-------------------------------------------------------------------------------
170-- Elimination
172-- Elimination
171-------------------------------------------------------------------------------
173-------------------------------------------------------------------------------
172
174
175+{-# INLINE_NORMAL producer #-}
176+producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
177+producer =
178+ Producer.translate A.unsafeThaw A.unsafeFreeze
179+ $ MA.producerWith (return . unsafeInlineIO)
180+
181+-- | Unfold an array into a stream.
182+--
183+{-# INLINE_NORMAL reader #-}
184+reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
185+reader = Producer.simplify producer
186+
187+-- | Unfold an array into a stream, does not check the end of the array, the
188+-- user is responsible for terminating the stream within the array bounds. For
189+-- high performance application where the end condition can be determined by
190+-- a terminating fold.
191+--
192+-- Written in the hope that it may be faster than "read", however, in the case
193+-- for which this was written, "read" proves to be faster even though the core
194+-- generated with unsafeRead looks simpler.
195+--
196+-- /Pre-release/
197+--
198+{-# INLINE_NORMAL readerUnsafe #-}
199+readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
200+readerUnsafe = Unfold step inject
201+ where
202+
203+ inject (Array contents start end) =
204+ return (ArrayUnsafe contents end start)
205+
206+ {-# INLINE_LATE step #-}
207+ step (ArrayUnsafe contents end p) = do
208+ -- unsafeInlineIO allows us to run this in Identity monad for pure
209+ -- toList/foldr case which makes them much faster due to not
210+ -- accumulating the list and fusing better with the pure consumers.
211+ --
212+ -- This should be safe as the array contents are guaranteed to be
213+ -- evaluated/written to before we peek at them.
214+ let !x = unsafeInlineIO $ peekByteIndex p contents
215+ let !p1 = INDEX_NEXT(p,a)
216+ return $ D.Yield x (ArrayUnsafe contents end p1)
217+
173-- |
218-- |
174--
219--
175-- >>> null arr = Array.byteLength arr == 0
220-- >>> null arr = Array.byteLength arr == 0
@@ -177,7 +222,7 @@ import Streamly.Internal.Data.Array.Type
177-- /Pre-release/
222-- /Pre-release/
178{-# INLINE null #-}
223{-# INLINE null #-}
179null :: Array a -> Bool
224null :: Array a -> Bool
180−null arr = byteLength arr == 0
225+null arr = A.byteLength arr == 0
181
226
182-- | Like 'getIndex' but indexes the array in reverse from the end.
227-- | Like 'getIndex' but indexes the array in reverse from the end.
183--
228--
@@ -189,7 +234,7 @@ getIndexRev i arr =
189 $ do
234 $ do
190 let elemPtr = RINDEX_OF(arrEnd arr, i, a)
235 let elemPtr = RINDEX_OF(arrEnd arr, i, a)
191 if i >= 0 && elemPtr >= arrStart arr
236 if i >= 0 && elemPtr >= arrStart arr
192− then Just <$> peekAt elemPtr (arrContents arr)
237+ then Just <$> peekByteIndex elemPtr (arrContents arr)
193 else return Nothing
238 else return Nothing
194
239
195-- |
240-- |
@@ -205,8 +250,6 @@ last = getIndexRev 0
205-- Folds with Array as the container
250-- Folds with Array as the container
206-------------------------------------------------------------------------------
251-------------------------------------------------------------------------------
207
252
208−-- XXX We should generate this from Ring.
209−
210-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
253-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
211-- stream to an 'Array'.
254-- stream to an 'Array'.
212--
255--
@@ -215,7 +258,7 @@ writeLastN ::
215 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
258 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
216writeLastN n
259writeLastN n
217 | n <= 0 = fmap (const mempty) FL.drain
260 | n <= 0 = fmap (const mempty) FL.drain
218− | otherwise = unsafeFreeze <$> Fold step initial done done
261+ | otherwise = A.unsafeFreeze <$> Fold step initial done
219
262
220 where
263 where
221
264
@@ -228,9 +271,11 @@ writeLastN n
228 in fmap f $ liftIO $ RB.new n
271 in fmap f $ liftIO $ RB.new n
229
272
230 done (Tuple3Fused' rb rh i) = do
273 done (Tuple3Fused' rb rh i) = do
231− arr <- MA.new n
274+ arr <- liftIO $ MA.new n
275+ foldFunc i rh snoc' arr rb
276+
232− -- XXX We should write a read unfold for ring.
277+ -- XXX We should write a read unfold for ring.
233− foldFunc i rh MA.snocUnsafe arr rb
278+ snoc' b a = liftIO $ MA.snocUnsafe b a
234
279
235 foldFunc i
280 foldFunc i
236 | i < n = RB.unsafeFoldRingM
281 | i < n = RB.unsafeFoldRingM
@@ -256,26 +301,19 @@ binarySearch = undefined
256-- compared to streams by using SIMD instructions.
301-- compared to streams by using SIMD instructions.
257-- We can also return a bit array instead.
302-- We can also return a bit array instead.
258
303
259−-- Can use SIMD.
260−
261-- | Perform a linear search to find all the indices where a given element is
304-- | Perform a linear search to find all the indices where a given element is
262-- present in an array.
305-- present in an array.
263--
306--
264-- /Unimplemented/
307-- /Unimplemented/
265−indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
308+findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
266−indexFinder = undefined
309+findIndicesOf = undefined
267−
268−-- |
269−-- /Unimplemented/
270−findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
271−findIndicesOf p = Stream.unfold (indexFinder p)
272
310
273{-
311{-
274findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
312findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
275−findIndexOf p = Unfold.fold Fold.one . Stream.unfold (indexFinder p)
313+findIndexOf p = Unfold.fold Fold.one . Stream.unfold (findIndicesOf p)
276
314
277find :: (a -> Bool) -> Array a -> Bool
315find :: (a -> Bool) -> Array a -> Bool
278−find = Unfold.fold Fold.null . Stream.unfold (indexFinder p)
316+find = Unfold.fold Fold.null . Stream.unfold (findIndicesOf p)
279-}
317-}
280
318
281-------------------------------------------------------------------------------
319-------------------------------------------------------------------------------
@@ -317,45 +355,29 @@ splitOn :: (Monad m, Unbox a) =>
317 (a -> Bool) -> Array a -> Stream m (Array a)
355 (a -> Bool) -> Array a -> Stream m (Array a)
318splitOn predicate arr =
356splitOn predicate arr =
319 fmap (\(i, len) -> getSliceUnsafe i len arr)
357 fmap (\(i, len) -> getSliceUnsafe i len arr)
320− $ D.indexOnSuffix predicate (read arr)
358+ $ D.sliceOnSuffix predicate (A.toStreamD arr)
321−
322−{-# INLINE sliceIndexerFromLen #-}
323−sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
324− => Int -- ^ from index
325− -> Int -- ^ length of the slice
326− -> Unfold m (Array a) (Int, Int)
327−sliceIndexerFromLen from len =
328− Unfold.lmap unsafeThaw (MA.sliceIndexerFromLen from len)
329
359
330−{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
331{-# INLINE genSlicesFromLen #-}
360{-# INLINE genSlicesFromLen #-}
332genSlicesFromLen :: forall m a. (Monad m, Unbox a)
361genSlicesFromLen :: forall m a. (Monad m, Unbox a)
333 => Int -- ^ from index
362 => Int -- ^ from index
334 -> Int -- ^ length of the slice
363 -> Int -- ^ length of the slice
335 -> Unfold m (Array a) (Int, Int)
364 -> Unfold m (Array a) (Int, Int)
336−genSlicesFromLen = sliceIndexerFromLen
365+genSlicesFromLen from len =
366+ Unfold.lmap A.unsafeThaw (MA.genSlicesFromLen from len)
337
367
338-- | Generate a stream of slices of specified length from an array, starting
368-- | Generate a stream of slices of specified length from an array, starting
339-- from the supplied array index. The last slice may be shorter than the
369-- from the supplied array index. The last slice may be shorter than the
340-- requested length.
370-- requested length.
341--
371--
342-- /Pre-release//
372-- /Pre-release//
343−{-# INLINE slicerFromLen #-}
344−slicerFromLen :: forall m a. (Monad m, Unbox a)
345− => Int -- ^ from index
346− -> Int -- ^ length of the slice
347− -> Unfold m (Array a) (Array a)
348−slicerFromLen from len =
349− fmap unsafeFreeze
350− $ Unfold.lmap unsafeThaw (MA.slicerFromLen from len)
351−
352−{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
353{-# INLINE getSlicesFromLen #-}
373{-# INLINE getSlicesFromLen #-}
354getSlicesFromLen :: forall m a. (Monad m, Unbox a)
374getSlicesFromLen :: forall m a. (Monad m, Unbox a)
355 => Int -- ^ from index
375 => Int -- ^ from index
356 -> Int -- ^ length of the slice
376 -> Int -- ^ length of the slice
357 -> Unfold m (Array a) (Array a)
377 -> Unfold m (Array a) (Array a)
358−getSlicesFromLen = slicerFromLen
378+getSlicesFromLen from len =
379+ fmap A.unsafeFreeze
380+ $ Unfold.lmap A.unsafeThaw (MA.getSlicesFromLen from len)
359
381
360-------------------------------------------------------------------------------
382-------------------------------------------------------------------------------
361-- Random reads and writes
383-- Random reads and writes
@@ -373,7 +395,7 @@ getIndex i arr =
373 $ do
395 $ do
374 let elemPtr = INDEX_OF(arrStart arr, i, a)
396 let elemPtr = INDEX_OF(arrStart arr, i, a)
375 if i >= 0 && INDEX_VALID(elemPtr, arrEnd arr, a)
397 if i >= 0 && INDEX_VALID(elemPtr, arrEnd arr, a)
376− then Just <$> peekAt elemPtr (arrContents arr)
398+ then Just <$> peekByteIndex elemPtr (arrContents arr)
377 else return Nothing
399 else return Nothing
378
400
379-- | Given a stream of array indices, read the elements on those indices from
401-- | Given a stream of array indices, read the elements on those indices from
@@ -385,25 +407,19 @@ getIndex i arr =
385-- @
407-- @
386-- read =
408-- read =
387-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
409-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
388−-- in Unfold.lmap f (indexReader arr)
410+-- in Unfold.lmap f (getIndices arr)
389--
411--
390-- readRev =
412-- readRev =
391-- let i = length arr - 1
413-- let i = length arr - 1
392−-- in Unfold.lmap f (indexReaderFromThenTo i (i - 1) 0)
414+-- in Unfold.lmap f (getIndicesFromThenTo i (i - 1) 0)
393-- @
415-- @
394--
416--
395-- /Pre-release/
417-- /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." #-}
404{-# INLINE getIndices #-}
418{-# INLINE getIndices #-}
405getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
419getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
406−getIndices = indexReader
420+getIndices m =
421+ let unf = MA.getIndicesD (return . unsafeInlineIO) m
422+ in Unfold.lmap A.unsafeThaw unf
407
423
408-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
424-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
409-- element is the array value from the index @from@ and the successive elements
425-- element is the array value from the index @from@ and the successive elements
@@ -419,9 +435,9 @@ getIndices = indexReader
419-- @
435-- @
420--
436--
421-- /Unimplemented/
437-- /Unimplemented/
422−{-# INLINE indexReaderFromThenTo #-}
438+{-# INLINE getIndicesFromThenTo #-}
423−indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
439+getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
424−indexReaderFromThenTo = undefined
440+getIndicesFromThenTo = undefined
425
441
426-------------------------------------------------------------------------------
442-------------------------------------------------------------------------------
427-- Transform via stream operations
443-- Transform via stream operations
@@ -438,7 +454,7 @@ indexReaderFromThenTo = undefined
438{-# INLINE runPipe #-}
454{-# INLINE runPipe #-}
439runPipe :: (MonadIO m, Unbox a, Unbox b)
455runPipe :: (MonadIO m, Unbox a, Unbox b)
440 => Pipe m a b -> Array a -> m (Array b)
456 => Pipe m a b -> Array a -> m (Array b)
441−runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
457+runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
442-}
458-}
443
459
444-- XXX For transformations that cannot change the number of elements e.g. "map"
460-- XXX For transformations that cannot change the number of elements e.g. "map"
@@ -452,7 +468,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
452streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
468streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
453 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
469 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
454streamTransform f arr =
470streamTransform f arr =
455− Stream.fold (createWith (length arr)) $ f (read arr)
471+ Stream.fold (A.writeWith (length arr)) $ f (A.read arr)
456
472
457-------------------------------------------------------------------------------
473-------------------------------------------------------------------------------
458-- Casts
474-- Casts
@@ -486,7 +502,7 @@ asBytes = castUnsafe
486--
502--
487cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
503cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
488cast arr =
504cast arr =
489− let len = byteLength arr
505+ let len = A.byteLength arr
490 r = len `mod` SIZE_OF(b)
506 r = len `mod` SIZE_OF(b)
491 in if r /= 0
507 in if r /= 0
492 then Nothing
508 then Nothing
@@ -504,9 +520,9 @@ cast arr =
504--
520--
505asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
521asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
506asCStringUnsafe arr act = do
522asCStringUnsafe arr act = do
507− let arr1 = asBytes arr <> fromList [0]
523+ let arr1 = asBytes arr <> A.fromList [0]
508− -- unsafePinnedAsPtr makes sure the array is pinned
524+ -- asPtrUnsafe makes sure the array is pinned
509− unsafePinnedAsPtr arr1 $ \ptr -> act (castPtr ptr)
525+ asPtrUnsafe arr1 $ \ptr -> act (castPtr ptr)
510
526
511-------------------------------------------------------------------------------
527-------------------------------------------------------------------------------
512-- Folds
528-- Folds
@@ -519,500 +535,11 @@ asCStringUnsafe arr act = do
519-- /Pre-release/
535-- /Pre-release/
520{-# INLINE fold #-}
536{-# INLINE fold #-}
521fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
537fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
522−fold f arr = Stream.fold f (read arr)
538+fold f arr = Stream.fold f (A.read arr)
523
539
524-- | Fold an array using a stream fold operation.
540-- | Fold an array using a stream fold operation.
525--
541--
526-- /Pre-release/
542-- /Pre-release/
527{-# INLINE streamFold #-}
543{-# INLINE streamFold #-}
528streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
544streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
529−streamFold f arr = f (read arr)
545+streamFold f arr = f (A.read arr)
530−
531−--------------------------------------------------------------------------------
532−-- Serialization
533−--------------------------------------------------------------------------------
534−
535−{-# INLINE encodeAs #-}
536−encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
537−encodeAs ps a =
538− unsafeInlineIO $ do
539− let len = Serialize.addSizeTo 0 a
540− mbarr <- MBA.newBytesAs ps len
541− off <- Serialize.serializeAt 0 mbarr a
542− assertM(len == off)
543− pure $ Array mbarr 0 off
544−
545−-- |
546−-- Properties:
547−-- 1. Identity: @deserialize . serialize == id@
548−-- 2. Encoded equivalence: @serialize a == serialize a@
549−{-# INLINE serialize #-}
550−serialize :: Serialize a => a -> Array Word8
551−serialize = encodeAs Unpinned
552−
553−-- | Serialize a Haskell type to a pinned byte array. The array is allocated
554−-- using pinned memory so that it can be used directly in OS APIs for writing
555−-- to file or sending over the network.
556−--
557−-- Properties:
558−-- 1. Identity: @deserialize . pinnedSerialize == id@
559−-- 2. Encoded equivalence: @pinnedSerialize a == pinnedSerialize a@
560−{-# INLINE pinnedSerialize #-}
561−pinnedSerialize :: Serialize a => a -> Array Word8
562−pinnedSerialize = encodeAs Pinned
563−
564−-- | Decode a Haskell type from a byte array containing its serialized
565−-- representation.
566−{-# INLINE deserialize #-}
567−deserialize :: Serialize a => Array Word8 -> a
568−deserialize arr@(Array {..}) = unsafeInlineIO $ do
569− let lenArr = length arr
570− (off, val) <-
571− Serialize.deserializeAt arrStart arrContents (arrStart + lenArr)
572− assertM(off == arrStart + lenArr)
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+6−22
@@ -11,8 +11,8 @@ module Streamly.Internal.Data.Array.Generic
11
11
12 -- * Construction
12 -- * Construction
13 , nil
13 , nil
14− , createOf
14+ , writeN
15− , create
15+ , write
16 , writeWith
16 , writeWith
17 , writeLastN
17 , writeLastN
18
18
@@ -44,10 +44,6 @@ 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
51 )
47 )
52where
48where
53
49
@@ -108,33 +104,21 @@ nil = unsafePerformIO $ unsafeFreeze <$> MArray.nil
108-- Construction - Folds
104-- Construction - Folds
109-------------------------------------------------------------------------------
105-------------------------------------------------------------------------------
110
106
111−{-# INLINE_NORMAL createOf #-}
107+{-# INLINE_NORMAL writeN #-}
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 #-}
118writeN :: MonadIO m => Int -> Fold m a (Array a)
108writeN :: MonadIO m => Int -> Fold m a (Array a)
119−writeN = createOf
109+writeN = fmap unsafeFreeze <$> MArray.writeN
120
110
121{-# INLINE_NORMAL writeWith #-}
111{-# INLINE_NORMAL writeWith #-}
122writeWith :: MonadIO m => Int -> Fold m a (Array a)
112writeWith :: MonadIO m => Int -> Fold m a (Array a)
123−writeWith elemCount = unsafeFreeze <$> MArray.createWith elemCount
113+writeWith elemCount = unsafeFreeze <$> MArray.writeWith elemCount
124
114
125-- | Fold the whole input to a single array.
115-- | Fold the whole input to a single array.
126--
116--
127-- /Caution! Do not use this on infinite streams./
117-- /Caution! Do not use this on infinite streams./
128--
118--
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." #-}
135{-# INLINE write #-}
119{-# INLINE write #-}
136write :: MonadIO m => Fold m a (Array a)
120write :: MonadIO m => Fold m a (Array a)
137−write = create
121+write = fmap unsafeFreeze MArray.write
138
122
139fromPureStream :: Stream Identity a -> Array a
123fromPureStream :: Stream Identity a -> Array a
140fromPureStream x =
124fromPureStream x =
core/src/Streamly/Internal/Data/Array/Type.hs+109−518
@@ -1,11 +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 #-}
6-- |
2-- |
7-- Module : Streamly.Internal.Data.Array.Type
3-- Module : Streamly.Internal.Data.Array.Type
8-- Copyright : (c) 2020 Composewell Technologies
4-- Copyright : (c) 2020 Composewell Technologies
5+--
9-- License : BSD3-3-Clause
6-- License : BSD3-3-Clause
10-- Maintainer : streamly@composewell.com
7-- Maintainer : streamly@composewell.com
11-- Stability : experimental
8-- Stability : experimental
@@ -13,146 +10,86 @@
13--
10--
14-- See notes in "Streamly.Internal.Data.MutArray.Type"
11-- See notes in "Streamly.Internal.Data.MutArray.Type"
15--
12--
16−
17module Streamly.Internal.Data.Array.Type
13module Streamly.Internal.Data.Array.Type
18 (
14 (
19− -- ** Type
20 -- $arrayNotes
15 -- $arrayNotes
21 Array (..)
16 Array (..)
17+ , asPtrUnsafe
18+ , nil
22
19
23− -- ** Conversion
20+ -- * Freezing and Thawing
24− -- *** Mutable and Immutable
25 , unsafeFreeze
21 , unsafeFreeze
26 , unsafeFreezeWithShrink
22 , unsafeFreezeWithShrink
27 , unsafeThaw
23 , unsafeThaw
28
24
29− -- *** Pinned and Unpinned
25+ -- * Pinning and Unpinning
30 , pin
26 , pin
31 , unpin
27 , unpin
32 , isPinned
28 , isPinned
33
29
34− -- *** Casting
35− , unsafePinnedAsPtr
36−
37− -- ** Construction
30+ -- * Construction
38− , empty
31+ , splice
39−
40− -- *** Cloning
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
32
50− -- *** Stream Folds
51− , unsafeMakePure
52− , createOf
53− , pinnedCreateOf
54− , unsafeCreateOf
55− , unsafePinnedCreateOf
56− , create
57− , pinnedCreate
58− , createWith
59−
60− -- *** From containers
61− , fromListN
62− , pinnedFromListN
63 , fromList
33 , fromList
64 , pinnedFromList
34 , pinnedFromList
65− , fromListRevN
35+ , fromListN
36+ , pinnedFromListN
66 , fromListRev
37 , fromListRev
67− , fromStreamN
38+ , fromListRevN
68− , fromStream
39+ , fromStreamDN
69− , fromPureStreamN
40+ , fromStreamD
70 , fromPureStream
41 , fromPureStream
71 , fromByteStr#
42 , fromByteStr#
72− , fromByteStr
73− , fromPtrN
74− , fromChunks
75− , fromChunksK
76
43
77− -- ** Reading
44+ -- * Split
45+ , breakOn
78
46
79− -- *** Indexing
47+ -- ** Cloning arrays
80− , unsafeIndexIO -- XXX unsafeGetIndexIO
48+ , clone
81− , getIndexUnsafe -- XXX unsafeGetIndex
49+ , pinnedClone
82−
83− -- *** To Streams
84− , read
85− , readRev
86− , toStreamK
87− , toStreamKRev
88−
89− -- *** To Containers
90− , toList
91−
92− -- *** Unfolds
93− , producer -- experimental
94− , readerUnsafe
95− , reader
96− , readerRev
97
50
98− -- *** Size
51+ -- * Elimination
99− , length
52+ , unsafeIndexIO
53+ , getIndexUnsafe
100 , byteLength
54 , byteLength
55+ , length
101
56
102− -- ** Folding
103 , foldl'
57 , foldl'
104 , foldr
58 , foldr
105− , byteCmp
59+ , splitAt
106− , byteEq
107−
108− -- ** Appending
109− , splice -- XXX requires MonadIO
110−
111− -- ** Streams of arrays
112− -- *** Chunk
113− -- | Group a stream into arrays.
114− , chunksOf
115− , pinnedChunksOf
116− , buildChunks
117−
118− -- *** Split
119− -- | Split an array into slices.
120−
121− -- *** Concat
122− -- | Append the arrays in a stream to form a stream of elements.
123− , concat
124− , concatRev
125−
126− -- *** Compact
127− -- | Append the arrays in a stream to form a stream of larger arrays.
128− , fCompactGE
129− , fPinnedCompactGE
130− , lCompactGE
131− , lPinnedCompactGE
132− , compactGE
133
60
134− -- ** Deprecated
135− , asPtrUnsafe
136− , unsafeIndex
137− , bufferChunks
138− , flattenArrays
139− , flattenArraysRev
140− , fromArrayStreamK
141− , fromStreamDN
142− , fromStreamD
143 , toStreamD
61 , toStreamD
144 , toStreamDRev
62 , toStreamDRev
63+ , toStreamK
64+ , toStreamKRev
145 , toStream
65 , toStream
146 , toStreamRev
66 , toStreamRev
147− , nil
67+ , read
68+ , readRev
69+ , readerRev
70+ , toList
71+
72+ -- * Folds
148 , writeWith
73 , writeWith
149 , writeN
74 , writeN
150 , pinnedWriteN
75 , pinnedWriteN
151 , writeNUnsafe
76 , writeNUnsafe
152 , pinnedWriteNUnsafe
77 , pinnedWriteNUnsafe
78+ , MA.ArrayUnsafe (..)
153 , pinnedWriteNAligned
79 , pinnedWriteNAligned
154 , write
80 , write
155 , pinnedWrite
81 , pinnedWrite
82+ , unsafeMakePure
83+
84+ -- * Streams of arrays
85+ , chunksOf
86+ , pinnedChunksOf
87+ , bufferChunks
88+ , flattenArrays
89+ , flattenArraysRev
90+
91+ -- * Deprecated
92+ , unsafeIndex
156 )
93 )
157where
94where
158
95
@@ -160,36 +97,31 @@ where
160#include "inline.hs"
97#include "inline.hs"
161
98
162import Control.Exception (assert)
99import Control.Exception (assert)
163−import Control.Monad (replicateM, when)
100+import Control.Monad (replicateM)
164import Control.Monad.IO.Class (MonadIO(..))
101import Control.Monad.IO.Class (MonadIO(..))
165import Data.Functor.Identity (Identity(..))
102import Data.Functor.Identity (Identity(..))
166−import Data.Int (Int8, Int16, Int32, Int64)
167import Data.Proxy (Proxy(..))
103import Data.Proxy (Proxy(..))
168−import Data.Word (Word8, Word16, Word32, Word64)
104+import Data.Word (Word8)
169import GHC.Base (build)
105import GHC.Base (build)
170import GHC.Exts (IsList, IsString(..), Addr#)
106import GHC.Exts (IsList, IsString(..), Addr#)
171
107
172import GHC.IO (unsafePerformIO)
108import GHC.IO (unsafePerformIO)
173import GHC.Ptr (Ptr(..))
109import GHC.Ptr (Ptr(..))
174−import Streamly.Internal.Data.Producer.Type (Producer(..))
110+import Streamly.Internal.Data.MutArray.Type (MutArray(..), MutableByteArray)
175−import Streamly.Internal.Data.MutArray.Type (MutArray(..))
176−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
177import Streamly.Internal.Data.Fold.Type (Fold(..))
111import Streamly.Internal.Data.Fold.Type (Fold(..))
178import Streamly.Internal.Data.Stream.Type (Stream)
112import Streamly.Internal.Data.Stream.Type (Stream)
179−import Streamly.Internal.Data.StreamK.Type (StreamK)
180import Streamly.Internal.Data.Unbox (Unbox(..))
113import Streamly.Internal.Data.Unbox (Unbox(..))
181import Streamly.Internal.Data.Unfold.Type (Unfold(..))
114import Streamly.Internal.Data.Unfold.Type (Unfold(..))
182import Text.Read (readPrec)
115import Text.Read (readPrec)
183
116
184−import Prelude hiding (Foldable(..), concat, read, unlines, splitAt)
117+import Prelude hiding (Foldable(..), read, unlines, splitAt)
185
118
186import qualified GHC.Exts as Exts
119import qualified GHC.Exts as Exts
187−import qualified Streamly.Internal.Data.Fold.Type as Fold
188import qualified Streamly.Internal.Data.MutArray.Type as MA
120import qualified Streamly.Internal.Data.MutArray.Type as MA
189import qualified Streamly.Internal.Data.Stream.Type as D
121import qualified Streamly.Internal.Data.Stream.Type as D
122+import qualified Streamly.Internal.Data.Stream.Generate as D
190import qualified Streamly.Internal.Data.StreamK.Type as K
123import qualified Streamly.Internal.Data.StreamK.Type as K
191−import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
124+import qualified Streamly.Internal.Data.Unbox as Unboxed
192−import qualified Streamly.Internal.Data.Producer as Producer
193import qualified Streamly.Internal.Data.Unfold.Type as Unfold
125import qualified Streamly.Internal.Data.Unfold.Type as Unfold
194import qualified Text.ParserCombinators.ReadPrec as ReadPrec
126import qualified Text.ParserCombinators.ReadPrec as ReadPrec
195
127
@@ -232,7 +164,7 @@ data Array a =
232#endif
164#endif
233 -- All offsets are in terms of bytes from the start of arraycontents
165 -- All offsets are in terms of bytes from the start of arraycontents
234 Array
166 Array
235− { arrContents :: {-# UNPACK #-} !MutByteArray
167+ { arrContents :: {-# UNPACK #-} !MutableByteArray
236 , arrStart :: {-# UNPACK #-} !Int -- offset
168 , arrStart :: {-# UNPACK #-} !Int -- offset
237 , arrEnd :: {-# UNPACK #-} !Int -- offset + len
169 , arrEnd :: {-# UNPACK #-} !Int -- offset + len
238 }
170 }
@@ -243,20 +175,14 @@ data Array a =
243
175
244-- | Use an @Array a@ as @Ptr a@.
176-- | Use an @Array a@ as @Ptr a@.
245--
177--
246−-- See 'MA.unsafePinnedAsPtr' in the Mutable array module for more details.
178+-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
247--
179--
248-- /Unsafe/
180-- /Unsafe/
249--
181--
250-- /Pre-release/
182-- /Pre-release/
251--
183--
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." #-}
257−{-# INLINE asPtrUnsafe #-}
258asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
184asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
259−asPtrUnsafe = unsafePinnedAsPtr
185+asPtrUnsafe arr = MA.asPtrUnsafe (unsafeThaw arr)
260
186
261-------------------------------------------------------------------------------
187-------------------------------------------------------------------------------
262-- Freezing and Thawing
188-- Freezing and Thawing
@@ -303,19 +229,18 @@ unsafeThaw (Array ac as ae) = MutArray ac as ae ae
303-- Pinning & Unpinning
229-- Pinning & Unpinning
304-------------------------------------------------------------------------------
230-------------------------------------------------------------------------------
305
231
306−-- | Return a copy of the 'Array' in pinned memory if unpinned, else return the
232+-- | Copy the 'Array' to pinned memory if unpinned, else do nothing. The
307−-- original array.
233+-- overhead is a copy if the input array is unpinned.
308{-# INLINE pin #-}
234{-# INLINE pin #-}
309pin :: Array a -> IO (Array a)
235pin :: Array a -> IO (Array a)
310pin = fmap unsafeFreeze . MA.pin . unsafeThaw
236pin = fmap unsafeFreeze . MA.pin . unsafeThaw
311
237
312−-- | Return a copy of the 'Array' in unpinned memory if pinned, else return the
238+-- | Copy the 'Array' to unpinned memory if pinned, else do nothing. The
313−-- original array.
239+-- overhead is a copy if the input array is pinned.
314{-# INLINE unpin #-}
240{-# INLINE unpin #-}
315unpin :: Array a -> IO (Array a)
241unpin :: Array a -> IO (Array a)
316unpin = fmap unsafeFreeze . MA.unpin . unsafeThaw
242unpin = fmap unsafeFreeze . MA.unpin . unsafeThaw
317
243
318−-- | Return 'True' if the array is allocated in pinned memory.
319{-# INLINE isPinned #-}
244{-# INLINE isPinned #-}
320isPinned :: Array a -> Bool
245isPinned :: Array a -> Bool
321isPinned = MA.isPinned . unsafeThaw
246isPinned = MA.isPinned . unsafeThaw
@@ -324,14 +249,11 @@ isPinned = MA.isPinned . unsafeThaw
324-- Construction
249-- Construction
325-------------------------------------------------------------------------------
250-------------------------------------------------------------------------------
326
251
327−-- | Copy two immutable arrays into a new array. If you want to splice more
252+-- Splice two immutable arrays creating a new array.
328−-- than two arrays then this operation would be highly inefficient because it
329−-- would make a copy on every splice operation, instead use the
330−-- 'fromChunksK' operation to combine n immutable arrays.
331{-# INLINE splice #-}
253{-# INLINE splice #-}
332−splice :: MonadIO m => Array a -> Array a -> m (Array a)
254+splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
333splice arr1 arr2 =
255splice arr1 arr2 =
334− unsafeFreeze <$> MA.spliceCopy (unsafeThaw arr1) (unsafeThaw arr2)
256+ unsafeFreeze <$> MA.splice (unsafeThaw arr1) (unsafeThaw arr2)
335
257
336-- | Create an 'Array' from the first N elements of a list. The array is
258-- | Create an 'Array' from the first N elements of a list. The array is
337-- allocated to size N, if the list terminates before N elements then the
259-- allocated to size N, if the list terminates before N elements then the
@@ -375,83 +297,36 @@ pinnedFromList xs = unsafePerformIO $ unsafeFreeze <$> MA.pinnedFromList xs
375fromListRev :: Unbox a => [a] -> Array a
297fromListRev :: Unbox a => [a] -> Array a
376fromListRev xs = unsafePerformIO $ unsafeFreeze <$> MA.fromListRev xs
298fromListRev xs = unsafePerformIO $ unsafeFreeze <$> MA.fromListRev xs
377
299
378−-- | Create an 'Array' from the first N elements of a stream. The array is
379−-- allocated to size N, if the stream terminates before N elements then the
380−-- array may hold less than N elements.
381−--
382−-- >>> fromStreamN n = Stream.fold (Array.writeN n)
383−--
384−-- /Pre-release/
385−{-# INLINE_NORMAL fromStreamN #-}
300+{-# INLINE_NORMAL fromStreamDN #-}
386−fromStreamN :: (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
387−fromStreamN n m = do
388− when (n < 0) $ error "writeN: negative write count specified"
389− unsafeFreeze <$> MA.fromStreamN n m
390−-- fromStreamN n = D.fold (writeN n)
391−
392−{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
393fromStreamDN :: forall m a. (MonadIO m, Unbox a)
301fromStreamDN :: forall m a. (MonadIO m, Unbox a)
394 => Int -> D.Stream m a -> m (Array a)
302 => Int -> D.Stream m a -> m (Array a)
395−fromStreamDN = fromStreamN
303+fromStreamDN limit str = unsafeFreeze <$> MA.fromStreamDN limit str
396
304
397−-- | Create an 'Array' from a stream. This is useful when we want to create a
398−-- single array from a stream of unknown size. 'writeN' is at least twice
399−-- as efficient when the size is already known.
400−--
401−-- >>> fromStream = Stream.fold Array.write
402−--
403−-- Note that if the input stream is too large memory allocation for the array
404−-- may fail. When the stream size is not known, `chunksOf` followed by
405−-- processing of indvidual arrays in the resulting stream should be preferred.
406−--
407−-- /Pre-release/
408{-# INLINE_NORMAL fromStreamD #-}
305{-# INLINE_NORMAL fromStreamD #-}
409−fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (Array a)
410−fromStream = D.fold write
411−-- fromStreamD str = unsafeFreeze <$> MA.fromStream str
412−
413−{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
414fromStreamD :: forall m a. (MonadIO m, Unbox a)
306fromStreamD :: forall m a. (MonadIO m, Unbox a)
415 => D.Stream m a -> m (Array a)
307 => D.Stream m a -> m (Array a)
416−fromStreamD = fromStream
308+fromStreamD str = unsafeFreeze <$> MA.fromStreamD str
417
309
418-------------------------------------------------------------------------------
310-------------------------------------------------------------------------------
419-- Cloning
311-- Cloning
420-------------------------------------------------------------------------------
312-------------------------------------------------------------------------------
421
313
422{-# INLINE clone #-}
314{-# INLINE clone #-}
423−clone ::
424− ( MonadIO m
425−#ifdef DEVBUILD
426− , Unbox a
427−#endif
428− )
429− => Array a -> m (Array a)
315+clone :: MonadIO m => Array a -> m (Array a)
430clone = fmap unsafeFreeze . MA.clone . unsafeThaw
316clone = fmap unsafeFreeze . MA.clone . unsafeThaw
431
317
432{-# INLINE pinnedClone #-}
318{-# INLINE pinnedClone #-}
433−pinnedClone ::
434− ( MonadIO m
435−#ifdef DEVBUILD
436− , Unbox a
437−#endif
438− )
439− => Array a -> m (Array a)
319+pinnedClone :: MonadIO m => Array a -> m (Array a)
440pinnedClone = fmap unsafeFreeze . MA.pinnedClone . unsafeThaw
320pinnedClone = fmap unsafeFreeze . MA.pinnedClone . unsafeThaw
441
321
442-------------------------------------------------------------------------------
322-------------------------------------------------------------------------------
443-- Streams of arrays
323-- Streams of arrays
444-------------------------------------------------------------------------------
324-------------------------------------------------------------------------------
445
325
446−{-# INLINE buildChunks #-}
326+{-# INLINE bufferChunks #-}
447−buildChunks :: (MonadIO m, Unbox a) =>
448− D.Stream m a -> m (K.StreamK m (Array a))
449−buildChunks m = D.foldr K.cons K.nil $ chunksOf defaultChunkSize m
450−
451−{-# DEPRECATED bufferChunks "Please use buildChunks instead." #-}
452bufferChunks :: (MonadIO m, Unbox a) =>
327bufferChunks :: (MonadIO m, Unbox a) =>
453 D.Stream m a -> m (K.StreamK m (Array a))
328 D.Stream m a -> m (K.StreamK m (Array a))
454−bufferChunks = buildChunks
329+bufferChunks m = D.foldr K.cons K.nil $ chunksOf defaultChunkSize m
455
330
456-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
331-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
457-- @n@ elements each.
332-- @n@ elements each.
@@ -472,100 +347,27 @@ pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
472 => Int -> D.Stream m a -> D.Stream m (Array a)
347 => Int -> D.Stream m a -> D.Stream m (Array a)
473pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
348pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
474
349
475−-- | Convert a stream of arrays into a stream of their elements.
350+-- | Use the "read" unfold instead.
476--
351--
477−-- >>> concat = Stream.unfoldMany Array.reader
352+-- @flattenArrays = unfoldMany read@
478--
353--
479−{-# INLINE_NORMAL concat #-}
354+-- We can try this if there are any fusion issues in the unfold.
480−concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
355+--
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
484−
485−{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
486−{-# INLINE flattenArrays #-}
356+{-# INLINE_NORMAL flattenArrays #-}
487flattenArrays :: forall m a. (MonadIO m, Unbox a)
357flattenArrays :: forall m a. (MonadIO m, Unbox a)
488 => D.Stream m (Array a) -> D.Stream m a
358 => D.Stream m (Array a) -> D.Stream m a
489−flattenArrays = concat
359+flattenArrays = MA.flattenArrays . D.map unsafeThaw
490
360
491−-- | Convert a stream of arrays into a stream of their elements reversing the
361+-- | Use the "readRev" unfold instead.
492−-- contents of each array before flattening.
493--
362--
494−-- >>> concatRev = Stream.unfoldMany Array.readerRev
363+-- @flattenArrays = unfoldMany readRev@
495--
364--
496−{-# INLINE_NORMAL concatRev #-}
365+-- We can try this if there are any fusion issues in the unfold.
497−concatRev :: forall m a. (Monad m, Unbox a)
366+--
498− => D.Stream m (Array a) -> D.Stream m a
499−-- XXX this requires MonadIO whereas the unfoldMany version does not
500−concatRev = MA.concatRevWith (pure . unsafeInlineIO) . D.map unsafeThaw
501−-- concatRev = D.unfoldMany readerRev
502−
503−{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
504−{-# INLINE flattenArraysRev #-}
367+{-# INLINE_NORMAL flattenArraysRev #-}
505flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
368flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
506 => D.Stream m (Array a) -> D.Stream m a
369 => D.Stream m (Array a) -> D.Stream m a
507−flattenArraysRev = concatRev
370+flattenArraysRev = MA.flattenArraysRev . D.map unsafeThaw
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−-------------------------------------------------------------------------------
569
371
570-- Drops the separator byte
372-- Drops the separator byte
571{-# INLINE breakOn #-}
373{-# INLINE breakOn #-}
@@ -609,68 +411,24 @@ byteLength = MA.byteLength . unsafeThaw
609length :: Unbox a => Array a -> Int
411length :: Unbox a => Array a -> Int
610length arr = MA.length (unsafeThaw arr)
412length arr = MA.length (unsafeThaw arr)
611
413
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−
655-- | Unfold an array into a stream in reverse order.
414-- | Unfold an array into a stream in reverse order.
656--
415--
657{-# INLINE_NORMAL readerRev #-}
416{-# INLINE_NORMAL readerRev #-}
658readerRev :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
417readerRev :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
659readerRev = Unfold.lmap unsafeThaw $ MA.readerRevWith (return . unsafeInlineIO)
418readerRev = Unfold.lmap unsafeThaw $ MA.readerRevWith (return . unsafeInlineIO)
660
419
661−{-# DEPRECATED toStreamD "Please use 'read' instead." #-}
662{-# INLINE_NORMAL toStreamD #-}
420{-# INLINE_NORMAL toStreamD #-}
663toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
421toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
664−toStreamD = read
422+toStreamD arr = MA.toStreamDWith (return . unsafeInlineIO) (unsafeThaw arr)
665
423
666{-# INLINE toStreamK #-}
424{-# INLINE toStreamK #-}
667toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
425toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
668toStreamK arr = MA.toStreamKWith (return . unsafeInlineIO) (unsafeThaw arr)
426toStreamK arr = MA.toStreamKWith (return . unsafeInlineIO) (unsafeThaw arr)
669
427
670−{-# DEPRECATED toStreamDRev "Please use 'readRev' instead." #-}
671{-# INLINE_NORMAL toStreamDRev #-}
428{-# INLINE_NORMAL toStreamDRev #-}
672toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
429toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
673−toStreamDRev = readRev
430+toStreamDRev arr =
431+ MA.toStreamDRevWith (return . unsafeInlineIO) (unsafeThaw arr)
674
432
675{-# INLINE toStreamKRev #-}
433{-# INLINE toStreamKRev #-}
676toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
434toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
@@ -682,7 +440,7 @@ toStreamKRev arr =
682-- /Pre-release/
440-- /Pre-release/
683{-# INLINE_EARLY read #-}
441{-# INLINE_EARLY read #-}
684read :: (Monad m, Unbox a) => Array a -> Stream m a
442read :: (Monad m, Unbox a) => Array a -> Stream m a
685−read arr = MA.toStreamWith (return . unsafeInlineIO) (unsafeThaw arr)
443+read = toStreamD
686
444
687-- | Same as 'read'
445-- | Same as 'read'
688--
446--
@@ -699,7 +457,7 @@ toStream = read
699-- /Pre-release/
457-- /Pre-release/
700{-# INLINE_EARLY readRev #-}
458{-# INLINE_EARLY readRev #-}
701readRev :: (Monad m, Unbox a) => Array a -> Stream m a
459readRev :: (Monad m, Unbox a) => Array a -> Stream m a
702−readRev arr = MA.toStreamRevWith (return . unsafeInlineIO) (unsafeThaw arr)
460+readRev = toStreamDRev
703
461
704-- | Same as 'readRev'
462-- | Same as 'readRev'
705--
463--
@@ -723,7 +481,6 @@ foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
723-- | Create two slices of an array without copying the original array. The
481-- | Create two slices of an array without copying the original array. The
724-- specified index @i@ is the first index of the second slice.
482-- specified index @i@ is the first index of the second slice.
725--
483--
726−{-# INLINE splitAt #-}
727splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
484splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
728splitAt i arr = (unsafeFreeze a, unsafeFreeze b)
485splitAt i arr = (unsafeFreeze a, unsafeFreeze b)
729 where
486 where
@@ -743,8 +500,8 @@ toListFB c n Array{..} = go arrStart
743 -- accumulating the list and fusing better with the pure consumers.
500 -- accumulating the list and fusing better with the pure consumers.
744 --
501 --
745 -- This should be safe as the array contents are guaranteed to be
502 -- This should be safe as the array contents are guaranteed to be
746− -- evaluated/written to before we peekAt at them.
503+ -- evaluated/written to before we peekByteIndex at them.
747− let !x = unsafeInlineIO $ peekAt p arrContents
504+ let !x = unsafeInlineIO $ peekByteIndex p arrContents
748 in c x (go (INDEX_NEXT(p,a)))
505 in c x (go (INDEX_NEXT(p,a)))
749
506
750-- | Convert an 'Array' into a list.
507-- | Convert an 'Array' into a list.
@@ -757,28 +514,17 @@ toList s = build (\c n -> toListFB c n s)
757-- Folds
514-- Folds
758-------------------------------------------------------------------------------
515-------------------------------------------------------------------------------
759
516
760−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
517+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
761-- 'Array'.
518-- 'Array'.
762--
519--
763−{-# INLINE_NORMAL createOf #-}
520+{-# INLINE_NORMAL writeN #-}
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 #-}
770writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
521writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
771−writeN = createOf
522+writeN = fmap unsafeFreeze . MA.writeN
772
523
773−-- | Like 'createOf' but creates a pinned array.
524+-- | Like 'fromListN' but creates a pinned array.
774−{-# INLINE_NORMAL pinnedCreateOf #-}
775−pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
776−pinnedCreateOf = fmap unsafeFreeze . MA.pinnedCreateOf
777−
778−{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
779−{-# INLINE pinnedWriteN #-}
525+{-# INLINE_NORMAL pinnedWriteN #-}
780pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
526pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
781−pinnedWriteN = pinnedCreateOf
527+pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
782
528
783-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
529-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
784-- stream to an 'Array' aligned to the given size.
530-- stream to an 'Array' aligned to the given size.
@@ -786,74 +532,44 @@ pinnedWriteN = pinnedCreateOf
786-- /Pre-release/
532-- /Pre-release/
787--
533--
788{-# INLINE_NORMAL pinnedWriteNAligned #-}
534{-# INLINE_NORMAL pinnedWriteNAligned #-}
789−{-# DEPRECATED pinnedWriteNAligned "To be removed." #-}
790pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
535pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
791 => Int -> Int -> Fold m a (Array a)
536 => Int -> Int -> Fold m a (Array a)
792pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
537pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
793
538
794−-- | Like 'createOf' but does not check the array bounds when writing. The fold
539+-- | Like 'writeN' but does not check the array bounds when writing. The fold
795-- driver must not call the step function more than 'n' times otherwise it will
540-- driver must not call the step function more than 'n' times otherwise it will
796-- corrupt the memory and crash. This function exists mainly because any
541-- corrupt the memory and crash. This function exists mainly because any
797-- conditional in the step function blocks fusion causing 10x performance
542-- conditional in the step function blocks fusion causing 10x performance
798-- slowdown.
543-- slowdown.
799--
544--
800−{-# INLINE_NORMAL unsafeCreateOf #-}
801−unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
802− => Int -> Fold m a (Array a)
803−unsafeCreateOf n = unsafeFreeze <$> MA.unsafeCreateOf n
804−
805−{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
806−{-# INLINE writeNUnsafe #-}
545+{-# INLINE_NORMAL writeNUnsafe #-}
807writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
546writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
808 => Int -> Fold m a (Array a)
547 => Int -> Fold m a (Array a)
809−writeNUnsafe = unsafeCreateOf
548+writeNUnsafe n = unsafeFreeze <$> MA.writeNUnsafe n
810
549
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." #-}
817−{-# INLINE pinnedWriteNUnsafe #-}
550+{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
818pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
551pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
819 => Int -> Fold m a (Array a)
552 => Int -> Fold m a (Array a)
820−pinnedWriteNUnsafe = unsafePinnedCreateOf
553+pinnedWriteNUnsafe n = unsafeFreeze <$> MA.pinnedWriteNUnsafe n
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
827
554
828−{-# DEPRECATED writeWith "Please use createWith instead." #-}
829−{-# INLINE writeWith #-}
555+{-# INLINE_NORMAL writeWith #-}
830writeWith :: forall m a. (MonadIO m, Unbox a)
556writeWith :: forall m a. (MonadIO m, Unbox a)
831 => Int -> Fold m a (Array a)
557 => Int -> Fold m a (Array a)
832−writeWith = createWith
558+-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
559+writeWith elemCount = unsafeFreeze <$> MA.writeWith elemCount
833
560
834-- | Fold the whole input to a single array.
561-- | Fold the whole input to a single array.
835--
562--
836-- /Caution! Do not use this on infinite streams./
563-- /Caution! Do not use this on infinite streams./
837--
564--
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." #-}
844{-# INLINE write #-}
565{-# INLINE write #-}
845write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
566write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
846−write = create
567+write = fmap unsafeFreeze MA.write
847
568
848−-- | Like 'create' but creates a pinned array.
569+-- | Like 'write' but creates a pinned array.
849−{-# INLINE pinnedCreate #-}
850−pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
851−pinnedCreate = fmap unsafeFreeze MA.pinnedCreate
852−
853−{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
854{-# INLINE pinnedWrite #-}
570{-# INLINE pinnedWrite #-}
855pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
571pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
856−pinnedWrite = pinnedCreate
572+pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
857
573
858-- | Fold "step" has a dependency on "initial", and each step is dependent on
574-- | Fold "step" has a dependency on "initial", and each step is dependent on
859-- the previous invocation of step due to state passing, finally extract
575-- the previous invocation of step due to state passing, finally extract
@@ -879,16 +595,10 @@ pinnedWrite = pinnedCreate
879--
595--
880{-# INLINE unsafeMakePure #-}
596{-# INLINE unsafeMakePure #-}
881unsafeMakePure :: Monad m => Fold IO a b -> Fold m a b
597unsafeMakePure :: Monad m => Fold IO a b -> Fold m a b
882−unsafeMakePure (Fold step initial extract final) =
598+unsafeMakePure (Fold step initial extract) =
883 Fold (\x a -> return $! unsafeInlineIO (step x a))
599 Fold (\x a -> return $! unsafeInlineIO (step x a))
884 (return $! unsafePerformIO initial)
600 (return $! unsafePerformIO initial)
885 (\s -> return $! unsafeInlineIO $ extract s)
601 (\s -> return $! unsafeInlineIO $ extract s)
886− (\s -> return $! unsafeInlineIO $ final s)
887−
888−{-# INLINE fromPureStreamN #-}
889−fromPureStreamN :: Unbox a => Int -> Stream Identity a -> Array a
890−fromPureStreamN n x =
891− unsafePerformIO $ fmap unsafeFreeze (MA.fromPureStreamN n x)
892
602
893-- | Convert a pure stream in Identity monad to an immutable array.
603-- | Convert a pure stream in Identity monad to an immutable array.
894--
604--
@@ -901,19 +611,6 @@ fromPureStream x = unsafePerformIO $ fmap (unsafeFreeze) (MA.fromPureStream x)
901-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
611-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
902-- fromPureStream = fromList . runIdentity . D.toList
612-- fromPureStream = fromList . runIdentity . D.toList
903
613
904−-- XXX This should be monadic.
905−
906−-- | Copy an immutable 'Ptr Word8' sequence into an array.
907−--
908−-- /Unsafe:/ The caller is responsible for safe addressing.
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.
912−fromPtrN :: Int -> Ptr Word8 -> Array Word8
913−fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
914−
915−-- XXX This should be monadic.
916−
917-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
614-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
918--
615--
919-- /Unsafe:/ The caller is responsible for safe addressing.
616-- /Unsafe:/ The caller is responsible for safe addressing.
@@ -924,46 +621,8 @@ fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
924-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
621-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
925-- [1,2,3]
622-- [1,2,3]
926--
623--
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.
929fromByteStr# :: Addr# -> Array Word8
624fromByteStr# :: Addr# -> Array Word8
930−fromByteStr# addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromByteStr# addr)
625+fromByteStr# addr = fromPureStream (D.fromByteStr# addr)
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.
936−fromByteStr :: Ptr Word8 -> Array Word8
937−fromByteStr (Ptr addr#) = fromByteStr# addr#
938−
939−-- XXX implement fromChunks/fromChunkList instead?
940−
941−-- | Convert an array stream to an array. Note that this requires peak memory
942−-- that is double the size of the array stream.
943−--
944−{-# INLINE fromChunksK #-}
945−fromChunksK :: (MonadIO m, Unbox a) => StreamK m (Array a) -> m (Array a)
946−fromChunksK stream =
947− -- We buffer the entire stream and then allocate the target array of the
948− -- same size, thus requiring double the memory.
949− fmap unsafeFreeze $ MA.fromChunksK $ fmap unsafeThaw stream
950−
951−{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
952−fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (Array a) -> m (Array a)
953−fromArrayStreamK = fromChunksK
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
626
968-------------------------------------------------------------------------------
627-------------------------------------------------------------------------------
969-- Instances
628-- Instances
@@ -995,66 +654,12 @@ instance Unbox a => IsList (Array a) where
995 {-# INLINE toList #-}
654 {-# INLINE toList #-}
996 toList = toList
655 toList = toList
997
656
998−-- | Byte compare two arrays. Compare the length of the arrays. If the length
657+-- XXX we are assuming that Unboxed equality means element equality. This may
999−-- is equal, compare the lexicographical ordering of two underlying byte arrays
658+-- or may not be correct? arrcmp is 40% faster compared to stream equality.
1000−-- otherwise return the result of length comparison.
1001−--
1002−-- /Unsafe/: Note that the 'Unbox' instance of sum types with constructors of
1003−-- different sizes may leave some memory uninitialized which can make byte
1004−-- comparison unreliable.
1005−--
1006−-- /Pre-release/
1007−{-# INLINE byteCmp #-}
1008−byteCmp :: Array a -> Array a -> Ordering
1009−byteCmp arr1 arr2 =
1010− -- unsafePerformIO?
1011− unsafeInlineIO $! unsafeThaw arr1 `MA.byteCmp` unsafeThaw arr2
1012−
1013−-- | Byte equality of two arrays.
1014−--
1015−-- >>> byteEq arr1 arr2 = (==) EQ $ Array.byteCmp arr1 arr2
1016−--
1017−-- /Unsafe/: See 'byteCmp'.
1018−{-# INLINE byteEq #-}
1019−byteEq :: Array a -> Array a -> Bool
1020−byteEq arr1 arr2 = (==) EQ $ byteCmp arr1 arr2
1021−
1022−#define MK_EQ_INSTANCE(typ) \
1023−instance {-# OVERLAPPING #-} Eq (Array typ) where { \
1024−; {-# INLINE (==) #-} \
1025−; (==) = byteEq \
1026−}
1027−
1028−MK_EQ_INSTANCE(Char)
1029−MK_EQ_INSTANCE(Word8)
1030−MK_EQ_INSTANCE(Word16)
1031−MK_EQ_INSTANCE(Word32)
1032−
1033−-- XXX The Word64 default instance should be as fast because we are comparing
1034−-- 64-bit at a time.
1035−MK_EQ_INSTANCE(Word64)
1036−MK_EQ_INSTANCE(Int)
1037−MK_EQ_INSTANCE(Int8)
1038−MK_EQ_INSTANCE(Int16)
1039−MK_EQ_INSTANCE(Int32)
1040−
1041−-- XXX The Int64 default instance should be as fast.
1042−MK_EQ_INSTANCE(Int64)
1043−
1044−-- | If the type allows a byte-by-byte comparison this instance can be
1045−-- overlapped by a more specific instance that uses 'byteCmp'. Byte comparison
1046−-- can be significantly faster.
1047−--
1048−instance {-# OVERLAPPABLE #-} (Unbox a, Eq a) => Eq (Array a) where
659+instance (Unbox a, Eq a) => Eq (Array a) where
1049 {-# INLINE (==) #-}
660 {-# INLINE (==) #-}
1050 arr1 == arr2 =
661 arr1 == arr2 =
1051− -- Does unboxed byte equality mean element equality?
1052− -- XXX This is incorrect for sum types, as we may have some
1053− -- uninitialized memory in that case. If we always initialize the
1054− -- unused memory to zero we can use this.
1055− -- Byte comparison is 40% faster compared to stream equality.
1056− -- (==) EQ $ unsafeInlineIO $! unsafeThaw arr1 `MA.cmp` unsafeThaw arr2
662+ (==) EQ $ unsafeInlineIO $! unsafeThaw arr1 `MA.cmp` unsafeThaw arr2
1057− (toStreamD arr1 :: Stream Identity a) == toStreamD arr2
1058
663
1059instance (Unbox a, Ord a) => Ord (Array a) where
664instance (Unbox a, Ord a) => Ord (Array a) where
1060 {-# INLINE compare #-}
665 {-# INLINE compare #-}
@@ -1096,7 +701,7 @@ _toStreamD_ size Array{..} = D.Stream step arrStart
1096 {-# INLINE_LATE step #-}
701 {-# INLINE_LATE step #-}
1097 step _ p | p == arrEnd = return D.Stop
702 step _ p | p == arrEnd = return D.Stop
1098 step _ p = liftIO $ do
703 step _ p = liftIO $ do
1099− x <- peekAt p arrContents
704+ x <- peekByteIndex p arrContents
1100 return $ D.Yield x (p + size)
705 return $ D.Yield x (p + size)
1101
706
1102{-
707{-
@@ -1119,29 +724,15 @@ instance Foldable Array where
1119-- Semigroup and Monoid
724-- Semigroup and Monoid
1120-------------------------------------------------------------------------------
725-------------------------------------------------------------------------------
1121
726
1122−-- XXX Deprecate and remove the Semigroup and Monoid instances because of
1123−-- potential misuse chances.
1124−
1125−-- | This should not be used for combining many or N arrays as it would copy
1126−-- the two arrays everytime to a new array. For coalescing multiple arrays use
1127−-- 'fromChunksK' instead.
1128instance Unbox a => Semigroup (Array a) where
727instance Unbox a => Semigroup (Array a) where
1129 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
728 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
1130
729
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." #-}
1139nil ::
730nil ::
1140#ifdef DEVBUILD
731#ifdef DEVBUILD
1141 Unbox a =>
732 Unbox a =>
1142#endif
733#endif
1143 Array a
734 Array a
1144−nil = empty
735+nil = Array Unboxed.nil 0 0
1145
736
1146instance Unbox a => Monoid (Array a) where
737instance Unbox a => Monoid (Array a) where
1147 mempty = nil
738 mempty = nil
core/src/Streamly/Internal/Data/Builder.hs−2
@@ -16,9 +16,7 @@ module Streamly.Internal.Data.Builder
16 )
16 )
17where
17where
18
18
19−#if !MIN_VERSION_base(4,18,0)
20import Control.Applicative (liftA2)
19import Control.Applicative (liftA2)
21−#endif
22
20
23------------------------------------------------------------------------------
21------------------------------------------------------------------------------
24-- The Builder type
22-- The Builder type
core/src/Streamly/Internal/Data/Fold/Chunked.hs+15−18
@@ -6,7 +6,7 @@
6-- Stability : experimental
6-- Stability : experimental
7-- Portability : GHC
7-- Portability : GHC
8--
8--
9−-- Use "Streamly.Data.Parser" instead.
9+-- Use "Streamly.Data.Parser.Chunked" instead.
10--
10--
11-- Fold a stream of foreign arrays. @Fold m a b@ in this module works
11-- Fold a stream of foreign arrays. @Fold m a b@ in this module works
12-- on a stream of "Array a" and produces an output of type @b@.
12-- on a stream of "Array a" and produces an output of type @b@.
@@ -19,19 +19,18 @@
19-- folds in Data.Fold to correctly work on an array stream as if it is an
19-- folds in Data.Fold to correctly work on an array stream as if it is an
20-- element stream. For example:
20-- element stream. For example:
21--
21--
22−-- >> import qualified Streamly.Data.Fold as Fold
22+-- >>> import qualified Streamly.Data.Fold as Fold
23−-- >> import qualified Streamly.Internal.Data.Array.Stream as ArrayStream
23+-- >>> import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
24−-- >> import qualified Streamly.Internal.Data.Fold.Chunked as ChunkFold
24+-- >>> import qualified Streamly.Internal.Data.Fold.Chunked as ChunkFold
25−-- >> import qualified Streamly.Data.Stream as Stream
25+-- >>> import qualified Streamly.Data.Stream as Stream
26−-- >> import qualified Streamly.Data.StreamK as StreamK
26+-- >>> import qualified Streamly.Data.StreamK as StreamK
27--
27--
28−-- >> f = ChunkFold.fromFold (Fold.take 7 Fold.toList)
28+-- >>> f = ChunkFold.fromFold (Fold.take 7 Fold.toList)
29−-- >> s = Stream.chunksOf 5 $ Stream.fromList "hello world"
29+-- >>> s = Stream.chunksOf 5 $ Stream.fromList "hello world"
30−-- >> ArrayStream.runArrayFold f (StreamK.fromStream s)
30+-- >>> ArrayStream.runArrayFold f (StreamK.fromStream s)
31-- Right "hello w"
31-- Right "hello w"
32--
32--
33module Streamly.Internal.Data.Fold.Chunked
33module Streamly.Internal.Data.Fold.Chunked
34− {-# DEPRECATED "Please use Streamly.Data.Parser instead." #-}
35 (
34 (
36 ChunkFold (..)
35 ChunkFold (..)
37
36
@@ -59,15 +58,14 @@ where
59
58
60#include "ArrayMacros.h"
59#include "ArrayMacros.h"
61
60
62−#if !MIN_VERSION_base(4,18,0)
63import Control.Applicative (liftA2)
61import Control.Applicative (liftA2)
64−#endif
65import Control.Exception (assert)
62import Control.Exception (assert)
66import Control.Monad.IO.Class (MonadIO(..))
63import Control.Monad.IO.Class (MonadIO(..))
67import Data.Bifunctor (first)
64import Data.Bifunctor (first)
68import Data.Proxy (Proxy(..))
65import Data.Proxy (Proxy(..))
69import Streamly.Internal.Data.Unbox (Unbox(..))
66import Streamly.Internal.Data.Unbox (Unbox(..))
70import GHC.Types (SPEC(..))
67import GHC.Types (SPEC(..))
68+import Streamly.Internal.Data.MutArray.Type (touch)
71import Streamly.Internal.Data.Array (Array(..))
69import Streamly.Internal.Data.Array (Array(..))
72import Streamly.Internal.Data.Parser (Initial(..), Step(..))
70import Streamly.Internal.Data.Parser (Initial(..), Step(..))
73import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
71import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
@@ -103,8 +101,8 @@ newtype ChunkFold m a b = ChunkFold (ParserD.Parser (Array a) m b)
103{-# INLINE fromFold #-}
101{-# INLINE fromFold #-}
104fromFold :: forall m a b. (MonadIO m, Unbox a) =>
102fromFold :: forall m a b. (MonadIO m, Unbox a) =>
105 Fold.Fold m a b -> ChunkFold m a b
103 Fold.Fold m a b -> ChunkFold m a b
106−fromFold (Fold.Fold fstep finitial _ ffinal) =
104+fromFold (Fold.Fold fstep finitial fextract) =
107− ChunkFold (ParserD.Parser step initial extract)
105+ ChunkFold (ParserD.Parser step initial (fmap (Done 0) . fextract))
108
106
109 where
107 where
110
108
@@ -124,7 +122,7 @@ fromFold (Fold.Fold fstep finitial _ ffinal) =
124 assert (cur == end) (return ())
122 assert (cur == end) (return ())
125 return $ Partial 0 fs
123 return $ Partial 0 fs
126 goArray !_ !cur !fs = do
124 goArray !_ !cur !fs = do
127− x <- liftIO $ peekAt cur contents
125+ x <- liftIO $ peekByteIndex cur contents
128 res <- fstep fs x
126 res <- fstep fs x
129 let elemSize = SIZE_OF(a)
127 let elemSize = SIZE_OF(a)
130 next = INDEX_NEXT(cur,a)
128 next = INDEX_NEXT(cur,a)
@@ -134,8 +132,6 @@ fromFold (Fold.Fold fstep finitial _ ffinal) =
134 Fold.Partial fs1 ->
132 Fold.Partial fs1 ->
135 goArray SPEC next fs1
133 goArray SPEC next fs1
136
134
137− extract = fmap (Done 0) . ffinal
138−
139-- | Convert an element 'ParserD.Parser' into an array stream fold. If the
135-- | Convert an element 'ParserD.Parser' into an array stream fold. If the
140-- parser fails the fold would throw an exception.
136-- parser fails the fold would throw an exception.
141--
137--
@@ -163,7 +159,8 @@ fromParserD (ParserD.Parser step1 initial1 extract1) =
163 else return $ st (arrRem + n) fs1
159 else return $ st (arrRem + n) fs1
164
160
165 goArray !_ !cur !fs = do
161 goArray !_ !cur !fs = do
166− x <- liftIO $ peekAt cur contents
162+ x <- liftIO $ peekByteIndex cur contents
163+ liftIO $ touch contents
167 res <- step1 fs x
164 res <- step1 fs x
168 let elemSize = SIZE_OF(a)
165 let elemSize = SIZE_OF(a)
169 next = INDEX_NEXT(cur,a)
166 next = INDEX_NEXT(cur,a)
core/src/Streamly/Internal/Data/Fold/Combinators.hs+137−81
@@ -30,6 +30,8 @@ module Streamly.Internal.Data.Fold.Combinators
30 -- *** Reducers
30 -- *** Reducers
31 , drainMapM
31 , drainMapM
32 , the
32 , the
33+ , length
34+ , lengthGeneric
33 , mean
35 , mean
34 , rollingHash
36 , rollingHash
35 , defaultSalt
37 , defaultSalt
@@ -164,6 +166,8 @@ module Streamly.Internal.Data.Fold.Combinators
164 -- ** Trimming
166 -- ** Trimming
165
167
166 -- By elements
168 -- By elements
169+ , takeEndBy
170+ , takeEndBy_
167 , takeEndBySeq
171 , takeEndBySeq
168 , takeEndBySeq_
172 , takeEndBySeq_
169 {-
173 {-
@@ -439,8 +443,8 @@ trace f = lmapM (tracing f)
439-- /Pre-release/
443-- /Pre-release/
440{-# INLINE transform #-}
444{-# INLINE transform #-}
441transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
445transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
442−transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract ffinal) =
446+transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
443− Fold step initial extract final
447+ Fold step initial extract
444
448
445 where
449 where
446
450
@@ -473,14 +477,10 @@ transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract ffinal) =
473
477
474 extract (Tuple' _ fs) = fextract fs
478 extract (Tuple' _ fs) = fextract fs
475
479
476− final (Tuple' _ fs) = ffinal fs
477−
478{-# INLINE scanWith #-}
480{-# INLINE scanWith #-}
479scanWith :: Monad m => Bool -> Fold m a b -> Fold m b c -> Fold m a c
481scanWith :: Monad m => Bool -> Fold m a b -> Fold m b c -> Fold m a c
480−scanWith isMany
481− (Fold stepL initialL extractL finalL)
482+scanWith isMany (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
482− (Fold stepR initialR extractR finalR) =
483− Fold step initial extract final
483+ Fold step initial extract
484
484
485 where
485 where
486
486
@@ -494,14 +494,15 @@ scanWith isMany
494 Partial sR1 ->
494 Partial sR1 ->
495 if isMany
495 if isMany
496 then runStep initialL sR1
496 then runStep initialL sR1
497− else Done <$> finalR sR1
497+ else Done <$> extractR sR1
498 Done bR -> return $ Done bR
498 Done bR -> return $ Done bR
499 Partial sL -> do
499 Partial sL -> do
500 !b <- extractL sL
500 !b <- extractL sL
501 rR <- stepR sR b
501 rR <- stepR sR b
502+ return
502− case rR of
503+ $ case rR of
503− Partial sR1 -> return $ Partial (sL, sR1)
504+ Partial sR1 -> Partial (sL, sR1)
504− Done bR -> finalL sL >> return (Done bR)
505+ Done bR -> Done bR
505
506
506 initial = do
507 initial = do
507 r <- initialR
508 r <- initialR
@@ -513,8 +514,6 @@ scanWith isMany
513
514
514 extract = extractR . snd
515 extract = extractR . snd
515
516
516− final (sL, sR) = finalL sL *> finalR sR
517−
518-- | Scan the input of a 'Fold' to change it in a stateful manner using another
517-- | Scan the input of a 'Fold' to change it in a stateful manner using another
519-- 'Fold'. The scan stops as soon as the fold terminates.
518-- 'Fold'. The scan stops as soon as the fold terminates.
520--
519--
@@ -566,7 +565,7 @@ deleteBy eq x0 = fmap extract $ foldl' step (Tuple' False Nothing)
566--
565--
567{-# INLINE slide2 #-}
566{-# INLINE slide2 #-}
568slide2 :: Monad m => Fold m (a, Maybe a) b -> Fold m a b
567slide2 :: Monad m => Fold m (a, Maybe a) b -> Fold m a b
569−slide2 (Fold step1 initial1 extract1 final1) = Fold step initial extract final
568+slide2 (Fold step1 initial1 extract1) = Fold step initial extract
570
569
571 where
570 where
572
571
@@ -578,8 +577,6 @@ slide2 (Fold step1 initial1 extract1 final1) = Fold step initial extract final
578
577
579 extract (Tuple' _ s) = extract1 s
578 extract (Tuple' _ s) = extract1 s
580
579
581− final (Tuple' _ s) = final1 s
582−
583-- | Return the latest unique element using the supplied comparison function.
580-- | Return the latest unique element using the supplied comparison function.
584-- Returns 'Nothing' if the current element is same as the last element
581-- Returns 'Nothing' if the current element is same as the last element
585-- otherwise returns 'Just'.
582-- otherwise returns 'Just'.
@@ -705,6 +702,30 @@ the = foldt' step initial id
705-- To Summary
702-- To Summary
706------------------------------------------------------------------------------
703------------------------------------------------------------------------------
707
704
705+-- | Like 'length', except with a more general 'Num' return value
706+--
707+-- Definition:
708+--
709+-- >>> lengthGeneric = fmap getSum $ Fold.foldMap (Sum . const 1)
710+-- >>> lengthGeneric = Fold.foldl' (\n _ -> n + 1) 0
711+--
712+-- /Pre-release/
713+{-# INLINE lengthGeneric #-}
714+lengthGeneric :: (Monad m, Num b) => Fold m a b
715+lengthGeneric = foldl' (\n _ -> n + 1) 0
716+
717+-- | Determine the length of the input stream.
718+--
719+-- Definition:
720+--
721+-- >>> length = Fold.lengthGeneric
722+-- >>> length = fmap getSum $ Fold.foldMap (Sum . const 1)
723+--
724+{-# INLINE length #-}
725+length :: Monad m => Fold m a Int
726+length = lengthGeneric
727+
728+
708-- | Determine the sum of all elements of a stream of numbers. Returns additive
729-- | Determine the sum of all elements of a stream of numbers. Returns additive
709-- identity (@0@) when the stream is empty. Note that this is not numerically
730-- identity (@0@) when the stream is empty. Note that this is not numerically
710-- stable for floating point numbers.
731-- stable for floating point numbers.
@@ -911,7 +932,7 @@ rollingHashFirstN n = take n rollingHash
911--
932--
912{-# INLINE rollingMapM #-}
933{-# INLINE rollingMapM #-}
913rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Fold m a b
934rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Fold m a b
914−rollingMapM f = Fold step initial extract extract
935+rollingMapM f = Fold step initial extract
915
936
916 where
937 where
917
938
@@ -1152,8 +1173,7 @@ head = one
1152-- /Pre-release/
1173-- /Pre-release/
1153{-# INLINE findM #-}
1174{-# INLINE findM #-}
1154findM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1175findM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1155−findM predicate =
1156− Fold step (return $ Partial ()) extract extract
1176+findM predicate = Fold step (return $ Partial ()) (const $ return Nothing)
1157
1177
1158 where
1178 where
1159
1179
@@ -1164,8 +1184,6 @@ findM predicate =
1164 else Partial ()
1184 else Partial ()
1165 in f <$> predicate a
1185 in f <$> predicate a
1166
1186
1167− extract = const $ return Nothing
1168−
1169-- | Returns the first element that satisfies the given predicate.
1187-- | Returns the first element that satisfies the given predicate.
1170--
1188--
1171{-# INLINE find #-}
1189{-# INLINE find #-}
@@ -1408,7 +1426,7 @@ splitAt n fld = splitWith (,) (take n fld)
1408
1426
1409{-# INLINE takingEndByM #-}
1427{-# INLINE takingEndByM #-}
1410takingEndByM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1428takingEndByM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1411−takingEndByM p = Fold step initial extract extract
1429+takingEndByM p = Fold step initial (return . toMaybe)
1412
1430
1413 where
1431 where
1414
1432
@@ -1421,8 +1439,6 @@ takingEndByM p = Fold step initial extract extract
1421 then Done $ Just a
1439 then Done $ Just a
1422 else Partial $ Just' a
1440 else Partial $ Just' a
1423
1441
1424− extract = return . toMaybe
1425−
1426-- |
1442-- |
1427--
1443--
1428-- >>> takingEndBy p = Fold.takingEndByM (return . p)
1444-- >>> takingEndBy p = Fold.takingEndByM (return . p)
@@ -1433,7 +1449,7 @@ takingEndBy p = takingEndByM (return . p)
1433
1449
1434{-# INLINE takingEndByM_ #-}
1450{-# INLINE takingEndByM_ #-}
1435takingEndByM_ :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1451takingEndByM_ :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1436−takingEndByM_ p = Fold step initial extract extract
1452+takingEndByM_ p = Fold step initial (return . toMaybe)
1437
1453
1438 where
1454 where
1439
1455
@@ -1446,8 +1462,6 @@ takingEndByM_ p = Fold step initial extract extract
1446 then Done Nothing
1462 then Done Nothing
1447 else Partial $ Just' a
1463 else Partial $ Just' a
1448
1464
1449− extract = return . toMaybe
1450−
1451-- |
1465-- |
1452--
1466--
1453-- >>> takingEndBy_ p = Fold.takingEndByM_ (return . p)
1467-- >>> takingEndBy_ p = Fold.takingEndByM_ (return . p)
@@ -1458,7 +1472,7 @@ takingEndBy_ p = takingEndByM_ (return . p)
1458
1472
1459{-# INLINE droppingWhileM #-}
1473{-# INLINE droppingWhileM #-}
1460droppingWhileM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1474droppingWhileM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1461−droppingWhileM p = Fold step initial extract extract
1475+droppingWhileM p = Fold step initial (return . toMaybe)
1462
1476
1463 where
1477 where
1464
1478
@@ -1473,8 +1487,6 @@ droppingWhileM p = Fold step initial extract extract
1473 else Just' a
1487 else Just' a
1474 step _ a = return $ Partial $ Just' a
1488 step _ a = return $ Partial $ Just' a
1475
1489
1476− extract = return . toMaybe
1477−
1478-- |
1490-- |
1479-- >>> droppingWhile p = Fold.droppingWhileM (return . p)
1491-- >>> droppingWhile p = Fold.droppingWhileM (return . p)
1480--
1492--
@@ -1482,6 +1494,70 @@ droppingWhileM p = Fold step initial extract extract
1482droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1494droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1483droppingWhile p = droppingWhileM (return . p)
1495droppingWhile p = droppingWhileM (return . p)
1484
1496
1497+-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
1498+-- S.splitOn in favor of the fold.
1499+--
1500+-- XXX Use Fold.many instead once it is fixed.
1501+-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1502+
1503+-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1504+--
1505+-- Example:
1506+--
1507+-- >>> input = Stream.fromList "hello\nthere\n"
1508+-- >>> line = Fold.takeEndBy_ (== '\n') Fold.toList
1509+-- >>> Stream.fold line input
1510+-- "hello"
1511+--
1512+-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1513+-- ["hello","there"]
1514+--
1515+{-# INLINE takeEndBy_ #-}
1516+takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1517+-- takeEndBy_ predicate = scanMaybe (takingEndBy_ predicate)
1518+takeEndBy_ predicate (Fold fstep finitial fextract) =
1519+ Fold step finitial fextract
1520+
1521+ where
1522+
1523+ step s a =
1524+ if not (predicate a)
1525+ then fstep s a
1526+ else Done <$> fextract s
1527+
1528+-- Note:
1529+-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1530+
1531+-- | Take the input, stop when the predicate succeeds taking the succeeding
1532+-- element as well.
1533+--
1534+-- Example:
1535+--
1536+-- >>> input = Stream.fromList "hello\nthere\n"
1537+-- >>> line = Fold.takeEndBy (== '\n') Fold.toList
1538+-- >>> Stream.fold line input
1539+-- "hello\n"
1540+--
1541+-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1542+-- ["hello\n","there\n"]
1543+--
1544+{-# INLINE takeEndBy #-}
1545+takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1546+-- takeEndBy predicate = scanMaybe (takingEndBy predicate)
1547+takeEndBy predicate (Fold fstep finitial fextract) =
1548+ Fold step finitial fextract
1549+
1550+ where
1551+
1552+ step s a = do
1553+ res <- fstep s a
1554+ if not (predicate a)
1555+ then return res
1556+ else do
1557+ case res of
1558+ Partial s1 -> Done <$> fextract s1
1559+ Done b -> return $ Done b
1560+
1485------------------------------------------------------------------------------
1561------------------------------------------------------------------------------
1486-- Binary splitting on a separator
1562-- Binary splitting on a separator
1487------------------------------------------------------------------------------
1563------------------------------------------------------------------------------
@@ -1514,8 +1590,8 @@ takeEndBySeq :: forall m a b. (MonadIO m, Storable a, Unbox a, Enum a, Eq a) =>
1514 Array.Array a
1590 Array.Array a
1515 -> Fold m a b
1591 -> Fold m a b
1516 -> Fold m a b
1592 -> Fold m a b
1517−takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1593+takeEndBySeq patArr (Fold fstep finitial fextract) =
1518− Fold step initial extract final
1594+ Fold step initial extract
1519
1595
1520 where
1596 where
1521
1597
@@ -1528,7 +1604,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1528 | patLen == 0 ->
1604 | patLen == 0 ->
1529 -- XXX Should we match nothing or everything on empty
1605 -- XXX Should we match nothing or everything on empty
1530 -- pattern?
1606 -- pattern?
1531− -- Done <$> ffinal acc
1607+ -- Done <$> fextract acc
1532 return $ Partial $ SplitOnSeqEmpty acc
1608 return $ Partial $ SplitOnSeqEmpty acc
1533 | patLen == 1 -> do
1609 | patLen == 1 -> do
1534 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
1610 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
@@ -1579,7 +1655,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1579 case res of
1655 case res of
1580 Partial s1
1656 Partial s1
1581 | pat /= x -> return $ Partial $ SplitOnSeqSingle s1 pat
1657 | pat /= x -> return $ Partial $ SplitOnSeqSingle s1 pat
1582− | otherwise -> Done <$> ffinal s1
1658+ | otherwise -> Done <$> fextract s1
1583 Done b -> return $ Done b
1659 Done b -> return $ Done b
1584 step (SplitOnSeqWord s idx wrd) x = do
1660 step (SplitOnSeqWord s idx wrd) x = do
1585 res <- fstep s x
1661 res <- fstep s x
@@ -1588,7 +1664,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1588 Partial s1
1664 Partial s1
1589 | idx == maxIndex -> do
1665 | idx == maxIndex -> do
1590 if wrd1 .&. wordMask == wordPat
1666 if wrd1 .&. wordMask == wordPat
1591− then Done <$> ffinal s1
1667+ then Done <$> fextract s1
1592 else return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1668 else return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1593 | otherwise ->
1669 | otherwise ->
1594 return $ Partial $ SplitOnSeqWord s1 (idx + 1) wrd1
1670 return $ Partial $ SplitOnSeqWord s1 (idx + 1) wrd1
@@ -1599,7 +1675,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1599 case res of
1675 case res of
1600 Partial s1
1676 Partial s1
1601 | wrd1 .&. wordMask == wordPat ->
1677 | wrd1 .&. wordMask == wordPat ->
1602− Done <$> ffinal s1
1678+ Done <$> fextract s1
1603 | otherwise ->
1679 | otherwise ->
1604 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1680 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1605 Done b -> return $ Done b
1681 Done b -> return $ Done b
@@ -1613,7 +1689,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1613 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1689 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1614 let !ringHash = fld addCksum 0 rb
1690 let !ringHash = fld addCksum 0 rb
1615 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1691 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1616− then Done <$> ffinal s1
1692+ then Done <$> fextract s1
1617 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1693 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1618 else
1694 else
1619 return $ Partial $ SplitOnSeqKR s1 (idx + 1) rb rh1
1695 return $ Partial $ SplitOnSeqKR s1 (idx + 1) rb rh1
@@ -1626,11 +1702,11 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1626 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1702 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1627 let ringHash = deltaCksum cksum old x
1703 let ringHash = deltaCksum cksum old x
1628 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1704 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1629− then Done <$> ffinal s1
1705+ then Done <$> fextract s1
1630 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1706 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1631 Done b -> return $ Done b
1707 Done b -> return $ Done b
1632
1708
1633− extractFunc fex state =
1709+ extract state =
1634 let st =
1710 let st =
1635 case state of
1711 case state of
1636 SplitOnSeqEmpty s -> s
1712 SplitOnSeqEmpty s -> s
@@ -1639,11 +1715,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1639 SplitOnSeqWordLoop s _ -> s
1715 SplitOnSeqWordLoop s _ -> s
1640 SplitOnSeqKR s _ _ _ -> s
1716 SplitOnSeqKR s _ _ _ -> s
1641 SplitOnSeqKRLoop s _ _ _ -> s
1717 SplitOnSeqKRLoop s _ _ _ -> s
1642− in fex st
1718+ in fextract st
1643−
1644− extract state = extractFunc fextract state
1645−
1646− final state = extractFunc ffinal state
1647
1719
1648-- | Like 'takeEndBySeq' but discards the matched sequence.
1720-- | Like 'takeEndBySeq' but discards the matched sequence.
1649--
1721--
@@ -1654,8 +1726,8 @@ takeEndBySeq_ :: forall m a b. (MonadIO m, Storable a, Unbox a, Enum a, Eq a) =>
1654 Array.Array a
1726 Array.Array a
1655 -> Fold m a b
1727 -> Fold m a b
1656 -> Fold m a b
1728 -> Fold m a b
1657−takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1729+takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1658− Fold step initial extract final
1730+ Fold step initial extract
1659
1731
1660 where
1732 where
1661
1733
@@ -1668,7 +1740,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1668 | patLen == 0 ->
1740 | patLen == 0 ->
1669 -- XXX Should we match nothing or everything on empty
1741 -- XXX Should we match nothing or everything on empty
1670 -- pattern?
1742 -- pattern?
1671− -- Done <$> ffinal acc
1743+ -- Done <$> fextract acc
1672 return $ Partial $ SplitOnSeqEmpty acc
1744 return $ Partial $ SplitOnSeqEmpty acc
1673 | patLen == 1 -> do
1745 | patLen == 1 -> do
1674 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
1746 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
@@ -1725,13 +1797,13 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1725 case res of
1797 case res of
1726 Partial s1 -> return $ Partial $ SplitOnSeqSingle s1 pat
1798 Partial s1 -> return $ Partial $ SplitOnSeqSingle s1 pat
1727 Done b -> return $ Done b
1799 Done b -> return $ Done b
1728− else Done <$> ffinal s
1800+ else Done <$> fextract s
1729 step (SplitOnSeqWord s idx wrd) x = do
1801 step (SplitOnSeqWord s idx wrd) x = do
1730 let wrd1 = addToWord wrd x
1802 let wrd1 = addToWord wrd x
1731 if idx == maxIndex
1803 if idx == maxIndex
1732 then do
1804 then do
1733 if wrd1 .&. wordMask == wordPat
1805 if wrd1 .&. wordMask == wordPat
1734− then Done <$> ffinal s
1806+ then Done <$> fextract s
1735 else return $ Partial $ SplitOnSeqWordLoop s wrd1
1807 else return $ Partial $ SplitOnSeqWordLoop s wrd1
1736 else return $ Partial $ SplitOnSeqWord s (idx + 1) wrd1
1808 else return $ Partial $ SplitOnSeqWord s (idx + 1) wrd1
1737 step (SplitOnSeqWordLoop s wrd) x = do
1809 step (SplitOnSeqWordLoop s wrd) x = do
@@ -1742,7 +1814,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1742 case res of
1814 case res of
1743 Partial s1
1815 Partial s1
1744 | wrd1 .&. wordMask == wordPat ->
1816 | wrd1 .&. wordMask == wordPat ->
1745− Done <$> ffinal s1
1817+ Done <$> fextract s1
1746 | otherwise ->
1818 | otherwise ->
1747 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1819 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1748 Done b -> return $ Done b
1820 Done b -> return $ Done b
@@ -1753,7 +1825,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1753 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1825 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1754 let !ringHash = fld addCksum 0 rb
1826 let !ringHash = fld addCksum 0 rb
1755 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1827 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1756− then Done <$> ffinal s
1828+ then Done <$> fextract s
1757 else return $ Partial $ SplitOnSeqKRLoop s ringHash rb rh1
1829 else return $ Partial $ SplitOnSeqKRLoop s ringHash rb rh1
1758 else return $ Partial $ SplitOnSeqKR s (idx + 1) rb rh1
1830 else return $ Partial $ SplitOnSeqKR s (idx + 1) rb rh1
1759 step (SplitOnSeqKRLoop s cksum rb rh) x = do
1831 step (SplitOnSeqKRLoop s cksum rb rh) x = do
@@ -1764,7 +1836,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1764 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1836 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1765 let ringHash = deltaCksum cksum old x
1837 let ringHash = deltaCksum cksum old x
1766 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1838 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1767− then Done <$> ffinal s1
1839+ then Done <$> fextract s1
1768 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1840 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1769 Done b -> return $ Done b
1841 Done b -> return $ Done b
1770
1842
@@ -1772,10 +1844,10 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1772 -- terminates early inside extract, we may still have buffered data
1844 -- terminates early inside extract, we may still have buffered data
1773 -- remaining which will be lost if we do not communicate that to the
1845 -- remaining which will be lost if we do not communicate that to the
1774 -- driver.
1846 -- driver.
1775− extractFunc fex state = do
1847+ extract state = do
1776 let consumeWord s n wrd = do
1848 let consumeWord s n wrd = do
1777 if n == 0
1849 if n == 0
1778− then fex s
1850+ then fextract s
1779 else do
1851 else do
1780 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
1852 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
1781 r <- fstep s (toEnum $ fromIntegral old)
1853 r <- fstep s (toEnum $ fromIntegral old)
@@ -1785,7 +1857,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1785
1857
1786 let consumeRing s n rb rh =
1858 let consumeRing s n rb rh =
1787 if n == 0
1859 if n == 0
1788− then fex s
1860+ then fextract s
1789 else do
1861 else do
1790 old <- liftIO $ peek rh
1862 old <- liftIO $ peek rh
1791 let rh1 = Ring.advance rb rh
1863 let rh1 = Ring.advance rb rh
@@ -1795,17 +1867,13 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1795 Done b -> return b
1867 Done b -> return b
1796
1868
1797 case state of
1869 case state of
1798− SplitOnSeqEmpty s -> fex s
1870+ SplitOnSeqEmpty s -> fextract s
1799− SplitOnSeqSingle s _ -> fex s
1871+ SplitOnSeqSingle s _ -> fextract s
1800 SplitOnSeqWord s idx wrd -> consumeWord s idx wrd
1872 SplitOnSeqWord s idx wrd -> consumeWord s idx wrd
1801 SplitOnSeqWordLoop s wrd -> consumeWord s patLen wrd
1873 SplitOnSeqWordLoop s wrd -> consumeWord s patLen wrd
1802 SplitOnSeqKR s idx rb _ -> consumeRing s idx rb (Ring.startOf rb)
1874 SplitOnSeqKR s idx rb _ -> consumeRing s idx rb (Ring.startOf rb)
1803 SplitOnSeqKRLoop s _ rb rh -> consumeRing s patLen rb rh
1875 SplitOnSeqKRLoop s _ rb rh -> consumeRing s patLen rb rh
1804
1876
1805− extract state = extractFunc fextract state
1806−
1807− final state = extractFunc ffinal state
1808−
1809------------------------------------------------------------------------------
1877------------------------------------------------------------------------------
1810-- Distributing
1878-- Distributing
1811------------------------------------------------------------------------------
1879------------------------------------------------------------------------------
@@ -2249,8 +2317,8 @@ toStreamRev = fmap StreamD.fromList toListRev
2249-- /Pre-release/
2317-- /Pre-release/
2250{-# INLINE unfoldMany #-}
2318{-# INLINE unfoldMany #-}
2251unfoldMany :: Monad m => Unfold m a b -> Fold m b c -> Fold m a c
2319unfoldMany :: Monad m => Unfold m a b -> Fold m b c -> Fold m a c
2252−unfoldMany (Unfold ustep inject) (Fold fstep initial extract final) =
2320+unfoldMany (Unfold ustep inject) (Fold fstep initial extract) =
2253− Fold consume initial extract final
2321+ Fold consume initial extract
2254
2322
2255 where
2323 where
2256
2324
@@ -2277,7 +2345,7 @@ bottomBy :: (MonadIO m, Unbox a) =>
2277 (a -> a -> Ordering)
2345 (a -> a -> Ordering)
2278 -> Int
2346 -> Int
2279 -> Fold m a (MutArray a)
2347 -> Fold m a (MutArray a)
2280−bottomBy cmp n = Fold step initial extract extract
2348+bottomBy cmp n = Fold step initial extract
2281
2349
2282 where
2350 where
2283
2351
@@ -2372,8 +2440,8 @@ intersperseWithQuotes
2372 quote
2440 quote
2373 esc
2441 esc
2374 separator
2442 separator
2375− (Fold stepL initialL _ finalL)
2443+ (Fold stepL initialL extractL)
2376− (Fold stepR initialR extractR finalR) = Fold step initial extract final
2444+ (Fold stepR initialR extractR) = Fold step initial extract
2377
2445
2378 where
2446 where
2379
2447
@@ -2416,13 +2484,11 @@ intersperseWithQuotes
2416 r <- stepL sL a
2484 r <- stepL sL a
2417 case r of
2485 case r of
2418 Partial s -> return $ Partial (nextState sR s)
2486 Partial s -> return $ Partial (nextState sR s)
2419− Done _ -> do
2420− _ <- finalR sR
2421− error "Collecting fold finished inside quote"
2487+ Done _ -> error "Collecting fold finished inside quote"
2422
2488
2423 step (IntersperseQUnquoted sR sL) a
2489 step (IntersperseQUnquoted sR sL) a
2424 | a == separator = do
2490 | a == separator = do
2425− b <- finalL sL
2491+ b <- extractL sL
2426 collect IntersperseQUnquoted sR b
2492 collect IntersperseQUnquoted sR b
2427 | a == quote = processQuoted a sL sR IntersperseQQuoted
2493 | a == quote = processQuoted a sL sR IntersperseQQuoted
2428 | otherwise = process a sL sR IntersperseQUnquoted
2494 | otherwise = process a sL sR IntersperseQUnquoted
@@ -2440,13 +2506,3 @@ intersperseWithQuotes
2440 error "intersperseWithQuotes: finished inside quote"
2506 error "intersperseWithQuotes: finished inside quote"
2441 extract (IntersperseQQuotedEsc _ _) =
2507 extract (IntersperseQQuotedEsc _ _) =
2442 error "intersperseWithQuotes: finished inside quote, at escape char"
2508 error "intersperseWithQuotes: finished inside quote, at escape char"
2443−
2444− final (IntersperseQUnquoted sR sL) = finalL sL *> finalR sR
2445− final (IntersperseQQuoted sR sL) = do
2446− _ <- finalR sR
2447− _ <- finalL sL
2448− error "intersperseWithQuotes: finished inside quote"
2449− final (IntersperseQQuotedEsc sR sL) = do
2450− _ <- finalR sR
2451− _ <- finalL sL
2452− error "intersperseWithQuotes: finished inside quote, at escape char"
core/src/Streamly/Internal/Data/Fold/Container.hs+28−73
@@ -270,15 +270,14 @@ demuxGeneric :: (Monad m, IsMap f, Traversable f) =>
270 (a -> Key f)
270 (a -> Key f)
271 -> (a -> m (Fold m a b))
271 -> (a -> m (Fold m a b))
272 -> Fold m a (m (f b), Maybe (Key f, b))
272 -> Fold m a (m (f b), Maybe (Key f, b))
273−demuxGeneric getKey getFold =
273+demuxGeneric getKey getFold = fmap extract $ foldlM' step initial
274− Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
275
274
276 where
275 where
277
276
278 initial = return $ Tuple' IsMap.mapEmpty Nothing
277 initial = return $ Tuple' IsMap.mapEmpty Nothing
279
278
280 {-# INLINE runFold #-}
279 {-# INLINE runFold #-}
281− runFold kv (Fold step1 initial1 extract1 final1) (k, a) = do
280+ runFold kv (Fold step1 initial1 extract1) (k, a) = do
282 res <- initial1
281 res <- initial1
283 case res of
282 case res of
284 Partial s -> do
283 Partial s -> do
@@ -286,7 +285,7 @@ demuxGeneric getKey getFold =
286 return
285 return
287 $ case res1 of
286 $ case res1 of
288 Partial _ ->
287 Partial _ ->
289− let fld = Fold step1 (return res1) extract1 final1
288+ let fld = Fold step1 (return res1) extract1
290 in Tuple' (IsMap.mapInsert k fld kv) Nothing
289 in Tuple' (IsMap.mapInsert k fld kv) Nothing
291 Done b -> Tuple' (IsMap.mapDelete k kv) (Just (k, b))
290 Done b -> Tuple' (IsMap.mapDelete k kv) (Just (k, b))
292 Done b -> return $ Tuple' kv (Just (k, b))
291 Done b -> return $ Tuple' kv (Just (k, b))
@@ -299,25 +298,15 @@ demuxGeneric getKey getFold =
299 runFold kv fld (k, a)
298 runFold kv fld (k, a)
300 Just f -> runFold kv f (k, a)
299 Just f -> runFold kv f (k, a)
301
300
302− extract (Tuple' kv x) = return (Prelude.mapM f kv, x)
301+ extract (Tuple' kv x) = (Prelude.mapM f kv, x)
303
302
304 where
303 where
305
304
306− f (Fold _ i e _) = do
305+ f (Fold _ i e) = do
307 r <- i
306 r <- i
308 case r of
307 case r of
309 Partial s -> e s
308 Partial s -> e s
310− _ -> error "demuxGeneric: unreachable code"
309+ Done b -> return b
311−
312− final (Tuple' kv x) = return (Prelude.mapM f kv, x)
313−
314− where
315−
316− f (Fold _ i _ fin) = do
317− r <- i
318− case r of
319− Partial s -> fin s
320− _ -> error "demuxGeneric: unreachable code"
321
310
322-- | @demux getKey getFold@: In a key value stream, fold values corresponding
311-- | @demux getKey getFold@: In a key value stream, fold values corresponding
323-- to each key using a key specific fold. @getFold@ is invoked to generate a
312-- to each key using a key specific fold. @getFold@ is invoked to generate a
@@ -359,36 +348,35 @@ demuxGenericIO :: (MonadIO m, IsMap f, Traversable f) =>
359 (a -> Key f)
348 (a -> Key f)
360 -> (a -> m (Fold m a b))
349 -> (a -> m (Fold m a b))
361 -> Fold m a (m (f b), Maybe (Key f, b))
350 -> Fold m a (m (f b), Maybe (Key f, b))
362−demuxGenericIO getKey getFold =
351+demuxGenericIO getKey getFold = fmap extract $ foldlM' step initial
363− Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
364
352
365 where
353 where
366
354
367 initial = return $ Tuple' IsMap.mapEmpty Nothing
355 initial = return $ Tuple' IsMap.mapEmpty Nothing
368
356
369 {-# INLINE initFold #-}
357 {-# INLINE initFold #-}
370− initFold kv (Fold step1 initial1 extract1 final1) (k, a) = do
358+ initFold kv (Fold step1 initial1 extract1) (k, a) = do
371 res <- initial1
359 res <- initial1
372 case res of
360 case res of
373 Partial s -> do
361 Partial s -> do
374 res1 <- step1 s a
362 res1 <- step1 s a
375 case res1 of
363 case res1 of
376 Partial _ -> do
364 Partial _ -> do
377− let fld = Fold step1 (return res1) extract1 final1
365+ let fld = Fold step1 (return res1) extract1
378 ref <- liftIO $ newIORef fld
366 ref <- liftIO $ newIORef fld
379 return $ Tuple' (IsMap.mapInsert k ref kv) Nothing
367 return $ Tuple' (IsMap.mapInsert k ref kv) Nothing
380 Done b -> return $ Tuple' kv (Just (k, b))
368 Done b -> return $ Tuple' kv (Just (k, b))
381 Done b -> return $ Tuple' kv (Just (k, b))
369 Done b -> return $ Tuple' kv (Just (k, b))
382
370
383 {-# INLINE runFold #-}
371 {-# INLINE runFold #-}
384− runFold kv ref (Fold step1 initial1 extract1 final1) (k, a) = do
372+ runFold kv ref (Fold step1 initial1 extract1) (k, a) = do
385 res <- initial1
373 res <- initial1
386 case res of
374 case res of
387 Partial s -> do
375 Partial s -> do
388 res1 <- step1 s a
376 res1 <- step1 s a
389 case res1 of
377 case res1 of
390 Partial _ -> do
378 Partial _ -> do
391− let fld = Fold step1 (return res1) extract1 final1
379+ let fld = Fold step1 (return res1) extract1
392 liftIO $ writeIORef ref fld
380 liftIO $ writeIORef ref fld
393 return $ Tuple' kv Nothing
381 return $ Tuple' kv Nothing
394 Done b ->
382 Done b ->
@@ -406,27 +394,16 @@ demuxGenericIO getKey getFold =
406 f <- liftIO $ readIORef ref
394 f <- liftIO $ readIORef ref
407 runFold kv ref f (k, a)
395 runFold kv ref f (k, a)
408
396
409− extract (Tuple' kv x) = return (Prelude.mapM f kv, x)
397+ extract (Tuple' kv x) = (Prelude.mapM f kv, x)
410
398
411 where
399 where
412
400
413 f ref = do
401 f ref = do
414− Fold _ i e _ <- liftIO $ readIORef ref
402+ (Fold _ i e) <- liftIO $ readIORef ref
415 r <- i
403 r <- i
416 case r of
404 case r of
417 Partial s -> e s
405 Partial s -> e s
418− _ -> error "demuxGenericIO: unreachable code"
406+ Done b -> return b
419−
420− final (Tuple' kv x) = return (Prelude.mapM f kv, x)
421−
422− where
423−
424− f ref = do
425− Fold _ i _ fin <- liftIO $ readIORef ref
426− r <- i
427− case r of
428− Partial s -> fin s
429− _ -> error "demuxGenericIO: unreachable code"
430
407
431-- | This is specialized version of 'demux' that uses mutable IO cells as
408-- | This is specialized version of 'demux' that uses mutable IO cells as
432-- fold accumulators for better performance.
409-- fold accumulators for better performance.
@@ -441,13 +418,6 @@ demuxIO :: (MonadIO m, Ord k) =>
441 -> Fold m a (m (Map k b), Maybe (k, b))
418 -> Fold m a (m (Map k b), Maybe (k, b))
442demuxIO = demuxGenericIO
419demuxIO = demuxGenericIO
443
420
444−-- | Fold a key value stream to a key-value Map. If the same key appears
445−-- multiple times, only the last value is retained.
446−{-# INLINE kvToMapOverwriteGeneric #-}
447−kvToMapOverwriteGeneric :: (Monad m, IsMap f) => Fold m (Key f, a) (f a)
448−kvToMapOverwriteGeneric =
449− foldl' (\kv (k, v) -> IsMap.mapInsert k v kv) IsMap.mapEmpty
450−
451{-# INLINE demuxToContainer #-}
421{-# INLINE demuxToContainer #-}
452demuxToContainer :: (Monad m, IsMap f, Traversable f) =>
422demuxToContainer :: (Monad m, IsMap f, Traversable f) =>
453 (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
423 (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
@@ -535,8 +505,8 @@ classifyGeneric :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
535 -- for that use case. We return an action because we want it to be lazy so
505 -- for that use case. We return an action because we want it to be lazy so
536 -- that the downstream consumers can choose to process or discard it.
506 -- that the downstream consumers can choose to process or discard it.
537 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
507 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
538−classifyGeneric f (Fold step1 initial1 extract1 final1) =
508+classifyGeneric f (Fold step1 initial1 extract1) =
539− Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
509+ fmap extract $ foldlM' step initial
540
510
541 where
511 where
542
512
@@ -573,16 +543,7 @@ classifyGeneric f (Fold step1 initial1 extract1 final1) =
573 let kv1 = IsMap.mapDelete k kv
543 let kv1 = IsMap.mapDelete k kv
574 in Tuple3' kv1 (Set.insert k set) (Just (k, b))
544 in Tuple3' kv1 (Set.insert k set) (Just (k, b))
575
545
576− extract (Tuple3' kv _ x) = return (Prelude.mapM extract1 kv, x)
546+ extract (Tuple3' kv _ x) = (Prelude.mapM extract1 kv, x)
577−
578− final (Tuple3' kv set x) = return (IsMap.mapTraverseWithKey f1 kv, x)
579−
580− where
581−
582− f1 k s = do
583− if Set.member k set
584− then extract1 s
585− else final1 s
586
547
587-- | Folds the values for each key using the supplied fold. When scanning, as
548-- | Folds the values for each key using the supplied fold. When scanning, as
588-- soon as the fold is complete, its result is available in the second
549-- soon as the fold is complete, its result is available in the second
@@ -607,8 +568,8 @@ classify = classifyGeneric
607{-# INLINE classifyGenericIO #-}
568{-# INLINE classifyGenericIO #-}
608classifyGenericIO :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) =>
569classifyGenericIO :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) =>
609 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
570 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
610−classifyGenericIO f (Fold step1 initial1 extract1 final1) =
571+classifyGenericIO f (Fold step1 initial1 extract1) =
611− Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
572+ fmap extract $ foldlM' step initial
612
573
613 where
574 where
614
575
@@ -647,21 +608,8 @@ classifyGenericIO f (Fold step1 initial1 extract1 final1) =
647 in return
608 in return
648 $ Tuple3' kv1 (Set.insert k set) (Just (k, b))
609 $ Tuple3' kv1 (Set.insert k set) (Just (k, b))
649
610
650− extract (Tuple3' kv _ x) = return (Prelude.mapM g kv, x)
611+ extract (Tuple3' kv _ x) =
651−
652− where
653−
654− g ref = liftIO (readIORef ref) >>= extract1
612+ (Prelude.mapM (\ref -> liftIO (readIORef ref) >>= extract1) kv, x)
655−
656− final (Tuple3' kv set x) = return (IsMap.mapTraverseWithKey g kv, x)
657−
658− where
659−
660− g k ref = do
661− s <- liftIO $ readIORef ref
662− if Set.member k set
663− then extract1 s
664− else final1 s
665
613
666-- | Same as classify except that it uses mutable IORef cells in the
614-- | Same as classify except that it uses mutable IORef cells in the
667-- Map providing better performance. Be aware that if this is used as a scan,
615-- Map providing better performance. Be aware that if this is used as a scan,
@@ -676,6 +624,13 @@ classifyIO :: (MonadIO m, Ord k) =>
676 (a -> k) -> Fold m a b -> Fold m a (m (Map k b), Maybe (k, b))
624 (a -> k) -> Fold m a b -> Fold m a (m (Map k b), Maybe (k, b))
677classifyIO = classifyGenericIO
625classifyIO = classifyGenericIO
678
626
627+-- | Fold a key value stream to a key-value Map. If the same key appears
628+-- multiple times, only the last value is retained.
629+{-# INLINE kvToMapOverwriteGeneric #-}
630+kvToMapOverwriteGeneric :: (Monad m, IsMap f) => Fold m (Key f, a) (f a)
631+kvToMapOverwriteGeneric =
632+ foldl' (\kv (k, v) -> IsMap.mapInsert k v kv) IsMap.mapEmpty
633+
679{-# INLINE toContainer #-}
634{-# INLINE toContainer #-}
680toContainer :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
635toContainer :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
681 (a -> Key f) -> Fold m a b -> Fold m a (f b)
636 (a -> Key f) -> Fold m a b -> Fold m a (f b)
core/src/Streamly/Internal/Data/Fold/Step.hs+1−1
@@ -40,7 +40,7 @@ data Step s b
40 = Partial !s
40 = Partial !s
41 | Done !b
41 | Done !b
42
42
43−-- | 'first' maps over the fold state and 'second' maps over the fold result.
43+-- | 'first' maps over 'Partial' and 'second' maps over 'Done'.
44--
44--
45instance Bifunctor Step where
45instance Bifunctor Step where
46 {-# INLINE bimap #-}
46 {-# INLINE bimap #-}
core/src/Streamly/Internal/Data/Fold/Tee.hs−2
@@ -16,9 +16,7 @@ module Streamly.Internal.Data.Fold.Tee
16 )
16 )
17where
17where
18
18
19−#if !MIN_VERSION_base(4,18,0)
20import Control.Applicative (liftA2)
19import Control.Applicative (liftA2)
21−#endif
22import Streamly.Internal.Data.Fold.Type (Fold)
20import Streamly.Internal.Data.Fold.Type (Fold)
23
21
24import qualified Streamly.Internal.Data.Fold.Type as Fold
22import qualified Streamly.Internal.Data.Fold.Type as Fold
core/src/Streamly/Internal/Data/Fold/Type.hs+114−338
@@ -367,8 +367,6 @@ module Streamly.Internal.Data.Fold.Type
367 , toList
367 , toList
368 , toStreamK
368 , toStreamK
369 , toStreamKRev
369 , toStreamKRev
370− , lengthGeneric
371− , length
372
370
373 -- * Combinators
371 -- * Combinators
374
372
@@ -393,8 +391,6 @@ module Streamly.Internal.Data.Fold.Type
393 -- ** Trimming
391 -- ** Trimming
394 , take
392 , take
395 , taking
393 , taking
396− , takeEndBy_
397− , takeEndBy
398 , dropping
394 , dropping
399
395
400 -- ** Sequential application
396 -- ** Sequential application
@@ -446,10 +442,8 @@ where
446
442
447#include "inline.hs"
443#include "inline.hs"
448
444
449−#if !MIN_VERSION_base(4,18,0)
450import Control.Applicative (liftA2)
445import Control.Applicative (liftA2)
451−#endif
452−import Control.Monad ((>=>), void)
446+import Control.Monad ((>=>))
453import Data.Bifunctor (Bifunctor(..))
447import Data.Bifunctor (Bifunctor(..))
454import Data.Either (fromLeft, fromRight, isLeft, isRight)
448import Data.Either (fromLeft, fromRight, isLeft, isRight)
455import Data.Functor.Identity (Identity(..))
449import Data.Functor.Identity (Identity(..))
@@ -475,64 +469,23 @@ import Streamly.Internal.Data.Fold.Step
475-- The type @b@ is the accumulator of the writer. That's the reason the
469-- The type @b@ is the accumulator of the writer. That's the reason the
476-- default folds in various modules are called "write".
470-- default folds in various modules are called "write".
477
471
478−-- An alternative to using an "extract" function is to use "Partial s b" style
472+-- | The type @Fold m a b@ having constructor @Fold step initial extract@
479−-- partial value so that we always emit the output value and there is no need
480−-- to extract. Then extract can be used for cleanup purposes. But in this case
481−-- in some cases we may need a "Continue" constructor where an output value is
482−-- not available, this was implicit earlier. Also, "b" should be lazy here so
483−-- that we do not always compute it even if we do not need it.
484−--
485−-- Partial s b --> extract :: s -> b
486−-- Continue --> extract :: s -> Maybe b
487−--
488−-- But keeping 'b' lazy does not let the fold optimize well. It leads to
489−-- significant regressions in the key-value folds.
490−--
491−-- The "final" function complicates combinators that take other folds as
492−-- argument because we need to call their finalizers at right places. An
493−-- alternative to reduce this complexity where it is not required is to use a
494−-- separate type for bracketed folds but then we need to manage the complexity
495−-- of two different fold types.
496−
497−-- The "final" function could be (s -> m (Step s b)), like in parsers so that
498−-- it can be called in a loop to drain the fold.
499−
500−-- | The type @Fold m a b@ represents a consumer of an input stream of values
473+-- represents a fold over an input stream of values of type @a@ to a final
501−-- of type @a@ and returning a final value of type @b@ in 'Monad' @m@. The
474+-- value of type @b@ in 'Monad' @m@.
502−-- constructor of a fold is @Fold step initial extract final@.
503−--
475+--
476+-- The fold uses an intermediate state @s@ as accumulator, the type @s@ is
504−-- The fold uses an internal state of type @s@. The initial value of the state
477+-- internal to the specific fold definition. The initial value of the fold
505−-- @s@ is created by @initial@. This function is called once and only once
506−-- before the fold starts consuming input. Any resource allocation can be done
507−-- in this function.
508−--
509−-- The @step@ function is called on each input, it consumes an input and
478+-- state @s@ is returned by @initial@. The @step@ function consumes an input
479+-- and either returns the final result @b@ if the fold is done or the next
510−-- returns the next intermediate state (see 'Step') or the final result @b@ if
480+-- intermediate state (see 'Step'). At any point the fold driver can extract
511−-- the fold terminates.
481+-- the result from the intermediate state using the @extract@ function.
512−--
513−-- If the fold is used as a scan, the @extract@ function is used by the scan
514−-- driver to map the current state @s@ of the fold to the fold result. Thus
515−-- @extract@ can be called multiple times. In some folds, where scanning does
516−-- not make sense, this function is left unimplemented; such folds cannot be
517−-- used as scans.
518−--
519−-- Before a fold terminates, @final@ is called once and only once (unless the
520−-- fold terminated in @initial@ itself). Any resources allocated by @initial@
521−-- can be released in @final@. In folds that do not require any cleanup
522−-- @extract@ and @final@ are typically the same.
523−--
524−-- When implementing fold combinators, care should be taken to cleanup any
525−-- state of the argument folds held by the fold by calling the respective
526−-- @final@ at all exit points of the fold. Also, @final@ should not be called
527−-- more than once. Note that if a fold terminates by 'Done' constructor, there
528−-- is no state to cleanup.
529--
482--
530-- NOTE: The constructor is not yet released, smart constructors are provided
483-- NOTE: The constructor is not yet released, smart constructors are provided
531-- to create folds.
484-- to create folds.
532--
485--
533data Fold m a b =
486data Fold m a b =
534− -- | @Fold@ @step@ @initial@ @extract@ @final@
487+ -- | @Fold @ @ step @ @ initial @ @ extract@
535− forall s. Fold (s -> a -> m (Step s b)) (m (Step s b)) (s -> m b) (s -> m b)
488+ forall s. Fold (s -> a -> m (Step s b)) (m (Step s b)) (s -> m b)
536
489
537------------------------------------------------------------------------------
490------------------------------------------------------------------------------
538-- Mapping on the output
491-- Mapping on the output
@@ -542,8 +495,7 @@ data Fold m a b =
542--
495--
543{-# INLINE rmapM #-}
496{-# INLINE rmapM #-}
544rmapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
497rmapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
545−rmapM f (Fold step initial extract final) =
498+rmapM f (Fold step initial extract) = Fold step1 initial1 (extract >=> f)
546− Fold step1 initial1 (extract >=> f) (final >=> f)
547
499
548 where
500 where
549
501
@@ -574,7 +526,6 @@ foldl' step initial =
574 (\s a -> return $ Partial $ step s a)
526 (\s a -> return $ Partial $ step s a)
575 (return (Partial initial))
527 (return (Partial initial))
576 return
528 return
577− return
578
529
579-- | Make a fold from a left fold style monadic step function and initial value
530-- | Make a fold from a left fold style monadic step function and initial value
580-- of the accumulator.
531-- of the accumulator.
@@ -589,7 +540,7 @@ foldl' step initial =
589{-# INLINE foldlM' #-}
540{-# INLINE foldlM' #-}
590foldlM' :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
541foldlM' :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
591foldlM' step initial =
542foldlM' step initial =
592− Fold (\s a -> Partial <$> step s a) (Partial <$> initial) return return
543+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) return
593
544
594-- | Make a strict left fold, for non-empty streams, using first element as the
545-- | Make a strict left fold, for non-empty streams, using first element as the
595-- starting value. Returns Nothing if the stream is empty.
546-- starting value. Returns Nothing if the stream is empty.
@@ -687,11 +638,7 @@ foldrM' g z =
687{-# INLINE foldt' #-}
638{-# INLINE foldt' #-}
688foldt' :: Monad m => (s -> a -> Step s b) -> Step s b -> (s -> b) -> Fold m a b
639foldt' :: Monad m => (s -> a -> Step s b) -> Step s b -> (s -> b) -> Fold m a b
689foldt' step initial extract =
640foldt' step initial extract =
690− Fold
691− (\s a -> return $ step s a)
641+ Fold (\s a -> return $ step s a) (return initial) (return . extract)
692− (return initial)
693− (return . extract)
694− (return . extract)
695
642
696-- | Make a terminating fold with an effectful step function and initial state,
643-- | Make a terminating fold with an effectful step function and initial state,
697-- and a state extraction function.
644-- and a state extraction function.
@@ -704,7 +651,7 @@ foldt' step initial extract =
704--
651--
705{-# INLINE foldtM' #-}
652{-# INLINE foldtM' #-}
706foldtM' :: (s -> a -> m (Step s b)) -> m (Step s b) -> (s -> m b) -> Fold m a b
653foldtM' :: (s -> a -> m (Step s b)) -> m (Step s b) -> (s -> m b) -> Fold m a b
707−foldtM' step initial extract = Fold step initial extract extract
654+foldtM' = Fold
708
655
709------------------------------------------------------------------------------
656------------------------------------------------------------------------------
710-- Refold
657-- Refold
@@ -718,7 +665,7 @@ foldtM' step initial extract = Fold step initial extract extract
718-- /Internal/
665-- /Internal/
719fromRefold :: Refold m c a b -> c -> Fold m a b
666fromRefold :: Refold m c a b -> c -> Fold m a b
720fromRefold (Refold step inject extract) c =
667fromRefold (Refold step inject extract) c =
721− Fold step (inject c) extract extract
668+ Fold step (inject c) extract
722
669
723------------------------------------------------------------------------------
670------------------------------------------------------------------------------
724-- Basic Folds
671-- Basic Folds
@@ -771,29 +718,6 @@ toStreamKRev = foldl' (flip K.cons) K.nil
771toStreamK :: Monad m => Fold m a (K.StreamK n a)
718toStreamK :: Monad m => Fold m a (K.StreamK n a)
772toStreamK = foldr K.cons K.nil
719toStreamK = foldr K.cons K.nil
773
720
774−-- | Like 'length', except with a more general 'Num' return value
775−--
776−-- Definition:
777−--
778−-- >>> lengthGeneric = fmap getSum $ Fold.foldMap (Sum . const 1)
779−-- >>> lengthGeneric = Fold.foldl' (\n _ -> n + 1) 0
780−--
781−-- /Pre-release/
782−{-# INLINE lengthGeneric #-}
783−lengthGeneric :: (Monad m, Num b) => Fold m a b
784−lengthGeneric = foldl' (\n _ -> n + 1) 0
785−
786−-- | Determine the length of the input stream.
787−--
788−-- Definition:
789−--
790−-- >>> length = Fold.lengthGeneric
791−-- >>> length = fmap getSum $ Fold.foldMap (Sum . const 1)
792−--
793−{-# INLINE length #-}
794−length :: Monad m => Fold m a Int
795−length = lengthGeneric
796−
797------------------------------------------------------------------------------
721------------------------------------------------------------------------------
798-- Instances
722-- Instances
799------------------------------------------------------------------------------
723------------------------------------------------------------------------------
@@ -801,8 +725,7 @@ length = lengthGeneric
801-- | Maps a function on the output of the fold (the type @b@).
725-- | Maps a function on the output of the fold (the type @b@).
802instance Functor m => Functor (Fold m a) where
726instance Functor m => Functor (Fold m a) where
803 {-# INLINE fmap #-}
727 {-# INLINE fmap #-}
804− fmap f (Fold step1 initial1 extract final) =
728+ fmap f (Fold step1 initial1 extract) = Fold step initial (fmap2 f extract)
805− Fold step initial (fmap2 f extract) (fmap2 f final)
806
729
807 where
730 where
808
731
@@ -837,7 +760,7 @@ instance Functor m => Functor (Fold m a) where
837--
760--
838{-# INLINE fromPure #-}
761{-# INLINE fromPure #-}
839fromPure :: Applicative m => b -> Fold m a b
762fromPure :: Applicative m => b -> Fold m a b
840−fromPure b = Fold undefined (pure $ Done b) pure pure
763+fromPure b = Fold undefined (pure $ Done b) pure
841
764
842-- | Make a fold that yields the result of the supplied effectful action
765-- | Make a fold that yields the result of the supplied effectful action
843-- without consuming any further input.
766-- without consuming any further input.
@@ -846,7 +769,7 @@ fromPure b = Fold undefined (pure $ Done b) pure pure
846--
769--
847{-# INLINE fromEffect #-}
770{-# INLINE fromEffect #-}
848fromEffect :: Applicative m => m b -> Fold m a b
771fromEffect :: Applicative m => m b -> Fold m a b
849−fromEffect b = Fold undefined (Done <$> b) pure pure
772+fromEffect b = Fold undefined (Done <$> b) pure
850
773
851{-# ANN type SeqFoldState Fuse #-}
774{-# ANN type SeqFoldState Fuse #-}
852data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
775data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
@@ -871,20 +794,16 @@ data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
871-- complexity, because each composition adds a new branch that each subsequent
794-- complexity, because each composition adds a new branch that each subsequent
872-- fold's input element has to traverse, therefore, it cannot scale to a large
795-- fold's input element has to traverse, therefore, it cannot scale to a large
873-- number of compositions. After around 100 compositions the performance starts
796-- number of compositions. After around 100 compositions the performance starts
874−-- dipping rapidly compared to a CPS style implementation.
797+-- dipping rapidly compared to a CPS style implementation. When you need
875−--
798+-- scaling use parser monad instead.
876−-- For larger number of compositions you can convert the fold to a parser and
877−-- use ParserK.
878--
799--
879-- /Time: O(n^2) where n is the number of compositions./
800-- /Time: O(n^2) where n is the number of compositions./
880--
801--
881{-# INLINE splitWith #-}
802{-# INLINE splitWith #-}
882splitWith :: Monad m =>
803splitWith :: Monad m =>
883 (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
804 (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
884−splitWith func
805+splitWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
885− (Fold stepL initialL _ finalL)
886− (Fold stepR initialR _ finalR) =
887− Fold step initial extract final
806+ Fold step initial extract
888
807
889 where
808 where
890
809
@@ -901,18 +820,13 @@ splitWith func
901 step (SeqFoldL st) a = runL (stepL st a)
820 step (SeqFoldL st) a = runL (stepL st a)
902 step (SeqFoldR f st) a = runR (stepR st a) f
821 step (SeqFoldR f st) a = runR (stepR st a) f
903
822
904− -- XXX splitWith should not be used for scanning
905− -- It would rarely make sense and resource tracking and cleanup would be
906− -- expensive. especially when multiple splitWith are chained.
907− extract _ = error "splitWith: cannot be used for scanning"
908−
909− final (SeqFoldR f sR) = fmap f (finalR sR)
823+ extract (SeqFoldR f sR) = fmap f (extractR sR)
910− final (SeqFoldL sL) = do
824+ extract (SeqFoldL sL) = do
911− rL <- finalL sL
825+ rL <- extractL sL
912 res <- initialR
826 res <- initialR
913 fmap (func rL)
827 fmap (func rL)
914 $ case res of
828 $ case res of
915− Partial sR -> finalR sR
829+ Partial sR -> extractR sR
916 Done rR -> return rR
830 Done rR -> return rR
917
831
918{-# DEPRECATED serialWith "Please use \"splitWith\" instead" #-}
832{-# DEPRECATED serialWith "Please use \"splitWith\" instead" #-}
@@ -932,8 +846,8 @@ data SeqFoldState_ sl sr = SeqFoldL_ !sl | SeqFoldR_ !sr
932--
846--
933{-# INLINE split_ #-}
847{-# INLINE split_ #-}
934split_ :: Monad m => Fold m x a -> Fold m x b -> Fold m x b
848split_ :: Monad m => Fold m x a -> Fold m x b -> Fold m x b
935−split_ (Fold stepL initialL _ finalL) (Fold stepR initialR _ finalR) =
849+split_ (Fold stepL initialL _) (Fold stepR initialR extractR) =
936− Fold step initial extract final
850+ Fold step initial extract
937
851
938 where
852 where
939
853
@@ -956,16 +870,11 @@ split_ (Fold stepL initialL _ finalL) (Fold stepR initialR _ finalR) =
956 resR <- stepR st a
870 resR <- stepR st a
957 return $ first SeqFoldR_ resR
871 return $ first SeqFoldR_ resR
958
872
959− -- XXX split_ should not be used for scanning
960− -- See splitWith for more details.
961− extract _ = error "split_: cannot be used for scanning"
962−
963− final (SeqFoldR_ sR) = finalR sR
873+ extract (SeqFoldR_ sR) = extractR sR
964− final (SeqFoldL_ sL) = do
874+ extract (SeqFoldL_ _) = do
965− _ <- finalL sL
966 res <- initialR
875 res <- initialR
967 case res of
876 case res of
968− Partial sR -> finalR sR
877+ Partial sR -> extractR sR
969 Done rR -> return rR
878 Done rR -> return rR
970
879
971-- | 'Applicative' form of 'splitWith'. Split the input serially over two
880-- | 'Applicative' form of 'splitWith'. Split the input serially over two
@@ -1013,10 +922,8 @@ data TeeState sL sR bL bR
1013--
922--
1014{-# INLINE teeWith #-}
923{-# INLINE teeWith #-}
1015teeWith :: Monad m => (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
924teeWith :: Monad m => (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
1016−teeWith f
1017− (Fold stepL initialL extractL finalL)
925+teeWith f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1018− (Fold stepR initialR extractR finalR) =
1019− Fold step initial extract final
926+ Fold step initial extract
1020
927
1021 where
928 where
1022
929
@@ -1043,10 +950,6 @@ teeWith f
1043 extract (TeeLeft bR sL) = (`f` bR) <$> extractL sL
950 extract (TeeLeft bR sL) = (`f` bR) <$> extractL sL
1044 extract (TeeRight bL sR) = f bL <$> extractR sR
951 extract (TeeRight bL sR) = f bL <$> extractR sR
1045
952
1046− final (TeeBoth sL sR) = f <$> finalL sL <*> finalR sR
1047− final (TeeLeft bR sL) = (`f` bR) <$> finalL sL
1048− final (TeeRight bL sR) = f bL <$> finalR sR
1049−
1050{-# ANN type TeeFstState Fuse #-}
953{-# ANN type TeeFstState Fuse #-}
1051data TeeFstState sL sR b
954data TeeFstState sL sR b
1052 = TeeFstBoth !sL !sR
955 = TeeFstBoth !sL !sR
@@ -1059,10 +962,8 @@ data TeeFstState sL sR b
1059{-# INLINE teeWithFst #-}
962{-# INLINE teeWithFst #-}
1060teeWithFst :: Monad m =>
963teeWithFst :: Monad m =>
1061 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
964 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1062−teeWithFst f
1063− (Fold stepL initialL extractL finalL)
965+teeWithFst f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1064− (Fold stepR initialR extractR finalR) =
1065− Fold step initial extract final
966+ Fold step initial extract
1066
967
1067 where
968 where
1068
969
@@ -1081,7 +982,7 @@ teeWithFst f
1081 Done bl -> do
982 Done bl -> do
1082 Done . f bl <$>
983 Done . f bl <$>
1083 case resR of
984 case resR of
1084− Partial sr -> finalR sr
985+ Partial sr -> extractR sr
1085 Done br -> return br
986 Done br -> return br
1086
987
1087 initial = runBoth initialL initialR
988 initial = runBoth initialL initialR
@@ -1092,9 +993,6 @@ teeWithFst f
1092 extract (TeeFstBoth sL sR) = f <$> extractL sL <*> extractR sR
993 extract (TeeFstBoth sL sR) = f <$> extractL sL <*> extractR sR
1093 extract (TeeFstLeft bR sL) = (`f` bR) <$> extractL sL
994 extract (TeeFstLeft bR sL) = (`f` bR) <$> extractL sL
1094
995
1095− final (TeeFstBoth sL sR) = f <$> finalL sL <*> finalR sR
1096− final (TeeFstLeft bR sL) = (`f` bR) <$> finalL sL
1097−
1098-- | Like 'teeWith' but terminates as soon as any one of the two folds
996-- | Like 'teeWith' but terminates as soon as any one of the two folds
1099-- terminates.
997-- terminates.
1100--
998--
@@ -1103,10 +1001,8 @@ teeWithFst f
1103{-# INLINE teeWithMin #-}
1001{-# INLINE teeWithMin #-}
1104teeWithMin :: Monad m =>
1002teeWithMin :: Monad m =>
1105 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1003 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1106−teeWithMin f
1107− (Fold stepL initialL extractL finalL)
1004+teeWithMin f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1108− (Fold stepR initialR extractR finalR) =
1109− Fold step initial extract final
1005+ Fold step initial extract
1110
1006
1111 where
1007 where
1112
1008
@@ -1118,12 +1014,12 @@ teeWithMin f
1118 Partial sl -> do
1014 Partial sl -> do
1119 case resR of
1015 case resR of
1120 Partial sr -> return $ Partial $ Tuple' sl sr
1016 Partial sr -> return $ Partial $ Tuple' sl sr
1121− Done br -> Done . (`f` br) <$> finalL sl
1017+ Done br -> Done . (`f` br) <$> extractL sl
1122
1018
1123 Done bl -> do
1019 Done bl -> do
1124 Done . f bl <$>
1020 Done . f bl <$>
1125 case resR of
1021 case resR of
1126− Partial sr -> finalR sr
1022+ Partial sr -> extractR sr
1127 Done br -> return br
1023 Done br -> return br
1128
1024
1129 initial = runBoth initialL initialR
1025 initial = runBoth initialL initialR
@@ -1132,8 +1028,6 @@ teeWithMin f
1132
1028
1133 extract (Tuple' sL sR) = f <$> extractL sL <*> extractR sR
1029 extract (Tuple' sL sR) = f <$> extractL sL <*> extractR sR
1134
1030
1135− final (Tuple' sL sR) = f <$> finalL sL <*> finalR sR
1136−
1137-- | Shortest alternative. Apply both folds in parallel but choose the result
1031-- | Shortest alternative. Apply both folds in parallel but choose the result
1138-- from the one which consumed least input i.e. take the shortest succeeding
1032-- from the one which consumed least input i.e. take the shortest succeeding
1139-- fold.
1033-- fold.
@@ -1145,8 +1039,8 @@ teeWithMin f
1145--
1039--
1146{-# INLINE shortest #-}
1040{-# INLINE shortest #-}
1147shortest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1041shortest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1148−shortest (Fold stepL initialL extractL finalL) (Fold stepR initialR _ finalR) =
1042+shortest (Fold stepL initialL extractL) (Fold stepR initialR _) =
1149− Fold step initial extract final
1043+ Fold step initial extract
1150
1044
1151 where
1045 where
1152
1046
@@ -1154,16 +1048,10 @@ shortest (Fold stepL initialL extractL finalL) (Fold stepR initialR _ finalR) =
1154 runBoth actionL actionR = do
1048 runBoth actionL actionR = do
1155 resL <- actionL
1049 resL <- actionL
1156 resR <- actionR
1050 resR <- actionR
1051+ return $
1157− case resL of
1052+ case resL of
1158− Partial sL ->
1159− case resR of
1160− Partial sR -> return $ Partial $ Tuple' sL sR
1053+ Partial sL -> bimap (Tuple' sL) Right resR
1161− Done bR -> finalL sL >> return (Done (Right bR))
1162− Done bL -> do
1054+ Done bL -> Done $ Left bL
1163− case resR of
1164− Partial sR -> void (finalR sR)
1165− Done _ -> return ()
1166− return (Done (Left bL))
1167
1055
1168 initial = runBoth initialL initialR
1056 initial = runBoth initialL initialR
1169
1057
@@ -1171,8 +1059,6 @@ shortest (Fold stepL initialL extractL finalL) (Fold stepR initialR _ finalR) =
1171
1059
1172 extract (Tuple' sL _) = Left <$> extractL sL
1060 extract (Tuple' sL _) = Left <$> extractL sL
1173
1061
1174− final (Tuple' sL sR) = Left <$> finalL sL <* finalR sR
1175−
1176{-# ANN type LongestState Fuse #-}
1062{-# ANN type LongestState Fuse #-}
1177data LongestState sL sR
1063data LongestState sL sR
1178 = LongestBoth !sL !sR
1064 = LongestBoth !sL !sR
@@ -1190,10 +1076,8 @@ data LongestState sL sR
1190--
1076--
1191{-# INLINE longest #-}
1077{-# INLINE longest #-}
1192longest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1078longest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1193−longest
1194− (Fold stepL initialL _ finalL)
1079+longest (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1195− (Fold stepR initialR _ finalR) =
1196− Fold step initial extract final
1080+ Fold step initial extract
1197
1081
1198 where
1082 where
1199
1083
@@ -1216,18 +1100,14 @@ longest
1216 step (LongestLeft sL) a = bimap LongestLeft Left <$> stepL sL a
1100 step (LongestLeft sL) a = bimap LongestLeft Left <$> stepL sL a
1217 step (LongestRight sR) a = bimap LongestRight Right <$> stepR sR a
1101 step (LongestRight sR) a = bimap LongestRight Right <$> stepR sR a
1218
1102
1219− -- XXX Scan with this may not make sense as we cannot determine the longest
1103+ left sL = Left <$> extractL sL
1220− -- until one of them have exhausted.
1221− extract _ = error $ "longest: scan is not allowed as longest cannot be "
1222− ++ "determined until one fold has exhausted."
1223−
1224− final (LongestLeft sL) = Left <$> finalL sL
1104+ extract (LongestLeft sL) = left sL
1225− final (LongestRight sR) = Right <$> finalR sR
1105+ extract (LongestRight sR) = Right <$> extractR sR
1226− final (LongestBoth sL sR) = Left <$> finalL sL <* finalR sR
1106+ extract (LongestBoth sL _) = left sL
1227
1107
1228−data ConcatMapState m sa a b c
1108+data ConcatMapState m sa a c
1229− = B !sa (sa -> m b)
1109+ = B !sa
1230− | forall s. C (s -> a -> m (Step s c)) !s (s -> m c) (s -> m c)
1110+ | forall s. C (s -> a -> m (Step s c)) !s (s -> m c)
1231
1111
1232-- | Map a 'Fold' returning function on the result of a 'Fold' and run the
1112-- | Map a 'Fold' returning function on the result of a 'Fold' and run the
1233-- returned fold. This operation can be used to express data dependencies
1113-- returned fold. This operation can be used to express data dependencies
@@ -1250,47 +1130,43 @@ data ConcatMapState m sa a b c
1250--
1130--
1251{-# INLINE concatMap #-}
1131{-# INLINE concatMap #-}
1252concatMap :: Monad m => (b -> Fold m a c) -> Fold m a b -> Fold m a c
1132concatMap :: Monad m => (b -> Fold m a c) -> Fold m a b -> Fold m a c
1253−concatMap f (Fold stepa initiala _ finala) =
1133+concatMap f (Fold stepa initiala extracta) = Fold stepc initialc extractc
1254− Fold stepc initialc extractc finalc
1255 where
1134 where
1256 initialc = do
1135 initialc = do
1257 r <- initiala
1136 r <- initiala
1258 case r of
1137 case r of
1259− Partial s -> return $ Partial (B s finala)
1138+ Partial s -> return $ Partial (B s)
1260 Done b -> initInnerFold (f b)
1139 Done b -> initInnerFold (f b)
1261
1140
1262− stepc (B s fin) a = do
1141+ stepc (B s) a = do
1263 r <- stepa s a
1142 r <- stepa s a
1264 case r of
1143 case r of
1265− Partial s1 -> return $ Partial (B s1 fin)
1144+ Partial s1 -> return $ Partial (B s1)
1266 Done b -> initInnerFold (f b)
1145 Done b -> initInnerFold (f b)
1267
1146
1268− stepc (C stepInner s extractInner fin) a = do
1147+ stepc (C stepInner s extractInner) a = do
1269 r <- stepInner s a
1148 r <- stepInner s a
1270 return $ case r of
1149 return $ case r of
1271− Partial sc -> Partial (C stepInner sc extractInner fin)
1150+ Partial sc -> Partial (C stepInner sc extractInner)
1272 Done c -> Done c
1151 Done c -> Done c
1273
1152
1274− -- XXX Cannot use for scanning
1153+ extractc (B s) = do
1275− extractc _ = error "concatMap: cannot be used for scanning"
1154+ r <- extracta s
1155+ initExtract (f r)
1156+ extractc (C _ sInner extractInner) = extractInner sInner
1276
1157
1277− initInnerFold (Fold step i e fin) = do
1158+ initInnerFold (Fold step i e) = do
1278 r <- i
1159 r <- i
1279 return $ case r of
1160 return $ case r of
1280− Partial s -> Partial (C step s e fin)
1161+ Partial s -> Partial (C step s e)
1281 Done c -> Done c
1162 Done c -> Done c
1282
1163
1283− initFinalize (Fold _ i _ fin) = do
1164+ initExtract (Fold _ i e) = do
1284 r <- i
1165 r <- i
1285 case r of
1166 case r of
1286− Partial s -> fin s
1167+ Partial s -> e s
1287 Done c -> return c
1168 Done c -> return c
1288
1169
1289− finalc (B s fin) = do
1290− r <- fin s
1291− initFinalize (f r)
1292− finalc (C _ sInner _ fin) = fin sInner
1293−
1294------------------------------------------------------------------------------
1170------------------------------------------------------------------------------
1295-- Mapping on input
1171-- Mapping on input
1296------------------------------------------------------------------------------
1172------------------------------------------------------------------------------
@@ -1309,7 +1185,7 @@ concatMap f (Fold stepa initiala _ finala) =
1309--
1185--
1310{-# INLINE lmap #-}
1186{-# INLINE lmap #-}
1311lmap :: (a -> b) -> Fold m b r -> Fold m a r
1187lmap :: (a -> b) -> Fold m b r -> Fold m a r
1312−lmap f (Fold step begin done final) = Fold step' begin done final
1188+lmap f (Fold step begin done) = Fold step' begin done
1313 where
1189 where
1314 step' x a = step x (f a)
1190 step' x a = step x (f a)
1315
1191
@@ -1317,7 +1193,7 @@ lmap f (Fold step begin done final) = Fold step' begin done final
1317--
1193--
1318{-# INLINE lmapM #-}
1194{-# INLINE lmapM #-}
1319lmapM :: Monad m => (a -> m b) -> Fold m b r -> Fold m a r
1195lmapM :: Monad m => (a -> m b) -> Fold m b r -> Fold m a r
1320−lmapM f (Fold step begin done final) = Fold step' begin done final
1196+lmapM f (Fold step begin done) = Fold step' begin done
1321 where
1197 where
1322 step' x a = f a >>= step x
1198 step' x a = f a >>= step x
1323
1199
@@ -1329,10 +1205,8 @@ lmapM f (Fold step begin done final) = Fold step' begin done final
1329-- /Pre-release/
1205-- /Pre-release/
1330{-# INLINE postscan #-}
1206{-# INLINE postscan #-}
1331postscan :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1207postscan :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1332−postscan
1333− (Fold stepL initialL extractL finalL)
1208+postscan (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1334− (Fold stepR initialR extractR finalR) =
1335− Fold step initial extract final
1209+ Fold step initial extract
1336
1210
1337 where
1211 where
1338
1212
@@ -1343,32 +1217,30 @@ postscan
1343 Done bL -> do
1217 Done bL -> do
1344 rR <- stepR sR bL
1218 rR <- stepR sR bL
1345 case rR of
1219 case rR of
1346− Partial sR1 -> Done <$> finalR sR1
1220+ Partial sR1 -> Done <$> extractR sR1
1347 Done bR -> return $ Done bR
1221 Done bR -> return $ Done bR
1348 Partial sL -> do
1222 Partial sL -> do
1349 !b <- extractL sL
1223 !b <- extractL sL
1350 rR <- stepR sR b
1224 rR <- stepR sR b
1225+ return
1351− case rR of
1226+ $ case rR of
1352− Partial sR1 -> return $ Partial (sL, sR1)
1227+ Partial sR1 -> Partial (sL, sR1)
1353− Done bR -> finalL sL >> return (Done bR)
1228+ Done bR -> Done bR
1354
1229
1355 initial = do
1230 initial = do
1356− rR <- initialR
1231+ r <- initialR
1232+ rL <- initialL
1357− case rR of
1233+ case r of
1358− Partial sR -> do
1234+ Partial sR ->
1359− rL <- initialL
1360 case rL of
1235 case rL of
1361− Done _ -> Done <$> finalR sR
1236+ Done _ -> Done <$> extractR sR
1362 Partial sL -> return $ Partial (sL, sR)
1237 Partial sL -> return $ Partial (sL, sR)
1363 Done b -> return $ Done b
1238 Done b -> return $ Done b
1364
1239
1365− -- XXX should use Tuple'
1366 step (sL, sR) x = runStep (stepL sL x) sR
1240 step (sL, sR) x = runStep (stepL sL x) sR
1367
1241
1368 extract = extractR . snd
1242 extract = extractR . snd
1369
1243
1370− final (sL, sR) = finalL sL *> finalR sR
1371−
1372------------------------------------------------------------------------------
1244------------------------------------------------------------------------------
1373-- Filtering
1245-- Filtering
1374------------------------------------------------------------------------------
1246------------------------------------------------------------------------------
@@ -1381,7 +1253,7 @@ postscan
1381--
1253--
1382{-# INLINE_NORMAL catMaybes #-}
1254{-# INLINE_NORMAL catMaybes #-}
1383catMaybes :: Monad m => Fold m a b -> Fold m (Maybe a) b
1255catMaybes :: Monad m => Fold m a b -> Fold m (Maybe a) b
1384−catMaybes (Fold step initial extract final) = Fold step1 initial extract final
1256+catMaybes (Fold step initial extract) = Fold step1 initial extract
1385
1257
1386 where
1258 where
1387
1259
@@ -1421,7 +1293,7 @@ filtering f = foldl' step Nothing
1421{-# INLINE filter #-}
1293{-# INLINE filter #-}
1422filter :: Monad m => (a -> Bool) -> Fold m a r -> Fold m a r
1294filter :: Monad m => (a -> Bool) -> Fold m a r -> Fold m a r
1423-- filter p = scanMaybe (filtering p)
1295-- filter p = scanMaybe (filtering p)
1424−filter f (Fold step begin extract final) = Fold step' begin extract final
1296+filter f (Fold step begin done) = Fold step' begin done
1425 where
1297 where
1426 step' x a = if f a then step x a else return $ Partial x
1298 step' x a = if f a then step x a else return $ Partial x
1427
1299
@@ -1432,7 +1304,7 @@ filter f (Fold step begin extract final) = Fold step' begin extract final
1432--
1304--
1433{-# INLINE filterM #-}
1305{-# INLINE filterM #-}
1434filterM :: Monad m => (a -> m Bool) -> Fold m a r -> Fold m a r
1306filterM :: Monad m => (a -> m Bool) -> Fold m a r -> Fold m a r
1435−filterM f (Fold step begin extract final) = Fold step' begin extract final
1307+filterM f (Fold step begin done) = Fold step' begin done
1436 where
1308 where
1437 step' x a = do
1309 step' x a = do
1438 use <- f a
1310 use <- f a
@@ -1521,7 +1393,7 @@ dropping n = foldt' step initial extract
1521{-# INLINE take #-}
1393{-# INLINE take #-}
1522take :: Monad m => Int -> Fold m a b -> Fold m a b
1394take :: Monad m => Int -> Fold m a b -> Fold m a b
1523-- take n = scanMaybe (taking n)
1395-- take n = scanMaybe (taking n)
1524−take n (Fold fstep finitial fextract ffinal) = Fold step initial extract final
1396+take n (Fold fstep finitial fextract) = Fold step initial extract
1525
1397
1526 where
1398 where
1527
1399
@@ -1533,7 +1405,7 @@ take n (Fold fstep finitial fextract ffinal) = Fold step initial extract final
1533 s1 = Tuple'Fused i1 s
1405 s1 = Tuple'Fused i1 s
1534 if i1 < n
1406 if i1 < n
1535 then return $ Partial s1
1407 then return $ Partial s1
1536− else Done <$> ffinal s
1408+ else Done <$> fextract s
1537 Done b -> return $ Done b
1409 Done b -> return $ Done b
1538
1410
1539 initial = finitial >>= next (-1)
1411 initial = finitial >>= next (-1)
@@ -1542,72 +1414,6 @@ take n (Fold fstep finitial fextract ffinal) = Fold step initial extract final
1542
1414
1543 extract (Tuple'Fused _ r) = fextract r
1415 extract (Tuple'Fused _ r) = fextract r
1544
1416
1545− final (Tuple'Fused _ r) = ffinal r
1546−
1547−-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
1548−-- S.splitOn in favor of the fold.
1549−--
1550−-- XXX Use Fold.many instead once it is fixed.
1551−-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1552−
1553−-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1554−--
1555−-- Example:
1556−--
1557−-- >>> input = Stream.fromList "hello\nthere\n"
1558−-- >>> line = Fold.takeEndBy_ (== '\n') Fold.toList
1559−-- >>> Stream.fold line input
1560−-- "hello"
1561−--
1562−-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1563−-- ["hello","there"]
1564−--
1565−{-# INLINE takeEndBy_ #-}
1566−takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1567−-- takeEndBy_ predicate = scanMaybe (takingEndBy_ predicate)
1568−takeEndBy_ predicate (Fold fstep finitial fextract ffinal) =
1569− Fold step finitial fextract ffinal
1570−
1571− where
1572−
1573− step s a =
1574− if not (predicate a)
1575− then fstep s a
1576− else Done <$> ffinal s
1577−
1578−-- Note:
1579−-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1580−
1581−-- | Take the input, stop when the predicate succeeds taking the succeeding
1582−-- element as well.
1583−--
1584−-- Example:
1585−--
1586−-- >>> input = Stream.fromList "hello\nthere\n"
1587−-- >>> line = Fold.takeEndBy (== '\n') Fold.toList
1588−-- >>> Stream.fold line input
1589−-- "hello\n"
1590−--
1591−-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1592−-- ["hello\n","there\n"]
1593−--
1594−{-# INLINE takeEndBy #-}
1595−takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1596−-- takeEndBy predicate = scanMaybe (takingEndBy predicate)
1597−takeEndBy predicate (Fold fstep finitial fextract ffinal) =
1598− Fold step finitial fextract ffinal
1599−
1600− where
1601−
1602− step s a = do
1603− res <- fstep s a
1604− if not (predicate a)
1605− then return res
1606− else do
1607− case res of
1608− Partial s1 -> Done <$> ffinal s1
1609− Done b -> return $ Done b
1610−
1611------------------------------------------------------------------------------
1417------------------------------------------------------------------------------
1612-- Nesting
1418-- Nesting
1613------------------------------------------------------------------------------
1419------------------------------------------------------------------------------
@@ -1625,8 +1431,8 @@ takeEndBy predicate (Fold fstep finitial fextract ffinal) =
1625-- /Pre-release/
1431-- /Pre-release/
1626{-# INLINE duplicate #-}
1432{-# INLINE duplicate #-}
1627duplicate :: Monad m => Fold m a b -> Fold m a (Fold m a b)
1433duplicate :: Monad m => Fold m a b -> Fold m a (Fold m a b)
1628−duplicate (Fold step1 initial1 extract1 final1) =
1434+duplicate (Fold step1 initial1 extract1) =
1629− Fold step initial extract final
1435+ Fold step initial (\s -> pure $ Fold step1 (pure $ Partial s) extract1)
1630
1436
1631 where
1437 where
1632
1438
@@ -1634,11 +1440,6 @@ duplicate (Fold step1 initial1 extract1 final1) =
1634
1440
1635 step s a = second fromPure <$> step1 s a
1441 step s a = second fromPure <$> step1 s a
1636
1442
1637− -- Scanning may be problematic due to multiple finalizations.
1638− extract = error "duplicate: scanning may be problematic"
1639−
1640− final s = pure $ Fold step1 (pure $ Partial s) extract1 final1
1641−
1642-- If there were a finalize/flushing action in the stream type that would be
1443-- If there were a finalize/flushing action in the stream type that would be
1643-- equivalent to running initialize in Fold. But we do not have a flushing
1444-- equivalent to running initialize in Fold. But we do not have a flushing
1644-- action in streams.
1445-- action in streams.
@@ -1650,9 +1451,9 @@ duplicate (Fold step1 initial1 extract1 final1) =
1650-- /Pre-release/
1451-- /Pre-release/
1651{-# INLINE reduce #-}
1452{-# INLINE reduce #-}
1652reduce :: Monad m => Fold m a b -> m (Fold m a b)
1453reduce :: Monad m => Fold m a b -> m (Fold m a b)
1653−reduce (Fold step initial extract final) = do
1454+reduce (Fold step initial extract) = do
1654 i <- initial
1455 i <- initial
1655− return $ Fold step (return i) extract final
1456+ return $ Fold step (return i) extract
1656
1457
1657-- This is the dual of Stream @cons@.
1458-- This is the dual of Stream @cons@.
1658
1459
@@ -1662,8 +1463,7 @@ reduce (Fold step initial extract final) = do
1662-- /Pre-release/
1463-- /Pre-release/
1663{-# INLINE snoclM #-}
1464{-# INLINE snoclM #-}
1664snoclM :: Monad m => Fold m a b -> m a -> Fold m a b
1465snoclM :: Monad m => Fold m a b -> m a -> Fold m a b
1665−snoclM (Fold fstep finitial fextract ffinal) action =
1466+snoclM (Fold fstep finitial fextract) action = Fold fstep initial fextract
1666− Fold fstep initial fextract ffinal
1667
1467
1668 where
1468 where
1669
1469
@@ -1690,8 +1490,7 @@ snoclM (Fold fstep finitial fextract ffinal) action =
1690{-# INLINE snocl #-}
1490{-# INLINE snocl #-}
1691snocl :: Monad m => Fold m a b -> a -> Fold m a b
1491snocl :: Monad m => Fold m a b -> a -> Fold m a b
1692-- snocl f = snoclM f . return
1492-- snocl f = snoclM f . return
1693−snocl (Fold fstep finitial fextract ffinal) a =
1493+snocl (Fold fstep finitial fextract) a = Fold fstep initial fextract
1694− Fold fstep initial fextract ffinal
1695
1494
1696 where
1495 where
1697
1496
@@ -1711,12 +1510,12 @@ snocl (Fold fstep finitial fextract ffinal) a =
1711-- /Pre-release/
1510-- /Pre-release/
1712{-# INLINE snocM #-}
1511{-# INLINE snocM #-}
1713snocM :: Monad m => Fold m a b -> m a -> m (Fold m a b)
1512snocM :: Monad m => Fold m a b -> m a -> m (Fold m a b)
1714−snocM (Fold step initial extract final) action = do
1513+snocM (Fold step initial extract) action = do
1715 res <- initial
1514 res <- initial
1716 r <- case res of
1515 r <- case res of
1717 Partial fs -> action >>= step fs
1516 Partial fs -> action >>= step fs
1718 Done _ -> return res
1517 Done _ -> return res
1719− return $ Fold step (return r) extract final
1518+ return $ Fold step (return r) extract
1720
1519
1721-- Definitions:
1520-- Definitions:
1722--
1521--
@@ -1735,12 +1534,12 @@ snocM (Fold step initial extract final) action = do
1735-- /Pre-release/
1534-- /Pre-release/
1736{-# INLINE snoc #-}
1535{-# INLINE snoc #-}
1737snoc :: Monad m => Fold m a b -> a -> m (Fold m a b)
1536snoc :: Monad m => Fold m a b -> a -> m (Fold m a b)
1738−snoc (Fold step initial extract final) a = do
1537+snoc (Fold step initial extract) a = do
1739 res <- initial
1538 res <- initial
1740 r <- case res of
1539 r <- case res of
1741 Partial fs -> step fs a
1540 Partial fs -> step fs a
1742 Done _ -> return res
1541 Done _ -> return res
1743− return $ Fold step (return r) extract final
1542+ return $ Fold step (return r) extract
1744
1543
1745-- | Append a singleton value to the fold.
1544-- | Append a singleton value to the fold.
1746--
1545--
@@ -1768,7 +1567,7 @@ addOne = flip snoc
1768-- /Pre-release/
1567-- /Pre-release/
1769{-# INLINE extractM #-}
1568{-# INLINE extractM #-}
1770extractM :: Monad m => Fold m a b -> m b
1569extractM :: Monad m => Fold m a b -> m b
1771−extractM (Fold _ initial extract _) = do
1570+extractM (Fold _ initial extract) = do
1772 res <- initial
1571 res <- initial
1773 case res of
1572 case res of
1774 Partial fs -> extract fs
1573 Partial fs -> extract fs
@@ -1777,15 +1576,14 @@ extractM (Fold _ initial extract _) = do
1777-- | Close a fold so that it does not accept any more input.
1576-- | Close a fold so that it does not accept any more input.
1778{-# INLINE close #-}
1577{-# INLINE close #-}
1779close :: Monad m => Fold m a b -> Fold m a b
1578close :: Monad m => Fold m a b -> Fold m a b
1780−close (Fold _ initial1 _ final1) =
1781− Fold undefined initial undefined undefined
1579+close (Fold _ initial1 extract1) = Fold undefined initial undefined
1782
1580
1783 where
1581 where
1784
1582
1785 initial = do
1583 initial = do
1786 res <- initial1
1584 res <- initial1
1787 case res of
1585 case res of
1788− Partial s -> Done <$> final1 s
1586+ Partial s -> Done <$> extract1 s
1789 Done b -> return $ Done b
1587 Done b -> return $ Done b
1790
1588
1791-- Corresponds to the null check for streams.
1589-- Corresponds to the null check for streams.
@@ -1795,7 +1593,7 @@ close (Fold _ initial1 _ final1) =
1795-- /Pre-release/
1593-- /Pre-release/
1796{-# INLINE isClosed #-}
1594{-# INLINE isClosed #-}
1797isClosed :: Monad m => Fold m a b -> m Bool
1595isClosed :: Monad m => Fold m a b -> m Bool
1798−isClosed (Fold _ initial _ _) = do
1596+isClosed (Fold _ initial _) = do
1799 res <- initial
1597 res <- initial
1800 return $ case res of
1598 return $ case res of
1801 Partial _ -> False
1599 Partial _ -> False
@@ -1829,10 +1627,8 @@ data ManyState s1 s2
1829--
1627--
1830{-# INLINE many #-}
1628{-# INLINE many #-}
1831many :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1629many :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1832−many
1833− (Fold sstep sinitial sextract sfinal)
1630+many (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1834− (Fold cstep cinitial cextract cfinal) =
1835− Fold step initial extract final
1631+ Fold step initial extract
1836
1632
1837 where
1633 where
1838
1634
@@ -1881,13 +1677,6 @@ many
1881 Partial s -> cextract s
1677 Partial s -> cextract s
1882 Done b -> return b
1678 Done b -> return b
1883
1679
1884− final (ManyFirst ss cs) = sfinal ss *> cfinal cs
1885− final (ManyLoop ss cs) = do
1886− cres <- sfinal ss >>= cstep cs
1887− case cres of
1888− Partial s -> cfinal s
1889− Done b -> return b
1890−
1891-- | Like many, but the "first" fold emits an output at the end even if no
1680-- | Like many, but the "first" fold emits an output at the end even if no
1892-- input is received.
1681-- input is received.
1893--
1682--
@@ -1897,10 +1686,8 @@ many
1897--
1686--
1898{-# INLINE manyPost #-}
1687{-# INLINE manyPost #-}
1899manyPost :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1688manyPost :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1900−manyPost
1901− (Fold sstep sinitial sextract sfinal)
1689+manyPost (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1902− (Fold cstep cinitial cextract cfinal) =
1903− Fold step initial extract final
1690+ Fold step initial extract
1904
1691
1905 where
1692 where
1906
1693
@@ -1936,12 +1723,6 @@ manyPost
1936 Partial s -> cextract s
1723 Partial s -> cextract s
1937 Done b -> return b
1724 Done b -> return b
1938
1725
1939− final (Tuple' ss cs) = do
1940− cres <- sfinal ss >>= cstep cs
1941− case cres of
1942− Partial s -> cfinal s
1943− Done b -> return b
1944−
1945-- | @groupsOf n split collect@ repeatedly applies the @split@ fold to chunks
1726-- | @groupsOf n split collect@ repeatedly applies the @split@ fold to chunks
1946-- of @n@ items in the input stream and supplies the result to the @collect@
1727-- of @n@ items in the input stream and supplies the result to the @collect@
1947-- fold.
1728-- fold.
@@ -1970,10 +1751,7 @@ groupsOf n split = many (take n split)
1970--
1751--
1971{-# INLINE refoldMany #-}
1752{-# INLINE refoldMany #-}
1972refoldMany :: Monad m => Fold m a b -> Refold m x b c -> Refold m x a c
1753refoldMany :: Monad m => Fold m a b -> Refold m x b c -> Refold m x a c
1973−refoldMany
1974− (Fold sstep sinitial sextract _sfinal)
1975− -- XXX We will need a "final" in refold as well
1976− (Refold cstep cinject cextract) =
1754+refoldMany (Fold sstep sinitial sextract) (Refold cstep cinject cextract) =
1977 Refold step inject extract
1755 Refold step inject extract
1978
1756
1979 where
1757 where
@@ -2024,9 +1802,7 @@ data ConsumeManyState x cs ss = ConsumeMany x cs (Either ss ss)
2024-- /Internal/
1802-- /Internal/
2025{-# INLINE refoldMany1 #-}
1803{-# INLINE refoldMany1 #-}
2026refoldMany1 :: Monad m => Refold m x a b -> Fold m b c -> Refold m x a c
1804refoldMany1 :: Monad m => Refold m x a b -> Fold m b c -> Refold m x a c
2027−refoldMany1
2028− (Refold sstep sinject sextract)
1805+refoldMany1 (Refold sstep sinject sextract) (Fold cstep cinitial cextract) =
2029− (Fold cstep cinitial cextract _cfinal) =
2030 Refold step inject extract
1806 Refold step inject extract
2031
1807
2032 where
1808 where
@@ -2077,7 +1853,7 @@ refoldMany1
2077{-# INLINE refold #-}
1853{-# INLINE refold #-}
2078refold :: Monad m => Refold m b a c -> Fold m a b -> Fold m a c
1854refold :: Monad m => Refold m b a c -> Fold m a b -> Fold m a c
2079refold (Refold step inject extract) f =
1855refold (Refold step inject extract) f =
2080− Fold step (extractM f >>= inject) extract extract
1856+ Fold step (extractM f >>= inject) extract
2081
1857
2082------------------------------------------------------------------------------
1858------------------------------------------------------------------------------
2083-- morphInner
1859-- morphInner
@@ -2087,8 +1863,8 @@ refold (Refold step inject extract) f =
2087--
1863--
2088-- /Pre-release/
1864-- /Pre-release/
2089morphInner :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
1865morphInner :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
2090−morphInner f (Fold step initial extract final) =
1866+morphInner f (Fold step initial extract) =
2091− Fold (\x a -> f $ step x a) (f initial) (f . extract) (f . final)
1867+ Fold (\x a -> f $ step x a) (f initial) (f . extract)
2092
1868
2093-- | Adapt a pure fold to any monad.
1869-- | Adapt a pure fold to any monad.
2094--
1870--
core/src/Streamly/Internal/Data/Fold/Window.hs+4−10
@@ -65,8 +65,6 @@ import Streamly.Internal.Data.Fold.Type (Fold(..), Step(..))
65import Streamly.Internal.Data.Tuple.Strict
65import Streamly.Internal.Data.Tuple.Strict
66 (Tuple'(..), Tuple3Fused' (Tuple3Fused'))
66 (Tuple'(..), Tuple3Fused' (Tuple3Fused'))
67
67
68−import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
69−
70import qualified Streamly.Internal.Data.Fold.Type as Fold
68import qualified Streamly.Internal.Data.Fold.Type as Fold
71import qualified Streamly.Internal.Data.Ring as Ring
69import qualified Streamly.Internal.Data.Ring as Ring
72
70
@@ -150,7 +148,7 @@ windowRollingMap f = Fold.foldl' f1 initial
150--
148--
151{-# INLINE windowSumInt #-}
149{-# INLINE windowSumInt #-}
152windowSumInt :: forall m a. (Monad m, Integral a) => Fold m (a, Maybe a) a
150windowSumInt :: forall m a. (Monad m, Integral a) => Fold m (a, Maybe a) a
153−windowSumInt = Fold step initial extract extract
151+windowSumInt = Fold step initial extract
154
152
155 where
153 where
156
154
@@ -184,7 +182,7 @@ windowSumInt = Fold step initial extract extract
184--
182--
185{-# INLINE windowSum #-}
183{-# INLINE windowSum #-}
186windowSum :: forall m a. (Monad m, Num a) => Fold m (a, Maybe a) a
184windowSum :: forall m a. (Monad m, Num a) => Fold m (a, Maybe a) a
187−windowSum = Fold step initial extract extract
185+windowSum = Fold step initial extract
188
186
189 where
187 where
190
188
@@ -269,7 +267,7 @@ windowPowerSumFrac p = windowLmap (** p) windowSum
269--
267--
270{-# INLINE windowRange #-}
268{-# INLINE windowRange #-}
271windowRange :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe (a, a))
269windowRange :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe (a, a))
272−windowRange n = Fold step initial extract extract
270+windowRange n = Fold step initial extract
273
271
274 where
272 where
275
273
@@ -302,11 +300,7 @@ windowRange n = Fold step initial extract extract
302 if i == 0
300 if i == 0
303 then return Nothing
301 then return Nothing
304 else do
302 else do
305− -- Here we use "ringStart" over "ringHead" as "ringHead" will be
303+ x <- liftIO $ peek rh
306− -- uninitialized if the ring is not full.
307− -- Using "unsafeForeignPtrToPtr" here is safe as we touch the ring
308− -- again in "foldFunc".
309− x <- liftIO $ peek (unsafeForeignPtrToPtr (Ring.ringStart rb))
310 let accum (mn, mx) a = return (min mn a, max mx a)
304 let accum (mn, mx) a = return (min mn a, max mx a)
311 fmap Just $ foldFunc i rh accum (x, x) rb
305 fmap Just $ foldFunc i rh accum (x, x) rb
312
306
core/src/Streamly/Internal/Data/IORef/Unboxed.hs+19−22
@@ -23,31 +23,34 @@ module Streamly.Internal.Data.IORef.Unboxed
23 (
23 (
24 IORef
24 IORef
25
25
26− -- Construction
26+ -- * Construction
27 , newIORef
27 , newIORef
28
28
29− -- Write
29+ -- * Write
30 , writeIORef
30 , writeIORef
31 , modifyIORef'
31 , modifyIORef'
32
32
33− -- Read
33+ -- * Read
34 , readIORef
34 , readIORef
35− , pollIntIORef
35+ , toStreamD
36 )
36 )
37where
37where
38
38
39#include "inline.hs"
39#include "inline.hs"
40
40
41−import Control.Monad.IO.Class (MonadIO(..))
42import Data.Proxy (Proxy(..))
41import Data.Proxy (Proxy(..))
43−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
42+import Control.Monad.IO.Class (MonadIO(..))
44−import Streamly.Internal.Data.Unbox (Unbox(..), sizeOf)
43+import Streamly.Internal.Data.Unbox
44+ ( MutableByteArray(..)
45+ , Unbox(..)
46+ , newBytes
47+ , sizeOf
48+ )
45
49
46−import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
47import qualified Streamly.Internal.Data.Stream.Type as D
50import qualified Streamly.Internal.Data.Stream.Type as D
48
51
49-- | An 'IORef' holds a single 'Unbox'-able value.
52-- | An 'IORef' holds a single 'Unbox'-able value.
50−newtype IORef a = IORef MutByteArray
53+newtype IORef a = IORef MutableByteArray
51
54
52-- | Create a new 'IORef'.
55-- | Create a new 'IORef'.
53--
56--
@@ -55,8 +58,8 @@ newtype IORef a = IORef MutByteArray
55{-# INLINE newIORef #-}
58{-# INLINE newIORef #-}
56newIORef :: forall a. Unbox a => a -> IO (IORef a)
59newIORef :: forall a. Unbox a => a -> IO (IORef a)
57newIORef x = do
60newIORef x = do
58− var <- MBA.new (sizeOf (Proxy :: Proxy a))
61+ var <- newBytes (sizeOf (Proxy :: Proxy a))
59− pokeAt 0 var x
62+ pokeByteIndex 0 var x
60 return $ IORef var
63 return $ IORef var
61
64
62-- | Write a value to an 'IORef'.
65-- | Write a value to an 'IORef'.
@@ -64,14 +67,14 @@ newIORef x = do
64-- /Pre-release/
67-- /Pre-release/
65{-# INLINE writeIORef #-}
68{-# INLINE writeIORef #-}
66writeIORef :: Unbox a => IORef a -> a -> IO ()
69writeIORef :: Unbox a => IORef a -> a -> IO ()
67−writeIORef (IORef var) = pokeAt 0 var
70+writeIORef (IORef var) = pokeByteIndex 0 var
68
71
69-- | Read a value from an 'IORef'.
72-- | Read a value from an 'IORef'.
70--
73--
71-- /Pre-release/
74-- /Pre-release/
72{-# INLINE readIORef #-}
75{-# INLINE readIORef #-}
73readIORef :: Unbox a => IORef a -> IO a
76readIORef :: Unbox a => IORef a -> IO a
74−readIORef (IORef var) = peekAt 0 var
77+readIORef (IORef var) = peekByteIndex 0 var
75
78
76-- | Modify the value of an 'IORef' using a function with strict application.
79-- | Modify the value of an 'IORef' using a function with strict application.
77--
80--
@@ -84,16 +87,10 @@ modifyIORef' var g = do
84
87
85-- | Generate a stream by continuously reading the IORef.
88-- | Generate a stream by continuously reading the IORef.
86--
89--
87−-- This operation reads the IORef without any synchronization. It can be
88−-- assumed to be atomic because the IORef (MutableByteArray) is always aligned
89−-- to Int boundaries, we are assuming that compiler uses single instructions to
90−-- access the memory. It may read stale values though until caches are
91−-- synchronised in a multiprocessor architecture.
92−--
93-- /Pre-release/
90-- /Pre-release/
94−{-# INLINE_NORMAL pollIntIORef #-}
91+{-# INLINE_NORMAL toStreamD #-}
95−pollIntIORef :: (MonadIO m, Unbox a) => IORef a -> D.Stream m a
92+toStreamD :: (MonadIO m, Unbox a) => IORef a -> D.Stream m a
96−pollIntIORef var = D.Stream step ()
93+toStreamD var = D.Stream step ()
97
94
98 where
95 where
99
96
core/src/Streamly/Internal/Data/IsMap.hs−8
@@ -1,7 +1,3 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- Must come after TypeFamilies, otherwise it is re-enabled.
3−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4−{-# LANGUAGE NoMonoLocalBinds #-}
5-- |
1-- |
6-- Module : Streamly.Internal.Data.IsMap
2-- Module : Streamly.Internal.Data.IsMap
7-- Copyright : (c) 2022 Composewell Technologies
3-- Copyright : (c) 2022 Composewell Technologies
@@ -32,8 +28,6 @@ class IsMap f where
32 mapDelete :: Key f -> f a -> f a
28 mapDelete :: Key f -> f a -> f a
33 mapUnion :: f a -> f a -> f a
29 mapUnion :: f a -> f a -> f a
34 mapNull :: f a -> Bool
30 mapNull :: f a -> Bool
35− mapTraverseWithKey ::
36− Applicative t => (Key f -> a -> t b) -> f a -> t (f b)
37
31
38instance Ord k => IsMap (Map k) where
32instance Ord k => IsMap (Map k) where
39 type Key (Map k) = k
33 type Key (Map k) = k
@@ -45,7 +39,6 @@ instance Ord k => IsMap (Map k) where
45 mapDelete = Map.delete
39 mapDelete = Map.delete
46 mapUnion = Map.union
40 mapUnion = Map.union
47 mapNull = Map.null
41 mapNull = Map.null
48− mapTraverseWithKey = Map.traverseWithKey
49
42
50instance IsMap IntMap.IntMap where
43instance IsMap IntMap.IntMap where
51 type Key IntMap.IntMap = Int
44 type Key IntMap.IntMap = Int
@@ -57,4 +50,3 @@ instance IsMap IntMap.IntMap where
57 mapDelete = IntMap.delete
50 mapDelete = IntMap.delete
58 mapUnion = IntMap.union
51 mapUnion = IntMap.union
59 mapNull = IntMap.null
52 mapNull = IntMap.null
60− mapTraverseWithKey = IntMap.traverseWithKey
core/src/Streamly/Internal/Data/MutArray.hs+33−154
@@ -8,200 +8,79 @@
8--
8--
9module Streamly.Internal.Data.MutArray
9module Streamly.Internal.Data.MutArray
10 (
10 (
11− -- * MutArray.Type module
12 module Streamly.Internal.Data.MutArray.Type
11 module Streamly.Internal.Data.MutArray.Type
13− -- * MutArray module
12+ , splitOn
14− , sliceIndexerFromLen
15− , slicerFromLen
16− , compactLE
17− , pinnedCompactLE
18− , compactOnByte
19− , compactOnByteSuffix
20− -- * Unboxed IORef
21− , module Streamly.Internal.Data.IORef.Unboxed
22−
23− -- * Deprecated
24 , genSlicesFromLen
13 , genSlicesFromLen
25 , getSlicesFromLen
14 , getSlicesFromLen
15+ , fromStream
26 )
16 )
27where
17where
28
18
29#include "inline.hs"
19#include "inline.hs"
30
20
31import Control.Monad.IO.Class (MonadIO(..))
21import 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)
35import Streamly.Internal.Data.Unbox (Unbox)
22import Streamly.Internal.Data.Unbox (Unbox)
23+import Streamly.Internal.Data.Stream (Stream)
36import Streamly.Internal.Data.Unfold.Type (Unfold(..))
24import Streamly.Internal.Data.Unfold.Type (Unfold(..))
37
25
38−import qualified Streamly.Internal.Data.Stream.Type as Stream
26+import qualified Streamly.Internal.Data.Stream as D
39−import qualified Streamly.Internal.Data.Stream.Nesting as Stream
40−-- import qualified Streamly.Internal.Data.Stream.Transform as Stream
41import qualified Streamly.Internal.Data.Unfold as Unfold
27import qualified Streamly.Internal.Data.Unfold as Unfold
42
28
43import Prelude hiding (foldr, length, read, splitAt)
29import Prelude hiding (foldr, length, read, splitAt)
44import Streamly.Internal.Data.MutArray.Type
30import Streamly.Internal.Data.MutArray.Type
45−import Streamly.Internal.Data.IORef.Unboxed
31+
32+-- | Split the array into a stream of slices using a predicate. The element
33+-- matching the predicate is dropped.
34+--
35+-- /Pre-release/
36+{-# INLINE splitOn #-}
37+splitOn :: (MonadIO m, Unbox a) =>
38+ (a -> Bool) -> MutArray a -> Stream m (MutArray a)
39+splitOn predicate arr =
40+ fmap (\(i, len) -> getSliceUnsafe i len arr)
41+ $ D.sliceOnSuffix predicate (read arr)
46
42
47-- | Generate a stream of array slice descriptors ((index, len)) of specified
43-- | Generate a stream of array slice descriptors ((index, len)) of specified
48-- length from an array, starting from the supplied array index. The last slice
44-- length from an array, starting from the supplied array index. The last slice
49-- may be shorter than the requested length depending on the array length.
45-- may be shorter than the requested length depending on the array length.
50--
46--
51-- /Pre-release/
47-- /Pre-release/
52−{-# INLINE sliceIndexerFromLen #-}
48+{-# INLINE genSlicesFromLen #-}
53−sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
49+genSlicesFromLen :: forall m a. (Monad m, Unbox a)
54 => Int -- ^ from index
50 => Int -- ^ from index
55 -> Int -- ^ length of the slice
51 -> Int -- ^ length of the slice
56 -> Unfold m (MutArray a) (Int, Int)
52 -> Unfold m (MutArray a) (Int, Int)
57−sliceIndexerFromLen from len =
53+genSlicesFromLen from len =
58 let fromThenTo n = (from, from + len, n - 1)
54 let fromThenTo n = (from, from + len, n - 1)
59 mkSlice n i = return (i, min len (n - i))
55 mkSlice n i = return (i, min len (n - i))
60 in Unfold.lmap length
56 in Unfold.lmap length
61 $ Unfold.mapM2 mkSlice
57 $ Unfold.mapM2 mkSlice
62 $ Unfold.lmap fromThenTo Unfold.enumerateFromThenTo
58 $ Unfold.lmap fromThenTo Unfold.enumerateFromThenTo
63
59
64−{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
65−genSlicesFromLen :: forall m a. (Monad m, Unbox a)
66− => Int -- ^ from index
67− -> Int -- ^ length of the slice
68− -> Unfold m (MutArray a) (Int, Int)
69−genSlicesFromLen = sliceIndexerFromLen
70−
71-- | Generate a stream of slices of specified length from an array, starting
60-- | Generate a stream of slices of specified length from an array, starting
72-- from the supplied array index. The last slice may be shorter than the
61-- from the supplied array index. The last slice may be shorter than the
73-- requested length depending on the array length.
62-- requested length depending on the array length.
74--
63--
75-- /Pre-release/
64-- /Pre-release/
76−{-# INLINE slicerFromLen #-}
77−slicerFromLen :: forall m a. (Monad m, Unbox a)
78− => Int -- ^ from index
79− -> Int -- ^ length of the slice
80− -> Unfold m (MutArray a) (MutArray a)
81−slicerFromLen from len =
82− let mkSlice arr (i, n) = return $ getSliceUnsafe i n arr
83− in Unfold.mapM2 mkSlice (sliceIndexerFromLen from len)
84−
85−{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
65+{-# INLINE getSlicesFromLen #-}
86getSlicesFromLen :: forall m a. (Monad m, Unbox a)
66getSlicesFromLen :: forall m a. (Monad m, Unbox a)
87 => Int -- ^ from index
67 => Int -- ^ from index
88 -> Int -- ^ length of the slice
68 -> Int -- ^ length of the slice
89 -> Unfold m (MutArray a) (MutArray a)
69 -> Unfold m (MutArray a) (MutArray a)
90−getSlicesFromLen = slicerFromLen
70+getSlicesFromLen from len =
91−
71+ let mkSlice arr (i, n) = return $ getSliceUnsafe i n arr
92−-------------------------------------------------------------------------------
72+ in Unfold.mapM2 mkSlice (genSlicesFromLen from len)
93−-- Compacting Streams of Arrays
94−-------------------------------------------------------------------------------
95
73
96−-- | @compactLE maxElems@ coalesces adjacent arrays in the input stream
74+-- | Create an 'Array' from a stream. This is useful when we want to create a
97−-- only if the combined size would be less than or equal to @maxElems@
75+-- single array from a stream of unknown size. 'writeN' is at least twice
98−-- elements. Note that it won't split an array if the original array is already
76+-- as efficient when the size is already known.
99−-- larger than maxElems.
100−--
101−-- @maxElems@ must be greater than 0.
102--
77--
103−-- Generates unpinned arrays irrespective of the pinning status of input
78+-- Note that if the input stream is too large memory allocation for the array
104−-- arrays.
79+-- may fail. When the stream size is not known, `chunksOf` followed by
105−{-# INLINE compactLE #-}
80+-- processing of indvidual arrays in the resulting stream should be preferred.
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--
81--
131−{-# INLINE_NORMAL _compactOnByteCustom #-}
82+-- /Pre-release/
132−_compactOnByteCustom
83+{-# INLINE fromStream #-}
133− :: MonadIO m
84+fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
134− => Word8
85+fromStream = fromStreamD
135− -> Stream m (MutArray Word8)
86+-- fromStream (Stream m) = P.fold write m
136− -> Stream m (MutArray Word8)
137−_compactOnByteCustom byte (Stream.Stream step state) =
138− Stream.Stream step' (Initial state)
139−
140− where
141−
142− {-# INLINE_LATE step' #-}
143− step' gst (Initial st) = do
144− r <- step gst st
145− case r of
146− Stream.Yield arr s -> do
147− (arr1, marr2) <- breakOn byte arr
148− return $ case marr2 of
149− Nothing -> Stream.Skip (Buffering s arr1)
150− Just arr2 -> Stream.Skip (Yielding arr1 (Splitting s arr2))
151− Stream.Skip s -> return $ Stream.Skip (Initial s)
152− Stream.Stop -> return Stream.Stop
153−
154− step' gst (Buffering st buf) = do
155− r <- step gst st
156− case r of
157− Stream.Yield arr s -> do
158− (arr1, marr2) <- breakOn byte arr
159− -- XXX Use spliceExp instead and then rightSize?
160− buf1 <- splice buf arr1
161− return $ case marr2 of
162− Nothing -> Stream.Skip (Buffering s buf1)
163− Just x -> Stream.Skip (Yielding buf1 (Splitting s x))
164− Stream.Skip s -> return $ Stream.Skip (Buffering s buf)
165− Stream.Stop -> return $
166− if byteLength buf == 0
167− then Stream.Stop
168− else Stream.Skip (Yielding buf Finishing)
169−
170− step' _ (Splitting st buf) = do
171− (arr1, marr2) <- breakOn byte buf
172− return $ case marr2 of
173− Nothing -> Stream.Skip $ Buffering st arr1
174− Just arr2 -> Stream.Skip $ Yielding arr1 (Splitting st arr2)
175−
176− step' _ (Yielding arr next) = return $ Stream.Yield arr next
177− step' _ Finishing = return Stream.Stop
178−
179−-- XXX implement predicate based version of this
180−-- XXX Naming of predicate based vs custom version
181−
182−-- | Split a stream of arrays on a given separator byte, dropping the separator
183−-- and coalescing all the arrays between two separators into a single array.
184−--
185−{-# INLINE compactOnByte #-}
186−compactOnByte
187− :: (MonadIO m)
188− => Word8
189− -> Stream m (MutArray Word8)
190− -> Stream m (MutArray Word8)
191−-- XXX compare perf of custom vs idiomatic version
192−-- compactOnByte = _compactOnByteCustom
193−-- XXX use spliceExp and rightSize?
194−compactOnByte byte = Stream.splitInnerBy (breakOn byte) splice
195−
196−-- | Like 'compactOnByte' considers the separator in suffix position instead of
197−-- infix position.
198−{-# INLINE compactOnByteSuffix #-}
199−compactOnByteSuffix
200− :: (MonadIO m)
201− => Word8
202− -> Stream m (MutArray Word8)
203− -> Stream m (MutArray Word8)
204−compactOnByteSuffix byte =
205− -- XXX use spliceExp and rightSize?
206− Stream.splitInnerBySuffix
207− (\arr -> byteLength arr == 0) (breakOn byte) splice
core/src/Streamly/Internal/Data/MutArray/Generic.hs+30−65
@@ -19,14 +19,14 @@ module Streamly.Internal.Data.MutArray.Generic
19 , nil
19 , nil
20
20
21 -- *** Uninitialized Arrays
21 -- *** Uninitialized Arrays
22− , emptyOf
22+ , new
23 -- , newArrayWith
23 -- , newArrayWith
24
24
25 -- *** From streams
25 -- *** From streams
26− , unsafeCreateOf
26+ , writeNUnsafe
27− , createOf
27+ , writeN
28− , createWith -- createOfMin/createMin/createGE?
28+ , writeWith
29− , create
29+ , write
30 , fromStreamN
30 , fromStreamN
31 , fromStream
31 , fromStream
32 , fromPureStream
32 , fromPureStream
@@ -160,13 +160,6 @@ 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
170 )
163 )
171where
164where
172
165
@@ -243,13 +236,13 @@ bottomElement =
243-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
236-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
244-- that we do not have to write undefined or error in the whole array.
237-- that we do not have to write undefined or error in the whole array.
245
238
246−-- | @emptyOf count@ allocates a zero length array that can be extended to hold
239+-- | @new count@ allocates a zero length array that can be extended to hold
247-- up to 'count' items without reallocating.
240-- up to 'count' items without reallocating.
248--
241--
249-- /Pre-release/
242-- /Pre-release/
250−{-# INLINE emptyOf #-}
243+{-# INLINE new #-}
251−emptyOf :: MonadIO m => Int -> m (MutArray a)
244+new :: MonadIO m => Int -> m (MutArray a)
252−emptyOf n@(I# n#) =
245+new n@(I# n#) =
253 liftIO
246 liftIO
254 $ IO
247 $ IO
255 $ \s# ->
248 $ \s# ->
@@ -258,12 +251,6 @@ emptyOf n@(I# n#) =
258 let ma = MutArray arr# 0 0 n
251 let ma = MutArray arr# 0 0 n
259 in (# s1#, ma #)
252 in (# s1#, ma #)
260
253
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−
267-- XXX This could be pure?
254-- XXX This could be pure?
268
255
269-- |
256-- |
@@ -331,7 +318,7 @@ putIndices arr = FL.foldlM' step (return ())
331
318
332 where
319 where
333
320
334− step () (i, x) = putIndex i arr x
321+ step () (i, x) = liftIO (putIndex i arr x)
335
322
336-- | Modify a given index of an array using a modifier function without checking
323-- | Modify a given index of an array using a modifier function without checking
337-- the bounds.
324-- the bounds.
@@ -602,16 +589,16 @@ readRev arr@MutArray{..} =
602arrayChunkSize :: Int
589arrayChunkSize :: Int
603arrayChunkSize = 1024
590arrayChunkSize = 1024
604
591
605−-- | Like 'createOf' but does not check the array bounds when writing. The fold
592+-- | Like 'writeN' but does not check the array bounds when writing. The fold
606-- driver must not call the step function more than 'n' times otherwise it will
593-- driver must not call the step function more than 'n' times otherwise it will
607-- corrupt the memory and crash. This function exists mainly because any
594-- corrupt the memory and crash. This function exists mainly because any
608-- conditional in the step function blocks fusion causing 10x performance
595-- conditional in the step function blocks fusion causing 10x performance
609-- slowdown.
596-- slowdown.
610--
597--
611-- /Pre-release/
598-- /Pre-release/
612−{-# INLINE_NORMAL unsafeCreateOf #-}
599+{-# INLINE_NORMAL writeNUnsafe #-}
613−unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
600+writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
614−unsafeCreateOf n = Fold step initial return return
601+writeNUnsafe n = Fold step initial return
615
602
616 where
603 where
617
604
@@ -619,81 +606,59 @@ unsafeCreateOf n = Fold step initial return return
619
606
620 step arr x = FL.Partial <$> snocUnsafe arr x
607 step arr x = FL.Partial <$> snocUnsafe arr x
621
608
622−{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
623−{-# INLINE writeNUnsafe #-}
624−writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
625−writeNUnsafe = unsafeCreateOf
626−
627−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
609+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
628-- 'Array'.
610-- 'Array'.
629--
611--
630−-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
612+-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
631--
613--
632-- /Pre-release/
614-- /Pre-release/
633−{-# INLINE_NORMAL createOf #-}
615+{-# INLINE_NORMAL writeN #-}
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 #-}
640writeN :: MonadIO m => Int -> Fold m a (MutArray a)
616writeN :: MonadIO m => Int -> Fold m a (MutArray a)
641−writeN = createOf
617+writeN n = FL.take n $ writeNUnsafe n
642
618
643-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
619-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
644-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
620-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
645-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
621-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
646
622
647−-- | @createWith minCount@ folds the whole input to a single array. The array
623+-- | @writeWith minCount@ folds the whole input to a single array. The array
648-- starts at a size big enough to hold minCount elements, the size is doubled
624-- starts at a size big enough to hold minCount elements, the size is doubled
649-- every time the array needs to be grown.
625-- every time the array needs to be grown.
650--
626--
651-- /Caution! Do not use this on infinite streams./
627-- /Caution! Do not use this on infinite streams./
652--
628--
653-- /Pre-release/
629-- /Pre-release/
654−{-# INLINE_NORMAL createWith #-}
630+{-# INLINE_NORMAL writeWith #-}
655−createWith :: MonadIO m => Int -> Fold m a (MutArray a)
631+writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
656-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
632-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
657−createWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
633+writeWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
658
634
659 where
635 where
660
636
661 initial = do
637 initial = do
662− when (elemCount < 0) $ error "createWith: elemCount is negative"
638+ when (elemCount < 0) $ error "writeWith: elemCount is negative"
663− new elemCount
639+ liftIO $ new elemCount
664
640
665 step arr@(MutArray _ start end bound) x
641 step arr@(MutArray _ start end bound) x
666 | end == bound = do
642 | end == bound = do
667 let oldSize = end - start
643 let oldSize = end - start
668 newSize = max (oldSize * 2) 1
644 newSize = max (oldSize * 2) 1
669− arr1 <- realloc newSize arr
645+ arr1 <- liftIO $ realloc newSize arr
670 snocUnsafe arr1 x
646 snocUnsafe arr1 x
671 step arr x = snocUnsafe arr x
647 step arr x = snocUnsafe arr x
672
648
673− -- extract = rightSize
649+ -- extract = liftIO . rightSize
674 extract = return
650 extract = return
675
651
676−{-# DEPRECATED writeWith "Please use createWith instead." #-}
677−{-# INLINE writeWith #-}
678−writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
679−writeWith = createWith
680−
681-- | Fold the whole input to a single array.
652-- | Fold the whole input to a single array.
682--
653--
683−-- Same as 'createWith' using an initial array size of 'arrayChunkSize' bytes
654+-- Same as 'writeWith' using an initial array size of 'arrayChunkSize' bytes
684-- rounded up to the element size.
655-- rounded up to the element size.
685--
656--
686-- /Caution! Do not use this on infinite streams./
657-- /Caution! Do not use this on infinite streams./
687--
658--
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." #-}
694{-# INLINE write #-}
659{-# INLINE write #-}
695write :: MonadIO m => Fold m a (MutArray a)
660write :: MonadIO m => Fold m a (MutArray a)
696−write = create
661+write = writeWith arrayChunkSize
697
662
698-- | Create a 'MutArray' from the first @n@ elements of a stream. The
663-- | Create a 'MutArray' from the first @n@ elements of a stream. The
699-- array is allocated to size @n@, if the stream terminates before @n@
664-- array is allocated to size @n@, if the stream terminates before @n@
@@ -718,7 +683,7 @@ fromList xs = fromStream $ D.fromList xs
718{-# INLINABLE fromPureStream #-}
683{-# INLINABLE fromPureStream #-}
719fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
684fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
720fromPureStream xs =
685fromPureStream xs =
721− D.fold write $ D.morphInner (return . runIdentity) xs
686+ liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
722
687
723-------------------------------------------------------------------------------
688-------------------------------------------------------------------------------
724-- Chunking
689-- Chunking
@@ -850,7 +815,7 @@ putSliceUnsafe src srcStart dst dstStart len = liftIO $ do
850
815
851{-# INLINE clone #-}
816{-# INLINE clone #-}
852clone :: MonadIO m => MutArray a -> m (MutArray a)
817clone :: MonadIO m => MutArray a -> m (MutArray a)
853−clone src = do
818+clone src = liftIO $ do
854 let len = arrLen src
819 let len = arrLen src
855 dst <- new len
820 dst <- new len
856 putSliceUnsafe src 0 dst 0 len
821 putSliceUnsafe src 0 dst 0 len
core/src/Streamly/Internal/Data/MutArray/Stream.hsdeleted−145
@@ -1,145 +0,0 @@
1−-- |
2−-- Module : Streamly.Internal.Data.MutArray.Stream
3−-- Copyright : (c) 2019 Composewell Technologies
4−-- License : BSD3-3-Clause
5−-- Maintainer : streamly@composewell.com
6−-- Stability : experimental
7−-- Portability : GHC
8−--
9−-- Combinators to efficiently manipulate streams of mutable arrays.
10−--
11−-- We can either push these in the MutArray module with a "chunks" prefix or
12−-- keep this as a separate module and release it.
13−--
14−module Streamly.Internal.Data.MutArray.Stream
15−{-# DEPRECATED "Please use \"Streamly.Internal.Data.MutArray\" instead." #-}
16− (
17− -- * Generation
18− MArray.chunksOf
19− , MArray.pinnedChunksOf
20− , MArray.writeChunks -- chunksWrite?
21− , MArray.splitOn -- chunksSplitOn
22−
23− -- * Compaction
24− , packArraysChunksOf
25− , MArray.SpliceState (..)
26− , lpackArraysChunksOf
27− , compact -- chunksCompact
28− , compactLE
29− , compactEQ
30− , compactGE
31−
32− -- * Elimination
33− , MArray.flattenArrays -- chunksConcat
34− , MArray.flattenArraysRev -- chunksConcatRev
35− , MArray.fromArrayStreamK -- chunksCoalesce
36− )
37−where
38−
39−import Control.Monad.IO.Class (MonadIO(..))
40−import Streamly.Internal.Data.Unbox (Unbox)
41−import Streamly.Internal.Data.MutArray.Type (MutArray(..))
42−import Streamly.Internal.Data.Fold.Type (Fold(..))
43−import Streamly.Internal.Data.Parser (ParseError)
44−import Streamly.Internal.Data.Stream.Type (Stream)
45−
46−import qualified Streamly.Internal.Data.MutArray as MArray
47−import qualified Streamly.Internal.Data.Fold.Type as FL
48−import qualified Streamly.Internal.Data.Parser as ParserD
49−import qualified Streamly.Internal.Data.Stream as D
50−
51−-------------------------------------------------------------------------------
52−-- Compact
53−-------------------------------------------------------------------------------
54−
55−-- XXX This can be removed once compactLEFold/compactLE are implemented.
56−--
57−-- | This mutates the first array (if it has space) to append values from the
58−-- second one. This would work for immutable arrays as well because an
59−-- immutable array never has space so a new array is allocated instead of
60−-- mutating it.
61−--
62−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
63−-- maximum specified size. Note that if a single array is bigger than the
64−-- specified size we do not split it to fit. When we coalesce multiple arrays
65−-- if the size would exceed the specified size we do not coalesce therefore the
66−-- actual array size may be less than the specified chunk size.
67−--
68−-- @since 0.7.0
69−{-# INLINE packArraysChunksOf #-}
70−packArraysChunksOf :: (MonadIO m, Unbox a)
71− => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
72−packArraysChunksOf = MArray.compactLE
73−
74−-- XXX Remove this once compactLEFold is implemented
75−-- lpackArraysChunksOf = Fold.many compactLEFold
76−--
77−{-# INLINE lpackArraysChunksOf #-}
78−lpackArraysChunksOf :: (MonadIO m, Unbox a)
79− => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
80−lpackArraysChunksOf = MArray.lCompactGE
81−
82−-- XXX Same as compactLE, to be removed once that is implemented.
83−--
84−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
85−-- maximum specified size in bytes.
86−--
87−-- /Internal/
88−{-# INLINE compact #-}
89−compact :: (MonadIO m, Unbox a)
90− => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
91−compact = packArraysChunksOf
92−
93−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
94−-- maximum specified size. Note that if a single array is bigger than the
95−-- specified size we do not split it to fit. When we coalesce multiple arrays
96−-- if the size would exceed the specified size we do not coalesce therefore the
97−-- actual array size may be less than the specified chunk size.
98−--
99−-- /Internal/
100−{-# INLINE compactLEParserD #-}
101−compactLEParserD ::
102− forall m a. (MonadIO m, Unbox a)
103− => Int -> ParserD.Parser (MutArray a) m (MutArray a)
104−compactLEParserD = MArray.pCompactLE
105−
106−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
107−-- minimum specified size. Note that if all the arrays in the stream together
108−-- are smaller than the specified size the resulting array will be smaller than
109−-- the specified size. When we coalesce multiple arrays if the size would exceed
110−-- the specified size we stop coalescing further.
111−--
112−-- /Internal/
113−{-# INLINE compactGEFold #-}
114−compactGEFold ::
115− forall m a. (MonadIO m, Unbox a)
116− => Int -> FL.Fold m (MutArray a) (MutArray a)
117−compactGEFold = MArray.fCompactGE
118−
119−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
120−-- maximum specified size in bytes.
121−--
122−-- /Internal/
123−compactLE :: (MonadIO m, Unbox a) =>
124− Int -> Stream m (MutArray a) -> Stream m (Either ParseError (MutArray a))
125−compactLE n = D.parseManyD (compactLEParserD n)
126−
127−-- | Like 'compactLE' but generates arrays of exactly equal to the size
128−-- specified except for the last array in the stream which could be shorter.
129−--
130−-- /Unimplemented/
131−{-# INLINE compactEQ #-}
132−compactEQ :: -- (MonadIO m, Unbox a) =>
133− Int -> Stream m (MutArray a) -> Stream m (MutArray a)
134−compactEQ _n _xs = undefined
135− -- IsStream.fromStreamD $ D.foldMany (compactEQFold n) (IsStream.toStreamD xs)
136−
137−-- | Like 'compactLE' but generates arrays of size greater than or equal to the
138−-- specified except for the last array in the stream which could be shorter.
139−--
140−-- /Internal/
141−{-# INLINE compactGE #-}
142−compactGE ::
143− (MonadIO m, Unbox a)
144− => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
145−compactGE n = D.foldMany (compactGEFold n)
core/src/Streamly/Internal/Data/MutArray/Type.hs+417−1272
@@ -28,80 +28,57 @@
28
28
29module Streamly.Internal.Data.MutArray.Type
29module Streamly.Internal.Data.MutArray.Type
30 (
30 (
31− -- ** Type
31+ -- * Type
32 -- $arrayNotes
32 -- $arrayNotes
33 MutArray (..)
33 MutArray (..)
34−
34+ , MutableByteArray
35− -- ** Conversion
35+ , touch
36− -- *** Pinned and Unpinned
37 , pin
36 , pin
38 , unpin
37 , unpin
39 , isPinned
38 , isPinned
40
39
41− -- ** Casting
40+ -- * Constructing and Writing
42− , cast
43− , castUnsafe -- XXX unsafeCast
44− , asBytes
45− , unsafePinnedAsPtr
46− , unsafeAsPtr
47−
48 -- ** Construction
41 -- ** Construction
49− , empty
42+ , nil
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
63
43
64− -- *** Slicing
44+ -- *** Uninitialized Arrays
65− -- | Get a subarray without copying
45+ , pinnedNew
66− , getSliceUnsafe -- XXX unsafeGetSlice
46+ , pinnedNewBytes
67− , getSlice
47+ , pinnedNewAligned
68− , splitAt -- XXX should be able to express using getSlice
48+ , new
69− , breakOn
49+ , newArrayWith
70
50
71− -- *** Stream Folds
51+ -- *** From streams
72 , ArrayUnsafe (..)
52 , ArrayUnsafe (..)
73− , unsafeCreateOfWith
53+ , writeNWithUnsafe
74− , unsafeCreateOf
54+ , writeNWith
75− , unsafePinnedCreateOf
55+ , writeNUnsafe
76− , pinnedCreateOf
56+ , pinnedWriteNUnsafe
77− , createOfWith
57+ , writeN
78− , createOf
58+ , pinnedWriteN
79− , revCreateOf
59+ , pinnedWriteNAligned
80−
60+
81− , pinnedCreate
61+ , writeWith
82− , createWith
62+ , write
83− , create
63+ , pinnedWrite
84− -- , revCreate
64+
85−
65+ , writeRevN
66+ -- , writeRev
67+
86− -- *** From containers
68+ -- ** From containers
87 , fromListN
69 , fromListN
88 , pinnedFromListN
70 , pinnedFromListN
89 , fromList
71 , fromList
90 , pinnedFromList
72 , pinnedFromList
91 , fromListRevN
73 , fromListRevN
92 , fromListRev
74 , fromListRev
93− , fromStreamN
75+ , fromStreamDN
94− , fromStream
76+ , fromStreamD
95− , fromPureStreamN
96 , fromPureStream
77 , fromPureStream
97− , fromByteStr#
98− , fromPtrN
99− , fromChunksK
100− , fromChunksRealloced -- fromSmallChunks
101
78
102− -- ** Random writes
79+ -- * Random writes
103 , putIndex
80 , putIndex
104− , putIndexUnsafe -- XXX unsafePutIndex
81+ , putIndexUnsafe
105 , putIndices
82 , putIndices
106 -- , putFromThenTo
83 -- , putFromThenTo
107 -- , putFrom -- start writing at the given position
84 -- , putFrom -- start writing at the given position
@@ -109,71 +86,78 @@ module Streamly.Internal.Data.MutArray.Type
109 -- , putFromTo
86 -- , putFromTo
110 -- , putFromRev
87 -- , putFromRev
111 -- , putUptoRev
88 -- , putUptoRev
112− , modifyIndexUnsafe -- XXX unsafeModifyIndex
89+ , modifyIndexUnsafe
113 , modifyIndex
90 , modifyIndex
114 , modifyIndices
91 , modifyIndices
115 , modify
92 , modify
116 , swapIndices
93 , swapIndices
117 , unsafeSwapIndices
94 , unsafeSwapIndices
118
95
119− -- ** Reading
96+ -- * Growing and Shrinking
97+ -- Arrays grow only at the end, though it is possible to grow on both sides
98+ -- and therefore have a cons as well as snoc. But that will require two
99+ -- bounds in the array representation.
120
100
121− -- *** Indexing
101+ -- ** Appending elements
122− , getIndex
102+ , snocWith
123− , getIndexUnsafe -- XXX unsafeGetIndex
103+ , snoc
124− -- , getFromThenTo
104+ , snocLinear
125− , getIndexRev -- getRevIndex?
105+ , snocMay
126− , indexReader
106+ , snocUnsafe
127− , indexReaderWith
128
107
129− -- *** To Streams
108+ -- ** Appending streams
109+ , writeAppendNUnsafe
110+ , writeAppendN
111+ , writeAppendWith
112+ , writeAppend
113+
114+ -- * Eliminating and Reading
115+
116+ -- ** To streams
117+ , reader
118+ , readerRevWith
119+ , readerRev
120+
121+ -- ** To containers
122+ , toStreamDWith
123+ , toStreamDRevWith
124+ , toStreamKWith
125+ , toStreamKRevWith
130 , read
126 , read
131 , readRev
127 , readRev
132− , toStreamWith
133− , toStreamRevWith
134 , toStreamK
128 , toStreamK
135− , toStreamKWith
136 , toStreamKRev
129 , toStreamKRev
137− , toStreamKRevWith
138−
139− -- *** To Containers
140 , toList
130 , toList
141
131
142− -- *** Unfolds
143 -- experimental
132 -- experimental
144 , producerWith
133 , producerWith
145 , producer
134 , producer
146
135
147− , reader
136+ -- ** Random reads
148− , readerRevWith
137+ , getIndex
149− , readerRev
138+ , getIndexUnsafe
150−
139+ , getIndices
151− -- ** Size and Capacity
140+ , getIndicesD
152− -- *** Size
141+ -- , getFromThenTo
153− , length
142+ , getIndexRev
154− , byteLength
155−
156− -- *** Capacity
157− -- , capacity
158− , byteCapacity
159− , bytesFree
160
143
161− -- *** Capacity Management
144+ -- * Memory Management
162 , blockSize
145 , blockSize
163 , arrayChunkBytes
146 , arrayChunkBytes
164 , allocBytesToElemCount
147 , allocBytesToElemCount
165− , realloc -- this is "resize"
148+ , realloc
166− , grow
149+ , resize
167− , growExp
150+ , resizeExp
168 , rightSize
151 , rightSize
169
152
170− -- ** Folding
153+ -- * Size
171− , foldl'
154+ , length
172− , foldr
155+ , byteLength
173− , byteCmp
156+ -- , capacity
174− , byteEq
157+ , byteCapacity
158+ , bytesFree
175
159
176− -- ** In-place Mutation Algorithms
160+ -- * In-place Mutation Algorithms
177 , strip
161 , strip
178 , reverse
162 , reverse
179 , permute
163 , permute
@@ -183,121 +167,62 @@ module Streamly.Internal.Data.MutArray.Type
183 , mergeBy
167 , mergeBy
184 , bubble
168 , bubble
185
169
186− -- ** Growing and Shrinking
170+ -- * Casting
187− -- | Arrays grow only at the end, though it is possible to grow on both
171+ , cast
188− -- sides and therefore have a cons as well as snoc. But that will require
172+ , castUnsafe
189− -- both lower and upper bound in the array representation.
173+ , asBytes
190−
174+ , asPtrUnsafe
191− -- *** Appending elements
192− , snocWith
193− , snoc
194− , snocLinear
195− , snocMay
196− , snocUnsafe -- XXX unsafeSnoc
197−
198− -- *** Appending streams
199− , unsafeAppendN
200− , appendN
201− , appendWith
202− , append
203−
204− -- *** Appending arrays
205− , spliceCopy
206− , spliceWith
207− , splice
208− , spliceExp
209− , spliceUnsafe -- XXX unsafeSplice
210− -- , putSlice
211− -- , appendSlice
212− -- , appendSliceFrom
213−
214− -- ** Serialization using Unbox
215− , pokeAppend
216− , pokeAppendMay
217− , pokeSkipUnsafe -- unsafePokeSkip
218
175
219− -- ** Deserialization using Unbox
176+ -- * Folding
220− , peekUncons
177+ , foldl'
221− , peekUnconsUnsafe -- unsafePeekUncons
178+ , foldr
222− , peekSkipUnsafe -- unsafePeekSkip
179+ , cmp
223
180
224− -- Arrays of arrays
181+ -- * Arrays of arrays
225 -- We can add dimensionality parameter to the array type to get
182 -- We can add dimensionality parameter to the array type to get
226 -- multidimensional arrays. Multidimensional arrays would just be a
183 -- multidimensional arrays. Multidimensional arrays would just be a
227 -- convenience wrapper on top of single dimensional arrays.
184 -- convenience wrapper on top of single dimensional arrays.
228
185
229− -- ** Streams of Arrays
186+ -- | Operations dealing with multiple arrays, streams of arrays or
230− -- *** Chunk
187+ -- multidimensional array representations.
231− -- | Group a stream into arrays.
188+
189+ -- ** Construct from streams
232 , chunksOf
190 , chunksOf
233 , pinnedChunksOf
191 , pinnedChunksOf
234− , buildChunks
192+ , writeChunks
235
193
236− -- *** Split
194+ -- ** Eliminate to streams
237− -- | Split an array into slices.
195+ , flattenArrays
196+ , flattenArraysRev
197+ , fromArrayStreamK
238
198
199+ -- ** Construct from arrays
200+ -- get chunks without copying
201+ , getSliceUnsafe
202+ , getSlice
239 -- , getSlicesFromLenN
203 -- , getSlicesFromLenN
240− , splitOn
204+ , splitAt -- XXX should be able to express using getSlice
241− -- , slicesOf
205+ , breakOn
242−
206+
243− -- *** Concat
207+ -- ** Cloning arrays
244− -- | Append the arrays in a stream to form a stream of elements.
208+ , clone
245− , concatWith
209+ , pinnedClone
246− , concatRevWith
210+
247− , concat
211+ -- ** Appending arrays
248− , concatRev
212+ , spliceCopy
249−
213+ , spliceWith
250− -- *** Compact
214+ , splice
251− -- | Append the arrays in a stream to form a stream of larger arrays.
215+ , spliceExp
252− , SpliceState (..)
216+ , spliceUnsafe
253− , pCompactLE
217+ -- , putSlice
254− , pPinnedCompactLE
218+ -- , appendSlice
255− , compactLeAs
219+ -- , appendSliceFrom
256− , fCompactGE
220+
257− , fPinnedCompactGE
258− , lCompactGE
259− , lPinnedCompactGE
260− , compactGE
261− , compactEQ
262−
263− -- ** Utilities
221+ -- * Utilities
264 , roundUpToPower2
222 , roundUpToPower2
265 , memcpy
223 , memcpy
266 , memcmp
224 , memcmp
267 , c_memchr
225 , c_memchr
268−
269− -- * Deprecated
270− , asPtrUnsafe
271− , writeChunks
272− , flattenArrays
273− , flattenArraysRev
274− , fromArrayStreamK
275− , fromStreamDN
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
301 )
226 )
302where
227where
303
228
@@ -308,52 +233,49 @@ where
308
233
309import Control.Monad (when, void)
234import Control.Monad (when, void)
310import Control.Monad.IO.Class (MonadIO(..))
235import Control.Monad.IO.Class (MonadIO(..))
311−import Data.Bifunctor (first)
312import Data.Bits (shiftR, (.|.), (.&.))
236import Data.Bits (shiftR, (.|.), (.&.))
313import Data.Functor.Identity (Identity(..))
237import Data.Functor.Identity (Identity(..))
314import Data.Proxy (Proxy(..))
238import Data.Proxy (Proxy(..))
315import Data.Word (Word8)
239import Data.Word (Word8)
316import Foreign.C.Types (CSize(..), CInt(..))
240import Foreign.C.Types (CSize(..), CInt(..))
317import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
241import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
318−import Streamly.Internal.Data.MutByteArray.Type
242+import Streamly.Internal.Data.Unbox
319− ( MutByteArray(..)
243+ ( MutableByteArray(..)
244+ , Unbox(..)
320 , PinnedState(..)
245 , PinnedState(..)
321 , getMutableByteArray#
246 , getMutableByteArray#
247+ , touch
322 , putSliceUnsafe
248 , putSliceUnsafe
323 )
249 )
324−import Streamly.Internal.Data.Unbox (Unbox(..))
325import GHC.Base
250import GHC.Base
326 ( IO(..)
251 ( IO(..)
327 , Int(..)
252 , Int(..)
253+ , byteArrayContents#
328 , compareByteArrays#
254 , compareByteArrays#
329 , copyMutableByteArray#
255 , copyMutableByteArray#
330 )
256 )
331import GHC.Base (noinline)
257import GHC.Base (noinline)
332−import GHC.Exts (unsafeCoerce#, Addr#)
258+import GHC.Exts (unsafeCoerce#)
333import GHC.Ptr (Ptr(..))
259import GHC.Ptr (Ptr(..))
334
260
335import Streamly.Internal.Data.Fold.Type (Fold(..))
261import Streamly.Internal.Data.Fold.Type (Fold(..))
336import Streamly.Internal.Data.Producer.Type (Producer (..))
262import Streamly.Internal.Data.Producer.Type (Producer (..))
337import Streamly.Internal.Data.Stream.Type (Stream)
263import Streamly.Internal.Data.Stream.Type (Stream)
338−import Streamly.Internal.Data.Parser.Type (Parser (..))
339import Streamly.Internal.Data.StreamK.Type (StreamK)
264import Streamly.Internal.Data.StreamK.Type (StreamK)
340import Streamly.Internal.Data.SVar.Type (adaptState, defState)
265import Streamly.Internal.Data.SVar.Type (adaptState, defState)
341−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
342import Streamly.Internal.Data.Unfold.Type (Unfold(..))
266import Streamly.Internal.Data.Unfold.Type (Unfold(..))
343import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
267import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
344
268
345import qualified Streamly.Internal.Data.Fold.Type as FL
269import qualified Streamly.Internal.Data.Fold.Type as FL
346−import 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
349import qualified Streamly.Internal.Data.Producer as Producer
270import qualified Streamly.Internal.Data.Producer as Producer
350import qualified Streamly.Internal.Data.Stream.Type as D
271import qualified Streamly.Internal.Data.Stream.Type as D
351import qualified Streamly.Internal.Data.Stream.Lift as D
272import qualified Streamly.Internal.Data.Stream.Lift as D
352import qualified Streamly.Internal.Data.StreamK.Type as K
273import qualified Streamly.Internal.Data.StreamK.Type as K
274+import qualified Streamly.Internal.Data.Unbox as Unboxed
353import qualified Prelude
275import qualified Prelude
354
276
355import Prelude hiding
277import Prelude hiding
356− (Foldable(..), concat, read, unlines, splitAt, reverse, truncate)
278+ (Foldable(..), read, unlines, splitAt, reverse, truncate)
357
279
358#include "DocTestDataMutArray.hs"
280#include "DocTestDataMutArray.hs"
359
281
@@ -361,7 +283,6 @@ import Prelude hiding
361-- Foreign helpers
283-- Foreign helpers
362-------------------------------------------------------------------------------
284-------------------------------------------------------------------------------
363
285
364−-- NOTE: Have to be "ccall unsafe" so that we can pass unpinned memory to these
365foreign import ccall unsafe "string.h memcpy" c_memcpy
286foreign import ccall unsafe "string.h memcpy" c_memcpy
366 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
287 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
367
288
@@ -371,9 +292,6 @@ foreign import ccall unsafe "string.h memchr" c_memchr
371foreign import ccall unsafe "string.h memcmp" c_memcmp
292foreign import ccall unsafe "string.h memcmp" c_memcmp
372 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
293 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
373
294
374−foreign import ccall unsafe "string.h strlen" c_strlen
375− :: Ptr Word8 -> IO CSize
376−
377-- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
295-- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
378-- how many elements of that type will completely fit in those bytes.
296-- how many elements of that type will completely fit in those bytes.
379--
297--
@@ -428,7 +346,7 @@ data MutArray a =
428 -- The array is a range into arrContents. arrContents may be a superset of
346 -- The array is a range into arrContents. arrContents may be a superset of
429 -- the slice represented by the array. All offsets are in bytes.
347 -- the slice represented by the array. All offsets are in bytes.
430 MutArray
348 MutArray
431− { arrContents :: {-# UNPACK #-} !MutByteArray
349+ { arrContents :: {-# UNPACK #-} !MutableByteArray
432 , arrStart :: {-# UNPACK #-} !Int -- ^ index into arrContents
350 , arrStart :: {-# UNPACK #-} !Int -- ^ index into arrContents
433 , arrEnd :: {-# UNPACK #-} !Int -- ^ index into arrContents
351 , arrEnd :: {-# UNPACK #-} !Int -- ^ index into arrContents
434 -- Represents the first invalid index of
352 -- Represents the first invalid index of
@@ -440,8 +358,8 @@ data MutArray a =
440-- Pinning & Unpinning
358-- Pinning & Unpinning
441-------------------------------------------------------------------------------
359-------------------------------------------------------------------------------
442
360
443−-- | Return a copy of the array in pinned memory if unpinned, else return the
361+-- | Copy the 'MutArray' to pinned memory if unpinned, else do nothing. The
444−-- original array.
362+-- overhead is a copy if the input array is unpinned.
445{-# INLINE pin #-}
363{-# INLINE pin #-}
446pin :: MutArray a -> IO (MutArray a)
364pin :: MutArray a -> IO (MutArray a)
447pin arr@MutArray{..} =
365pin arr@MutArray{..} =
@@ -449,8 +367,8 @@ pin arr@MutArray{..} =
449 then pure arr
367 then pure arr
450 else pinnedClone arr
368 else pinnedClone arr
451
369
452−-- | Return a copy of the array in unpinned memory if pinned, else return the
370+-- | Copy the 'MutArray' to unpinned memory if pinned, else do nothing. The
453−-- original array.
371+-- overhead is a copy if the input array is pinned.
454{-# INLINE unpin #-}
372{-# INLINE unpin #-}
455unpin :: MutArray a -> IO (MutArray a)
373unpin :: MutArray a -> IO (MutArray a)
456unpin arr@MutArray{..} =
374unpin arr@MutArray{..} =
@@ -458,7 +376,6 @@ unpin arr@MutArray{..} =
458 then clone arr
376 then clone arr
459 else pure arr
377 else pure arr
460
378
461−-- | Return 'True' if the array is allocated in pinned memory.
462{-# INLINE isPinned #-}
379{-# INLINE isPinned #-}
463isPinned :: MutArray a -> Bool
380isPinned :: MutArray a -> Bool
464isPinned MutArray{..} = Unboxed.isPinned arrContents
381isPinned MutArray{..} = Unboxed.isPinned arrContents
@@ -479,8 +396,6 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
479-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
396-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
480-- allocatePinned in GHC source.
397-- allocatePinned in GHC source.
481
398
482−-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
483−
484-- | @newArrayWith allocator alignment count@ allocates a new array of zero
399-- | @newArrayWith allocator alignment count@ allocates a new array of zero
485-- length and with a capacity to hold @count@ elements, using @allocator
400-- length and with a capacity to hold @count@ elements, using @allocator
486-- size alignment@ as the memory allocator function.
401-- size alignment@ as the memory allocator function.
@@ -493,7 +408,7 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
493-- /Pre-release/
408-- /Pre-release/
494{-# INLINE newArrayWith #-}
409{-# INLINE newArrayWith #-}
495newArrayWith :: forall m a. (MonadIO m, Unbox a)
410newArrayWith :: forall m a. (MonadIO m, Unbox a)
496− => (Int -> Int -> m MutByteArray) -> Int -> Int -> m (MutArray a)
411+ => (Int -> Int -> m MutableByteArray) -> Int -> Int -> m (MutArray a)
497newArrayWith alloc alignSize count = do
412newArrayWith alloc alignSize count = do
498 let size = max (count * SIZE_OF(a)) 0
413 let size = max (count * SIZE_OF(a)) 0
499 contents <- alloc size alignSize
414 contents <- alloc size alignSize
@@ -504,25 +419,12 @@ newArrayWith alloc alignSize count = do
504 , arrBound = size
419 , arrBound = size
505 }
420 }
506
421
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." #-}
520nil ::
422nil ::
521#ifdef DEVBUILD
423#ifdef DEVBUILD
522 Unbox a =>
424 Unbox a =>
523#endif
425#endif
524 MutArray a
426 MutArray a
525−nil = empty
427+nil = MutArray Unboxed.nil 0 0 0
526
428
527{-# INLINE newBytesAs #-}
429{-# INLINE newBytesAs #-}
528newBytesAs :: MonadIO m =>
430newBytesAs :: MonadIO m =>
@@ -539,13 +441,12 @@ newBytesAs ps bytes = do
539 , arrBound = bytes
441 , arrBound = bytes
540 }
442 }
541
443
542−-- | Allocates a pinned empty array that with a reserved capacity of bytes.
444+-- | Allocates a pinned empty array that can hold 'count' items. The memory of
543−-- The memory of the array is uninitialized and the allocation is aligned as
445+-- the array is uninitialized and the allocation is aligned as per the
544−-- per the 'Unboxed' instance of the type.
446+-- 'Unboxed' instance of the type.
545--
447--
546-- /Pre-release/
448-- /Pre-release/
547{-# INLINE pinnedNewBytes #-}
449{-# INLINE pinnedNewBytes #-}
548−{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
549pinnedNewBytes :: MonadIO m =>
450pinnedNewBytes :: MonadIO m =>
550#ifdef DEVBUILD
451#ifdef DEVBUILD
551 Unbox a =>
452 Unbox a =>
@@ -570,31 +471,21 @@ newAs ps =
570 (error "new: alignment is not used in unpinned arrays.")
471 (error "new: alignment is not used in unpinned arrays.")
571
472
572-- XXX can unaligned allocation be more efficient when alignment is not needed?
473-- XXX can unaligned allocation be more efficient when alignment is not needed?
573−
474+--
574−-- | Allocates a pinned array of zero length but growable to the specified
475+-- | Allocates an empty pinned array that can hold 'count' items. The memory of
575−-- capacity without reallocation.
476+-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
576−{-# INLINE pinnedEmptyOf #-}
477+-- instance of the type.
577−pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
478+--
578−pinnedEmptyOf = newAs Pinned
579−
580−-- XXX Deprecate in major
581−-- {-# DEPRECATED pinnedNew "Please use pinnedEmptyOf instead." #-}
582{-# INLINE pinnedNew #-}
479{-# INLINE pinnedNew #-}
583pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
480pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
584−pinnedNew = pinnedEmptyOf
481+pinnedNew = newAs Pinned
585
482
586−-- | Allocates an unpinned array of zero length but growable to the specified
483+-- | Allocates an empty unpinned array that can hold 'count' items. The memory
587−-- capacity without reallocation.
484+-- of the array is uninitialized.
588--
485--
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." #-}
595{-# INLINE new #-}
486{-# INLINE new #-}
596new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
487new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
597−new = emptyOf
488+new = newAs Unpinned
598
489
599-------------------------------------------------------------------------------
490-------------------------------------------------------------------------------
600-- Random writes
491-- Random writes
@@ -610,7 +501,7 @@ putIndexUnsafe :: forall m a. (MonadIO m, Unbox a)
610putIndexUnsafe i MutArray{..} x = do
501putIndexUnsafe i MutArray{..} x = do
611 let index = INDEX_OF(arrStart, i, a)
502 let index = INDEX_OF(arrStart, i, a)
612 assert (i >= 0 && INDEX_VALID(index, arrEnd, a)) (return ())
503 assert (i >= 0 && INDEX_VALID(index, arrEnd, a)) (return ())
613− liftIO $ pokeAt index arrContents x
504+ liftIO $ pokeByteIndex index arrContents x
614
505
615invalidIndex :: String -> Int -> a
506invalidIndex :: String -> Int -> a
616invalidIndex label i =
507invalidIndex label i =
@@ -628,7 +519,7 @@ putIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m ()
628putIndex i MutArray{..} x = do
519putIndex i MutArray{..} x = do
629 let index = INDEX_OF(arrStart,i,a)
520 let index = INDEX_OF(arrStart,i,a)
630 if i >= 0 && INDEX_VALID(index,arrEnd,a)
521 if i >= 0 && INDEX_VALID(index,arrEnd,a)
631− then liftIO $ pokeAt index arrContents x
522+ then liftIO $ pokeByteIndex index arrContents x
632 else invalidIndex "putIndex" i
523 else invalidIndex "putIndex" i
633
524
634-- | Write an input stream of (index, value) pairs to an array. Throws an
525-- | Write an input stream of (index, value) pairs to an array. Throws an
@@ -642,7 +533,7 @@ putIndices arr = FL.foldlM' step (return ())
642
533
643 where
534 where
644
535
645− step () (i, x) = putIndex i arr x
536+ step () (i, x) = liftIO (putIndex i arr x)
646
537
647-- | Modify a given index of an array using a modifier function.
538-- | Modify a given index of an array using a modifier function.
648--
539--
@@ -654,9 +545,9 @@ modifyIndexUnsafe :: forall m a b. (MonadIO m, Unbox a) =>
654modifyIndexUnsafe i MutArray{..} f = liftIO $ do
545modifyIndexUnsafe i MutArray{..} f = liftIO $ do
655 let index = INDEX_OF(arrStart,i,a)
546 let index = INDEX_OF(arrStart,i,a)
656 assert (i >= 0 && INDEX_NEXT(index,a) <= arrEnd) (return ())
547 assert (i >= 0 && INDEX_NEXT(index,a) <= arrEnd) (return ())
657− r <- peekAt index arrContents
548+ r <- peekByteIndex index arrContents
658 let (x, res) = f r
549 let (x, res) = f r
659− pokeAt index arrContents x
550+ pokeByteIndex index arrContents x
660 return res
551 return res
661
552
662-- | Modify a given index of an array using a modifier function.
553-- | Modify a given index of an array using a modifier function.
@@ -668,9 +559,9 @@ modifyIndex i MutArray{..} f = do
668 let index = INDEX_OF(arrStart,i,a)
559 let index = INDEX_OF(arrStart,i,a)
669 if i >= 0 && INDEX_VALID(index,arrEnd,a)
560 if i >= 0 && INDEX_VALID(index,arrEnd,a)
670 then liftIO $ do
561 then liftIO $ do
671− r <- peekAt index arrContents
562+ r <- peekByteIndex index arrContents
672 let (x, res) = f r
563 let (x, res) = f r
673− pokeAt index arrContents x
564+ pokeByteIndex index arrContents x
674 return res
565 return res
675 else invalidIndex "modifyIndex" i
566 else invalidIndex "modifyIndex" i
676
567
@@ -704,8 +595,8 @@ modify MutArray{..} f = liftIO $
704
595
705 go i =
596 go i =
706 when (INDEX_VALID(i,arrEnd,a)) $ do
597 when (INDEX_VALID(i,arrEnd,a)) $ do
707− r <- peekAt i arrContents
598+ r <- peekByteIndex i arrContents
708− pokeAt i arrContents (f r)
599+ pokeByteIndex i arrContents (f r)
709 go (INDEX_NEXT(i,a))
600 go (INDEX_NEXT(i,a))
710
601
711-- XXX We could specify the number of bytes to swap instead of Proxy. Need
602-- XXX We could specify the number of bytes to swap instead of Proxy. Need
@@ -714,15 +605,15 @@ modify MutArray{..} f = liftIO $
714swapArrayByteIndices ::
605swapArrayByteIndices ::
715 forall a. Unbox a
606 forall a. Unbox a
716 => Proxy a
607 => Proxy a
717− -> MutByteArray
608+ -> MutableByteArray
718 -> Int
609 -> Int
719 -> Int
610 -> Int
720 -> IO ()
611 -> IO ()
721swapArrayByteIndices _ arrContents i1 i2 = do
612swapArrayByteIndices _ arrContents i1 i2 = do
722− r1 <- peekAt i1 arrContents
613+ r1 <- peekByteIndex i1 arrContents
723− r2 <- peekAt i2 arrContents
614+ r2 <- peekByteIndex i2 arrContents
724− pokeAt i1 arrContents (r2 :: a)
615+ pokeByteIndex i1 arrContents (r2 :: a)
725− pokeAt i2 arrContents (r1 :: a)
616+ pokeByteIndex i2 arrContents (r1 :: a)
726
617
727-- | Swap the elements at two indices without validating the indices.
618-- | Swap the elements at two indices without validating the indices.
728--
619--
@@ -838,23 +729,26 @@ arrayChunkBytes = 1024
838roundDownTo :: Int -> Int -> Int
729roundDownTo :: Int -> Int -> Int
839roundDownTo elemSize size = size - (size `mod` elemSize)
730roundDownTo elemSize size = size - (size `mod` elemSize)
840
731
732+-- XXX See if resizing can be implemented by reading the old array as a stream
733+-- and then using writeN to the new array.
734+--
841-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
735-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
842-- Since this is not inlined Unboxed consrraint leads to dictionary passing
736-- Since this is not inlined Unboxed consrraint leads to dictionary passing
843-- which complicates some inspection tests.
737-- which complicates some inspection tests.
844--
738--
845−{-# NOINLINE reallocExplicitAs #-}
739+{-# NOINLINE reallocExplicit #-}
846−reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
740+reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
847−reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
741+reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
848 assertM(arrEnd <= arrBound)
742 assertM(arrEnd <= arrBound)
849
743
850 -- Allocate new array
744 -- Allocate new array
851 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
745 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
852 contents <-
746 contents <-
853− if ps == Pinned
747+ if Unboxed.isPinned arrContents
854− then Unboxed.pinnedNew newCapMaxInBytes
748+ then Unboxed.pinnedNewBytes newCapMaxInBytes
855− else Unboxed.new newCapMaxInBytes
749+ else Unboxed.newBytes newCapMaxInBytes
856− let !(MutByteArray mbarrFrom#) = arrContents
750+ let !(MutableByteArray mbarrFrom#) = arrContents
857− !(MutByteArray mbarrTo#) = contents
751+ !(MutableByteArray mbarrTo#) = contents
858
752
859 -- Copy old data
753 -- Copy old data
860 let oldStart = arrStart
754 let oldStart = arrStart
@@ -875,10 +769,6 @@ reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
875 , arrBound = newCapInBytes
769 , arrBound = newCapInBytes
876 }
770 }
877
771
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−
882-- | @realloc newCapacity array@ reallocates the array to the specified
772-- | @realloc newCapacity array@ reallocates the array to the specified
883-- capacity in bytes.
773-- capacity in bytes.
884--
774--
@@ -890,12 +780,7 @@ reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
890-- If the original array is pinned, the newly allocated array is also pinned.
780-- If the original array is pinned, the newly allocated array is also pinned.
891{-# INLINABLE realloc #-}
781{-# INLINABLE realloc #-}
892realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
782realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
893−realloc bytes arr =
894− let ps =
895− if isPinned arr
896− then Pinned
897− else Unpinned
898− in liftIO $ reallocExplicitAs ps (SIZE_OF(a)) bytes arr
783+realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
899
784
900-- | @reallocWith label capSizer minIncrBytes array@. The label is used
785-- | @reallocWith label capSizer minIncrBytes array@. The label is used
901-- in error messages and the capSizer is used to determine the capacity of the
786-- in error messages and the capSizer is used to determine the capacity of the
@@ -918,14 +803,14 @@ reallocWith label capSizer minIncrBytes arr = do
918 where
803 where
919
804
920 badSize newSize =
805 badSize newSize =
921− Prelude.concat
806+ concat
922 [ label
807 [ label
923 , ": new array size (in bytes) is less than required size "
808 , ": new array size (in bytes) is less than required size "
924 , show newSize
809 , show newSize
925 , ". Please check the sizing function passed."
810 , ". Please check the sizing function passed."
926 ]
811 ]
927
812
928−-- | @grow newCapacity array@ changes the total capacity of the array so that
813+-- | @resize newCapacity array@ changes the total capacity of the array so that
929-- it is enough to hold the specified number of elements. Nothing is done if
814-- it is enough to hold the specified number of elements. Nothing is done if
930-- the specified capacity is less than the length of the array.
815-- the specified capacity is less than the length of the array.
931--
816--
@@ -933,46 +818,34 @@ reallocWith label capSizer minIncrBytes arr = do
933-- the block size (4K).
818-- the block size (4K).
934--
819--
935-- /Pre-release/
820-- /Pre-release/
936−{-# INLINE grow #-}
821+{-# INLINE resize #-}
937−grow :: forall m a. (MonadIO m, Unbox a) =>
822+resize :: forall m a. (MonadIO m, Unbox a) =>
938 Int -> MutArray a -> m (MutArray a)
823 Int -> MutArray a -> m (MutArray a)
939−grow nElems arr@MutArray{..} = do
824+resize nElems arr@MutArray{..} = do
940 let req = SIZE_OF(a) * nElems
825 let req = SIZE_OF(a) * nElems
941− cap = arrBound - arrStart
826+ len = arrEnd - arrStart
942− if req < cap
827+ if req < len
943 then return arr
828 then return arr
944 else realloc req arr
829 else realloc req arr
945
830
946−{-# DEPRECATED resize "Please use grow instead." #-}
947−{-# INLINE resize #-}
948−resize :: forall m a. (MonadIO m, Unbox a) =>
949− Int -> MutArray a -> m (MutArray a)
950−resize = grow
951−
952−-- | Like 'grow' but if the requested byte capacity is more than
831+-- | Like 'resize' but if the byte capacity is more than 'largeObjectThreshold'
953−-- 'largeObjectThreshold' then it is rounded up to the closest power of 2.
832+-- then it is rounded up to the closest power of 2.
954--
833--
955-- /Pre-release/
834-- /Pre-release/
956−{-# INLINE growExp #-}
835+{-# INLINE resizeExp #-}
957−growExp :: forall m a. (MonadIO m, Unbox a) =>
836+resizeExp :: forall m a. (MonadIO m, Unbox a) =>
958 Int -> MutArray a -> m (MutArray a)
837 Int -> MutArray a -> m (MutArray a)
959−growExp nElems arr@MutArray{..} = do
838+resizeExp nElems arr@MutArray{..} = do
960 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
839 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
961 req1 =
840 req1 =
962 if req > largeObjectThreshold
841 if req > largeObjectThreshold
963 then roundUpToPower2 req
842 then roundUpToPower2 req
964 else req
843 else req
965− cap = arrBound - arrStart
844+ len = arrEnd - arrStart
966− if req1 < cap
845+ if req1 < len
967 then return arr
846 then return arr
968 else realloc req1 arr
847 else realloc req1 arr
969
848
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−
976-- | Resize the allocated memory to drop any reserved free space at the end of
849-- | Resize the allocated memory to drop any reserved free space at the end of
977-- the array and reallocate it to reduce wastage.
850-- the array and reallocate it to reduce wastage.
978--
851--
@@ -1017,7 +890,7 @@ rightSize arr@MutArray{..} = do
1017snocNewEnd :: (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m (MutArray a)
890snocNewEnd :: (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m (MutArray a)
1018snocNewEnd newEnd arr@MutArray{..} x = liftIO $ do
891snocNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1019 assert (newEnd <= arrBound) (return ())
892 assert (newEnd <= arrBound) (return ())
1020− pokeAt arrEnd arrContents x
893+ pokeByteIndex arrEnd arrContents x
1021 return $ arr {arrEnd = newEnd}
894 return $ arr {arrEnd = newEnd}
1022
895
1023-- | Really really unsafe, appends the element into the first array, may
896-- | Really really unsafe, appends the element into the first array, may
@@ -1037,7 +910,7 @@ snocUnsafe arr@MutArray{..} = snocNewEnd (INDEX_NEXT(arrEnd,a)) arr
1037{-# INLINE snocMay #-}
910{-# INLINE snocMay #-}
1038snocMay :: forall m a. (MonadIO m, Unbox a) =>
911snocMay :: forall m a. (MonadIO m, Unbox a) =>
1039 MutArray a -> a -> m (Maybe (MutArray a))
912 MutArray a -> a -> m (Maybe (MutArray a))
1040−snocMay arr@MutArray{..} x = do
913+snocMay arr@MutArray{..} x = liftIO $ do
1041 let newEnd = INDEX_NEXT(arrEnd,a)
914 let newEnd = INDEX_NEXT(arrEnd,a)
1042 if newEnd <= arrBound
915 if newEnd <= arrBound
1043 then Just <$> snocNewEnd newEnd arr x
916 then Just <$> snocNewEnd newEnd arr x
@@ -1051,7 +924,7 @@ snocWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1051 -> a
924 -> a
1052 -> m (MutArray a)
925 -> m (MutArray a)
1053snocWithRealloc sizer arr x = do
926snocWithRealloc sizer arr x = do
1054− arr1 <- reallocWith "snocWith" sizer (SIZE_OF(a)) arr
927+ arr1 <- liftIO $ reallocWith "snocWith" sizer (SIZE_OF(a)) arr
1055 snocUnsafe arr1 x
928 snocUnsafe arr1 x
1056
929
1057-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
930-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
@@ -1073,7 +946,7 @@ snocWith :: forall m a. (MonadIO m, Unbox a) =>
1073 -> MutArray a
946 -> MutArray a
1074 -> a
947 -> a
1075 -> m (MutArray a)
948 -> m (MutArray a)
1076−snocWith allocSize arr x = do
949+snocWith allocSize arr x = liftIO $ do
1077 let newEnd = INDEX_NEXT(arrEnd arr,a)
950 let newEnd = INDEX_NEXT(arrEnd arr,a)
1078 if newEnd <= arrBound arr
951 if newEnd <= arrBound arr
1079 then snocNewEnd newEnd arr x
952 then snocNewEnd newEnd arr x
@@ -1117,126 +990,6 @@ snoc = snocWith f
1117 then oldSize * 2
990 then oldSize * 2
1118 else roundUpToPower2 oldSize * 2
991 else roundUpToPower2 oldSize * 2
1119
992
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−
1240-------------------------------------------------------------------------------
993-------------------------------------------------------------------------------
1241-- Random reads
994-- Random reads
1242-------------------------------------------------------------------------------
995-------------------------------------------------------------------------------
@@ -1251,7 +1004,7 @@ getIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1251getIndexUnsafe i MutArray{..} = do
1004getIndexUnsafe i MutArray{..} = do
1252 let index = INDEX_OF(arrStart,i,a)
1005 let index = INDEX_OF(arrStart,i,a)
1253 assert (i >= 0 && INDEX_VALID(index,arrEnd,a)) (return ())
1006 assert (i >= 0 && INDEX_VALID(index,arrEnd,a)) (return ())
1254− liftIO $ peekAt index arrContents
1007+ liftIO $ peekByteIndex index arrContents
1255
1008
1256-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
1009-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
1257--
1010--
@@ -1260,7 +1013,7 @@ getIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (Maybe a)
1260getIndex i MutArray{..} = do
1013getIndex i MutArray{..} = do
1261 let index = INDEX_OF(arrStart,i,a)
1014 let index = INDEX_OF(arrStart,i,a)
1262 if i >= 0 && INDEX_VALID(index,arrEnd,a)
1015 if i >= 0 && INDEX_VALID(index,arrEnd,a)
1263− then liftIO $ Just <$> peekAt index arrContents
1016+ then liftIO $ Just <$> peekByteIndex index arrContents
1264 else return Nothing
1017 else return Nothing
1265
1018
1266-- | /O(1)/ Lookup the element at the given index from the end of the array.
1019-- | /O(1)/ Lookup the element at the given index from the end of the array.
@@ -1273,16 +1026,21 @@ getIndexRev :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1273getIndexRev i MutArray{..} = do
1026getIndexRev i MutArray{..} = do
1274 let index = RINDEX_OF(arrEnd,i,a)
1027 let index = RINDEX_OF(arrEnd,i,a)
1275 if i >= 0 && index >= arrStart
1028 if i >= 0 && index >= arrStart
1276− then liftIO $ peekAt index arrContents
1029+ then liftIO $ peekByteIndex index arrContents
1277 else invalidIndex "getIndexRev" i
1030 else invalidIndex "getIndexRev" i
1278
1031
1279data GetIndicesState contents start end st =
1032data GetIndicesState contents start end st =
1280 GetIndicesState contents start end st
1033 GetIndicesState contents start end st
1281
1034
1282−{-# INLINE indexReaderWith #-}
1035+-- | Given an unfold that generates array indices, read the elements on those
1036+-- indices from the supplied MutArray. An error is thrown if an index is out of
1037+-- bounds.
1038+--
1039+-- /Pre-release/
1040+{-# INLINE getIndicesD #-}
1283−indexReaderWith :: (Monad m, Unbox a) =>
1041+getIndicesD :: (Monad m, Unbox a) =>
1284 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1042 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1285−indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
1043+getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
1286
1044
1287 where
1045 where
1288
1046
@@ -1301,26 +1059,9 @@ indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
1301 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1059 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1302 D.Stop -> return D.Stop
1060 D.Stop -> return D.Stop
1303
1061
1304−{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1305−{-# INLINE getIndicesWith #-}
1306−getIndicesWith :: (Monad m, Unbox a) =>
1307− (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1308−getIndicesWith = indexReaderWith
1309−
1310−-- | Given an unfold that generates array indices, read the elements on those
1311−-- indices from the supplied MutArray. An error is thrown if an index is out of
1312−-- bounds.
1313−--
1314−-- /Pre-release/
1315−{-# INLINE indexReader #-}
1316−indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1317−indexReader = indexReaderWith liftIO
1318−
1319−-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
1320−{-# DEPRECATED getIndices "Please use indexReader instead." #-}
1321{-# INLINE getIndices #-}
1062{-# INLINE getIndices #-}
1322getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1063getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1323−getIndices = indexReader
1064+getIndices = getIndicesD liftIO
1324
1065
1325-------------------------------------------------------------------------------
1066-------------------------------------------------------------------------------
1326-- Subarrays
1067-- Subarrays
@@ -1425,7 +1166,7 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1425
1166
1426 -- Invariant low < high on entry, and on return as well
1167 -- Invariant low < high on entry, and on return as well
1427 moveHigh low high = do
1168 moveHigh low high = do
1428− h <- peekAt high arrContents
1169+ h <- peekByteIndex high arrContents
1429 if f h
1170 if f h
1430 then
1171 then
1431 -- Correctly classified, continue the loop
1172 -- Correctly classified, continue the loop
@@ -1445,7 +1186,7 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1445 -- low <= high
1186 -- low <= high
1446 -- Both low and high are valid locations within the array
1187 -- Both low and high are valid locations within the array
1447 go low high = do
1188 go low high = do
1448− l <- peekAt low arrContents
1189+ l <- peekByteIndex low arrContents
1449 if f l
1190 if f l
1450 then
1191 then
1451 -- low is wrongly classified
1192 -- low is wrongly classified
@@ -1456,8 +1197,8 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1456 case r of
1197 case r of
1457 Nothing -> return low
1198 Nothing -> return low
1458 Just (high1, h) -> do -- low < high1
1199 Just (high1, h) -> do -- low < high1
1459− pokeAt low arrContents h
1200+ pokeByteIndex low arrContents h
1460− pokeAt high1 arrContents l
1201+ pokeByteIndex high1 arrContents l
1461 let low1 = INDEX_NEXT(low,a)
1202 let low1 = INDEX_NEXT(low,a)
1462 high2 = INDEX_PREV(high1,a)
1203 high2 = INDEX_PREV(high1,a)
1463 if low1 <= high2
1204 if low1 <= high2
@@ -1591,7 +1332,7 @@ chunksOfAs ps n (D.Stream step state) =
1591 r <- step (adaptState gst) st
1332 r <- step (adaptState gst) st
1592 case r of
1333 case r of
1593 D.Yield x s -> do
1334 D.Yield x s -> do
1594− liftIO $ pokeAt end contents x
1335+ liftIO $ pokeByteIndex end contents x
1595 let end1 = INDEX_NEXT(end,a)
1336 let end1 = INDEX_NEXT(end,a)
1596 return $
1337 return $
1597 if end1 >= bound
1338 if end1 >= bound
@@ -1610,12 +1351,10 @@ chunksOfAs ps n (D.Stream step state) =
1610
1351
1611 step' _ GroupFinish = return D.Stop
1352 step' _ GroupFinish = return D.Stop
1612
1353
1613−-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
1354+-- | @chunksOf n stream@ groups the input stream into a stream of
1614−-- @n@ elements each.
1355+-- arrays of size n.
1615−--
1616−-- Same as the following but may be more efficient:
1617--
1356--
1618−-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1357+-- @chunksOf n = StreamD.foldMany (MutArray.writeN n)@
1619--
1358--
1620-- /Pre-release/
1359-- /Pre-release/
1621{-# INLINE_NORMAL chunksOf #-}
1360{-# INLINE_NORMAL chunksOf #-}
@@ -1624,29 +1363,17 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
1624-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1363-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1625-- benchmark. It seems it has difficulty producing optimized code when
1364-- benchmark. It seems it has difficulty producing optimized code when
1626-- converting to StreamK. Investigate GHC optimizations.
1365-- converting to StreamK. Investigate GHC optimizations.
1627−-- chunksOf n = D.foldMany (createOf n)
1366+-- chunksOf n = D.foldMany (writeN n)
1628chunksOf = chunksOfAs Unpinned
1367chunksOf = chunksOfAs Unpinned
1629
1368
1630-- | Like 'chunksOf' but creates pinned arrays.
1369-- | Like 'chunksOf' but creates pinned arrays.
1631{-# INLINE_NORMAL pinnedChunksOf #-}
1370{-# INLINE_NORMAL pinnedChunksOf #-}
1632pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1371pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1633 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1372 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1634−-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1373+-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
1635pinnedChunksOf = chunksOfAs Pinned
1374pinnedChunksOf = chunksOfAs Pinned
1636
1375
1637−-- | When we are buffering a stream of unknown size into an array we do not
1376+-- XXX This should take a PinnedState
1638−-- know how much space to pre-allocate. So we start with the min size and emit
1639−-- the array then keep on doubling the size every time. Thus we do not need to
1640−-- guess the optimum chunk size.
1641−--
1642−-- We can incorporate this in chunksOfAs if the additional size parameter does
1643−-- not impact perf.
1644−--
1645−{-# INLINE _chunksOfRange #-}
1646−_chunksOfRange :: -- (MonadIO m, Unbox a) =>
1647− PinnedState -> Int -> Int -> D.Stream m a -> D.Stream m (MutArray a)
1648−_chunksOfRange _ps _low _hi = undefined
1649−
1650-- XXX buffer to a list instead?
1377-- XXX buffer to a list instead?
1651-- | Buffer the stream into arrays in memory.
1378-- | Buffer the stream into arrays in memory.
1652{-# INLINE arrayStreamKFromStreamDAs #-}
1379{-# INLINE arrayStreamKFromStreamDAs #-}
@@ -1664,10 +1391,16 @@ data FlattenState s contents a =
1664 OuterLoop s
1391 OuterLoop s
1665 | InnerLoop s contents !Int !Int
1392 | InnerLoop s contents !Int !Int
1666
1393
1394+-- | Use the "reader" unfold instead.
1395+--
1396+-- @flattenArrays = unfoldMany reader@
1397+--
1398+-- We can try this if there are any fusion issues in the unfold.
1399+--
1667−{-# INLINE_NORMAL concatWith #-}
1400+{-# INLINE_NORMAL flattenArrays #-}
1668−concatWith :: forall m a. (Monad m, Unbox a)
1401+flattenArrays :: forall m a. (MonadIO m, Unbox a)
1669− => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1402+ => D.Stream m (MutArray a) -> D.Stream m a
1670−concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1403+flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
1671
1404
1672 where
1405 where
1673
1406
@@ -1684,30 +1417,19 @@ concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1684 return $ D.Skip $ OuterLoop st
1417 return $ D.Skip $ OuterLoop st
1685
1418
1686 step' _ (InnerLoop st contents p end) = do
1419 step' _ (InnerLoop st contents p end) = do
1687− x <- liftio $ peekAt p contents
1420+ x <- liftIO $ peekByteIndex p contents
1688 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1421 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1689
1422
1690−-- | Use the "reader" unfold instead.
1423+-- | Use the "readerRev" unfold instead.
1691--
1424--
1692−-- @concat = unfoldMany reader@
1425+-- @flattenArrays = unfoldMany readerRev@
1693--
1426--
1694-- We can try this if there are any fusion issues in the unfold.
1427-- We can try this if there are any fusion issues in the unfold.
1695--
1428--
1696−{-# INLINE_NORMAL concat #-}
1429+{-# INLINE_NORMAL flattenArraysRev #-}
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 #-}
1703−flattenArrays :: forall m a. (MonadIO m, Unbox a)
1430+flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1704 => D.Stream m (MutArray a) -> D.Stream m a
1431 => D.Stream m (MutArray a) -> D.Stream m a
1705−flattenArrays = concat
1706−
1707−{-# INLINE_NORMAL concatRevWith #-}
1708−concatRevWith :: forall m a. (Monad m, Unbox a)
1709− => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1710−concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1432+flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1711
1433
1712 where
1434 where
1713
1435
@@ -1725,33 +1447,16 @@ concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1725 return $ D.Skip $ OuterLoop st
1447 return $ D.Skip $ OuterLoop st
1726
1448
1727 step' _ (InnerLoop st contents p start) = do
1449 step' _ (InnerLoop st contents p start) = do
1728− x <- liftio $ peekAt p contents
1450+ x <- liftIO $ peekByteIndex p contents
1729 let cur = INDEX_PREV(p,a)
1451 let cur = INDEX_PREV(p,a)
1730 return $ D.Yield x (InnerLoop st contents cur start)
1452 return $ D.Yield x (InnerLoop st contents cur start)
1731
1453
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−
1743−{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1744−{-# INLINE flattenArraysRev #-}
1745−flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1746− => D.Stream m (MutArray a) -> D.Stream m a
1747−flattenArraysRev = concatRev
1748−
1749-------------------------------------------------------------------------------
1454-------------------------------------------------------------------------------
1750-- Unfolds
1455-- Unfolds
1751-------------------------------------------------------------------------------
1456-------------------------------------------------------------------------------
1752
1457
1753data ArrayUnsafe a = ArrayUnsafe
1458data ArrayUnsafe a = ArrayUnsafe
1754− {-# UNPACK #-} !MutByteArray -- contents
1459+ {-# UNPACK #-} !MutableByteArray -- contents
1755 {-# UNPACK #-} !Int -- index 1
1460 {-# UNPACK #-} !Int -- index 1
1756 {-# UNPACK #-} !Int -- index 2
1461 {-# UNPACK #-} !Int -- index 2
1757
1462
@@ -1781,7 +1486,7 @@ producerWith liftio = Producer step (return . toArrayUnsafe) extract
1781 -- few actions for correctness and execution order sanity. We want
1486 -- few actions for correctness and execution order sanity. We want
1782 -- the peek to occur right here and not lazily at some later point
1487 -- the peek to occur right here and not lazily at some later point
1783 -- because we want the peek to be ordered with respect to the touch.
1488 -- because we want the peek to be ordered with respect to the touch.
1784− !x <- liftio $ peekAt cur contents
1489+ !x <- liftio $ peekByteIndex cur contents
1785 return $ D.Yield x (ArrayUnsafe contents (INDEX_NEXT(cur,a)) end)
1490 return $ D.Yield x (ArrayUnsafe contents (INDEX_NEXT(cur,a)) end)
1786
1491
1787 extract = return . fromArrayUnsafe
1492 extract = return . fromArrayUnsafe
@@ -1812,7 +1517,7 @@ readerRevWith liftio = Unfold step inject
1812 {-# INLINE_LATE step #-}
1517 {-# INLINE_LATE step #-}
1813 step (ArrayUnsafe _ start p) | p < start = return D.Stop
1518 step (ArrayUnsafe _ start p) | p < start = return D.Stop
1814 step (ArrayUnsafe contents start p) = do
1519 step (ArrayUnsafe contents start p) = do
1815− !x <- liftio $ peekAt p contents
1520+ !x <- liftio $ peekByteIndex p contents
1816 return $ D.Yield x (ArrayUnsafe contents start (INDEX_PREV(p,a)))
1521 return $ D.Yield x (ArrayUnsafe contents start (INDEX_PREV(p,a)))
1817
1522
1818-- | Unfold an array into a stream in reverse order.
1523-- | Unfold an array into a stream in reverse order.
@@ -1843,7 +1548,7 @@ toListFB c n MutArray{..} = go arrStart
1843 -- evaluated/written to before we peek at them.
1548 -- evaluated/written to before we peek at them.
1844 -- XXX
1549 -- XXX
1845 let !x = unsafeInlineIO $ do
1550 let !x = unsafeInlineIO $ do
1846− r <- peekAt arrContents p
1551+ r <- peekByteIndex arrContents p
1847 return r
1552 return r
1848 in c x (go (PTR_NEXT(p,a)))
1553 in c x (go (PTR_NEXT(p,a)))
1849-}
1554-}
@@ -1860,21 +1565,21 @@ toList MutArray{..} = liftIO $ go arrStart
1860
1565
1861 go p | assert (p <= arrEnd) (p == arrEnd) = return []
1566 go p | assert (p <= arrEnd) (p == arrEnd) = return []
1862 go p = do
1567 go p = do
1863− x <- peekAt p arrContents
1568+ x <- peekByteIndex p arrContents
1864 (:) x <$> go (INDEX_NEXT(p,a))
1569 (:) x <$> go (INDEX_NEXT(p,a))
1865
1570
1866−{-# INLINE_NORMAL toStreamWith #-}
1571+{-# INLINE_NORMAL toStreamDWith #-}
1867−toStreamWith ::
1572+toStreamDWith ::
1868 forall m a. (Monad m, Unbox a)
1573 forall m a. (Monad m, Unbox a)
1869 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1574 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1870−toStreamWith liftio MutArray{..} = D.Stream step arrStart
1575+toStreamDWith liftio MutArray{..} = D.Stream step arrStart
1871
1576
1872 where
1577 where
1873
1578
1874 {-# INLINE_LATE step #-}
1579 {-# INLINE_LATE step #-}
1875 step _ p | assert (p <= arrEnd) (p == arrEnd) = return D.Stop
1580 step _ p | assert (p <= arrEnd) (p == arrEnd) = return D.Stop
1876 step _ p = liftio $ do
1581 step _ p = liftio $ do
1877− r <- peekAt p arrContents
1582+ r <- peekByteIndex p arrContents
1878 return $ D.Yield r (INDEX_NEXT(p,a))
1583 return $ D.Yield r (INDEX_NEXT(p,a))
1879
1584
1880-- | Convert a 'MutArray' into a stream.
1585-- | Convert a 'MutArray' into a stream.
@@ -1883,7 +1588,7 @@ toStreamWith liftio MutArray{..} = D.Stream step arrStart
1883--
1588--
1884{-# INLINE_NORMAL read #-}
1589{-# INLINE_NORMAL read #-}
1885read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1590read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1886−read = toStreamWith liftIO
1591+read = toStreamDWith liftIO
1887
1592
1888{-# INLINE toStreamKWith #-}
1593{-# INLINE toStreamKWith #-}
1889toStreamKWith ::
1594toStreamKWith ::
@@ -1895,18 +1600,18 @@ toStreamKWith liftio MutArray{..} = go arrStart
1895
1600
1896 go p | assert (p <= arrEnd) (p == arrEnd) = K.nil
1601 go p | assert (p <= arrEnd) (p == arrEnd) = K.nil
1897 | otherwise =
1602 | otherwise =
1898− let elemM = peekAt p arrContents
1603+ let elemM = peekByteIndex p arrContents
1899 in liftio elemM `K.consM` go (INDEX_NEXT(p,a))
1604 in liftio elemM `K.consM` go (INDEX_NEXT(p,a))
1900
1605
1901{-# INLINE toStreamK #-}
1606{-# INLINE toStreamK #-}
1902toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1607toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1903toStreamK = toStreamKWith liftIO
1608toStreamK = toStreamKWith liftIO
1904
1609
1905−{-# INLINE_NORMAL toStreamRevWith #-}
1610+{-# INLINE_NORMAL toStreamDRevWith #-}
1906−toStreamRevWith ::
1611+toStreamDRevWith ::
1907 forall m a. (Monad m, Unbox a)
1612 forall m a. (Monad m, Unbox a)
1908 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1613 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1909−toStreamRevWith liftio MutArray{..} =
1614+toStreamDRevWith liftio MutArray{..} =
1910 let p = INDEX_PREV(arrEnd,a)
1615 let p = INDEX_PREV(arrEnd,a)
1911 in D.Stream step p
1616 in D.Stream step p
1912
1617
@@ -1915,7 +1620,7 @@ toStreamRevWith liftio MutArray{..} =
1915 {-# INLINE_LATE step #-}
1620 {-# INLINE_LATE step #-}
1916 step _ p | p < arrStart = return D.Stop
1621 step _ p | p < arrStart = return D.Stop
1917 step _ p = liftio $ do
1622 step _ p = liftio $ do
1918− r <- peekAt p arrContents
1623+ r <- peekByteIndex p arrContents
1919 return $ D.Yield r (INDEX_PREV(p,a))
1624 return $ D.Yield r (INDEX_PREV(p,a))
1920
1625
1921-- | Convert a 'MutArray' into a stream in reverse order.
1626-- | Convert a 'MutArray' into a stream in reverse order.
@@ -1924,7 +1629,7 @@ toStreamRevWith liftio MutArray{..} =
1924--
1629--
1925{-# INLINE_NORMAL readRev #-}
1630{-# INLINE_NORMAL readRev #-}
1926readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1631readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1927−readRev = toStreamRevWith liftIO
1632+readRev = toStreamDRevWith liftIO
1928
1633
1929{-# INLINE toStreamKRevWith #-}
1634{-# INLINE toStreamKRevWith #-}
1930toStreamKRevWith ::
1635toStreamKRevWith ::
@@ -1938,7 +1643,7 @@ toStreamKRevWith liftio MutArray {..} =
1938
1643
1939 go p | p < arrStart = K.nil
1644 go p | p < arrStart = K.nil
1940 | otherwise =
1645 | otherwise =
1941− let elemM = peekAt p arrContents
1646+ let elemM = peekByteIndex p arrContents
1942 in liftio elemM `K.consM` go (INDEX_PREV(p,a))
1647 in liftio elemM `K.consM` go (INDEX_PREV(p,a))
1943
1648
1944{-# INLINE toStreamKRev #-}
1649{-# INLINE toStreamKRev #-}
@@ -1973,7 +1678,7 @@ foldr f z arr = D.foldr f z $ read arr
1973
1678
1974-- XXX Keep the bound intact to not lose any free space? Perf impact?
1679-- XXX Keep the bound intact to not lose any free space? Perf impact?
1975
1680
1976−-- | @unsafeAppendN n arr@ appends up to @n@ input items to the supplied
1681+-- | @writeAppendNUnsafe n arr@ appends up to @n@ input items to the supplied
1977-- array.
1682-- array.
1978--
1683--
1979-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
1684-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
@@ -1982,12 +1687,13 @@ foldr f z arr = D.foldr f z $ read arr
1982-- Any free space left in the array after appending @n@ elements is lost.
1687-- Any free space left in the array after appending @n@ elements is lost.
1983--
1688--
1984-- /Internal/
1689-- /Internal/
1985−{-# INLINE_NORMAL unsafeAppendN #-}
1690+{-# INLINE_NORMAL writeAppendNUnsafe #-}
1986−unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1691+writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1987 Int
1692 Int
1988 -> m (MutArray a)
1693 -> m (MutArray a)
1989 -> Fold m a (MutArray a)
1694 -> Fold m a (MutArray a)
1695+writeAppendNUnsafe n action =
1990−unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
1696+ fmap fromArrayUnsafe $ FL.foldlM' step initial
1991
1697
1992 where
1698 where
1993
1699
@@ -2000,59 +1706,38 @@ unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
2000 -- otherwise we lose that space.
1706 -- otherwise we lose that space.
2001 arr1 <-
1707 arr1 <-
2002 if free < needed
1708 if free < needed
2003− then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1709+ then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
2004 else return arr
1710 else return arr
2005 return $ toArrayUnsafe arr1
1711 return $ toArrayUnsafe arr1
2006
1712
2007 step (ArrayUnsafe contents start end) x = do
1713 step (ArrayUnsafe contents start end) x = do
2008− liftIO $ pokeAt end contents x
1714+ liftIO $ pokeByteIndex end contents x
2009 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1715 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2010
1716
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−
2019-- | Append @n@ elements to an existing array. Any free space left in the array
1717-- | Append @n@ elements to an existing array. Any free space left in the array
2020-- after appending @n@ elements is lost.
1718-- after appending @n@ elements is lost.
2021--
1719--
2022−-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1720+-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
2023--
1721--
2024−{-# INLINE_NORMAL appendN #-}
1722+{-# INLINE_NORMAL writeAppendN #-}
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 #-}
2032writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1723writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
2033 Int -> m (MutArray a) -> Fold m a (MutArray a)
1724 Int -> m (MutArray a) -> Fold m a (MutArray a)
2034−writeAppendN = appendN
1725+writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
2035
1726
2036−-- | @appendWith realloc action@ mutates the array generated by @action@ to
1727+-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
2037-- append the input stream. If there is no reserved space available in the
1728-- append the input stream. If there is no reserved space available in the
2038-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
1729-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
2039-- where @oldSize@ is the current size of the array in bytes.
1730-- where @oldSize@ is the current size of the array in bytes.
2040--
1731--
2041-- Note that the returned array may be a mutated version of original array.
1732-- Note that the returned array may be a mutated version of original array.
2042--
1733--
2043−-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1734+-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
2044--
1735--
2045-- /Pre-release/
1736-- /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." #-}
2052{-# INLINE writeAppendWith #-}
1737{-# INLINE writeAppendWith #-}
2053writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1738writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
2054 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
1739 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2055−writeAppendWith = appendWith
1740+writeAppendWith sizer = FL.foldlM' (snocWith sizer)
2056
1741
2057-- | @append action@ mutates the array generated by @action@ to append the
1742-- | @append action@ mutates the array generated by @action@ to append the
2058-- input stream. If there is no reserved space available in the array it is
1743-- input stream. If there is no reserved space available in the array it is
@@ -2060,101 +1745,70 @@ writeAppendWith = appendWith
2060--
1745--
2061-- Note that the returned array may be a mutated version of original array.
1746-- Note that the returned array may be a mutated version of original array.
2062--
1747--
2063−-- >>> append = MutArray.appendWith (* 2)
1748+-- >>> writeAppend = MutArray.writeAppendWith (* 2)
2064--
1749--
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." #-}
2072{-# INLINE writeAppend #-}
1750{-# INLINE writeAppend #-}
2073writeAppend :: forall m a. (MonadIO m, Unbox a) =>
1751writeAppend :: forall m a. (MonadIO m, Unbox a) =>
2074 m (MutArray a) -> Fold m a (MutArray a)
1752 m (MutArray a) -> Fold m a (MutArray a)
2075−writeAppend = append
1753+writeAppend = writeAppendWith (* 2)
2076
1754
2077-- XXX We can carry bound as well in the state to make sure we do not lose the
1755-- XXX We can carry bound as well in the state to make sure we do not lose the
2078-- remaining capacity. Need to check perf impact.
1756-- remaining capacity. Need to check perf impact.
2079--
1757--
2080−-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
1758+-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
2081−-- function as argument.
1759+-- as argument.
2082--
1760--
2083−-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1761+-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
2084--
1762--
2085-- /Pre-release/
1763-- /Pre-release/
2086−{-# INLINE_NORMAL unsafeCreateOfWith #-}
1764+{-# INLINE_NORMAL writeNWithUnsafe #-}
2087−unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1765+writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2088 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1766 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2089−unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1767+writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2090
1768
2091 where
1769 where
2092
1770
2093 initial = toArrayUnsafe <$> alloc (max n 0)
1771 initial = toArrayUnsafe <$> alloc (max n 0)
2094
1772
2095 step (ArrayUnsafe contents start end) x = do
1773 step (ArrayUnsafe contents start end) x = do
2096− liftIO $ pokeAt end contents x
1774+ liftIO $ pokeByteIndex end contents x
2097 return
1775 return
2098 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1776 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2099
1777
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−
2106{-# INLINE_NORMAL writeNUnsafeAs #-}
1778{-# INLINE_NORMAL writeNUnsafeAs #-}
2107writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
1779writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
2108 => PinnedState -> Int -> Fold m a (MutArray a)
1780 => PinnedState -> Int -> Fold m a (MutArray a)
2109−writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
1781+writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
2110
1782
2111−-- | Like 'createOf' but does not check the array bounds when writing. The fold
1783+-- | Like 'writeN' but does not check the array bounds when writing. The fold
2112-- driver must not call the step function more than 'n' times otherwise it will
1784-- driver must not call the step function more than 'n' times otherwise it will
2113-- corrupt the memory and crash. This function exists mainly because any
1785-- corrupt the memory and crash. This function exists mainly because any
2114-- conditional in the step function blocks fusion causing 10x performance
1786-- conditional in the step function blocks fusion causing 10x performance
2115-- slowdown.
1787-- slowdown.
2116--
1788--
2117−-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
1789+-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
2118--
1790--
2119−{-# INLINE_NORMAL unsafeCreateOf #-}
2120−unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
2121− => Int -> Fold m a (MutArray a)
2122−unsafeCreateOf = writeNUnsafeAs Unpinned
2123−
2124−{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
2125−{-# INLINE writeNUnsafe #-}
1791+{-# INLINE_NORMAL writeNUnsafe #-}
2126writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
1792writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
2127 => Int -> Fold m a (MutArray a)
1793 => Int -> Fold m a (MutArray a)
2128−writeNUnsafe = unsafeCreateOf
1794+writeNUnsafe = writeNUnsafeAs Unpinned
2129
1795
2130−-- | Like 'unsafeCreateOf' but creates a pinned array.
1796+-- | Like 'writeNUnsafe' but creates a pinned array.
2131−{-# INLINE_NORMAL unsafePinnedCreateOf #-}
2132−unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a)
2133− => Int -> Fold m a (MutArray a)
2134−unsafePinnedCreateOf = writeNUnsafeAs Pinned
2135−
2136−{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
2137−{-# INLINE pinnedWriteNUnsafe #-}
1797+{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
2138pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
1798pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
2139 => Int -> Fold m a (MutArray a)
1799 => Int -> Fold m a (MutArray a)
2140−pinnedWriteNUnsafe = unsafePinnedCreateOf
1800+pinnedWriteNUnsafe = writeNUnsafeAs Pinned
2141
1801
2142−-- | @createOfWith alloc n@ folds a maximum of @n@ elements into an array
1802+-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
2143-- allocated using the @alloc@ function.
1803-- allocated using the @alloc@ function.
2144--
1804--
2145−-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
1805+-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
2146−-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
1806+-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
2147--
1807--
2148−{-# INLINE_NORMAL createOfWith #-}
1808+{-# INLINE_NORMAL writeNWith #-}
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 #-}
2155writeNWith :: forall m a. (MonadIO m, Unbox a)
1809writeNWith :: forall m a. (MonadIO m, Unbox a)
2156 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1810 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2157−writeNWith = createOfWith
1811+writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
2158
1812
2159{-# INLINE_NORMAL writeNAs #-}
1813{-# INLINE_NORMAL writeNAs #-}
2160writeNAs ::
1814writeNAs ::
@@ -2162,42 +1816,28 @@ writeNAs ::
2162 => PinnedState
1816 => PinnedState
2163 -> Int
1817 -> Int
2164 -> Fold m a (MutArray a)
1818 -> Fold m a (MutArray a)
2165−writeNAs ps = createOfWith (newAs ps)
1819+writeNAs ps = writeNWith (newAs ps)
2166
1820
2167−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
1821+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
2168-- 'MutArray'.
1822-- 'MutArray'.
2169--
1823--
2170−-- >>> createOf = MutArray.createOfWith MutArray.new
1824+-- >>> writeN = MutArray.writeNWith MutArray.new
2171−-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
1825+-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
2172−-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
1826+-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
2173--
1827--
2174−{-# INLINE_NORMAL createOf #-}
1828+{-# INLINE_NORMAL writeN #-}
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 #-}
2181writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1829writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2182−writeN = createOf
1830+writeN = writeNAs Unpinned
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
2191
1831
2192−{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
1832+-- | Like 'writeN' but creates a pinned array.
2193−{-# INLINE pinnedWriteN #-}
1833+{-# INLINE_NORMAL pinnedWriteN #-}
2194pinnedWriteN ::
1834pinnedWriteN ::
2195 forall m a. (MonadIO m, Unbox a)
1835 forall m a. (MonadIO m, Unbox a)
2196 => Int
1836 => Int
2197 -> Fold m a (MutArray a)
1837 -> Fold m a (MutArray a)
2198−pinnedWriteN = pinnedCreateOf
1838+pinnedWriteN = writeNAs Pinned
2199
1839
2200−-- | Like unsafeCreateOfWith but writes the array in reverse order.
1840+-- | Like writeNWithUnsafe but writes the array in reverse order.
2201--
1841--
2202-- /Internal/
1842-- /Internal/
2203{-# INLINE_NORMAL writeRevNWithUnsafe #-}
1843{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -2214,11 +1854,11 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2214
1854
2215 step (ArrayUnsafe contents start end) x = do
1855 step (ArrayUnsafe contents start end) x = do
2216 let ptr = INDEX_PREV(start,a)
1856 let ptr = INDEX_PREV(start,a)
2217− liftIO $ pokeAt ptr contents x
1857+ liftIO $ pokeByteIndex ptr contents x
2218 return
1858 return
2219 $ ArrayUnsafe contents ptr end
1859 $ ArrayUnsafe contents ptr end
2220
1860
2221−-- | Like createOfWith but writes the array in reverse order.
1861+-- | Like writeNWith but writes the array in reverse order.
2222--
1862--
2223-- /Internal/
1863-- /Internal/
2224{-# INLINE_NORMAL writeRevNWith #-}
1864{-# INLINE_NORMAL writeRevNWith #-}
@@ -2226,36 +1866,31 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
2226 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1866 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2227writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
1867writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
2228
1868
2229−-- | Like 'createOf' but writes the array in reverse order.
1869+-- | Like writeN but writes the array in reverse order.
2230--
1870--
2231-- /Pre-release/
1871-- /Pre-release/
2232−{-# INLINE_NORMAL revCreateOf #-}
1872+{-# INLINE_NORMAL writeRevN #-}
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 #-}
2238writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1873writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2239−writeRevN = revCreateOf
1874+writeRevN = writeRevNWith new
2240
1875
2241-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
1876-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
2242-- input stream to a 'MutArray' aligned to the given size.
1877-- input stream to a 'MutArray' aligned to the given size.
2243--
1878--
2244−-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
1879+-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
2245−-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
1880+-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
2246--
1881--
2247-- /Pre-release/
1882-- /Pre-release/
2248--
1883--
2249{-# INLINE_NORMAL pinnedWriteNAligned #-}
1884{-# INLINE_NORMAL pinnedWriteNAligned #-}
2250pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
1885pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
2251 => Int -> Int -> Fold m a (MutArray a)
1886 => Int -> Int -> Fold m a (MutArray a)
2252−pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
1887+pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
2253
1888
2254-- XXX Buffer to a list instead?
1889-- XXX Buffer to a list instead?
2255−
1890+--
2256-- | Buffer a stream into a stream of arrays.
1891-- | Buffer a stream into a stream of arrays.
2257--
1892--
2258−-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
1893+-- >>> writeChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
2259--
1894--
2260-- Breaking an array into an array stream can be useful to consume a large
1895-- Breaking an array into an array stream can be useful to consume a large
2261-- array sequentially such that memory of the array is released incrementatlly.
1896-- array sequentially such that memory of the array is released incrementatlly.
@@ -2264,43 +1899,37 @@ pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
2264--
1899--
2265-- /Unimplemented/
1900-- /Unimplemented/
2266--
1901--
2267−{-# INLINE_NORMAL buildChunks #-}
1902+{-# INLINE_NORMAL writeChunks #-}
2268−buildChunks :: (MonadIO m, Unbox a) =>
2269− Int -> Fold m a (StreamK n (MutArray a))
2270−buildChunks n = FL.many (createOf n) FL.toStreamK
2271−
2272−{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2273−{-# INLINE writeChunks #-}
2274writeChunks :: (MonadIO m, Unbox a) =>
1903writeChunks :: (MonadIO m, Unbox a) =>
2275 Int -> Fold m a (StreamK n (MutArray a))
1904 Int -> Fold m a (StreamK n (MutArray a))
2276−writeChunks = buildChunks
1905+writeChunks n = FL.many (writeN n) FL.toStreamK
2277
1906
2278{-# INLINE_NORMAL writeWithAs #-}
1907{-# INLINE_NORMAL writeWithAs #-}
2279writeWithAs :: forall m a. (MonadIO m, Unbox a)
1908writeWithAs :: forall m a. (MonadIO m, Unbox a)
2280 => PinnedState -> Int -> Fold m a (MutArray a)
1909 => PinnedState -> Int -> Fold m a (MutArray a)
2281−-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
1910+-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
2282writeWithAs ps elemCount =
1911writeWithAs ps elemCount =
2283 FL.rmapM extract $ FL.foldlM' step initial
1912 FL.rmapM extract $ FL.foldlM' step initial
2284
1913
2285 where
1914 where
2286
1915
2287 initial = do
1916 initial = do
2288− when (elemCount < 0) $ error "createWith: elemCount is negative"
1917+ when (elemCount < 0) $ error "writeWith: elemCount is negative"
2289− newAs ps elemCount
1918+ liftIO $ newAs ps elemCount
2290
1919
2291 step arr@(MutArray _ start end bound) x
1920 step arr@(MutArray _ start end bound) x
2292 | INDEX_NEXT(end,a) > bound = do
1921 | INDEX_NEXT(end,a) > bound = do
2293 let oldSize = end - start
1922 let oldSize = end - start
2294 newSize = max (oldSize * 2) 1
1923 newSize = max (oldSize * 2) 1
2295− arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
1924+ arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
2296 snocUnsafe arr1 x
1925 snocUnsafe arr1 x
2297 step arr x = snocUnsafe arr x
1926 step arr x = snocUnsafe arr x
2298
1927
2299 extract = liftIO . rightSize
1928 extract = liftIO . rightSize
2300
1929
2301−-- XXX Compare createWith with fromStreamD which uses an array of streams
1930+-- XXX Compare writeWith with fromStreamD which uses an array of streams
2302−-- implementation. We can write this using buildChunks above if that is faster.
1931+-- implementation. We can write this using writeChunks above if that is faster.
2303−-- If createWith is faster then we should use that to implement
1932+-- If writeWith is faster then we should use that to implement
2304-- fromStreamD.
1933-- fromStreamD.
2305--
1934--
2306-- XXX The realloc based implementation needs to make one extra copy if we use
1935-- XXX The realloc based implementation needs to make one extra copy if we use
@@ -2315,56 +1944,39 @@ writeWithAs ps elemCount =
2315-- XXX check if GHC's memory allocator is efficient enough. We can try the C
1944-- XXX check if GHC's memory allocator is efficient enough. We can try the C
2316-- malloc to compare against.
1945-- malloc to compare against.
2317
1946
2318−-- | @createWith minCount@ folds the whole input to a single array. The array
1947+-- | @writeWith minCount@ folds the whole input to a single array. The array
2319-- starts at a size big enough to hold minCount elements, the size is doubled
1948-- starts at a size big enough to hold minCount elements, the size is doubled
2320-- every time the array needs to be grown.
1949-- every time the array needs to be grown.
2321--
1950--
2322-- /Caution! Do not use this on infinite streams./
1951-- /Caution! Do not use this on infinite streams./
2323--
1952--
2324−-- >>> f n = MutArray.appendWith (* 2) (MutArray.emptyOf n)
1953+-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2325−-- >>> createWith n = Fold.rmapM MutArray.rightSize (f n)
1954+-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2326−-- >>> createWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
1955+-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
2327--
1956--
2328-- /Pre-release/
1957-- /Pre-release/
2329−{-# INLINE_NORMAL createWith #-}
1958+{-# INLINE_NORMAL writeWith #-}
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 #-}
2337writeWith :: forall m a. (MonadIO m, Unbox a)
1959writeWith :: forall m a. (MonadIO m, Unbox a)
2338 => Int -> Fold m a (MutArray a)
1960 => Int -> Fold m a (MutArray a)
2339−writeWith = createWith
1961+-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
1962+writeWith = writeWithAs Unpinned
2340
1963
2341-- | Fold the whole input to a single array.
1964-- | Fold the whole input to a single array.
2342--
1965--
2343−-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
1966+-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
2344-- rounded up to the element size.
1967-- rounded up to the element size.
2345--
1968--
2346-- /Caution! Do not use this on infinite streams./
1969-- /Caution! Do not use this on infinite streams./
2347--
1970--
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." #-}
2354{-# INLINE write #-}
1971{-# INLINE write #-}
2355write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1972write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2356−write = create
2357−
2358−-- | Like 'create' but creates a pinned array.
2359−{-# INLINE pinnedCreate #-}
2360−pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2361−pinnedCreate =
2362− writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
1973+write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2363
1974
2364−{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
1975+-- | Like 'write' but creates a pinned array.
2365{-# INLINE pinnedWrite #-}
1976{-# INLINE pinnedWrite #-}
2366pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1977pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2367−pinnedWrite = pinnedCreate
1978+pinnedWrite =
1979+ writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2368
1980
2369-------------------------------------------------------------------------------
1981-------------------------------------------------------------------------------
2370-- construct from streams, known size
1982-- construct from streams, known size
@@ -2374,31 +1986,25 @@ pinnedWrite = pinnedCreate
2374fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
1986fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
2375 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
1987 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
2376fromStreamDNAs ps limit str = do
1988fromStreamDNAs ps limit str = do
2377− (arr :: MutArray a) <- newAs ps limit
1989+ (arr :: MutArray a) <- liftIO $ newAs ps limit
2378 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
1990 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
2379 return $ arr {arrEnd = end}
1991 return $ arr {arrEnd = end}
2380
1992
2381 where
1993 where
2382
1994
2383 fwrite arrContents ptr x = do
1995 fwrite arrContents ptr x = do
2384− liftIO $ pokeAt ptr arrContents x
1996+ liftIO $ pokeByteIndex ptr arrContents x
2385 return $ INDEX_NEXT(ptr,a)
1997 return $ INDEX_NEXT(ptr,a)
2386
1998
2387−-- | Use the 'createOf' fold instead.
1999+-- | Use the 'writeN' fold instead.
2388--
2000--
2389−-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2001+-- >>> fromStreamDN n = Stream.fold (MutArray.writeN n)
2390--
2002--
2391−{-# INLINE_NORMAL fromStreamN #-}
2392−fromStreamN :: forall m a. (MonadIO m, Unbox a)
2393− => Int -> D.Stream m a -> m (MutArray a)
2394−-- fromStreamDN n = D.fold (createOf n)
2395−fromStreamN = fromStreamDNAs Unpinned
2396−
2397−{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2398−{-# INLINE fromStreamDN #-}
2003+{-# INLINE_NORMAL fromStreamDN #-}
2399fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2004fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2400 => Int -> D.Stream m a -> m (MutArray a)
2005 => Int -> D.Stream m a -> m (MutArray a)
2006+-- fromStreamDN n = D.fold (writeN n)
2401−fromStreamDN = fromStreamN
2007+fromStreamDN = fromStreamDNAs Unpinned
2402
2008
2403-- | Create a 'MutArray' from the first N elements of a list. The array is
2009-- | Create a 'MutArray' from the first N elements of a list. The array is
2404-- allocated to size N, if the list terminates before N elements then the
2010-- allocated to size N, if the list terminates before N elements then the
@@ -2418,70 +2024,16 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
2418-- /Pre-release/
2024-- /Pre-release/
2419{-# INLINE fromListRevN #-}
2025{-# INLINE fromListRevN #-}
2420fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2026fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2421−fromListRevN n xs = D.fold (revCreateOf n) $ D.fromList xs
2027+fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
2422−
2423−-- | Convert a pure stream in Identity monad to a mutable array.
2424−{-# INLINABLE fromPureStreamN #-}
2425−fromPureStreamN :: (MonadIO m, Unbox a) =>
2426− Int -> Stream Identity a -> m (MutArray a)
2427−fromPureStreamN n xs =
2428− D.fold (createOf n) $ D.morphInner (return . runIdentity) xs
2429
2028
2430-- | Convert a pure stream in Identity monad to a mutable array.
2029-- | Convert a pure stream in Identity monad to a mutable array.
2431{-# INLINABLE fromPureStream #-}
2030{-# INLINABLE fromPureStream #-}
2432fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2031fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2433fromPureStream xs =
2032fromPureStream xs =
2434− D.fold create $ D.morphInner (return . runIdentity) xs
2033+ liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
2435−
2436−{-# INLINABLE fromPtrN #-}
2437−fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
2438−fromPtrN len addr = do
2439− -- memcpy is better than stream copy when the size is known.
2440− -- XXX We can implement a stream copy in a similar way by streaming Word64
2441− -- first and then remaining Word8.
2442− arr <- new len
2443− _ <- unsafeAsPtr arr
2444− (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
2445− return (arr {arrEnd = len})
2446−
2447−{-# INLINABLE fromByteStr# #-}
2448−fromByteStr# :: MonadIO m => Addr# -> m (MutArray Word8)
2449−fromByteStr# addr = do
2450− -- It is better to count the size first and allocate exact space.
2451− -- Also, memcpy is better than stream copy when the size is known.
2452− -- C strlen compares 4 bytes at a time, so is better than the stream
2453− -- version. https://github.com/bminor/glibc/blob/master/string/strlen.c
2454− -- XXX We can possibly use a stream of Word64 to do the same.
2455− -- fromByteStr# addr = fromPureStream (D.fromByteStr# addr)
2456− len <- liftIO $ c_strlen (Ptr addr)
2457− let lenInt = fromIntegral len
2458− arr <- new lenInt
2459− _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2460− return (arr {arrEnd = lenInt})
2461
2034
2462-------------------------------------------------------------------------------
2035-------------------------------------------------------------------------------
2463−-- convert a stream of arrays to a single array by reallocating and copying
2464−-------------------------------------------------------------------------------
2465−
2466−-- XXX Both of these implementations of splicing seem to perform equally well.
2467−-- We need to perform benchmarks over a range of sizes though.
2468−
2469−-- | Also see 'fromChunksK'.
2470−{-# INLINE fromChunksRealloced #-}
2471−fromChunksRealloced :: forall m a. (MonadIO m, Unbox a)
2472− => Stream m (MutArray a) -> m (MutArray a)
2473−fromChunksRealloced s = do
2474− res <- D.uncons s
2475− case res of
2476− Just (a, strm) -> do
2477− arr <- D.foldlM' spliceExp (pure a) strm
2478− -- Reallocation is exponential so there may be 50% empty space in
2479− -- worst case. One more reallocation to reclaim the space.
2480− rightSize arr
2481− Nothing -> pure nil
2482−
2483−-------------------------------------------------------------------------------
2484−-- convert a stream of arrays to a single array by buffering arrays first
2036+-- convert stream to a single array
2485-------------------------------------------------------------------------------
2037-------------------------------------------------------------------------------
2486
2038
2487{-# INLINE arrayStreamKLength #-}
2039{-# INLINE arrayStreamKLength #-}
@@ -2491,72 +2043,34 @@ arrayStreamKLength as = K.foldl' (+) 0 (K.map length as)
2491-- | Convert an array stream to an array. Note that this requires peak memory
2043-- | Convert an array stream to an array. Note that this requires peak memory
2492-- that is double the size of the array stream.
2044-- that is double the size of the array stream.
2493--
2045--
2494−{-# INLINE fromChunkskAs #-}
2495−fromChunkskAs :: (Unbox a, MonadIO m) =>
2496− PinnedState -> StreamK m (MutArray a) -> m (MutArray a)
2497−fromChunkskAs ps as = do
2498− len <- arrayStreamKLength as
2499− arr <- newAs ps len
2500− -- XXX is StreamK fold faster or StreamD fold?
2501− K.foldlM' spliceUnsafe (pure arr) as
2502− -- fromStreamDN len $ D.unfoldMany reader $ D.fromStreamK as
2503−
2504−-- XXX Need to compare this with fromChunks and fromChunkList and keep the
2505−-- fastest or simplest one if all are equally fast.
2506−
2507−-- | Convert an array stream to an array. Note that this requires peak memory
2508−-- that is double the size of the array stream.
2509−--
2510−-- Also see 'fromChunksRealloced'.
2511−--
2512−{-# INLINE fromChunksK #-}
2513−fromChunksK :: (Unbox a, MonadIO m) =>
2514− StreamK m (MutArray a) -> m (MutArray a)
2515−fromChunksK = fromChunkskAs Unpinned
2516−
2517−{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2518{-# INLINE fromArrayStreamK #-}
2046{-# INLINE fromArrayStreamK #-}
2519fromArrayStreamK :: (Unbox a, MonadIO m) =>
2047fromArrayStreamK :: (Unbox a, MonadIO m) =>
2520 StreamK m (MutArray a) -> m (MutArray a)
2048 StreamK m (MutArray a) -> m (MutArray a)
2521−fromArrayStreamK = fromChunksK
2049+fromArrayStreamK as = do
2050+ len <- arrayStreamKLength as
2051+ fromStreamDN len $ D.unfoldMany reader $ D.fromStreamK as
2522
2052
2523{-# INLINE fromStreamDAs #-}
2053{-# INLINE fromStreamDAs #-}
2524fromStreamDAs ::
2054fromStreamDAs ::
2525 (MonadIO m, Unbox a) => PinnedState -> D.Stream m a -> m (MutArray a)
2055 (MonadIO m, Unbox a) => PinnedState -> D.Stream m a -> m (MutArray a)
2526−fromStreamDAs ps m =
2527− arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2056+fromStreamDAs ps m = arrayStreamKFromStreamDAs ps m >>= fromArrayStreamK
2528
2057
2529−-- | Create an 'Array' from a stream. This is useful when we want to create a
2530−-- single array from a stream of unknown size. 'createOf' is at least twice
2531−-- as efficient when the size is already known.
2532−--
2533−-- Note that if the input stream is too large memory allocation for the array
2534−-- may fail. When the stream size is not known, `chunksOf` followed by
2535−-- processing of indvidual arrays in the resulting stream should be preferred.
2536−--
2537−-- /Pre-release/
2538−{-# INLINE fromStream #-}
2539−fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
2540−fromStream = fromStreamDAs Unpinned
2541−
2542−-- fromStream (Stream m) = P.fold create m
2543-- CAUTION: a very large number (millions) of arrays can degrade performance
2058-- CAUTION: a very large number (millions) of arrays can degrade performance
2544-- due to GC overhead because we need to buffer the arrays before we flatten
2059-- due to GC overhead because we need to buffer the arrays before we flatten
2545-- all the arrays.
2060-- all the arrays.
2546--
2061--
2547−-- XXX Compare if this is faster or "fold create".
2062+-- XXX Compare if this is faster or "fold write".
2548--
2063--
2549-- | We could take the approach of doubling the memory allocation on each
2064-- | We could take the approach of doubling the memory allocation on each
2550-- overflow. This would result in more or less the same amount of copying as in
2065-- overflow. This would result in more or less the same amount of copying as in
2551-- the chunking approach. However, if we have to shrink in the end then it may
2066-- the chunking approach. However, if we have to shrink in the end then it may
2552-- result in an extra copy of the entire data.
2067-- result in an extra copy of the entire data.
2553--
2068--
2554−-- >>> fromStreamD = StreamD.fold MutArray.create
2069+-- >>> fromStreamD = StreamD.fold MutArray.write
2555--
2070--
2556{-# INLINE fromStreamD #-}
2071{-# INLINE fromStreamD #-}
2557−{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
2558fromStreamD :: (MonadIO m, Unbox a) => D.Stream m a -> m (MutArray a)
2072fromStreamD :: (MonadIO m, Unbox a) => D.Stream m a -> m (MutArray a)
2559−fromStreamD = fromStream
2073+fromStreamD = fromStreamDAs Unpinned
2560
2074
2561-- | Create a 'MutArray' from a list. The list must be of finite size.
2075-- | Create a 'MutArray' from a list. The list must be of finite size.
2562--
2076--
@@ -2581,44 +2095,22 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
2581-- Cloning
2095-- Cloning
2582-------------------------------------------------------------------------------
2096-------------------------------------------------------------------------------
2583
2097
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−
2588{-# INLINE cloneAs #-}
2098{-# INLINE cloneAs #-}
2589−cloneAs ::
2590− ( MonadIO m
2591−#ifdef DEVBUILD
2592− , Unbox a
2593−#endif
2594− )
2595− => PinnedState -> MutArray a -> m (MutArray a)
2099+cloneAs :: MonadIO m => PinnedState -> MutArray a -> m (MutArray a)
2596cloneAs ps src =
2100cloneAs ps src =
2597− do
2101+ liftIO $ do
2598 let startSrc = arrStart src
2102 let startSrc = arrStart src
2599 srcLen = arrEnd src - startSrc
2103 srcLen = arrEnd src - startSrc
2600− newArrContents <-
2104+ newArrContents <- Unboxed.newBytesAs ps srcLen
2601− Unboxed.cloneSliceUnsafeAs ps startSrc srcLen (arrContents src)
2105+ putSliceUnsafe (arrContents src) startSrc newArrContents 0 srcLen
2602 return $ MutArray newArrContents 0 srcLen srcLen
2106 return $ MutArray newArrContents 0 srcLen srcLen
2603
2107
2604{-# INLINE clone #-}
2108{-# INLINE clone #-}
2605−clone ::
2606− ( MonadIO m
2607−#ifdef DEVBUILD
2608− , Unbox a
2609−#endif
2610− )
2611− => MutArray a -> m (MutArray a)
2109+clone :: MonadIO m => MutArray a -> m (MutArray a)
2612clone = cloneAs Unpinned
2110clone = cloneAs Unpinned
2613
2111
2614{-# INLINE pinnedClone #-}
2112{-# INLINE pinnedClone #-}
2615−pinnedClone ::
2616− ( MonadIO m
2617−#ifdef DEVBUILD
2618− , Unbox a
2619−#endif
2620− )
2621− => MutArray a -> m (MutArray a)
2113+pinnedClone :: MonadIO m => MutArray a -> m (MutArray a)
2622pinnedClone = cloneAs Pinned
2114pinnedClone = cloneAs Pinned
2623
2115
2624-------------------------------------------------------------------------------
2116-------------------------------------------------------------------------------
@@ -2633,16 +2125,17 @@ spliceCopy :: forall m a. MonadIO m =>
2633 Unbox a =>
2125 Unbox a =>
2634#endif
2126#endif
2635 MutArray a -> MutArray a -> m (MutArray a)
2127 MutArray a -> MutArray a -> m (MutArray a)
2636−spliceCopy arr1 arr2 = do
2128+spliceCopy arr1 arr2 = liftIO $ do
2637 let start1 = arrStart arr1
2129 let start1 = arrStart arr1
2638 start2 = arrStart arr2
2130 start2 = arrStart arr2
2639 len1 = arrEnd arr1 - start1
2131 len1 = arrEnd arr1 - start1
2640 len2 = arrEnd arr2 - start2
2132 len2 = arrEnd arr2 - start2
2641− let len = len1 + len2
2133+ let newLen = len1 + len2
2642 newArrContents <-
2134 newArrContents <-
2643 if Unboxed.isPinned (arrContents arr1)
2135 if Unboxed.isPinned (arrContents arr1)
2644− then liftIO $ Unboxed.pinnedNew len
2136+ then Unboxed.pinnedNewBytes newLen
2645− else liftIO $ Unboxed.new len
2137+ else Unboxed.newBytes newLen
2138+ let len = len1 + len2
2646 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2139 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2647 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2140 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2648 return $ MutArray newArrContents 0 len len
2141 return $ MutArray newArrContents 0 len len
@@ -2654,7 +2147,7 @@ spliceCopy arr1 arr2 = do
2654spliceUnsafe :: MonadIO m =>
2147spliceUnsafe :: MonadIO m =>
2655 MutArray a -> MutArray a -> m (MutArray a)
2148 MutArray a -> MutArray a -> m (MutArray a)
2656spliceUnsafe dst src =
2149spliceUnsafe dst src =
2657− do
2150+ liftIO $ do
2658 let startSrc = arrStart src
2151 let startSrc = arrStart src
2659 srcLen = arrEnd src - startSrc
2152 srcLen = arrEnd src - startSrc
2660 endDst = arrEnd dst
2153 endDst = arrEnd dst
@@ -2676,7 +2169,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
2676 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2169 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2677spliceWith sizer dst@(MutArray _ start end bound) src = do
2170spliceWith sizer dst@(MutArray _ start end bound) src = do
2678{-
2171{-
2679− let f = appendWith (`sizer` byteLength src) (return dst)
2172+ let f = writeAppendWith (`sizer` byteLength src) (return dst)
2680 in D.fold f (toStreamD src)
2173 in D.fold f (toStreamD src)
2681-}
2174-}
2682 assert (end <= bound) (return ())
2175 assert (end <= bound) (return ())
@@ -2692,7 +2185,7 @@ spliceWith sizer dst@(MutArray _ start end bound) src = do
2692 $ "splice: newSize is less than the total size "
2185 $ "splice: newSize is less than the total size "
2693 ++ "of arrays being appended. Please check the "
2186 ++ "of arrays being appended. Please check the "
2694 ++ "sizer function passed."
2187 ++ "sizer function passed."
2695− realloc newSizeInBytes dst
2188+ liftIO $ realloc newSizeInBytes dst
2696 else return dst
2189 else return dst
2697 spliceUnsafe dst1 src
2190 spliceUnsafe dst1 src
2698
2191
@@ -2729,24 +2222,14 @@ spliceExp = spliceWith (\l1 l2 -> max (l1 * 2) (l1 + l2))
2729-- Splitting
2222-- Splitting
2730-------------------------------------------------------------------------------
2223-------------------------------------------------------------------------------
2731
2224
2732−-- | Generate a stream of array slices using a predicate. The array element
2733−-- matching the predicate is dropped.
2734−--
2735−-- /Pre-release/
2736−{-# INLINE splitOn #-}
2737−splitOn :: (MonadIO m, Unbox a) =>
2738− (a -> Bool) -> MutArray a -> Stream m (MutArray a)
2739−splitOn predicate arr =
2740− fmap (\(i, len) -> getSliceUnsafe i len arr)
2741− $ D.indexOnSuffix predicate (read arr)
2742−
2743-- | Drops the separator byte
2225-- | Drops the separator byte
2744{-# INLINE breakOn #-}
2226{-# INLINE breakOn #-}
2745breakOn :: MonadIO m
2227breakOn :: MonadIO m
2746 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2228 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2747−breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2229+breakOn sep arr@MutArray{..} = asPtrUnsafe arr $ \p -> liftIO $ do
2230+ -- XXX Instead of using asPtrUnsafe (pinning memory) we can pass unlifted
2231+ -- Addr# to memchr and it should be safe (from ghc 8.4).
2748 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2232 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2749− -- Need efficient stream based primitives that work on Word64.
2750 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2233 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2751 let sepIndex = loc `minusPtr` p
2234 let sepIndex = loc `minusPtr` p
2752 return $
2235 return $
@@ -2767,41 +2250,32 @@ breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2767 }
2250 }
2768 )
2251 )
2769
2252
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−
2792-- | Create two slices of an array without copying the original array. The
2253-- | Create two slices of an array without copying the original array. The
2793-- specified index @i@ is the first index of the second slice.
2254-- specified index @i@ is the first index of the second slice.
2794--
2255--
2795−{-# INLINE splitAt #-}
2796splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2256splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2797−splitAt i arr =
2257+splitAt i arr@MutArray{..} =
2798 let maxIndex = length arr - 1
2258 let maxIndex = length arr - 1
2799 in if i < 0
2259 in if i < 0
2800 then error "sliceAt: negative array index"
2260 then error "sliceAt: negative array index"
2801 else if i > maxIndex
2261 else if i > maxIndex
2802 then error $ "sliceAt: specified array index " ++ show i
2262 then error $ "sliceAt: specified array index " ++ show i
2803 ++ " is beyond the maximum index " ++ show maxIndex
2263 ++ " is beyond the maximum index " ++ show maxIndex
2804− else unsafeSplitAt i arr
2264+ else let off = i * SIZE_OF(a)
2265+ p = arrStart + off
2266+ in ( MutArray
2267+ { arrContents = arrContents
2268+ , arrStart = arrStart
2269+ , arrEnd = p
2270+ , arrBound = p
2271+ }
2272+ , MutArray
2273+ { arrContents = arrContents
2274+ , arrStart = p
2275+ , arrEnd = arrEnd
2276+ , arrBound = arrBound
2277+ }
2278+ )
2805
2279
2806-------------------------------------------------------------------------------
2280-------------------------------------------------------------------------------
2807-- Casting
2281-- Casting
@@ -2851,16 +2325,13 @@ cast arr =
2851-- guarantees that unsafe calls will be performed in the calling thread. Making
2325-- guarantees that unsafe calls will be performed in the calling thread. Making
2852-- it safe to pass heap-allocated objects to unsafe functions.
2326-- it safe to pass heap-allocated objects to unsafe functions.
2853
2327
2328+-- Unsafe because of direct pointer operations. The user must ensure that they
2329+-- are writing within the legal bounds of the array. Should we just name it
2854−-- XXX Should we just name it asPtr, the unsafety is implicit for any pointer
2330+-- asPtr, the unsafety is implicit for any pointer operations. And we are safe
2855−-- operations. And we are safe from Haskell perspective because we will be
2331+-- from Haskell perspective because we will be 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.
2861
2332
2862−-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
2333+-- | Use an @MutArray a@ as @Ptr a@. This is useful when we want to pass an array
2863−-- array as a pointer to some operating system call or to a "safe" FFI call.
2334+-- as a pointer to some operating system call or to a "safe" FFI call.
2864--
2335--
2865-- If the array is not pinned it is copied to pinned memory before passing it
2336-- If the array is not pinned it is copied to pinned memory before passing it
2866-- to the monadic action.
2337-- to the monadic action.
@@ -2870,382 +2341,56 @@ cast arr =
2870-- opportunistically before this operation occurs, to avoid the cost of a copy
2341-- opportunistically before this operation occurs, to avoid the cost of a copy
2871-- if possible.
2342-- if possible.
2872--
2343--
2873−-- /Unsafe/ because of direct pointer operations. The user must ensure that
2344+-- /Unsafe/
2874−-- they are writing within the legal bounds of the array.
2875--
2345--
2876-- /Pre-release/
2346-- /Pre-release/
2877--
2347--
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." #-}
2885−{-# INLINE asPtrUnsafe #-}
2886asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2348asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2887−asPtrUnsafe = unsafePinnedAsPtr
2349+asPtrUnsafe arr f = do
2350+ contents <- liftIO $ Unboxed.pin $ arrContents arr
2351+ let !ptr = Ptr (byteArrayContents#
2352+ (unsafeCoerce# (getMutableByteArray# contents)))
2888
2353
2889−{-# INLINE unsafeAsPtr #-}
2890−unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2891−unsafeAsPtr arr f =
2892− Unboxed.unsafeAsPtr
2893− (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2354+ r <- f (ptr `plusPtr` arrStart arr)
2355+ liftIO $ touch contents
2356+ return r
2894
2357
2895-------------------------------------------------------------------------------
2358-------------------------------------------------------------------------------
2896-- Equality
2359-- Equality
2897-------------------------------------------------------------------------------
2360-------------------------------------------------------------------------------
2898
2361
2899−-- | Byte compare two arrays. Compare the length of the arrays. If the length
2362+-- | Compare the length of the arrays. If the length is equal, compare the
2900−-- is equal, compare the lexicographical ordering of two underlying byte arrays
2363+-- lexicographical ordering of two underlying byte arrays otherwise return the
2901−-- otherwise return the result of length comparison.
2364+-- result of length comparison.
2902−--
2903−-- /Unsafe/: Note that the 'Unbox' instance of sum types with constructors of
2904−-- different sizes may leave some memory uninitialized which can make byte
2905−-- comparison unreliable.
2906--
2365--
2907-- /Pre-release/
2366-- /Pre-release/
2908−{-# INLINE byteCmp #-}
2909−byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2910−byteCmp arr1 arr2 = do
2911− let marr1 = getMutableByteArray# (arrContents arr1)
2912− marr2 = getMutableByteArray# (arrContents arr2)
2913− !(I# st1#) = arrStart arr1
2914− !(I# st2#) = arrStart arr2
2915− !(I# len#) = byteLength arr1
2916− case compare (byteLength arr1) (byteLength arr2) of
2917− EQ -> do
2918− r <- liftIO $ IO $ \s# ->
2919− let res =
2920− I#
2921− (compareByteArrays#
2922− (unsafeCoerce# marr1)
2923− st1#
2924− (unsafeCoerce# marr2)
2925− st2#
2926− len#)
2927− in (# s#, res #)
2928− return $ compare r 0
2929− x -> return x
2930−
2931{-# INLINE cmp #-}
2367{-# INLINE cmp #-}
2932−{-# DEPRECATED cmp "Please use byteCmp instead." #-}
2933cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2368cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2934−cmp = byteCmp
2369+cmp arr1 arr2 =
2935−
2370+ liftIO
2936−-- | Byte equality of two arrays.
2371+ $ do
2937−--
2372+ let marr1 = getMutableByteArray# (arrContents arr1)
2938−-- >>> byteEq arr1 arr2 = (==) EQ $ MArray.byteCmp arr1 arr2
2373+ marr2 = getMutableByteArray# (arrContents arr2)
2939−--
2374+ !(I# st1#) = arrStart arr1
2940−-- /Unsafe/: See 'byteCmp'.
2375+ !(I# st2#) = arrStart arr2
2941−{-# INLINE byteEq #-}
2376+ !(I# len#) = byteLength arr1
2942−byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
2377+ case compare (byteLength arr1) (byteLength arr2) of
2943−byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2378+ EQ -> do
2944−
2379+ r <- liftIO $ IO $ \s# ->
2945−-------------------------------------------------------------------------------
2380+ let res =
2946−-- Compact
2381+ I#
2947−-------------------------------------------------------------------------------
2382+ (compareByteArrays#
2948−
2383+ (unsafeCoerce# marr1)
2949−-- Note: LE versions avoid an extra copy compared to GE. LE parser trades
2384+ st1#
2950−-- backtracking one array in lieu of avoiding a copy. However, LE and GE both
2385+ (unsafeCoerce# marr2)
2951−-- can leave some memory unused. They can split the last array to fit it
2386+ st2#
2952−-- exactly in the space.
2387+ len#)
2953−
2388+ in (# s#, res #)
2954−{-# INLINE_NORMAL pCompactLeAs #-}
2389+ return $ compare r 0
2955−pCompactLeAs ::
2390+ x -> return x
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
2391
3247-------------------------------------------------------------------------------
2392-------------------------------------------------------------------------------
3248−-- In-place mutation algorithms
2393+-- NFData
3249-------------------------------------------------------------------------------
2394-------------------------------------------------------------------------------
3250
2395
3251-- | Strip elements which match with predicate from both ends.
2396-- | Strip elements which match with predicate from both ends.
@@ -3274,7 +2419,7 @@ strip eq arr@MutArray{..} = liftIO $ do
3274 getStart cur = do
2419 getStart cur = do
3275 if cur < arrEnd
2420 if cur < arrEnd
3276 then do
2421 then do
3277− r <- peekAt cur arrContents
2422+ r <- peekByteIndex cur arrContents
3278 if eq r
2423 if eq r
3279 then getStart (INDEX_NEXT(cur,a))
2424 then getStart (INDEX_NEXT(cur,a))
3280 else return cur
2425 else return cur
@@ -3284,7 +2429,7 @@ strip eq arr@MutArray{..} = liftIO $ do
3284 if cur > low
2429 if cur > low
3285 then do
2430 then do
3286 let prev = INDEX_PREV(cur,a)
2431 let prev = INDEX_PREV(cur,a)
3287− r <- peekAt prev arrContents
2432+ r <- peekByteIndex prev arrContents
3288 if eq r
2433 if eq r
3289 then getLast prev low
2434 then getLast prev low
3290 else return cur
2435 else return cur
core/src/Streamly/Internal/Data/MutByteArray.hsdeleted−251
@@ -1,251 +0,0 @@
1−{-# LANGUAGE TemplateHaskell #-}
2−
3−-- This is required as all the instances in this module are orphan instances.
4−{-# OPTIONS_GHC -fno-warn-orphans #-}
5−
6−-- |
7−-- Module : Streamly.Internal.Data.MutByteArray
8−-- Copyright : (c) 2023 Composewell Technologies
9−-- License : BSD3-3-Clause
10−-- Maintainer : streamly@composewell.com
11−-- Portability : GHC
12−--
13−
14−module Streamly.Internal.Data.MutByteArray
15− (
16− -- * MutByteArray
17− module Streamly.Internal.Data.MutByteArray.Type
18− -- * Unbox
19− , module Streamly.Internal.Data.Unbox
20− , module Streamly.Internal.Data.Unbox.TH
21− -- * Serialize
22− , module Streamly.Internal.Data.Serialize.Type
23− -- * Serialize TH
24− , module Streamly.Internal.Data.Serialize.TH
25− ) where
26−
27−--------------------------------------------------------------------------------
28−-- Imports
29−--------------------------------------------------------------------------------
30−
31−import Data.Proxy (Proxy(..))
32−import Streamly.Internal.Data.Array (Array(..))
33−import GHC.Exts (Int(..), sizeofByteArray#, unsafeCoerce#)
34−import GHC.Word (Word8)
35−
36−#if __GLASGOW_HASKELL__ >= 900
37−import GHC.Num.Integer (Integer(..))
38−#else
39−import GHC.Integer.GMP.Internals (Integer(..), BigNat(..))
40−#endif
41−
42−import Streamly.Internal.Data.MutByteArray.Type
43−import Streamly.Internal.Data.Serialize.TH
44−import Streamly.Internal.Data.Serialize.Type
45−import Streamly.Internal.Data.Unbox
46−import Streamly.Internal.Data.Unbox.TH
47−
48−--------------------------------------------------------------------------------
49−-- Common instances
50−--------------------------------------------------------------------------------
51−
52−-- Note
53−-- ====
54−--
55−-- Even a non-functional change such as changing the order of constructors will
56−-- change the instance derivation.
57−--
58−-- This will not pose a problem if both, encode, and decode are done by the same
59−-- version of the application. There *might* be a problem if version that
60−-- encodes differs from the version that decodes.
61−--
62−-- We need to add some compatibility tests using different versions of
63−-- dependencies.
64−--
65−-- Although such chages for the most basic types won't happen we need to detect
66−-- if it ever happens.
67−--
68−-- Should we worry about these kind of changes and this kind of compatibility?
69−-- This is a problem for all types of derivations that depend on the order of
70−-- constructors, for example, Enum.
71−
72−-- Note on Windows build
73−-- =====================
74−--
75−-- On Windows, having template haskell splices here fail the build with the
76−-- following error:
77−--
78−-- @
79−-- addLibrarySearchPath: C:\... (Win32 error 3): The system cannot find the path specified.
80−-- @
81−--
82−-- The error might be irrelavant but having these splices triggers it. We should
83−-- either fix the problem or avoid the use to template haskell splices in this
84−-- file.
85−--
86−-- Similar issue: https://github.com/haskell/cabal/issues/4741
87−
88−-- $(Serialize.deriveSerialize ''Maybe)
89−instance Serialize a => Serialize (Maybe a) where
90−
91− {-# INLINE addSizeTo #-}
92− addSizeTo acc x =
93− case x of
94− Nothing -> (acc + 1)
95− Just field0 -> (addSizeTo (acc + 1)) field0
96−
97− {-# INLINE deserializeAt #-}
98− deserializeAt initialOffset arr endOffset = do
99− (i0, tag) <- ((deserializeAt initialOffset) arr) endOffset
100− case tag :: Word8 of
101− 0 -> pure (i0, Nothing)
102− 1 -> do (i1, a0) <- ((deserializeAt i0) arr) endOffset
103− pure (i1, Just a0)
104− _ -> error "Found invalid tag while peeking (Maybe a)"
105−
106− {-# INLINE serializeAt #-}
107− serializeAt initialOffset arr val =
108− case val of
109− Nothing -> do
110− i0 <- ((serializeAt initialOffset) arr) (0 :: Word8)
111− pure i0
112− Just field0 -> do
113− i0 <- ((serializeAt initialOffset) arr) (1 :: Word8)
114− i1 <- ((serializeAt i0) arr) field0
115− pure i1
116−
117−-- $(Serialize.deriveSerialize ''Either)
118−instance (Serialize a, Serialize b) => Serialize (Either a b) where
119−
120− {-# INLINE addSizeTo #-}
121− addSizeTo acc x =
122− case x of
123− Left field0 -> (addSizeTo (acc + 1)) field0
124− Right field0 -> (addSizeTo (acc + 1)) field0
125−
126− {-# INLINE deserializeAt #-}
127− deserializeAt initialOffset arr endOffset = do
128− (i0, tag) <- ((deserializeAt initialOffset) arr) endOffset
129− case tag :: Word8 of
130− 0 -> do (i1, a0) <- ((deserializeAt i0) arr) endOffset
131− pure (i1, Left a0)
132− 1 -> do (i1, a0) <- ((deserializeAt i0) arr) endOffset
133− pure (i1, Right a0)
134− _ -> error "Found invalid tag while peeking (Either a b)"
135−
136− {-# INLINE serializeAt #-}
137− serializeAt initialOffset arr val =
138− case val of
139− Left field0 -> do
140− i0 <- ((serializeAt initialOffset) arr) (0 :: Word8)
141− i1 <- ((serializeAt i0) arr) field0
142− pure i1
143− Right field0 -> do
144− i0 <- ((serializeAt initialOffset) arr) (1 :: Word8)
145− i1 <- ((serializeAt i0) arr) field0
146− pure i1
147−
148−instance Serialize (Proxy a) where
149−
150− {-# INLINE addSizeTo #-}
151− addSizeTo acc _ = (acc + 1)
152−
153− {-# INLINE deserializeAt #-}
154− deserializeAt initialOffset _ _ = pure ((initialOffset + 1), Proxy)
155−
156− {-# INLINE serializeAt #-}
157− serializeAt initialOffset _ _ = pure (initialOffset + 1)
158−
159−--------------------------------------------------------------------------------
160−-- Integer
161−--------------------------------------------------------------------------------
162−
163−data LiftedInteger
164− = LIS Int
165− | LIP (Array Word)
166− | LIN (Array Word)
167−
168−-- $(Serialize.deriveSerialize ''LiftedInteger)
169−instance Serialize LiftedInteger where
170−
171− {-# INLINE addSizeTo #-}
172− addSizeTo acc x =
173− case x of
174− LIS field0 -> (addSizeTo (acc + 1)) field0
175− LIP field0 -> (addSizeTo (acc + 1)) field0
176− LIN field0 -> (addSizeTo (acc + 1)) field0
177−
178− {-# INLINE deserializeAt #-}
179− deserializeAt initialOffset arr endOffset = do
180− (i0, tag) <- ((deserializeAt initialOffset) arr) endOffset
181− case tag :: Word8 of
182− 0 -> do (i1, a0) <- ((deserializeAt i0) arr) endOffset
183− pure (i1, LIS a0)
184− 1 -> do (i1, a0) <- ((deserializeAt i0) arr) endOffset
185− pure (i1, LIP a0)
186− 2 -> do (i1, a0) <- ((deserializeAt i0) arr) endOffset
187− pure (i1, LIN a0)
188− _ -> error "Found invalid tag while peeking (LiftedInteger)"
189−
190− {-# INLINE serializeAt #-}
191− serializeAt initialOffset arr val =
192− case val of
193− LIS field0 -> do
194− i0 <- ((serializeAt initialOffset) arr) (0 :: Word8)
195− i1 <- ((serializeAt i0) arr) field0
196− pure i1
197− LIP field0 -> do
198− i0 <- ((serializeAt initialOffset) arr) (1 :: Word8)
199− i1 <- ((serializeAt i0) arr) field0
200− pure i1
201− LIN field0 -> do
202− i0 <- ((serializeAt initialOffset) arr) (2 :: Word8)
203− i1 <- ((serializeAt i0) arr) field0
204− pure i1
205−
206−#if __GLASGOW_HASKELL__ >= 900
207−
208−{-# INLINE liftInteger #-}
209−liftInteger :: Integer -> LiftedInteger
210−liftInteger (IS x) = LIS (I# x)
211−liftInteger (IP x) =
212− LIP (Array (MutByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
213−liftInteger (IN x) =
214− LIN (Array (MutByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
215−
216−{-# INLINE unliftInteger #-}
217−unliftInteger :: LiftedInteger -> Integer
218−unliftInteger (LIS (I# x)) = IS x
219−unliftInteger (LIP (Array (MutByteArray x) _ _)) = IP (unsafeCoerce# x)
220−unliftInteger (LIN (Array (MutByteArray x) _ _)) = IN (unsafeCoerce# x)
221−
222−#else
223−
224−{-# INLINE liftInteger #-}
225−liftInteger :: Integer -> LiftedInteger
226−liftInteger (S# x) = LIS (I# x)
227−liftInteger (Jp# (BN# x)) =
228− LIP (Array (MutByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
229−liftInteger (Jn# (BN# x)) =
230− LIN (Array (MutByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
231−
232−{-# INLINE unliftInteger #-}
233−unliftInteger :: LiftedInteger -> Integer
234−unliftInteger (LIS (I# x)) = S# x
235−unliftInteger (LIP (Array (MutByteArray x) _ _)) =
236− Jp# (BN# (unsafeCoerce# x))
237−unliftInteger (LIN (Array (MutByteArray x) _ _)) =
238− Jn# (BN# (unsafeCoerce# x))
239−
240−#endif
241−
242−instance Serialize Integer where
243− {-# INLINE addSizeTo #-}
244− addSizeTo i a = addSizeTo i (liftInteger a)
245−
246− {-# INLINE deserializeAt #-}
247− deserializeAt off arr end =
248− fmap unliftInteger <$> deserializeAt off arr end
249−
250− {-# INLINE serializeAt #-}
251− serializeAt off arr val = serializeAt off arr (liftInteger val)
core/src/Streamly/Internal/Data/MutByteArray/Type.hsdeleted−321
@@ -1,321 +0,0 @@
1−{-# LANGUAGE UnboxedTuples #-}
2−
3−-- |
4−-- Module : Streamly.Internal.Data.MutByteArray.Type
5−-- Copyright : (c) 2023 Composewell Technologies
6−-- License : BSD3-3-Clause
7−-- Maintainer : streamly@composewell.com
8−-- Stability : experimental
9−-- Portability : GHC
10−--
11−module Streamly.Internal.Data.MutByteArray.Type
12− (
13− -- ** MutByteArray
14− MutByteArray(..)
15− , MutableByteArray
16− , getMutableByteArray# -- XXX getMutByteArray#
17−
18− -- ** Pinning
19− , PinnedState(..)
20− , isPinned
21− , pin
22− , unpin
23−
24− -- ** Allocation
25− , empty
26− , newBytesAs -- XXX should be removed
27− , new
28− , pinnedNew
29− , pinnedNewAlignedBytes -- XXX should be removed
30−
31− -- ** Access
32− , sizeOfMutableByteArray -- XXX length
33− , putSliceUnsafe
34− , cloneSliceUnsafeAs
35− , cloneSliceUnsafe
36− , pinnedCloneSliceUnsafe
37− , unsafePinnedAsPtr
38− , unsafeAsPtr
39−
40− -- ** Deprecated
41− , asPtrUnsafe
42− , nil
43− ) where
44−
45−import Control.Monad.IO.Class (MonadIO(..))
46−#ifdef DEBUG
47−import Control.Monad (when)
48−import Debug.Trace (trace)
49−#endif
50−import GHC.Base (IO(..))
51−import System.IO.Unsafe (unsafePerformIO)
52−
53−import GHC.Exts
54−
55−--------------------------------------------------------------------------------
56−-- The ArrayContents type
57−--------------------------------------------------------------------------------
58−
59−data PinnedState
60− = Pinned
61− | Unpinned deriving (Show, Eq)
62−
63−-- XXX can use UnliftedNewtypes
64−
65−-- | A lifted mutable byte array type wrapping @MutableByteArray# RealWorld@.
66−-- This is a low level array used to back high level unboxed arrays and
67−-- serialized data.
68−data MutByteArray = MutByteArray (MutableByteArray# RealWorld)
69−
70−{-# DEPRECATED MutableByteArray "Please use MutByteArray instead" #-}
71−type MutableByteArray = MutByteArray
72−
73−{-# INLINE getMutableByteArray# #-}
74−getMutableByteArray# :: MutByteArray -> MutableByteArray# RealWorld
75−getMutableByteArray# (MutByteArray mbarr) = mbarr
76−
77−-- | Return the size of the array in bytes.
78−{-# INLINE sizeOfMutableByteArray #-}
79−sizeOfMutableByteArray :: MutByteArray -> IO Int
80−sizeOfMutableByteArray (MutByteArray arr) =
81− IO $ \s ->
82− case getSizeofMutableByteArray# arr s of
83− (# s1, i #) -> (# s1, I# i #)
84−
85−{-# INLINE touch #-}
86−touch :: MutByteArray -> IO ()
87−touch (MutByteArray contents) =
88− IO $ \s -> case touch# contents s of s' -> (# s', () #)
89−
90−-- XXX Some functions in this module are "IO" and others are "m", we need to
91−-- make it consistent.
92−
93−-- XXX We can provide another API for "unsafe" FFI calls passing an unlifted
94−-- pointer to the FFI call. For unsafe calls we do not need to pin the array.
95−-- We can pass an unlifted pointer to the FFI routine to avoid GC kicking in
96−-- before the pointer is wrapped.
97−--
98−-- From the GHC manual:
99−--
100−-- GHC, since version 8.4, guarantees that garbage collection will never occur
101−-- during an unsafe call, even in the bytecode interpreter, and further
102−-- guarantees that unsafe calls will be performed in the calling thread. Making
103−-- it safe to pass heap-allocated objects to unsafe functions.
104−
105−-- | Use a @MutByteArray@ as @Ptr a@. This is useful when we want to pass
106−-- an array as a pointer to some operating system call or to a "safe" FFI call.
107−--
108−-- If the array is not pinned it is copied to pinned memory before passing it
109−-- to the monadic action.
110−--
111−-- /Performance Notes:/ Forces a copy if the array is not pinned. It is advised
112−-- that the programmer keeps this in mind and creates a pinned array
113−-- opportunistically before this operation occurs, to avoid the cost of a copy
114−-- if possible.
115−--
116−-- /Unsafe/ because of direct pointer operations. The user must ensure that
117−-- they are writing within the legal bounds of the array.
118−--
119−-- /Pre-release/
120−--
121−{-# INLINE unsafePinnedAsPtr #-}
122−unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
123−unsafePinnedAsPtr arr f = do
124− contents <- liftIO $ pin arr
125− let !ptr = Ptr (byteArrayContents#
126− (unsafeCoerce# (getMutableByteArray# contents)))
127− r <- f ptr
128− liftIO $ touch contents
129− return r
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−
136−-- | For use with unsafe FFI functions. Does not force pin the array memory.
137−{-# INLINE unsafeAsPtr #-}
138−unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
139−unsafeAsPtr arr f = do
140− let !ptr = Ptr (byteArrayContents#
141− (unsafeCoerce# (getMutableByteArray# arr)))
142− r <- f ptr
143− liftIO $ touch arr
144− return r
145−
146−--------------------------------------------------------------------------------
147−-- Creation
148−--------------------------------------------------------------------------------
149−
150−{-# NOINLINE empty #-}
151−empty :: MutByteArray
152−empty = unsafePerformIO $ new 0
153−
154−{-# DEPRECATED nil "Please use empty instead" #-}
155−nil :: MutByteArray
156−nil = empty
157−
158−-- XXX add "newRounded" to round up the large size to the next page boundary
159−-- and return the allocated size.
160−{-# INLINE new #-}
161−new :: Int -> IO MutByteArray
162−new nbytes | nbytes < 0 =
163− errorWithoutStackTrace "newByteArray: size must be >= 0"
164−new (I# nbytes) = IO $ \s ->
165− case newByteArray# nbytes s of
166− (# s', mbarr# #) ->
167− let c = MutByteArray mbarr#
168− in (# s', c #)
169−
170−{-# INLINE pinnedNew #-}
171−pinnedNew :: Int -> IO MutByteArray
172−pinnedNew nbytes | nbytes < 0 =
173− errorWithoutStackTrace "pinnedNew: size must be >= 0"
174−pinnedNew (I# nbytes) = IO $ \s ->
175− case newPinnedByteArray# nbytes s of
176− (# s', mbarr# #) ->
177− let c = MutByteArray mbarr#
178− in (# s', c #)
179−
180−{-# INLINE pinnedNewAlignedBytes #-}
181−pinnedNewAlignedBytes :: Int -> Int -> IO MutByteArray
182−pinnedNewAlignedBytes nbytes _align | nbytes < 0 =
183− errorWithoutStackTrace "pinnedNewAlignedBytes: size must be >= 0"
184−pinnedNewAlignedBytes (I# nbytes) (I# align) = IO $ \s ->
185− case newAlignedPinnedByteArray# nbytes align s of
186− (# s', mbarr# #) ->
187− let c = MutByteArray mbarr#
188− in (# s', c #)
189−
190−{-# INLINE newBytesAs #-}
191−newBytesAs :: PinnedState -> Int -> IO MutByteArray
192−newBytesAs Unpinned = new
193−newBytesAs Pinned = pinnedNew
194−
195−-------------------------------------------------------------------------------
196−-- Copying
197−-------------------------------------------------------------------------------
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−
205−-- | Put a sub range of a source array into a subrange of a destination array.
206−-- This is not safe as it does not check the bounds of neither the src array
207−-- nor the destination array.
208−{-# INLINE putSliceUnsafe #-}
209−putSliceUnsafe ::
210− MonadIO m
211− => MutByteArray
212− -> Int
213− -> MutByteArray
214− -> Int
215− -> Int
216− -> m ()
217−putSliceUnsafe src srcStartBytes dst dstStartBytes lenBytes = liftIO $ do
218−#ifdef DEBUG
219− srcLen <- sizeOfMutableByteArray src
220− dstLen <- sizeOfMutableByteArray dst
221− when (srcLen - srcStartBytes < lenBytes)
222− $ error $ "putSliceUnsafe: src overflow: start" ++ show srcStartBytes
223− ++ " end " ++ show srcLen ++ " len " ++ show lenBytes
224− when (dstLen - dstStartBytes < lenBytes)
225− $ error $ "putSliceUnsafe: dst overflow: start" ++ show dstStartBytes
226− ++ " end " ++ show dstLen ++ " len " ++ show lenBytes
227−#endif
228− let !(I# srcStartBytes#) = srcStartBytes
229− !(I# dstStartBytes#) = dstStartBytes
230− !(I# lenBytes#) = lenBytes
231− let arrS# = getMutableByteArray# src
232− arrD# = getMutableByteArray# dst
233− IO $ \s# -> (# copyMutableByteArray#
234− arrS# srcStartBytes# arrD# dstStartBytes# lenBytes# s#
235− , () #)
236−
237−-- | Unsafe as it does not check whether the start offset and length supplied
238−-- are valid inside the array.
239−{-# INLINE cloneSliceUnsafeAs #-}
240−cloneSliceUnsafeAs :: MonadIO m =>
241− PinnedState -> Int -> Int -> MutByteArray -> m MutByteArray
242−cloneSliceUnsafeAs ps srcOff srcLen src =
243− liftIO $ do
244− mba <- newBytesAs ps srcLen
245− putSliceUnsafe src srcOff mba 0 srcLen
246− return mba
247−
248−-- | @cloneSliceUnsafe offset len arr@ clones a slice of the supplied array
249−-- starting at the given offset and equal to the given length.
250−{-# INLINE cloneSliceUnsafe #-}
251−cloneSliceUnsafe :: MonadIO m => Int -> Int -> MutByteArray -> m MutByteArray
252−cloneSliceUnsafe = cloneSliceUnsafeAs Unpinned
253−
254−-- | @pinnedCloneSliceUnsafe offset len arr@
255−{-# INLINE pinnedCloneSliceUnsafe #-}
256−pinnedCloneSliceUnsafe :: MonadIO m =>
257− Int -> Int -> MutByteArray -> m MutByteArray
258−pinnedCloneSliceUnsafe = cloneSliceUnsafeAs Pinned
259−
260−-------------------------------------------------------------------------------
261−-- Pinning & Unpinning
262−-------------------------------------------------------------------------------
263−
264−-- | Return 'True' if the array is allocated in pinned memory.
265−{-# INLINE isPinned #-}
266−isPinned :: MutByteArray -> Bool
267−isPinned (MutByteArray arr#) =
268− let pinnedInt = I# (isMutableByteArrayPinned# arr#)
269− in pinnedInt /= 0
270−
271−
272−{-# INLINE cloneMutableArrayWith# #-}
273−cloneMutableArrayWith#
274− :: (Int# -> State# RealWorld -> (# State# RealWorld
275− , MutableByteArray# RealWorld #))
276− -> MutableByteArray# RealWorld
277− -> State# RealWorld
278− -> (# State# RealWorld, MutableByteArray# RealWorld #)
279−cloneMutableArrayWith# alloc# arr# s# =
280− case getSizeofMutableByteArray# arr# s# of
281− (# s1#, i# #) ->
282− case alloc# i# s1# of
283− (# s2#, arr1# #) ->
284− case copyMutableByteArray# arr# 0# arr1# 0# i# s2# of
285− s3# -> (# s3#, arr1# #)
286−
287−-- | Return a copy of the array in pinned memory if unpinned, else return the
288−-- original array.
289−{-# INLINE pin #-}
290−pin :: MutByteArray -> IO MutByteArray
291−pin arr@(MutByteArray marr#) =
292− if isPinned arr
293− then return arr
294− else
295−#ifdef DEBUG
296− do
297− -- XXX dump stack trace
298− trace ("pin: Copying array") (return ())
299−#endif
300− IO
301− $ \s# ->
302− case cloneMutableArrayWith# newPinnedByteArray# marr# s# of
303− (# s1#, marr1# #) -> (# s1#, MutByteArray marr1# #)
304−
305−-- | Return a copy of the array in unpinned memory if pinned, else return the
306−-- original array.
307−{-# INLINE unpin #-}
308−unpin :: MutByteArray -> IO MutByteArray
309−unpin arr@(MutByteArray marr#) =
310− if not (isPinned arr)
311− then return arr
312− else
313−#ifdef DEBUG
314− do
315− -- XXX dump stack trace
316− trace ("unpin: Copying array") (return ())
317−#endif
318− IO
319− $ \s# ->
320− case cloneMutableArrayWith# newByteArray# marr# s# of
321− (# s1#, marr1# #) -> (# s1#, MutByteArray marr1# #)
core/src/Streamly/Internal/Data/Parser.hs+119−126
@@ -10,13 +10,10 @@
10module Streamly.Internal.Data.Parser
10module Streamly.Internal.Data.Parser
11 (
11 (
12 -- * Setup
12 -- * Setup
13− -- | To execute the code examples provided in this module in ghci, please
14− -- run the following commands first.
15− --
16 -- $setup
13 -- $setup
17
14
18 module Streamly.Internal.Data.Parser.Type
15 module Streamly.Internal.Data.Parser.Type
19− --, module Streamly.Internal.Data.Parser.Tee
16+ --, module Streamly.Internal.Data.Parser.Tee
20
17
21 -- * Types
18 -- * Types
22 , Parser (..)
19 , Parser (..)
@@ -284,7 +281,7 @@ import Prelude hiding
284--
281--
285{-# INLINE toFold #-}
282{-# INLINE toFold #-}
286toFold :: Monad m => Parser a m b -> Fold m a b
283toFold :: Monad m => Parser a m b -> Fold m a b
287−toFold (Parser pstep pinitial pextract) = Fold step initial extract final
284+toFold (Parser pstep pinitial pextract) = Fold step initial extract
288
285
289 where
286 where
290
287
@@ -312,9 +309,7 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract final
312 Done n _ -> derror n
309 Done n _ -> derror n
313 Error err -> eerror err
310 Error err -> eerror err
314
311
315− extract = error "toFold: parser cannot be used for scanning"
316−
317− final st = do
312+ extract st = do
318 r <- pextract st
313 r <- pextract st
319 case r of
314 case r of
320 Done 0 b -> return b
315 Done 0 b -> return b
@@ -332,7 +327,7 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract final
332--
327--
333{-# INLINE fromFold #-}
328{-# INLINE fromFold #-}
334fromFold :: Monad m => Fold m a b -> Parser a m b
329fromFold :: Monad m => Fold m a b -> Parser a m b
335−fromFold (Fold fstep finitial _ ffinal) = Parser step initial extract
330+fromFold (Fold fstep finitial fextract) = Parser step initial extract
336
331
337 where
332 where
338
333
@@ -350,7 +345,7 @@ fromFold (Fold fstep finitial _ ffinal) = Parser step initial extract
350 FL.Partial s1 -> Partial 0 s1
345 FL.Partial s1 -> Partial 0 s1
351 FL.Done b -> Done 0 b
346 FL.Done b -> Done 0 b
352
347
353− extract = fmap (Done 0) . ffinal
348+ extract = fmap (Done 0) . fextract
354
349
355-- | Convert a Maybe returning fold to an error returning parser. The first
350-- | Convert a Maybe returning fold to an error returning parser. The first
356-- argument is the error message that the parser would return when the fold
351-- argument is the error message that the parser would return when the fold
@@ -360,7 +355,7 @@ fromFold (Fold fstep finitial _ ffinal) = Parser step initial extract
360--
355--
361{-# INLINE fromFoldMaybe #-}
356{-# INLINE fromFoldMaybe #-}
362fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
357fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
363−fromFoldMaybe errMsg (Fold fstep finitial _ ffinal) =
358+fromFoldMaybe errMsg (Fold fstep finitial fextract) =
364 Parser step initial extract
359 Parser step initial extract
365
360
366 where
361 where
@@ -386,7 +381,7 @@ fromFoldMaybe errMsg (Fold fstep finitial _ ffinal) =
386 Nothing -> Error errMsg
381 Nothing -> Error errMsg
387
382
388 extract s = do
383 extract s = do
389− res <- ffinal s
384+ res <- fextract s
390 case res of
385 case res of
391 Just x -> return $ Done 0 x
386 Just x -> return $ Done 0 x
392 Nothing -> return $ Error errMsg
387 Nothing -> return $ Error errMsg
@@ -635,7 +630,7 @@ data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
635--
630--
636{-# INLINE takeBetween #-}
631{-# INLINE takeBetween #-}
637takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
632takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
638−takeBetween low high (Fold fstep finitial _ ffinal) =
633+takeBetween low high (Fold fstep finitial fextract) =
639
634
640 Parser step initial (extract streamErr)
635 Parser step initial (extract streamErr)
641
636
@@ -686,11 +681,9 @@ takeBetween low high (Fold fstep finitial _ ffinal) =
686 in case res of
681 in case res of
687 FL.Partial s -> do
682 FL.Partial s -> do
688 let s1 = Tuple'Fused i1 s
683 let s1 = Tuple'Fused i1 s
689− if i1 < low
684+ if i1 < high
690 then return $ Continue 0 s1
685 then return $ Continue 0 s1
691− else if i1 < high
686+ else extract foldErr s1
692− then return $ Partial 0 s1
693− else fmap (Done 0) (ffinal s)
694 FL.Done b ->
687 FL.Done b ->
695 return
688 return
696 $ if i1 >= low
689 $ if i1 >= low
@@ -700,12 +693,12 @@ takeBetween low high (Fold fstep finitial _ ffinal) =
700 step (Tuple'Fused i s) a = fstep s a >>= snext i
693 step (Tuple'Fused i s) a = fstep s a >>= snext i
701
694
702 extract f (Tuple'Fused i s)
695 extract f (Tuple'Fused i s)
703− | i >= low && i <= high = fmap (Done 0) (ffinal s)
696+ | i >= low && i <= high = fmap (Done 0) (fextract s)
704 | otherwise = return $ Error (f i)
697 | otherwise = return $ Error (f i)
705
698
706 -- XXX Need to make Initial return type Step to deduplicate this
699 -- XXX Need to make Initial return type Step to deduplicate this
707 iextract f (Tuple'Fused i s)
700 iextract f (Tuple'Fused i s)
708− | i >= low && i <= high = fmap IDone (ffinal s)
701+ | i >= low && i <= high = fmap IDone (fextract s)
709 | otherwise = return $ IError (f i)
702 | otherwise = return $ IError (f i)
710
703
711-- | Stops after taking exactly @n@ input elements.
704-- | Stops after taking exactly @n@ input elements.
@@ -722,7 +715,7 @@ takeBetween low high (Fold fstep finitial _ ffinal) =
722--
715--
723{-# INLINE takeEQ #-}
716{-# INLINE takeEQ #-}
724takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
717takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
725−takeEQ n (Fold fstep finitial _ ffinal) = Parser step initial extract
718+takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
726
719
727 where
720 where
728
721
@@ -732,7 +725,7 @@ takeEQ n (Fold fstep finitial _ ffinal) = Parser step initial extract
732 FL.Partial s ->
725 FL.Partial s ->
733 if n > 0
726 if n > 0
734 then return $ IPartial $ Tuple'Fused 1 s
727 then return $ IPartial $ Tuple'Fused 1 s
735− else fmap IDone (ffinal s)
728+ else fmap IDone (fextract s)
736 FL.Done b -> return $
729 FL.Done b -> return $
737 if n > 0
730 if n > 0
738 then IError
731 then IError
@@ -756,7 +749,7 @@ takeEQ n (Fold fstep finitial _ ffinal) = Parser step initial extract
756 -- assert (n == i1)
749 -- assert (n == i1)
757 Done 0
750 Done 0
758 <$> case res of
751 <$> case res of
759− FL.Partial s -> ffinal s
752+ FL.Partial s -> fextract s
760 FL.Done b -> return b
753 FL.Done b -> return b
761
754
762 extract (Tuple'Fused i _) =
755 extract (Tuple'Fused i _) =
@@ -788,7 +781,7 @@ data TakeGEState s =
788--
781--
789{-# INLINE takeGE #-}
782{-# INLINE takeGE #-}
790takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
783takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
791−takeGE n (Fold fstep finitial _ ffinal) = Parser step initial extract
784+takeGE n (Fold fstep finitial fextract) = Parser step initial extract
792
785
793 where
786 where
794
787
@@ -836,7 +829,7 @@ takeGE n (Fold fstep finitial _ ffinal) = Parser step initial extract
836 $ Error
829 $ Error
837 $ "takeGE: Expecting at least " ++ show n
830 $ "takeGE: Expecting at least " ++ show n
838 ++ " elements, input terminated on " ++ show (i - 1)
831 ++ " elements, input terminated on " ++ show (i - 1)
839− extract (TakeGEGE r) = fmap (Done 0) $ ffinal r
832+ extract (TakeGEGE r) = fmap (Done 0) $ fextract r
840
833
841-------------------------------------------------------------------------------
834-------------------------------------------------------------------------------
842-- Conditional splitting
835-- Conditional splitting
@@ -897,7 +890,7 @@ takeWhileP predicate (Parser pstep pinitial pextract) =
897{-# INLINE takeWhile #-}
890{-# INLINE takeWhile #-}
898takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
891takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
899-- takeWhile cond f = takeWhileP cond (fromFold f)
892-- takeWhile cond f = takeWhileP cond (fromFold f)
900−takeWhile predicate (Fold fstep finitial _ ffinal) =
893+takeWhile predicate (Fold fstep finitial fextract) =
901 Parser step initial extract
894 Parser step initial extract
902
895
903 where
896 where
@@ -916,9 +909,9 @@ takeWhile predicate (Fold fstep finitial _ ffinal) =
916 $ case fres of
909 $ case fres of
917 FL.Partial s1 -> Partial 0 s1
910 FL.Partial s1 -> Partial 0 s1
918 FL.Done b -> Done 0 b
911 FL.Done b -> Done 0 b
919− else Done 1 <$> ffinal s
912+ else Done 1 <$> fextract s
920
913
921− extract s = fmap (Done 0) (ffinal s)
914+ extract s = fmap (Done 0) (fextract s)
922
915
923{-
916{-
924-- XXX This may not be composable because of the b argument. We can instead
917-- XXX This may not be composable because of the b argument. We can instead
@@ -938,7 +931,7 @@ takeWhile1 acc cond f = undefined
938{-# INLINE takeWhile1 #-}
931{-# INLINE takeWhile1 #-}
939takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
932takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
940-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
933-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
941−takeWhile1 predicate (Fold fstep finitial _ ffinal) =
934+takeWhile1 predicate (Fold fstep finitial fextract) =
942 Parser step initial extract
935 Parser step initial extract
943
936
944 where
937 where
@@ -968,11 +961,11 @@ takeWhile1 predicate (Fold fstep finitial _ ffinal) =
968 if predicate a
961 if predicate a
969 then process s a
962 then process s a
970 else do
963 else do
971− b <- ffinal s
964+ b <- fextract s
972 return $ Done 1 b
965 return $ Done 1 b
973
966
974 extract (Left' _) = return $ Error "takeWhile1: end of input"
967 extract (Left' _) = return $ Error "takeWhile1: end of input"
975− extract (Right' s) = fmap (Done 0) (ffinal s)
968+ extract (Right' s) = fmap (Done 0) (fextract s)
976
969
977-- | Drain the input as long as the predicate succeeds, running the effects and
970-- | Drain the input as long as the predicate succeeds, running the effects and
978-- discarding the results.
971-- discarding the results.
@@ -1001,7 +994,7 @@ takeFramedByGeneric :: Monad m =>
1001 -> Maybe (a -> Bool) -- is frame end?
994 -> Maybe (a -> Bool) -- is frame end?
1002 -> Fold m a b
995 -> Fold m a b
1003 -> Parser a m b
996 -> Parser a m b
1004−takeFramedByGeneric esc begin end (Fold fstep finitial _ ffinal) =
997+takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
1005
998
1006 Parser step initial extract
999 Parser step initial extract
1007
1000
@@ -1033,20 +1026,20 @@ takeFramedByGeneric esc begin end (Fold fstep finitial _ ffinal) =
1033 if isEnd a
1026 if isEnd a
1034 then
1027 then
1035 if n == 0
1028 if n == 0
1036− then Done 0 <$> ffinal s
1029+ then Done 0 <$> fextract s
1037 else process s a (n - 1)
1030 else process s a (n - 1)
1038 else
1031 else
1039 let n1 = if isBegin a then n + 1 else n
1032 let n1 = if isBegin a then n + 1 else n
1040 in process s a n1
1033 in process s a n1
1041 Nothing -> -- takeEndBy case
1034 Nothing -> -- takeEndBy case
1042 if isEnd a
1035 if isEnd a
1043− then Done 0 <$> ffinal s
1036+ then Done 0 <$> fextract s
1044 else process s a n
1037 else process s a n
1045 Nothing -> -- takeStartBy case
1038 Nothing -> -- takeStartBy case
1046 case begin of
1039 case begin of
1047 Just isBegin ->
1040 Just isBegin ->
1048 if isBegin a
1041 if isBegin a
1049− then Done 0 <$> ffinal s
1042+ then Done 0 <$> fextract s
1050 else process s a n
1043 else process s a n
1051 Nothing ->
1044 Nothing ->
1052 error $ "takeFramedByGeneric: "
1045 error $ "takeFramedByGeneric: "
@@ -1071,7 +1064,7 @@ takeFramedByGeneric esc begin end (Fold fstep finitial _ ffinal) =
1071 case end of
1064 case end of
1072 Just isEnd ->
1065 Just isEnd ->
1073 if isEnd a
1066 if isEnd a
1074− then Done 0 <$> ffinal s
1067+ then Done 0 <$> fextract s
1075 else processCheckEsc s a 0
1068 else processCheckEsc s a 0
1076 Nothing ->
1069 Nothing ->
1077 error "Both begin and end frame predicate missing"
1070 error "Both begin and end frame predicate missing"
@@ -1086,7 +1079,7 @@ takeFramedByGeneric esc begin end (Fold fstep finitial _ ffinal) =
1086 case begin of
1079 case begin of
1087 Just _ ->
1080 Just _ ->
1088 case end of
1081 case end of
1089− Nothing -> fmap (Done 0) $ ffinal s
1082+ Nothing -> fmap (Done 0) $ fextract s
1090 Just _ -> err "takeFramedByGeneric: missing frame end"
1083 Just _ -> err "takeFramedByGeneric: missing frame end"
1091 Nothing -> err "takeFramedByGeneric: missing closing frame"
1084 Nothing -> err "takeFramedByGeneric: missing closing frame"
1092 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
1085 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
@@ -1125,7 +1118,7 @@ blockWithQuotes :: (Monad m, Eq a) =>
1125 -> Fold m a b
1118 -> Fold m a b
1126 -> Parser a m b
1119 -> Parser a m b
1127blockWithQuotes isEsc isQuote bopen bclose
1120blockWithQuotes isEsc isQuote bopen bclose
1128− (Fold fstep finitial _ ffinal) =
1121+ (Fold fstep finitial fextract) =
1129 Parser step initial extract
1122 Parser step initial extract
1130
1123
1131 where
1124 where
@@ -1155,7 +1148,7 @@ blockWithQuotes isEsc isQuote bopen bclose
1155 | a == bopen = process s a (BlockUnquoted (level + 1))
1148 | a == bopen = process s a (BlockUnquoted (level + 1))
1156 | a == bclose =
1149 | a == bclose =
1157 if level == 1
1150 if level == 1
1158− then fmap (Done 0) (ffinal s)
1151+ then fmap (Done 0) (fextract s)
1159 else process s a (BlockUnquoted (level - 1))
1152 else process s a (BlockUnquoted (level - 1))
1160 | isQuote a = process s a (BlockQuoted level)
1153 | isQuote a = process s a (BlockQuoted level)
1161 | otherwise = process s a (BlockUnquoted level)
1154 | otherwise = process s a (BlockUnquoted level)
@@ -1169,7 +1162,7 @@ blockWithQuotes isEsc isQuote bopen bclose
1169
1162
1170 err = return . Error
1163 err = return . Error
1171
1164
1172− extract (BlockInit s) = fmap (Done 0) $ ffinal s
1165+ extract (BlockInit s) = fmap (Done 0) $ fextract s
1173 extract (BlockUnquoted level _) =
1166 extract (BlockUnquoted level _) =
1174 err $ "blockWithQuotes: finished at block nest level " ++ show level
1167 err $ "blockWithQuotes: finished at block nest level " ++ show level
1175 extract (BlockQuoted level _) =
1168 extract (BlockQuoted level _) =
@@ -1304,7 +1297,7 @@ takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
1304--
1297--
1305{-# INLINE takeStartBy #-}
1298{-# INLINE takeStartBy #-}
1306takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1299takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1307−takeStartBy cond (Fold fstep finitial _ ffinal) =
1300+takeStartBy cond (Fold fstep finitial fextract) =
1308
1301
1309 Parser step initial extract
1302 Parser step initial extract
1310
1303
@@ -1332,10 +1325,10 @@ takeStartBy cond (Fold fstep finitial _ ffinal) =
1332 step (Right' s) a =
1325 step (Right' s) a =
1333 if not (cond a)
1326 if not (cond a)
1334 then process s a
1327 then process s a
1335− else Done 1 <$> ffinal s
1328+ else Done 1 <$> fextract s
1336
1329
1337− extract (Left' s) = fmap (Done 0) $ ffinal s
1330+ extract (Left' s) = fmap (Done 0) $ fextract s
1338− extract (Right' s) = fmap (Done 0) $ ffinal s
1331+ extract (Right' s) = fmap (Done 0) $ fextract s
1339
1332
1340-- | Like 'takeStartBy' but drops the separator.
1333-- | Like 'takeStartBy' but drops the separator.
1341--
1334--
@@ -1371,7 +1364,7 @@ takeFramedByEsc_ :: Monad m =>
1371 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1364 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1372-- takeFramedByEsc_ isEsc isEnd p =
1365-- takeFramedByEsc_ isEsc isEnd p =
1373-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
1366-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
1374−takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial _ ffinal ) =
1367+takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial fextract) =
1375
1368
1376 Parser step initial extract
1369 Parser step initial extract
1377
1370
@@ -1407,7 +1400,7 @@ takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial _ ffinal ) =
1407 in process s a n1
1400 in process s a n1
1408 else
1401 else
1409 if n == 0
1402 if n == 0
1410− then Done 0 <$> ffinal s
1403+ then Done 0 <$> fextract s
1411 else process s a (n - 1)
1404 else process s a (n - 1)
1412 step (FrameEscEsc s n) a = process s a n
1405 step (FrameEscEsc s n) a = process s a n
1413
1406
@@ -1429,7 +1422,7 @@ takeFramedBy_ :: Monad m =>
1429 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1422 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1430-- takeFramedBy_ isBegin isEnd =
1423-- takeFramedBy_ isBegin isEnd =
1431-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
1424-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
1432−takeFramedBy_ isBegin isEnd (Fold fstep finitial _ ffinal) =
1425+takeFramedBy_ isBegin isEnd (Fold fstep finitial fextract) =
1433
1426
1434 Parser step initial extract
1427 Parser step initial extract
1435
1428
@@ -1459,7 +1452,7 @@ takeFramedBy_ isBegin isEnd (Fold fstep finitial _ ffinal) =
1459 | not (isEnd a) =
1452 | not (isEnd a) =
1460 let n1 = if isBegin a then n + 1 else n
1453 let n1 = if isBegin a then n + 1 else n
1461 in process s a n1
1454 in process s a n1
1462− | n == 0 = Done 0 <$> ffinal s
1455+ | n == 0 = Done 0 <$> fextract s
1463 | otherwise = process s a (n - 1)
1456 | otherwise = process s a (n - 1)
1464
1457
1465 err = return . Error
1458 err = return . Error
@@ -1494,7 +1487,7 @@ data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
1494--
1487--
1495{-# INLINE wordBy #-}
1488{-# INLINE wordBy #-}
1496wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1489wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1497−wordBy predicate (Fold fstep finitial _ ffinal) = Parser step initial extract
1490+wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
1498
1491
1499 where
1492 where
1500
1493
@@ -1521,7 +1514,7 @@ wordBy predicate (Fold fstep finitial _ ffinal) = Parser step initial extract
1521 if not (predicate a)
1514 if not (predicate a)
1522 then worder s a
1515 then worder s a
1523 else do
1516 else do
1524− b <- ffinal s
1517+ b <- fextract s
1525 return $ Partial 0 $ WBRight b
1518 return $ Partial 0 $ WBRight b
1526 step (WBRight b) a =
1519 step (WBRight b) a =
1527 return
1520 return
@@ -1529,8 +1522,8 @@ wordBy predicate (Fold fstep finitial _ ffinal) = Parser step initial extract
1529 then Done 1 b
1522 then Done 1 b
1530 else Partial 0 $ WBRight b
1523 else Partial 0 $ WBRight b
1531
1524
1532− extract (WBLeft s) = fmap (Done 0) $ ffinal s
1525+ extract (WBLeft s) = fmap (Done 0) $ fextract s
1533− extract (WBWord s) = fmap (Done 0) $ ffinal s
1526+ extract (WBWord s) = fmap (Done 0) $ fextract s
1534 extract (WBRight b) = return (Done 0 b)
1527 extract (WBRight b) = return (Done 0 b)
1535
1528
1536data WordFramedState s b =
1529data WordFramedState s b =
@@ -1567,7 +1560,7 @@ wordFramedBy :: Monad m =>
1567 -> Fold m a b
1560 -> Fold m a b
1568 -> Parser a m b
1561 -> Parser a m b
1569wordFramedBy isEsc isBegin isEnd isSep
1562wordFramedBy isEsc isBegin isEnd isSep
1570− (Fold fstep finitial _ ffinal) =
1563+ (Fold fstep finitial fextract) =
1571 Parser step initial extract
1564 Parser step initial extract
1572
1565
1573 where
1566 where
@@ -1598,7 +1591,7 @@ wordFramedBy isEsc isBegin isEnd isSep
1598 step (WordFramedWord s n) a
1591 step (WordFramedWord s n) a
1599 | isEsc a = return $ Continue 0 $ WordFramedEsc s n
1592 | isEsc a = return $ Continue 0 $ WordFramedEsc s n
1600 | n == 0 && isSep a = do
1593 | n == 0 && isSep a = do
1601− b <- ffinal s
1594+ b <- fextract s
1602 return $ Partial 0 $ WordFramedSkipPost b
1595 return $ Partial 0 $ WordFramedSkipPost b
1603 | otherwise = do
1596 | otherwise = do
1604 -- We need to use different order for checking begin and end for
1597 -- We need to use different order for checking begin and end for
@@ -1631,10 +1624,10 @@ wordFramedBy isEsc isBegin isEnd isSep
1631
1624
1632 err = return . Error
1625 err = return . Error
1633
1626
1634− extract (WordFramedSkipPre s) = fmap (Done 0) $ ffinal s
1627+ extract (WordFramedSkipPre s) = fmap (Done 0) $ fextract s
1635 extract (WordFramedWord s n) =
1628 extract (WordFramedWord s n) =
1636 if n == 0
1629 if n == 0
1637− then fmap (Done 0) $ ffinal s
1630+ then fmap (Done 0) $ fextract s
1638 else err "wordFramedBy: missing frame end"
1631 else err "wordFramedBy: missing frame end"
1639 extract (WordFramedEsc _ _) =
1632 extract (WordFramedEsc _ _) =
1640 err "wordFramedBy: trailing escape"
1633 err "wordFramedBy: trailing escape"
@@ -1721,7 +1714,7 @@ wordWithQuotes :: (Monad m, Eq a) =>
1721 -> Fold m a b
1714 -> Fold m a b
1722 -> Parser a m b
1715 -> Parser a m b
1723wordWithQuotes keepQuotes tr escChar toRight isSep
1716wordWithQuotes keepQuotes tr escChar toRight isSep
1724− (Fold fstep finitial _ ffinal) =
1717+ (Fold fstep finitial fextract) =
1725 Parser step initial extract
1718 Parser step initial extract
1726
1719
1727 where
1720 where
@@ -1772,7 +1765,7 @@ wordWithQuotes keepQuotes tr escChar toRight isSep
1772 step (WordUnquotedWord s) a
1765 step (WordUnquotedWord s) a
1773 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1766 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1774 | isSep a = do
1767 | isSep a = do
1775− b <- ffinal s
1768+ b <- fextract s
1776 return $ Partial 0 $ WordQuotedSkipPost b
1769 return $ Partial 0 $ WordQuotedSkipPost b
1777 | otherwise = do
1770 | otherwise = do
1778 case toRight a of
1771 case toRight a of
@@ -1820,11 +1813,11 @@ wordWithQuotes keepQuotes tr escChar toRight isSep
1820
1813
1821 err = return . Error
1814 err = return . Error
1822
1815
1823− extract (WordQuotedSkipPre s) = fmap (Done 0) $ ffinal s
1816+ extract (WordQuotedSkipPre s) = fmap (Done 0) $ fextract s
1824− extract (WordUnquotedWord s) = fmap (Done 0) $ ffinal s
1817+ extract (WordUnquotedWord s) = fmap (Done 0) $ fextract s
1825 extract (WordQuotedWord s n _ _) =
1818 extract (WordQuotedWord s n _ _) =
1826 if n == 0
1819 if n == 0
1827− then fmap (Done 0) $ ffinal s
1820+ then fmap (Done 0) $ fextract s
1828 else err "wordWithQuotes: missing frame end"
1821 else err "wordWithQuotes: missing frame end"
1829 extract WordQuotedEsc {} =
1822 extract WordQuotedEsc {} =
1830 err "wordWithQuotes: trailing escape"
1823 err "wordWithQuotes: trailing escape"
@@ -1902,7 +1895,7 @@ data GroupByState a s
1902--
1895--
1903{-# INLINE groupBy #-}
1896{-# INLINE groupBy #-}
1904groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1897groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1905−groupBy eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1898+groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
1906
1899
1907 where
1900 where
1908
1901
@@ -1925,10 +1918,10 @@ groupBy eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1925 step (GroupByGrouping a0 s) a =
1918 step (GroupByGrouping a0 s) a =
1926 if eq a0 a
1919 if eq a0 a
1927 then grouper s a0 a
1920 then grouper s a0 a
1928− else Done 1 <$> ffinal s
1921+ else Done 1 <$> fextract s
1929
1922
1930− extract (GroupByInit s) = fmap (Done 0) $ ffinal s
1923+ extract (GroupByInit s) = fmap (Done 0) $ fextract s
1931− extract (GroupByGrouping _ s) = fmap (Done 0) $ ffinal s
1924+ extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
1932
1925
1933-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
1926-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
1934-- successive elements in the input stream. Assuming the input stream
1927-- successive elements in the input stream. Assuming the input stream
@@ -1962,7 +1955,7 @@ groupBy eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1962--
1955--
1963{-# INLINE groupByRolling #-}
1956{-# INLINE groupByRolling #-}
1964groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1957groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1965−groupByRolling eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1958+groupByRolling eq (Fold fstep finitial fextract) = Parser step initial extract
1966
1959
1967 where
1960 where
1968
1961
@@ -1985,10 +1978,10 @@ groupByRolling eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1985 step (GroupByGrouping a0 s) a =
1978 step (GroupByGrouping a0 s) a =
1986 if eq a0 a
1979 if eq a0 a
1987 then grouper s a
1980 then grouper s a
1988− else Done 1 <$> ffinal s
1981+ else Done 1 <$> fextract s
1989
1982
1990− extract (GroupByInit s) = fmap (Done 0) $ ffinal s
1983+ extract (GroupByInit s) = fmap (Done 0) $ fextract s
1991− extract (GroupByGrouping _ s) = fmap (Done 0) $ ffinal s
1984+ extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
1992
1985
1993{-# ANN type GroupByStatePair Fuse #-}
1986{-# ANN type GroupByStatePair Fuse #-}
1994data GroupByStatePair a s1 s2
1987data GroupByStatePair a s1 s2
@@ -2012,8 +2005,8 @@ groupByRollingEither :: Monad m =>
2012 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
2005 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
2013groupByRollingEither
2006groupByRollingEither
2014 eq
2007 eq
2015− (Fold fstep1 finitial1 _ ffinal1)
2008+ (Fold fstep1 finitial1 fextract1)
2016− (Fold fstep2 finitial2 _ ffinal2) = Parser step initial extract
2009+ (Fold fstep2 finitial2 fextract2) = Parser step initial extract
2017
2010
2018 where
2011 where
2019
2012
@@ -2072,21 +2065,21 @@ groupByRollingEither
2072 step (GroupByGroupingPairL a0 s1 s2) a =
2065 step (GroupByGroupingPairL a0 s1 s2) a =
2073 if not (eq a0 a)
2066 if not (eq a0 a)
2074 then grouperL2 s1 s2 a
2067 then grouperL2 s1 s2 a
2075− else Done 1 . Left <$> ffinal1 s1
2068+ else Done 1 . Left <$> fextract1 s1
2076
2069
2077 step (GroupByGroupingPairR a0 s1 s2) a =
2070 step (GroupByGroupingPairR a0 s1 s2) a =
2078 if eq a0 a
2071 if eq a0 a
2079 then grouperR2 s1 s2 a
2072 then grouperR2 s1 s2 a
2080− else Done 1 . Right <$> ffinal2 s2
2073+ else Done 1 . Right <$> fextract2 s2
2081
2074
2082− extract (GroupByInitPair s1 _) = Done 0 . Left <$> ffinal1 s1
2075+ extract (GroupByInitPair s1 _) = Done 0 . Left <$> fextract1 s1
2083− extract (GroupByGroupingPairL _ s1 _) = Done 0 . Left <$> ffinal1 s1
2076+ extract (GroupByGroupingPairL _ s1 _) = Done 0 . Left <$> fextract1 s1
2084− extract (GroupByGroupingPairR _ _ s2) = Done 0 . Right <$> ffinal2 s2
2077+ extract (GroupByGroupingPairR _ _ s2) = Done 0 . Right <$> fextract2 s2
2085 extract (GroupByGroupingPair a s1 _) = do
2078 extract (GroupByGroupingPair a s1 _) = do
2086 res <- fstep1 s1 a
2079 res <- fstep1 s1 a
2087 case res of
2080 case res of
2088 FL.Done b -> return $ Done 0 (Left b)
2081 FL.Done b -> return $ Done 0 (Left b)
2089− FL.Partial s11 -> Done 0 . Left <$> ffinal1 s11
2082+ FL.Partial s11 -> Done 0 . Left <$> fextract1 s11
2090
2083
2091-- XXX use an Unfold instead of a list?
2084-- XXX use an Unfold instead of a list?
2092-- XXX custom combinators for matching list, array and stream?
2085-- XXX custom combinators for matching list, array and stream?
@@ -2239,7 +2232,7 @@ postscan = undefined
2239{-# INLINE zipWithM #-}
2232{-# INLINE zipWithM #-}
2240zipWithM :: Monad m =>
2233zipWithM :: Monad m =>
2241 (a -> b -> m c) -> D.Stream m a -> Fold m c x -> Parser b m x
2234 (a -> b -> m c) -> D.Stream m a -> Fold m c x -> Parser b m x
2242−zipWithM zf (D.Stream sstep state) (Fold fstep finitial _ ffinal) =
2235+zipWithM zf (D.Stream sstep state) (Fold fstep finitial fextract) =
2243 Parser step initial extract
2236 Parser step initial extract
2244
2237
2245 where
2238 where
@@ -2252,7 +2245,7 @@ zipWithM zf (D.Stream sstep state) (Fold fstep finitial _ ffinal) =
2252 case r of
2245 case r of
2253 D.Yield x s -> return $ IPartial (Just' x, s, fs)
2246 D.Yield x s -> return $ IPartial (Just' x, s, fs)
2254 D.Stop -> do
2247 D.Stop -> do
2255− x <- ffinal fs
2248+ x <- fextract fs
2256 return $ IDone x
2249 return $ IDone x
2257 -- Need Skip/Continue in initial to loop right here
2250 -- Need Skip/Continue in initial to loop right here
2258 D.Skip s -> return $ IPartial (Nothing', s, fs)
2251 D.Skip s -> return $ IPartial (Nothing', s, fs)
@@ -2267,7 +2260,7 @@ zipWithM zf (D.Stream sstep state) (Fold fstep finitial _ ffinal) =
2267 case r of
2260 case r of
2268 D.Yield x1 s -> return $ Continue 0 (Just' x1, s, fs1)
2261 D.Yield x1 s -> return $ Continue 0 (Just' x1, s, fs1)
2269 D.Stop -> do
2262 D.Stop -> do
2270− x <- ffinal fs1
2263+ x <- fextract fs1
2271 return $ Done 0 x
2264 return $ Done 0 x
2272 D.Skip s -> return $ Continue 1 (Nothing', s, fs1)
2265 D.Skip s -> return $ Continue 1 (Nothing', s, fs1)
2273 FL.Done x -> return $ Done 0 x
2266 FL.Done x -> return $ Done 0 x
@@ -2282,7 +2275,7 @@ zipWithM zf (D.Stream sstep state) (Fold fstep finitial _ ffinal) =
2282 return $ Continue 0 (Nothing', s, fs1)
2275 return $ Continue 0 (Nothing', s, fs1)
2283 FL.Done x -> return $ Done 0 x
2276 FL.Done x -> return $ Done 0 x
2284 D.Stop -> do
2277 D.Stop -> do
2285− x <- ffinal fs
2278+ x <- fextract fs
2286 return $ Done 1 x
2279 return $ Done 1 x
2287 D.Skip s -> return $ Continue 1 (Nothing', s, fs)
2280 D.Skip s -> return $ Continue 1 (Nothing', s, fs)
2288
2281
@@ -2566,7 +2559,7 @@ deintercalateAll :: Monad m =>
2566deintercalateAll
2559deintercalateAll
2567 (Parser stepL initialL extractL)
2560 (Parser stepL initialL extractL)
2568 (Parser stepR initialR _)
2561 (Parser stepR initialR _)
2569− (Fold fstep finitial _ ffinal) = Parser step initial extract
2562+ (Fold fstep finitial fextract) = Parser step initial extract
2570
2563
2571 where
2564 where
2572
2565
@@ -2637,9 +2630,9 @@ deintercalateAll
2637 extractResult n fs r = do
2630 extractResult n fs r = do
2638 res <- fstep fs r
2631 res <- fstep fs r
2639 case res of
2632 case res of
2640− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2633+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2641 FL.Done c -> return (Done n c)
2634 FL.Done c -> return (Done n c)
2642− extract (DeintercalateAllInitL fs) = fmap (Done 0) $ ffinal fs
2635+ extract (DeintercalateAllInitL fs) = fmap (Done 0) $ fextract fs
2643 extract (DeintercalateAllL fs sL) = do
2636 extract (DeintercalateAllL fs sL) = do
2644 r <- extractL sL
2637 r <- extractL sL
2645 case r of
2638 case r of
@@ -2647,7 +2640,7 @@ deintercalateAll
2647 Error err -> return $ Error err
2640 Error err -> return $ Error err
2648 Continue n s -> return $ Continue n (DeintercalateAllL fs s)
2641 Continue n s -> return $ Continue n (DeintercalateAllL fs s)
2649 Partial _ _ -> error "Partial in extract"
2642 Partial _ _ -> error "Partial in extract"
2650− extract (DeintercalateAllInitR fs) = fmap (Done 0) $ ffinal fs
2643+ extract (DeintercalateAllInitR fs) = fmap (Done 0) $ fextract fs
2651 extract (DeintercalateAllR _ _) =
2644 extract (DeintercalateAllR _ _) =
2652 return $ Error "deintercalateAll: input ended at 'Right' value"
2645 return $ Error "deintercalateAll: input ended at 'Right' value"
2653
2646
@@ -2690,7 +2683,7 @@ deintercalate :: Monad m =>
2690deintercalate
2683deintercalate
2691 (Parser stepL initialL extractL)
2684 (Parser stepL initialL extractL)
2692 (Parser stepR initialR _)
2685 (Parser stepR initialR _)
2693− (Fold fstep finitial _ ffinal) = Parser step initial extract
2686+ (Fold fstep finitial fextract) = Parser step initial extract
2694
2687
2695 where
2688 where
2696
2689
@@ -2721,7 +2714,7 @@ deintercalate
2721 Done n b ->
2714 Done n b ->
2722 processL (fstep fs (Left b)) n DeintercalateInitR
2715 processL (fstep fs (Left b)) n DeintercalateInitR
2723 Error _ -> do
2716 Error _ -> do
2724− xs <- ffinal fs
2717+ xs <- fextract fs
2725 return $ Done cnt1 xs
2718 return $ Done cnt1 xs
2726
2719
2727 {-# INLINE processR #-}
2720 {-# INLINE processR #-}
@@ -2741,7 +2734,7 @@ deintercalate
2741 Continue n s -> return $ Continue n (DeintercalateR (cnt1 - n) fs s)
2734 Continue n s -> return $ Continue n (DeintercalateR (cnt1 - n) fs s)
2742 Done n b -> processR (cnt1 - n) b fs n
2735 Done n b -> processR (cnt1 - n) b fs n
2743 Error _ -> do
2736 Error _ -> do
2744− xs <- ffinal fs
2737+ xs <- fextract fs
2745 return $ Done cnt1 xs
2738 return $ Done cnt1 xs
2746
2739
2747 step (DeintercalateInitL fs) a = do
2740 step (DeintercalateInitL fs) a = do
@@ -2776,17 +2769,17 @@ deintercalate
2776 -- XXX We could have the fold accept pairs of (bR, bL)
2769 -- XXX We could have the fold accept pairs of (bR, bL)
2777 FL.Done _ -> error "Fold terminated consuming partial input"
2770 FL.Done _ -> error "Fold terminated consuming partial input"
2778 Error _ -> do
2771 Error _ -> do
2779− xs <- ffinal fs
2772+ xs <- fextract fs
2780 return $ Done cnt1 xs
2773 return $ Done cnt1 xs
2781
2774
2782 {-# INLINE extractResult #-}
2775 {-# INLINE extractResult #-}
2783 extractResult n fs r = do
2776 extractResult n fs r = do
2784 res <- fstep fs r
2777 res <- fstep fs r
2785 case res of
2778 case res of
2786− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2779+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2787 FL.Done c -> return (Done n c)
2780 FL.Done c -> return (Done n c)
2788
2781
2789− extract (DeintercalateInitL fs) = fmap (Done 0) $ ffinal fs
2782+ extract (DeintercalateInitL fs) = fmap (Done 0) $ fextract fs
2790 extract (DeintercalateL cnt fs sL) = do
2783 extract (DeintercalateL cnt fs sL) = do
2791 r <- extractL sL
2784 r <- extractL sL
2792 case r of
2785 case r of
@@ -2794,10 +2787,10 @@ deintercalate
2794 Continue n s -> return $ Continue n (DeintercalateL (cnt - n) fs s)
2787 Continue n s -> return $ Continue n (DeintercalateL (cnt - n) fs s)
2795 Partial _ _ -> error "Partial in extract"
2788 Partial _ _ -> error "Partial in extract"
2796 Error _ -> do
2789 Error _ -> do
2797− xs <- ffinal fs
2790+ xs <- fextract fs
2798 return $ Done cnt xs
2791 return $ Done cnt xs
2799− extract (DeintercalateInitR fs) = fmap (Done 0) $ ffinal fs
2792+ extract (DeintercalateInitR fs) = fmap (Done 0) $ fextract fs
2800− extract (DeintercalateR cnt fs _) = fmap (Done cnt) $ ffinal fs
2793+ extract (DeintercalateR cnt fs _) = fmap (Done cnt) $ fextract fs
2801 extract (DeintercalateRL cnt bR fs sL) = do
2794 extract (DeintercalateRL cnt bR fs sL) = do
2802 r <- extractL sL
2795 r <- extractL sL
2803 case r of
2796 case r of
@@ -2809,7 +2802,7 @@ deintercalate
2809 Continue n s -> return $ Continue n (DeintercalateRL (cnt - n) bR fs s)
2802 Continue n s -> return $ Continue n (DeintercalateRL (cnt - n) bR fs s)
2810 Partial _ _ -> error "Partial in extract"
2803 Partial _ _ -> error "Partial in extract"
2811 Error _ -> do
2804 Error _ -> do
2812− xs <- ffinal fs
2805+ xs <- fextract fs
2813 return $ Done cnt xs
2806 return $ Done cnt xs
2814
2807
2815{-# ANN type Deintercalate1State Fuse #-}
2808{-# ANN type Deintercalate1State Fuse #-}
@@ -2846,7 +2839,7 @@ deintercalate1 :: Monad m =>
2846deintercalate1
2839deintercalate1
2847 (Parser stepL initialL extractL)
2840 (Parser stepL initialL extractL)
2848 (Parser stepR initialR _)
2841 (Parser stepR initialR _)
2849− (Fold fstep finitial _ ffinal) = Parser step initial extract
2842+ (Fold fstep finitial fextract) = Parser step initial extract
2850
2843
2851 where
2844 where
2852
2845
@@ -2900,7 +2893,7 @@ deintercalate1
2900 Continue n s -> return $ Continue n (Deintercalate1R (cnt1 - n) fs s)
2893 Continue n s -> return $ Continue n (Deintercalate1R (cnt1 - n) fs s)
2901 Done n b -> processR (cnt1 - n) b fs n
2894 Done n b -> processR (cnt1 - n) b fs n
2902 Error _ -> do
2895 Error _ -> do
2903− xs <- ffinal fs
2896+ xs <- fextract fs
2904 return $ Done cnt1 xs
2897 return $ Done cnt1 xs
2905
2898
2906 step (Deintercalate1InitL cnt fs sL) a = runStepInitL cnt fs sL a
2899 step (Deintercalate1InitL cnt fs sL) a = runStepInitL cnt fs sL a
@@ -2929,14 +2922,14 @@ deintercalate1
2929 -- XXX We could have the fold accept pairs of (bR, bL)
2922 -- XXX We could have the fold accept pairs of (bR, bL)
2930 FL.Done _ -> error "Fold terminated consuming partial input"
2923 FL.Done _ -> error "Fold terminated consuming partial input"
2931 Error _ -> do
2924 Error _ -> do
2932− xs <- ffinal fs
2925+ xs <- fextract fs
2933 return $ Done cnt1 xs
2926 return $ Done cnt1 xs
2934
2927
2935 {-# INLINE extractResult #-}
2928 {-# INLINE extractResult #-}
2936 extractResult n fs r = do
2929 extractResult n fs r = do
2937 res <- fstep fs r
2930 res <- fstep fs r
2938 case res of
2931 case res of
2939− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2932+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2940 FL.Done c -> return (Done n c)
2933 FL.Done c -> return (Done n c)
2941
2934
2942 extract (Deintercalate1InitL cnt fs sL) = do
2935 extract (Deintercalate1InitL cnt fs sL) = do
@@ -2946,8 +2939,8 @@ deintercalate1
2946 Continue n s -> return $ Continue n (Deintercalate1InitL (cnt - n) fs s)
2939 Continue n s -> return $ Continue n (Deintercalate1InitL (cnt - n) fs s)
2947 Partial _ _ -> error "Partial in extract"
2940 Partial _ _ -> error "Partial in extract"
2948 Error err -> return $ Error err
2941 Error err -> return $ Error err
2949− extract (Deintercalate1InitR fs) = fmap (Done 0) $ ffinal fs
2942+ extract (Deintercalate1InitR fs) = fmap (Done 0) $ fextract fs
2950− extract (Deintercalate1R cnt fs _) = fmap (Done cnt) $ ffinal fs
2943+ extract (Deintercalate1R cnt fs _) = fmap (Done cnt) $ fextract fs
2951 extract (Deintercalate1RL cnt bR fs sL) = do
2944 extract (Deintercalate1RL cnt bR fs sL) = do
2952 r <- extractL sL
2945 r <- extractL sL
2953 case r of
2946 case r of
@@ -2959,7 +2952,7 @@ deintercalate1
2959 Continue n s -> return $ Continue n (Deintercalate1RL (cnt - n) bR fs s)
2952 Continue n s -> return $ Continue n (Deintercalate1RL (cnt - n) bR fs s)
2960 Partial _ _ -> error "Partial in extract"
2953 Partial _ _ -> error "Partial in extract"
2961 Error _ -> do
2954 Error _ -> do
2962− xs <- ffinal fs
2955+ xs <- fextract fs
2963 return $ Done cnt xs
2956 return $ Done cnt xs
2964
2957
2965{-# ANN type SepByState Fuse #-}
2958{-# ANN type SepByState Fuse #-}
@@ -3002,7 +2995,7 @@ sepBy :: Monad m =>
3002sepBy
2995sepBy
3003 (Parser stepL initialL extractL)
2996 (Parser stepL initialL extractL)
3004 (Parser stepR initialR _)
2997 (Parser stepR initialR _)
3005− (Fold fstep finitial _ ffinal) = Parser step initial extract
2998+ (Fold fstep finitial fextract) = Parser step initial extract
3006
2999
3007 where
3000 where
3008
3001
@@ -3033,7 +3026,7 @@ sepBy
3033 Done n b ->
3026 Done n b ->
3034 processL (fstep fs b) n SepByInitR
3027 processL (fstep fs b) n SepByInitR
3035 Error _ -> do
3028 Error _ -> do
3036− xs <- ffinal fs
3029+ xs <- fextract fs
3037 return $ Done cnt1 xs
3030 return $ Done cnt1 xs
3038
3031
3039 {-# INLINE processR #-}
3032 {-# INLINE processR #-}
@@ -3053,7 +3046,7 @@ sepBy
3053 Continue n s -> return $ Continue n (SepByR (cnt1 - n) fs s)
3046 Continue n s -> return $ Continue n (SepByR (cnt1 - n) fs s)
3054 Done n _ -> processR (cnt1 - n) fs n
3047 Done n _ -> processR (cnt1 - n) fs n
3055 Error _ -> do
3048 Error _ -> do
3056− xs <- ffinal fs
3049+ xs <- fextract fs
3057 return $ Done cnt1 xs
3050 return $ Done cnt1 xs
3058
3051
3059 step (SepByInitL fs) a = do
3052 step (SepByInitL fs) a = do
@@ -3075,10 +3068,10 @@ sepBy
3075 extractResult n fs r = do
3068 extractResult n fs r = do
3076 res <- fstep fs r
3069 res <- fstep fs r
3077 case res of
3070 case res of
3078− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3071+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3079 FL.Done c -> return (Done n c)
3072 FL.Done c -> return (Done n c)
3080
3073
3081− extract (SepByInitL fs) = fmap (Done 0) $ ffinal fs
3074+ extract (SepByInitL fs) = fmap (Done 0) $ fextract fs
3082 extract (SepByL cnt fs sL) = do
3075 extract (SepByL cnt fs sL) = do
3083 r <- extractL sL
3076 r <- extractL sL
3084 case r of
3077 case r of
@@ -3086,10 +3079,10 @@ sepBy
3086 Continue n s -> return $ Continue n (SepByL (cnt - n) fs s)
3079 Continue n s -> return $ Continue n (SepByL (cnt - n) fs s)
3087 Partial _ _ -> error "Partial in extract"
3080 Partial _ _ -> error "Partial in extract"
3088 Error _ -> do
3081 Error _ -> do
3089− xs <- ffinal fs
3082+ xs <- fextract fs
3090 return $ Done cnt xs
3083 return $ Done cnt xs
3091− extract (SepByInitR fs) = fmap (Done 0) $ ffinal fs
3084+ extract (SepByInitR fs) = fmap (Done 0) $ fextract fs
3092− extract (SepByR cnt fs _) = fmap (Done cnt) $ ffinal fs
3085+ extract (SepByR cnt fs _) = fmap (Done cnt) $ fextract fs
3093
3086
3094-- | Non-backtracking version of sepBy. Several times faster.
3087-- | Non-backtracking version of sepBy. Several times faster.
3095{-# INLINE sepByAll #-}
3088{-# INLINE sepByAll #-}
@@ -3144,7 +3137,7 @@ sepBy1 :: Monad m =>
3144sepBy1
3137sepBy1
3145 (Parser stepL initialL extractL)
3138 (Parser stepL initialL extractL)
3146 (Parser stepR initialR _)
3139 (Parser stepR initialR _)
3147− (Fold fstep finitial _ ffinal) = Parser step initial extract
3140+ (Fold fstep finitial fextract) = Parser step initial extract
3148
3141
3149 where
3142 where
3150
3143
@@ -3191,7 +3184,7 @@ sepBy1
3191 Done n b ->
3184 Done n b ->
3192 processL (fstep fs b) n SepBy1InitR
3185 processL (fstep fs b) n SepBy1InitR
3193 Error _ -> do
3186 Error _ -> do
3194− xs <- ffinal fs
3187+ xs <- fextract fs
3195 return $ Done cnt1 xs
3188 return $ Done cnt1 xs
3196
3189
3197 {-# INLINE processR #-}
3190 {-# INLINE processR #-}
@@ -3211,7 +3204,7 @@ sepBy1
3211 Continue n s -> return $ Continue n (SepBy1R (cnt1 - n) fs s)
3204 Continue n s -> return $ Continue n (SepBy1R (cnt1 - n) fs s)
3212 Done n _ -> processR (cnt1 - n) fs n
3205 Done n _ -> processR (cnt1 - n) fs n
3213 Error _ -> do
3206 Error _ -> do
3214− xs <- ffinal fs
3207+ xs <- fextract fs
3215 return $ Done cnt1 xs
3208 return $ Done cnt1 xs
3216
3209
3217 step (SepBy1InitL cnt fs sL) a = runStepInitL cnt fs sL a
3210 step (SepBy1InitL cnt fs sL) a = runStepInitL cnt fs sL a
@@ -3228,7 +3221,7 @@ sepBy1
3228 extractResult n fs r = do
3221 extractResult n fs r = do
3229 res <- fstep fs r
3222 res <- fstep fs r
3230 case res of
3223 case res of
3231− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3224+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3232 FL.Done c -> return (Done n c)
3225 FL.Done c -> return (Done n c)
3233
3226
3234 extract (SepBy1InitL cnt fs sL) = do
3227 extract (SepBy1InitL cnt fs sL) = do
@@ -3245,10 +3238,10 @@ sepBy1
3245 Continue n s -> return $ Continue n (SepBy1L (cnt - n) fs s)
3238 Continue n s -> return $ Continue n (SepBy1L (cnt - n) fs s)
3246 Partial _ _ -> error "Partial in extract"
3239 Partial _ _ -> error "Partial in extract"
3247 Error _ -> do
3240 Error _ -> do
3248− xs <- ffinal fs
3241+ xs <- fextract fs
3249 return $ Done cnt xs
3242 return $ Done cnt xs
3250− extract (SepBy1InitR fs) = fmap (Done 0) $ ffinal fs
3243+ extract (SepBy1InitR fs) = fmap (Done 0) $ fextract fs
3251− extract (SepBy1R cnt fs _) = fmap (Done cnt) $ ffinal fs
3244+ extract (SepBy1R cnt fs _) = fmap (Done cnt) $ fextract fs
3252
3245
3253-------------------------------------------------------------------------------
3246-------------------------------------------------------------------------------
3254-- Interleaving a collection of parsers
3247-- Interleaving a collection of parsers
@@ -3278,7 +3271,7 @@ roundRobin _ps _f = undefined
3278{-# INLINE sequence #-}
3271{-# INLINE sequence #-}
3279sequence :: Monad m =>
3272sequence :: Monad m =>
3280 D.Stream m (Parser a m b) -> Fold m b c -> Parser a m c
3273 D.Stream m (Parser a m b) -> Fold m b c -> Parser a m c
3281−sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3274+sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
3282 Parser step initial extract
3275 Parser step initial extract
3283
3276
3284 where
3277 where
@@ -3296,7 +3289,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3296 case sres of
3289 case sres of
3297 D.Yield p ss1 -> return $ Continue 1 (Just' p, ss1, fs)
3290 D.Yield p ss1 -> return $ Continue 1 (Just' p, ss1, fs)
3298 D.Stop -> do
3291 D.Stop -> do
3299− c <- ffinal fs
3292+ c <- fextract fs
3300 return $ Done 1 c
3293 return $ Done 1 c
3301 D.Skip ss1 -> return $ Continue 1 (Nothing', ss1, fs)
3294 D.Skip ss1 -> return $ Continue 1 (Nothing', ss1, fs)
3302
3295
@@ -3332,7 +3325,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3332 FL.Done c -> return $ Done 1 c
3325 FL.Done c -> return $ Done 1 c
3333 IError err -> return $ Error err
3326 IError err -> return $ Error err
3334
3327
3335− extract (Nothing', _, fs) = fmap (Done 0) $ ffinal fs
3328+ extract (Nothing', _, fs) = fmap (Done 0) $ fextract fs
3336 extract (Just' (Parser pstep pinit pextr), ss, fs) = do
3329 extract (Just' (Parser pstep pinit pextr), ss, fs) = do
3337 ps <- pinit
3330 ps <- pinit
3338 case ps of
3331 case ps of
@@ -3342,7 +3335,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3342 Done n b -> do
3335 Done n b -> do
3343 res <- fstep fs b
3336 res <- fstep fs b
3344 case res of
3337 case res of
3345− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3338+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3346 FL.Done c -> return (Done n c)
3339 FL.Done c -> return (Done n c)
3347 Error err -> return $ Error err
3340 Error err -> return $ Error err
3348 Continue n s -> return $ Continue n (Just' (Parser pstep (return (IPartial s)) pextr), ss, fs)
3341 Continue n s -> return $ Continue n (Just' (Parser pstep (return (IPartial s)) pextr), ss, fs)
@@ -3350,7 +3343,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3350 IDone b -> do
3343 IDone b -> do
3351 fres <- fstep fs b
3344 fres <- fstep fs b
3352 case fres of
3345 case fres of
3353− FL.Partial fs1 -> fmap (Done 0) $ ffinal fs1
3346+ FL.Partial fs1 -> fmap (Done 0) $ fextract fs1
3354 FL.Done c -> return (Done 0 c)
3347 FL.Done c -> return (Done 0 c)
3355 IError err -> return $ Error err
3348 IError err -> return $ Error err
3356
3349
@@ -3485,7 +3478,7 @@ manyTill :: Monad m
3485 => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3478 => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3486manyTill (Parser stepL initialL extractL)
3479manyTill (Parser stepL initialL extractL)
3487 (Parser stepR initialR _)
3480 (Parser stepR initialR _)
3488− (Fold fstep finitial _ ffinal) =
3481+ (Fold fstep finitial fextract) =
3489 Parser step initial extract
3482 Parser step initial extract
3490
3483
3491 where
3484 where
@@ -3507,7 +3500,7 @@ manyTill (Parser stepL initialL extractL)
3507 resR <- initialR
3500 resR <- initialR
3508 case resR of
3501 case resR of
3509 IPartial sr -> return $ p (ManyTillR 0 fs sr)
3502 IPartial sr -> return $ p (ManyTillR 0 fs sr)
3510− IDone _ -> d <$> ffinal fs
3503+ IDone _ -> d <$> fextract fs
3511 IError _ -> scrutL fs p c d e
3504 IError _ -> scrutL fs p c d e
3512
3505
3513 initial = do
3506 initial = do
@@ -3524,7 +3517,7 @@ manyTill (Parser stepL initialL extractL)
3524 assertM(cnt + 1 - n >= 0)
3517 assertM(cnt + 1 - n >= 0)
3525 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
3518 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
3526 Done n _ -> do
3519 Done n _ -> do
3527− b <- ffinal fs
3520+ b <- fextract fs
3528 return $ Done n b
3521 return $ Done n b
3529 Error _ -> do
3522 Error _ -> do
3530 resL <- initialL
3523 resL <- initialL
@@ -3563,12 +3556,12 @@ manyTill (Parser stepL initialL extractL)
3563 Done n b -> do
3556 Done n b -> do
3564 r <- fstep fs b
3557 r <- fstep fs b
3565 case r of
3558 case r of
3566− FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3559+ FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3567 FL.Done c -> return (Done n c)
3560 FL.Done c -> return (Done n c)
3568 Error err -> return $ Error err
3561 Error err -> return $ Error err
3569 Continue n s -> return $ Continue n (ManyTillL fs s)
3562 Continue n s -> return $ Continue n (ManyTillL fs s)
3570 Partial _ _ -> error "Partial in extract"
3563 Partial _ _ -> error "Partial in extract"
3571− extract (ManyTillR _ fs _) = fmap (Done 0) $ ffinal fs
3564+ extract (ManyTillR _ fs _) = fmap (Done 0) $ fextract fs
3572
3565
3573-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
3566-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
3574-- collects the output in the supplied fold. If the the parser @collect@ fails,
3567-- collects the output in the supplied fold. If the the parser @collect@ fails,
core/src/Streamly/Internal/Data/Parser/Type.hs+70−93
@@ -175,6 +175,9 @@
175
175
176module Streamly.Internal.Data.Parser.Type
176module Streamly.Internal.Data.Parser.Type
177 (
177 (
178+ -- * Setup
179+ -- $setup
180+
178 -- * Types
181 -- * Types
179 Initial (..)
182 Initial (..)
180 , Step (..)
183 , Step (..)
@@ -213,10 +216,7 @@ where
213#include "inline.hs"
216#include "inline.hs"
214#include "assert.hs"
217#include "assert.hs"
215
218
216−#if !MIN_VERSION_base(4,18,0)
217−import Control.Applicative (liftA2)
218−#endif
219−import Control.Applicative (Alternative(..))
219+import Control.Applicative (Alternative(..), liftA2)
220import Control.Exception (Exception(..))
220import Control.Exception (Exception(..))
221-- import Control.Monad (MonadPlus(..), (>=>))
221-- import Control.Monad (MonadPlus(..), (>=>))
222import Control.Monad ((>=>))
222import Control.Monad ((>=>))
@@ -438,7 +438,6 @@ newtype ParseError = ParseError String
438instance Exception ParseError where
438instance Exception ParseError where
439 displayException (ParseError err) = err
439 displayException (ParseError err) = err
440
440
441−-- | Map a function on the result i.e. on @b@ in @Parser a m b@.
442instance Functor m => Functor (Parser a m) where
441instance Functor m => Functor (Parser a m) where
443 {-# INLINE fmap #-}
442 {-# INLINE fmap #-}
444 fmap f (Parser step1 initial1 extract) =
443 fmap f (Parser step1 initial1 extract) =
@@ -505,30 +504,26 @@ data SeqParseState sl f sr = SeqParseL !sl | SeqParseR !f !sr
505-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and
504-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and
506-- zips the results.
505-- zips the results.
507
506
508−-- | Sequential parser application. Apply two parsers sequentially to an input
507+-- | Sequential parser application.
509−-- stream. The first parser runs and processes the input, the remaining input
510−-- is then passed to the second parser. If both parsers succeed, their outputs
511−-- are combined using the supplied function. If either parser fails, the
512−-- operation fails.
513--
508--
514−-- This combinator delivers high performance by stream fusion but it comes with
509+-- Apply two parsers sequentially to an input stream. The first parser runs and
515−-- some limitations. For those cases use the 'Applicative' instance of
510+-- processes the input, the remaining input is then passed to the second
516−-- 'Streamly.Data.ParserK.ParserK'.
511+-- parser. If both parsers succeed, their outputs are combined using the
512+-- supplied function. If either parser fails, the operation fails.
517--
513--
518−-- CAVEAT 1: NO RECURSION. This function is strict in both arguments. As a
514+-- This implementation is strict in the second argument, therefore, the
519−-- result, if a parser is defined recursively using this, it may cause an
515+-- following will fail:
520−-- infintie loop. The following example checks the strictness:
521--
516--
522−-- >>> p = Parser.splitWith const (Parser.satisfy (> 0)) undefined
517+-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
523−-- >>> Stream.parse p $ Stream.fromList [1]
524-- *** Exception: Prelude.undefined
518-- *** Exception: Prelude.undefined
525-- ...
519-- ...
526--
520--
527−-- CAVEAT 2: QUADRATIC TIME COMPLEXITY. Static composition is fast due to
521+-- Although this implementation allows stream fusion, it has quadratic
528−-- stream fusion, but it works well only for limited (e.g. up to 8)
522+-- complexity, making it suitable only for a small number of compositions.
529−-- compositions, use "Streamly.Data.ParserK" for larger compositions.
523+-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
530--
524--
531−-- Below are some common idioms that can be expressed using 'splitWith':
525+-- Below are some common idioms that can be expressed using 'splitWith' and
526+-- other parser primitives:
532--
527--
533-- >>> span p f1 f2 = Parser.splitWith (,) (Parser.takeWhile p f1) (Parser.fromFold f2)
528-- >>> span p f1 f2 = Parser.splitWith (,) (Parser.takeWhile p f1) (Parser.fromFold f2)
534-- >>> spanBy eq f1 f2 = Parser.splitWith (,) (Parser.groupBy eq f1) (Parser.fromFold f2)
529-- >>> spanBy eq f1 f2 = Parser.splitWith (,) (Parser.groupBy eq f1) (Parser.fromFold f2)
@@ -617,12 +612,7 @@ splitWith func (Parser stepL initialL extractL)
617-- We can use the compiler to automatically annotate accumulators, terminating
612-- We can use the compiler to automatically annotate accumulators, terminating
618-- folds, non-failing parsers and failing parsers.
613-- folds, non-failing parsers and failing parsers.
619
614
620−-- | Better performance 'splitWith' for non-failing parsers.
621−--
622−-- Does not work correctly for parsers that can fail.
615+-- | Works correctly only if both the parsers are guaranteed to never fail.
623−--
624−-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
625−--
626{-# INLINE noErrorUnsafeSplitWith #-}
616{-# INLINE noErrorUnsafeSplitWith #-}
627noErrorUnsafeSplitWith :: Monad m
617noErrorUnsafeSplitWith :: Monad m
628 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
618 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
@@ -693,8 +683,6 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
693-- second parser. The output of the parser is the output of the second parser.
683-- second parser. The output of the parser is the output of the second parser.
694-- The operation fails if any of the parsers fail.
684-- The operation fails if any of the parsers fail.
695--
685--
696−-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
697−--
698-- This implementation is strict in the second argument, therefore, the
686-- This implementation is strict in the second argument, therefore, the
699-- following will fail:
687-- following will fail:
700--
688--
@@ -702,6 +690,10 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
702-- *** Exception: Prelude.undefined
690-- *** Exception: Prelude.undefined
703-- ...
691-- ...
704--
692--
693+-- Although this implementation allows stream fusion, it has quadratic
694+-- complexity, making it suitable only for a small number of compositions.
695+-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
696+--
705-- /Pre-release/
697-- /Pre-release/
706--
698--
707{-# INLINE split_ #-}
699{-# INLINE split_ #-}
@@ -757,12 +749,7 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
757 Partial _ _ -> error "split_: Partial"
749 Partial _ _ -> error "split_: Partial"
758 Continue n s -> return $ Continue n (SeqAL s)
750 Continue n s -> return $ Continue n (SeqAL s)
759
751
760−-- | Better performance 'split_' for non-failing parsers.
752+-- For backtracking folds
761−--
762−-- Does not work correctly for parsers that can fail.
763−--
764−-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
765−--
766{-# INLINE noErrorUnsafeSplit_ #-}
753{-# INLINE noErrorUnsafeSplit_ #-}
767noErrorUnsafeSplit_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
754noErrorUnsafeSplit_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
768noErrorUnsafeSplit_
755noErrorUnsafeSplit_
@@ -817,11 +804,7 @@ noErrorUnsafeSplit_
817 Partial _ _ -> error "split_: Partial"
804 Partial _ _ -> error "split_: Partial"
818 Continue n s -> return $ Continue n (SeqAL s)
805 Continue n s -> return $ Continue n (SeqAL s)
819
806
820−-- | READ THE CAVEATS in 'splitWith' before using this instance.
807+-- | 'Applicative' form of 'splitWith'.
821−--
822−-- >>> pure = Parser.fromPure
823−-- >>> (<*>) = Parser.splitWith id
824−-- >>> (*>) = Parser.split_
825instance Monad m => Applicative (Parser a m) where
808instance Monad m => Applicative (Parser a m) where
826 {-# INLINE pure #-}
809 {-# INLINE pure #-}
827 pure = fromPure
810 pure = fromPure
@@ -847,26 +830,20 @@ data AltParseState sl sr = AltParseL !Int !sl | AltParseR !sr
847-- each subsequent alternative's input element has to go through, therefore, it
830-- each subsequent alternative's input element has to go through, therefore, it
848-- cannot scale to a large number of compositions
831-- cannot scale to a large number of compositions
849
832
850−-- | Sequential alternative. The input is first passed to the first parser,
833+-- | Sequential alternative. The input is first passed to the first parser, and
851-- if it succeeds, the result is returned. However, if the first parser fails,
834-- if it succeeds, the result is returned. However, if the first parser fails,
852−-- the parser driver backtracks and tries the same input on the second
835+-- the parser driver backtracks and tries the same input on the second parser,
853−-- (alternative) parser, returning the result if it succeeds.
836+-- returning the result if it succeeds.
854−--
855−-- This combinator delivers high performance by stream fusion but it comes with
856−-- some limitations. For those cases use the 'Alternative' instance of
857−-- 'Streamly.Data.ParserK.ParserK'.
858--
837--
859−-- CAVEAT 1: NO RECURSION. This function is strict in both arguments. As a
838+-- Note: This implementation is not lazy in the second argument. The following
860−-- result, if a parser is defined recursively using this, it may cause an
839+-- will fail:
861−-- infintie loop. The following example checks the strictness:
862--
840--
863−-- >>> p = Parser.satisfy (> 0) `Parser.alt` undefined
841+-- >> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
864−-- >>> Stream.parse p $ Stream.fromList [1..10]
865-- *** Exception: Prelude.undefined
842-- *** Exception: Prelude.undefined
866--
843--
867−-- CAVEAT 2: QUADRATIC TIME COMPLEXITY. Static composition is fast due to
844+-- Although this implementation allows stream fusion, it has quadratic
868−-- stream fusion, but it works well only for limited (e.g. up to 8)
845+-- complexity, making it suitable only for a small number of compositions.
869−-- compositions, use "Streamly.Data.ParserK" for larger compositions.
846+-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
870--
847--
871-- /Time Complexity:/ O(n^2) where n is the number of compositions.
848-- /Time Complexity:/ O(n^2) where n is the number of compositions.
872--
849--
@@ -947,7 +924,7 @@ data Fused3 a b c = Fused3 !a !b !c
947--
924--
948{-# INLINE splitMany #-}
925{-# INLINE splitMany #-}
949splitMany :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
926splitMany :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
950−splitMany (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
927+splitMany (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
951 Parser step initial extract
928 Parser step initial extract
952
929
953 where
930 where
@@ -963,7 +940,7 @@ splitMany (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
963 IPartial ps -> return $ partial $ Fused3 ps 0 fs
940 IPartial ps -> return $ partial $ Fused3 ps 0 fs
964 IDone pb ->
941 IDone pb ->
965 runCollectorWith (handleCollect partial done) fs pb
942 runCollectorWith (handleCollect partial done) fs pb
966− IError _ -> done <$> ffinal fs
943+ IError _ -> done <$> fextract fs
967 FL.Done fb -> return $ done fb
944 FL.Done fb -> return $ done fb
968
945
969 runCollectorWith cont fs pb = fstep fs pb >>= cont
946 runCollectorWith cont fs pb = fstep fs pb >>= cont
@@ -987,19 +964,19 @@ splitMany (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
987 assertM(cnt1 - n >= 0)
964 assertM(cnt1 - n >= 0)
988 fstep fs b >>= handleCollect (Partial n) (Done n)
965 fstep fs b >>= handleCollect (Partial n) (Done n)
989 Error _ -> do
966 Error _ -> do
990− xs <- ffinal fs
967+ xs <- fextract fs
991 return $ Done cnt xs
968 return $ Done cnt xs
992
969
993− extract (Fused3 _ 0 fs) = fmap (Done 0) (ffinal fs)
970+ extract (Fused3 _ 0 fs) = fmap (Done 0) (fextract fs)
994 extract (Fused3 s cnt fs) = do
971 extract (Fused3 s cnt fs) = do
995 r <- extract1 s
972 r <- extract1 s
996 case r of
973 case r of
997− Error _ -> fmap (Done cnt) (ffinal fs)
974+ Error _ -> fmap (Done cnt) (fextract fs)
998 Done n b -> do
975 Done n b -> do
999 assertM(n <= cnt)
976 assertM(n <= cnt)
1000 fs1 <- fstep fs b
977 fs1 <- fstep fs b
1001 case fs1 of
978 case fs1 of
1002− FL.Partial s1 -> fmap (Done n) (ffinal s1)
979+ FL.Partial s1 -> fmap (Done n) (fextract s1)
1003 FL.Done b1 -> return (Done n b1)
980 FL.Done b1 -> return (Done n b1)
1004 Partial _ _ -> error "splitMany: Partial in extract"
981 Partial _ _ -> error "splitMany: Partial in extract"
1005 Continue n s1 -> do
982 Continue n s1 -> do
@@ -1013,7 +990,7 @@ splitMany (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1013--
990--
1014{-# INLINE splitManyPost #-}
991{-# INLINE splitManyPost #-}
1015splitManyPost :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
992splitManyPost :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1016−splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
993+splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1017 Parser step initial extract
994 Parser step initial extract
1018
995
1019 where
996 where
@@ -1029,7 +1006,7 @@ splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1029 IPartial ps -> return $ partial $ Fused3 ps 0 fs
1006 IPartial ps -> return $ partial $ Fused3 ps 0 fs
1030 IDone pb ->
1007 IDone pb ->
1031 runCollectorWith (handleCollect partial done) fs pb
1008 runCollectorWith (handleCollect partial done) fs pb
1032− IError _ -> done <$> ffinal fs
1009+ IError _ -> done <$> fextract fs
1033 FL.Done fb -> return $ done fb
1010 FL.Done fb -> return $ done fb
1034
1011
1035 runCollectorWith cont fs pb = fstep fs pb >>= cont
1012 runCollectorWith cont fs pb = fstep fs pb >>= cont
@@ -1051,18 +1028,18 @@ splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1051 assertM(cnt1 - n >= 0)
1028 assertM(cnt1 - n >= 0)
1052 fstep fs b >>= handleCollect (Partial n) (Done n)
1029 fstep fs b >>= handleCollect (Partial n) (Done n)
1053 Error _ -> do
1030 Error _ -> do
1054− xs <- ffinal fs
1031+ xs <- fextract fs
1055 return $ Done cnt1 xs
1032 return $ Done cnt1 xs
1056
1033
1057 extract (Fused3 s cnt fs) = do
1034 extract (Fused3 s cnt fs) = do
1058 r <- extract1 s
1035 r <- extract1 s
1059 case r of
1036 case r of
1060− Error _ -> fmap (Done cnt) (ffinal fs)
1037+ Error _ -> fmap (Done cnt) (fextract fs)
1061 Done n b -> do
1038 Done n b -> do
1062 assertM(n <= cnt)
1039 assertM(n <= cnt)
1063 fs1 <- fstep fs b
1040 fs1 <- fstep fs b
1064 case fs1 of
1041 case fs1 of
1065− FL.Partial s1 -> fmap (Done n) (ffinal s1)
1042+ FL.Partial s1 -> fmap (Done n) (fextract s1)
1066 FL.Done b1 -> return (Done n b1)
1043 FL.Done b1 -> return (Done n b1)
1067 Partial _ _ -> error "splitMany: Partial in extract"
1044 Partial _ _ -> error "splitMany: Partial in extract"
1068 Continue n s1 -> do
1045 Continue n s1 -> do
@@ -1075,7 +1052,7 @@ splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1075--
1052--
1076{-# INLINE splitSome #-}
1053{-# INLINE splitSome #-}
1077splitSome :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1054splitSome :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1078−splitSome (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1055+splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1079 Parser step initial extract
1056 Parser step initial extract
1080
1057
1081 where
1058 where
@@ -1091,7 +1068,7 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1091 IPartial ps -> return $ partial $ Fused3 ps 0 $ Right fs
1068 IPartial ps -> return $ partial $ Fused3 ps 0 $ Right fs
1092 IDone pb ->
1069 IDone pb ->
1093 runCollectorWith (handleCollect partial done) fs pb
1070 runCollectorWith (handleCollect partial done) fs pb
1094− IError _ -> done <$> ffinal fs
1071+ IError _ -> done <$> fextract fs
1095 FL.Done fb -> return $ done fb
1072 FL.Done fb -> return $ done fb
1096
1073
1097 runCollectorWith cont fs pb = fstep fs pb >>= cont
1074 runCollectorWith cont fs pb = fstep fs pb >>= cont
@@ -1141,7 +1118,7 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1141 Done n b -> do
1118 Done n b -> do
1142 assertM(cnt1 - n >= 0)
1119 assertM(cnt1 - n >= 0)
1143 fstep fs b >>= handleCollect (Partial n) (Done n)
1120 fstep fs b >>= handleCollect (Partial n) (Done n)
1144− Error _ -> Done cnt1 <$> ffinal fs
1121+ Error _ -> Done cnt1 <$> fextract fs
1145
1122
1146 extract (Fused3 s cnt (Left fs)) = do
1123 extract (Fused3 s cnt (Left fs)) = do
1147 r <- extract1 s
1124 r <- extract1 s
@@ -1151,7 +1128,7 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1151 assertM(n <= cnt)
1128 assertM(n <= cnt)
1152 fs1 <- fstep fs b
1129 fs1 <- fstep fs b
1153 case fs1 of
1130 case fs1 of
1154− FL.Partial s1 -> fmap (Done n) (ffinal s1)
1131+ FL.Partial s1 -> fmap (Done n) (fextract s1)
1155 FL.Done b1 -> return (Done n b1)
1132 FL.Done b1 -> return (Done n b1)
1156 Partial _ _ -> error "splitSome: Partial in extract"
1133 Partial _ _ -> error "splitSome: Partial in extract"
1157 Continue n s1 -> do
1134 Continue n s1 -> do
@@ -1160,12 +1137,12 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1160 extract (Fused3 s cnt (Right fs)) = do
1137 extract (Fused3 s cnt (Right fs)) = do
1161 r <- extract1 s
1138 r <- extract1 s
1162 case r of
1139 case r of
1163− Error _ -> fmap (Done cnt) (ffinal fs)
1140+ Error _ -> fmap (Done cnt) (fextract fs)
1164 Done n b -> do
1141 Done n b -> do
1165 assertM(n <= cnt)
1142 assertM(n <= cnt)
1166 fs1 <- fstep fs b
1143 fs1 <- fstep fs b
1167 case fs1 of
1144 case fs1 of
1168− FL.Partial s1 -> fmap (Done n) (ffinal s1)
1145+ FL.Partial s1 -> fmap (Done n) (fextract s1)
1169 FL.Done b1 -> return (Done n b1)
1146 FL.Done b1 -> return (Done n b1)
1170 Partial _ _ -> error "splitSome: Partial in extract"
1147 Partial _ _ -> error "splitSome: Partial in extract"
1171 Continue n s1 -> do
1148 Continue n s1 -> do
@@ -1196,12 +1173,23 @@ dieM err = Parser undefined (IError <$> err) undefined
1196-- Note: With the direct style parser type, the list in "some" and "many" is
1173-- Note: With the direct style parser type, the list in "some" and "many" is
1197-- accumulated strictly, it cannot be consumed lazily.
1174-- accumulated strictly, it cannot be consumed lazily.
1198
1175
1199−-- | READ THE CAVEATS in 'alt' before using this instance.
1176+-- | Sequential alternative. The input is first passed to the first parser, and
1177+-- if it succeeds, the result is returned. However, if the first parser fails,
1178+-- the parser driver backtracks and tries the same input on the second parser,
1179+-- returning the result if it succeeds.
1180+--
1181+-- Note: The implementation of '<|>' is not lazy in the second
1182+-- argument. The following code will fail:
1183+--
1184+-- >>> Stream.parse (Parser.satisfy (> 0) <|> undefined) $ Stream.fromList [1..10]
1185+-- *** Exception: Prelude.undefined
1186+-- ...
1200--
1187--
1201−-- >>> empty = Parser.die "empty"
1188+-- WARNING! this is not suitable for large scale use. As a thumb rule stream
1202−-- >>> (<|>) = Parser.alt
1189+-- fusion works well for less than 8 compositions of this operation, otherwise
1203−-- >>> many = flip Parser.many Fold.toList
1190+-- consider using 'ParserK'. Do not use recursive parser implementations based
1204−-- >>> some = flip Parser.some Fold.toList
1191+-- on this Alternative instance.
1192+
1205instance Monad m => Alternative (Parser a m) where
1193instance Monad m => Alternative (Parser a m) where
1206 {-# INLINE empty #-}
1194 {-# INLINE empty #-}
1207 empty = die "empty"
1195 empty = die "empty"
@@ -1220,13 +1208,8 @@ data ConcatParseState sl m a b =
1220 ConcatParseL !sl
1208 ConcatParseL !sl
1221 | forall s. ConcatParseR (s -> a -> m (Step s b)) s (s -> m (Step s b))
1209 | forall s. ConcatParseR (s -> a -> m (Step s b)) s (s -> m (Step s b))
1222
1210
1223−-- XXX Does it fuse completely? Check and update, it cannot fuse the
1224−-- dynamically generated parser.
1225−
1226-- | Map a 'Parser' returning function on the result of a 'Parser'.
1211-- | Map a 'Parser' returning function on the result of a 'Parser'.
1227--
1212--
1228−-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
1229−--
1230-- /Pre-release/
1213-- /Pre-release/
1231--
1214--
1232{-# INLINE concatMap #-}
1215{-# INLINE concatMap #-}
@@ -1296,12 +1279,6 @@ concatMap func (Parser stepL initialL extractL) = Parser step initial extract
1296 Partial _ _ -> error "concatMap: extract Partial"
1279 Partial _ _ -> error "concatMap: extract Partial"
1297 Continue n s -> return $ Continue n (ConcatParseL s)
1280 Continue n s -> return $ Continue n (ConcatParseL s)
1298
1281
1299−-- | Better performance 'concatMap' for non-failing parsers.
1300−--
1301−-- Does not work correctly for parsers that can fail.
1302−--
1303−-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
1304−--
1305{-# INLINE noErrorUnsafeConcatMap #-}
1282{-# INLINE noErrorUnsafeConcatMap #-}
1306noErrorUnsafeConcatMap :: Monad m =>
1283noErrorUnsafeConcatMap :: Monad m =>
1307 (b -> Parser a m c) -> Parser a m b -> Parser a m c
1284 (b -> Parser a m c) -> Parser a m b -> Parser a m c
@@ -1374,9 +1351,11 @@ noErrorUnsafeConcatMap func (Parser stepL initialL extractL) =
1374-- for small number of compositions but for a scalable implementation we need a
1351-- for small number of compositions but for a scalable implementation we need a
1375-- CPS version.
1352-- CPS version.
1376
1353
1377−-- | READ THE CAVEATS in 'concatMap' before using this instance.
1354+-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1378--
1355--
1379−-- >>> (>>=) = flip Parser.concatMap
1356+-- Although this implementation allows stream fusion, it has quadratic
1357+-- complexity, making it suitable only for a small number of compositions. As a
1358+-- thumb rule use it for less than 8 compositions, use 'ParserK' otherwise.
1380--
1359--
1381instance Monad m => Monad (Parser a m) where
1360instance Monad m => Monad (Parser a m) where
1382 {-# INLINE return #-}
1361 {-# INLINE return #-}
@@ -1388,7 +1367,6 @@ instance Monad m => Monad (Parser a m) where
1388 {-# INLINE (>>) #-}
1367 {-# INLINE (>>) #-}
1389 (>>) = (*>)
1368 (>>) = (*>)
1390
1369
1391−-- | >>> fail = Parser.die
1392instance Monad m => Fail.MonadFail (Parser a m) where
1370instance Monad m => Fail.MonadFail (Parser a m) where
1393 {-# INLINE fail #-}
1371 {-# INLINE fail #-}
1394 fail = die
1372 fail = die
@@ -1404,7 +1382,6 @@ instance Monad m => MonadPlus (Parser a m) where
1404 mplus = alt
1382 mplus = alt
1405-}
1383-}
1406
1384
1407−-- | >>> liftIO = Parser.fromEffect . liftIO
1408instance (MonadIO m) => MonadIO (Parser a m) where
1385instance (MonadIO m) => MonadIO (Parser a m) where
1409 {-# INLINE liftIO #-}
1386 {-# INLINE liftIO #-}
1410 liftIO = fromEffect . liftIO
1387 liftIO = fromEffect . liftIO
core/src/Streamly/Internal/Data/ParserK/Type.hs+65−28
@@ -41,10 +41,7 @@ where
41#include "assert.hs"
41#include "assert.hs"
42#include "inline.hs"
42#include "inline.hs"
43
43
44−#if !MIN_VERSION_base(4,18,0)
45−import Control.Applicative (liftA2)
46−#endif
47−import Control.Applicative (Alternative(..))
44+import Control.Applicative (Alternative(..), liftA2)
48import Control.Monad (MonadPlus(..), ap)
45import Control.Monad (MonadPlus(..), ap)
49import Control.Monad.IO.Class (MonadIO, liftIO)
46import Control.Monad.IO.Class (MonadIO, liftIO)
50-- import Control.Monad.Trans.Class (MonadTrans(lift))
47-- import Control.Monad.Trans.Class (MonadTrans(lift))
@@ -168,8 +165,8 @@ newtype ParserK a m b = MkParser
168-------------------------------------------------------------------------------
165-------------------------------------------------------------------------------
169
166
170-- XXX rewrite this using ParserD, expose rmapM from ParserD.
167-- XXX rewrite this using ParserD, expose rmapM from ParserD.
171−
168+-- | Maps a function over the output of the parser.
172−-- | Map a function on the result i.e. on @b@ in @Parser a m b@.
169+--
173instance Functor m => Functor (ParserK a m) where
170instance Functor m => Functor (ParserK a m) where
174 {-# INLINE fmap #-}
171 {-# INLINE fmap #-}
175 fmap f parser = MkParser $ \k n st arr ->
172 fmap f parser = MkParser $ \k n st arr ->
@@ -181,7 +178,7 @@ instance Functor m => Functor (ParserK a m) where
181-------------------------------------------------------------------------------
178-------------------------------------------------------------------------------
182
179
183-- This is the dual of stream "fromPure".
180-- This is the dual of stream "fromPure".
184−
181+--
185-- | A parser that always yields a pure value without consuming any input.
182-- | A parser that always yields a pure value without consuming any input.
186--
183--
187-- /Pre-release/
184-- /Pre-release/
@@ -199,11 +196,9 @@ fromEffect :: Monad m => m b -> ParserK a m b
199fromEffect eff =
196fromEffect eff =
200 MkParser $ \k n st arr -> eff >>= \b -> k (Success n b) st arr
197 MkParser $ \k n st arr -> eff >>= \b -> k (Success n b) st arr
201
198
202−-- | @f \<$> p1 \<*> p2@ applies parsers p1 and p2 sequentially to an input
199+-- | 'Applicative' form of 'Streamly.Internal.Data.Parser.splitWith'. Note that
203−-- stream. The first parser runs and processes the input, the remaining input
200+-- this operation does not fuse, use 'Streamly.Internal.Data.Parser.splitWith'
204−-- is then passed to the second parser. If both parsers succeed, their outputs
201+-- when fusion is important.
205−-- are applied to the function @f@. If either parser fails, the operation
206−-- fails.
207--
202--
208instance Monad m => Applicative (ParserK a m) where
203instance Monad m => Applicative (ParserK a m) where
209 {-# INLINE pure #-}
204 {-# INLINE pure #-}
@@ -245,8 +240,48 @@ instance Monad m => Applicative (ParserK a m) where
245die :: String -> ParserK a m b
240die :: String -> ParserK a m b
246die err = MkParser (\k n st arr -> k (Failure n err) st arr)
241die err = MkParser (\k n st arr -> k (Failure n err) st arr)
247
242
248−-- | Monad composition can be used for lookbehind parsers, we can dynamically
243+-- | Monad composition can be used for lookbehind parsers, we can make the
249−-- compose new parsers based on the results of the previously parsed values.
244+-- future parses depend on the previously parsed values.
245+--
246+-- If we have to parse "a9" or "9a" but not "99" or "aa" we can use the
247+-- following parser:
248+--
249+-- @
250+-- backtracking :: MonadCatch m => PR.Parser Char m String
251+-- backtracking =
252+-- sequence [PR.satisfy isDigit, PR.satisfy isAlpha]
253+-- '<|>'
254+-- sequence [PR.satisfy isAlpha, PR.satisfy isDigit]
255+-- @
256+--
257+-- We know that if the first parse resulted in a digit at the first place then
258+-- the second parse is going to fail. However, we waste that information and
259+-- parse the first character again in the second parse only to know that it is
260+-- not an alphabetic char. By using lookbehind in a 'Monad' composition we can
261+-- avoid redundant work:
262+--
263+-- @
264+-- data DigitOrAlpha = Digit Char | Alpha Char
265+--
266+-- lookbehind :: MonadCatch m => PR.Parser Char m String
267+-- lookbehind = do
268+-- x1 \<- Digit '<$>' PR.satisfy isDigit
269+-- '<|>' Alpha '<$>' PR.satisfy isAlpha
270+--
271+-- -- Note: the parse depends on what we parsed already
272+-- x2 <- case x1 of
273+-- Digit _ -> PR.satisfy isAlpha
274+-- Alpha _ -> PR.satisfy isDigit
275+--
276+-- return $ case x1 of
277+-- Digit x -> [x,x2]
278+-- Alpha x -> [x,x2]
279+-- @
280+--
281+-- See also 'Streamly.Internal.Data.Parser.concatMap'. This monad instance
282+-- does not fuse, use 'Streamly.Internal.Data.Parser.concatMap' when you need
283+-- fusion.
284+--
250instance Monad m => Monad (ParserK a m) where
285instance Monad m => Monad (ParserK a m) where
251 {-# INLINE return #-}
286 {-# INLINE return #-}
252 return = pure
287 return = pure
@@ -278,10 +313,18 @@ instance MonadIO m => MonadIO (ParserK a m) where
278-- Alternative
313-- Alternative
279-------------------------------------------------------------------------------
314-------------------------------------------------------------------------------
280
315
281−-- | @p1 \<|> p2@ passes the input to parser p1, if it succeeds, the result is
316+-- | 'Alternative' form of 'Streamly.Internal.Data.Parser.alt'. Backtrack and
282−-- returned. However, if p1 fails, the parser driver backtracks and tries the
317+-- run the second parser if the first one fails.
283−-- same input on the alternative parser p2, returning the result if it
318+--
284−-- succeeds.
319+-- The "some" and "many" operations of alternative accumulate results in a pure
320+-- list which is not scalable and streaming. Instead use
321+-- 'Streamly.Internal.Data.Parser.some' and
322+-- 'Streamly.Internal.Data.Parser.many' for fusible operations with composable
323+-- accumulation of results.
324+--
325+-- See also 'Streamly.Internal.Data.Parser.alt'. This 'Alternative' instance
326+-- does not fuse, use 'Streamly.Internal.Data.Parser.alt' when you need
327+-- fusion.
285--
328--
286instance Monad m => Alternative (ParserK a m) where
329instance Monad m => Alternative (ParserK a m) where
287 {-# INLINE empty #-}
330 {-# INLINE empty #-}
@@ -404,7 +447,7 @@ adaptCWith pstep initial extract cont !offset0 !usedCount !input = do
404 go !_ !cur !pst | cur >= end =
447 go !_ !cur !pst | cur >= end =
405 onContinue ((end - start) `div` SIZE_OF(a)) pst
448 onContinue ((end - start) `div` SIZE_OF(a)) pst
406 go !_ !cur !pst = do
449 go !_ !cur !pst = do
407− let !x = unsafeInlineIO $ peekAt cur contents
450+ let !x = unsafeInlineIO $ peekByteIndex cur contents
408 pRes <- pstep pst x
451 pRes <- pstep pst x
409 let elemSize = SIZE_OF(a)
452 let elemSize = SIZE_OF(a)
410 next = INDEX_NEXT(cur,a)
453 next = INDEX_NEXT(cur,a)
@@ -461,8 +504,7 @@ adaptCWith pstep initial extract cont !offset0 !usedCount !input = do
461 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
504 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
462 parseCont !cnt !pst None = parseContNothing cnt pst
505 parseCont !cnt !pst None = parseContNothing cnt pst
463
506
464−-- | Convert an element 'Parser' to a chunked 'ParserK'. A chunked parser is
507+-- | Convert a raw byte 'Parser' to a chunked 'ParserK'.
465−-- more efficient than an element parser.
466--
508--
467-- /Pre-release/
509-- /Pre-release/
468--
510--
@@ -564,9 +606,7 @@ adaptWith pstep initial extract cont !relPos !usedCount !input = do
564 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt pst arr
606 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt pst arr
565 parseCont !cnt !pst None = parseContNothing cnt pst
607 parseCont !cnt !pst None = parseContNothing cnt pst
566
608
567−-- | Convert a 'Parser' to 'ParserK'.
609+-- | Similar to "adaptC" but for non-chunked input.
568−--
569−-- /Pre-release/
570--
610--
571{-# INLINE_LATE adapt #-}
611{-# INLINE_LATE adapt #-}
572adapt :: Monad m => ParserD.Parser a m b -> ParserK a m b
612adapt :: Monad m => ParserD.Parser a m b -> ParserK a m b
@@ -694,10 +734,7 @@ adaptCGWith pstep initial extract cont !offset0 !usedCount !input = do
694 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
734 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
695 parseCont !cnt !pst None = parseContNothing cnt pst
735 parseCont !cnt !pst None = parseContNothing cnt pst
696
736
697−-- | A generic 'adaptC'. Similar to 'adaptC' but is not constrained to 'Unbox'
737+-- | Similar to "adaptC" but is not constrained.
698−-- types.
699−--
700−-- /Pre-release/
701--
738--
702{-# INLINE_LATE adaptCG #-}
739{-# INLINE_LATE adaptCG #-}
703adaptCG ::
740adaptCG ::
core/src/Streamly/Internal/Data/Ring.hs+4−7
@@ -79,7 +79,7 @@ import Foreign.Storable
79import Foreign.ForeignPtr (ForeignPtr, withForeignPtr, touchForeignPtr)
79import Foreign.ForeignPtr (ForeignPtr, withForeignPtr, touchForeignPtr)
80import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
80import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
81import Foreign.Ptr (plusPtr, minusPtr, castPtr)
81import Foreign.Ptr (plusPtr, minusPtr, castPtr)
82−import Streamly.Internal.Data.Unbox as Unboxed (Unbox(peekAt))
82+import Streamly.Internal.Data.Unbox as Unboxed (Unbox(peekByteIndex))
83import GHC.ForeignPtr (mallocPlainForeignPtrAlignedBytes)
83import GHC.ForeignPtr (mallocPlainForeignPtrAlignedBytes)
84import GHC.Ptr (Ptr(..))
84import GHC.Ptr (Ptr(..))
85import Streamly.Internal.Data.MutArray.Type (MutArray)
85import Streamly.Internal.Data.MutArray.Type (MutArray)
@@ -411,7 +411,7 @@ unsafeEqArrayN Ring{..} rh A.Array{..} nBytes
411
411
412 check p i = do
412 check p i = do
413 (relem :: Word8) <- peek p
413 (relem :: Word8) <- peek p
414− aelem <- peekAt i w8Contents
414+ aelem <- peekByteIndex i w8Contents
415 if relem == aelem
415 if relem == aelem
416 then go (p `plusPtr` 1) (i + 1)
416 then go (p `plusPtr` 1) (i + 1)
417 else return False
417 else return False
@@ -445,7 +445,7 @@ unsafeEqArray Ring{..} rh A.Array{..} =
445
445
446 check p i = do
446 check p i = do
447 (relem :: Word8) <- peek p
447 (relem :: Word8) <- peek p
448− aelem <- peekAt i w8Contents
448+ aelem <- peekByteIndex i w8Contents
449 if relem == aelem
449 if relem == aelem
450 then go (p `plusPtr` 1) (i + 1)
450 then go (p `plusPtr` 1) (i + 1)
451 else return False
451 else return False
@@ -558,8 +558,7 @@ data Tuple4' a b c d = Tuple4' !a !b !c !d deriving Show
558{-# INLINE slidingWindowWith #-}
558{-# INLINE slidingWindowWith #-}
559slidingWindowWith :: forall m a b. (MonadIO m, Storable a, Unbox a)
559slidingWindowWith :: forall m a b. (MonadIO m, Storable a, Unbox a)
560 => Int -> Fold m ((a, Maybe a), m (MutArray a)) b -> Fold m a b
560 => Int -> Fold m ((a, Maybe a), m (MutArray a)) b -> Fold m a b
561−slidingWindowWith n (Fold step1 initial1 extract1 final1) =
561+slidingWindowWith n (Fold step1 initial1 extract1) = Fold step initial extract
562− Fold step initial extract final
563
562
564 where
563 where
565
564
@@ -602,8 +601,6 @@ slidingWindowWith n (Fold step1 initial1 extract1 final1) =
602
601
603 extract (Tuple4' _ _ _ st) = extract1 st
602 extract (Tuple4' _ _ _ st) = extract1 st
604
603
605− final (Tuple4' _ _ _ st) = final1 st
606−
607-- | @slidingWindow collector@ is an incremental sliding window
604-- | @slidingWindow collector@ is an incremental sliding window
608-- fold that does not require all the intermediate elements in a computation.
605-- fold that does not require all the intermediate elements in a computation.
609-- This maintains @n@ elements in the window, when a new element comes it slides
606-- This maintains @n@ elements in the window, when a new element comes it slides
core/src/Streamly/Internal/Data/Ring/Generic.hs+1−1
@@ -69,7 +69,7 @@ createRing count = liftIO $ do
69-- the Ring.
69-- the Ring.
70{-# INLINE writeLastN #-}
70{-# INLINE writeLastN #-}
71writeLastN :: MonadIO m => Int -> Fold m a (Ring a)
71writeLastN :: MonadIO m => Int -> Fold m a (Ring a)
72−writeLastN n = Fold step initial extract extract
72+writeLastN n = Fold step initial extract
73
73
74 where
74 where
75
75
core/src/Streamly/Internal/Data/Serialize.hsnew file+122
@@ -0,0 +1,122 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+-- This is required as all the instances in this module are orphan instances.
4+{-# OPTIONS_GHC -fno-warn-orphans #-}
5+
6+-- |
7+-- Module : Streamly.Internal.Data.Serialize
8+-- Copyright : (c) 2023 Composewell Technologies
9+-- License : BSD3-3-Clause
10+-- Maintainer : streamly@composewell.com
11+-- Portability : GHC
12+--
13+
14+module Streamly.Internal.Data.Serialize
15+ ( module Streamly.Internal.Data.Serialize.Type
16+ ) where
17+
18+--------------------------------------------------------------------------------
19+-- Imports
20+--------------------------------------------------------------------------------
21+
22+import Data.Proxy (Proxy)
23+import Streamly.Internal.Data.Array (Array(..))
24+import Streamly.Internal.Data.Unbox (MutableByteArray(..))
25+import GHC.Exts (Int(..), sizeofByteArray#, unsafeCoerce#)
26+
27+import qualified Streamly.Internal.Data.Serialize.TH as Serialize
28+
29+#if __GLASGOW_HASKELL__ >= 900
30+import GHC.Num.Integer (Integer(..))
31+#else
32+import GHC.Integer.GMP.Internals (Integer(..), BigNat(..))
33+#endif
34+
35+import Streamly.Internal.Data.Serialize.Type
36+
37+--------------------------------------------------------------------------------
38+-- Common instances
39+--------------------------------------------------------------------------------
40+
41+-- Note
42+-- ====
43+--
44+-- Even a non-functional change such as changing the order of constructors will
45+-- change the instance derivation.
46+--
47+-- This will not pose a problem if both, encode, and decode are done by the same
48+-- version of the application. There *might* be a problem if version that
49+-- encodes differs from the version that decodes.
50+--
51+-- We need to add some compatibility tests using different versions of
52+-- dependencies.
53+--
54+-- Although such chages for the most basic types won't happen we need to detect
55+-- if it ever happens.
56+--
57+-- Should we worry about these kind of changes and this kind of compatibility?
58+-- This is a problem for all types of derivations that depend on the order of
59+-- constructors, for example, Enum.
60+
61+$(Serialize.deriveSerialize ''Maybe)
62+$(Serialize.deriveSerialize ''Either)
63+$(Serialize.deriveSerializeWith
64+ Serialize.defaultConfig
65+ [d|instance Serialize (Proxy a)|])
66+
67+--------------------------------------------------------------------------------
68+-- Integer
69+--------------------------------------------------------------------------------
70+
71+data LiftedInteger
72+ = LIS Int
73+ | LIP (Array Word)
74+ | LIN (Array Word)
75+
76+$(Serialize.deriveSerialize ''LiftedInteger)
77+
78+#if __GLASGOW_HASKELL__ >= 900
79+
80+{-# INLINE liftInteger #-}
81+liftInteger :: Integer -> LiftedInteger
82+liftInteger (IS x) = LIS (I# x)
83+liftInteger (IP x) =
84+ LIP (Array (MutableByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
85+liftInteger (IN x) =
86+ LIN (Array (MutableByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
87+
88+{-# INLINE unliftInteger #-}
89+unliftInteger :: LiftedInteger -> Integer
90+unliftInteger (LIS (I# x)) = IS x
91+unliftInteger (LIP (Array (MutableByteArray x) _ _)) = IP (unsafeCoerce# x)
92+unliftInteger (LIN (Array (MutableByteArray x) _ _)) = IN (unsafeCoerce# x)
93+
94+#else
95+
96+{-# INLINE liftInteger #-}
97+liftInteger :: Integer -> LiftedInteger
98+liftInteger (S# x) = LIS (I# x)
99+liftInteger (Jp# (BN# x)) =
100+ LIP (Array (MutableByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
101+liftInteger (Jn# (BN# x)) =
102+ LIN (Array (MutableByteArray (unsafeCoerce# x)) 0 (I# (sizeofByteArray# x)))
103+
104+{-# INLINE unliftInteger #-}
105+unliftInteger :: LiftedInteger -> Integer
106+unliftInteger (LIS (I# x)) = S# x
107+unliftInteger (LIP (Array (MutableByteArray x) _ _)) =
108+ Jp# (BN# (unsafeCoerce# x))
109+unliftInteger (LIN (Array (MutableByteArray x) _ _)) =
110+ Jn# (BN# (unsafeCoerce# x))
111+
112+#endif
113+
114+instance Serialize Integer where
115+ {-# INLINE size #-}
116+ size i a = size i (liftInteger a)
117+
118+ {-# INLINE deserialize #-}
119+ deserialize off arr end = fmap unliftInteger <$> deserialize off arr end
120+
121+ {-# INLINE serialize #-}
122+ serialize off arr val = serialize off arr (liftInteger val)
core/src/Streamly/Internal/Data/Serialize/TH.hs+111−118
@@ -7,23 +7,12 @@
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−
15module Streamly.Internal.Data.Serialize.TH
11module Streamly.Internal.Data.Serialize.TH
16− (
17− -- Deriving
18− deriveSerialize
12+ ( deriveSerialize
13+ , Config(..)
14+ , defaultConfig
19 , deriveSerializeWith
15 , deriveSerializeWith
20−
21− -- Utilities
22− , module Streamly.Internal.Data.Serialize.TH.Bottom
23− -- ** Common
24− , module Streamly.Internal.Data.Serialize.TH.Common
25− -- ** RecHeader
26− , module Streamly.Internal.Data.Serialize.TH.RecHeader
27 ) where
16 ) where
28
17
29--------------------------------------------------------------------------------
18--------------------------------------------------------------------------------
@@ -40,6 +29,7 @@ import Streamly.Internal.Data.Serialize.Type
40import Streamly.Internal.Data.Unbox.TH
29import Streamly.Internal.Data.Unbox.TH
41 ( DataCon(..)
30 ( DataCon(..)
42 , DataType(..)
31 , DataType(..)
32+ , appsT
43 , reifyDataType
33 , reifyDataType
44 )
34 )
45
35
@@ -47,14 +37,13 @@ import qualified Streamly.Internal.Data.Serialize.TH.RecHeader as RecHeader
47
37
48import Streamly.Internal.Data.Serialize.TH.Bottom
38import Streamly.Internal.Data.Serialize.TH.Bottom
49import Streamly.Internal.Data.Serialize.TH.Common
39import Streamly.Internal.Data.Serialize.TH.Common
50−import Streamly.Internal.Data.Serialize.TH.RecHeader
51
40
52--------------------------------------------------------------------------------
41--------------------------------------------------------------------------------
53-- Domain specific helpers
42-- Domain specific helpers
54--------------------------------------------------------------------------------
43--------------------------------------------------------------------------------
55
44
56exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
45exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
57−exprGetSize acc (i, _) = [|addSizeTo $(acc) $(varE (mkFieldName i))|]
46+exprGetSize acc (i, _) = [|size $(acc) $(varE (mkFieldName i))|]
58
47
59getTagSize :: Int -> Int
48getTagSize :: Int -> Int
60getTagSize numConstructors
49getTagSize numConstructors
@@ -159,25 +148,22 @@ mkSizeOfExpr False False tyOfTy =
159 [varP _acc, varP _x]
148 [varP _acc, varP _x]
160 (caseE (varE _x) (fmap (matchCons acc) cons))
149 (caseE (varE _x) (fmap (matchCons acc) cons))
161
150
162−mkSizeOfExpr False True (TheType con) = RecHeader.mkRecSizeOfExpr con
151+mkSizeOfExpr False True (TheType con) = RecHeader.mkSizeOfExpr con
163
152
164mkSizeOfExpr _ _ _ = errorUnimplemented
153mkSizeOfExpr _ _ _ = errorUnimplemented
165
154
166−mkSizeDec :: SerializeConfig -> Type -> [DataCon] -> Q [Dec]
155+mkSizeDec :: Config -> Type -> [DataCon] -> Q [Dec]
167−mkSizeDec (SerializeConfig {..}) headTy cons = do
156+mkSizeDec (Config {..}) headTy cons = do
168 -- INLINE on sizeOf actually worsens some benchmarks, and improves none
157 -- INLINE on sizeOf actually worsens some benchmarks, and improves none
169 sizeOfMethod <-
158 sizeOfMethod <-
170 mkSizeOfExpr
159 mkSizeOfExpr
171− cfgConstructorTagAsString
160+ constructorTagAsString
172− cfgRecordSyntaxWithHeader
161+ recordSyntaxWithHeader
173 (typeOfType headTy cons)
162 (typeOfType headTy cons)
174 pure
163 pure
175− ( maybe
176− []
177− (\x -> [PragmaD (InlineP 'addSizeTo x FunLike AllPhases)])
164+ [ PragmaD (InlineP 'size inlineSize FunLike AllPhases)
178− cfgInlineSize
179− ++ [FunD 'addSizeTo [Clause [] (NormalB sizeOfMethod) []]]
165+ , FunD 'size [Clause [] (NormalB sizeOfMethod) []]
180− )
166+ ]
181
167
182--------------------------------------------------------------------------------
168--------------------------------------------------------------------------------
183-- Peek
169-- Peek
@@ -196,7 +182,7 @@ mkDeserializeExpr True False headTy tyOfTy =
196 conLen <- newName "conLen"
182 conLen <- newName "conLen"
197 off1 <- newName "off1"
183 off1 <- newName "off1"
198 [|do ($(varP off1), $(varP conLen) :: Word8) <-
184 [|do ($(varP off1), $(varP conLen) :: Word8) <-
199− deserializeAt
185+ deserialize
200 $(varE _initialOffset)
186 $(varE _initialOffset)
201 $(varE _arr)
187 $(varE _arr)
202 $(varE _endOffset)
188 $(varE _endOffset)
@@ -216,19 +202,18 @@ mkDeserializeExpr True False headTy tyOfTy =
216 [|($(litIntegral lenCname) == $(varE conLen))
202 [|($(litIntegral lenCname) == $(varE conLen))
217 && $(xorCmp tag off _arr)|]
203 && $(xorCmp tag off _arr)|]
218 [|let $(varP (makeI 0)) = $(varE off) + $(litIntegral lenCname)
204 [|let $(varP (makeI 0)) = $(varE off) + $(litIntegral lenCname)
219− in $(mkDeserializeExprOne 'deserializeAt con)|]
205+ in $(mkDeserializeExprOne 'deserialize con)|]
220
206
221mkDeserializeExpr False False headTy tyOfTy =
207mkDeserializeExpr False False headTy tyOfTy =
222 case tyOfTy of
208 case tyOfTy of
223 -- Unit constructor
209 -- Unit constructor
224− -- XXX Should we peek and check if the byte value is 0?
225 UnitType cname ->
210 UnitType cname ->
226 [|pure ($(varE _initialOffset) + 1, $(conE cname))|]
211 [|pure ($(varE _initialOffset) + 1, $(conE cname))|]
227 -- Product type
212 -- Product type
228 TheType con ->
213 TheType con ->
229 letE
214 letE
230 [valD (varP (mkName "i0")) (normalB (varE _initialOffset)) []]
215 [valD (varP (mkName "i0")) (normalB (varE _initialOffset)) []]
231− (mkDeserializeExprOne 'deserializeAt con)
216+ (mkDeserializeExprOne 'deserialize con)
232 -- Sum type
217 -- Sum type
233 MultiType cons -> do
218 MultiType cons -> do
234 let lenCons = length cons
219 let lenCons = length cons
@@ -236,7 +221,7 @@ mkDeserializeExpr False False headTy tyOfTy =
236 doE
221 doE
237 [ bindS
222 [ bindS
238 (tupP [varP (mkName "i0"), varP _tag])
223 (tupP [varP (mkName "i0"), varP _tag])
239− [|deserializeAt $(varE _initialOffset) $(varE _arr) $(varE _endOffset)|]
224+ [|deserialize $(varE _initialOffset) $(varE _arr) $(varE _endOffset)|]
240 , noBindS
225 , noBindS
241 (caseE
226 (caseE
242 (sigE (varE _tag) (conT tagType))
227 (sigE (varE _tag) (conT tagType))
@@ -246,7 +231,7 @@ mkDeserializeExpr False False headTy tyOfTy =
246 peekMatch (i, con) =
231 peekMatch (i, con) =
247 match
232 match
248 (litP (IntegerL i))
233 (litP (IntegerL i))
249− (normalB (mkDeserializeExprOne 'deserializeAt con)) []
234+ (normalB (mkDeserializeExprOne 'deserialize con)) []
250 peekErr =
235 peekErr =
251 match
236 match
252 wildP
237 wildP
@@ -257,15 +242,25 @@ mkDeserializeExpr False False headTy tyOfTy =
257 $(lift (pprint headTy)) ++ ")")|])
242 $(lift (pprint headTy)) ++ ")")|])
258 []
243 []
259
244
260−mkDeserializeExpr False True _ (TheType con@(SimpleDataCon _ fields)) = do
245+mkDeserializeExpr False True headTy (TheType con@(SimpleDataCon _ fields)) = do
261 deserializeWithKeys <- newName "deserializeWithKeys"
246 deserializeWithKeys <- newName "deserializeWithKeys"
262 updateFunc <- newName "updateFunc"
247 updateFunc <- newName "updateFunc"
263− updateFuncDec <- RecHeader.conUpdateFuncDec updateFunc fields
248+ hOff <- newName "hOff"
264− deserializeWithKeysDec <-
249+ finalOff <- newName "finalOff"
265− RecHeader.mkDeserializeKeysDec deserializeWithKeys updateFunc con
250+ deserializeWithKeysMethod <-
251+ RecHeader.mkDeserializeKeysExpr
252+ hOff finalOff _arr _endOffset updateFunc con
253+ updateFuncDec <- RecHeader.conUpdateFuncExpr updateFunc headTy fields
266 letE
254 letE
255+ ([ pure $ FunD
256+ deserializeWithKeys
257+ [ Clause
258+ [VarP hOff, VarP finalOff]
259+ (NormalB deserializeWithKeysMethod)
260+ []
261+ ]
267− (pure <$> (deserializeWithKeysDec ++ updateFuncDec))
262+ ] ++ (pure <$> updateFuncDec))
268− (RecHeader.mkRecDeserializeExpr
263+ (RecHeader.mkDeserializeExpr
269 _initialOffset
264 _initialOffset
270 _endOffset
265 _endOffset
271 deserializeWithKeys
266 deserializeWithKeys
@@ -273,31 +268,26 @@ mkDeserializeExpr False True _ (TheType con@(SimpleDataCon _ fields)) = do
273
268
274mkDeserializeExpr _ _ _ _ = errorUnimplemented
269mkDeserializeExpr _ _ _ _ = errorUnimplemented
275
270
276−mkDeserializeDec :: SerializeConfig -> Type -> [DataCon] -> Q [Dec]
271+mkDeserializeDec :: Config -> Type -> [DataCon] -> Q [Dec]
277−mkDeserializeDec (SerializeConfig {..}) headTy cons = do
272+mkDeserializeDec (Config {..}) headTy cons = do
278 peekMethod <-
273 peekMethod <-
279 mkDeserializeExpr
274 mkDeserializeExpr
280− cfgConstructorTagAsString
275+ constructorTagAsString
281− cfgRecordSyntaxWithHeader
276+ recordSyntaxWithHeader
282 headTy
277 headTy
283 (typeOfType headTy cons)
278 (typeOfType headTy cons)
284 pure
279 pure
285− ( maybe
286− []
287− (\x -> [PragmaD (InlineP 'deserializeAt x FunLike AllPhases)])
280+ [ PragmaD (InlineP 'deserialize inlineDeserialize FunLike AllPhases)
288− cfgInlineDeserialize
289− ++
290− [ FunD
281+ , FunD
291− 'deserializeAt
282+ 'deserialize
292 [ Clause
283 [ Clause
293− (if isUnitType cons && not cfgConstructorTagAsString
284+ (if isUnitType cons && not constructorTagAsString
294 then [VarP _initialOffset, WildP, WildP]
285 then [VarP _initialOffset, WildP, WildP]
295 else [VarP _initialOffset, VarP _arr, VarP _endOffset])
286 else [VarP _initialOffset, VarP _arr, VarP _endOffset])
296 (NormalB peekMethod)
287 (NormalB peekMethod)
297 []
288 []
298 ]
289 ]
299− ]
290+ ]
300− )
301
291
302--------------------------------------------------------------------------------
292--------------------------------------------------------------------------------
303-- Poke
293-- Poke
@@ -305,7 +295,7 @@ mkDeserializeDec (SerializeConfig {..}) headTy cons = do
305
295
306mkSerializeExprTag :: Name -> Int -> Q Exp
296mkSerializeExprTag :: Name -> Int -> Q Exp
307mkSerializeExprTag tagType tagVal =
297mkSerializeExprTag tagType tagVal =
308− [|serializeAt
298+ [|serialize
309 $(varE _initialOffset)
299 $(varE _initialOffset)
310 $(varE _arr)
300 $(varE _arr)
311 $((sigE (litE (IntegerL (fromIntegral tagVal))) (conT tagType)))|]
301 $((sigE (litE (IntegerL (fromIntegral tagVal))) (conT tagType)))|]
@@ -340,14 +330,13 @@ mkSerializeExpr True False tyOfTy =
340 (doE [ bindS
330 (doE [ bindS
341 (varP (mkName "i0"))
331 (varP (mkName "i0"))
342 (serializeW8List _initialOffset _arr conEnc)
332 (serializeW8List _initialOffset _arr conEnc)
343− , noBindS (mkSerializeExprFields 'serializeAt fields)
333+ , noBindS (mkSerializeExprFields 'serialize fields)
344 ])
334 ])
345
335
346mkSerializeExpr False False tyOfTy =
336mkSerializeExpr False False tyOfTy =
347 case tyOfTy of
337 case tyOfTy of
348 -- Unit type
338 -- Unit type
349− UnitType _ ->
350− [|serializeAt $(varE _initialOffset) $(varE _arr) (0 :: Word8)|]
339+ UnitType _ -> [|pure ($(varE _initialOffset) + 1)|]
351 -- Product type
340 -- Product type
352 (TheType (SimpleDataCon cname fields)) ->
341 (TheType (SimpleDataCon cname fields)) ->
353 letE
342 letE
@@ -357,7 +346,7 @@ mkSerializeExpr False False tyOfTy =
357 [ matchConstructor
346 [ matchConstructor
358 cname
347 cname
359 (length fields)
348 (length fields)
360− (mkSerializeExprFields 'serializeAt fields)
349+ (mkSerializeExprFields 'serialize fields)
361 ])
350 ])
362 -- Sum type
351 -- Sum type
363 (MultiType cons) -> do
352 (MultiType cons) -> do
@@ -374,40 +363,35 @@ mkSerializeExpr False False tyOfTy =
374 (mkSerializeExprTag tagType tagVal)
363 (mkSerializeExprTag tagType tagVal)
375 , noBindS
364 , noBindS
376 (mkSerializeExprFields
365 (mkSerializeExprFields
377− 'serializeAt
366+ 'serialize
378 fields)
367 fields)
379 ]))
368 ]))
380 (zip [0 ..] cons))
369 (zip [0 ..] cons))
381
370
382mkSerializeExpr False True (TheType con) =
371mkSerializeExpr False True (TheType con) =
383− RecHeader.mkRecSerializeExpr _initialOffset con
372+ RecHeader.mkSerializeExpr _initialOffset con
384
373
385mkSerializeExpr _ _ _ = errorUnimplemented
374mkSerializeExpr _ _ _ = errorUnimplemented
386
375
387−mkSerializeDec :: SerializeConfig -> Type -> [DataCon] -> Q [Dec]
376+mkSerializeDec :: Config -> Type -> [DataCon] -> Q [Dec]
388−mkSerializeDec (SerializeConfig {..}) headTy cons = do
377+mkSerializeDec (Config {..}) headTy cons = do
389 pokeMethod <-
378 pokeMethod <-
390 mkSerializeExpr
379 mkSerializeExpr
391− cfgConstructorTagAsString
380+ constructorTagAsString
392− cfgRecordSyntaxWithHeader
381+ recordSyntaxWithHeader
393 (typeOfType headTy cons)
382 (typeOfType headTy cons)
394 pure
383 pure
395− ( maybe
396− []
397− (\x -> [PragmaD (InlineP 'serializeAt x FunLike AllPhases)])
384+ [ PragmaD (InlineP 'serialize inlineSerialize FunLike AllPhases)
398− cfgInlineSerialize
399− ++
400− [FunD
385+ , FunD
401− 'serializeAt
386+ 'serialize
402− [ Clause
387+ [ Clause
403− (if isUnitType cons && not cfgConstructorTagAsString
388+ (if isUnitType cons && not constructorTagAsString
404− then [VarP _initialOffset, VarP _arr, WildP]
389+ then [VarP _initialOffset, WildP, WildP]
405− else [VarP _initialOffset, VarP _arr, VarP _val])
390+ else [VarP _initialOffset, VarP _arr, VarP _val])
406− (NormalB pokeMethod)
391+ (NormalB pokeMethod)
407− []
408− ]
392+ []
409− ]
393+ ]
410− )
394+ ]
411
395
412--------------------------------------------------------------------------------
396--------------------------------------------------------------------------------
413-- Main
397-- Main
@@ -429,7 +413,7 @@ mkSerializeDec (SerializeConfig {..}) headTy cons = do
429-- Usage:
413-- Usage:
430-- @
414-- @
431-- $(deriveSerializeInternal
415-- $(deriveSerializeInternal
432−-- serializeConfig
416+-- defaultConfig
433-- [AppT (ConT ''Serialize) (VarT (mkName "b"))]
417-- [AppT (ConT ''Serialize) (VarT (mkName "b"))]
434-- (AppT
418-- (AppT
435-- (AppT (ConT ''CustomDataType) (VarT (mkName "a")))
419-- (AppT (ConT ''CustomDataType) (VarT (mkName "a")))
@@ -444,7 +428,7 @@ mkSerializeDec (SerializeConfig {..}) headTy cons = do
444-- ])
428-- ])
445-- @
429-- @
446deriveSerializeInternal ::
430deriveSerializeInternal ::
447− SerializeConfig -> Type -> [DataCon] -> ([Dec] -> Q [Dec]) -> Q [Dec]
431+ Config -> Type -> [DataCon] -> ([Dec] -> Q [Dec]) -> Q [Dec]
448deriveSerializeInternal conf headTy cons next = do
432deriveSerializeInternal conf headTy cons next = do
449 sizeDec <- mkSizeDec conf headTy cons
433 sizeDec <- mkSizeDec conf headTy cons
450 peekDec <- mkDeserializeDec conf headTy cons
434 peekDec <- mkDeserializeDec conf headTy cons
@@ -452,41 +436,30 @@ deriveSerializeInternal conf headTy cons next = do
452 let methods = concat [sizeDec, peekDec, pokeDec]
436 let methods = concat [sizeDec, peekDec, pokeDec]
453 next methods
437 next methods
454
438
455−-- | @deriveSerializeWith config-modifier instance-dec@ generates a template
439+-- | Similar to 'deriveSerialize' but take a 'Config' to control how the
456−-- Haskell splice consisting of a declaration of a 'Serialize' instance.
440+-- instance is generated.
457−-- @instance-dec@ is a template Haskell declaration splice consisting of a
458−-- standard Haskell instance declaration without the type class methods (e.g.
459−-- @[d|instance Serialize a => Serialize (Maybe a)|]@).
460−--
461−-- The type class methods for the given instance are generated according to the
462−-- supplied @config-modifier@ parameter. See 'SerializeConfig' for default
463−-- configuration settings.
464--
441--
465-- Usage:
442-- Usage:
466−--
467-- @
443-- @
468−-- \$(deriveSerializeWith
444+-- $(deriveSerializeWith
469−-- ( inlineSerializeAt (Just NoInline)
445+-- config
470−-- . inlineDeserializeAt (Just NoInline)
471−-- )
472-- [d|instance Serialize a => Serialize (Maybe a)|])
446-- [d|instance Serialize a => Serialize (Maybe a)|])
473-- @
447-- @
474−deriveSerializeWith ::
448+deriveSerializeWith :: Config -> Q [Dec] -> Q [Dec]
475− (SerializeConfig -> SerializeConfig) -> Q [Dec] -> Q [Dec]
476−deriveSerializeWith modifier mDecs = do
449+deriveSerializeWith conf mDecs = do
477 dec <- mDecs
450 dec <- mDecs
478 case dec of
451 case dec of
479− [InstanceD mo preds headTyWC []] -> do
452+ [inst@(InstanceD _ _ headTyWC [])] -> do
480 let headTy = unwrap dec headTyWC
453 let headTy = unwrap dec headTyWC
481 dt <- reifyDataType (getMainTypeName dec headTy)
454 dt <- reifyDataType (getMainTypeName dec headTy)
482 let cons = dtCons dt
455 let cons = dtCons dt
483− deriveSerializeInternal
456+ deriveSerializeInternal conf headTy cons (next inst)
484− (modifier serializeConfig) headTy cons (next mo preds headTyWC)
457+ _ -> errorUnsupported
485− _ -> errorMessage dec
486−
487− where
458+ where
488
459
460+ next (InstanceD mo preds headTyWC []) methods =
489− next mo preds headTyWC methods = pure [InstanceD mo preds headTyWC methods]
461+ pure [InstanceD mo preds headTyWC methods]
462+ next _ _ = errorUnsupported
490
463
491 errorMessage dec =
464 errorMessage dec =
492 error $ unlines
465 error $ unlines
@@ -494,8 +467,8 @@ deriveSerializeWith modifier mDecs = do
494 , ""
467 , ""
495 , ">> " ++ pprint dec
468 , ">> " ++ pprint dec
496 , ""
469 , ""
497− , "The supplied declaration is not a valid instance declaration."
470+ , "The above is not a valid instance declaration."
498− , "Provide a valid Haskell instance declaration without a body."
471+ , "Any haskell instance declaration without a body is valid."
499 , ""
472 , ""
500 , "Examples:"
473 , "Examples:"
501 , "instance Serialize (Proxy a)"
474 , "instance Serialize (Proxy a)"
@@ -514,17 +487,37 @@ deriveSerializeWith modifier mDecs = do
514 go (AppT l _) = go l
487 go (AppT l _) = go l
515 go _ = errorMessage dec
488 go _ = errorMessage dec
516
489
517−-- | Given an 'Serialize' instance declaration splice without the methods (e.g.
490+
518−-- @[d|instance Serialize a => Serialize (Maybe a)|]@), generate an instance
491+-- | Template haskell helper to create instances of 'Serialize' automatically.
519−-- declaration including all the type class method implementations.
520--
492--
521−-- >>> deriveSerialize = deriveSerializeWith id
493+-- Consider the datatype:
494+-- @
495+-- data CustomDataType a b c = ...
496+-- @
522--
497--
523−-- Usage:
498+-- Usage: @$(deriveSerialize ''CustomDataType)@
524--
499--
500+-- Note: All type variables automatcally get an "Serialize" constraint.
501+-- The derived code will look like the following,
525-- @
502-- @
526−-- \$(deriveSerialize
527−-- [d|instance Serialize a => Serialize (Maybe a)|])
503+-- instance (Serialize a, Serialize b, Serialize c) => Serialize (CustomDataType a b c) where
504+-- ...
528-- @
505-- @
506+--
507+-- To control which type variables don't get the Serialize constraint, use
508+-- 'deriveSerializeWith'.
529−deriveSerialize :: Q [Dec] -> Q [Dec]
509+deriveSerialize :: Name -> Q [Dec]
530−deriveSerialize = deriveSerializeWith id
510+deriveSerialize name = do
511+ dt <- reifyDataType name
512+ let preds = map (unboxPred . VarT) (dtTvs dt)
513+ headTy = appsT (ConT name) (map VarT (dtTvs dt))
514+ cons = dtCons dt
515+ deriveSerializeInternal defaultConfig headTy cons (next preds headTy)
516+
517+
518+ where
519+
520+ next preds headTy methods =
521+ pure [InstanceD Nothing preds (AppT (ConT ''Serialize) headTy) methods]
522+
523+ unboxPred ty = AppT (ConT ''Serialize) ty
core/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs+39−153
@@ -9,17 +9,8 @@
9-- Portability : GHC
9-- Portability : GHC
10--
10--
11module Streamly.Internal.Data.Serialize.TH.Bottom
11module Streamly.Internal.Data.Serialize.TH.Bottom
12− (
13− -- ** Config
12+ ( Config(..)
14− SerializeConfig(..)
13+ , defaultConfig
15− , serializeConfig
16− , inlineAddSizeTo
17− , inlineSerializeAt
18− , inlineDeserializeAt
19− , encodeConstrNames
20− , encodeRecordFields
21−
22− -- ** Other Utilities
23 , TypeOfType(..)
14 , TypeOfType(..)
24 , typeOfType
15 , typeOfType
25 , SimpleDataCon(..)
16 , SimpleDataCon(..)
@@ -74,134 +65,35 @@ import Streamly.Internal.Data.Unbox.TH (DataCon(..))
74-- Config
65-- Config
75--------------------------------------------------------------------------------
66--------------------------------------------------------------------------------
76
67
77−-- NOTE: 'Nothing' is not eqvivalant to 'Just Inlinable'. Ie. Having no inline
78−-- specific pragma and having an Inlinable pragma are different. Having an
79−-- Inlinable pragma makes GHC put the code in the interface file whereas having
80−-- no inline specific pragma let's GHC decide whether to put the code in
81−-- interface file or not.
82−
83−-- | Configuration to control how the 'Serialize' instance is generated. The
68+-- | Config to control how the 'Serialize' instance is generated.
84−-- configuration is opaque and is modified by composing config modifier
69+data Config =
85−-- functions, for example:
70+ Config
86−--
71+ { inlineSize :: Inline
87−-- >>> (inlineSerializeAt (Just NoInline)) . (inlineSerializeAt (Just Inlinable))
72+ -- ^ Inline value for 'size'. Default is Inline.
88−--
73+ , inlineSerialize :: Inline
89−-- The default configuration settings are:
74+ -- ^ Inline value for 'serialize'. Default is Inline.
90−--
75+ , inlineDeserialize :: Inline
91−-- * 'inlineAddSizeTo' Nothing
76+ -- ^ Inline value for 'deserialize'. Default is Inline.
92−-- * 'inlineSerializeAt' (Just Inline)
77+ , constructorTagAsString :: Bool
93−-- * 'inlineDeserializeAt' (Just Inline)
78+ -- ^ __Experimental__
94−--
79+ --
95−-- The following experimental options are also available:
80+ -- If True, encode constructors using the constructor names as Latin-1
96−--
81+ -- byte sequence.
97−-- * 'encodeConstrNames' False
82+ , recordSyntaxWithHeader :: Bool
98−-- * 'encodeRecordFields' False
83+ -- ^ __Experimental__
99−--
84+ --
100−data SerializeConfig =
85+ -- If True, encode the keys of the record as a header and then
101− SerializeConfig
86+ -- serialize the data.
102− { cfgInlineSize :: Maybe Inline
103− , cfgInlineSerialize :: Maybe Inline
104− , cfgInlineDeserialize :: Maybe Inline
105− , cfgConstructorTagAsString :: Bool
106− , cfgRecordSyntaxWithHeader :: Bool
107 }
87 }
108
88
109−-- | How should we inline the 'addSizeTo' function? The default is 'Nothing'
89+defaultConfig :: Config
110−-- which means left to the compiler. Forcing inline on @addSizeTo@ function
90+defaultConfig =
111−-- actually worsens some benchmarks and improves none.
91+ Config
112−inlineAddSizeTo :: Maybe Inline -> SerializeConfig -> SerializeConfig
92+ { inlineSize = Inline
113−inlineAddSizeTo v cfg = cfg {cfgInlineSize = v}
93+ , inlineSerialize = Inline
114−
94+ , inlineDeserialize = Inline
115−-- XXX Should we make the default Inlinable instead?
95+ , constructorTagAsString = False
116−
96+ , recordSyntaxWithHeader = False
117−-- | How should we inline the 'serialize' function? The default 'Just Inline'.
118−-- However, aggressive inlining can bloat the code and increase in compilation
119−-- times when there are big functions and too many nesting levels so you can
120−-- change it accordingly. A 'Nothing' value leaves the decision to the
121−-- compiler.
122−inlineSerializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
123−inlineSerializeAt v cfg = cfg {cfgInlineSerialize = v}
124−
125−-- XXX Should we make the default Inlinable instead?
126−
127−-- | How should we inline the 'deserialize' function? See guidelines in
128−-- 'inlineSerializeAt'.
129−inlineDeserializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
130−inlineDeserializeAt v cfg = cfg {cfgInlineDeserialize = v}
131−
132−-- | __Experimental__
133−--
134−-- In sum types, use Latin-1 encoded original constructor names rather than
135−-- binary values to identify constructors. This option is not applicable to
136−-- product types.
137−--
138−-- This option enables the following behavior:
139−--
140−-- * __Reordering__: Order of the fields can be changed without affecting
141−-- serialization.
142−-- * __Addition__: If a field is added in the new version, the old version of
143−-- the data type can still be deserialized by the new version. The new value
144−-- would never occur in the old one.
145−-- * __Deletion__: If a field is deleted in the new version, deserialization
146−-- of the old version will result in an error. TBD: We can possibly designate a
147−-- catch-all case to handle this scenario.
148−--
149−-- Note that if you change a type, change the semantics of a type, or delete a
150−-- field and add a new field with the same name, deserialization of old data
151−-- may result in silent unexpected behavior.
152−--
153−-- This option has to be the same on both encoding and decoding side.
154−--
155−-- The default is 'False'.
156−--
157−encodeConstrNames :: Bool -> SerializeConfig -> SerializeConfig
158−encodeConstrNames v cfg = cfg {cfgConstructorTagAsString = v}
159−
160−-- XXX We can deserialize each field to Either, so if there is a
161−-- deserialization error in any field it can handled independently. Also, a
162−-- unique type/version identifier of the field (based on the versions of the
163−-- packages, full module name space + type identifier) can be serialized along
164−-- with the value for stricter compatibility, semantics checking. Or we can
165−-- store a type hash.
166−
167−-- | __Experimental__
168−--
169−-- In explicit record types, use Latin-1 encoded record field names rather than
170−-- binary values to identify the record fields. Note that this option is not
171−-- applicable to sum types. Also, it does not work on a product type which is
172−-- not a record, because there are no field names to begin with.
173−--
174−-- This option enables the following behavior:
175−--
176−-- * __Reordering__: Order of the fields can be changed without affecting
177−-- serialization.
178−-- * __Addition__: If a 'Maybe' type field is added in the new version, the old
179−-- version of the data type can still be deserialized by the new version, the
180−-- field value in the older version is assumed to be 'Nothing'. If any other
181−-- type of field is added, deserialization of the older version results in an
182−-- error but only when that field is actually accessed in the deserialized
183−-- record.
184−-- * __Deletion__: If a field is deleted in the new version and it is
185−-- encountered in a previously serialized version then the field is discarded.
186−--
187−-- This option has to be the same on both encoding and decoding side.
188−--
189−-- There is a constant performance overhead proportional to the total length of
190−-- the record field names and the number of record fields.
191−--
192−-- The default is 'False'.
193−--
194−encodeRecordFields :: Bool -> SerializeConfig -> SerializeConfig
195−encodeRecordFields v cfg = cfg {cfgRecordSyntaxWithHeader = v}
196−
197−serializeConfig :: SerializeConfig
198−serializeConfig =
199− SerializeConfig
200− { cfgInlineSize = Nothing
201− , cfgInlineSerialize = Just Inline
202− , cfgInlineDeserialize = Just Inline
203− , cfgConstructorTagAsString = False
204− , cfgRecordSyntaxWithHeader = False
205 }
97 }
206
98
207--------------------------------------------------------------------------------
99--------------------------------------------------------------------------------
@@ -347,7 +239,7 @@ xorCmp tag off arr =
347 go8 i = do
239 go8 i = do
348 let wIntegral = litIntegral i
240 let wIntegral = litIntegral i
349 [|xor (unsafeInlineIO
241 [|xor (unsafeInlineIO
350− (Unbox.peekAt
242+ (Unbox.peekByteIndex
351 ($(varE off) + $(litIntegral i))
243 ($(varE off) + $(litIntegral i))
352 $(varE arr)))
244 $(varE arr)))
353 ($(wIntegral) :: Word8) .|.
245 ($(wIntegral) :: Word8) .|.
@@ -361,7 +253,7 @@ xorCmp tag off arr =
361 litIntegral
253 litIntegral
362 (shiftAdd w8_w16 [tag !! i, tag !! (i + 1)] :: Word16)
254 (shiftAdd w8_w16 [tag !! i, tag !! (i + 1)] :: Word16)
363 [|xor (unsafeInlineIO
255 [|xor (unsafeInlineIO
364− (Unbox.peekAt
256+ (Unbox.peekByteIndex
365 ($(varE off) + $(litIntegral i))
257 ($(varE off) + $(litIntegral i))
366 $(varE arr)))
258 $(varE arr)))
367 ($(wIntegral) :: Word16) .|.
259 ($(wIntegral) :: Word16) .|.
@@ -381,7 +273,7 @@ xorCmp tag off arr =
381 , tag !! (i + 3)
273 , tag !! (i + 3)
382 ] :: Word32)
274 ] :: Word32)
383 [|xor (unsafeInlineIO
275 [|xor (unsafeInlineIO
384− (Unbox.peekAt
276+ (Unbox.peekByteIndex
385 ($(varE off) + $(litIntegral i))
277 ($(varE off) + $(litIntegral i))
386 $(varE arr)))
278 $(varE arr)))
387 ($(wIntegral) :: Word32) .|.
279 ($(wIntegral) :: Word32) .|.
@@ -405,7 +297,7 @@ xorCmp tag off arr =
405 , tag !! (i + 7)
297 , tag !! (i + 7)
406 ])
298 ])
407 [|xor (unsafeInlineIO
299 [|xor (unsafeInlineIO
408− (Unbox.peekAt
300+ (Unbox.peekByteIndex
409 ($(varE off) + $(litIntegral i))
301 ($(varE off) + $(litIntegral i))
410 $(varE arr)))
302 $(varE arr)))
411 ($(wIntegral) :: Word64) .|.
303 ($(wIntegral) :: Word64) .|.
@@ -431,7 +323,7 @@ serializeW8List off arr w8List = do
431 makeBind i =
323 makeBind i =
432 bindS
324 bindS
433 (varP (makeN (i + 1)))
325 (varP (makeN (i + 1)))
434− [|$(varE 'serializeAt)
326+ [|$(varE 'serialize)
435 $(varE (makeN i))
327 $(varE (makeN i))
436 $(varE arr)
328 $(varE arr)
437 ($(litIntegral (w8List !! i)) :: Word8)|]
329 ($(litIntegral (w8List !! i)) :: Word8)|]
@@ -450,26 +342,20 @@ litProxy = litE . IntegerL . fromIntegral . Unbox.sizeOf
450-- Error codes
342-- Error codes
451--------------------------------------------------------------------------------
343--------------------------------------------------------------------------------
452
344
453−errorUnsupported :: String -> a
345+errorUnsupported :: a
454−errorUnsupported err =
346+errorUnsupported =
455 error
347 error
456 $ unlines
348 $ unlines
457− [ "Unsupported"
349+ [ "Unsupported."
458− , "==========="
459− , "This is improper use of the library."
350+ , "There is improper use of the library."
460 , "This case is unsupported."
351 , "This case is unsupported."
461 , "Please contact the developer if this case is of interest."
352 , "Please contact the developer if this case is of interest."
462− , ""
463− , "Message"
464− , "-------"
465− , err
466 ]
353 ]
467
354
468errorUnimplemented :: a
355errorUnimplemented :: a
469errorUnimplemented =
356errorUnimplemented =
470 error
357 error
471 $ unlines
358 $ unlines
472− [ "Unimplemented"
359+ [ "Unimplemented."
473− , "============="
474 , "Please contact the developer if this case is of interest."
360 , "Please contact the developer if this case is of interest."
475 ]
361 ]
core/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs+98−181
@@ -9,11 +9,11 @@
9-- Portability : GHC
9-- Portability : GHC
10--
10--
11module Streamly.Internal.Data.Serialize.TH.RecHeader
11module Streamly.Internal.Data.Serialize.TH.RecHeader
12− ( mkRecSerializeExpr
12+ ( mkSerializeExpr
13− , mkRecDeserializeExpr
13+ , mkDeserializeExpr
14− , mkRecSizeOfExpr
14+ , mkSizeOfExpr
15− , conUpdateFuncDec
15+ , conUpdateFuncExpr
16− , mkDeserializeKeysDec
16+ , mkDeserializeKeysExpr
17 ) where
17 ) where
18
18
19--------------------------------------------------------------------------------
19--------------------------------------------------------------------------------
@@ -22,12 +22,12 @@ module Streamly.Internal.Data.Serialize.TH.RecHeader
22
22
23import Control.Monad (void)
23import Control.Monad (void)
24import Data.List (foldl')
24import Data.List (foldl')
25−import Data.Word (Word32, Word8)
25+import Data.Word (Word16, Word32, Word8)
26import Data.Maybe (fromJust)
26import Data.Maybe (fromJust)
27import Language.Haskell.TH
27import Language.Haskell.TH
28import Streamly.Internal.Data.Serialize.Type (Serialize(..))
28import Streamly.Internal.Data.Serialize.Type (Serialize(..))
29import Data.Foldable (foldlM)
29import Data.Foldable (foldlM)
30−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
30+import Streamly.Internal.Data.Unbox (MutableByteArray)
31import Data.Proxy (Proxy(..))
31import Data.Proxy (Proxy(..))
32
32
33import qualified Streamly.Internal.Data.Unbox as Unbox
33import qualified Streamly.Internal.Data.Unbox as Unbox
@@ -39,55 +39,9 @@ import Streamly.Internal.Data.Serialize.TH.Common
39-- Notes
39-- Notes
40--------------------------------------------------------------------------------
40--------------------------------------------------------------------------------
41
41
42−-- Compatibility Algorithm
42+-- Encoding the header length is required to check if we want to compare the
43−-- =======================
43+-- header. We should not compare the headers if the lengths of the headers are
44−--
44+-- not equal as this might lead to a runtime error.
45−-- The algorithm is written without any low level implementation details. See
46−-- the code for any low level implementation details.
47−--
48−-- Serialization:
49−-- --------------
50−--
51−-- To serialize the data,
52−--
53−-- * Get the list of keys for the record as @keyList@.
54−-- * Serialize the @keyList@.
55−-- * Serialize the @fields@ one-by-one after serializing the @keyList@.
56−--
57−-- Deserialization:
58−-- ----------------
59−--
60−-- To deserialize the data to type @T@,
61−--
62−-- __Checking for type match__:
63−--
64−-- * Get the list of keys for type @T@ as @targetKeyList@.
65−-- * Get the list of keys encoded as @encodedKeyList@.
66−-- * If @targetKeyList == encodedKeyList@ see the __Type Match__ section else
67−-- see the __No Type Match__ section.
68−--
69−-- __Type Match__:
70−--
71−-- * Decode the fields one-by-one and construct the type @T@ in the end.
72−--
73−-- __No Type Match__:
74−--
75−-- * Decode the list of keys encoded into @encodedKeyList@.
76−-- * Get the list of keys for type @T@ as @targetKeyList@.
77−-- * Loop through @encodedKeyList@ and start deserializing the encoded data.
78−-- * If the key is present in @encodedKeyList@ and not in @targetKeyList@
79−-- then skip parsing the corresponding value.
80−-- * If the key is present in @targetKeyList@ and not in @encodedKeyList@
81−-- then set the value for that key as @Nothing@.
82−-- * If the key is present in both @encodedKeyList@ and in @targetKeyList@
83−-- parse the value.
84−-- * Construct @T@ after parsing all the data.
85−
86−-- Developer Notes
87−-- ===============
88−--
89−-- * Record update syntax is not robust across language extensions and common
90−-- record plugins (like record-dot-processor, large-records, etc.).
91
45
92--------------------------------------------------------------------------------
46--------------------------------------------------------------------------------
93-- Compact lists
47-- Compact lists
@@ -103,36 +57,36 @@ newtype CompactList a =
103-- the list is 255.
57-- the list is 255.
104instance forall a. Serialize a => Serialize (CompactList a) where
58instance forall a. Serialize a => Serialize (CompactList a) where
105
59
106− -- {-# INLINE addSizeTo #-}
60+ -- {-# INLINE size #-}
107− addSizeTo acc (CompactList xs) =
61+ size acc (CompactList xs) =
108− foldl' addSizeTo (acc + (Unbox.sizeOf (Proxy :: Proxy Word8))) xs
62+ foldl' size (acc + (Unbox.sizeOf (Proxy :: Proxy Word8))) xs
109
63
110 -- Inlining this causes large compilation times for tests
64 -- Inlining this causes large compilation times for tests
111− {-# INLINABLE deserializeAt #-}
65+ {-# INLINABLE deserialize #-}
112− deserializeAt off arr sz = do
66+ deserialize off arr sz = do
113− (off1, len8) <- deserializeAt off arr sz :: IO (Int, Word8)
67+ (off1, len8) <- deserialize off arr sz :: IO (Int, Word8)
114 let len = w8_int len8
68 let len = w8_int len8
115 peekList f o i | i >= 3 = do
69 peekList f o i | i >= 3 = do
116 -- Unfold the loop three times
70 -- Unfold the loop three times
117− (o1, x1) <- deserializeAt o arr sz
71+ (o1, x1) <- deserialize o arr sz
118− (o2, x2) <- deserializeAt o1 arr sz
72+ (o2, x2) <- deserialize o1 arr sz
119− (o3, x3) <- deserializeAt o2 arr sz
73+ (o3, x3) <- deserialize o2 arr sz
120 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
74 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
121 peekList f o 0 = pure (o, f [])
75 peekList f o 0 = pure (o, f [])
122 peekList f o i = do
76 peekList f o i = do
123− (o1, x) <- deserializeAt o arr sz
77+ (o1, x) <- deserialize o arr sz
124 peekList (f . (x:)) o1 (i - 1)
78 peekList (f . (x:)) o1 (i - 1)
125 (nextOff, lst) <- peekList id off1 len
79 (nextOff, lst) <- peekList id off1 len
126 pure (nextOff, CompactList lst)
80 pure (nextOff, CompactList lst)
127
81
128 -- Inlining this causes large compilation times for tests
82 -- Inlining this causes large compilation times for tests
129− {-# INLINABLE serializeAt #-}
83+ {-# INLINABLE serialize #-}
130− serializeAt off arr (CompactList val) = do
84+ serialize off arr (CompactList val) = do
131− void $ serializeAt off arr (int_w8 (length val) :: Word8)
85+ void $ serialize off arr (int_w8 (length val) :: Word8)
132 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Word8)
86 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Word8)
133 let pokeList o [] = pure o
87 let pokeList o [] = pure o
134 pokeList o (x:xs) = do
88 pokeList o (x:xs) = do
135− o1 <- serializeAt o arr x
89+ o1 <- serialize o arr x
136 pokeList o1 xs
90 pokeList o1 xs
137 pokeList off1 val
91 pokeList off1 val
138
92
@@ -154,7 +108,7 @@ isMaybeType _ = False
154-- We add 4 here because we use 'serializeWithSize' for serializing.
108-- We add 4 here because we use 'serializeWithSize' for serializing.
155exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
109exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
156exprGetSize acc (i, _) =
110exprGetSize acc (i, _) =
157− [|addSizeTo $(acc) $(varE (mkFieldName i)) + 4|]
111+ [|size $(acc) $(varE (mkFieldName i)) + 4|]
158
112
159sizeOfHeader :: SimpleDataCon -> Int
113sizeOfHeader :: SimpleDataCon -> Int
160sizeOfHeader (SimpleDataCon _ fields) =
114sizeOfHeader (SimpleDataCon _ fields) =
@@ -164,15 +118,13 @@ sizeOfHeader (SimpleDataCon _ fields) =
164 where
118 where
165
119
166 sizeForFinalOff = 4
120 sizeForFinalOff = 4
167− sizeForHeaderLength = 4 -- Max header length is (255 * (255 + 1) + 1) and
121+ sizeForHeaderLength = 2 -- Max header length is (255 * (255 + 1) + 1) and
168− -- hence 2 bytes is enough to store it. But we still
122+ -- hence 2 bytes is enough to store it.
169− -- use 4 bytes as using 2 bytes introduces
170− -- regression.
171 sizeForNumFields = 1 -- At max 255 fields in the record constructor
123 sizeForNumFields = 1 -- At max 255 fields in the record constructor
172 sizeForFieldLen = 1 -- At max 255 letters in the key
124 sizeForFieldLen = 1 -- At max 255 letters in the key
173
125
174−mkRecSizeOfExpr :: SimpleDataCon -> Q Exp
126+mkSizeOfExpr :: SimpleDataCon -> Q Exp
175−mkRecSizeOfExpr con = do
127+mkSizeOfExpr con = do
176 n_acc <- newName "acc"
128 n_acc <- newName "acc"
177 n_x <- newName "x"
129 n_x <- newName "x"
178 (lamE
130 (lamE
@@ -205,47 +157,40 @@ headerValue (SimpleDataCon _ fields) =
205 in if lenFields <= 255
157 in if lenFields <= 255
206 then lenFields
158 then lenFields
207 else errorUnsupported
159 else errorUnsupported
208− "Number of fields in the record should be <= 255."
209 lengthPrependedFieldEncoding field =
160 lengthPrependedFieldEncoding field =
210 let fEnc =
161 let fEnc =
211 let fEnc_ = map c2w (fieldToNameBase field)
162 let fEnc_ = map c2w (fieldToNameBase field)
212 lenFEnc = length fEnc_
163 lenFEnc = length fEnc_
213 in if lenFEnc <= 255
164 in if lenFEnc <= 255
214 then fEnc_
165 then fEnc_
215− else
216− errorUnsupported
166+ else errorUnsupported
217− "Length of any key should be <= 255."
218 in (int_w8 (length fEnc)) : fEnc
167 in (int_w8 (length fEnc)) : fEnc
219
168
220--------------------------------------------------------------------------------
169--------------------------------------------------------------------------------
221-- Peek
170-- Peek
222--------------------------------------------------------------------------------
171--------------------------------------------------------------------------------
223
172
224−-- Encoding the size is required if we want to skip the field without knowing
173+-- Encoding the size is required if we want to skip the field.
225−-- its type. We encode the size as 'Word32' hence there is a 4 bytes increase
174+-- We encode the size as 'Word32' hence there is a 4 bytes increase in size.
226−-- in size.
227{-# INLINE serializeWithSize #-}
175{-# INLINE serializeWithSize #-}
228−serializeWithSize :: Serialize a => Int -> MutByteArray -> a -> IO Int
176+serializeWithSize :: Serialize a => Int -> MutableByteArray -> a -> IO Int
229serializeWithSize off arr val = do
177serializeWithSize off arr val = do
230− off1 <- serializeAt (off + 4) arr val
178+ off1 <- serialize (off + 4) arr val
231− Unbox.pokeAt off arr (int_w32 (off1 - off - 4) :: Word32)
179+ Unbox.pokeByteIndex off arr (int_w32 (off1 - off - 4) :: Word32)
232 pure off1
180 pure off1
233
181
234−mkRecSerializeExpr :: Name -> SimpleDataCon -> Q Exp
182+mkSerializeExpr :: Name -> SimpleDataCon -> Q Exp
235−mkRecSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
183+mkSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
236 afterHLen <- newName "afterHLen"
184 afterHLen <- newName "afterHLen"
237− -- Encoding the header length is required.
238− -- We first compare the header length encoded and the current header
239− -- length. Only if the header lengths match, we compare the headers.
240 [|do $(varP afterHLen) <-
185 [|do $(varP afterHLen) <-
241− serializeAt
186+ serialize
242 ($(varE initialOffset) + 4)
187 ($(varE initialOffset) + 4)
243 $(varE _arr)
188 $(varE _arr)
244− ($(litIntegral hlen) :: Word32)
189+ ($(litIntegral hlen) :: Word16)
245 $(varP (makeI 0)) <- $(serializeW8List afterHLen _arr hval)
190 $(varP (makeI 0)) <- $(serializeW8List afterHLen _arr hval)
246 let $(openConstructor cname (length fields)) = $(varE _val)
191 let $(openConstructor cname (length fields)) = $(varE _val)
247 finalOff <- $(mkSerializeExprFields 'serializeWithSize fields)
192 finalOff <- $(mkSerializeExprFields 'serializeWithSize fields)
248− Unbox.pokeAt
193+ Unbox.pokeByteIndex
249 $(varE initialOffset)
194 $(varE initialOffset)
250 $(varE _arr)
195 $(varE _arr)
251 ((fromIntegral :: Int -> Word32)
196 ((fromIntegral :: Int -> Word32)
@@ -263,12 +208,12 @@ mkRecSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
263
208
264{-# INLINE deserializeWithSize #-}
209{-# INLINE deserializeWithSize #-}
265deserializeWithSize ::
210deserializeWithSize ::
266− Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
211+ Serialize a => Int -> MutableByteArray -> Int -> IO (Int, a)
267−deserializeWithSize off arr endOff = deserializeAt (off + 4) arr endOff
212+deserializeWithSize off arr endOff = deserialize (off + 4) arr endOff
268
213
269−conUpdateFuncDec :: Name -> [Field] -> Q [Dec]
214+conUpdateFuncExpr :: Name -> Type -> [Field] -> Q [Dec]
270−conUpdateFuncDec funcName fields = do
215+conUpdateFuncExpr funcName headTy fields = do
271− prevAcc <- newName "prevAcc"
216+ prevRec <- newName "prevRec"
272 curOff <- newName "curOff"
217 curOff <- newName "curOff"
273 endOff <- newName "endOff"
218 endOff <- newName "endOff"
274 arr <- newName "arr"
219 arr <- newName "arr"
@@ -277,17 +222,17 @@ conUpdateFuncDec funcName fields = do
277 (caseE
222 (caseE
278 (varE key)
223 (varE key)
279 (concat
224 (concat
280− [ map (matchField arr endOff (prevAcc, curOff)) fnames
225+ [ map (matchField arr endOff (prevRec, curOff)) fnames
281 , [ match
226 , [ match
282 wildP
227 wildP
283 (normalB
228 (normalB
284 [|do (valOff, valLen :: Word32) <-
229 [|do (valOff, valLen :: Word32) <-
285− deserializeAt
230+ deserialize
286 $(varE curOff)
231 $(varE curOff)
287 $(varE arr)
232 $(varE arr)
288 $(varE endOff)
233 $(varE endOff)
289 pure
234 pure
290− ( $(varE prevAcc)
235+ ( $(varE prevRec)
291 , valOff + w32_int valLen)|])
236 , valOff + w32_int valLen)|])
292 []
237 []
293 ]
238 ]
@@ -299,7 +244,7 @@ conUpdateFuncDec funcName fields = do
299 [ Clause
244 [ Clause
300 [ VarP arr
245 [ VarP arr
301 , VarP endOff
246 , VarP endOff
302− , TupP [VarP prevAcc, VarP curOff]
247+ , TupP [VarP prevRec, VarP curOff]
303 , VarP key
248 , VarP key
304 ]
249 ]
305 (NormalB method)
250 (NormalB method)
@@ -311,99 +256,71 @@ conUpdateFuncDec funcName fields = do
311
256
312 fnames = fmap (fromJust . fst) fields
257 fnames = fmap (fromJust . fst) fields
313 matchField :: Name -> Name -> (Name, Name) -> Name -> Q Match
258 matchField :: Name -> Name -> (Name, Name) -> Name -> Q Match
314− matchField arr endOff (acc, currOff) fname = do
259+ matchField arr endOff (prevRec, currOff) fname = do
315− let fnameLit = StringL (nameBase fname)
260+ val <- newName "val"
261+ newOff <- newName "newOff"
316 match
262 match
317− (litP fnameLit)
263+ (litP (StringL (nameBase fname)))
318 (normalB
264 (normalB
319− [|do (valOff, valLen :: Word32) <-
265+ [|do ($(varP newOff), $(varP val)) <-
320− deserializeAt
266+ deserializeWithSize
321− $(varE currOff)
267+ $(varE currOff)
322− $(varE arr)
268+ $(varE arr)
323− $(varE endOff)
269+ $(varE endOff)
324 pure
270 pure
325− ( ($(litE fnameLit), $(varE currOff)) : $(varE acc)
271+ ( $(recUpdE (varE prevRec) [pure (fname, VarE val)])
326− , valOff + w32_int valLen)|])
272+ :: $(pure headTy)
273+ , $(varE newOff))|])
327 []
274 []
328
275
276+mkDeserializeKeysExpr ::
329−mkDeserializeKeysDec :: Name -> Name -> SimpleDataCon -> Q [Dec]
277+ Name -> Name -> Name -> Name -> Name -> SimpleDataCon -> Q Exp
330−mkDeserializeKeysDec funcName updateFunc (SimpleDataCon cname fields) = do
278+mkDeserializeKeysExpr
331− hOff <- newName "hOff"
279+ hOff finalOff arr endOff updateFunc (SimpleDataCon cname fields) = do
332− finalOff <- newName "finalOff"
280+
333− arr <- newName "arr"
334− endOff <- newName "endOff"
335− kvEncoded <- newName "kvEncoded"
336− finalRec <- newName "finalRec"
337− let deserializeFieldExpr (Just name, ty) = do
338− let nameLit = litE (StringL (nameBase name))
339− [|case lookup $(nameLit) $(varE kvEncoded) of
340− Nothing -> $(emptyTy name ty)
341− Just off -> do
342− val <- deserializeWithSize off $(varE arr) $(varE endOff)
343− pure $ snd val|]
344− deserializeFieldExpr _ =
345− errorUnsupported "The datatype should use record syntax."
346− method <-
347− [|do (dataOff, hlist :: CompactList (CompactList Word8)) <-
281+ [|do (dataOff, hlist :: CompactList (CompactList Word8)) <-
348− deserializeAt $(varE hOff) $(varE arr) $(varE endOff)
282+ deserialize $(varE hOff) $(varE arr) $(varE endOff)
349− let keys = wListToString . unCompactList <$> unCompactList hlist
283+ let keys = wListToString . unCompactList <$> unCompactList hlist
350− ($(varP kvEncoded), _) <-
284+ (finalRec, _) <-
351− foldlM
285+ foldlM
352− ($(varE updateFunc) $(varE arr) $(varE endOff))
286+ ($(varE updateFunc) $(varE arr) $(varE endOff))
353− ([], dataOff)
287+ ($(emptyConExpr), dataOff)
354− keys
288+ keys
355− $(varP finalRec) <-
356− $(foldl
357− (\acc i ->
358− [|$(acc) <*>
359− $(deserializeFieldExpr i)|])
360− [|pure $(conE cname)|]
361− fields)
362− pure ($(varE finalOff), $(varE finalRec))|]
289+ pure ($(varE finalOff), finalRec)|]
363− pure
364− [ PragmaD (InlineP funcName NoInline FunLike AllPhases)
365− , FunD
366− funcName
367− [ Clause
368− [ VarP hOff
369− , VarP finalOff
370− , VarP arr
371− , VarP endOff
372− ]
373− (NormalB method)
374− []
375− ]
376− ]
377
290
378 where
291 where
379
292
380 emptyTy k ty =
293 emptyTy k ty =
381 if isMaybeType ty
294 if isMaybeType ty
382− then [|pure Nothing|]
295+ then [|Nothing|]
383 else [|error $(litE (StringL (nameBase k ++ " is not found.")))|]
296 else [|error $(litE (StringL (nameBase k ++ " is not found.")))|]
297+ fieldToEmptyRecC (Just name, ty) = (name, ) <$> emptyTy name ty
298+ fieldToEmptyRecC _ = errorUnsupported
299+ emptyConExpr = recConE cname (fmap fieldToEmptyRecC fields)
384
300
385−
386−mkRecDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
301+mkDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
387−mkRecDeserializeExpr initialOff endOff deserializeWithKeys con = do
302+mkDeserializeExpr initialOff endOff deserializeWithKeys con = do
388 hOff <- newName "hOff"
303 hOff <- newName "hOff"
389 let sizeForFinalOff = 4 -- Word32
304 let sizeForFinalOff = 4 -- Word32
390− sizeForHeaderLength = 4 -- Word32
305+ sizeForHeaderLength = 2 -- Word16
391 sizePreData = sizeForFinalOff + sizeForHeaderLength + hlen
306 sizePreData = sizeForFinalOff + sizeForHeaderLength + hlen
392 [|do (hlenOff, encLen :: Word32) <-
307 [|do (hlenOff, encLen :: Word32) <-
393− deserializeAt $(varE initialOff) $(varE _arr) $(varE endOff)
308+ deserialize $(varE initialOff) $(varE _arr) $(varE endOff)
394− ($(varP hOff), hlen1 :: Word32) <-
309+ ($(varP hOff), hlen1 :: Word16) <-
395− deserializeAt hlenOff $(varE _arr) $(varE endOff)
310+ deserialize hlenOff $(varE _arr) $(varE endOff)
396− if (hlen1 == $(litIntegral hlen)) && $(xorCmp hval hOff _arr)
311+ if hlen1 == $(litIntegral hlen)
312+ then if $(xorCmp hval hOff _arr)
397− then do
313+ then do
398− let $(varP (makeI 0)) =
314+ let $(varP (makeI 0)) =
399− $(varE initialOff) +
315+ $(varE initialOff) +
400− $(litIntegral sizePreData)
316+ $(litIntegral sizePreData)
401− $(mkDeserializeExprOne 'deserializeWithSize con)
317+ $(mkDeserializeExprOne 'deserializeWithSize con)
402− else $(varE deserializeWithKeys)
318+ else $(varE deserializeWithKeys)
403− $(varE hOff)
319+ $(varE hOff)
404− ($(varE initialOff) + w32_int encLen)
320+ ($(varE initialOff) + w32_int encLen)
321+ else $(varE deserializeWithKeys)
405− $(varE _arr)
322+ $(varE hOff)
406− $(varE endOff)|]
323+ ($(varE initialOff) + w32_int encLen)|]
407
324
408 where
325 where
409
326
core/src/Streamly/Internal/Data/Serialize/Type.hs+123−142
@@ -7,27 +7,37 @@
7--
7--
8
8
9module Streamly.Internal.Data.Serialize.Type
9module Streamly.Internal.Data.Serialize.Type
10− (
11− Serialize(..)
10+ ( Serialize(..)
11+ , encode
12+ , pinnedEncode
13+ , decode
12 ) where
14 ) where
13
15
14--------------------------------------------------------------------------------
16--------------------------------------------------------------------------------
15-- Imports
17-- Imports
16--------------------------------------------------------------------------------
18--------------------------------------------------------------------------------
17
19
20+#include "assert.hs"
21+
22+#ifdef DEBUG
18−import Control.Monad (when)
23+import Control.Exception (assert)
24+#endif
25+
19import Data.List (foldl')
26import Data.List (foldl')
20import Data.Proxy (Proxy (..))
27import Data.Proxy (Proxy (..))
21−import Streamly.Internal.Data.Unbox (Unbox)
28+import Streamly.Internal.Data.Unbox
22−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray(..))
29+ ( MutableByteArray(..)
30+ , PinnedState(..)
31+ , Unbox
32+ )
23import Streamly.Internal.Data.Array.Type (Array(..))
33import Streamly.Internal.Data.Array.Type (Array(..))
34+import Streamly.Internal.System.IO (unsafeInlineIO)
24import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
35import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
25import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
36import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
26import GHC.Stable (StablePtr(..))
37import GHC.Stable (StablePtr(..))
27
38
28−import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
29import qualified Streamly.Internal.Data.Unbox as Unbox
39import qualified Streamly.Internal.Data.Unbox as Unbox
30−import qualified Streamly.Internal.Data.Array.Type as Array
40+import qualified Streamly.Internal.Data.Array as Array
31import qualified Streamly.Internal.Data.MutArray as MutArray
41import qualified Streamly.Internal.Data.MutArray as MutArray
32
42
33import GHC.Exts
43import GHC.Exts
@@ -49,33 +59,21 @@ import GHC.Exts
49-- Types
59-- Types
50--------------------------------------------------------------------------------
60--------------------------------------------------------------------------------
51
61
52−-- | The 'Serialize' type class provides operations for serialization and
62+-- | A type implementing the 'Serialize' interface supplies operations for
53−-- deserialization of general Haskell data types to and from their byte stream
63+-- reading and writing the type from and to a mutable byte array (an unboxed
54−-- representation.
64+-- representation of the type) in memory. The read operation 'deserialize'
65+-- deserializes the boxed type from the mutable byte array. The write operation
66+-- 'serialize' serializes the boxed type to the mutable byte array.
55--
67--
56−-- Unlike 'Unbox', 'Serialize' uses variable length encoding, therefore, it can
68+-- IMPORTANT: The serialized data's byte ordering is not normalized, which means
57−-- serialize recursive and variable length data types like lists, or variable
69+-- it remains the same as the machine's byte order where the function is
58−-- length sum types where the length of the value may vary depending on a
70+-- executed. Consequently, it may not be compatible across machines with
59−-- particular constructor. For variable length data types the length is encoded
71+-- different byte ordering.
60−-- along with the data.
61--
72--
62−-- The 'deserializeAt' operation reads bytes from the mutable byte array and
73+-- 'Serialize' contains enough information to serialize and deserialize variable
63−-- builds a Haskell data type from these bytes, the number of bytes it reads
74+-- length types.
64−-- depends on the type and the encoded value it is reading. 'serializeAt'
65−-- operation converts a Haskell data type to its binary representation which
66−-- must consist of as many bytes as added by the @addSizeTo@ operation for that
67−-- value and then stores these bytes into the mutable byte array. The
68−-- programmer is expected to use the @addSizeTo@ operation and allocate an
69−-- array of sufficient length before calling 'serializeAt'.
70--
75--
71−-- IMPORTANT: The serialized data's byte ordering remains the same as the host
76+-- >>> import Streamly.Internal.Data.Serialize.Type (Serialize(..))
72−-- machine's byte order. Therefore, it can not be deserialized from host
73−-- machines with a different byte ordering.
74−--
75−-- Instances can be derived via Template Haskell, or written manually.
76−--
77−-- Here is an example, for deriving an instance of this type class using
78−-- template Haskell:
79--
77--
80-- >>> :{
78-- >>> :{
81-- data Object = Object
79-- data Object = Object
@@ -84,30 +82,16 @@ import GHC.Exts
84-- }
82-- }
85-- :}
83-- :}
86--
84--
87−-- @
88−-- import Streamly.Data.MutByteArray (deriveSerialize)
89−-- \$(deriveSerialize [d|instance Serialize Object|])
90−-- @
91−--
92−-- See 'Streamly.Data.MutByteArray.deriveSerialize' and
93−-- 'Streamly.Data.MutByteArray.deriveSerializeWith' for more information on
94−-- deriving using Template Haskell.
95−--
96−-- Here is an example of a manual instance.
97−--
98−-- >>> import Streamly.Data.MutByteArray (Serialize(..))
99−--
100-- >>> :{
85-- >>> :{
101-- instance Serialize Object where
86-- instance Serialize Object where
102−-- addSizeTo acc obj = addSizeTo (addSizeTo acc (_obj1 obj)) (_obj2 obj)
87+-- size acc obj = size (size acc (_obj1 obj)) (_obj2 obj)
103−-- deserializeAt i arr len = do
88+-- deserialize i arr len = do
104−-- -- Check the array bounds before reading
105−-- (i1, x0) <- deserializeAt i arr len
89+-- (i1, x0) <- deserialize i arr len
106−-- (i2, x1) <- deserializeAt i1 arr len
90+-- (i2, x1) <- deserialize i1 arr len
107-- pure (i2, Object x0 x1)
91-- pure (i2, Object x0 x1)
108−-- serializeAt i arr (Object x0 x1) = do
92+-- serialize i arr (Object x0 x1) = do
109−-- i1 <- serializeAt i arr x0
93+-- i1 <- serialize i arr x0
110−-- i2 <- serializeAt i1 arr x1
94+-- i2 <- serialize i1 arr x1
111-- pure i2
95-- pure i2
112-- :}
96-- :}
113--
97--
@@ -118,50 +102,44 @@ class Serialize a where
118 -- It is of the form @Int -> a -> Int@ because you can have tail-recursive
102 -- It is of the form @Int -> a -> Int@ because you can have tail-recursive
119 -- traversal of the structures.
103 -- traversal of the structures.
120
104
121− -- | @addSizeTo accum value@ returns @accum@ incremented by the size of the
105+ -- | Get the size, in bytes, reqired to store the serialized
122− -- serialized representation of @value@ in bytes. Size cannot be zero. It
106+ -- representation of the type. Size cannot be zero.
123− -- should be at least 1 byte.
124− addSizeTo :: Int -> a -> Int
107+ size :: Int -> a -> Int
125
108
126 -- We can implement the following functions without returning the `Int`
109 -- We can implement the following functions without returning the `Int`
127 -- offset but that may require traversing the Haskell structure again to get
110 -- offset but that may require traversing the Haskell structure again to get
128 -- the size. Therefore, this is a performance optimization.
111 -- the size. Therefore, this is a performance optimization.
129
112
130− -- | @deserializeAt byte-offset array arrayLen@ deserializes a value from
113+ -- | @deserialize offset array arrayLen@ deserializes a value from the
131− -- the given byte-offset in the array. Returns a tuple consisting of the
114+ -- given byte-index in the array. Returns a tuple of the next byte-index
132− -- next byte-offset and the deserialized value.
115+ -- and the deserialized value.
133− --
116+ deserialize :: Int -> MutableByteArray -> Int -> IO (Int, a)
134− -- The arrayLen passed is the entire length of the input buffer. It is to
117+
135− -- be used to check if we would overflow the input buffer when
136− -- deserializing.
137− --
138− -- Throws an exception if the operation would exceed the supplied arrayLen.
139− deserializeAt :: Int -> MutByteArray -> Int -> IO (Int, a)
140−
141− -- | @serializeAt byte-offset array value@ writes the serialized
142− -- representation of the @value@ in the array at the given byte-offset.
118+ -- | Write the serialized representation of the value in the array at the
143− -- Returns the next byte-offset.
119+ -- given byte-index. Returns the next byte-index. This is an unsafe
144− --
145− -- This is an unsafe operation, the programmer must ensure that the array
120+ -- operation, the programmer must ensure that the array has enough space
146− -- has enough space available to serialize the value as determined by the
121+ -- available in the array to serialize the value as determined by the
147− -- @addSizeTo@ operation.
122+ -- @size@ operation.
148− serializeAt :: Int -> MutByteArray -> a -> IO Int
123+ serialize :: Int -> MutableByteArray -> a -> IO Int
149
124
150--------------------------------------------------------------------------------
125--------------------------------------------------------------------------------
151-- Instances
126-- Instances
152--------------------------------------------------------------------------------
127--------------------------------------------------------------------------------
153
128
154−-- _size is the length from array start to the last accessed byte.
129+-- XXX We do not need to pass the end of data offset, we can just check the
130+-- mutable array end here to avoid a crash, and when we return from deserialize
131+-- we can check if the offset returned is beyond the bound or not.
132+--
155#ifdef DEBUG
133#ifdef DEBUG
156{-# INLINE checkBounds #-}
134{-# INLINE checkBounds #-}
157−checkBounds :: String -> Int -> MutByteArray -> IO ()
135+checkBounds :: String -> Int -> MutableByteArray -> IO ()
158−checkBounds _label _size _arr = do
136+checkBounds _label _off _arr = do
159− sz <- MBA.sizeOfMutableByteArray _arr
137+ sz <- sizeOfMutableByteArray _arr
160− if (_size > sz)
138+ if (_off > sz)
161 then error
139 then error
162 $ _label
140 $ _label
163 ++ ": accessing array at offset = "
141 ++ ": accessing array at offset = "
164− ++ show (_size - 1)
142+ ++ show (_off - 1)
165 ++ " max valid offset = " ++ show (sz - 1)
143 ++ " max valid offset = " ++ show (sz - 1)
166 else return ()
144 else return ()
167#endif
145#endif
@@ -184,39 +162,39 @@ checkBounds _label _size _arr = do
184-- single array for deserializing. But that can also be done by framing the
162-- single array for deserializing. But that can also be done by framing the
185-- serialized value with a size header.
163-- serialized value with a size header.
186--
164--
187−{-# INLINE deserializeChecked #-}
165+{-# INLINE deserializeUnsafe #-}
188−deserializeChecked :: forall a. Unbox a => Int -> MutByteArray -> Int -> IO (Int, a)
166+deserializeUnsafe :: forall a. Unbox a => Int -> MutableByteArray -> Int -> IO (Int, a)
189−deserializeChecked off arr sz =
167+deserializeUnsafe off arr sz =
190 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
168 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
191 in do
169 in do
192 -- Keep likely path in the straight branch.
170 -- Keep likely path in the straight branch.
193 if (next <= sz)
171 if (next <= sz)
194− then Unbox.peekAt off arr >>= \val -> pure (next, val)
172+ then Unbox.peekByteIndex off arr >>= \val -> pure (next, val)
195 else error
173 else error
196− $ "deserializeAt: accessing array at offset = "
174+ $ "deserialize: accessing array at offset = "
197 ++ show (next - 1)
175 ++ show (next - 1)
198 ++ " max valid offset = " ++ show (sz - 1)
176 ++ " max valid offset = " ++ show (sz - 1)
199
177
200{-# INLINE serializeUnsafe #-}
178{-# INLINE serializeUnsafe #-}
201−serializeUnsafe :: forall a. Unbox a => Int -> MutByteArray -> a -> IO Int
179+serializeUnsafe :: forall a. Unbox a => Int -> MutableByteArray -> a -> IO Int
202serializeUnsafe off arr val =
180serializeUnsafe off arr val =
203 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
181 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
204 in do
182 in do
205#ifdef DEBUG
183#ifdef DEBUG
206− checkBounds "serializeAt" next arr
184+ checkBounds "serialize" next arr
207#endif
185#endif
208− Unbox.pokeAt off arr val
186+ Unbox.pokeByteIndex off arr val
209 pure next
187 pure next
210
188
211#define DERIVE_SERIALIZE_FROM_UNBOX(_type) \
189#define DERIVE_SERIALIZE_FROM_UNBOX(_type) \
212instance Serialize _type where \
190instance Serialize _type where \
213−; {-# INLINE addSizeTo #-} \
191+; {-# INLINE size #-} \
214−; addSizeTo acc _ = acc + Unbox.sizeOf (Proxy :: Proxy _type) \
192+; size acc _ = acc + Unbox.sizeOf (Proxy :: Proxy _type) \
215−; {-# INLINE deserializeAt #-} \
193+; {-# INLINE deserialize #-} \
216−; deserializeAt off arr end = deserializeChecked off arr end :: IO (Int, _type) \
194+; deserialize off arr end = deserializeUnsafe off arr end :: IO (Int, _type) \
217−; {-# INLINE serializeAt #-} \
195+; {-# INLINE serialize #-} \
218−; serializeAt = \
196+; serialize = \
219− serializeUnsafe :: Int -> MutByteArray -> _type -> IO Int
197+ serializeUnsafe :: Int -> MutableByteArray -> _type -> IO Int
220
198
221DERIVE_SERIALIZE_FROM_UNBOX(())
199DERIVE_SERIALIZE_FROM_UNBOX(())
222DERIVE_SERIALIZE_FROM_UNBOX(Bool)
200DERIVE_SERIALIZE_FROM_UNBOX(Bool)
@@ -239,79 +217,82 @@ DERIVE_SERIALIZE_FROM_UNBOX((FunPtr a))
239
217
240instance forall a. Serialize a => Serialize [a] where
218instance forall a. Serialize a => Serialize [a] where
241
219
242− -- {-# INLINE addSizeTo #-}
220+ -- {-# INLINE size #-}
243− addSizeTo acc xs =
244− foldl' addSizeTo (acc + (Unbox.sizeOf (Proxy :: Proxy Int))) xs
221+ size acc xs = foldl' size (acc + (Unbox.sizeOf (Proxy :: Proxy Int))) xs
245
222
246 -- Inlining this causes large compilation times for tests
223 -- Inlining this causes large compilation times for tests
247− {-# INLINABLE deserializeAt #-}
224+ {-# INLINABLE deserialize #-}
248− deserializeAt off arr sz = do
225+ deserialize off arr sz = do
249− (off1, len64) <- deserializeAt off arr sz :: IO (Int, Int64)
226+ (off1, len64) <- deserialize off arr sz :: IO (Int, Int64)
250 let len = (fromIntegral :: Int64 -> Int) len64
227 let len = (fromIntegral :: Int64 -> Int) len64
251 peekList f o i | i >= 3 = do
228 peekList f o i | i >= 3 = do
252 -- Unfold the loop three times
229 -- Unfold the loop three times
253− (o1, x1) <- deserializeAt o arr sz
230+ (o1, x1) <- deserialize o arr sz
254− (o2, x2) <- deserializeAt o1 arr sz
231+ (o2, x2) <- deserialize o1 arr sz
255− (o3, x3) <- deserializeAt o2 arr sz
232+ (o3, x3) <- deserialize o2 arr sz
256 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
233 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
257 peekList f o 0 = pure (o, f [])
234 peekList f o 0 = pure (o, f [])
258 peekList f o i = do
235 peekList f o i = do
259− (o1, x) <- deserializeAt o arr sz
236+ (o1, x) <- deserialize o arr sz
260 peekList (f . (x:)) o1 (i - 1)
237 peekList (f . (x:)) o1 (i - 1)
261 peekList id off1 len
238 peekList id off1 len
262
239
263 -- Inlining this causes large compilation times for tests
240 -- Inlining this causes large compilation times for tests
264− {-# INLINABLE serializeAt #-}
241+ {-# INLINABLE serialize #-}
265− serializeAt off arr val = do
242+ serialize off arr val = do
266 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Int64)
243 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Int64)
267 let pokeList acc o [] =
244 let pokeList acc o [] =
268− Unbox.pokeAt off arr (acc :: Int64) >> pure o
245+ Unbox.pokeByteIndex off arr (acc :: Int64) >> pure o
269 pokeList acc o (x:xs) = do
246 pokeList acc o (x:xs) = do
270− o1 <- serializeAt o arr x
247+ o1 <- serialize o arr x
271 pokeList (acc + 1) o1 xs
248 pokeList (acc + 1) o1 xs
272 pokeList 0 off1 val
249 pokeList 0 off1 val
273
250
274−instance
275−#ifdef DEVBUILD
276− Unbox a =>
277−#endif
278− Serialize (Array a) where
251+instance Serialize (Array a) where
279− {-# INLINE addSizeTo #-}
252+ {-# INLINE size #-}
280− addSizeTo i (Array {..}) = i + (arrEnd - arrStart) + 8
253+ size i (Array {..}) = i + (arrEnd - arrStart) + 8
281
254
282− {-# INLINE deserializeAt #-}
255+ {-# INLINE deserialize #-}
283− deserializeAt off arr len = do
256+ deserialize off arr end = do
284− (off1, byteLen) <- deserializeAt off arr len :: IO (Int, Int)
257+ (off1, byteLen) <- deserialize off arr end :: IO (Int, Int)
285 let off2 = off1 + byteLen
258 let off2 = off1 + byteLen
286− when (off2 > len) $
287− error
288− $ "deserializeAt: accessing array at offset = "
289− ++ show (off2 - 1)
290− ++ " max valid offset = " ++ show (len - 1)
291− -- XXX Use MutByteArray.cloneSliceUnsafe
292 let slice = MutArray.MutArray arr off1 off2 off2
259 let slice = MutArray.MutArray arr off1 off2 off2
293 newArr <- MutArray.clone slice
260 newArr <- MutArray.clone slice
294 pure (off2, Array.unsafeFreeze newArr)
261 pure (off2, Array.unsafeFreeze newArr)
295
262
296− {-# INLINE serializeAt #-}
263+ {-# INLINE serialize #-}
297− serializeAt off arr (Array {..}) = do
264+ serialize off arr (Array {..}) = do
298 let arrLen = arrEnd - arrStart
265 let arrLen = arrEnd - arrStart
299− off1 <- serializeAt off arr arrLen
266+ off1 <- serialize off arr arrLen
300− MBA.putSliceUnsafe arrContents arrStart arr off1 arrLen
267+ Unbox.putSliceUnsafe arrContents arrStart arr off1 arrLen
301 pure (off1 + arrLen)
268 pure (off1 + arrLen)
302
269
303−instance (Serialize a, Serialize b) => Serialize (a, b) where
270+--------------------------------------------------------------------------------
271+-- High level functions
272+--------------------------------------------------------------------------------
273+
274+{-# INLINE encodeAs #-}
275+encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
276+encodeAs ps a =
277+ unsafeInlineIO $ do
278+ let len = size 0 a
279+ mbarr <- Unbox.newBytesAs ps len
280+ off <- serialize 0 mbarr a
281+ assertM(len == off)
282+ pure $ Array mbarr 0 off
304
283
305− {-# INLINE addSizeTo #-}
284+{-# INLINE encode #-}
306− addSizeTo acc (a, b) = addSizeTo (addSizeTo acc a) b
285+encode :: Serialize a => a -> Array Word8
286+encode = encodeAs Unpinned
307
287
308− {-# INLINE serializeAt #-}
288+{-# INLINE pinnedEncode #-}
309− serializeAt off arr (a, b) = do
289+pinnedEncode :: Serialize a => a -> Array Word8
310− off1 <- serializeAt off arr a
290+pinnedEncode = encodeAs Pinned
311− serializeAt off1 arr b
312
291
313− {-# INLINE deserializeAt #-}
292+{-# INLINE decode #-}
314− deserializeAt off arr end = do
293+decode :: Serialize a => Array Word8 -> a
315− (off1, a) <- deserializeAt off arr end
294+decode arr@(Array {..}) = unsafeInlineIO $ do
316− (off2, b) <- deserializeAt off1 arr end
295+ let lenArr = Array.length arr
296+ (off, val) <- deserialize arrStart arrContents (arrStart + lenArr)
297+ assertM(off == arrStart + lenArr)
317− pure (off2, (a, b))
298+ pure val
core/src/Streamly/Internal/Data/Array/Stream.hs → core/src/Streamly/Internal/Data/Stream/Chunked.hsrenamed+586−74
@@ -1,6 +1,5 @@
1−{-# OPTIONS_GHC -Wno-deprecations #-}
2-- |
1-- |
3−-- Module : Streamly.Internal.Data.Array.Stream
2+-- Module : Streamly.Internal.Data.Stream.Chunked
4-- Copyright : (c) 2019 Composewell Technologies
3-- Copyright : (c) 2019 Composewell Technologies
5-- License : BSD3-3-Clause
4-- License : BSD3-3-Clause
6-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
@@ -8,25 +7,17 @@
8--
7--
9-- Combinators to efficiently manipulate streams of immutable arrays.
8-- Combinators to efficiently manipulate streams of immutable arrays.
10--
9--
11−-- We can either push these in the MutArray module with a "chunks" prefix or
12−-- keep this as a separate module and release it.
13−--
14−module Streamly.Internal.Data.Array.Stream
10+module Streamly.Internal.Data.Stream.Chunked
15−{-# DEPRECATED "Please use \"Streamly.Internal.Data.Array\" instead." #-}
16 (
11 (
17 -- * Creation
12 -- * Creation
18− Array.chunksOf
13+ chunksOf
19− , Array.pinnedChunksOf
20− , Array.bufferChunks
21
14
22 -- * Flattening to elements
15 -- * Flattening to elements
23− , Array.concat
16+ , concat
24− , Array.flattenArrays
25− , Array.concatRev
17+ , concatRev
26− , Array.flattenArraysRev
27− , Array.interpose
18+ , interpose
28− , Array.interposeSuffix
19+ , interposeSuffix
29− , Array.intercalateSuffix
20+ , intercalateSuffix
30 , unlines
21 , unlines
31
22
32 -- * Elimination
23 -- * Elimination
@@ -35,27 +26,24 @@ module Streamly.Internal.Data.Array.Stream
35 -- can flatten the stream to byte stream and use that. But if we want the
26 -- can flatten the stream to byte stream and use that. But if we want the
36 -- remaining stream to be a chunk stream then this could be handy. But it
27 -- remaining stream to be a chunk stream then this could be handy. But it
37 -- could also be implemented using parseBreak.
28 -- could also be implemented using parseBreak.
38− , foldBreak
29+ , foldBreak -- StreamK.foldBreakChunks
39 , foldBreakD
30 , foldBreakD
40− -- This is chunked parseBreak. A byte level parseBreak cannot work
31+ -- The byte level parseBreak cannot work efficiently. Because the stream
41− -- efficiently. Because the stream will have to be a StreamK for
42− -- backtracking, StreamK at byte level would not be efficient.
32+ -- will have to be a StreamK for backtracking, StreamK at byte level would
33+ -- not be efficient.
43− -- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
34+ , parseBreak -- StreamK.parseBreakChunks
44− , parseBreak
45 -- , parseBreakD
35 -- , parseBreakD
46 -- , foldManyChunks
36 -- , foldManyChunks
47 -- , parseManyChunks
37 -- , parseManyChunks
48− , K.parseBreakChunks
49− , K.parseChunks
50
38
51 -- ** Array Folds
39 -- ** Array Folds
52− -- XXX Use parseBreakChunks/parseChunks instead
40+ -- XXX Use Parser.Chunked instead, need only chunkedParseBreak,
53 -- foldBreak can be implemented using parseBreak. Use StreamK.
41 -- foldBreak can be implemented using parseBreak. Use StreamK.
54 , runArrayFold
42 , runArrayFold
55 , runArrayFoldBreak
43 , runArrayFoldBreak
56 -- , parseArr
44 -- , parseArr
57− , runArrayParserDBreak -- StreamK.parseBreakChunks
45+ , runArrayParserDBreak -- StreamK.chunkedParseBreak
58− , runArrayFoldMany
46+ , runArrayFoldMany -- StreamK.chunkedParseMany
59
47
60 , toArray
48 , toArray
61
49
@@ -79,8 +67,6 @@ where
79import Data.Bifunctor (second)
67import Data.Bifunctor (second)
80import Control.Exception (assert)
68import Control.Exception (assert)
81import Control.Monad.IO.Class (MonadIO(..))
69import Control.Monad.IO.Class (MonadIO(..))
82−-- import Data.Bifunctor (first)
83−-- import Data.Either (fromRight)
84import Data.Proxy (Proxy(..))
70import Data.Proxy (Proxy(..))
85import Data.Word (Word8)
71import Data.Word (Word8)
86import Streamly.Internal.Data.Unbox (Unbox(..))
72import Streamly.Internal.Data.Unbox (Unbox(..))
@@ -96,32 +82,142 @@ import Streamly.Internal.Data.Parser (ParseError(..))
96import Streamly.Internal.Data.Stream (Stream)
82import Streamly.Internal.Data.Stream (Stream)
97import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
83import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
98import Streamly.Internal.Data.SVar.Type (adaptState, defState)
84import Streamly.Internal.Data.SVar.Type (adaptState, defState)
85+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
99
86
87+import qualified Streamly.Data.Fold as FL
100import qualified Streamly.Internal.Data.Array as A
88import qualified Streamly.Internal.Data.Array as A
101import qualified Streamly.Internal.Data.Array as Array
89import qualified Streamly.Internal.Data.Array as Array
90+import qualified Streamly.Internal.Data.MutArray.Type as MA
91+import qualified Streamly.Internal.Data.Stream.MutChunked as AS
92+import qualified Streamly.Internal.Data.Fold.Type as FL (Fold(..), Step(..))
102import qualified Streamly.Internal.Data.Parser as PR
93import qualified Streamly.Internal.Data.Parser as PR
103import qualified Streamly.Internal.Data.Parser as PRD
94import qualified Streamly.Internal.Data.Parser as PRD
104 (Parser(..), Initial(..))
95 (Parser(..), Initial(..))
105−-- import qualified Streamly.Internal.Data.ParserK as ParserK
106import qualified Streamly.Internal.Data.Stream as D
96import qualified Streamly.Internal.Data.Stream as D
107import qualified Streamly.Internal.Data.StreamK as K
97import qualified Streamly.Internal.Data.StreamK as K
108
98
109-- XXX Since these are immutable arrays MonadIO constraint can be removed from
99-- XXX Since these are immutable arrays MonadIO constraint can be removed from
110-- most places.
100-- most places.
111
101
102+-------------------------------------------------------------------------------
103+-- Generation
104+-------------------------------------------------------------------------------
105+
106+-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
107+-- @n@ elements each.
108+--
109+-- > chunksOf n = Stream.groupsOf n (Array.writeN n)
110+--
111+-- /Pre-release/
112+{-# INLINE chunksOf #-}
113+chunksOf :: (MonadIO m, Unbox a)
114+ => Int -> Stream m a -> Stream m (Array a)
115+chunksOf = A.chunksOf
116+
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+
112-------------------------------------------------------------------------------
149-------------------------------------------------------------------------------
113-- Intersperse and append
150-- Intersperse and append
114-------------------------------------------------------------------------------
151-------------------------------------------------------------------------------
115
152
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 !MA.MutableByteArray !Int !Int
179+
180+-- XXX This is a special case of interposeSuffix, can be removed.
181+-- XXX Remove monadIO constraint
116{-# INLINE_NORMAL unlines #-}
182{-# INLINE_NORMAL unlines #-}
117unlines :: forall m a. (MonadIO m, Unbox a)
183unlines :: forall m a. (MonadIO m, Unbox a)
118 => a -> D.Stream m (Array a) -> D.Stream m a
184 => a -> D.Stream m (Array a) -> D.Stream m a
119−unlines = Array.interposeSuffix
185+unlines sep (D.Stream step state) = D.Stream step' (OuterLoop state)
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)
120
202
121-------------------------------------------------------------------------------
203-------------------------------------------------------------------------------
122-- Compact
204-- Compact
123-------------------------------------------------------------------------------
205-------------------------------------------------------------------------------
124
206
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+
125-- XXX instead of writing two different versions of this operation, we should
221-- XXX instead of writing two different versions of this operation, we should
126-- write it as a pipe.
222-- write it as a pipe.
127--
223--
@@ -129,7 +225,8 @@ unlines = Array.interposeSuffix
129{-# INLINE_NORMAL lpackArraysChunksOf #-}
225{-# INLINE_NORMAL lpackArraysChunksOf #-}
130lpackArraysChunksOf :: (MonadIO m, Unbox a)
226lpackArraysChunksOf :: (MonadIO m, Unbox a)
131 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
227 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
132−lpackArraysChunksOf = Array.lCompactGE
228+lpackArraysChunksOf n fld =
229+ FL.lmap A.unsafeThaw $ AS.lpackArraysChunksOf n (FL.lmap A.unsafeFreeze fld)
133
230
134-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
231-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
135-- maximum specified size in bytes.
232-- maximum specified size in bytes.
@@ -138,20 +235,69 @@ lpackArraysChunksOf = Array.lCompactGE
138{-# INLINE compact #-}
235{-# INLINE compact #-}
139compact :: (MonadIO m, Unbox a)
236compact :: (MonadIO m, Unbox a)
140 => Int -> Stream m (Array a) -> Stream m (Array a)
237 => Int -> Stream m (Array a) -> Stream m (Array a)
141−compact = Array.compactLE
238+compact = packArraysChunksOf
142−
143−-- | Given a stream of arrays, splice them all together to generate a single
144−-- array. The stream must be /finite/.
145−--
146−-- @since 0.7.0
147−{-# INLINE toArray #-}
148−toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
149−toArray = Array.fromChunks
150
239
151-------------------------------------------------------------------------------
240-------------------------------------------------------------------------------
152-- Split
241-- Split
153-------------------------------------------------------------------------------
242-------------------------------------------------------------------------------
154
243
244+data SplitState s arr
245+ = Initial s
246+ | Buffering s arr
247+ | Splitting s arr
248+ | Yielding arr (SplitState s arr)
249+ | Finishing
250+
251+-- | Split a stream of arrays on a given separator byte, dropping the separator
252+-- and coalescing all the arrays between two separators into a single array.
253+--
254+-- @since 0.7.0
255+{-# INLINE_NORMAL _splitOn #-}
256+_splitOn
257+ :: MonadIO m
258+ => Word8
259+ -> D.Stream m (Array Word8)
260+ -> D.Stream m (Array Word8)
261+_splitOn byte (D.Stream step state) = D.Stream step' (Initial state)
262+
263+ where
264+
265+ {-# INLINE_LATE step' #-}
266+ step' gst (Initial st) = do
267+ r <- step gst st
268+ case r of
269+ D.Yield arr s -> do
270+ (arr1, marr2) <- A.breakOn byte arr
271+ return $ case marr2 of
272+ Nothing -> D.Skip (Buffering s arr1)
273+ Just arr2 -> D.Skip (Yielding arr1 (Splitting s arr2))
274+ D.Skip s -> return $ D.Skip (Initial s)
275+ D.Stop -> return D.Stop
276+
277+ step' gst (Buffering st buf) = do
278+ r <- step gst st
279+ case r of
280+ D.Yield arr s -> do
281+ (arr1, marr2) <- A.breakOn byte arr
282+ buf' <- A.splice buf arr1
283+ return $ case marr2 of
284+ Nothing -> D.Skip (Buffering s buf')
285+ Just x -> D.Skip (Yielding buf' (Splitting s x))
286+ D.Skip s -> return $ D.Skip (Buffering s buf)
287+ D.Stop -> return $
288+ if A.byteLength buf == 0
289+ then D.Stop
290+ else D.Skip (Yielding buf Finishing)
291+
292+ step' _ (Splitting st buf) = do
293+ (arr1, marr2) <- A.breakOn byte buf
294+ return $ case marr2 of
295+ Nothing -> D.Skip $ Buffering st arr1
296+ Just arr2 -> D.Skip $ Yielding arr1 (Splitting st arr2)
297+
298+ step' _ (Yielding arr next) = return $ D.Yield arr next
299+ step' _ Finishing = return D.Stop
300+
155-- XXX Remove MonadIO constraint.
301-- XXX Remove MonadIO constraint.
156-- | Split a stream of arrays on a given separator byte, dropping the separator
302-- | Split a stream of arrays on a given separator byte, dropping the separator
157-- and coalescing all the arrays between two separators into a single array.
303-- and coalescing all the arrays between two separators into a single array.
@@ -163,7 +309,7 @@ splitOn
163 => Word8
309 => Word8
164 -> Stream m (Array Word8)
310 -> Stream m (Array Word8)
165 -> Stream m (Array Word8)
311 -> Stream m (Array Word8)
166−splitOn = Array.compactOnByte
312+splitOn byte = D.splitInnerBy (A.breakOn byte) A.splice
167
313
168{-# INLINE splitOnSuffix #-}
314{-# INLINE splitOnSuffix #-}
169splitOnSuffix
315splitOnSuffix
@@ -171,7 +317,8 @@ splitOnSuffix
171 => Word8
317 => Word8
172 -> Stream m (Array Word8)
318 -> Stream m (Array Word8)
173 -> Stream m (Array Word8)
319 -> Stream m (Array Word8)
174−splitOnSuffix = Array.compactOnByteSuffix
320+-- splitOn byte s = fromStreamD $ A.splitOn byte $ toStreamD s
321+splitOnSuffix byte = D.splitInnerBySuffix (A.breakOn byte) A.splice
175
322
176-------------------------------------------------------------------------------
323-------------------------------------------------------------------------------
177-- Elimination - Running folds
324-- Elimination - Running folds
@@ -180,24 +327,77 @@ splitOnSuffix = Array.compactOnByteSuffix
180{-# INLINE_NORMAL foldBreakD #-}
327{-# INLINE_NORMAL foldBreakD #-}
181foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
328foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
182 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
329 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
183−foldBreakD = Array.foldBreakChunks
330+foldBreakD (FL.Fold fstep initial extract) stream@(D.Stream step state) = do
331+ res <- initial
332+ case res of
333+ FL.Partial fs -> go SPEC state fs
334+ FL.Done fb -> return $! (fb, stream)
335+
336+ where
337+
338+ {-# INLINE go #-}
339+ go !_ st !fs = do
340+ r <- step defState st
341+ case r of
342+ D.Yield (Array contents start end) s ->
343+ let fp = Tuple' end contents
344+ in goArray SPEC s fp start fs
345+ D.Skip s -> go SPEC s fs
346+ D.Stop -> do
347+ b <- extract fs
348+ return (b, D.nil)
349+
350+ goArray !_ s (Tuple' end _) !cur !fs
351+ | cur == end = do
352+ go SPEC s fs
353+ goArray !_ st fp@(Tuple' end contents) !cur !fs = do
354+ x <- liftIO $ peekByteIndex cur contents
355+ res <- fstep fs x
356+ let next = INDEX_NEXT(cur,a)
357+ case res of
358+ FL.Done b -> do
359+ let arr = Array contents next end
360+ return $! (b, D.cons arr (D.Stream step st))
361+ FL.Partial fs1 -> goArray SPEC st fp next fs1
362+
363+{-# INLINE_NORMAL foldBreakK #-}
364+foldBreakK :: forall m a b. (MonadIO m, Unbox a) =>
365+ Fold m a b -> K.StreamK m (Array a) -> m (b, K.StreamK m (Array a))
366+foldBreakK (FL.Fold fstep initial extract) stream = do
367+ res <- initial
368+ case res of
369+ FL.Partial fs -> go fs stream
370+ FL.Done fb -> return (fb, stream)
371+
372+ where
373+
374+ {-# INLINE go #-}
375+ go !fs st = do
376+ let stop = (, K.nil) <$> extract fs
377+ single a = yieldk a K.nil
378+ yieldk (Array contents start end) r =
379+ let fp = Tuple' end contents
380+ in goArray fs r fp start
381+ in K.foldStream defState yieldk single stop st
382+
383+ goArray !fs st (Tuple' end _) !cur
384+ | cur == end = do
385+ go fs st
386+ goArray !fs st fp@(Tuple' end contents) !cur = do
387+ x <- liftIO $ peekByteIndex cur contents
388+ res <- fstep fs x
389+ let next = INDEX_NEXT(cur,a)
390+ case res of
391+ FL.Done b -> do
392+ let arr = Array contents next end
393+ return $! (b, K.cons arr st)
394+ FL.Partial fs1 -> goArray fs1 st fp next
184
395
185-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
396-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
186-- and the unconsumed stream.
397-- and the unconsumed stream.
187--
398--
188-- > foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
399-- > foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
189--
400--
190−-- Instead of using this we can adapt the fold to ParserK and use
191−-- parseBreakChunks instead. ParserK allows composing using Monad as well.
192−--
193−-- @
194−-- foldBreak f s =
195−-- fmap (first (fromRight undefined))
196−-- $ K.parseBreakChunks (ParserK.adaptC (PR.fromFold f)) s
197−-- @
198−--
199−-- We can compare perf and remove this one or define it in terms of that.
200−--
201-- /Internal/
401-- /Internal/
202--
402--
203{-# INLINE_NORMAL foldBreak #-}
403{-# INLINE_NORMAL foldBreak #-}
@@ -206,20 +406,14 @@ foldBreak ::
206 => Fold m a b
406 => Fold m a b
207 -> StreamK m (A.Array a)
407 -> StreamK m (A.Array a)
208 -> m (b, StreamK m (A.Array a))
408 -> m (b, StreamK m (A.Array a))
209−foldBreak = Array.foldBreakChunksK
210−--
211-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
409-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
212−--
213−-- foldBreak f s =
410+foldBreak = foldBreakK
214−-- fmap (first (fromRight undefined))
215−-- $ K.parseBreakChunks (ParserK.adaptC (PR.fromFold f)) s
216−--
217-- If foldBreak performs better than runArrayFoldBreak we can use a rewrite
411-- If foldBreak performs better than runArrayFoldBreak we can use a rewrite
218-- rule to rewrite runArrayFoldBreak to fold.
412-- rule to rewrite runArrayFoldBreak to fold.
219-- foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
413-- foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
220
414
221-------------------------------------------------------------------------------
415-------------------------------------------------------------------------------
222−-- Elimination - running element parsers
416+-- Fold to a single Array
223-------------------------------------------------------------------------------
417-------------------------------------------------------------------------------
224
418
225-- When we have to take an array partially, take the last part of the array.
419-- When we have to take an array partially, take the last part of the array.
@@ -265,22 +459,341 @@ splitAtArrayListRev n ls
265 arr1 = Array contents end1 end
459 arr1 = Array contents end1 end
266 in ([arr1], arr2:xs)
460 in ([arr1], arr2:xs)
267
461
462+-------------------------------------------------------------------------------
463+-- Fold to a single Array
464+-------------------------------------------------------------------------------
465+
466+{-
467+
468+-- XXX Both of these implementations of splicing seem to perform equally well.
469+-- We need to perform benchmarks over a range of sizes though.
470+
471+-- CAUTION! length must more than equal to lengths of all the arrays in the
472+-- stream.
473+{-# INLINE spliceArraysLenUnsafe #-}
474+spliceArraysLenUnsafe :: (MonadIO m, Unbox a)
475+ => Int -> Stream m (MutArray a) -> m (MutArray a)
476+spliceArraysLenUnsafe len buffered = do
477+ -- XXX The new array's pinned state should depend on the first element
478+ -- of the stream. We should uncons the stream and do the required.
479+ arr <- undefined
480+ D.foldlM' MA.spliceUnsafe (return arr) buffered
481+
482+{-# INLINE _spliceArrays #-}
483+_spliceArrays :: (MonadIO m, Unbox a)
484+ => Stream m (Array a) -> m (Array a)
485+_spliceArrays s = do
486+ buffered <- D.foldr K.cons K.nil s
487+ len <- K.fold FL.sum (fmap Array.length buffered)
488+ -- XXX The new array's pinned state should depend on the first element
489+ -- of the stream. We should uncons the stream and do the required.
490+ arr <- undefined
491+ final <- D.foldlM' writeArr (return arr) (toStream buffered)
492+ return $ A.unsafeFreeze final
493+
494+ where
495+
496+ writeArr dst arr = MA.spliceUnsafe dst (A.unsafeThaw arr)
497+
498+{-# INLINE _spliceArraysBuffered #-}
499+_spliceArraysBuffered :: (MonadIO m, Unbox a)
500+ => Stream m (Array a) -> m (Array a)
501+_spliceArraysBuffered s = do
502+ buffered <- D.foldr K.cons K.nil s
503+ len <- K.fold FL.sum (fmap Array.length buffered)
504+ A.unsafeFreeze <$>
505+ spliceArraysLenUnsafe len (fmap A.unsafeThaw (toStream buffered))
506+
507+-}
508+
509+{-# INLINE spliceArraysRealloced #-}
510+spliceArraysRealloced :: forall m a. (MonadIO m, Unbox a)
511+ => Stream m (Array a) -> m (Array a)
512+spliceArraysRealloced s = do
513+ res <- D.uncons s
514+ case res of
515+ Just (a, strm) -> do
516+ arr <-
517+ D.foldlM'
518+ MA.spliceExp
519+ (pure (A.unsafeThaw a))
520+ (fmap A.unsafeThaw strm)
521+ liftIO $ A.unsafeFreeze <$> MA.rightSize arr
522+ Nothing -> pure A.nil
523+
524+-- XXX This should just be "fold A.write"
525+--
526+-- | Given a stream of arrays, splice them all together to generate a single
527+-- array. The stream must be /finite/.
528+--
529+-- @since 0.7.0
530+{-# INLINE toArray #-}
531+toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
532+toArray = spliceArraysRealloced
533+-- spliceArrays = _spliceArraysBuffered
534+
535+-- exponentially increasing sizes of the chunks upto the max limit.
536+-- XXX this will be easier to implement with parsers/terminating folds
537+-- With this we should be able to reduce the number of chunks/allocations.
538+-- The reallocation/copy based toArray can also be implemented using this.
539+--
540+{-
541+{-# INLINE toArraysInRange #-}
542+toArraysInRange :: (MonadIO m, Unbox a)
543+ => Int -> Int -> Fold m (Array a) b -> Fold m a b
544+toArraysInRange low high (Fold step initial extract) =
545+-}
546+
547+{-
548+-- | Fold the input to a pure buffered stream (List) of arrays.
549+{-# INLINE _toArraysOf #-}
550+_toArraysOf :: (MonadIO m, Unbox a)
551+ => Int -> Fold m a (Stream Identity (Array a))
552+_toArraysOf n = FL.groupsOf n (A.writeNF n) FL.toStream
553+-}
554+
555+-------------------------------------------------------------------------------
556+-- Elimination - running element parsers
557+-------------------------------------------------------------------------------
558+
268-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
559-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
269-- to make a newtype.
560-- to make a newtype.
270{-# ANN type List NoSpecConstr #-}
561{-# ANN type List NoSpecConstr #-}
271newtype List a = List {getList :: [a]}
562newtype List a = List {getList :: [a]}
272
563
564+{-
565+-- This can be generalized to any type provided it can be unfolded to a stream
566+-- and it can be combined using a semigroup operation.
567+--
568+-- XXX This should be written using CPS (as parseK) if we want it to scale wrt
569+-- to the number of times it can be called on the same stream.
570+{-# INLINE_NORMAL parseBreakD #-}
571+parseBreakD ::
572+ forall m a b. (MonadIO m, MonadThrow m, Unbox a)
573+ => PRD.Parser a m b
574+ -> D.Stream m (Array.Array a)
575+ -> m (b, D.Stream m (Array.Array a))
576+parseBreakD
577+ (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
578+
579+ res <- initial
580+ case res of
581+ PRD.IPartial s -> go SPEC state (List []) s
582+ PRD.IDone b -> return (b, stream)
583+ PRD.IError err -> throwM $ ParseError err
584+
585+ where
586+
587+ -- "backBuf" contains last few items in the stream that we may have to
588+ -- backtrack to.
589+ --
590+ -- XXX currently we are using a dumb list based approach for backtracking
591+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
592+ -- That will allow us more efficient random back and forth movement.
593+ go !_ st backBuf !pst = do
594+ r <- step defState st
595+ case r of
596+ D.Yield (Array contents start end) s ->
597+ gobuf SPEC s backBuf
598+ (Tuple' end contents) start pst
599+ D.Skip s -> go SPEC s backBuf pst
600+ D.Stop -> do
601+ b <- extract pst
602+ return (b, D.nil)
603+
604+ -- Use strictness on "cur" to keep it unboxed
605+ gobuf !_ s backBuf (Tuple' end _) !cur !pst
606+ | cur == end = do
607+ go SPEC s backBuf pst
608+ gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
609+ x <- liftIO $ peekByteIndex contents cur
610+ pRes <- pstep pst x
611+ let next = INDEX_NEXT(cur,a)
612+ case pRes of
613+ PR.Partial 0 pst1 ->
614+ gobuf SPEC s (List []) fp next pst1
615+ PR.Partial n pst1 -> do
616+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
617+ let src0 = Prelude.take n (x:getList backBuf)
618+ arr0 = A.fromListN n (Prelude.reverse src0)
619+ arr1 = Array contents next end
620+ src = arr0 <> arr1
621+ let !(Array cont1 start end1) = src
622+ fp1 = Tuple' end1 cont1
623+ gobuf SPEC s (List []) fp1 start pst1
624+ PR.Continue 0 pst1 ->
625+ gobuf SPEC s (List (x:getList backBuf)) fp next pst1
626+ PR.Continue n pst1 -> do
627+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
628+ let (src0, buf1) = splitAt n (x:getList backBuf)
629+ arr0 = A.fromListN n (Prelude.reverse src0)
630+ arr1 = Array contents next end
631+ src = arr0 <> arr1
632+ let !(Array cont1 start end1) = src
633+ fp1 = Tuple' end1 cont1
634+ gobuf SPEC s (List buf1) fp1 start pst1
635+ PR.Done 0 b -> do
636+ let arr = Array contents next end
637+ return (b, D.cons arr (D.Stream step s))
638+ PR.Done n b -> do
639+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
640+ let src0 = Prelude.take n (x:getList backBuf)
641+ -- XXX create the array in reverse instead
642+ arr0 = A.fromListN n (Prelude.reverse src0)
643+ arr1 = Array contents next end
644+ -- XXX Use StreamK to avoid adding arbitrary layers of
645+ -- constructors every time.
646+ str = D.cons arr0 (D.cons arr1 (D.Stream step s))
647+ return (b, str)
648+ PR.Error err -> throwM $ ParseError err
649+-}
650+
651+{-# INLINE_NORMAL parseBreakK #-}
652+parseBreakK ::
653+ forall m a b. (MonadIO m, Unbox a)
654+ => PRD.Parser a m b
655+ -> K.StreamK m (Array.Array a)
656+ -> m (Either ParseError b, K.StreamK m (Array.Array a))
657+parseBreakK (PRD.Parser pstep initial extract) stream = do
658+ res <- initial
659+ case res of
660+ PRD.IPartial s -> go s stream []
661+ PRD.IDone b -> return (Right b, stream)
662+ PRD.IError err -> return (Left (ParseError err), stream)
663+
664+ where
665+
666+ -- "backBuf" contains last few items in the stream that we may have to
667+ -- backtrack to.
668+ --
669+ -- XXX currently we are using a dumb list based approach for backtracking
670+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
671+ -- That will allow us more efficient random back and forth movement.
672+ go !pst st backBuf = do
673+ let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
674+ single a = yieldk a K.nil
675+ yieldk arr r = goArray pst backBuf r arr
676+ in K.foldStream defState yieldk single stop st
677+
678+ -- Use strictness on "cur" to keep it unboxed
679+ goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
680+ goArray !pst backBuf st (Array contents cur end) = do
681+ x <- liftIO $ peekByteIndex cur contents
682+ pRes <- pstep pst x
683+ let next = INDEX_NEXT(cur,a)
684+ case pRes of
685+ PR.Partial 0 s ->
686+ goArray s [] st (Array contents next end)
687+ PR.Partial n s -> do
688+ assert (n <= Prelude.length (x:backBuf)) (return ())
689+ let src0 = Prelude.take n (x:backBuf)
690+ arr0 = A.fromListN n (Prelude.reverse src0)
691+ arr1 = Array contents next end
692+ src = arr0 <> arr1
693+ goArray s [] st src
694+ PR.Continue 0 s ->
695+ goArray s (x:backBuf) st (Array contents next end)
696+ PR.Continue n s -> do
697+ assert (n <= Prelude.length (x:backBuf)) (return ())
698+ let (src0, buf1) = splitAt n (x:backBuf)
699+ arr0 = A.fromListN n (Prelude.reverse src0)
700+ arr1 = Array contents next end
701+ src = arr0 <> arr1
702+ goArray s buf1 st src
703+ PR.Done 0 b -> do
704+ let arr = Array contents next end
705+ return (Right b, K.cons arr st)
706+ PR.Done n b -> do
707+ assert (n <= Prelude.length (x:backBuf)) (return ())
708+ let src0 = Prelude.take n (x:backBuf)
709+ -- XXX Use fromListRevN once implemented
710+ -- arr0 = A.fromListRevN n src0
711+ arr0 = A.fromListN n (Prelude.reverse src0)
712+ arr1 = Array contents next end
713+ str = K.cons arr0 (K.cons arr1 st)
714+ return (Right b, str)
715+ PR.Error err -> do
716+ let n = Prelude.length backBuf
717+ arr0 = A.fromListN n (Prelude.reverse backBuf)
718+ arr1 = Array contents cur end
719+ str = K.cons arr0 (K.cons arr1 stream)
720+ return (Left (ParseError err), str)
721+
722+ -- This is a simplified goArray
723+ goExtract !pst backBuf (Array _ cur end)
724+ | cur == end = goStop pst backBuf
725+ goExtract !pst backBuf (Array contents cur end) = do
726+ x <- liftIO $ peekByteIndex cur contents
727+ pRes <- pstep pst x
728+ let next = INDEX_NEXT(cur,a)
729+ case pRes of
730+ PR.Partial 0 s ->
731+ goExtract s [] (Array contents next end)
732+ PR.Partial n s -> do
733+ assert (n <= Prelude.length (x:backBuf)) (return ())
734+ let src0 = Prelude.take n (x:backBuf)
735+ arr0 = A.fromListN n (Prelude.reverse src0)
736+ arr1 = Array contents next end
737+ src = arr0 <> arr1
738+ goExtract s [] src
739+ PR.Continue 0 s ->
740+ goExtract s backBuf (Array contents next end)
741+ PR.Continue n s -> do
742+ assert (n <= Prelude.length (x:backBuf)) (return ())
743+ let (src0, buf1) = splitAt n (x:backBuf)
744+ arr0 = A.fromListN n (Prelude.reverse src0)
745+ arr1 = Array contents next end
746+ src = arr0 <> arr1
747+ goExtract s buf1 src
748+ PR.Done 0 b -> do
749+ let arr = Array contents next end
750+ return (Right b, K.fromPure arr)
751+ PR.Done n b -> do
752+ assert (n <= Prelude.length backBuf) (return ())
753+ let src0 = Prelude.take n backBuf
754+ -- XXX Use fromListRevN once implemented
755+ -- arr0 = A.fromListRevN n src0
756+ arr0 = A.fromListN n (Prelude.reverse src0)
757+ arr1 = Array contents next end
758+ str = K.cons arr0 (K.fromPure arr1)
759+ return (Right b, str)
760+ PR.Error err -> do
761+ let n = Prelude.length backBuf
762+ arr0 = A.fromListN n (Prelude.reverse backBuf)
763+ arr1 = Array contents cur end
764+ str = K.cons arr0 (K.cons arr1 stream)
765+ return (Left (ParseError err), str)
766+
767+ -- This is a simplified goExtract
768+ {-# INLINE goStop #-}
769+ goStop !pst backBuf = do
770+ pRes <- extract pst
771+ case pRes of
772+ PR.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
773+ PR.Continue 0 s ->
774+ goStop s backBuf
775+ PR.Continue n s -> do
776+ assert (n <= Prelude.length backBuf) (return ())
777+ let (src0, buf1) = splitAt n backBuf
778+ arr = A.fromListN n (Prelude.reverse src0)
779+ goExtract s buf1 arr
780+ PR.Done 0 b ->
781+ return (Right b, K.nil)
782+ PR.Done n b -> do
783+ assert (n <= Prelude.length backBuf) (return ())
784+ let src0 = Prelude.take n backBuf
785+ -- XXX Use fromListRevN once implemented
786+ -- arr0 = A.fromListRevN n src0
787+ arr0 = A.fromListN n (Prelude.reverse src0)
788+ return (Right b, K.fromPure arr0)
789+ PR.Error err -> do
790+ let n = Prelude.length backBuf
791+ arr0 = A.fromListN n (Prelude.reverse backBuf)
792+ return (Left (ParseError err), K.fromPure arr0)
793+
273-- | Parse an array stream using the supplied 'Parser'. Returns the parse
794-- | Parse an array stream using the supplied 'Parser'. Returns the parse
274-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
795-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
275--
796--
276−-- >> parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
277−--
278−-- This is redundant and we can just use parseBreakChunks, as ParserK can be
279−-- composed using Monad. The only advantage of this is that we do not need to
280−-- adapt.
281−--
282−-- We can compare perf and remove this one or define it in terms of that.
283−--
284-- /Internal/
797-- /Internal/
285--
798--
286{-# INLINE_NORMAL parseBreak #-}
799{-# INLINE_NORMAL parseBreak #-}
@@ -293,8 +806,7 @@ parseBreak ::
293parseBreak p s =
806parseBreak p s =
294 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
807 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
295-}
808-}
296−parseBreak = Array.parseBreakChunksK
809+parseBreak = parseBreakK
297−-- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
298
810
299-------------------------------------------------------------------------------
811-------------------------------------------------------------------------------
300-- Elimination - Running Array Folds and parsers
812-- Elimination - Running Array Folds and parsers
src/Streamly/Internal/Data/Stream/Common.hs → core/src/Streamly/Internal/Data/Stream/Common.hsrenamed+3−3
@@ -30,10 +30,10 @@ where
30
30
31#include "inline.hs"
31#include "inline.hs"
32
32
33−import Streamly.Data.Fold (Fold)
33+import Streamly.Internal.Data.Fold.Type (Fold (..))
34
34
35−import qualified Streamly.Data.StreamK as K
35+import qualified Streamly.Internal.Data.StreamK.Type as K
36−import qualified Streamly.Internal.Data.Stream as D
36+import qualified Streamly.Internal.Data.Stream.Type as D
37
37
38import Prelude hiding (Foldable(..), repeat)
38import Prelude hiding (Foldable(..), repeat)
39
39
core/src/Streamly/Internal/Data/Stream/Container.hs+48−56
@@ -11,17 +11,16 @@
11
11
12module Streamly.Internal.Data.Stream.Container
12module Streamly.Internal.Data.Stream.Container
13 (
13 (
14− -- * Deduplication
14+ nub
15− ordNub
16
15
17− -- * Joins
16+ -- * Joins for unconstrained types
18− , leftJoin
17+ , joinLeftGeneric
19− , outerJoin
18+ , joinOuterGeneric
20
19
21− -- * Ord Joins
20+ -- * Joins with Ord constraint
22− , innerOrdJoin
21+ , joinInner
23− , leftOrdJoin
22+ , joinLeft
24− , outerOrdJoin
23+ , joinOuter
25 )
24 )
26where
25where
27
26
@@ -48,15 +47,12 @@ import qualified Streamly.Internal.Data.Stream.Transformer as Stream
48
47
49#include "DocTestDataStream.hs"
48#include "DocTestDataStream.hs"
50
49
51−-- | @nub@ specialized to 'Ord' types for better performance. Returns a
52−-- subsequence of the stream removing any duplicate elements.
53−--
54−-- The memory used is proportional to the number of unique elements in the
50+-- | The memory used is proportional to the number of unique elements in the
55−-- stream. One way to limit the memory is to use @take@ on the resulting
51+-- stream. If we want to limit the memory we can just use "take" to limit the
56−-- stream to limit the unique elements in the stream.
52+-- uniq elements in the stream.
57−{-# INLINE_NORMAL ordNub #-}
53+{-# INLINE_NORMAL nub #-}
58−ordNub :: (Monad m, Ord a) => Stream m a -> Stream m a
54+nub :: (Monad m, Ord a) => Stream m a -> Stream m a
59−ordNub (Stream step1 state1) = Stream step (Set.empty, state1)
55+nub (Stream step1 state1) = Stream step (Set.empty, state1)
60
56
61 where
57 where
62
58
@@ -82,8 +78,8 @@ toMap =
82--
78--
83-- XXX An IntMap may be faster when the keys are Int.
79-- XXX An IntMap may be faster when the keys are Int.
84-- XXX Use hashmap instead of map?
80-- XXX Use hashmap instead of map?
85−
81+--
86−-- | 'innerJoin' specialized to 'Ord' types for better performance.
82+-- | Like 'joinInner' but uses a 'Map' for efficiency.
87--
83--
88-- If the input streams have duplicate keys, the behavior is undefined.
84-- If the input streams have duplicate keys, the behavior is undefined.
89--
85--
@@ -94,10 +90,10 @@ toMap =
94-- Time: O(m + n)
90-- Time: O(m + n)
95--
91--
96-- /Pre-release/
92-- /Pre-release/
97−{-# INLINE innerOrdJoin #-}
93+{-# INLINE joinInner #-}
98−innerOrdJoin :: (Monad m, Ord k) =>
94+joinInner :: (Monad m, Ord k) =>
99 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
95 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
100−innerOrdJoin s1 s2 =
96+joinInner s1 s2 =
101 Stream.concatEffect $ do
97 Stream.concatEffect $ do
102 km <- toMap s2
98 km <- toMap s2
103 pure $ Stream.mapMaybe (joinAB km) s1
99 pure $ Stream.mapMaybe (joinAB km) s1
@@ -110,33 +106,32 @@ innerOrdJoin s1 s2 =
110 Nothing -> Nothing
106 Nothing -> Nothing
111
107
112-- XXX We can do this concurrently.
108-- XXX We can do this concurrently.
113−-- XXX Check performance of StreamD vs StreamK
114-- XXX If the second stream is sorted and passed as an Array or a seek capable
109-- XXX If the second stream is sorted and passed as an Array or a seek capable
115-- stream then we could use binary search if we have an Ord instance or
110-- stream then we could use binary search if we have an Ord instance or
116-- Ordering returning function. The time complexity would then become (m x log
111-- Ordering returning function. The time complexity would then become (m x log
117-- n).
112-- n).
118
113
119−-- | Like 'innerJoin' but emits @(a, Just b)@ whenever a and b are equal, for
114+-- XXX Check performance of StreamD vs StreamK
115+
116+-- | Like 'joinInner' but emit @(a, Just b)@, and additionally, for those @a@'s
120−-- those @a@'s that are not equal to any @b@ emits @(a, Nothing)@.
117+-- that are not equal to any @b@ emit @(a, Nothing)@.
121−--
122−-- This is a generalization of 'innerJoin' to include all elements from the
123−-- left stream and not just those which have an equal in the right stream. This
124−-- is not a commutative operation, the order of the stream arguments matters.
125--
118--
126−-- All the caveats mentioned in 'innerJoin' apply here as well. Right join is
119+-- The second stream is evaluated multiple times. If the stream is a
127−-- not provided because it is just a flipped left join:
120+-- consume-once stream then the caller should cache it in an 'Data.Array.Array'
121+-- before calling this function. Caching may also improve performance if the
122+-- stream is expensive to evaluate.
128--
123--
129−-- >>> rightJoin eq = flip (Stream.leftJoin eq)
124+-- >>> joinRightGeneric eq = flip (Stream.joinLeftGeneric eq)
130--
125--
131-- Space: O(n) assuming the second stream is cached in memory.
126-- Space: O(n) assuming the second stream is cached in memory.
132--
127--
133-- Time: O(m x n)
128-- Time: O(m x n)
134--
129--
135-- /Unimplemented/
130-- /Unimplemented/
136−{-# INLINE leftJoin #-}
131+{-# INLINE joinLeftGeneric #-}
137−leftJoin :: Monad m =>
132+joinLeftGeneric :: Monad m =>
138 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
133 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
139−leftJoin eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
134+joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
140 a <- mkCross (Stream.liftInner s1)
135 a <- mkCross (Stream.liftInner s1)
141 -- XXX should we use StreamD monad here?
136 -- XXX should we use StreamD monad here?
142 -- XXX Is there a better way to perform some action at the end of a loop
137 -- XXX Is there a better way to perform some action at the end of a loop
@@ -157,17 +152,19 @@ leftJoin eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
157 else mkCross Stream.nil
152 else mkCross Stream.nil
158 Nothing -> return (a, Nothing)
153 Nothing -> return (a, Nothing)
159
154
160−-- | 'leftJoin' specialized to 'Ord' types for better performance.
155+-- XXX rename to joinLeftOrd?
156+
157+-- | A more efficient 'joinLeft' using a hashmap for efficiency.
161--
158--
162-- Space: O(n)
159-- Space: O(n)
163--
160--
164-- Time: O(m + n)
161-- Time: O(m + n)
165--
162--
166-- /Pre-release/
163-- /Pre-release/
167−{-# INLINE leftOrdJoin #-}
164+{-# INLINE joinLeft #-}
168−leftOrdJoin :: (Ord k, Monad m) =>
165+joinLeft :: (Ord k, Monad m) =>
169 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
166 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
170−leftOrdJoin s1 s2 =
167+joinLeft s1 s2 =
171 Stream.concatEffect $ do
168 Stream.concatEffect $ do
172 km <- toMap s2
169 km <- toMap s2
173 return $ fmap (joinAB km) s1
170 return $ fmap (joinAB km) s1
@@ -180,19 +177,14 @@ leftOrdJoin s1 s2 =
180 Nothing -> (k, a, Nothing)
177 Nothing -> (k, a, Nothing)
181
178
182-- XXX We can do this concurrently.
179-- XXX We can do this concurrently.
183−-- XXX Check performance of StreamD vs StreamK cross operation.
184
180
181+-- XXX Check performance of StreamD vs StreamK
182+
185−-- | Like 'leftJoin' but emits a @(Just a, Just b)@. Like 'leftJoin', for those
183+-- | Like 'joinLeft' but emits a @(Just a, Just b)@. Like 'joinLeft', for those
186-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
184-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
187-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
185-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
188-- Just b)@.
186-- Just b)@.
189--
187--
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−--
196-- For space efficiency use the smaller stream as the second stream.
188-- For space efficiency use the smaller stream as the second stream.
197--
189--
198-- Space: O(n)
190-- Space: O(n)
@@ -200,15 +192,15 @@ leftOrdJoin s1 s2 =
200-- Time: O(m x n)
192-- Time: O(m x n)
201--
193--
202-- /Pre-release/
194-- /Pre-release/
203−{-# INLINE outerJoin #-}
195+{-# INLINE joinOuterGeneric #-}
204−outerJoin :: MonadIO m =>
196+joinOuterGeneric :: MonadIO m =>
205 (a -> b -> Bool)
197 (a -> b -> Bool)
206 -> Stream m a
198 -> Stream m a
207 -> Stream m b
199 -> Stream m b
208 -> Stream m (Maybe a, Maybe b)
200 -> Stream m (Maybe a, Maybe b)
209−outerJoin eq s1 s2 =
201+joinOuterGeneric eq s1 s =
210 Stream.concatEffect $ do
202 Stream.concatEffect $ do
211− inputArr <- Array.fromStream s2
203+ inputArr <- Array.fromStream s
212 let len = Array.length inputArr
204 let len = Array.length inputArr
213 foundArr <-
205 foundArr <-
214 Stream.fold
206 Stream.fold
@@ -262,18 +254,18 @@ outerJoin eq s1 s2 =
262-- a flag. At the end go through @Stream m b@ and find those that are not in that
254-- a flag. At the end go through @Stream m b@ and find those that are not in that
263-- hash to return (Nothing, b).
255-- hash to return (Nothing, b).
264
256
265−-- | 'outerJoin' specialized to 'Ord' types for better performance.
257+-- | Like 'joinOuter' but uses a 'Map' for efficiency.
266--
258--
267-- Space: O(m + n)
259-- Space: O(m + n)
268--
260--
269-- Time: O(m + n)
261-- Time: O(m + n)
270--
262--
271-- /Pre-release/
263-- /Pre-release/
272−{-# INLINE outerOrdJoin #-}
264+{-# INLINE joinOuter #-}
273−outerOrdJoin ::
265+joinOuter ::
274 (Ord k, MonadIO m) =>
266 (Ord k, MonadIO m) =>
275 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
267 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
276−outerOrdJoin s1 s2 =
268+joinOuter s1 s2 =
277 Stream.concatEffect $ do
269 Stream.concatEffect $ do
278 km1 <- kvFold s1
270 km1 <- kvFold s1
279 km2 <- kvFold s2
271 km2 <- kvFold s2
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+25−33
@@ -13,24 +13,36 @@
13--
13--
14module Streamly.Internal.Data.Stream.Eliminate
14module Streamly.Internal.Data.Stream.Eliminate
15 (
15 (
16− -- * Running a Parser
16+ -- * Running a 'Fold'
17+ fold
18+
19+ -- -- * Running a 'Parser'
17− parse
20+ , parse
18 , parseD
21 , parseD
19 , parseBreak
22 , parseBreak
20 , parseBreakD
23 , parseBreakD
21
24
22− -- * Deconstruction
25+ -- * Stream Deconstruction
23 , uncons
26 , uncons
24
27
25 -- * Right Folds
28 -- * Right Folds
29+ , foldrM
30+ , foldr
31+ , foldrMx
26 , foldr1
32 , foldr1
27
33
34+ -- * Left Folds
35+ , foldlM'
36+ , foldl'
37+ , foldlMx'
38+ , foldlx'
39+
28 -- * Specific Fold Functions
40 -- * Specific Fold Functions
41+ , drain
29 , mapM_ -- Map and Fold
42 , mapM_ -- Map and Fold
30 , null
43 , null
31 , head
44 , head
32 , headElse
45 , headElse
33− , init
34 , tail
46 , tail
35 , last
47 , last
36 , elem
48 , elem
@@ -48,9 +60,16 @@ module Streamly.Internal.Data.Stream.Eliminate
48 , the
60 , the
49
61
50 -- * To containers
62 -- * To containers
63+ , toList
51 , toListRev
64 , toListRev
52
65
53 -- * Multi-Stream Folds
66 -- * Multi-Stream Folds
67+ -- ** Comparisons
68+ -- | These should probably be expressed using zipping operations.
69+ , eqBy
70+ , cmpBy
71+
72+ -- ** Substreams
54 -- | These should probably be expressed using parsers.
73 -- | These should probably be expressed using parsers.
55 , isPrefixOf
74 , isPrefixOf
56 , isInfixOf
75 , isInfixOf
@@ -71,7 +90,7 @@ import Foreign.Storable (Storable)
71import GHC.Exts (SpecConstrAnnotation(..))
90import GHC.Exts (SpecConstrAnnotation(..))
72import GHC.Types (SPEC(..))
91import GHC.Types (SPEC(..))
73import Streamly.Internal.Data.Parser (ParseError(..))
92import Streamly.Internal.Data.Parser (ParseError(..))
74−import Streamly.Internal.Data.SVar.Type (adaptState, defState)
93+import Streamly.Internal.Data.SVar.Type (defState)
75import Streamly.Internal.Data.Unbox (Unbox)
94import Streamly.Internal.Data.Unbox (Unbox)
76
95
77import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
96import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
@@ -86,7 +105,7 @@ import qualified Streamly.Internal.Data.Stream.Transform as StreamD
86
105
87import Prelude hiding
106import Prelude hiding
88 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
107 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
89− , notElem, splitAt, init, tail, (!!))
108+ , notElem, splitAt, tail, (!!))
90import Data.Foldable (length)
109import Data.Foldable (length)
91import Streamly.Internal.Data.Stream.Type
110import Streamly.Internal.Data.Stream.Type
92
111
@@ -372,35 +391,9 @@ head = foldrM (\x _ -> return (Just x)) (return Nothing)
372headElse :: Monad m => a -> Stream m a -> m a
391headElse :: Monad m => a -> Stream m a -> m a
373headElse a = foldrM (\x _ -> return x) (return a)
392headElse a = foldrM (\x _ -> return x) (return a)
374
393
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−--
398-- Does not fuse, has the same performance as the StreamK version.
394-- Does not fuse, has the same performance as the StreamK version.
399−--
400{-# INLINE_NORMAL tail #-}
395{-# INLINE_NORMAL tail #-}
401tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
396tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
402−tail = fmap (fmap snd) . uncons
403−{-
404tail (UnStream step state) = go SPEC state
397tail (UnStream step state) = go SPEC state
405 where
398 where
406 go !_ st = do
399 go !_ st = do
@@ -409,7 +402,6 @@ tail (UnStream step state) = go SPEC state
409 Yield _ s -> return (Just $ Stream step s)
402 Yield _ s -> return (Just $ Stream step s)
410 Skip s -> go SPEC s
403 Skip s -> go SPEC s
411 Stop -> return Nothing
404 Stop -> return Nothing
412−-}
413
405
414-- XXX will it fuse? need custom impl?
406-- XXX will it fuse? need custom impl?
415{-# INLINE_NORMAL last #-}
407{-# INLINE_NORMAL last #-}
core/src/Streamly/Internal/Data/Stream/Exception.hs+6−9
@@ -9,20 +9,17 @@
9
9
10module Streamly.Internal.Data.Stream.Exception
10module Streamly.Internal.Data.Stream.Exception
11 (
11 (
12− -- * Resources
13− before
14− , afterIO
15− , afterUnsafe
16− , finallyIO
17− , finallyUnsafe
18− , gbracket_
12+ gbracket_
19 , gbracket
13 , gbracket
14+ , before
15+ , afterUnsafe
16+ , afterIO
20 , bracketUnsafe
17 , bracketUnsafe
21 , bracketIO3
18 , bracketIO3
22 , bracketIO
19 , bracketIO
23−
24− -- * Exceptions
25 , onException
20 , onException
21+ , finallyUnsafe
22+ , finallyIO
26 , ghandle
23 , ghandle
27 , handle
24 , handle
28 )
25 )
core/src/Streamly/Internal/Data/Stream/Generate.hs+12−2
@@ -16,13 +16,20 @@ module Streamly.Internal.Data.Stream.Generate
16 (
16 (
17 -- * Primitives
17 -- * Primitives
18 nil
18 nil
19+ , nilM
19 , cons
20 , cons
21+ , consM
22+
23+ -- * From 'Unfold'
24+ , unfold
20
25
21 -- * Unfolding
26 -- * Unfolding
22 , unfoldr
27 , unfoldr
23 , unfoldrM
28 , unfoldrM
24
29
25 -- * From Values
30 -- * From Values
31+ , fromPure
32+ , fromEffect
26 , repeat
33 , repeat
27 , repeatM
34 , repeatM
28 , replicate
35 , replicate
@@ -88,6 +95,7 @@ module Streamly.Internal.Data.Stream.Generate
88 -- * From Containers
95 -- * From Containers
89 -- | Transform an input structure into a stream.
96 -- | Transform an input structure into a stream.
90
97
98+ , fromList
91 , fromListM
99 , fromListM
92 , fromFoldable
100 , fromFoldable
93 , fromFoldableM
101 , fromFoldableM
@@ -96,6 +104,10 @@ module Streamly.Internal.Data.Stream.Generate
96 , fromPtr
104 , fromPtr
97 , fromPtrN
105 , fromPtrN
98 , fromByteStr#
106 , fromByteStr#
107+
108+ -- * Conversions
109+ , fromStreamK
110+ , toStreamK
99 )
111 )
100where
112where
101
113
@@ -142,8 +154,6 @@ import Streamly.Internal.Data.Stream.Type
142nil :: Applicative m => Stream m a
154nil :: Applicative m => Stream m a
143nil = Stream (\_ _ -> pure Stop) ()
155nil = Stream (\_ _ -> pure Stop) ()
144
156
145−infixr 5 `cons`
146−
147-- XXX implement in terms of consM?
157-- XXX implement in terms of consM?
148-- cons x = consM (return x)
158-- cons x = consM (return x)
149-- From an implementation perspective, StreamK.cons translates into a
159-- From an implementation perspective, StreamK.cons translates into a
core/src/Streamly/Internal/Data/Stream/MutChunked.hsnew file+323
@@ -0,0 +1,323 @@
1+-- |
2+-- Module : Streamly.Internal.Data.Stream.MutChunked
3+-- Copyright : (c) 2019 Composewell Technologies
4+-- License : BSD3-3-Clause
5+-- Maintainer : streamly@composewell.com
6+-- Stability : experimental
7+-- Portability : GHC
8+--
9+-- Combinators to efficiently manipulate streams of mutable arrays.
10+--
11+module Streamly.Internal.Data.Stream.MutChunked
12+ (
13+ -- * Generation
14+ chunksOf
15+
16+ -- * Compaction
17+ , packArraysChunksOf
18+ , SpliceState (..)
19+ , lpackArraysChunksOf
20+ , compact
21+ , compactLE
22+ , compactEQ
23+ , compactGE
24+ )
25+where
26+
27+#include "inline.hs"
28+#include "ArrayMacros.h"
29+
30+import Control.Monad.IO.Class (MonadIO(..))
31+import Control.Monad (when)
32+import Data.Bifunctor (first)
33+import Data.Proxy (Proxy(..))
34+import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
35+import Streamly.Internal.Data.MutArray.Type (MutArray(..))
36+import Streamly.Internal.Data.Fold.Type (Fold(..))
37+import Streamly.Internal.Data.Parser (ParseError)
38+import Streamly.Internal.Data.Stream.Type (Stream)
39+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
40+
41+import qualified Streamly.Internal.Data.MutArray.Type as MArray
42+import qualified Streamly.Internal.Data.Fold.Type as FL
43+import qualified Streamly.Internal.Data.Parser as ParserD
44+import qualified Streamly.Internal.Data.Stream as D
45+
46+-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
47+-- @n@ elements each.
48+--
49+-- Same as the following but may be more efficient:
50+--
51+-- > chunksOf n = Stream.foldMany (MArray.writeN n)
52+--
53+-- /Pre-release/
54+{-# INLINE chunksOf #-}
55+chunksOf :: (MonadIO m, Unbox a)
56+ => Int -> Stream m a -> Stream m (MutArray a)
57+chunksOf = MArray.chunksOf
58+
59+-------------------------------------------------------------------------------
60+-- Compact
61+-------------------------------------------------------------------------------
62+
63+data SpliceState s arr
64+ = SpliceInitial s
65+ | SpliceBuffering s arr
66+ | SpliceYielding arr (SpliceState s arr)
67+ | SpliceFinish
68+
69+-- XXX This can be removed once compactLEFold/compactLE are implemented.
70+--
71+-- | This mutates the first array (if it has space) to append values from the
72+-- second one. This would work for immutable arrays as well because an
73+-- immutable array never has space so a new array is allocated instead of
74+-- mutating it.
75+--
76+-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
77+-- maximum specified size. Note that if a single array is bigger than the
78+-- specified size we do not split it to fit. When we coalesce multiple arrays
79+-- if the size would exceed the specified size we do not coalesce therefore the
80+-- actual array size may be less than the specified chunk size.
81+--
82+-- @since 0.7.0
83+{-# INLINE_NORMAL packArraysChunksOf #-}
84+packArraysChunksOf :: (MonadIO m, Unbox a)
85+ => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
86+packArraysChunksOf n (D.Stream step state) =
87+ D.Stream step' (SpliceInitial state)
88+
89+ where
90+
91+ {-# INLINE_LATE step' #-}
92+ step' gst (SpliceInitial st) = do
93+ when (n <= 0) $
94+ -- XXX we can pass the module string from the higher level API
95+ error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
96+ ++ "arrays [" ++ show n ++ "] must be a natural number"
97+ r <- step gst st
98+ case r of
99+ D.Yield arr s -> return $
100+ let len = MArray.byteLength arr
101+ in if len >= n
102+ then D.Skip (SpliceYielding arr (SpliceInitial s))
103+ else D.Skip (SpliceBuffering s arr)
104+ D.Skip s -> return $ D.Skip (SpliceInitial s)
105+ D.Stop -> return D.Stop
106+
107+ step' gst (SpliceBuffering st buf) = do
108+ r <- step gst st
109+ case r of
110+ D.Yield arr s -> do
111+ let len = MArray.byteLength buf + MArray.byteLength arr
112+ if len > n
113+ then return $
114+ D.Skip (SpliceYielding buf (SpliceBuffering s arr))
115+ else do
116+ buf' <- if MArray.byteCapacity buf < n
117+ then liftIO $ MArray.realloc n buf
118+ else return buf
119+ buf'' <- MArray.splice buf' arr
120+ return $ D.Skip (SpliceBuffering s buf'')
121+ D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
122+ D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
123+
124+ step' _ SpliceFinish = return D.Stop
125+
126+ step' _ (SpliceYielding arr next) = return $ D.Yield arr next
127+
128+-- XXX Remove this once compactLEFold is implemented
129+-- lpackArraysChunksOf = Fold.many compactLEFold
130+--
131+{-# INLINE_NORMAL lpackArraysChunksOf #-}
132+lpackArraysChunksOf :: (MonadIO m, Unbox a)
133+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
134+lpackArraysChunksOf n (Fold step1 initial1 extract1) =
135+ Fold step initial extract
136+
137+ where
138+
139+ initial = do
140+ when (n <= 0) $
141+ -- XXX we can pass the module string from the higher level API
142+ error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
143+ ++ "arrays [" ++ show n ++ "] must be a natural number"
144+
145+ r <- initial1
146+ return $ first (Tuple' Nothing) r
147+
148+ extract (Tuple' Nothing r1) = extract1 r1
149+ extract (Tuple' (Just buf) r1) = do
150+ r <- step1 r1 buf
151+ case r of
152+ FL.Partial rr -> extract1 rr
153+ FL.Done _ -> return ()
154+
155+ step (Tuple' Nothing r1) arr =
156+ let len = MArray.byteLength arr
157+ in if len >= n
158+ then do
159+ r <- step1 r1 arr
160+ case r of
161+ FL.Done _ -> return $ FL.Done ()
162+ FL.Partial s -> do
163+ extract1 s
164+ res <- initial1
165+ return $ first (Tuple' Nothing) res
166+ else return $ FL.Partial $ Tuple' (Just arr) r1
167+
168+ step (Tuple' (Just buf) r1) arr = do
169+ let len = MArray.byteLength buf + MArray.byteLength arr
170+ buf' <- if MArray.byteCapacity buf < len
171+ then liftIO $ MArray.realloc (max n len) buf
172+ else return buf
173+ buf'' <- MArray.splice buf' arr
174+
175+ -- XXX this is common in both the equations of step
176+ if len >= n
177+ then do
178+ r <- step1 r1 buf''
179+ case r of
180+ FL.Done _ -> return $ FL.Done ()
181+ FL.Partial s -> do
182+ extract1 s
183+ res <- initial1
184+ return $ first (Tuple' Nothing) res
185+ else return $ FL.Partial $ Tuple' (Just buf'') r1
186+
187+-- XXX Same as compactLE, to be removed once that is implemented.
188+--
189+-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
190+-- maximum specified size in bytes.
191+--
192+-- /Internal/
193+{-# INLINE compact #-}
194+compact :: (MonadIO m, Unbox a)
195+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
196+compact = packArraysChunksOf
197+
198+-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
199+-- maximum specified size. Note that if a single array is bigger than the
200+-- specified size we do not split it to fit. When we coalesce multiple arrays
201+-- if the size would exceed the specified size we do not coalesce therefore the
202+-- actual array size may be less than the specified chunk size.
203+--
204+-- /Internal/
205+{-# INLINE_NORMAL compactLEParserD #-}
206+compactLEParserD ::
207+ forall m a. (MonadIO m, Unbox a)
208+ => Int -> ParserD.Parser (MutArray a) m (MutArray a)
209+compactLEParserD n = ParserD.Parser step initial extract
210+
211+ where
212+
213+ nBytes = n * SIZE_OF(a)
214+
215+ initial =
216+ return
217+ $ if n <= 0
218+ then error
219+ $ functionPath
220+ ++ ": the size of arrays ["
221+ ++ show n ++ "] must be a natural number"
222+ else ParserD.IPartial Nothing
223+
224+ step Nothing arr =
225+ return
226+ $ let len = MArray.byteLength arr
227+ in if len >= nBytes
228+ then ParserD.Done 0 arr
229+ else ParserD.Partial 0 (Just arr)
230+ step (Just buf) arr =
231+ let len = MArray.byteLength buf + MArray.byteLength arr
232+ in if len > nBytes
233+ then return $ ParserD.Done 1 buf
234+ else do
235+ buf1 <-
236+ if MArray.byteCapacity buf < nBytes
237+ then liftIO $ MArray.realloc nBytes buf
238+ else return buf
239+ buf2 <- MArray.splice buf1 arr
240+ return $ ParserD.Partial 0 (Just buf2)
241+
242+ extract Nothing = return $ ParserD.Done 0 MArray.nil
243+ extract (Just buf) = return $ ParserD.Done 0 buf
244+
245+ functionPath =
246+ "Streamly.Internal.Data.Stream.MutChunked.compactLEParserD"
247+
248+-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
249+-- minimum specified size. Note that if all the arrays in the stream together
250+-- are smaller than the specified size the resulting array will be smaller than
251+-- the specified size. When we coalesce multiple arrays if the size would exceed
252+-- the specified size we stop coalescing further.
253+--
254+-- /Internal/
255+{-# INLINE_NORMAL compactGEFold #-}
256+compactGEFold ::
257+ forall m a. (MonadIO m, Unbox a)
258+ => Int -> FL.Fold m (MutArray a) (MutArray a)
259+compactGEFold n = Fold step initial extract
260+
261+ where
262+
263+ nBytes = n * SIZE_OF(a)
264+
265+ initial =
266+ return
267+ $ if n < 0
268+ then error
269+ $ functionPath
270+ ++ ": the size of arrays ["
271+ ++ show n ++ "] must be a natural number"
272+ else FL.Partial Nothing
273+
274+ step Nothing arr =
275+ return
276+ $ let len = MArray.byteLength arr
277+ in if len >= nBytes
278+ then FL.Done arr
279+ else FL.Partial (Just arr)
280+ step (Just buf) arr = do
281+ let len = MArray.byteLength buf + MArray.byteLength arr
282+ buf1 <-
283+ if MArray.byteCapacity buf < len
284+ then liftIO $ MArray.realloc (max len nBytes) buf
285+ else return buf
286+ buf2 <- MArray.splice buf1 arr
287+ if len >= n
288+ then return $ FL.Done buf2
289+ else return $ FL.Partial (Just buf2)
290+
291+ extract Nothing = return MArray.nil
292+ extract (Just buf) = return buf
293+
294+ functionPath =
295+ "Streamly.Internal.Data.Stream.MutChunked.compactGEFold"
296+
297+-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
298+-- maximum specified size in bytes.
299+--
300+-- /Internal/
301+compactLE :: (MonadIO m, Unbox a) =>
302+ Int -> Stream m (MutArray a) -> Stream m (Either ParseError (MutArray a))
303+compactLE n = D.parseManyD (compactLEParserD n)
304+
305+-- | Like 'compactLE' but generates arrays of exactly equal to the size
306+-- specified except for the last array in the stream which could be shorter.
307+--
308+-- /Unimplemented/
309+{-# INLINE compactEQ #-}
310+compactEQ :: -- (MonadIO m, Unbox a) =>
311+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
312+compactEQ _n _xs = undefined
313+ -- IsStream.fromStreamD $ D.foldMany (compactEQFold n) (IsStream.toStreamD xs)
314+
315+-- | Like 'compactLE' but generates arrays of size greater than or equal to the
316+-- specified except for the last array in the stream which could be shorter.
317+--
318+-- /Internal/
319+{-# INLINE compactGE #-}
320+compactGE ::
321+ (MonadIO m, Unbox a)
322+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
323+compactGE n = D.foldMany (compactGEFold n)
core/src/Streamly/Internal/Data/Stream/Nesting.hs+202−86
@@ -55,6 +55,11 @@ 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+
58 -- *** Merging
63 -- *** Merging
59 -- | Interleave elements from two streams based on a condition.
64 -- | Interleave elements from two streams based on a condition.
60 , mergeBy
65 , mergeBy
@@ -71,10 +76,17 @@ module Streamly.Internal.Data.Stream.Nesting
71 -- unfoldMany: Unfold m a b -> t m a -> t m b
76 -- unfoldMany: Unfold m a b -> t m a -> t m b
72 -- @
77 -- @
73
78
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+
74 -- *** ConcatUnfold
85 -- *** ConcatUnfold
75 -- | Generate streams by using an unfold on each element of an input
86 -- | Generate streams by using an unfold on each element of an input
76 -- stream, append the resulting streams and flatten. A special case of
87 -- stream, append the resulting streams and flatten. A special case of
77 -- gintercalate.
88 -- gintercalate.
89+ , unfoldMany
78 , ConcatUnfoldInterleaveState (..)
90 , ConcatUnfoldInterleaveState (..)
79 , unfoldInterleave
91 , unfoldInterleave
80 , unfoldRoundRobin
92 , unfoldRoundRobin
@@ -106,8 +118,11 @@ module Streamly.Internal.Data.Stream.Nesting
106
118
107 -- ** Folding
119 -- ** Folding
108 -- | Apply folds on a stream.
120 -- | Apply folds on a stream.
121+ , foldMany
122+ , refoldMany
109 , foldSequence
123 , foldSequence
110 , foldIterateM
124 , foldIterateM
125+ , refoldIterateM
111
126
112 -- ** Parsing
127 -- ** Parsing
113 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
128 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
@@ -124,6 +139,7 @@ module Streamly.Internal.Data.Stream.Nesting
124
139
125 -- ** Grouping
140 -- ** Grouping
126 -- | Group segments of a stream and fold. Special case of parsing.
141 -- | Group segments of a stream and fold. Special case of parsing.
142+ , groupsOf
127 , groupsBy
143 , groupsBy
128 , groupsWhile
144 , groupsWhile
129 , groupsRollingBy
145 , groupsRollingBy
@@ -131,8 +147,9 @@ module Streamly.Internal.Data.Stream.Nesting
131 -- ** Splitting
147 -- ** Splitting
132 -- | A special case of parsing.
148 -- | A special case of parsing.
133 , wordsBy
149 , wordsBy
134− , splitOnSeq -- XXX splitOnSeg
150+ , splitOnSeq
135− , splitOnSuffixSeq -- XXX splitOnSegSuffix, splitOnTrailer
151+ , splitOnSuffixSeq
152+ , sliceOnSuffix
136
153
137 -- XXX Implement these as folds or parsers instead.
154 -- XXX Implement these as folds or parsers instead.
138 , splitOnSuffixSeqAny
155 , splitOnSuffixSeqAny
@@ -141,8 +158,9 @@ module Streamly.Internal.Data.Stream.Nesting
141
158
142 -- * Transform (Nested Containers)
159 -- * Transform (Nested Containers)
143 -- | Opposite to compact in ArrayStream
160 -- | Opposite to compact in ArrayStream
144− , splitInnerBy -- XXX innerSplitOn
161+ , splitInnerBy
145− , splitInnerBySuffix -- XXX innerSplitOnSuffix
162+ , splitInnerBySuffix
163+ , intersectBySorted
146
164
147 -- * Reduce By Streams
165 -- * Reduce By Streams
148 , dropPrefix
166 , dropPrefix
@@ -164,9 +182,12 @@ import Fusion.Plugin.Types (Fuse(..))
164import GHC.Types (SPEC(..))
182import GHC.Types (SPEC(..))
165
183
166import Streamly.Internal.Data.Array.Type (Array(..))
184import Streamly.Internal.Data.Array.Type (Array(..))
185+import Streamly.Internal.Data.Fold.Step (Step(..))
167import Streamly.Internal.Data.Fold.Type (Fold(..))
186import Streamly.Internal.Data.Fold.Type (Fold(..))
168import Streamly.Internal.Data.Parser (ParseError(..))
187import Streamly.Internal.Data.Parser (ParseError(..))
188+import Streamly.Internal.Data.Refold.Type (Refold(..))
169import Streamly.Internal.Data.SVar.Type (adaptState)
189import Streamly.Internal.Data.SVar.Type (adaptState)
190+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
170import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
191import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
171import Streamly.Internal.Data.Unfold.Type (Unfold(..))
192import Streamly.Internal.Data.Unfold.Type (Unfold(..))
172
193
@@ -592,6 +613,49 @@ mergeFstBy :: -- Monad m =>
592mergeFstBy _f _m1 _m2 = undefined
613mergeFstBy _f _m1 _m2 = undefined
593 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
614 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
594
615
616+-------------------------------------------------------------------------------
617+-- Intersection of sorted streams
618+-------------------------------------------------------------------------------
619+
620+-- Assuming the streams are sorted in ascending order
621+{-# INLINE_NORMAL intersectBySorted #-}
622+intersectBySorted :: Monad m
623+ => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
624+intersectBySorted cmp (Stream stepa ta) (Stream stepb tb) =
625+ Stream step
626+ ( ta -- left stream state
627+ , tb -- right stream state
628+ , Nothing -- left value
629+ , Nothing -- right value
630+ )
631+
632+ where
633+
634+ {-# INLINE_LATE step #-}
635+ -- step 1, fetch the first value
636+ step gst (sa, sb, Nothing, b) = do
637+ r <- stepa gst sa
638+ return $ case r of
639+ Yield a sa' -> Skip (sa', sb, Just a, b) -- step 2/3
640+ Skip sa' -> Skip (sa', sb, Nothing, b)
641+ Stop -> Stop
642+
643+ -- step 2, fetch the second value
644+ step gst (sa, sb, a@(Just _), Nothing) = do
645+ r <- stepb gst sb
646+ return $ case r of
647+ Yield b sb' -> Skip (sa, sb', a, Just b) -- step 3
648+ Skip sb' -> Skip (sa, sb', a, Nothing)
649+ Stop -> Stop
650+
651+ -- step 3, compare the two values
652+ step _ (sa, sb, Just a, Just b) = do
653+ let res = cmp a b
654+ return $ case res of
655+ GT -> Skip (sa, sb, Just a, Nothing) -- step 2
656+ LT -> Skip (sa, sb, Nothing, Just b) -- step 1
657+ EQ -> Yield a (sa, sb, Nothing, Just b) -- step 1
658+
595------------------------------------------------------------------------------
659------------------------------------------------------------------------------
596-- Combine N Streams - unfoldMany
660-- Combine N Streams - unfoldMany
597------------------------------------------------------------------------------
661------------------------------------------------------------------------------
@@ -1178,7 +1242,6 @@ foldSequence _f _m = undefined
1178data FIterState s f m a b
1242data FIterState s f m a b
1179 = FIterInit s f
1243 = FIterInit s f
1180 | forall fs. FIterStream s (fs -> a -> m (FL.Step fs b)) fs (fs -> m b)
1244 | forall fs. FIterStream s (fs -> a -> m (FL.Step fs b)) fs (fs -> m b)
1181− (fs -> m b)
1182 | FIterYield b (FIterState s f m a b)
1245 | FIterYield b (FIterState s f m a b)
1183 | FIterStop
1246 | FIterStop
1184
1247
@@ -1206,30 +1269,101 @@ foldIterateM func seed0 (Stream step state) =
1206 where
1269 where
1207
1270
1208 {-# INLINE iterStep #-}
1271 {-# INLINE iterStep #-}
1209− iterStep from st fstep extract final = do
1272+ iterStep from st fstep extract = do
1210 res <- from
1273 res <- from
1211 return
1274 return
1212 $ Skip
1275 $ Skip
1213 $ case res of
1276 $ case res of
1214− FL.Partial fs -> FIterStream st fstep fs extract final
1277+ FL.Partial fs -> FIterStream st fstep fs extract
1215 FL.Done fb -> FIterYield fb $ FIterInit st (return fb)
1278 FL.Done fb -> FIterYield fb $ FIterInit st (return fb)
1216
1279
1217 {-# INLINE_LATE stepOuter #-}
1280 {-# INLINE_LATE stepOuter #-}
1218 stepOuter _ (FIterInit st seed) = do
1281 stepOuter _ (FIterInit st seed) = do
1219− (FL.Fold fstep initial extract final) <- seed >>= func
1282+ (FL.Fold fstep initial extract) <- seed >>= func
1220− iterStep initial st fstep extract final
1283+ iterStep initial st fstep extract
1221− stepOuter gst (FIterStream st fstep fs extract final) = do
1284+ stepOuter gst (FIterStream st fstep fs extract) = do
1222 r <- step (adaptState gst) st
1285 r <- step (adaptState gst) st
1223 case r of
1286 case r of
1224 Yield x s -> do
1287 Yield x s -> do
1225− iterStep (fstep fs x) s fstep extract final
1288+ iterStep (fstep fs x) s fstep extract
1226− Skip s -> return $ Skip $ FIterStream s fstep fs extract final
1289+ Skip s -> return $ Skip $ FIterStream s fstep fs extract
1227 Stop -> do
1290 Stop -> do
1228− b <- final fs
1291+ b <- extract fs
1229 return $ Skip $ FIterYield b FIterStop
1292 return $ Skip $ FIterYield b FIterStop
1230 stepOuter _ (FIterYield a next) = return $ Yield a next
1293 stepOuter _ (FIterYield a next) = return $ Yield a next
1231 stepOuter _ FIterStop = return Stop
1294 stepOuter _ FIterStop = return Stop
1232
1295
1296+{-# ANN type CIterState Fuse #-}
1297+data CIterState s f fs b
1298+ = CIterInit s f
1299+ | CIterConsume s fs
1300+ | CIterYield b (CIterState s f fs b)
1301+ | CIterStop
1302+
1303+-- | Like 'foldIterateM' but using the 'Refold' type instead. This could be
1304+-- much more efficient due to stream fusion.
1305+--
1306+-- /Internal/
1307+{-# INLINE_NORMAL refoldIterateM #-}
1308+refoldIterateM ::
1309+ Monad m => Refold m b a b -> m b -> Stream m a -> Stream m b
1310+refoldIterateM (Refold fstep finject fextract) initial (Stream step state) =
1311+ Stream stepOuter (CIterInit state initial)
1312+
1313+ where
1314+
1315+ {-# INLINE iterStep #-}
1316+ iterStep st action = do
1317+ res <- action
1318+ return
1319+ $ Skip
1320+ $ case res of
1321+ FL.Partial fs -> CIterConsume st fs
1322+ FL.Done fb -> CIterYield fb $ CIterInit st (return fb)
1323+
1324+ {-# INLINE_LATE stepOuter #-}
1325+ stepOuter _ (CIterInit st action) = do
1326+ iterStep st (action >>= finject)
1327+ stepOuter gst (CIterConsume st fs) = do
1328+ r <- step (adaptState gst) st
1329+ case r of
1330+ Yield x s -> iterStep s (fstep fs x)
1331+ Skip s -> return $ Skip $ CIterConsume s fs
1332+ Stop -> do
1333+ b <- fextract fs
1334+ return $ Skip $ CIterYield b CIterStop
1335+ stepOuter _ (CIterYield a next) = return $ Yield a next
1336+ stepOuter _ CIterStop = return Stop
1337+
1338+-- "n" elements at the end are dropped by the fold.
1339+{-# INLINE sliceBy #-}
1340+sliceBy :: Monad m => Fold m a Int -> Int -> Refold m (Int, Int) a (Int, Int)
1341+sliceBy (Fold step1 initial1 extract1) n = Refold step inject extract
1342+
1343+ where
1344+
1345+ inject (i, len) = do
1346+ r <- initial1
1347+ return $ case r of
1348+ Partial s -> Partial $ Tuple' (i + len + n) s
1349+ Done l -> Done (i, l)
1350+
1351+ step (Tuple' i s) x = do
1352+ r <- step1 s x
1353+ return $ case r of
1354+ Partial s1 -> Partial $ Tuple' i s1
1355+ Done len -> Done (i, len)
1356+
1357+ extract (Tuple' i s) = (i,) <$> extract1 s
1358+
1359+{-# INLINE sliceOnSuffix #-}
1360+sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
1361+sliceOnSuffix predicate =
1362+ -- Scan the stream with the given refold
1363+ refoldIterateM
1364+ (sliceBy (FL.takeEndBy_ predicate FL.length) 1)
1365+ (return (-1, 0))
1366+
1233------------------------------------------------------------------------------
1367------------------------------------------------------------------------------
1234-- Parsing
1368-- Parsing
1235------------------------------------------------------------------------------
1369------------------------------------------------------------------------------
@@ -1782,7 +1916,7 @@ groupsWhile :: Monad m
1782{-
1916{-
1783groupsWhile eq fld = parseMany (PRD.groupBy eq fld)
1917groupsWhile eq fld = parseMany (PRD.groupBy eq fld)
1784-}
1918-}
1785−groupsWhile cmp (Fold fstep initial _ final) (Stream step state) =
1919+groupsWhile cmp (Fold fstep initial done) (Stream step state) =
1786 Stream stepOuter (GroupingInit state)
1920 Stream stepOuter (GroupingInit state)
1787
1921
1788 where
1922 where
@@ -1805,7 +1939,7 @@ groupsWhile cmp (Fold fstep initial _ final) (Stream step state) =
1805 FL.Partial fs1 -> go SPEC x s fs1
1939 FL.Partial fs1 -> go SPEC x s fs1
1806 FL.Done b -> return $ Yield b (GroupingInit s)
1940 FL.Done b -> return $ Yield b (GroupingInit s)
1807 Skip s -> return $ Skip $ GroupingDo s fs
1941 Skip s -> return $ Skip $ GroupingDo s fs
1808− Stop -> final fs >> return Stop
1942+ Stop -> return Stop
1809
1943
1810 where
1944 where
1811
1945
@@ -1820,12 +1954,10 @@ groupsWhile cmp (Fold fstep initial _ final) (Stream step state) =
1820 FL.Partial fs1 -> go SPEC prev s fs1
1954 FL.Partial fs1 -> go SPEC prev s fs1
1821 FL.Done b -> return $ Yield b (GroupingInit s)
1955 FL.Done b -> return $ Yield b (GroupingInit s)
1822 else do
1956 else do
1823− r <- final acc
1957+ r <- done acc
1824 return $ Yield r (GroupingInitWith s x)
1958 return $ Yield r (GroupingInitWith s x)
1825 Skip s -> go SPEC prev s acc
1959 Skip s -> go SPEC prev s acc
1826− Stop -> do
1827− r <- final acc
1828− return $ Yield r GroupingDone
1960+ Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1829 stepOuter _ (GroupingInitWith st x) = do
1961 stepOuter _ (GroupingInitWith st x) = do
1830 res <- initial
1962 res <- initial
1831 return
1963 return
@@ -1852,12 +1984,10 @@ groupsWhile cmp (Fold fstep initial _ final) (Stream step state) =
1852 FL.Partial fs1 -> go SPEC s fs1
1984 FL.Partial fs1 -> go SPEC s fs1
1853 FL.Done b -> return $ Yield b (GroupingInit s)
1985 FL.Done b -> return $ Yield b (GroupingInit s)
1854 else do
1986 else do
1855− r <- final acc
1987+ r <- done acc
1856 return $ Yield r (GroupingInitWith s x)
1988 return $ Yield r (GroupingInitWith s x)
1857 Skip s -> go SPEC s acc
1989 Skip s -> go SPEC s acc
1858− Stop -> do
1859− r <- final acc
1860− return $ Yield r GroupingDone
1990+ Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1861 stepOuter _ (GroupingYield _ _) = error "groupsWhile: Unreachable"
1991 stepOuter _ (GroupingYield _ _) = error "groupsWhile: Unreachable"
1862 stepOuter _ GroupingDone = return Stop
1992 stepOuter _ GroupingDone = return Stop
1863
1993
@@ -1879,7 +2009,7 @@ groupsRollingBy :: Monad m
1879{-
2009{-
1880groupsRollingBy eq fld = parseMany (PRD.groupByRolling eq fld)
2010groupsRollingBy eq fld = parseMany (PRD.groupByRolling eq fld)
1881-}
2011-}
1882−groupsRollingBy cmp (Fold fstep initial _ final) (Stream step state) =
2012+groupsRollingBy cmp (Fold fstep initial done) (Stream step state) =
1883 Stream stepOuter (GroupingInit state)
2013 Stream stepOuter (GroupingInit state)
1884
2014
1885 where
2015 where
@@ -1902,7 +2032,7 @@ groupsRollingBy cmp (Fold fstep initial _ final) (Stream step state) =
1902 FL.Partial fs1 -> go SPEC x s fs1
2032 FL.Partial fs1 -> go SPEC x s fs1
1903 FL.Done fb -> return $ Yield fb (GroupingInit s)
2033 FL.Done fb -> return $ Yield fb (GroupingInit s)
1904 Skip s -> return $ Skip $ GroupingDo s fs
2034 Skip s -> return $ Skip $ GroupingDo s fs
1905− Stop -> final fs >> return Stop
2035+ Stop -> return Stop
1906
2036
1907 where
2037 where
1908
2038
@@ -1917,12 +2047,10 @@ groupsRollingBy cmp (Fold fstep initial _ final) (Stream step state) =
1917 FL.Partial fs1 -> go SPEC x s fs1
2047 FL.Partial fs1 -> go SPEC x s fs1
1918 FL.Done b -> return $ Yield b (GroupingInit s)
2048 FL.Done b -> return $ Yield b (GroupingInit s)
1919 else do
2049 else do
1920− r <- final acc
2050+ r <- done acc
1921 return $ Yield r (GroupingInitWith s x)
2051 return $ Yield r (GroupingInitWith s x)
1922 Skip s -> go SPEC prev s acc
2052 Skip s -> go SPEC prev s acc
1923− Stop -> do
1924− r <- final acc
1925− return $ Yield r GroupingDone
2053+ Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1926 stepOuter _ (GroupingInitWith st x) = do
2054 stepOuter _ (GroupingInitWith st x) = do
1927 res <- initial
2055 res <- initial
1928 return
2056 return
@@ -1953,7 +2081,7 @@ groupsRollingBy cmp (Fold fstep initial _ final) (Stream step state) =
1953 FL.Done b -> return $ Yield b (GroupingInit st)
2081 FL.Done b -> return $ Yield b (GroupingInit st)
1954 else do
2082 else do
1955 {-
2083 {-
1956− r <- final acc
2084+ r <- done acc
1957 return $ Yield r (GroupingInitWith s x)
2085 return $ Yield r (GroupingInitWith s x)
1958 -}
2086 -}
1959 -- The code above does not let groupBy fuse. We use the
2087 -- The code above does not let groupBy fuse. We use the
@@ -1962,16 +2090,14 @@ groupsRollingBy cmp (Fold fstep initial _ final) (Stream step state) =
1962 -- GroupingInitWith state here to help GHC with stream
2090 -- GroupingInitWith state here to help GHC with stream
1963 -- fusion.
2091 -- fusion.
1964 result <- initial
2092 result <- initial
1965− r <- final acc
2093+ r <- done acc
1966 return
2094 return
1967 $ Yield r
2095 $ Yield r
1968 $ case result of
2096 $ case result of
1969 FL.Partial fsi -> GroupingDoWith s fsi x
2097 FL.Partial fsi -> GroupingDoWith s fsi x
1970 FL.Done b -> GroupingYield b (GroupingInit s)
2098 FL.Done b -> GroupingYield b (GroupingInit s)
1971 Skip s -> go SPEC prev s acc
2099 Skip s -> go SPEC prev s acc
1972− Stop -> do
1973− r <- final acc
1974− return $ Yield r GroupingDone
2100+ Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1975 stepOuter _ (GroupingYield r next) = return $ Yield r next
2101 stepOuter _ (GroupingYield r next) = return $ Yield r next
1976 stepOuter _ GroupingDone = return Stop
2102 stepOuter _ GroupingDone = return Stop
1977
2103
@@ -1993,7 +2119,7 @@ data WordsByState st fs b
1993
2119
1994{-# INLINE_NORMAL wordsBy #-}
2120{-# INLINE_NORMAL wordsBy #-}
1995wordsBy :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
2121wordsBy :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
1996−wordsBy predicate (Fold fstep initial _ final) (Stream step state) =
2122+wordsBy predicate (Fold fstep initial done) (Stream step state) =
1997 Stream stepOuter (WordsByInit state)
2123 Stream stepOuter (WordsByInit state)
1998
2124
1999 where
2125 where
@@ -2023,7 +2149,7 @@ wordsBy predicate (Fold fstep initial _ final) (Stream step state) =
2023 FL.Partial fs1 -> go SPEC s fs1
2149 FL.Partial fs1 -> go SPEC s fs1
2024 FL.Done b -> return $ Yield b (WordsByInit s)
2150 FL.Done b -> return $ Yield b (WordsByInit s)
2025 Skip s -> return $ Skip $ WordsByDo s fs
2151 Skip s -> return $ Skip $ WordsByDo s fs
2026− Stop -> final fs >> return Stop
2152+ Stop -> return Stop
2027
2153
2028 where
2154 where
2029
2155
@@ -2034,7 +2160,7 @@ wordsBy predicate (Fold fstep initial _ final) (Stream step state) =
2034 if predicate x
2160 if predicate x
2035 then do
2161 then do
2036 {-
2162 {-
2037− r <- final acc
2163+ r <- done acc
2038 return $ Yield r (WordsByInit s)
2164 return $ Yield r (WordsByInit s)
2039 -}
2165 -}
2040 -- The above code does not fuse well. Need to check why
2166 -- The above code does not fuse well. Need to check why
@@ -2043,7 +2169,7 @@ wordsBy predicate (Fold fstep initial _ final) (Stream step state) =
2043 -- state always, we directly go to WordsByDo state in
2169 -- state always, we directly go to WordsByDo state in
2044 -- the common case of Partial.
2170 -- the common case of Partial.
2045 resi <- initial
2171 resi <- initial
2046− r <- final acc
2172+ r <- done acc
2047 return
2173 return
2048 $ Yield r
2174 $ Yield r
2049 $ case resi of
2175 $ case resi of
@@ -2055,9 +2181,7 @@ wordsBy predicate (Fold fstep initial _ final) (Stream step state) =
2055 FL.Partial fs1 -> go SPEC s fs1
2181 FL.Partial fs1 -> go SPEC s fs1
2056 FL.Done b -> return $ Yield b (WordsByInit s)
2182 FL.Done b -> return $ Yield b (WordsByInit s)
2057 Skip s -> go SPEC s acc
2183 Skip s -> go SPEC s acc
2058− Stop -> do
2059− r <- final acc
2060− return $ Yield r WordsByDone
2184+ Stop -> done acc >>= \r -> return $ Yield r WordsByDone
2061
2185
2062 stepOuter _ WordsByDone = return Stop
2186 stepOuter _ WordsByDone = return Stop
2063
2187
@@ -2115,7 +2239,7 @@ splitOnSeq
2115 -> Fold m a b
2239 -> Fold m a b
2116 -> Stream m a
2240 -> Stream m a
2117 -> Stream m b
2241 -> Stream m b
2118−splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2242+splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2119 Stream stepOuter SplitOnSeqInit
2243 Stream stepOuter SplitOnSeqInit
2120
2244
2121 where
2245 where
@@ -2198,12 +2322,12 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2198 r <- fstep acc x
2322 r <- fstep acc x
2199 b1 <-
2323 b1 <-
2200 case r of
2324 case r of
2201− FL.Partial acc1 -> final acc1
2325+ FL.Partial acc1 -> done acc1
2202 FL.Done b -> return b
2326 FL.Done b -> return b
2203 let jump c = SplitOnSeqEmpty c s
2327 let jump c = SplitOnSeqEmpty c s
2204 in yieldProceed jump b1
2328 in yieldProceed jump b1
2205 Skip s -> skip (SplitOnSeqEmpty acc s)
2329 Skip s -> skip (SplitOnSeqEmpty acc s)
2206− Stop -> final acc >> return Stop
2330+ Stop -> return Stop
2207
2331
2208 -----------------
2332 -----------------
2209 -- Done
2333 -- Done
@@ -2221,7 +2345,7 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2221 Yield x s -> do
2345 Yield x s -> do
2222 let jump c = SplitOnSeqSingle c s pat
2346 let jump c = SplitOnSeqSingle c s pat
2223 if pat == x
2347 if pat == x
2224− then final fs >>= yieldProceed jump
2348+ then done fs >>= yieldProceed jump
2225 else do
2349 else do
2226 r <- fstep fs x
2350 r <- fstep fs x
2227 case r of
2351 case r of
@@ -2229,7 +2353,7 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2229 FL.Done b -> yieldProceed jump b
2353 FL.Done b -> yieldProceed jump b
2230 Skip s -> return $ Skip $ SplitOnSeqSingle fs s pat
2354 Skip s -> return $ Skip $ SplitOnSeqSingle fs s pat
2231 Stop -> do
2355 Stop -> do
2232− r <- final fs
2356+ r <- done fs
2233 return $ Skip $ SplitOnSeqYield r SplitOnSeqDone
2357 return $ Skip $ SplitOnSeqYield r SplitOnSeqDone
2234
2358
2235 ---------------------------
2359 ---------------------------
@@ -2237,7 +2361,7 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2237 ---------------------------
2361 ---------------------------
2238
2362
2239 stepOuter _ (SplitOnSeqWordDone 0 fs _) = do
2363 stepOuter _ (SplitOnSeqWordDone 0 fs _) = do
2240− r <- final fs
2364+ r <- done fs
2241 skip $ SplitOnSeqYield r SplitOnSeqDone
2365 skip $ SplitOnSeqYield r SplitOnSeqDone
2242 stepOuter _ (SplitOnSeqWordDone n fs wrd) = do
2366 stepOuter _ (SplitOnSeqWordDone n fs wrd) = do
2243 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
2367 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
@@ -2264,7 +2388,7 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2264 if wrd1 .&. wordMask == wordPat
2388 if wrd1 .&. wordMask == wordPat
2265 then do
2389 then do
2266 let jump c = SplitOnSeqWordInit c s
2390 let jump c = SplitOnSeqWordInit c s
2267− final fs >>= yieldProceed jump
2391+ done fs >>= yieldProceed jump
2268 else skip $ SplitOnSeqWordLoop wrd1 s fs
2392 else skip $ SplitOnSeqWordLoop wrd1 s fs
2269 else go SPEC (idx + 1) wrd1 s
2393 else go SPEC (idx + 1) wrd1 s
2270 Skip s -> go SPEC idx wrd s
2394 Skip s -> go SPEC idx wrd s
@@ -2272,7 +2396,7 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2272 if idx /= 0
2396 if idx /= 0
2273 then skip $ SplitOnSeqWordDone idx fs wrd
2397 then skip $ SplitOnSeqWordDone idx fs wrd
2274 else do
2398 else do
2275− r <- final fs
2399+ r <- done fs
2276 skip $ SplitOnSeqYield r SplitOnSeqDone
2400 skip $ SplitOnSeqYield r SplitOnSeqDone
2277
2401
2278 stepOuter gst (SplitOnSeqWordLoop wrd0 st0 fs0) =
2402 stepOuter gst (SplitOnSeqWordLoop wrd0 st0 fs0) =
@@ -2293,7 +2417,7 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2293 case r of
2417 case r of
2294 FL.Partial fs1 -> do
2418 FL.Partial fs1 -> do
2295 if wrd1 .&. wordMask == wordPat
2419 if wrd1 .&. wordMask == wordPat
2296− then final fs1 >>= yieldProceed jump
2420+ then done fs1 >>= yieldProceed jump
2297 else go SPEC wrd1 s fs1
2421 else go SPEC wrd1 s fs1
2298 FL.Done b -> yieldProceed jump b
2422 FL.Done b -> yieldProceed jump b
2299 Skip s -> go SPEC wrd s fs
2423 Skip s -> go SPEC wrd s fs
@@ -2378,14 +2502,14 @@ splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2378 stepOuter _ (SplitOnSeqKRCheck fs st rb rh) = do
2502 stepOuter _ (SplitOnSeqKRCheck fs st rb rh) = do
2379 if RB.unsafeEqArray rb rh patArr
2503 if RB.unsafeEqArray rb rh patArr
2380 then do
2504 then do
2381− r <- final fs
2505+ r <- done fs
2382 let rst = RB.startOf rb
2506 let rst = RB.startOf rb
2383 jump c = SplitOnSeqKRInit 0 c st rb rst
2507 jump c = SplitOnSeqKRInit 0 c st rb rst
2384 yieldProceed jump r
2508 yieldProceed jump r
2385 else skip $ SplitOnSeqKRLoop fs st rb rh patHash
2509 else skip $ SplitOnSeqKRLoop fs st rb rh patHash
2386
2510
2387 stepOuter _ (SplitOnSeqKRDone 0 fs _ _) = do
2511 stepOuter _ (SplitOnSeqKRDone 0 fs _ _) = do
2388− r <- final fs
2512+ r <- done fs
2389 skip $ SplitOnSeqYield r SplitOnSeqDone
2513 skip $ SplitOnSeqYield r SplitOnSeqDone
2390 stepOuter _ (SplitOnSeqKRDone n fs rb rh) = do
2514 stepOuter _ (SplitOnSeqKRDone n fs rb rh) = do
2391 old <- liftIO $ peek rh
2515 old <- liftIO $ peek rh
@@ -2429,7 +2553,7 @@ splitOnSuffixSeq
2429 -> Fold m a b
2553 -> Fold m a b
2430 -> Stream m a
2554 -> Stream m a
2431 -> Stream m b
2555 -> Stream m b
2432−splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state) =
2556+splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2433 Stream stepOuter SplitOnSuffixSeqInit
2557 Stream stepOuter SplitOnSuffixSeqInit
2434
2558
2435 where
2559 where
@@ -2469,7 +2593,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2469 r <- if withSep then fstep fs x else return $ FL.Partial fs
2593 r <- if withSep then fstep fs x else return $ FL.Partial fs
2470 b1 <-
2594 b1 <-
2471 case r of
2595 case r of
2472− FL.Partial fs1 -> final fs1
2596+ FL.Partial fs1 -> done fs1
2473 FL.Done b -> return b
2597 FL.Done b -> return b
2474 yieldProceed jump b1
2598 yieldProceed jump b1
2475 else do
2599 else do
@@ -2532,11 +2656,11 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2532 r <- fstep acc x
2656 r <- fstep acc x
2533 b1 <-
2657 b1 <-
2534 case r of
2658 case r of
2535− FL.Partial fs -> final fs
2659+ FL.Partial fs -> done fs
2536 FL.Done b -> return b
2660 FL.Done b -> return b
2537 yieldProceed jump b1
2661 yieldProceed jump b1
2538 Skip s -> skip (SplitOnSuffixSeqEmpty acc s)
2662 Skip s -> skip (SplitOnSuffixSeqEmpty acc s)
2539− Stop -> final acc >> return Stop
2663+ Stop -> return Stop
2540
2664
2541 -----------------
2665 -----------------
2542 -- Done
2666 -- Done
@@ -2553,7 +2677,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2553 case res of
2677 case res of
2554 Yield x s -> processYieldSingle pat x s fs
2678 Yield x s -> processYieldSingle pat x s fs
2555 Skip s -> skip $ SplitOnSuffixSeqSingleInit fs s pat
2679 Skip s -> skip $ SplitOnSuffixSeqSingleInit fs s pat
2556− Stop -> final fs >> return Stop
2680+ Stop -> return Stop
2557
2681
2558 stepOuter gst (SplitOnSuffixSeqSingle fs st pat) = do
2682 stepOuter gst (SplitOnSuffixSeqSingle fs st pat) = do
2559 res <- step (adaptState gst) st
2683 res <- step (adaptState gst) st
@@ -2561,7 +2685,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2561 Yield x s -> processYieldSingle pat x s fs
2685 Yield x s -> processYieldSingle pat x s fs
2562 Skip s -> skip $ SplitOnSuffixSeqSingle fs s pat
2686 Skip s -> skip $ SplitOnSuffixSeqSingle fs s pat
2563 Stop -> do
2687 Stop -> do
2564− r <- final fs
2688+ r <- done fs
2565 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2689 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2566
2690
2567 ---------------------------
2691 ---------------------------
@@ -2569,7 +2693,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2569 ---------------------------
2693 ---------------------------
2570
2694
2571 stepOuter _ (SplitOnSuffixSeqWordDone 0 fs _) = do
2695 stepOuter _ (SplitOnSuffixSeqWordDone 0 fs _) = do
2572− r <- final fs
2696+ r <- done fs
2573 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2697 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2574 stepOuter _ (SplitOnSuffixSeqWordDone n fs wrd) = do
2698 stepOuter _ (SplitOnSuffixSeqWordDone n fs wrd) = do
2575 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
2699 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
@@ -2592,7 +2716,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2592 let jump c = SplitOnSuffixSeqWordInit c s
2716 let jump c = SplitOnSuffixSeqWordInit c s
2593 yieldProceed jump b
2717 yieldProceed jump b
2594 Skip s -> skip (SplitOnSuffixSeqWordInit fs0 s)
2718 Skip s -> skip (SplitOnSuffixSeqWordInit fs0 s)
2595− Stop -> final fs0 >> return Stop
2719+ Stop -> return Stop
2596
2720
2597 where
2721 where
2598
2722
@@ -2610,7 +2734,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2610 then go SPEC (idx + 1) wrd1 s fs1
2734 then go SPEC (idx + 1) wrd1 s fs1
2611 else if wrd1 .&. wordMask /= wordPat
2735 else if wrd1 .&. wordMask /= wordPat
2612 then skip $ SplitOnSuffixSeqWordLoop wrd1 s fs1
2736 then skip $ SplitOnSuffixSeqWordLoop wrd1 s fs1
2613− else do final fs >>= yieldProceed jump
2737+ else do done fs >>= yieldProceed jump
2614 FL.Done b -> yieldProceed jump b
2738 FL.Done b -> yieldProceed jump b
2615 Skip s -> go SPEC idx wrd s fs
2739 Skip s -> go SPEC idx wrd s fs
2616 Stop -> skip $ SplitOnSuffixSeqWordDone idx fs wrd
2740 Stop -> skip $ SplitOnSuffixSeqWordDone idx fs wrd
@@ -2636,16 +2760,16 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2636 case r of
2760 case r of
2637 FL.Partial fs1 ->
2761 FL.Partial fs1 ->
2638 if wrd1 .&. wordMask == wordPat
2762 if wrd1 .&. wordMask == wordPat
2639− then final fs1 >>= yieldProceed jump
2763+ then done fs1 >>= yieldProceed jump
2640 else go SPEC wrd1 s fs1
2764 else go SPEC wrd1 s fs1
2641 FL.Done b -> yieldProceed jump b
2765 FL.Done b -> yieldProceed jump b
2642 Skip s -> go SPEC wrd s fs
2766 Skip s -> go SPEC wrd s fs
2643 Stop ->
2767 Stop ->
2644 if wrd .&. wordMask == wordPat
2768 if wrd .&. wordMask == wordPat
2645− then final fs >> return Stop
2769+ then return Stop
2646 else if withSep
2770 else if withSep
2647 then do
2771 then do
2648− r <- final fs
2772+ r <- done fs
2649 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2773 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2650 else skip $ SplitOnSuffixSeqWordDone patLen fs wrd
2774 else skip $ SplitOnSuffixSeqWordDone patLen fs wrd
2651
2775
@@ -2667,7 +2791,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2667 jump c = SplitOnSuffixSeqKRInit 0 c s rb rst
2791 jump c = SplitOnSuffixSeqKRInit 0 c s rb rst
2668 yieldProceed jump b
2792 yieldProceed jump b
2669 Skip s -> skip $ SplitOnSuffixSeqKRInit idx0 fs s rb rh0
2793 Skip s -> skip $ SplitOnSuffixSeqKRInit idx0 fs s rb rh0
2670− Stop -> final fs >> return Stop
2794+ Stop -> return Stop
2671
2795
2672 stepOuter gst (SplitOnSuffixSeqKRInit1 fs0 st0 rb rh0) = do
2796 stepOuter gst (SplitOnSuffixSeqKRInit1 fs0 st0 rb rh0) = do
2673 go SPEC 1 rh0 st0 fs0
2797 go SPEC 1 rh0 st0 fs0
@@ -2699,10 +2823,10 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2699 Stop -> do
2823 Stop -> do
2700 -- do not issue a blank segment when we end at pattern
2824 -- do not issue a blank segment when we end at pattern
2701 if (idx == maxIndex) && RB.unsafeEqArray rb rh patArr
2825 if (idx == maxIndex) && RB.unsafeEqArray rb rh patArr
2702− then final fs >> return Stop
2826+ then return Stop
2703 else if withSep
2827 else if withSep
2704 then do
2828 then do
2705− r <- final fs
2829+ r <- done fs
2706 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2830 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2707 else skip $ SplitOnSuffixSeqKRDone idx fs rb (RB.startOf rb)
2831 else skip $ SplitOnSuffixSeqKRDone idx fs rb (RB.startOf rb)
2708
2832
@@ -2731,24 +2855,24 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state)
2731 Skip s -> go SPEC fs s rh cksum
2855 Skip s -> go SPEC fs s rh cksum
2732 Stop ->
2856 Stop ->
2733 if RB.unsafeEqArray rb rh patArr
2857 if RB.unsafeEqArray rb rh patArr
2734− then final fs >> return Stop
2858+ then return Stop
2735 else if withSep
2859 else if withSep
2736 then do
2860 then do
2737− r <- final fs
2861+ r <- done fs
2738 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2862 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2739 else skip $ SplitOnSuffixSeqKRDone patLen fs rb rh
2863 else skip $ SplitOnSuffixSeqKRDone patLen fs rb rh
2740
2864
2741 stepOuter _ (SplitOnSuffixSeqKRCheck fs st rb rh) = do
2865 stepOuter _ (SplitOnSuffixSeqKRCheck fs st rb rh) = do
2742 if RB.unsafeEqArray rb rh patArr
2866 if RB.unsafeEqArray rb rh patArr
2743 then do
2867 then do
2744− r <- final fs
2868+ r <- done fs
2745 let rst = RB.startOf rb
2869 let rst = RB.startOf rb
2746 jump c = SplitOnSuffixSeqKRInit 0 c st rb rst
2870 jump c = SplitOnSuffixSeqKRInit 0 c st rb rst
2747 yieldProceed jump r
2871 yieldProceed jump r
2748 else skip $ SplitOnSuffixSeqKRLoop fs st rb rh patHash
2872 else skip $ SplitOnSuffixSeqKRLoop fs st rb rh patHash
2749
2873
2750 stepOuter _ (SplitOnSuffixSeqKRDone 0 fs _ _) = do
2874 stepOuter _ (SplitOnSuffixSeqKRDone 0 fs _ _) = do
2751− r <- final fs
2875+ r <- done fs
2752 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2876 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2753 stepOuter _ (SplitOnSuffixSeqKRDone n fs rb rh) = do
2877 stepOuter _ (SplitOnSuffixSeqKRDone n fs rb rh) = do
2754 old <- liftIO $ peek rh
2878 old <- liftIO $ peek rh
@@ -2930,13 +3054,12 @@ splitInnerBy splitter joiner (Stream step1 state1) =
2930-- | Performs infix separator style splitting.
3054-- | Performs infix separator style splitting.
2931{-# INLINE_NORMAL splitInnerBySuffix #-}
3055{-# INLINE_NORMAL splitInnerBySuffix #-}
2932splitInnerBySuffix
3056splitInnerBySuffix
2933− :: Monad m
3057+ :: (Monad m, Eq (f a), Monoid (f a))
2934− => (f a -> Bool) -- isEmpty?
2935− -> (f a -> m (f a, Maybe (f a))) -- splitter
3058+ => (f a -> m (f a, Maybe (f a))) -- splitter
2936 -> (f a -> f a -> m (f a)) -- joiner
3059 -> (f a -> f a -> m (f a)) -- joiner
2937 -> Stream m (f a)
3060 -> Stream m (f a)
2938 -> Stream m (f a)
3061 -> Stream m (f a)
2939−splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
3062+splitInnerBySuffix splitter joiner (Stream step1 state1) =
2940 Stream step (SplitInitial state1)
3063 Stream step (SplitInitial state1)
2941
3064
2942 where
3065 where
@@ -2963,11 +3086,10 @@ splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
2963 Nothing -> Skip (SplitBuffering s buf')
3086 Nothing -> Skip (SplitBuffering s buf')
2964 Just x2 -> Skip (SplitYielding buf' (SplitSplitting s x2))
3087 Just x2 -> Skip (SplitYielding buf' (SplitSplitting s x2))
2965 Skip s -> return $ Skip (SplitBuffering s buf)
3088 Skip s -> return $ Skip (SplitBuffering s buf)
2966− Stop ->
2967− return $
3089+ Stop -> return $
2968− if isEmpty buf
3090+ if buf == mempty
2969− then Stop
3091+ then Stop
2970− else Skip (SplitYielding buf SplitFinishing)
3092+ else Skip (SplitYielding buf SplitFinishing)
2971
3093
2972 step _ (SplitSplitting st buf) = do
3094 step _ (SplitSplitting st buf) = do
2973 (x1, mx2) <- splitter buf
3095 (x1, mx2) <- splitter buf
@@ -2986,8 +3108,6 @@ splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
2986--
3108--
2987-- Space: @O(1)@
3109-- Space: @O(1)@
2988--
3110--
2989−-- See also stripPrefix.
2990−--
2991-- /Unimplemented/
3111-- /Unimplemented/
2992{-# INLINE dropPrefix #-}
3112{-# INLINE dropPrefix #-}
2993dropPrefix ::
3113dropPrefix ::
@@ -3000,8 +3120,6 @@ dropPrefix = error "Not implemented yet!"
3000--
3120--
3001-- Space: @O(n)@ where n is the length of the infix.
3121-- Space: @O(n)@ where n is the length of the infix.
3002--
3122--
3003−-- See also stripInfix.
3004−--
3005-- /Unimplemented/
3123-- /Unimplemented/
3006{-# INLINE dropInfix #-}
3124{-# INLINE dropInfix #-}
3007dropInfix ::
3125dropInfix ::
@@ -3014,8 +3132,6 @@ dropInfix = error "Not implemented yet!"
3014--
3132--
3015-- Space: @O(n)@ where n is the length of the suffix.
3133-- Space: @O(n)@ where n is the length of the suffix.
3016--
3134--
3017−-- See also stripSuffix.
3018−--
3019-- /Unimplemented/
3135-- /Unimplemented/
3020{-# INLINE dropSuffix #-}
3136{-# INLINE dropSuffix #-}
3021dropSuffix ::
3137dropSuffix ::
core/src/Streamly/Internal/Data/Stream/Top.hs+116−243
@@ -8,73 +8,38 @@
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.
48
11
49module Streamly.Internal.Data.Stream.Top
12module Streamly.Internal.Data.Stream.Top
50 (
13 (
14+ -- * Transformation
51− -- * Sampling
15+ -- ** Sampling
52 -- | Value agnostic filtering.
16 -- | Value agnostic filtering.
53 strideFromThen
17 strideFromThen
54
18
55− -- * Straight Joins
19+ -- * Nesting
20+ -- ** Set like operations
56− -- | These are set-like operations but not exactly set operations because
21+ -- | These are not exactly set operations because streams are not
57− -- streams are not necessarily sets, they may have duplicated elements.
22+ -- necessarily sets, they may have duplicated elements. These operations
58− -- These operations are generic i.e. they work on streams of unconstrained
23+ -- are generic i.e. they work on streams of unconstrained types, therefore,
59− -- types, therefore, they have quadratic performance characterstics. For
24+ -- they have quadratic performance characterstics. For better performance
60− -- better performance using Set or Map structures see the
61− -- Streamly.Internal.Data.Stream.Container module.
25+ -- using Set structures see the Streamly.Internal.Data.Stream.Container
62− , intersectBy
26+ -- module.
63− , deleteFirstsBy
27+ , filterInStreamGenericBy
64− , unionBy
28+ , deleteInStreamGenericBy
65−
29+ , unionWithStreamGenericBy
30+
66− -- Set like operations on sorted streams
31+ -- ** Set like operations on sorted streams
67− , sortedIntersectBy
32+ , filterInStreamAscBy
68− , sortedDeleteFirstsBy
33+ , deleteInStreamAscBy
69− , sortedUnionBy
34+ , unionWithStreamAscBy
70−
35+
71− -- * Cross Joins
36+ -- ** Join operations
72− , innerJoin
37+ , joinInnerGeneric
73−
38+
74− -- Joins on sorted stream
39+ -- * Joins on sorted stream
75− , innerSortedJoin
40+ , joinInnerAscBy
76− , leftSortedJoin
41+ , joinLeftAscBy
77− , outerSortedJoin
42+ , joinOuterAscBy
78 )
43 )
79where
44where
80
45
@@ -83,7 +48,8 @@ where
83import Control.Monad.IO.Class (MonadIO(..))
48import Control.Monad.IO.Class (MonadIO(..))
84import Data.IORef (newIORef, readIORef, modifyIORef')
49import Data.IORef (newIORef, readIORef, modifyIORef')
85import Streamly.Internal.Data.Fold.Type (Fold)
50import Streamly.Internal.Data.Fold.Type (Fold)
86−import Streamly.Internal.Data.Stream.Type (Stream(..), Step(..), cross)
51+import Streamly.Internal.Data.Stream.Common ()
52+import Streamly.Internal.Data.Stream.Type (Stream, cross)
87
53
88import qualified Data.List as List
54import qualified Data.List as List
89import qualified Streamly.Internal.Data.Fold as Fold
55import qualified Streamly.Internal.Data.Fold as Fold
@@ -145,40 +111,29 @@ strideFromThen offset stride =
145-- binary search if we have an Ord instance or Ordering returning function. The
111-- binary search if we have an Ord instance or Ordering returning function. The
146-- time complexity would then become (m x log n).
112-- time complexity would then become (m x log n).
147
113
148−-- | Like 'cross' but emits only those tuples where @a == b@ using the supplied
114+-- | Like 'cross' but emits only those tuples where @a == b@ using the
149−-- equality predicate. This is essentially a @cross intersection@ of two
115+-- supplied equality predicate.
150−-- streams.
151--
116--
152-- Definition:
117-- Definition:
153--
118--
154−-- >>> innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ Stream.cross s1 s2
119+-- >>> joinInnerGeneric 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.
162--
120--
163−-- If you care about performance this function should be your last choice among
121+-- You should almost always prefer @joinInnerOrd@ over 'joinInnerGeneric' if
164−-- all inner joins. 'Streamly.Internal.Data.Unfold.innerJoin' is a much faster
165−-- fused alternative. 'innerSortedJoin' is a faster alternative when streams
166−-- are sorted. 'innerOrdJoin' is an order of magnitude faster alternative when
122+-- possible. @joinInnerOrd@ is an order of magnitude faster but may take more
167−-- the type has an 'Ord' instance.
123+-- space for caching the second stream.
168--
124--
169−-- Note: Conceptually, this is a commutative operation. Result includes all the
125+-- See 'Streamly.Internal.Data.Unfold.joinInnerGeneric' for a much faster fused
170−-- elements from the left and the right stream. The order of streams can be
126+-- alternative.
171−-- changed without affecting results, except for the ordering within the tuple.
172--
127--
173-- Time: O(m x n)
128-- Time: O(m x n)
174--
129--
175-- /Pre-release/
130-- /Pre-release/
176−{-# INLINE innerJoin #-}
131+{-# INLINE joinInnerGeneric #-}
177−innerJoin :: Monad m =>
132+joinInnerGeneric :: Monad m =>
178 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
133 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
179−innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
134+joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
180{-
135{-
181−innerJoin eq s1 s2 = do
136+joinInnerGeneric eq s1 s2 = do
182 -- ConcatMap works faster than bind
137 -- ConcatMap works faster than bind
183 Stream.concatMap (\a ->
138 Stream.concatMap (\a ->
184 Stream.concatMap (\b ->
139 Stream.concatMap (\b ->
@@ -189,44 +144,44 @@ innerJoin eq s1 s2 = do
189 ) s1
144 ) s1
190-}
145-}
191
146
192−-- | A more efficient 'innerJoin' for sorted streams.
147+-- | A more efficient 'joinInner' for sorted streams.
193--
148--
194-- Space: O(1)
149-- Space: O(1)
195--
150--
196-- Time: O(m + n)
151-- Time: O(m + n)
197--
152--
198-- /Unimplemented/
153-- /Unimplemented/
199−{-# INLINE innerSortedJoin #-}
154+{-# INLINE joinInnerAscBy #-}
200−innerSortedJoin ::
155+joinInnerAscBy ::
201 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
156 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
202−innerSortedJoin = undefined
157+joinInnerAscBy = undefined
203
158
204−-- | A more efficient 'leftJoin' for sorted streams.
159+-- | A more efficient 'joinLeft' for sorted streams.
205--
160--
206-- Space: O(1)
161-- Space: O(1)
207--
162--
208-- Time: O(m + n)
163-- Time: O(m + n)
209--
164--
210-- /Unimplemented/
165-- /Unimplemented/
211−{-# INLINE leftSortedJoin #-}
166+{-# INLINE joinLeftAscBy #-}
212−leftSortedJoin :: -- Monad m =>
167+joinLeftAscBy :: -- Monad m =>
213 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
168 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
214−leftSortedJoin _eq _s1 _s2 = undefined
169+joinLeftAscBy _eq _s1 _s2 = undefined
215
170
216−-- | A more efficient 'outerJoin' for sorted streams.
171+-- | A more efficient 'joinOuter' for sorted streams.
217--
172--
218-- Space: O(1)
173-- Space: O(1)
219--
174--
220-- Time: O(m + n)
175-- Time: O(m + n)
221--
176--
222-- /Unimplemented/
177-- /Unimplemented/
223−{-# INLINE outerSortedJoin #-}
178+{-# INLINE joinOuterAscBy #-}
224−outerSortedJoin :: -- Monad m =>
179+joinOuterAscBy :: -- Monad m =>
225 (a -> b -> Ordering)
180 (a -> b -> Ordering)
226 -> Stream m a
181 -> Stream m a
227 -> Stream m b
182 -> Stream m b
228 -> Stream m (Maybe a, Maybe b)
183 -> Stream m (Maybe a, Maybe b)
229−outerSortedJoin _eq _s1 _s2 = undefined
184+joinOuterAscBy _eq _s1 _s2 = undefined
230
185
231------------------------------------------------------------------------------
186------------------------------------------------------------------------------
232-- Set operations (special joins)
187-- Set operations (special joins)
@@ -236,8 +191,8 @@ outerSortedJoin _eq _s1 _s2 = undefined
236-- the best would be to use an Array with linear search. If the second stream
191-- the best would be to use an Array with linear search. If the second stream
237-- is sorted we can also use a binary search, using Ord constraint.
192-- is sorted we can also use a binary search, using Ord constraint.
238
193
239−-- | Keep only those elements in the first stream that are present in the
194+-- | Keep only those elements in the second stream that are present in the
240−-- second stream too. The second stream is folded to a container using the
195+-- first stream too. The first stream is folded to a container using the
241-- supplied fold and then the elements in the container are looked up using the
196-- supplied fold and then the elements in the container are looked up using the
242-- supplied lookup function.
197-- supplied lookup function.
243--
198--
@@ -252,30 +207,23 @@ filterStreamWith :: Monad m =>
252filterStreamWith fld member s1 s2 =
207filterStreamWith fld member s1 s2 =
253 Stream.concatEffect
208 Stream.concatEffect
254 $ do
209 $ do
255− xs <- Stream.fold fld s2
210+ xs <- Stream.fold fld s1
256− return $ Stream.filter (`member` xs) s1
211+ return $ Stream.filter (`member` xs) s2
257−
258−-- XXX instead of folding the second stream to a list we could use it directly.
259−-- If the user wants they can generate the stream from an array and also call
260−-- uniq or nub on it. We can provide a convenience Stream -> Stream to cache
261−-- a finite stream in an array and serve it from the cache. The user can decide
262−-- what is best based on the context. They can also choose to use a boxed or
263−-- unboxed array for caching. To force caching we can make the second stream
264−-- monad type Identity. But that may be less flexible. One option is to use
265−-- cachedIntersectBy etc for automatic caching.
266
212
267−-- | 'intersectBy' returns a subsequence of the first stream which intersects
213+-- | 'filterInStreamGenericBy' retains only those elements in the second stream that
268−-- with the second stream. Note that this is not a commutative operation unlike
214+-- are present in the first stream.
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'.
272--
215--
273−-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.intersectBy (==) (Stream.fromList s1) (Stream.fromList s2)
216+-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [2,1,1,3])
274−-- >>> f [1,3,4,4,5]) [2,3,4,5,5]
217+-- [2,1,1]
275−-- [3,4,4,5]
276--
218--
219+-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [2,1,1,3]) (Stream.fromList [1,2,2,4])
220+-- [1,2,2]
221+--
222+-- Similar to the list intersectBy operation but with the stream argument order
223+-- flipped.
224+--
277−-- First stream can be infinite, the second stream must be finite and must be
225+-- The first stream must be finite and must not block. Second stream is
278−-- capable of multiple evaluations.
226+-- processed only after the first stream is fully realized.
279--
227--
280-- Space: O(n) where @n@ is the number of elements in the second stream.
228-- Space: O(n) where @n@ is the number of elements in the second stream.
281--
229--
@@ -283,87 +231,46 @@ filterStreamWith fld member s1 s2 =
283-- @n@ is the number of elements in the second stream.
231-- @n@ is the number of elements in the second stream.
284--
232--
285-- /Pre-release/
233-- /Pre-release/
286−{-# INLINE intersectBy #-}
234+{-# INLINE filterInStreamGenericBy #-}
287−intersectBy :: Monad m =>
235+filterInStreamGenericBy :: Monad m =>
288 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
236 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
289−intersectBy eq =
237+filterInStreamGenericBy eq =
290 -- XXX Use an (unboxed) array instead.
238 -- XXX Use an (unboxed) array instead.
291 filterStreamWith
239 filterStreamWith
292 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
240 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
293 (List.any . eq)
241 (List.any . eq)
294
242
295−-------------------------------------------------------------------------------
296−-- Intersection of sorted streams
297−-------------------------------------------------------------------------------
298−
299−-- XXX The sort order is not important as long both the streams have the same
300−-- sort order. We need to move only in one direction in each stream.
301−-- XXX Fix the argument order to use the same behavior as intersectBy.
302−
303−-- | Like 'intersectBy' but assumes that the input streams are sorted in
243+-- | Like 'filterInStreamGenericBy' but assumes that the input streams are sorted in
304-- ascending order. To use it on streams sorted in descending order pass an
244-- ascending order. To use it on streams sorted in descending order pass an
305-- inverted comparison function returning GT for less than and LT for greater
245-- inverted comparison function returning GT for less than and LT for greater
306-- than.
246-- than.
307--
247--
308−-- Both streams can be infinite.
309−--
310-- Space: O(1)
248-- Space: O(1)
311--
249--
312-- Time: O(m+n)
250-- Time: O(m+n)
313--
251--
314-- /Pre-release/
252-- /Pre-release/
315−{-# INLINE_NORMAL sortedIntersectBy #-}
253+{-# INLINE filterInStreamAscBy #-}
316−sortedIntersectBy :: Monad m =>
254+filterInStreamAscBy :: Monad m =>
317 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
255 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
318−sortedIntersectBy cmp (Stream stepa ta) (Stream stepb tb) =
256+filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
319− Stream step
320− ( ta -- left stream state
321− , tb -- right stream state
322− , Nothing -- left value
323− , Nothing -- right value
324− )
325−
326− where
327
257
328− {-# INLINE_LATE step #-}
258+-- | Delete all elements of the first stream from the seconds stream. If an
329− -- step 1, fetch the first value
259+-- element occurs multiple times in the first stream as many occurrences of it
330− step gst (sa, sb, Nothing, b) = do
260+-- are deleted from the second stream.
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'.
356--
261--
357−-- >>> f xs ys = Stream.fold Fold.toList $ Stream.deleteFirstsBy (==) (Stream.fromList xs) (Stream.fromList ys)
262+-- >>> Stream.fold Fold.toList $ Stream.deleteInStreamGenericBy (==) (Stream.fromList [1,2,3]) (Stream.fromList [1,2,2])
358−-- >>> f [1,2,2,3,3,5] [1,2,2,3,4]
359−-- [2,3,5]
263+-- [2]
360--
264--
361−-- The following holds:
265+-- The following laws hold:
362--
266--
363−-- > deleteFirstsBy (==) (Stream.nub s2 `append` s1) s2 === s1
267+-- > deleteInStreamGenericBy (==) s1 (s1 `append` s2) === s2
364−-- > deleteFirstsBy (==) (Stream.nub s2 `interleave` s1) s2 === s1
268+-- > deleteInStreamGenericBy (==) s1 (s1 `interleave` s2) === s2
365--
269--
366−-- First stream can be infinite, second stream must be finite.
270+-- Same as the list 'Data.List.//' operation but with argument order flipped.
271+--
272+-- The first stream must be finite and must not block. Second stream is
273+-- processed only after the first stream is fully realized.
367--
274--
368-- Space: O(m) where @m@ is the number of elements in the first stream.
275-- Space: O(m) where @m@ is the number of elements in the first stream.
369--
276--
@@ -371,83 +278,58 @@ sortedIntersectBy cmp (Stream stepa ta) (Stream stepb tb) =
371-- @n@ is the number of elements in the second stream.
278-- @n@ is the number of elements in the second stream.
372--
279--
373-- /Pre-release/
280-- /Pre-release/
374−{-# INLINE deleteFirstsBy #-}
281+{-# INLINE deleteInStreamGenericBy #-}
375−deleteFirstsBy :: Monad m =>
282+deleteInStreamGenericBy :: Monad m =>
376 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
283 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
377−deleteFirstsBy eq s2 s1 =
284+deleteInStreamGenericBy eq s1 s2 =
378− -- XXX s2 can be a sorted mutable array and we can use binary
285+ Stream.concatEffect
379− -- search to find. Mark the element deleted, count the deletions
286+ $ do
380− -- and reconsolidate the array when a min number of elements is
287+ -- This may work well if s1 is small
381− -- deleted.
288+ -- If s1 is big we can go through s1, deleting elements from s2 and
382−
289+ -- not emitting an element if it was successfully deleted from s2.
383− -- XXX Use StreamK or list as second argument instead of Stream to avoid
290+ -- we will need a deleteBy that can return whether the element was
384− -- concatEffect?
291+ -- deleted or not.
385− Stream.concatEffect $ do
386− xs <- Stream.toList s1
292+ xs <- Stream.fold Fold.toList s2
387− -- It reverses the list but that is fine.
293+ let f = Fold.foldl' (flip (List.deleteBy eq)) xs
388− let del x =
294+ fmap Stream.fromList $ Stream.fold f s1
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
403−-- | A more efficient 'deleteFirstsBy' for streams sorted in ascending order.
296+-- | A more efficient 'deleteInStreamGenericBy' for streams sorted in ascending order.
404−--
405−-- Both streams can be infinite.
406--
297--
407-- Space: O(1)
298-- Space: O(1)
408--
299--
409-- /Unimplemented/
300-- /Unimplemented/
410−{-# INLINE sortedDeleteFirstsBy #-}
301+{-# INLINE deleteInStreamAscBy #-}
411−sortedDeleteFirstsBy :: -- (Monad m) =>
302+deleteInStreamAscBy :: -- (Monad m) =>
412 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
303 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
413−sortedDeleteFirstsBy _eq _s1 _s2 = undefined
304+deleteInStreamAscBy _eq _s1 _s2 = undefined
414
305
415-- XXX Remove the MonadIO constraint. We can just cache one stream and then
306-- XXX Remove the MonadIO constraint. We can just cache one stream and then
416-- implement using differenceEqBy.
307-- implement using differenceEqBy.
417
308
418−-- | Returns the first stream appended with those unique elements from the
309+-- | This essentially appends to the second stream all the occurrences of
419−-- second stream that are not already present in the first stream. Note that
310+-- elements in the first stream that are not already present in the second
420−-- this is not a commutative operation unlike a set union, argument order
311+-- stream.
421−-- matters. The behavior is similar to the 'Data.List.unionBy'.
422--
312--
423-- Equivalent to the following except that @s2@ is evaluated only once:
313-- Equivalent to the following except that @s2@ is evaluated only once:
424--
314--
425−-- >>> unionBy eq s1 s2 = s1 `Stream.append` Stream.deleteFirstsBy eq s1 (Stream.nub s2)
315+-- >>> unionWithStreamGenericBy eq s1 s2 = s2 `Stream.append` (Stream.deleteInStreamGenericBy eq s2 s1)
426--
316--
427-- Example:
317-- Example:
428--
318--
429−-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.unionBy (==) (Stream.fromList s1) (Stream.fromList s2)
319+-- >>> Stream.fold Fold.toList $ Stream.unionWithStreamGenericBy (==) (Stream.fromList [1,1,2,3]) (Stream.fromList [1,2,2,4])
430−-- >>> f [1,2,2,4] [1,1,2,3,3]
431-- [1,2,2,4,3]
320-- [1,2,2,4,3]
432--
321--
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−--
438-- Space: O(n)
322-- Space: O(n)
439--
323--
440-- Time: O(m x n)
324-- Time: O(m x n)
441--
325--
442-- /Pre-release/
326-- /Pre-release/
443−{-# INLINE unionBy #-}
327+{-# INLINE unionWithStreamGenericBy #-}
444−unionBy :: MonadIO m =>
328+unionWithStreamGenericBy :: MonadIO m =>
445 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
329 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
446−unionBy eq s2 s1 =
330+unionWithStreamGenericBy eq s1 s2 =
447 Stream.concatEffect
331 Stream.concatEffect
448 $ do
332 $ 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.
451 xs <- Stream.fold Fold.toList s1
333 xs <- Stream.fold Fold.toList s1
452 -- XXX we can use postscanlMAfter' instead of IORef
334 -- XXX we can use postscanlMAfter' instead of IORef
453 ref <- liftIO $ newIORef $! List.nubBy eq xs
335 ref <- liftIO $ newIORef $! List.nubBy eq xs
@@ -460,21 +342,12 @@ unionBy eq s2 s1 =
460 return $ Stream.fromList xs1
342 return $ Stream.fromList xs1
461 return $ Stream.mapM f s2 `Stream.append` s3
343 return $ Stream.mapM f s2 `Stream.append` s3
462
344
463−-- | A more efficient 'unionBy' for sorted streams.
345+-- | A more efficient 'unionWithStreamGenericBy' 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.
471--
346--
472-- Space: O(1)
347-- Space: O(1)
473--
348--
474−-- Both streams can be infinite.
475−--
476-- /Unimplemented/
349-- /Unimplemented/
477−{-# INLINE sortedUnionBy #-}
350+{-# INLINE unionWithStreamAscBy #-}
478−sortedUnionBy :: -- (Monad m) =>
351+unionWithStreamAscBy :: -- (Monad m) =>
479 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
352 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
480−sortedUnionBy _eq _s1 _s2 = undefined
353+unionWithStreamAscBy _eq _s1 _s2 = undefined
core/src/Streamly/Internal/Data/Stream/Transform.hs+35−61
@@ -21,6 +21,8 @@ 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
24 , sequence
26 , sequence
25
27
26 -- * Mapping Effects
28 -- * Mapping Effects
@@ -73,7 +75,7 @@ module Streamly.Internal.Data.Stream.Transform
73 , scanMaybe
75 , scanMaybe
74 , filter
76 , filter
75 , filterM
77 , filterM
76− , deleteBy -- deleteOnceBy?
78+ , deleteBy
77 , uniqBy
79 , uniqBy
78 , uniq
80 , uniq
79 , prune
81 , prune
@@ -81,8 +83,9 @@ module Streamly.Internal.Data.Stream.Transform
81
83
82 -- * Trimming
84 -- * Trimming
83 -- | Produce a subset of the stream trimmed at ends.
85 -- | Produce a subset of the stream trimmed at ends.
84− , initNonEmpty
86+ , take
85− , tailNonEmpty
87+ , takeWhile
88+ , takeWhileM
86 , takeWhileLast
89 , takeWhileLast
87 , takeWhileAround
90 , takeWhileAround
88 , drop
91 , drop
@@ -129,6 +132,7 @@ module Streamly.Internal.Data.Stream.Transform
129 -- * Searching
132 -- * Searching
130 , findIndices
133 , findIndices
131 , elemIndices
134 , elemIndices
135+ , slicesBy
132
136
133 -- * Rolling map
137 -- * Rolling map
134 -- | Map using the previous element.
138 -- | Map using the previous element.
@@ -296,7 +300,7 @@ data TapState fs st a
296--
300--
297{-# INLINE tap #-}
301{-# INLINE tap #-}
298tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
302tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
299−tap (Fold fstep initial _ final) (Stream step state) = Stream step' TapInit
303+tap (Fold fstep initial extract) (Stream step state) = Stream step' TapInit
300
304
301 where
305 where
302
306
@@ -319,7 +323,7 @@ tap (Fold fstep initial _ final) (Stream step state) = Stream step' TapInit
319 FL.Done _ -> TapDone s
323 FL.Done _ -> TapDone s
320 Skip s -> return $ Skip (Tapping acc s)
324 Skip s -> return $ Skip (Tapping acc s)
321 Stop -> do
325 Stop -> do
322− void $ final acc
326+ void $ extract acc
323 return Stop
327 return Stop
324 step' gst (TapDone st) = do
328 step' gst (TapDone st) = do
325 r <- step gst st
329 r <- step gst st
@@ -338,7 +342,7 @@ data TapOffState fs s a
338{-# INLINE_NORMAL tapOffsetEvery #-}
342{-# INLINE_NORMAL tapOffsetEvery #-}
339tapOffsetEvery :: Monad m
343tapOffsetEvery :: Monad m
340 => Int -> Int -> Fold m a b -> Stream m a -> Stream m a
344 => Int -> Int -> Fold m a b -> Stream m a -> Stream m a
341−tapOffsetEvery offset n (Fold fstep initial _ final) (Stream step state) =
345+tapOffsetEvery offset n (Fold fstep initial extract) (Stream step state) =
342 Stream step' TapOffInit
346 Stream step' TapOffInit
343
347
344 where
348 where
@@ -368,7 +372,7 @@ tapOffsetEvery offset n (Fold fstep initial _ final) (Stream step state) =
368 return $ Yield x next
372 return $ Yield x next
369 Skip s -> return $ Skip (TapOffTapping acc s count)
373 Skip s -> return $ Skip (TapOffTapping acc s count)
370 Stop -> do
374 Stop -> do
371− void $ final acc
375+ void $ extract acc
372 return Stop
376 return Stop
373 step' gst (TapOffDone st) = do
377 step' gst (TapOffDone st) = do
374 r <- step gst st
378 r <- step gst st
@@ -433,7 +437,7 @@ data ScanState s f = ScanInit s | ScanDo s !f | ScanDone
433--
437--
434{-# INLINE_NORMAL postscan #-}
438{-# INLINE_NORMAL postscan #-}
435postscan :: Monad m => FL.Fold m a b -> Stream m a -> Stream m b
439postscan :: Monad m => FL.Fold m a b -> Stream m a -> Stream m b
436−postscan (FL.Fold fstep initial extract final) (Stream sstep state) =
440+postscan (FL.Fold fstep initial extract) (Stream sstep state) =
437 Stream step (ScanInit state)
441 Stream step (ScanInit state)
438
442
439 where
443 where
@@ -456,13 +460,13 @@ postscan (FL.Fold fstep initial extract final) (Stream sstep state) =
456 return $ Yield b $ ScanDo s fs1
460 return $ Yield b $ ScanDo s fs1
457 FL.Done b -> return $ Yield b ScanDone
461 FL.Done b -> return $ Yield b ScanDone
458 Skip s -> return $ Skip $ ScanDo s fs
462 Skip s -> return $ Skip $ ScanDo s fs
459− Stop -> final fs >> return Stop
463+ Stop -> return Stop
460 step _ ScanDone = return Stop
464 step _ ScanDone = return Stop
461
465
462{-# INLINE scanWith #-}
466{-# INLINE scanWith #-}
463scanWith :: Monad m
467scanWith :: Monad m
464 => Bool -> Fold m a b -> Stream m a -> Stream m b
468 => Bool -> Fold m a b -> Stream m a -> Stream m b
465−scanWith restart (Fold fstep initial extract final) (Stream sstep state) =
469+scanWith restart (Fold fstep initial extract) (Stream sstep state) =
466 Stream step (ScanInit state)
470 Stream step (ScanInit state)
467
471
468 where
472 where
@@ -485,7 +489,7 @@ scanWith restart (Fold fstep initial extract final) (Stream sstep state) =
485 case res of
489 case res of
486 Yield x s -> runStep s (fstep fs x)
490 Yield x s -> runStep s (fstep fs x)
487 Skip s -> return $ Skip $ ScanDo s fs
491 Skip s -> return $ Skip $ ScanDo s fs
488− Stop -> final fs >> return Stop
492+ Stop -> return Stop
489 step _ ScanDone = return Stop
493 step _ ScanDone = return Stop
490
494
491-- XXX It may be useful to have a version of scan where we can keep the
495-- XXX It may be useful to have a version of scan where we can keep the
@@ -1070,55 +1074,6 @@ repeated = undefined
1070-- Trimming
1074-- Trimming
1071------------------------------------------------------------------------------
1075------------------------------------------------------------------------------
1072
1076
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−
1122-- | Take all consecutive elements at the end of the stream for which the
1077-- | Take all consecutive elements at the end of the stream for which the
1123-- predicate is true.
1078-- predicate is true.
1124--
1079--
@@ -1582,7 +1537,7 @@ reverse m = Stream step Nothing
1582{-# INLINE reverseUnbox #-}
1537{-# INLINE reverseUnbox #-}
1583reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1538reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1584reverseUnbox =
1539reverseUnbox =
1585− A.concatRev -- unfoldMany A.readerRev
1540+ A.flattenArraysRev -- unfoldMany A.readRev
1586 . fromStreamK
1541 . fromStreamK
1587 . K.reverse
1542 . K.reverse
1588 . toStreamK
1543 . toStreamK
@@ -1754,6 +1709,25 @@ findIndices p (Stream step state) = Stream step' (state, 0)
1754elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1709elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1755elemIndices a = findIndices (== a)
1710elemIndices a = findIndices (== a)
1756
1711
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+
1757------------------------------------------------------------------------------
1731------------------------------------------------------------------------------
1758-- Rolling map
1732-- Rolling map
1759------------------------------------------------------------------------------
1733------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/Transformer.hs+1−2
@@ -11,11 +11,10 @@
11
11
12module Streamly.Internal.Data.Stream.Transformer
12module Streamly.Internal.Data.Stream.Transformer
13 (
13 (
14− -- * Fold to Transformer Monad
15 foldlT
14 foldlT
16 , foldrT
15 , foldrT
17
16
18− -- * Inner Monad Operations
17+ -- * Transform Inner Monad
19 , liftInner
18 , liftInner
20 , runReaderT
19 , runReaderT
21 , usingReaderT
20 , usingReaderT
core/src/Streamly/Internal/Data/Stream/Type.hs+14−147
@@ -1,11 +1,5 @@
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 #-}
7{-# LANGUAGE UndecidableInstances #-}
2{-# LANGUAGE UndecidableInstances #-}
8−{-# LANGUAGE ViewPatterns #-}
9
3
10-- |
4-- |
11-- Module : Streamly.Internal.Data.Stream.Type
5-- Module : Streamly.Internal.Data.Stream.Type
@@ -22,18 +16,18 @@
22
16
23module Streamly.Internal.Data.Stream.Type
17module Streamly.Internal.Data.Stream.Type
24 (
18 (
25− -- * Type
19+ -- * The stream type
26 Step (..)
20 Step (..)
27 -- XXX UnStream is exported to avoid a performance issue in some
21 -- XXX UnStream is exported to avoid a performance issue in some
28 -- combinators if we use the pattern synonym "Stream".
22 -- combinators if we use the pattern synonym "Stream".
29 , Stream (Stream, UnStream)
23 , Stream (Stream, UnStream)
30
24
31− -- * CrossStream
25+ -- * CrossStream type wrapper
32 , CrossStream
26 , CrossStream
33 , unCross
27 , unCross
34 , mkCross
28 , mkCross
35
29
36− -- * To StreamK
30+ -- * Conversion to StreamK
37 , fromStreamK
31 , fromStreamK
38 , toStreamK
32 , toStreamK
39
33
@@ -91,7 +85,6 @@ module Streamly.Internal.Data.Stream.Type
91
85
92 -- * Combining Two Streams
86 -- * Combining Two Streams
93 -- ** Zipping
87 -- ** Zipping
94− -- | Zip corresponding elements of two streams.
95 , zipWithM
88 , zipWithM
96 , zipWith
89 , zipWith
97
90
@@ -107,8 +100,6 @@ module Streamly.Internal.Data.Stream.Type
107 , unfoldMany
100 , unfoldMany
108
101
109 -- * Concat
102 -- * Concat
110− -- | Generate streams by mapping a stream generator on each element of an
111− -- input stream, append the resulting streams and flatten.
112 , concatEffect
103 , concatEffect
113 , concatMap
104 , concatMap
114 , concatMapM
105 , concatMapM
@@ -132,30 +123,20 @@ module Streamly.Internal.Data.Stream.Type
132 , foldManyPost
123 , foldManyPost
133 , groupsOf
124 , groupsOf
134 , refoldMany
125 , refoldMany
135− , refoldIterateM
136
126
137 -- * Fold Iterate
127 -- * Fold Iterate
138 , reduceIterateBfs
128 , reduceIterateBfs
139 , foldIterateBfs
129 , foldIterateBfs
140
130
141− -- * Splitting
142− , indexOnSuffix
143−
144 -- * Multi-stream folds
131 -- * Multi-stream folds
145− -- | These should probably be expressed using zipping operations.
146 , eqBy
132 , eqBy
147 , cmpBy
133 , cmpBy
148−
149− -- * Deprecated
150− , sliceOnSuffix
151 )
134 )
152where
135where
153
136
154#include "inline.hs"
137#include "inline.hs"
155
138
156−#if !MIN_VERSION_base(4,18,0)
157import Control.Applicative (liftA2)
139import Control.Applicative (liftA2)
158−#endif
159import Control.Monad.Catch (MonadThrow, throwM)
140import Control.Monad.Catch (MonadThrow, throwM)
160import Control.Monad.Trans.Class (MonadTrans(lift))
141import Control.Monad.Trans.Class (MonadTrans(lift))
161import Control.Monad.IO.Class (MonadIO(..))
142import Control.Monad.IO.Class (MonadIO(..))
@@ -179,7 +160,6 @@ import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
179import Streamly.Internal.Data.Refold.Type (Refold(..))
160import Streamly.Internal.Data.Refold.Type (Refold(..))
180import Streamly.Internal.Data.Stream.Step (Step (..))
161import Streamly.Internal.Data.Stream.Step (Step (..))
181import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
162import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
182−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
183import Streamly.Internal.Data.Unfold.Type (Unfold(..))
163import Streamly.Internal.Data.Unfold.Type (Unfold(..))
184
164
185import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
165import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
@@ -230,9 +210,6 @@ pattern Stream step state <- (unShare -> UnStream step state)
230nilM :: Applicative m => m b -> Stream m a
210nilM :: Applicative m => m b -> Stream m a
231nilM m = Stream (\_ _ -> m $> Stop) ()
211nilM m = Stream (\_ _ -> m $> Stop) ()
232
212
233−
234−infixr 5 `consM`
235−
236-- | Like 'cons' but fuses an effect instead of a pure value.
213-- | Like 'cons' but fuses an effect instead of a pure value.
237{-# INLINE_NORMAL consM #-}
214{-# INLINE_NORMAL consM #-}
238consM :: Applicative m => m a -> Stream m a -> Stream m a
215consM :: Applicative m => m a -> Stream m a -> Stream m a
@@ -419,7 +396,7 @@ toStreamK (Stream step state) = go state
419{-# INLINE_NORMAL foldEither #-}
396{-# INLINE_NORMAL foldEither #-}
420foldEither :: Monad m =>
397foldEither :: Monad m =>
421 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
398 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
422−foldEither (Fold fstep begin done final) (UnStream step state) = do
399+foldEither (Fold fstep begin done) (UnStream step state) = do
423 res <- begin
400 res <- begin
424 case res of
401 case res of
425 FL.Partial fs -> go SPEC fs state
402 FL.Partial fs -> go SPEC fs state
@@ -437,9 +414,7 @@ foldEither (Fold fstep begin done final) (UnStream step state) = do
437 FL.Done b -> return $! Right (b, Stream step s)
414 FL.Done b -> return $! Right (b, Stream step s)
438 FL.Partial fs1 -> go SPEC fs1 s
415 FL.Partial fs1 -> go SPEC fs1 s
439 Skip s -> go SPEC fs s
416 Skip s -> go SPEC fs s
440− Stop ->
441− let f = Fold fstep (return $ FL.Partial fs) done final
417+ Stop -> return $! Left (Fold fstep (return $ FL.Partial fs) done)
442− in return $! Left f
443
418
444-- | Like 'fold' but also returns the remaining stream. The resulting stream
419-- | Like 'fold' but also returns the remaining stream. The resulting stream
445-- would be 'Stream.nil' if the stream finished before the fold.
420-- would be 'Stream.nil' if the stream finished before the fold.
@@ -450,12 +425,12 @@ foldBreak fld strm = do
450 r <- foldEither fld strm
425 r <- foldEither fld strm
451 case r of
426 case r of
452 Right res -> return res
427 Right res -> return res
453− Left (Fold _ initial _ final) -> do
428+ Left (Fold _ initial extract) -> do
454 res <- initial
429 res <- initial
455 case res of
430 case res of
456 FL.Done _ -> error "foldBreak: unreachable state"
431 FL.Done _ -> error "foldBreak: unreachable state"
457 FL.Partial s -> do
432 FL.Partial s -> do
458− b <- final s
433+ b <- extract s
459 return (b, nil)
434 return (b, nil)
460
435
461 where
436 where
@@ -498,8 +473,8 @@ fold fld strm = do
498--
473--
499{-# INLINE_NORMAL foldAddLazy #-}
474{-# INLINE_NORMAL foldAddLazy #-}
500foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
475foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
501−foldAddLazy (Fold fstep finitial fextract ffinal) (Stream sstep state) =
476+foldAddLazy (Fold fstep finitial fextract) (Stream sstep state) =
502− Fold fstep initial fextract ffinal
477+ Fold fstep initial fextract
503
478
504 where
479 where
505
480
@@ -572,12 +547,8 @@ foldAdd f =
572-- >>> Stream.foldrM step (return False) s
547-- >>> Stream.foldrM step (return False) s
573-- True
548-- True
574--
549--
575−-- >>> import Control.Monad (join)
576−-- >>> foldrM f z = join $ Stream.foldr f z
577−--
578{-# INLINE_NORMAL foldrM #-}
550{-# INLINE_NORMAL foldrM #-}
579foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
551foldrM :: 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
581foldrM f z (Stream step state) = go SPEC state
552foldrM f z (Stream step state) = go SPEC state
582 where
553 where
583 {-# INLINE_LATE go #-}
554 {-# INLINE_LATE go #-}
@@ -1823,7 +1794,7 @@ data FoldManyPost s fs b a
1823--
1794--
1824{-# INLINE_NORMAL foldManyPost #-}
1795{-# INLINE_NORMAL foldManyPost #-}
1825foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
1796foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
1826−foldManyPost (Fold fstep initial _ final) (Stream step state) =
1797+foldManyPost (Fold fstep initial extract) (Stream step state) =
1827 Stream step' (FoldManyPostStart state)
1798 Stream step' (FoldManyPostStart state)
1828
1799
1829 where
1800 where
@@ -1851,7 +1822,7 @@ foldManyPost (Fold fstep initial _ final) (Stream step state) =
1851 Yield x s -> consume x s fs
1822 Yield x s -> consume x s fs
1852 Skip s -> return $ Skip (FoldManyPostLoop s fs)
1823 Skip s -> return $ Skip (FoldManyPostLoop s fs)
1853 Stop -> do
1824 Stop -> do
1854− b <- final fs
1825+ b <- extract fs
1855 return $ Skip (FoldManyPostYield b FoldManyPostDone)
1826 return $ Skip (FoldManyPostYield b FoldManyPostDone)
1856 step' _ (FoldManyPostYield b next) = return $ Yield b next
1827 step' _ (FoldManyPostYield b next) = return $ Yield b next
1857 step' _ FoldManyPostDone = return Stop
1828 step' _ FoldManyPostDone = return Stop
@@ -1895,7 +1866,7 @@ data FoldMany s fs b a
1895--
1866--
1896{-# INLINE_NORMAL foldMany #-}
1867{-# INLINE_NORMAL foldMany #-}
1897foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
1868foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
1898−foldMany (Fold fstep initial _ final) (Stream step state) =
1869+foldMany (Fold fstep initial extract) (Stream step state) =
1899 Stream step' (FoldManyStart state)
1870 Stream step' (FoldManyStart state)
1900
1871
1901 where
1872 where
@@ -1922,14 +1893,14 @@ foldMany (Fold fstep initial _ final) (Stream step state) =
1922 case r of
1893 case r of
1923 Yield x s -> consume x s fs
1894 Yield x s -> consume x s fs
1924 Skip s -> return $ Skip (FoldManyFirst fs s)
1895 Skip s -> return $ Skip (FoldManyFirst fs s)
1925− Stop -> final fs >> return Stop
1896+ Stop -> return Stop
1926 step' gst (FoldManyLoop st fs) = do
1897 step' gst (FoldManyLoop st fs) = do
1927 r <- step (adaptState gst) st
1898 r <- step (adaptState gst) st
1928 case r of
1899 case r of
1929 Yield x s -> consume x s fs
1900 Yield x s -> consume x s fs
1930 Skip s -> return $ Skip (FoldManyLoop s fs)
1901 Skip s -> return $ Skip (FoldManyLoop s fs)
1931 Stop -> do
1902 Stop -> do
1932− b <- final fs
1903+ b <- extract fs
1933 return $ Skip (FoldManyYield b FoldManyDone)
1904 return $ Skip (FoldManyYield b FoldManyDone)
1934 step' _ (FoldManyYield b next) = return $ Yield b next
1905 step' _ (FoldManyYield b next) = return $ Yield b next
1935 step' _ FoldManyDone = return Stop
1906 step' _ FoldManyDone = return Stop
@@ -1996,110 +1967,6 @@ refoldMany (Refold fstep inject extract) action (Stream step state) =
1996 step' _ (FoldManyYield b next) = return $ Yield b next
1967 step' _ (FoldManyYield b next) = return $ Yield b next
1997 step' _ FoldManyDone = return Stop
1968 step' _ FoldManyDone = return Stop
1998
1969
1999−{-# ANN type CIterState Fuse #-}
2000−data CIterState s f fs b
2001− = CIterInit s f
2002− | CIterConsume s fs
2003− | CIterYield b (CIterState s f fs b)
2004− | CIterStop
2005−
2006−-- | Like 'foldIterateM' but using the 'Refold' type instead. This could be
2007−-- much more efficient due to stream fusion.
2008−--
2009−-- /Internal/
2010−{-# INLINE_NORMAL refoldIterateM #-}
2011−refoldIterateM ::
2012− Monad m => Refold m b a b -> m b -> Stream m a -> Stream m b
2013−refoldIterateM (Refold fstep finject fextract) initial (Stream step state) =
2014− Stream stepOuter (CIterInit state initial)
2015−
2016− where
2017−
2018− {-# INLINE iterStep #-}
2019− iterStep st action = do
2020− res <- action
2021− return
2022− $ Skip
2023− $ case res of
2024− FL.Partial fs -> CIterConsume st fs
2025− FL.Done fb -> CIterYield fb $ CIterInit st (return fb)
2026−
2027− {-# INLINE_LATE stepOuter #-}
2028− stepOuter _ (CIterInit st action) = do
2029− iterStep st (action >>= finject)
2030− stepOuter gst (CIterConsume st fs) = do
2031− r <- step (adaptState gst) st
2032− case r of
2033− Yield x s -> iterStep s (fstep fs x)
2034− Skip s -> return $ Skip $ CIterConsume s fs
2035− Stop -> do
2036− b <- fextract fs
2037− return $ Skip $ CIterYield b CIterStop
2038− stepOuter _ (CIterYield a next) = return $ Yield a next
2039− stepOuter _ CIterStop = return Stop
2040−
2041−-- | The refold @indexerBy f n@ takes an (index, len) tuple as initial input,
2042−-- and returns @(index + len + n, b)@ as output where @b@ is the output of the
2043−-- fold.
2044−{-# INLINE indexerBy #-}
2045−indexerBy :: Monad m =>
2046− Fold m a Int -> Int -> Refold m (Int, Int) a (Int, Int)
2047−indexerBy (Fold step1 initial1 extract1 _final) n =
2048− Refold step inject extract
2049−
2050− where
2051−
2052− inject (i, len) = do
2053− r <- initial1
2054− return $ case r of
2055− FL.Partial s -> FL.Partial $ Tuple' (i + len + n) s
2056− FL.Done l -> FL.Done (i, l)
2057−
2058− step (Tuple' i s) x = do
2059− r <- step1 s x
2060− return $ case r of
2061− FL.Partial s1 -> FL.Partial $ Tuple' i s1
2062− FL.Done len -> FL.Done (i, len)
2063−
2064− extract (Tuple' i s) = (i,) <$> extract1 s
2065−
2066−-- | Like 'splitOnSuffix' but generates a stream of (index, len) tuples marking
2067−-- the places where the predicate matches in the stream.
2068−--
2069−-- /Pre-release/
2070−{-# INLINE indexOnSuffix #-}
2071−indexOnSuffix :: Monad m =>
2072− (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2073−indexOnSuffix predicate =
2074− -- Scan the stream with the given refold
2075− refoldIterateM
2076− (indexerBy (FL.takeEndBy_ predicate FL.length) 1)
2077− (return (-1, 0))
2078−
2079−-- Alternate implementation
2080−{-# INLINE_NORMAL _indexOnSuffix #-}
2081−_indexOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2082−_indexOnSuffix p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
2083−
2084− where
2085−
2086− {-# INLINE_LATE step #-}
2087− step gst (Just (st, i, len)) = i `seq` len `seq` do
2088− r <- step1 (adaptState gst) st
2089− return
2090− $ case r of
2091− Yield x s ->
2092− if p x
2093− then Yield (i, len + 1) (Just (s, i + len + 1, 0))
2094− else Skip (Just (s, i, len + 1))
2095− Skip s -> Skip (Just (s, i, len))
2096− Stop -> if len == 0 then Stop else Yield (i, len) Nothing
2097− step _ Nothing = return Stop
2098−
2099−{-# DEPRECATED sliceOnSuffix "Please use indexOnSuffix instead." #-}
2100−sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2101−sliceOnSuffix = indexOnSuffix
2102−
2103------------------------------------------------------------------------------
1970------------------------------------------------------------------------------
2104-- Stream with a cross product style monad instance
1971-- Stream with a cross product style monad instance
2105------------------------------------------------------------------------------
1972------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/StreamK.hs+40−35
@@ -16,15 +16,16 @@ module Streamly.Internal.Data.StreamK
16 --
16 --
17 -- $setup
17 -- $setup
18
18
19+ -- * The stream type
19 module Streamly.Internal.Data.StreamK.Type
20 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− -- * From containers
23+ , StreamK(..)
24 , fromList
24 , fromList
25 , fromStream
25 , fromStream
26+ , toStream
26
27
27− -- * Specialized Generation
28+ -- ** Specialized Generation
28 , repeatM
29 , repeatM
29 , replicate
30 , replicate
30 , replicateM
31 , replicateM
@@ -36,6 +37,8 @@ module Streamly.Internal.Data.StreamK
36 -- * Elimination
37 -- * Elimination
37 -- ** General Folds
38 -- ** General Folds
38 , foldr1
39 , foldr1
40+ , foldlM'
41+ , foldlMx'
39 , fold
42 , fold
40 , foldBreak
43 , foldBreak
41 , foldEither
44 , foldEither
@@ -66,13 +69,13 @@ module Streamly.Internal.Data.StreamK
66 , find
69 , find
67 , (!!)
70 , (!!)
68
71
69− -- ** To Containers
70− , toList
71− , toStream
72−
73 -- ** Map and Fold
72 -- ** Map and Fold
74 , mapM_
73 , mapM_
75
74
75+ -- ** Conversions
76+ , toList
77+ , hoist
78+
76 -- * Transformation
79 -- * Transformation
77 -- ** By folding (scans)
80 -- ** By folding (scans)
78 , scanl'
81 , scanl'
@@ -99,7 +102,6 @@ module Streamly.Internal.Data.StreamK
99
102
100 -- ** Reordering
103 -- ** Reordering
101 , sortBy
104 , sortBy
102− , sortOn
103
105
104 -- ** Map and Filter
106 -- ** Map and Filter
105 , mapMaybe
107 , mapMaybe
@@ -115,9 +117,6 @@ module Streamly.Internal.Data.StreamK
115 -- ** Transformation comprehensions
117 -- ** Transformation comprehensions
116 , the
118 , the
117
119
118− -- ** Transforming Inner Monad
119− , hoist
120−
121 -- * Exceptions
120 -- * Exceptions
122 , handle
121 , handle
123
122
@@ -134,7 +133,6 @@ import Control.Exception (mask_, Exception)
134import Control.Monad (void, join)
133import Control.Monad (void, join)
135import Control.Monad.Catch (MonadCatch)
134import Control.Monad.Catch (MonadCatch)
136import Control.Monad.IO.Class (MonadIO(..))
135import Control.Monad.IO.Class (MonadIO(..))
137−import Data.Ord (comparing)
138import Data.Proxy (Proxy(..))
136import Data.Proxy (Proxy(..))
139import GHC.Types (SPEC(..))
137import GHC.Types (SPEC(..))
140import Streamly.Internal.Data.Array.Type (Array(..))
138import Streamly.Internal.Data.Array.Type (Array(..))
@@ -308,6 +306,19 @@ foldr1 step m = do
308 yieldk a r = fmap (step p) (go a r)
306 yieldk a r = fmap (step p) (go a r)
309 in foldStream defState yieldk single stp m1
307 in foldStream defState yieldk single stp m1
310
308
309+-- XXX replace the recursive "go" with explicit continuations.
310+-- | Like 'foldx', but with a monadic step function.
311+{-# INLINABLE foldlMx' #-}
312+foldlMx' :: Monad m
313+ => (x -> a -> m x) -> m x -> (x -> m b) -> StreamK m a -> m b
314+foldlMx' step begin done = go begin
315+ where
316+ go !acc m1 =
317+ let stop = acc >>= done
318+ single a = acc >>= \b -> step b a >>= done
319+ yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
320+ in foldStream defState yieldk single stop m1
321+
311-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
322-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
312-- expression strictly at each step. The behavior is similar to 'foldl''. A
323-- expression strictly at each step. The behavior is similar to 'foldl''. A
313-- 'Fold' can terminate early without consuming the full stream. See the
324-- 'Fold' can terminate early without consuming the full stream. See the
@@ -325,7 +336,7 @@ foldr1 step m = do
325--
336--
326{-# INLINABLE fold #-}
337{-# INLINABLE fold #-}
327fold :: Monad m => FL.Fold m a b -> StreamK m a -> m b
338fold :: Monad m => FL.Fold m a b -> StreamK m a -> m b
328−fold (FL.Fold step begin _ final) m = do
339+fold (FL.Fold step begin done) m = do
329 res <- begin
340 res <- begin
330 case res of
341 case res of
331 FL.Partial fs -> go fs m
342 FL.Partial fs -> go fs m
@@ -333,10 +344,10 @@ fold (FL.Fold step begin _ final) m = do
333
344
334 where
345 where
335 go !acc m1 =
346 go !acc m1 =
336− let stop = final acc
347+ let stop = done acc
337 single a = step acc a
348 single a = step acc a
338 >>= \case
349 >>= \case
339− FL.Partial s -> final s
350+ FL.Partial s -> done s
340 FL.Done b1 -> return b1
351 FL.Done b1 -> return b1
341 yieldk a r = step acc a
352 yieldk a r = step acc a
342 >>= \case
353 >>= \case
@@ -354,7 +365,7 @@ fold (FL.Fold step begin _ final) m = do
354{-# INLINE foldEither #-}
365{-# INLINE foldEither #-}
355foldEither :: Monad m =>
366foldEither :: Monad m =>
356 Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a))
367 Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a))
357−foldEither (FL.Fold step begin done final) m = do
368+foldEither (FL.Fold step begin done) m = do
358 res <- begin
369 res <- begin
359 case res of
370 case res of
360 FL.Partial fs -> go fs m
371 FL.Partial fs -> go fs m
@@ -363,15 +374,12 @@ foldEither (FL.Fold step begin done final) m = do
363 where
374 where
364
375
365 go !acc m1 =
376 go !acc m1 =
366− let stop =
367− let f = Fold step (return $ FL.Partial acc) done final
377+ let stop = return $ Left (Fold step (return $ FL.Partial acc) done)
368− in return $ Left f
369 single a =
378 single a =
370 step acc a
379 step acc a
371 >>= \case
380 >>= \case
372 FL.Partial s ->
381 FL.Partial s ->
373− let f = Fold step (return $ FL.Partial s) done final
382+ return $ Left (Fold step (return $ FL.Partial s) done)
374− in return $ Left f
375 FL.Done b1 -> return $ Right (b1, nil)
383 FL.Done b1 -> return $ Right (b1, nil)
376 yieldk a r =
384 yieldk a r =
377 step acc a
385 step acc a
@@ -389,12 +397,12 @@ foldBreak fld strm = do
389 r <- foldEither fld strm
397 r <- foldEither fld strm
390 case r of
398 case r of
391 Right res -> return res
399 Right res -> return res
392− Left (Fold _ initial _ final) -> do
400+ Left (Fold _ initial extract) -> do
393 res <- initial
401 res <- initial
394 case res of
402 case res of
395 FL.Done _ -> error "foldBreak: unreachable state"
403 FL.Done _ -> error "foldBreak: unreachable state"
396 FL.Partial s -> do
404 FL.Partial s -> do
397− b <- final s
405+ b <- extract s
398 return (b, nil)
406 return (b, nil)
399
407
400-- XXX Array folds can be implemented using this.
408-- XXX Array folds can be implemented using this.
@@ -413,7 +421,7 @@ foldConcat :: Monad m =>
413 Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
421 Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
414foldConcat
422foldConcat
415 (Producer pstep pinject pextract)
423 (Producer pstep pinject pextract)
416− (Fold fstep begin _ final)
424+ (Fold fstep begin done)
417 stream = do
425 stream = do
418
426
419 res <- begin
427 res <- begin
@@ -425,14 +433,14 @@ foldConcat
425
433
426 go !acc m1 = do
434 go !acc m1 = do
427 let stop = do
435 let stop = do
428− r <- final acc
436+ r <- done acc
429 return (r, nil)
437 return (r, nil)
430 single a = do
438 single a = do
431 st <- pinject a
439 st <- pinject a
432 res <- go1 SPEC acc st
440 res <- go1 SPEC acc st
433 case res of
441 case res of
434 Left fs -> do
442 Left fs -> do
435− r <- final fs
443+ r <- done fs
436 return (r, nil)
444 return (r, nil)
437 Right (b, s) -> do
445 Right (b, s) -> do
438 x <- pextract s
446 x <- pextract s
@@ -459,6 +467,11 @@ foldConcat
459 Stream.Skip s -> go1 SPEC fs s
467 Stream.Skip s -> go1 SPEC fs s
460 Stream.Stop -> return $ Left fs
468 Stream.Stop -> return $ Left fs
461
469
470+-- | Like 'foldl'' but with a monadic step function.
471+{-# INLINE foldlM' #-}
472+foldlM' :: Monad m => (b -> a -> m b) -> m b -> StreamK m a -> m b
473+foldlM' step begin = foldlMx' step begin return
474+
462------------------------------------------------------------------------------
475------------------------------------------------------------------------------
463-- Specialized folds
476-- Specialized folds
464------------------------------------------------------------------------------
477------------------------------------------------------------------------------
@@ -1315,8 +1328,7 @@ parserDone (ParserK.Failure n e) _ _ = pure $ ParserK.Error n e
1315-- using parseBreakChunks. We can also use parseBreak as an alternative to the
1328-- using parseBreakChunks. We can also use parseBreak as an alternative to the
1316-- monad instance of ParserD.
1329-- monad instance of ParserD.
1317
1330
1318−-- | Run a 'ParserK' over a chunked 'StreamK' and return the parse result and
1331+-- | Run a 'ParserK' over a chunked 'StreamK' and return the rest of the Stream.
1319−-- the remaining Stream.
1320{-# INLINE_NORMAL parseBreakChunks #-}
1332{-# INLINE_NORMAL parseBreakChunks #-}
1321parseBreakChunks
1333parseBreakChunks
1322 :: (Monad m, Unbox a)
1334 :: (Monad m, Unbox a)
@@ -1721,10 +1733,3 @@ sortBy cmp =
1721 . Stream.catRights -- its a non-failing backtracking parser
1733 . Stream.catRights -- its a non-failing backtracking parser
1722 . Stream.parseMany (fmap (either id id) p)
1734 . Stream.parseMany (fmap (either id id) p)
1723 . Stream.fromStreamK
1735 . Stream.fromStreamK
1724−
1725−{-# INLINE sortOn #-}
1726−sortOn :: (Monad m, Ord b) => (a -> b) -> StreamK m a -> StreamK m a
1727−sortOn f =
1728− fmap snd
1729− . sortBy (comparing fst)
1730− . fmap (\x -> let y = f x in y `seq` (y, x))
core/src/Streamly/Internal/Data/StreamK/Type.hs+11−82
@@ -1,8 +1,4 @@
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 #-}
6{-# LANGUAGE UndecidableInstances #-}
2{-# LANGUAGE UndecidableInstances #-}
7-- |
3-- |
8-- Module : Streamly.Internal.Data.StreamK.Type
4-- Module : Streamly.Internal.Data.StreamK.Type
@@ -88,8 +84,6 @@ module Streamly.Internal.Data.StreamK.Type
88 -- ** Strict Left Folds
84 -- ** Strict Left Folds
89 , Streamly.Internal.Data.StreamK.Type.foldl'
85 , Streamly.Internal.Data.StreamK.Type.foldl'
90 , foldlx'
86 , foldlx'
91− , foldlMx'
92− , foldlM'
93
87
94 -- ** Lazy Right Folds
88 -- ** Lazy Right Folds
95 , Streamly.Internal.Data.StreamK.Type.foldr
89 , Streamly.Internal.Data.StreamK.Type.foldr
@@ -97,11 +91,8 @@ module Streamly.Internal.Data.StreamK.Type
97 -- ** Specific Folds
91 -- ** Specific Folds
98 , drain
92 , drain
99 , null
93 , null
100− , headNonEmpty
101 , tail
94 , tail
102− , tailNonEmpty
103 , init
95 , init
104− , initNonEmpty
105
96
106 -- * Mapping
97 -- * Mapping
107 , map
98 , map
@@ -153,9 +144,7 @@ where
153import Control.Monad ((>=>))
144import Control.Monad ((>=>))
154import Control.Monad.Catch (MonadThrow, throwM)
145import Control.Monad.Catch (MonadThrow, throwM)
155import Control.Monad.Trans.Class (MonadTrans(lift))
146import Control.Monad.Trans.Class (MonadTrans(lift))
156−#if !MIN_VERSION_base(4,18,0)
157import Control.Applicative (liftA2)
147import Control.Applicative (liftA2)
158−#endif
159import Control.Monad.IO.Class (MonadIO(..))
148import Control.Monad.IO.Class (MonadIO(..))
160import Data.Foldable (Foldable(foldl'), fold, foldr)
149import Data.Foldable (Foldable(foldl'), fold, foldr)
161import Data.Function (fix)
150import Data.Function (fix)
@@ -826,24 +815,6 @@ foldlx' step begin done m = get $ go m begin
826foldl' :: Monad m => (b -> a -> b) -> b -> StreamK m a -> m b
815foldl' :: Monad m => (b -> a -> b) -> b -> StreamK m a -> m b
827foldl' step begin = foldlx' step begin id
816foldl' step begin = foldlx' step begin id
828
817
829−-- XXX replace the recursive "go" with explicit continuations.
830−-- | Like 'foldx', but with a monadic step function.
831−{-# INLINABLE foldlMx' #-}
832−foldlMx' :: Monad m
833− => (x -> a -> m x) -> m x -> (x -> m b) -> StreamK m a -> m b
834−foldlMx' step begin done = go begin
835− where
836− go !acc m1 =
837− let stop = acc >>= done
838− single a = acc >>= \b -> step b a >>= done
839− yieldk a r = acc >>= \b -> step b a >>= \x -> go (return x) r
840− in foldStream defState yieldk single stop m1
841−
842−-- | Like 'foldl'' but with a monadic step function.
843−{-# INLINE foldlM' #-}
844−foldlM' :: Monad m => (b -> a -> m b) -> m b -> StreamK m a -> m b
845−foldlM' step begin = foldlMx' step begin return
846−
847------------------------------------------------------------------------------
818------------------------------------------------------------------------------
848-- Specialized folds
819-- Specialized folds
849------------------------------------------------------------------------------
820------------------------------------------------------------------------------
@@ -1814,42 +1785,14 @@ iterateMWith cns step = go
1814 !next <- s
1785 !next <- s
1815 foldStreamShared st stp sng yld (return next `cns` go (step next))
1786 foldStreamShared st stp sng yld (return next `cns` go (step next))
1816
1787
1817−-- | head for non-empty streams, fails for empty stream case.
1788+{-# INLINE headPartial #-}
1818−--
1819−{-# INLINE headNonEmpty #-}
1820−headNonEmpty :: Monad m => StreamK m a -> m a
1789+headPartial :: Monad m => StreamK m a -> m a
1821−headNonEmpty = foldrM (\x _ -> return x) (error "headNonEmpty: empty stream")
1790+headPartial = foldrM (\x _ -> return x) (error "head of nil")
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
1843
1791
1844−-- | tail for non-empty streams, fails for empty stream case.
1792+{-# INLINE tailPartial #-}
1845−--
1846−-- See also 'tail' for a non-partial version of this function..
1847−--
1848−-- Note: this is same as "drop 1" with error on empty stream.
1849−{-# INLINE tailNonEmpty #-}
1850−tailNonEmpty :: StreamK m a -> StreamK m a
1793+tailPartial :: StreamK m a -> StreamK m a
1851−tailNonEmpty m = mkStream $ \st yld sng stp ->
1794+tailPartial m = mkStream $ \st yld sng stp ->
1852− let stop = error "tailNonEmpty: empty stream"
1795+ let stop = error "tail of nil"
1853 single _ = stp
1796 single _ = stp
1854 yieldk _ r = foldStream st yld sng stp r
1797 yieldk _ r = foldStream st yld sng stp r
1855 in foldStream st yieldk single stop m
1798 in foldStream st yieldk single stop m
@@ -1914,10 +1857,10 @@ mfix f = mkStream $ \st yld sng stp ->
1914 where
1857 where
1915
1858
1916 -- fix the head element of the stream
1859 -- fix the head element of the stream
1917− xs = fix (f . headNonEmpty)
1860+ xs = fix (f . headPartial)
1918
1861
1919 -- now fix the tail recursively
1862 -- now fix the tail recursively
1920− ys = mfix (tailNonEmpty . f)
1863+ ys = mfix (tailPartial . f)
1921
1864
1922-------------------------------------------------------------------------------
1865-------------------------------------------------------------------------------
1923-- Conversions
1866-- Conversions
@@ -1948,15 +1891,6 @@ uncons m =
1948 yieldk a r = pure (Just (a, r))
1891 yieldk a r = pure (Just (a, r))
1949 in foldStream defState yieldk single stop m
1892 in foldStream defState yieldk single stop m
1950
1893
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−--
1960{-# INLINE tail #-}
1894{-# INLINE tail #-}
1961tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
1895tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
1962tail =
1896tail =
@@ -1965,14 +1899,9 @@ tail =
1965 yieldk _ r = pure $ Just r
1899 yieldk _ r = pure $ Just r
1966 in foldStream defState yieldk single stop
1900 in foldStream defState yieldk single stop
1967
1901
1968−-- Note that this is not a StreamK -> StreamK because then we cannot handle the
1902+-- | Extract all but the last element of the stream, if any.
1969−-- empty stream case without making this a partial function.
1970--
1903--
1971−-- XXX How do we implement unsnoc? Make StreamK a monad and return the
1904+-- Note: This will end up buffering the entire stream.
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.
1976--
1905--
1977-- /Pre-release/
1906-- /Pre-release/
1978{-# INLINE init #-}
1907{-# INLINE init #-}
core/src/Streamly/Internal/Data/Time/Units.hs+3
@@ -1,3 +1,6 @@
1+{-# LANGUAGE TypeInType #-}
2+{-# LANGUAGE UnboxedTuples #-}
3+
1-- |
4-- |
2-- Module : Streamly.Internal.Data.Time.Units
5-- Module : Streamly.Internal.Data.Time.Units
3-- Copyright : (c) 2019 Composewell Technologies
6-- Copyright : (c) 2019 Composewell Technologies
core/src/Streamly/Internal/Data/Unbox.hs+289−165

This diff is too big to show here.

core/src/Streamly/Internal/Data/Unbox/TH.hs+74−74

This diff is too big to show here.

core/src/Streamly/Internal/Data/Unfold.hs+13−15

This diff is too big to show here.

core/src/Streamly/Internal/FileSystem/File.hs+13−11

This diff is too big to show here.

core/src/Streamly/Internal/FileSystem/Handle.hs+28−21

This diff is too big to show here.

core/src/Streamly/Internal/FileSystem/Path.hsdeleted−515

This diff is too big to show here.

core/src/Streamly/Internal/Data/Binary/Parser.hs → core/src/Streamly/Internal/Serialize/FromBytes.hsrenamed+2−8

This diff is too big to show here.

core/src/Streamly/Internal/Data/Binary/Stream.hs → core/src/Streamly/Internal/Serialize/ToBytes.hsrenamed+2−2

This diff is too big to show here.

core/src/Streamly/Internal/Unicode/Parser.hs−3

This diff is too big to show here.

core/src/Streamly/Internal/Unicode/Stream.hs+11−39

This diff is too big to show here.

core/src/Streamly/Internal/Unicode/String.hs+7−7

This diff is too big to show here.

core/streamly-core.cabal+41−95

This diff is too big to show here.

docs/Developer/optimization-guidelines.md−12

This diff is too big to show here.

docs/Developer/paths.rst+2−25

This diff is too big to show here.

docs/User/HowTo/Compiling.md+3−5

This diff is too big to show here.

docs/User/Project/ApiChangelogs/0.9.0-0.10.0.txtdeleted−424

This diff is too big to show here.

docs/User/Project/CONTRIBUTORS.md−8

This diff is too big to show here.

docs/User/Project/Changelog.md+10−25

This diff is too big to show here.

docs/User/Project/README.md+2−9

This diff is too big to show here.

docs/User/Project/Upgrading-0.8-to-0.9.md → docs/User/Project/Upgrading.mdrenamed+9−87

This diff is too big to show here.

docs/User/Tutorials/quick-overview.md+14−10

This diff is too big to show here.

docs/streamly-docs.cabal+1−1

This diff is too big to show here.

src/Streamly.hsnew file+625

This diff is too big to show here.

src/Streamly/Data/Fold/Prelude.hs+13−31

This diff is too big to show here.

src/Streamly/Data/Fold/Tee.hs+1−1

This diff is too big to show here.

src/Streamly/Data/Stream/Concurrent.hsnew file+194

This diff is too big to show here.

src/Streamly/Data/Stream/Exception.hsnew file+25

This diff is too big to show here.

src/Streamly/Data/Stream/MkType.hs+10−41

This diff is too big to show here.

src/Streamly/Data/Stream/Prelude.hs+15−217

This diff is too big to show here.

src/Streamly/Data/Stream/Time.hsnew file+37

This diff is too big to show here.

src/Streamly/Data/Unicode/Stream.hsnew file+99

This diff is too big to show here.

src/Streamly/Internal/Data/Array/ArrayMacros.hnew file+40

This diff is too big to show here.

src/Streamly/Internal/Data/Channel.hsdeleted−19

This diff is too big to show here.

src/Streamly/Internal/Data/Fold/Async.hs+2−5

This diff is too big to show here.

src/Streamly/Internal/Data/Fold/Concurrent.hs+44−1

This diff is too big to show here.

src/Streamly/Internal/Data/Fold/Concurrent/Channel.hs+10−29

This diff is too big to show here.

src/Streamly/Internal/Data/Fold/Concurrent/Channel/Type.hs+3−3

This diff is too big to show here.

src/Streamly/Internal/Data/Fold/Prelude.hsdeleted−19

This diff is too big to show here.

src/Streamly/Internal/Data/Fold/SVar.hs+5−6

This diff is too big to show here.

src/Streamly/Internal/Data/IsMap/HashMap.hs−6

This diff is too big to show here.

src/Streamly/Internal/Data/SVar.hs−1

This diff is too big to show here.

src/Streamly/Internal/Data/SmallArray.hs+1−1

This diff is too big to show here.

src/Streamly/Internal/Data/Channel/Dispatcher.hs → src/Streamly/Internal/Data/Stream/Channel/Dispatcher.hsrenamed+3−3

This diff is too big to show here.

src/Streamly/Internal/Data/Channel/Types.hs → src/Streamly/Internal/Data/Stream/Channel/Types.hsrenamed+37−12

This diff is too big to show here.

src/Streamly/Internal/Data/Channel/Worker.hs → src/Streamly/Internal/Data/Stream/Channel/Worker.hsrenamed+3−3

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent.hs+39−50

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel.hs+14−17

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel/Append.hs+10−10

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel/Consumer.hs+2−2

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel/Dispatcher.hs+3−3

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel/Interleave.hs+8−8

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel/Operations.hs+1−1

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Concurrent/Channel/Type.hs+3−3

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Lifted.hs → src/Streamly/Internal/Data/Stream/Exception/Lifted.hsrenamed+2−2

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream.hs−6

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Common.hs+2−2

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+1−1

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Exception.hs+1−1

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Expand.hs−5

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Generate.hs+4−4

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Reduce.hs+4−4

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/IsStream/Top.hs+1−1

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/MkType.hs+34−33

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Prelude.hsdeleted−19

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/SVar.hsdeleted−18

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/SVar/Generate.hs−2

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Serial.hs−5

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Time.hs+2−2

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Zip.hs−39

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Zip/Concurrent.hsnew file+50

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/ZipAsync.hs+1−2

This diff is too big to show here.

src/Streamly/Internal/Data/Unfold/Prelude.hsdeleted−17

This diff is too big to show here.

src/Streamly/Internal/Data/Unfold/SVar.hs−1

This diff is too big to show here.

src/Streamly/Internal/FileSystem/Event.hs−3

This diff is too big to show here.

src/Streamly/Internal/FileSystem/Event/Darwin.hs+1−1

This diff is too big to show here.

src/Streamly/Internal/FileSystem/Event/Linux.hs+2−2

This diff is too big to show here.

src/Streamly/Internal/FileSystem/Event/Windows.hs+2−2

This diff is too big to show here.

src/Streamly/Internal/FileSystem/FD.hs+8−7

This diff is too big to show here.

src/Streamly/Internal/Network/Inet/TCP.hs+44−76

This diff is too big to show here.

src/Streamly/Internal/Network/Socket.hs+14−17

This diff is too big to show here.

src/Streamly/Internal/Unicode/Char.hs+3−7

This diff is too big to show here.

src/Streamly/Memory/Array.hsnew file+74

This diff is too big to show here.

src/Streamly/Network/Inet/TCP.hs+30−41

This diff is too big to show here.

src/Streamly/Network/Socket.hs+30−16

This diff is too big to show here.

streamly.cabal+62−81

This diff is too big to show here.

targets/Targets.hs+2−5

This diff is too big to show here.

test/Streamly/Test/Data/Array.hs+3−3

This diff is too big to show here.

test/Streamly/Test/Data/Array/Stream.hs+1−1

This diff is too big to show here.

test/Streamly/Test/Data/Fold.hs+6−7

This diff is too big to show here.

test/Streamly/Test/Data/MutArray.hs+1−1

This diff is too big to show here.

test/Streamly/Test/Data/Parser.hs+6−12

This diff is too big to show here.

test/Streamly/Test/Data/ParserK.hs+2−7

This diff is too big to show here.

test/Streamly/Test/Data/Serialize.hs+20−52

This diff is too big to show here.

test/Streamly/Test/Data/Serialize/CompatV0.hs+4−4

This diff is too big to show here.

test/Streamly/Test/Data/Serialize/CompatV1.hs+4−4

This diff is too big to show here.

test/Streamly/Test/Data/Serialize/TH.hs+2−2

This diff is too big to show here.

test/Streamly/Test/Data/Stream/Concurrent.hs+1−1

This diff is too big to show here.

test/Streamly/Test/Data/Unbox.hs+50−47

This diff is too big to show here.

test/Streamly/Test/Data/Unbox/TH.hs+10−11

This diff is too big to show here.

test/Streamly/Test/FileSystem/Event/Common.hs+1−1

This diff is too big to show here.

test/Streamly/Test/FileSystem/Handle.hs+2−2

This diff is too big to show here.

test/Streamly/Test/Prelude/Serial.hs+3−7

This diff is too big to show here.

test/Streamly/Test/Serialize/Serializable.hs+2−2

This diff is too big to show here.

test/Streamly/Test/Unicode/Char.hs+1−1

This diff is too big to show here.

test/Streamly/Test/Unicode/Stream.hs+1−1

This diff is too big to show here.

test/lib/Streamly/Test/Prelude/Common.hs+2−9

This diff is too big to show here.

test/streamly-tests.cabal+11−12

This diff is too big to show here.