on master help sign in
.circleci/config.yml+73−277
since splitsnapshots
unifiedsplit
@@ -1,7 +1,7 @@
1version: 2.1
1version: 2.1
2
2
3#-----------------------------------------------------------------------------
3#-----------------------------------------------------------------------------
4−# packcheck-0.4.2
4+# packcheck-0.7.0
5# Packcheck global environment variables
5# Packcheck global environment variables
6#-----------------------------------------------------------------------------
6#-----------------------------------------------------------------------------
7
7
@@ -11,6 +11,8 @@ 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
14 CABAL_REINIT_CONFIG: "y"
16 CABAL_REINIT_CONFIG: "y"
15 LC_ALL: "C.UTF-8"
17 LC_ALL: "C.UTF-8"
16
18
@@ -22,7 +24,6 @@ env: &env
22 # DISABLE_DOCS: "y"
24 # DISABLE_DOCS: "y"
23 # DISABLE_SDIST_BUILD: "y"
25 # DISABLE_SDIST_BUILD: "y"
24 # DISABLE_DIST_CHECKS: "y"
26 # DISABLE_DIST_CHECKS: "y"
25− ENABLE_INSTALL: "y"
26
27
27 # ------------------------------------------------------------------------
28 # ------------------------------------------------------------------------
28 # stack options
29 # stack options
@@ -38,15 +39,12 @@ env: &env
38 # cabal options
39 # cabal options
39 # ------------------------------------------------------------------------
40 # ------------------------------------------------------------------------
40 CABAL_CHECK_RELAX: "y"
41 CABAL_CHECK_RELAX: "y"
41− CABAL_NO_SANDBOX: "y"
42− CABAL_HACKAGE_MIRROR: "hackage.haskell.org:http://hackage.fpcomplete.com"
43 CABAL_BUILD_OPTIONS: "-j1 --flag limit-build-mem"
42 CABAL_BUILD_OPTIONS: "-j1 --flag limit-build-mem"
44
43
45 # ------------------------------------------------------------------------
44 # ------------------------------------------------------------------------
46 # Where to find the required tools
45 # Where to find the required tools
47 # ------------------------------------------------------------------------
46 # ------------------------------------------------------------------------
48− PATH: /opt/ghc/bin:/opt/ghcjs/bin:/sbin:/usr/sbin:/bin:/usr/bin
47+ PATH: /sbin:/usr/sbin:/bin:/usr/bin
49− TOOLS_DIR: /opt
50
48
51 # ------------------------------------------------------------------------
49 # ------------------------------------------------------------------------
52 # Location of packcheck.sh (the shell script invoked to perform CI tests ).
50 # Location of packcheck.sh (the shell script invoked to perform CI tests ).
@@ -59,15 +57,15 @@ env: &env
59 # If you have not committed packcheck.sh in your repo at PACKCHECK
57 # If you have not committed packcheck.sh in your repo at PACKCHECK
60 # then it is automatically pulled from this URL.
58 # then it is automatically pulled from this URL.
61 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
59 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
62− PACKCHECK_GITHUB_COMMIT: "a302772c8f3791c477edd1764b82f8d1f5b22fdf"
60+ PACKCHECK_GITHUB_COMMIT: "f6cfd7b7a33b4bf6fd63cce6a3fb3d26f5031403"
63
61
64executors:
62executors:
65 amd64-executor:
63 amd64-executor:
66 docker:
64 docker:
67− - image: ubuntu:xenial
65+ - image: ubuntu:latest
68 x86-executor:
66 x86-executor:
69 docker:
67 docker:
70− - image: i386/ubuntu:eoan
68+ - image: i386/ubuntu:focal
71
69
72#-----------------------------------------------------------------------------
70#-----------------------------------------------------------------------------
73# Common utility stuff, not to be modified usually
71# Common utility stuff, not to be modified usually
@@ -79,38 +77,50 @@ preinstall: &preinstall
79 # required for https/cache save and restore
77 # required for https/cache save and restore
80 apt-get install -y ca-certificates
78 apt-get install -y ca-certificates
81
79
82− # required to (re)generate the configure script
80+ # Alternative way of installing ghc and cabal, directly from
83− apt-get install -y autoconf
81+ # haskell.org instead of using ghcup. NOTE: this is for Debian
84−
82+ # only and is debian release specific.
85− # For ghc and cabal-install packages from hvr's ppa
86 # gnupg is required for apt-key to work
83 # gnupg is required for apt-key to work
87− apt-get install -y gnupg
84+ #apt-get install -y gnupg
88− apt-get install -y apt-transport-https
89− apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA3CBA3FFE22B574
85+ #apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA3CBA3FFE22B574
90− apt-get install -y software-properties-common
91− add-apt-repository -y ppa:hvr/ghc
92− # echo "deb http://downloads.haskell.org/debian stretch main" >> /etc/apt/sources.list
86+ #echo "deb http://downloads.haskell.org/debian buster 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
87+ #apt-get update
95
88
96− # required for packcheck
89+ # required for outbound https for stack and for stack setup
90+ apt-get install -y netbase xz-utils make
97− apt-get install -y curl
91+ apt-get install -y zlib1g-dev
98
92
93+ # For ghcup to install ghc
94+ if test -n "$GHCUP_VERSION"
95+ then
96+ apt-get install -y gcc
97+ apt-get install -y g++
98+ fi
99+
99− # required for circleci.
100+ # libgmp required by ghc for linking
100− apt-get install -y libcurl4-gnutls-dev
101+ apt-get install -y libgmp-dev
101− apt-get install -y git
102 apt-get install -y libtinfo-dev
102 apt-get install -y libtinfo-dev
103
103
104− # required for outbound https for stack and for stack setup
104+ # Required by cabal when git URL is specified in project file
105+ apt-get install -y git
106+
107+ # Required for and by packcheck
105− apt-get install -y netbase xz-utils make
108+ apt-get install -y curl
106
109
107−project-preinstall: &project-preinstall
108− run: |
109 # Get packcheck if needed
110 # Get packcheck if needed
110− CURL=$(which curl)
111+ if test ! -e "$PACKCHECK"
112+ then
113+ if test -z "$PACKCHECK_GITHUB_COMMIT"
114+ then
115+ die "PACKCHECK_GITHUB_COMMIT is not specified."
116+ fi
111− PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
117+ PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
112− if test ! -e "$PACKCHECK"; then $CURL -sL -o "$PACKCHECK" $PACKCHECK_URL; fi;
118+ curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1
119+ chmod +x $PACKCHECK
120+ elif test ! -x "$PACKCHECK"
121+ then
113− chmod +x $PACKCHECK
122+ chmod +x $PACKCHECK
123+ fi
114
124
115restore: &restore
125restore: &restore
116 # Needs to happen after installing ca-certificates
126 # Needs to happen after installing ca-certificates
@@ -126,271 +136,71 @@ save: &save
126 save_cache:
136 save_cache:
127 key: v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}
137 key: v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}
128 paths:
138 paths:
129− - ~/.cabal
130− - ~/.ghc
131 - ~/.local
139 - ~/.local
140+ - ~/.cabal
132 - ~/.stack
141 - ~/.stack
142+ - ~/.ghcup
133
143
134#-----------------------------------------------------------------------------
144#-----------------------------------------------------------------------------
135# Build matrix
145# Build matrix
136#-----------------------------------------------------------------------------
146#-----------------------------------------------------------------------------
137
147
138jobs:
148jobs:
139− cabal-ghc-8_10_4:
149+ cabal-ghc-8_6_5:
140 <<: *env
150 <<: *env
141 executor: amd64-executor
151 executor: amd64-executor
142 steps:
152 steps:
143− - *preinstall
144 - checkout
153 - checkout
145− - *project-preinstall
146 - *restore
154 - *restore
155+ - *preinstall
147 - run:
156 - run:
148 environment:
157 environment:
158+ GHCVER: "8.6.5"
159+ CABAL_VERSION: "3.6.2.0"
149 CABAL_PROJECT: "cabal.project"
160 CABAL_PROJECT: "cabal.project"
150− DISABLE_TEST: "yes"
151− DISABLE_BENCH: "yes"
152 DISABLE_SDIST_BUILD: "yes"
161 DISABLE_SDIST_BUILD: "yes"
162+ CABAL_BUILD_OPTIONS: "--flag debug --flag -opt"
153 command: |
163 command: |
154− apt-get install -y ghc-8.10.4
155− apt-get install -y cabal-install-3.4
156 bash -c "$PACKCHECK cabal"
164 bash -c "$PACKCHECK cabal"
157 - *save
165 - *save
158− stack-ghc-8_8:
166+ cabal-ghc-9_8_1-docspec:
159 <<: *env
167 <<: *env
160 executor: amd64-executor
168 executor: amd64-executor
161 steps:
169 steps:
162− - *preinstall
163 - checkout
170 - checkout
164− - *project-preinstall
165 - *restore
171 - *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:
182 - *preinstall
172 - *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
218 - run:
173 - run:
219 environment:
174 environment:
220− BUILD: "cabal-v2"
175+ GHCVER: "9.8.1"
176+ CABAL_VERSION: "3.10.1.0"
177+ CABAL_PROJECT: "cabal.project.doctest"
178+ DISABLE_SDIST_BUILD: "y"
221− DISABLE_TEST: "yes"
179+ DISABLE_TEST: "y"
222− DISABLE_BENCH: "yes"
180+ DISABLE_BENCH: "y"
223− DISABLE_DOCS: "yes"
181+ DISABLE_DOCS: "y"
224− DISABLE_SDIST_BUILD: "yes"
182+ ENABLE_DOCSPEC: "y"
225− DISABLE_DIST_CHECKS: "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
184+ DOCSPEC_OPTIONS: "--timeout 60 --check-properties --property-variables xs"
226 command: |
185 command: |
227− apt-get install -y ghc-8.2.2
228− apt-get install -y cabal-install-3.2
229− bash -c "$PACKCHECK $BUILD"
230− - *save
231− cabal-ghc-8_0_2:
232− <<: *env
233− executor: amd64-executor
234− steps:
235− - *preinstall
236− - checkout
237− - *project-preinstall
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"
186+ bash -c "$PACKCHECK cabal"
251− - *save
252− cabal-ghc-7_10_3:
253− <<: *env
254− executor: amd64-executor
255− steps:
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
187 - *save
265− stack-ghc-8_4:
188+ hlint-trailing-spaces:
266 <<: *env
189 <<: *env
267 executor: amd64-executor
190 executor: amd64-executor
268 steps:
191 steps:
269− - *preinstall
270 - checkout
192 - checkout
271− - *project-preinstall
272 - *restore
193 - *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
194 - *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
295 - run:
195 - run:
296− name: GHCJS 8.4+no-test+no-docs
196+ name: hlint and trailing spaces
297 environment:
197 environment:
298− BUILD: cabal-v2
299− ENABLE_GHCJS: "yes"
300− DISABLE_TEST: "yes"
301− ENABLE_INSTALL: ""
302− DISABLE_DOCS: "yes"
303 DISABLE_SDIST_BUILD: "yes"
198 DISABLE_SDIST_BUILD: "yes"
304− command: |
199+ HLINT_VERSION: 3.6.1
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
389 HLINT_OPTIONS: lint
200 HLINT_OPTIONS: lint
390− DISABLE_SDIST_BUILD: "yes"
391 HLINT_TARGETS: core/src src test benchmark
201 HLINT_TARGETS: core/src src test benchmark
392 command: |
202 command: |
393− bash -c "$PACKCHECK $BUILD" || exit 1
203+ bash -c "$PACKCHECK hlint" || exit 1
394 echo "Checking trailing spaces..."
204 echo "Checking trailing spaces..."
395 count=$(find . -name "*.hs" -exec grep -H '\ $' {} \; | tee /dev/tty | wc -l)
205 count=$(find . -name "*.hs" -exec grep -H '\ $' {} \; | tee /dev/tty | wc -l)
396 exit $count
206 exit $count
@@ -400,23 +210,9 @@ workflows:
400 version: 2
210 version: 2
401 build:
211 build:
402 jobs:
212 jobs:
403− - cabal-ghc-8_10_4:
213+ #- cabal-ghc-8_6_5:
404− name: GHC 8.10.4 + sdist + no-test + no-bench
214+ # name: 8.6.5-debug-unoptimized
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
410− #- cabal-ghc-8_0_2:
411− # name: GHC 8.0.2 + no-test + no-bench + no-docs
412− #- cabal-ghc-7.10.3
215+ - cabal-ghc-9_8_1-docspec:
413− # - cabal-ghcjs-8_4:
216+ name: ghc-9.8.1-docspec
414− # name: GHCJS 8.4 + no-test + no-docs
217+ - hlint-trailing-spaces:
415− #- stack-ghc-8.4
218+ name: hlint and trailing spaces
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+61−60
@@ -13,9 +13,15 @@ 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 }}
16 GHCVER: ${{ matrix.ghc_version }}
21 GHCVER: ${{ matrix.ghc_version }}
17 CABALVER: ${{ matrix.cabal_version }}
22 CABALVER: ${{ matrix.cabal_version }}
18 DISABLE_DOCS: ${{ matrix.disable_docs }}
23 DISABLE_DOCS: ${{ matrix.disable_docs }}
24+ ENABLE_DOCSPEC: ${{ matrix.enable_docspec }}
19 DISABLE_TEST: ${{ matrix.disable_test }}
25 DISABLE_TEST: ${{ matrix.disable_test }}
20 DISABLE_BENCH: ${{ matrix.disable_bench }}
26 DISABLE_BENCH: ${{ matrix.disable_bench }}
21 DISABLE_DIST_CHECKS: ${{ matrix.disable_dist_checks }}
27 DISABLE_DIST_CHECKS: ${{ matrix.disable_dist_checks }}
@@ -39,14 +45,18 @@ jobs:
39 STACK_BUILD_OPTIONS: ${{ matrix.stack_build_options }}
45 STACK_BUILD_OPTIONS: ${{ matrix.stack_build_options }}
40
46
41 # packcheck location and revision
47 # packcheck location and revision
42− PACKCHECK_LOCAL_PATH: "./packcheck.sh"
48+ PACKCHECK: "./packcheck.sh"
43 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
49 PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck"
44− PACKCHECK_GITHUB_COMMIT: "a302772c8f3791c477edd1764b82f8d1f5b22fdf"
50+ PACKCHECK_GITHUB_COMMIT: "v0.7.0"
45
51
46 # Pull token from "secrets" setting of the github repo
52 # Pull token from "secrets" setting of the github repo
47 COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
53 COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
48 COVERAGE: ${{ matrix.coverage }}
54 COVERAGE: ${{ matrix.coverage }}
49− DOCTEST: ${{ matrix.doctest }}
55+
56+ # hlint
57+ HLINT_VERSION: 3.6.1
58+ HLINT_OPTIONS: "lint"
59+ HLINT_TARGETS: "core/src src test benchmark"
50
60
51 # Subdir
61 # Subdir
52 SUBDIR: ${{ matrix.subdir }}
62 SUBDIR: ${{ matrix.subdir }}
@@ -59,7 +69,7 @@ jobs:
59 # The order is important to optimize fail-fast.
69 # The order is important to optimize fail-fast.
60 name:
70 name:
61 - 9.8.1-Werror
71 - 9.8.1-Werror
62− - 9.2.8-docspec
72+ # - 9.8.1-docspec
63 # - 8.10.7-coverage
73 # - 8.10.7-coverage
64
74
65 # Note: if cabal.project is not specified benchmarks and tests won't
75 # Note: if cabal.project is not specified benchmarks and tests won't
@@ -68,9 +78,19 @@ jobs:
68 include:
78 include:
69 - name: head
79 - name: head
70 ghc_version: head
80 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"
71 runner: ubuntu-latest
91 runner: ubuntu-latest
72 build: cabal
92 build: cabal
73− cabal_version: 3.10.1.0
93+ cabal_version: 3.10.2.0
74 cabal_project: cabal.project.ghc-head
94 cabal_project: cabal.project.ghc-head
75 disable_sdist_build: "y"
95 disable_sdist_build: "y"
76 ignore_error: true
96 ignore_error: true
@@ -83,6 +103,18 @@ jobs:
83 disable_sdist_build: "y"
103 disable_sdist_build: "y"
84 cabal_project: cabal.project.Werror
104 cabal_project: cabal.project.Werror
85 ignore_error: false
105 ignore_error: false
106+ #- name: 9.8.1-docspec
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
86 - name: 9.8.1-fusion-inspection
118 - name: 9.8.1-fusion-inspection
87 ghc_version: 9.8.1
119 ghc_version: 9.8.1
88 runner: ubuntu-latest
120 runner: ubuntu-latest
@@ -116,14 +148,6 @@ jobs:
116 cabal_version: 3.6.2.0
148 cabal_version: 3.6.2.0
117 disable_sdist_build: "y"
149 disable_sdist_build: "y"
118 ignore_error: false
150 ignore_error: false
119− - name: 9.2.8-docspec
120− ghc_version: 9.2.8
121− runner: ubuntu-latest
122− doctest: "y"
123− cabal_version: 3.6.2.0
124− cabal_project: cabal.project
125− disable_sdist_build: "y"
126− ignore_error: false
127 - name: 9.0.2-streamly-sdist
151 - name: 9.0.2-streamly-sdist
128 ghc_version: 9.0.2
152 ghc_version: 9.0.2
129 runner: ubuntu-latest
153 runner: ubuntu-latest
@@ -170,66 +194,44 @@ jobs:
170 cabal_build_options: "--flag debug --flag -opt"
194 cabal_build_options: "--flag debug --flag -opt"
171 disable_sdist_build: "y"
195 disable_sdist_build: "y"
172 ignore_error: false
196 ignore_error: false
197+ - name: hlint
198+ build: hlint
199+ runner: ubuntu-latest
200+ ignore_error: true
173
201
174 steps:
202 steps:
175 - uses: actions/checkout@v2
203 - uses: actions/checkout@v2
176
204
177 - uses: actions/cache@v1
205 - uses: actions/cache@v1
178− name: Cache ~/.cabal
206+ name: Cache common directories
179 with:
207 with:
208+ path: |
209+ ~/.local
180− path: ~/.cabal
210+ ~/.cabal
211+ ~/.stack
212+ ~/.ghcup
181 # Bump the key version to clear the cache
213 # Bump the key version to clear the cache
182 key: ${{ runner.os }}-${{ matrix.ghc_version }}-cabal-v2
214 key: ${{ runner.os }}-${{ matrix.ghc_version }}-cabal-v2
183
215
184 - name: Download packcheck
216 - name: Download packcheck
185 run: |
217 run: |
186− # Get packcheck if needed
218+ if test ! -e "$PACKCHECK"
187− CURL=$(which curl)
188− PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
189− if test ! -e "$PACKCHECK_LOCAL_PATH"; then $CURL -sL -o "$PACKCHECK_LOCAL_PATH" $PACKCHECK_URL; fi;
190− chmod +x $PACKCHECK_LOCAL_PATH
191−
192− os=$(uname -s -m)
193− case "$os" in
194− "Linux x86_64") GHCUP_ARCH="x86_64-linux" ;;
195− "Darwin x86_64") GHCUP_ARCH="x86_64-apple-darwin" ;;
196− *) echo "Unknown OS/Arch: $os"; exit 1;;
197− esac
198−
199− # Check available versions here: https://downloads.haskell.org/~ghcup/
200− GHCUP_VER=0.1.18.0
201− $CURL -sL -o ./ghcup https://downloads.haskell.org/~ghcup/$GHCUP_VER/${GHCUP_ARCH}-ghcup-$GHCUP_VER
202− chmod +x ./ghcup
203− if test "$GHCVER" = "head"
204 then
219 then
205− # The URL may change, to find a working URL go to https://gitlab.haskell.org/ghc/ghc/-/jobs/
220+ if test -z "$PACKCHECK_GITHUB_COMMIT"
206− # Find a debian10 job, click on a passed/failed job, at the
221+ then
207− # end of the output you will find the tar.xz name, put that after
222+ die "PACKCHECK_GITHUB_COMMIT is not specified."
208− # "raw/", and put the job name after "job=".
223+ fi
209− # Also see https://github.com/mpickering/ghc-artefact-nix/blob/master/gitlab-artifact.nix
224+ PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh
210− ./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
225+ curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1
211− else
226+ chmod +x $PACKCHECK
212− ./ghcup install ghc $GHCVER
227+ elif test ! -x "$PACKCHECK"
228+ then
229+ chmod +x $PACKCHECK
213 fi
230 fi
214− ./ghcup install cabal $CABALVER
215− ./ghcup set ghc $GHCVER
216− ./ghcup set cabal $CABALVER
217
231
218 - name: Run tests
232 - name: Run tests
219 run: |
233 run: |
220− if test -n "$DOCTEST"
221− then
222− mkdir -p $HOME/.cabal/bin
223− 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
224− echo '0829bd034fba901cbcfe491d98ed8b28fd54f9cb5c91fa8e1ac62dc4413c9562 cabal-docspec.xz' | sha256sum -c -
225− xz -d < cabal-docspec.xz > $HOME/.cabal/bin/cabal-docspec
226− rm -f cabal-docspec.xz
227− chmod a+x $HOME/.cabal/bin/cabal-docspec
228− cabal update
229− cabal build --project-file cabal.project.doctest all
230− $HOME/.cabal/bin/cabal-docspec --version
231− $HOME/.cabal/bin/cabal-docspec --timeout 60 --check-properties --property-variables xs
232− elif test -n "$COVERAGE"
234+ if test -n "$COVERAGE"
233 then
235 then
234 # Run tests with coverage
236 # Run tests with coverage
235 cabal update
237 cabal update
@@ -242,16 +244,15 @@ jobs:
242 # XXX Uncomment this and fix it properly later
244 # XXX Uncomment this and fix it properly later
243 # hpc-coveralls --repo-token="$COVERALLS_TOKEN" --coverage-mode=StrictlyFullLines
245 # hpc-coveralls --repo-token="$COVERALLS_TOKEN" --coverage-mode=StrictlyFullLines
244 else
246 else
245− export TOOLS_DIR=/opt
246 # /usr/local/opt/curl/bin for macOS
247 # /usr/local/opt/curl/bin for macOS
247 export PATH=$HOME/.local/bin:$HOME/.ghcup/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/opt/curl/bin
248 export PATH=$HOME/.local/bin:$HOME/.ghcup/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/opt/curl/bin
248 if test -n "$SUBDIR"
249 if test -n "$SUBDIR"
249 then
250 then
250− mv "$PACKCHECK_LOCAL_PATH" "$SUBDIR/packcheck.sh"
251+ mv "$PACKCHECK" "$SUBDIR/packcheck.sh"
251 # This is required as dist-newstyle will be created on the top level
252 # This is required as dist-newstyle will be created on the top level
252 # directory as it is considered the working dir.
253 # directory as it is considered the working dir.
253 rm cabal.project
254 rm cabal.project
254 cd "$SUBDIR"
255 cd "$SUBDIR"
255 fi
256 fi
256− bash -c "$PACKCHECK_LOCAL_PATH $BUILD"
257+ bash -c "$PACKCHECK $BUILD"
257 fi
258 fi
.hlint.ignore+5
@@ -2,6 +2,9 @@ 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
5test/Streamly/Test/Data/Array.hs
8test/Streamly/Test/Data/Array.hs
6test/Streamly/Test/Data/Parser.hs
9test/Streamly/Test/Data/Parser.hs
7test/Streamly/Test/Data/ParserK.hs
10test/Streamly/Test/Data/ParserK.hs
@@ -10,6 +13,7 @@ test/Streamly/Test/Data/Unfold.hs
10test/Streamly/Test/FileSystem/Event.hs
13test/Streamly/Test/FileSystem/Event.hs
11test/Streamly/Test/Prelude/Concurrent.hs
14test/Streamly/Test/Prelude/Concurrent.hs
12test/Streamly/Test/Data/Stream/Concurrent.hs
15test/Streamly/Test/Data/Stream/Concurrent.hs
16+test/lib/Streamly/Test/Prelude/Common.hs
13test/Streamly/Test/Prelude/Fold.hs
17test/Streamly/Test/Prelude/Fold.hs
14test/Streamly/Test/Prelude/Rate.hs
18test/Streamly/Test/Prelude/Rate.hs
15test/Streamly/Test/Prelude/Serial.hs
19test/Streamly/Test/Prelude/Serial.hs
@@ -27,6 +31,7 @@ benchmark/Streamly/Benchmark/Data/Stream/StreamK.hs
27benchmark/Streamly/Benchmark/Data/Unfold.hs
31benchmark/Streamly/Benchmark/Data/Unfold.hs
28benchmark/Streamly/Benchmark/FileSystem/Handle.hs
32benchmark/Streamly/Benchmark/FileSystem/Handle.hs
29benchmark/Streamly/Benchmark/Prelude/Async.hs
33benchmark/Streamly/Benchmark/Prelude/Async.hs
34+benchmark/Streamly/Benchmark/Prelude/Concurrent.hs
30benchmark/Streamly/Benchmark/Prelude/Merge.hs
35benchmark/Streamly/Benchmark/Prelude/Merge.hs
31benchmark/Streamly/Benchmark/Prelude/Parallel.hs
36benchmark/Streamly/Benchmark/Prelude/Parallel.hs
32benchmark/Streamly/Benchmark/Prelude/Rate.hs
37benchmark/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 Gauge
21+import Test.Tasty.Bench
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 Gauge
12+import Test.Tasty.Bench
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.Stream.Chunked as ArrayStream
42+import qualified Streamly.Internal.Data.Array.Stream 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 Gauge hiding (env)
50+import Test.Tasty.Bench 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.Unbox (Unbox)
56+import Streamly.Internal.Data.MutByteArray (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 Gauge
44+import Test.Tasty.Bench
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 Gauge
16+import Test.Tasty.Bench
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 Gauge
52+import Test.Tasty.Bench
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+3−3
@@ -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 Gauge hiding (env)
52+import Test.Tasty.Bench 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 fextract) =
351+takeWhileFail predicate (Fold fstep finitial _ ffinal) =
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 fextract) =
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) (fextract s)
372+ extract s = fmap (Done 0) (ffinal s)
373
373
374{-# INLINE alt2 #-}
374{-# INLINE alt2 #-}
375alt2 :: Monad m
375alt2 :: Monad m
benchmark/Streamly/Benchmark/Data/ParserK.hs+3−3
@@ -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 Gauge
51+import Test.Tasty.Bench
52import Streamly.Benchmark.Common
52import Streamly.Benchmark.Common
53
53
54-------------------------------------------------------------------------------
54-------------------------------------------------------------------------------
@@ -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 fextract) =
216+takeWhileFailD predicate (Fold fstep finitial _ ffinal) =
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 fextract) =
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) (fextract s)
237+ extract s = fmap (Done 0) (ffinal 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 Gauge
19+import Test.Tasty.Bench
20import Streamly.Benchmark.Common
20import Streamly.Benchmark.Common
21
21
22import Prelude as P
22import Prelude as P
benchmark/Streamly/Benchmark/Data/Serialize.hs+34−48
@@ -1,4 +1,5 @@
1{-# LANGUAGE TemplateHaskell #-}
1{-# LANGUAGE TemplateHaskell #-}
2+{- HLINT ignore -}
2
3
3#undef FUSION_CHECK
4#undef FUSION_CHECK
4#ifdef FUSION_CHECK
5#ifdef FUSION_CHECK
@@ -18,31 +19,23 @@ module Main (main) where
18-------------------------------------------------------------------------------
19-------------------------------------------------------------------------------
19
20
20import Control.DeepSeq (NFData(..), deepseq)
21import Control.DeepSeq (NFData(..), deepseq)
22+import Control.Monad (when, void)
21import GHC.Generics (Generic)
23import GHC.Generics (Generic)
22import System.Random (randomRIO)
24import System.Random (randomRIO)
23#ifndef USE_UNBOX
25#ifndef USE_UNBOX
24import Test.QuickCheck (Arbitrary, arbitrary)
26import Test.QuickCheck (Arbitrary, arbitrary)
25#endif
27#endif
26
28
29+import Streamly.Internal.Data.MutByteArray
30+import qualified Streamly.Internal.Data.MutByteArray as MBA
27#ifdef USE_UNBOX
31#ifdef USE_UNBOX
28import Data.Proxy (Proxy(..))
32import Data.Proxy (Proxy(..))
29−import Streamly.Internal.Data.Unbox
30#else
33#else
31import Control.DeepSeq (force)
34import Control.DeepSeq (force)
32import Test.QuickCheck (oneof, generate)
35import Test.QuickCheck (oneof, generate)
33−import Streamly.Internal.Data.Unbox (newBytes, MutableByteArray)
34−import Streamly.Internal.Data.Serialize hiding (encode)
35#endif
36#endif
36
37
37−#ifdef USE_TH
38+import Test.Tasty.Bench
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
46import Streamly.Benchmark.Common
39import Streamly.Benchmark.Common
47
40
48#ifndef USE_UNBOX
41#ifndef USE_UNBOX
@@ -52,14 +45,14 @@ import Streamly.Benchmark.Data.Serialize.RecNonCompatible
52
45
53#ifdef USE_UNBOX
46#ifdef USE_UNBOX
54#define SERIALIZE_CLASS Unbox
47#define SERIALIZE_CLASS Unbox
55−#define DERIVE_CLASS deriveUnbox
48+#define DERIVE_CLASS(typ) $(deriveUnbox [d|instance Unbox typ|])
56−#define SERIALIZE_OP pokeByteIndex
49+#define SERIALIZE_OP pokeAt
57−#define DESERIALIZE_OP peekByteIndex
50+#define DESERIALIZE_OP peekAt
58#else
51#else
59#define SERIALIZE_CLASS Serialize
52#define SERIALIZE_CLASS Serialize
60−#define DERIVE_CLASS deriveSerialize
53+#define DERIVE_CLASS(typ) $(deriveSerialize [d|instance Serialize typ|])
61−#define SERIALIZE_OP serialize
54+#define SERIALIZE_OP serializeAt
62−#define DESERIALIZE_OP deserialize
55+#define DESERIALIZE_OP deserializeAt
63#endif
56#endif
64
57
65-------------------------------------------------------------------------------
58-------------------------------------------------------------------------------
@@ -72,7 +65,7 @@ data Unit = Unit
72#ifndef USE_TH
65#ifndef USE_TH
73instance SERIALIZE_CLASS Unit
66instance SERIALIZE_CLASS Unit
74#else
67#else
75−$(DERIVE_CLASS ''Unit)
68+DERIVE_CLASS(Unit)
76#endif
69#endif
77
70
78instance NFData Unit where
71instance NFData Unit where
@@ -87,7 +80,7 @@ data Sum2
87#ifndef USE_TH
80#ifndef USE_TH
88instance SERIALIZE_CLASS Sum2
81instance SERIALIZE_CLASS Sum2
89#else
82#else
90−$(DERIVE_CLASS ''Sum2)
83+DERIVE_CLASS(Sum2)
91#endif
84#endif
92
85
93instance NFData Sum2 where
86instance NFData Sum2 where
@@ -125,7 +118,7 @@ data Sum25
125#ifndef USE_TH
118#ifndef USE_TH
126instance SERIALIZE_CLASS Sum25
119instance SERIALIZE_CLASS Sum25
127#else
120#else
128−$(DERIVE_CLASS ''Sum25)
121+DERIVE_CLASS(Sum25)
129#endif
122#endif
130
123
131instance NFData Sum25 where
124instance NFData Sum25 where
@@ -164,7 +157,7 @@ data Product25
164#ifndef USE_TH
157#ifndef USE_TH
165instance SERIALIZE_CLASS Product25
158instance SERIALIZE_CLASS Product25
166#else
159#else
167−$(DERIVE_CLASS ''Product25)
160+DERIVE_CLASS(Product25)
168#endif
161#endif
169
162
170instance NFData Product25 where
163instance NFData Product25 where
@@ -244,7 +237,7 @@ data CustomDT1
244#ifndef USE_TH
237#ifndef USE_TH
245instance SERIALIZE_CLASS CustomDT1
238instance SERIALIZE_CLASS CustomDT1
246#else
239#else
247−$(DERIVE_CLASS ''CustomDT1)
240+DERIVE_CLASS(CustomDT1)
248#endif
241#endif
249
242
250instance NFData CustomDT1 where
243instance NFData CustomDT1 where
@@ -267,19 +260,20 @@ data BinTree a
267#ifndef USE_TH
260#ifndef USE_TH
268instance Serialize (BinTree a)
261instance Serialize (BinTree a)
269#else
262#else
270−$(deriveSerialize ''BinTree)
263+$(deriveSerialize [d|instance Serialize a => Serialize (BinTree a)|])
271#endif
264#endif
272
265
273instance NFData a => NFData (BinTree a) where
266instance NFData a => NFData (BinTree a) where
274 {-# INLINE rnf #-}
267 {-# INLINE rnf #-}
275 rnf (Leaf a) = rnf a `seq` ()
268 rnf (Leaf a) = rnf a `seq` ()
276− rnf (Tree l r) = rnf l `seq` rnf r `seq` ()
269+ rnf (Tree l r) = rnf l `seq` rnf r
277
270
271+-- XXX This may not terminate, or could become really large.
278instance Arbitrary a => Arbitrary (BinTree a) where
272instance Arbitrary a => Arbitrary (BinTree a) where
279 arbitrary = oneof [Leaf <$> arbitrary, Tree <$> arbitrary <*> arbitrary]
273 arbitrary = oneof [Leaf <$> arbitrary, Tree <$> arbitrary <*> arbitrary]
280
274
281mkBinTree :: (Arbitrary a) => Int -> IO (BinTree a)
275mkBinTree :: (Arbitrary a) => Int -> IO (BinTree a)
282−mkBinTree = go (generate $ arbitrary)
276+mkBinTree = go (generate arbitrary)
283
277
284 where
278 where
285
279
@@ -297,23 +291,21 @@ getSize :: forall a. SERIALIZE_CLASS a => a -> Int
297#ifdef USE_UNBOX
291#ifdef USE_UNBOX
298getSize _ = sizeOf (Proxy :: Proxy a)
292getSize _ = sizeOf (Proxy :: Proxy a)
299#else
293#else
300−getSize = size 0
294+getSize = addSizeTo 0
301#endif
295#endif
302
296
303-------------------------------------------------------------------------------
297-------------------------------------------------------------------------------
304-- Common helpers
298-- Common helpers
305-------------------------------------------------------------------------------
299-------------------------------------------------------------------------------
306
300
301+{- HLINT ignore "Eta reduce" -}
307-- Parts of "f" that are dependent on val will not be optimized out.
302-- Parts of "f" that are dependent on val will not be optimized out.
308{-# INLINE loop #-}
303{-# INLINE loop #-}
309loop :: Int -> (a -> IO b) -> a -> IO ()
304loop :: Int -> (a -> IO b) -> a -> IO ()
310loop count f val = go count val
305loop count f val = go count val
311 where
306 where
312
307
313− go n x = do
314− if n > 0
315− then f x >> go (n-1) x
308+ go n x = when (n > 0) $ f x >> go (n-1) x
316− else return ()
317
309
318-- The first arg of "f" is the environment which is not threaded around in the
310-- The first arg of "f" is the environment which is not threaded around in the
319-- loop.
311-- loop.
@@ -322,10 +314,7 @@ loopWith :: Int -> (e -> a -> IO b) -> e -> a -> IO ()
322loopWith count f e val = go count val
314loopWith count f e val = go count val
323 where
315 where
324
316
325− go n x = do
326− if n > 0
327− then f e x >> go (n-1) x
317+ go n x = when (n > 0) $ f e x >> go (n-1) x
328− else return ()
329
318
330benchSink :: NFData b => String -> Int -> (Int -> IO b) -> Benchmark
319benchSink :: NFData b => String -> Int -> (Int -> IO b) -> Benchmark
331benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
320benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
@@ -336,7 +325,7 @@ benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
336
325
337{-
326{-
338{-# INLINE pokeWithSize #-}
327{-# INLINE pokeWithSize #-}
339−pokeWithSize :: SERIALIZE_CLASS a => MutableByteArray -> a -> IO ()
328+pokeWithSize :: SERIALIZE_CLASS a => MutByteArray -> a -> IO ()
340pokeWithSize arr val = do
329pokeWithSize arr val = do
341 let n = getSize val
330 let n = getSize val
342 n `seq` SERIALIZE_OP 0 arr val >> return ()
331 n `seq` SERIALIZE_OP 0 arr val >> return ()
@@ -345,27 +334,27 @@ pokeWithSize arr val = do
345pokeTimesWithSize :: SERIALIZE_CLASS a => a -> Int -> IO ()
334pokeTimesWithSize :: SERIALIZE_CLASS a => a -> Int -> IO ()
346pokeTimesWithSize val times = do
335pokeTimesWithSize val times = do
347 let n = getSize val
336 let n = getSize val
348− arr <- newBytes n
337+ arr <- MBA.new n
349 loopWith times pokeWithSize arr val
338 loopWith times pokeWithSize arr val
350-}
339-}
351
340
352{-# INLINE poke #-}
341{-# INLINE poke #-}
353−poke :: SERIALIZE_CLASS a => MutableByteArray -> a -> IO ()
342+poke :: SERIALIZE_CLASS a => MutByteArray -> a -> IO ()
354−poke arr val = SERIALIZE_OP 0 arr val >> return ()
343+poke arr val = void (SERIALIZE_OP 0 arr val)
355
344
356{-# INLINE pokeTimes #-}
345{-# INLINE pokeTimes #-}
357pokeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
346pokeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
358pokeTimes val times = do
347pokeTimes val times = do
359 let n = getSize val
348 let n = getSize val
360− arr <- newBytes n
349+ arr <- MBA.new n
361 loopWith times poke arr val
350 loopWith times poke arr val
362
351
363{-# INLINE encode #-}
352{-# INLINE encode #-}
364encode :: SERIALIZE_CLASS a => a -> IO ()
353encode :: SERIALIZE_CLASS a => a -> IO ()
365encode val = do
354encode val = do
366 let n = getSize val
355 let n = getSize val
367− arr <- newBytes n
356+ arr <- MBA.new n
368− SERIALIZE_OP 0 arr val >> return ()
357+ void (SERIALIZE_OP 0 arr val)
369
358
370{-# INLINE encodeTimes #-}
359{-# INLINE encodeTimes #-}
371encodeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
360encodeTimes :: SERIALIZE_CLASS a => a -> Int -> IO ()
@@ -373,7 +362,7 @@ encodeTimes val times = loop times encode val
373
362
374{-# INLINE peek #-}
363{-# INLINE peek #-}
375peek :: forall a. (NFData a, SERIALIZE_CLASS a) =>
364peek :: forall a. (NFData a, SERIALIZE_CLASS a) =>
376− (a, Int) -> MutableByteArray -> IO ()
365+ (a, Int) -> MutByteArray -> IO ()
377#ifdef USE_UNBOX
366#ifdef USE_UNBOX
378peek (_val, _) arr = do
367peek (_val, _) arr = do
379 (val1 :: a) <- DESERIALIZE_OP 0 arr
368 (val1 :: a) <- DESERIALIZE_OP 0 arr
@@ -400,7 +389,7 @@ peek (_val, n) arr = do
400{-# INLINE peekTimes #-}
389{-# INLINE peekTimes #-}
401peekTimes :: (NFData a, SERIALIZE_CLASS a) => Int -> a -> Int -> IO ()
390peekTimes :: (NFData a, SERIALIZE_CLASS a) => Int -> a -> Int -> IO ()
402peekTimes n val times = do
391peekTimes n val times = do
403− arr <- newBytes n
392+ arr <- MBA.new n
404 _ <- SERIALIZE_OP 0 arr val
393 _ <- SERIALIZE_OP 0 arr val
405 loopWith times peek (val, n) arr
394 loopWith times peek (val, n) arr
406
395
@@ -408,7 +397,7 @@ peekTimes n val times = do
408trip :: forall a. (NFData a, SERIALIZE_CLASS a) => a -> IO ()
397trip :: forall a. (NFData a, SERIALIZE_CLASS a) => a -> IO ()
409trip val = do
398trip val = do
410 let n = getSize val
399 let n = getSize val
411− arr <- newBytes n
400+ arr <- MBA.new n
412 _ <- SERIALIZE_OP 0 arr val
401 _ <- SERIALIZE_OP 0 arr val
413#ifdef USE_UNBOX
402#ifdef USE_UNBOX
414 (val1 :: a) <- DESERIALIZE_OP 0 arr
403 (val1 :: a) <- DESERIALIZE_OP 0 arr
@@ -571,8 +560,6 @@ main = do
571 let !len = length lInt -- evaluate the list
560 let !len = length lInt -- evaluate the list
572#endif
561#endif
573#ifndef FUSION_CHECK
562#ifndef FUSION_CHECK
574− -- This can take too much memory/CPU, need to restrict the test
575− -- runQC
576#ifdef USE_UNBOX
563#ifdef USE_UNBOX
577 runWithCLIOpts defaultStreamSize allBenchmarks
564 runWithCLIOpts defaultStreamSize allBenchmarks
578#else
565#else
@@ -580,7 +567,6 @@ main = do
580 `seq` runWithCLIOpts
567 `seq` runWithCLIOpts
581 defaultStreamSize
568 defaultStreamSize
582 (allBenchmarks tInt lInt recL recR)
569 (allBenchmarks tInt lInt recL recR)
583−
584#endif
570#endif
585#else
571#else
586 -- Enable FUSION_CHECK macro at the beginning of the file
572 -- 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.Serialize (Serialize)
12+import Streamly.Internal.Data.MutByteArray (Serialize)
13import Streamly.Benchmark.Data.Serialize.TH (genLargeRecord)
13import Streamly.Benchmark.Data.Serialize.TH (genLargeRecord)
14
14
15−import qualified Streamly.Internal.Data.Serialize.TH as Serialize
15+import qualified Streamly.Internal.Data.MutByteArray as Serialize
16
16
17--------------------------------------------------------------------------------
17--------------------------------------------------------------------------------
18-- Code
18-- Code
@@ -20,5 +20,5 @@ import qualified Streamly.Internal.Data.Serialize.TH as Serialize
20
20
21$(genLargeRecord "RecCompatible" 50)
21$(genLargeRecord "RecCompatible" 50)
22$(Serialize.deriveSerializeWith
22$(Serialize.deriveSerializeWith
23− (Serialize.defaultConfig {Serialize.recordSyntaxWithHeader = True})
23+ (Serialize.encodeRecordFields 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.Serialize.TH as Serialize
14+import qualified Streamly.Internal.Data.MutByteArray 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 ''RecNonCompatible)
21+$(Serialize.deriveSerialize [d|instance Serialize.Serialize 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.Serialize.TH.Bottom (makeI)
11+import Streamly.Internal.Data.MutByteArray (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− (const (conE '()) <$> [0 .. (numFields - 1)])))
67+ (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−1
@@ -104,7 +104,7 @@ import qualified Streamly.Internal.Data.Stream as StreamK
104#endif
104#endif
105#endif
105#endif
106
106
107−import Gauge
107+import Test.Tasty.Bench
108import Prelude hiding (Foldable(..), mapM, replicate)
108import Prelude hiding (Foldable(..), mapM, replicate)
109
109
110#ifdef USE_STREAMK
110#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.Concurrent (MonadAsync, Config)
17+import Streamly.Internal.Data.Stream.Prelude (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.Concurrent as Async
22+import qualified Streamly.Internal.Data.Stream.Prelude as Async
23
23
24−import Gauge
24+import Test.Tasty.Bench
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.Concurrent as Async
12+import qualified Streamly.Internal.Data.Stream.Prelude 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.Concurrent as Async
12+import qualified Streamly.Internal.Data.Stream.Prelude 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.Concurrent as Async
12+import qualified Streamly.Internal.Data.Stream.Prelude as Async
13
13
14moduleName :: String
14moduleName :: String
15moduleName = "Data.Stream.ConcurrentOrdered"
15moduleName = "Data.Stream.ConcurrentOrdered"
benchmark/Streamly/Benchmark/Data/Stream/Eliminate.hs+3−1
@@ -57,7 +57,7 @@ import qualified Streamly.Internal.Data.Stream as StreamK
57#endif
57#endif
58#endif
58#endif
59
59
60−import Gauge
60+import Test.Tasty.Bench
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,12 +132,14 @@ 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"-}
135{-# INLINE foldableAnd #-}
136{-# INLINE foldableAnd #-}
136foldableAnd :: Int -> Int -> Bool
137foldableAnd :: Int -> Int -> Bool
137foldableAnd value n =
138foldableAnd value n =
138 Prelude.and $ fmap
139 Prelude.and $ fmap
139 (<= (value + 1)) (sourceUnfoldr value n :: Stream Identity Int)
140 (<= (value + 1)) (sourceUnfoldr value n :: Stream Identity Int)
140
141
142+{- HLINT ignore "Use any"-}
141{-# INLINE foldableOr #-}
143{-# INLINE foldableOr #-}
142foldableOr :: Int -> Int -> Bool
144foldableOr :: Int -> Int -> Bool
143foldableOr value n =
145foldableOr value n =
benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs+3−3
@@ -36,16 +36,16 @@ 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.Exception as IUF
39+import qualified Streamly.Internal.Data.Unfold.Prelude 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.Exception.Lifted as Stream
45+import qualified Streamly.Internal.Data.Stream.Prelude as Stream
46#endif
46#endif
47
47
48−import Gauge hiding (env)
48+import Test.Tasty.Bench 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
benchmark/Streamly/Benchmark/Data/Stream/Expand.hs+1−1
@@ -54,7 +54,7 @@ import qualified Streamly.Internal.Data.Stream as StreamK
54#endif
54#endif
55#endif
55#endif
56
56
57−import Gauge
57+import Test.Tasty.Bench
58import Stream.Common
58import Stream.Common
59import Streamly.Benchmark.Common
59import Streamly.Benchmark.Common
60import Prelude hiding (concatMap)
60import Prelude hiding (concatMap)
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 Gauge
43+import Test.Tasty.Bench
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 Gauge
40+import Test.Tasty.Bench
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.Time as S
51+import qualified Streamly.Internal.Data.Stream.Prelude 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 Gauge
64+import Test.Tasty.Bench
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 Gauge hiding (env)
38+import Test.Tasty.Bench 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−1
@@ -27,7 +27,7 @@ import Control.Applicative (liftA2)
27#endif
27#endif
28import Control.Monad (when)
28import Control.Monad (when)
29import Data.Maybe (isJust)
29import Data.Maybe (isJust)
30−import Gauge (bench, nfIO, bgroup, Benchmark, defaultMain)
30+import Test.Tasty.Bench (bench, nfIO, bgroup, Benchmark, defaultMain)
31import System.Random (randomRIO)
31import System.Random (randomRIO)
32import Prelude hiding (tail, mapM_, foldl, last, map, mapM, concatMap, zip)
32import Prelude hiding (tail, mapM_, foldl, last, map, mapM, concatMap, zip)
33
33
benchmark/Streamly/Benchmark/Data/Stream/StreamK.hs+1−1
@@ -37,7 +37,7 @@ import qualified Data.List as List
37
37
38import qualified Streamly.Internal.Data.StreamK as S
38import qualified Streamly.Internal.Data.StreamK as S
39
39
40−import Gauge (bench, nfIO, bgroup, Benchmark, defaultMain)
40+import Test.Tasty.Bench (bench, nfIO, bgroup, Benchmark, defaultMain)
41
41
42import Streamly.Benchmark.Common
42import Streamly.Benchmark.Common
43
43
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 Gauge (bgroup, Benchmark, defaultMain)
26+import Test.Tasty.Bench (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 $ concat [o_1_space]
455+main = defaultMain [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 Gauge (bgroup, Benchmark, defaultMain)
40+import Test.Tasty.Bench (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 S.nil (Prelude.fmap return [n..n+streamLen])
123+ Prelude.foldr (S.consM . return) S.nil [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.Time as Stream
49+import qualified Streamly.Internal.Data.Stream.Prelude 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 Gauge
61+import Test.Tasty.Bench
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−2
@@ -31,12 +31,12 @@ 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.Exception as UF
34+import qualified Streamly.Internal.Data.Unfold.Prelude 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 Gauge hiding (env)
39+import Test.Tasty.Bench 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
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 Gauge hiding (env)
25+import Test.Tasty.Bench 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+8−9
@@ -33,7 +33,6 @@ import qualified Streamly.Data.Stream as Stream
33import qualified Streamly.Data.Fold as Fold
33import qualified Streamly.Data.Fold as Fold
34import qualified Streamly.FileSystem.Handle as FH
34import qualified Streamly.FileSystem.Handle as FH
35import qualified Streamly.Internal.Data.Array as A
35import qualified Streamly.Internal.Data.Array as A
36−import qualified Streamly.Internal.Data.Array as AT
37import qualified Streamly.Internal.Data.Fold as FL
36import qualified Streamly.Internal.Data.Fold as FL
38import qualified Streamly.Internal.Data.Stream as IP
37import qualified Streamly.Internal.Data.Stream as IP
39import qualified Streamly.Internal.FileSystem.Handle as IFH
38import qualified Streamly.Internal.FileSystem.Handle as IFH
@@ -41,14 +40,14 @@ import qualified Streamly.Internal.Unicode.Stream as IUS
41import qualified Streamly.Data.Stream.Prelude as S
40import qualified Streamly.Data.Stream.Prelude as S
42import qualified Streamly.Unicode.Stream as SS
41import qualified Streamly.Unicode.Stream as SS
43
42
44−import Gauge hiding (env)
43+import Test.Tasty.Bench hiding (env)
45import Prelude hiding (last, length)
44import Prelude hiding (last, length)
46import Streamly.Benchmark.Common.Handle
45import Streamly.Benchmark.Common.Handle
47
46
48#ifdef INSPECTION
47#ifdef INSPECTION
49import Streamly.Internal.Data.Stream (Step(..), FoldMany)
48import Streamly.Internal.Data.Stream (Step(..), FoldMany)
50
49
51−import qualified Streamly.Internal.Data.MutArray as MA
50+import qualified Streamly.Internal.Data.MutArray as MutArray
52import qualified Streamly.Internal.Data.Stream as D
51import qualified Streamly.Internal.Data.Stream as D
53import qualified Streamly.Internal.Data.Unfold as IUF
52import qualified Streamly.Internal.Data.Unfold as IUF
54
53
@@ -69,7 +68,7 @@ readLast = S.fold Fold.last . S.unfold FH.reader
69inspect $ hasNoTypeClasses 'readLast
68inspect $ hasNoTypeClasses 'readLast
70inspect $ 'readLast `hasNoType` ''Step -- S.unfold
69inspect $ 'readLast `hasNoType` ''Step -- S.unfold
71inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
70inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
72−inspect $ 'readLast `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
71+inspect $ 'readLast `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
73#endif
72#endif
74
73
75-- assert that flattenArrays constructors are not present
74-- assert that flattenArrays constructors are not present
@@ -81,7 +80,7 @@ readCountBytes = S.fold Fold.length . S.unfold FH.reader
81inspect $ hasNoTypeClasses 'readCountBytes
80inspect $ hasNoTypeClasses 'readCountBytes
82inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
81inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
83inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
82inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
84−inspect $ 'readCountBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
83+inspect $ 'readCountBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
85#endif
84#endif
86
85
87-- | Count the number of lines in a file.
86-- | Count the number of lines in a file.
@@ -96,7 +95,7 @@ readCountLines =
96inspect $ hasNoTypeClasses 'readCountLines
95inspect $ hasNoTypeClasses 'readCountLines
97inspect $ 'readCountLines `hasNoType` ''Step
96inspect $ 'readCountLines `hasNoType` ''Step
98inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
97inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
99−inspect $ 'readCountLines `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
98+inspect $ 'readCountLines `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
100#endif
99#endif
101
100
102-- | Count the number of words in a file.
101-- | Count the number of words in a file.
@@ -120,7 +119,7 @@ readSumBytes = S.fold Fold.sum . S.unfold FH.reader
120inspect $ hasNoTypeClasses 'readSumBytes
119inspect $ hasNoTypeClasses 'readSumBytes
121inspect $ 'readSumBytes `hasNoType` ''Step
120inspect $ 'readSumBytes `hasNoType` ''Step
122inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
121inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
123−inspect $ 'readSumBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
122+inspect $ 'readSumBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
124#endif
123#endif
125
124
126-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
125-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
@@ -236,13 +235,13 @@ groupsOf :: Int -> Handle -> IO Int
236groupsOf n inh =
235groupsOf n inh =
237 -- writeNUnsafe gives 2.5x boost here over writeN.
236 -- writeNUnsafe gives 2.5x boost here over writeN.
238 S.fold Fold.length
237 S.fold Fold.length
239− $ IP.groupsOf n (AT.writeNUnsafe n) (S.unfold FH.reader inh)
238+ $ IP.groupsOf n (A.writeNUnsafe n) (S.unfold FH.reader inh)
240
239
241#ifdef INSPECTION
240#ifdef INSPECTION
242inspect $ hasNoTypeClasses 'groupsOf
241inspect $ hasNoTypeClasses 'groupsOf
243inspect $ 'groupsOf `hasNoType` ''Step
242inspect $ 'groupsOf `hasNoType` ''Step
244inspect $ 'groupsOf `hasNoType` ''FoldMany
243inspect $ 'groupsOf `hasNoType` ''FoldMany
245−inspect $ 'groupsOf `hasNoType` ''AT.ArrayUnsafe -- AT.writeNUnsafe
244+inspect $ 'groupsOf `hasNoType` ''MutArray.ArrayUnsafe -- AT.writeNUnsafe
246 -- FH.read/A.read
245 -- FH.read/A.read
247inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
246inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
248#endif
247#endif
benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs+9−10
@@ -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 Gauge hiding (env)
37+import Test.Tasty.Bench hiding (env)
38import Streamly.Benchmark.Common.Handle
38import Streamly.Benchmark.Common.Handle
39
39
40#ifdef INSPECTION
40#ifdef INSPECTION
@@ -42,8 +42,7 @@ import Streamly.Internal.Data.Stream (Step(..))
42
42
43import qualified Streamly.Internal.Data.Stream as D
43import qualified Streamly.Internal.Data.Stream as D
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
45−import qualified Streamly.Internal.Data.Stream.MutChunked as MAS
45+import qualified Streamly.Internal.Data.MutArray as MutArray
46−import qualified Streamly.Internal.Data.Array as AT
47
46
48import Test.Inspection
47import Test.Inspection
49#endif
48#endif
@@ -83,7 +82,7 @@ copyStream inh outh = S.fold (FH.write outh) (S.unfold FH.reader inh)
83inspect $ hasNoTypeClasses 'copyStream
82inspect $ hasNoTypeClasses 'copyStream
84inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
83inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
85inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
84inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
86−inspect $ 'copyStream `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
85+inspect $ 'copyStream `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
87 -- FH.read/A.read
86 -- FH.read/A.read
88inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
87inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
89#endif
88#endif
@@ -109,8 +108,8 @@ readFromBytesNull inh devNull = IFH.putBytes devNull $ S.unfold FH.reader inh
109#ifdef INSPECTION
108#ifdef INSPECTION
110inspect $ hasNoTypeClasses 'readFromBytesNull
109inspect $ hasNoTypeClasses 'readFromBytesNull
111inspect $ 'readFromBytesNull `hasNoType` ''Step
110inspect $ 'readFromBytesNull `hasNoType` ''Step
112−inspect $ 'readFromBytesNull `hasNoType` ''MAS.SpliceState
111+inspect $ 'readFromBytesNull `hasNoType` ''MutArray.SpliceState
113−inspect $ 'readFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
112+inspect $ 'readFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
114inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
113inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
115#endif
114#endif
116
115
@@ -123,8 +122,8 @@ readWithFromBytesNull inh devNull =
123#ifdef INSPECTION
122#ifdef INSPECTION
124inspect $ hasNoTypeClasses 'readWithFromBytesNull
123inspect $ hasNoTypeClasses 'readWithFromBytesNull
125inspect $ 'readWithFromBytesNull `hasNoType` ''Step
124inspect $ 'readWithFromBytesNull `hasNoType` ''Step
126−inspect $ 'readWithFromBytesNull `hasNoType` ''MAS.SpliceState
125+inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.SpliceState
127−inspect $ 'readWithFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
126+inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
128inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
127inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
129#endif
128#endif
130
129
@@ -171,7 +170,7 @@ writeReadWith inh devNull = IUF.fold fld unf (defaultChunkSize, inh)
171inspect $ hasNoTypeClasses 'writeReadWith
170inspect $ hasNoTypeClasses 'writeReadWith
172inspect $ 'writeReadWith `hasNoType` ''Step
171inspect $ 'writeReadWith `hasNoType` ''Step
173inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
172inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
174−inspect $ 'writeReadWith `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
173+inspect $ 'writeReadWith `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
175 -- FH.read/A.read
174 -- FH.read/A.read
176#endif
175#endif
177
176
@@ -188,7 +187,7 @@ writeRead inh devNull = IUF.fold fld unf inh
188inspect $ hasNoTypeClasses 'writeRead
187inspect $ hasNoTypeClasses 'writeRead
189inspect $ 'writeRead `hasNoType` ''Step
188inspect $ 'writeRead `hasNoType` ''Step
190inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
189inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
191−inspect $ 'writeRead `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
190+inspect $ 'writeRead `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
192 -- FH.read/A.read
191 -- FH.read/A.read
193#endif
192#endif
194
193
benchmark/Streamly/Benchmark/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 Gauge
13+import Test.Tasty.Bench
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 Gauge
18+import Test.Tasty.Bench
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 Gauge
19+import Test.Tasty.Bench
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 Gauge
18+import Test.Tasty.Bench
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 Gauge
33+import Test.Tasty.Bench
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 Gauge
25+import Test.Tasty.Bench
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 Gauge
17+import Test.Tasty.Bench
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 Gauge
18+import Test.Tasty.Bench
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 Gauge
32+import Test.Tasty.Bench
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 Gauge
18+import Test.Tasty.Bench
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 Gauge
32+import Test.Tasty.Bench
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 Gauge.Main (Benchmark, bench, bgroup, defaultMain, env, nfIO)
19+import Test.Tasty.Bench (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 Gauge hiding (env)
34+import Test.Tasty.Bench 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+24−6
@@ -11,6 +11,11 @@
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+
14#ifdef __HADDOCK_VERSION__
19#ifdef __HADDOCK_VERSION__
15#undef INSPECTION
20#undef INSPECTION
16#endif
21#endif
@@ -33,16 +38,17 @@ import qualified Streamly.Internal.FileSystem.Handle as Handle
33import qualified Streamly.Internal.Unicode.Array as UnicodeArr
38import qualified Streamly.Internal.Unicode.Array as UnicodeArr
34import qualified Streamly.Internal.Unicode.Stream as Unicode
39import qualified Streamly.Internal.Unicode.Stream as Unicode
35
40
36−import Gauge hiding (env)
41+import Test.Tasty.Bench hiding (env)
37import Streamly.Benchmark.Common
42import Streamly.Benchmark.Common
38import Streamly.Benchmark.Common.Handle
43import Streamly.Benchmark.Common.Handle
39
44
40#ifdef INSPECTION
45#ifdef INSPECTION
41−import Streamly.Internal.Data.Unbox (Unbox)
46+import Streamly.Internal.Data.MutByteArray (Unbox)
42import Streamly.Internal.Data.Stream (Step(..))
47import Streamly.Internal.Data.Stream (Step(..))
48+import qualified Streamly.Internal.Data.Array as Array
49+import qualified Streamly.Internal.Data.MutArray as MutArray
43import qualified Streamly.Internal.Data.Fold as Fold
50import qualified Streamly.Internal.Data.Fold as Fold
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
51import qualified Streamly.Internal.Data.Tuple.Strict as Strict
45−import qualified Streamly.Internal.Data.Array as Array
46
52
47import Test.Inspection
53import Test.Inspection
48#endif
54#endif
@@ -218,7 +224,7 @@ inspect $ 'copyStreamLatin1' `hasNoType` ''Step
218inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
224inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
219
225
220inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
226inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
221−inspect $ 'copyStreamLatin1' `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
227+inspect $ 'copyStreamLatin1' `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
222 -- Handle.read/Array.read
228 -- Handle.read/Array.read
223inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
229inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
224#endif
230#endif
@@ -239,7 +245,7 @@ inspect $ 'copyStreamLatin1 `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.m
239
245
240inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
246inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
241inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
247inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
242−inspect $ 'copyStreamLatin1 `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
248+inspect $ 'copyStreamLatin1 `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
243 -- Handle.read/Array.read
249 -- Handle.read/Array.read
244inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
250inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
245#endif
251#endif
@@ -280,7 +286,8 @@ _copyStreamUtf8'Fold :: Handle -> Handle -> IO ()
280_copyStreamUtf8'Fold inh outh =
286_copyStreamUtf8'Fold inh outh =
281 Stream.fold (Handle.write outh)
287 Stream.fold (Handle.write outh)
282 $ Unicode.encodeUtf8
288 $ Unicode.encodeUtf8
289+ $ Stream.catRights
283− $ Stream.foldMany Unicode.writeCharUtf8'
290+ $ Stream.parseMany Unicode.writeCharUtf8'
284 $ Stream.unfold Handle.reader inh
291 $ Stream.unfold Handle.reader inh
285
292
286{-# NOINLINE _copyStreamUtf8Parser #-}
293{-# NOINLINE _copyStreamUtf8Parser #-}
@@ -317,6 +324,7 @@ o_1_space_decode_encode_read env =
317
324
318main :: IO ()
325main :: IO ()
319main = do
326main = do
327+#ifndef FUSION_CHECK
320 env <- mkHandleBenchEnv
328 env <- mkHandleBenchEnv
321 defaultMain (allBenchmarks env)
329 defaultMain (allBenchmarks env)
322
330
@@ -329,3 +337,13 @@ main = do
329 , o_1_space_decode_encode_read env
337 , o_1_space_decode_encode_read env
330 ]
338 ]
331 ]
339 ]
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 Gauge hiding (env)
16+import Test.Tasty.Bench 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/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 Gauge
59+import Test.Tasty.Bench
60
60
61-------------------------------------------------------------------------------
61-------------------------------------------------------------------------------
62-- Benchmark Prefixes
62-- Benchmark Prefixes
benchmark/lib/Streamly/Benchmark/Common/Handle.hs+3−1
@@ -30,6 +30,8 @@ module Streamly.Benchmark.Common.Handle
30 , isSpace
30 , isSpace
31 , isSp
31 , isSp
32 , mkHandleBenchEnv
32 , mkHandleBenchEnv
33+ , Handles(..)
34+ , getHandles
33 )
35 )
34where
36where
35
37
@@ -46,7 +48,7 @@ import System.Process (callCommand)
46
48
47import Data.IORef
49import Data.IORef
48import Prelude hiding (last, length)
50import Prelude hiding (last, length)
49−import Gauge hiding (env)
51+import Test.Tasty.Bench hiding (env)
50
52
51
53
52scratchDir :: String
54scratchDir :: 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 Gauge
85+import Test.Tasty.Bench
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+5−20
@@ -54,11 +54,6 @@ 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−
62flag use-streamly-core
57flag use-streamly-core
63 description: Benchmark only core package
58 description: Benchmark only core package
64 manual: True
59 manual: True
@@ -193,24 +188,14 @@ common bench-depends
193 , unordered-containers >= 0.2 && < 0.3
188 , unordered-containers >= 0.2 && < 0.3
194 , process >= 1.4 && < 1.7
189 , process >= 1.4 && < 1.7
195 , directory >= 1.2.2 && < 1.4
190 , directory >= 1.2.2 && < 1.4
196− , filepath >= 1.4.1 && < 1.5
191+ , filepath >= 1.4.1 && < 1.6
197 , ghc-prim >= 0.4 && < 0.12
192 , ghc-prim >= 0.4 && < 0.12
193+ , tasty-bench >= 0.3 && < 0.4
194+ , tasty >= 1.4.1 && < 1.6
195+ , streamly-core
198
196
199− if flag(use-streamly-core)
197+ if !flag(use-streamly-core)
200− build-depends: streamly-core
201− else
202 build-depends: streamly
198 build-depends: streamly
203− , streamly-core
204−
205− if flag(use-gauge)
206− build-depends: gauge >= 0.2.4 && < 0.3
207− else
208− build-depends: tasty-bench >= 0.3 && < 0.4
209− , tasty >= 1.4.1 && < 1.6
210− mixins: tasty-bench
211− (Test.Tasty.Bench as Gauge
212− , Test.Tasty.Bench as Gauge.Main
213− )
214
199
215 if flag(fusion-plugin) && !impl(ghcjs) && !impl(ghc < 8.6)
200 if flag(fusion-plugin) && !impl(ghcjs) && !impl(ghc < 8.6)
216 build-depends:
201 build-depends:
configure+9−9
@@ -1,6 +1,6 @@
1#! /bin/sh
1#! /bin/sh
2# Guess values for system-dependent variables and create Makefiles.
2# Guess values for system-dependent variables and create Makefiles.
3−# Generated by GNU Autoconf 2.71 for streamly 0.10.0.
3+# Generated by GNU Autoconf 2.71 for streamly 0.10.1.
4#
4#
5# Report bugs to <streamly@composewell.com>.
5# Report bugs to <streamly@composewell.com>.
6#
6#
@@ -610,8 +610,8 @@ MAKEFLAGS=
610# Identity of this package.
610# Identity of this package.
611PACKAGE_NAME='streamly'
611PACKAGE_NAME='streamly'
612PACKAGE_TARNAME='streamly'
612PACKAGE_TARNAME='streamly'
613−PACKAGE_VERSION='0.10.0'
613+PACKAGE_VERSION='0.10.1'
614−PACKAGE_STRING='streamly 0.10.0'
614+PACKAGE_STRING='streamly 0.10.1'
615PACKAGE_BUGREPORT='streamly@composewell.com'
615PACKAGE_BUGREPORT='streamly@composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
617
617
@@ -1224,7 +1224,7 @@ if test "$ac_init_help" = "long"; then
1224 # Omit some internal or obsolete options to make the list less imposing.
1224 # Omit some internal or obsolete options to make the list less imposing.
1225 # This message is too long to be a string in the A/UX 3.1 sh.
1225 # This message is too long to be a string in the A/UX 3.1 sh.
1226 cat <<_ACEOF
1226 cat <<_ACEOF
1227−\`configure' configures streamly 0.10.0 to adapt to many kinds of systems.
1227+\`configure' configures streamly 0.10.1 to adapt to many kinds of systems.
1228
1228
1229Usage: $0 [OPTION]... [VAR=VALUE]...
1229Usage: $0 [OPTION]... [VAR=VALUE]...
1230
1230
@@ -1286,7 +1286,7 @@ fi
1286
1286
1287if test -n "$ac_init_help"; then
1287if test -n "$ac_init_help"; then
1288 case $ac_init_help in
1288 case $ac_init_help in
1289− short | recursive ) echo "Configuration of streamly 0.10.0:";;
1289+ short | recursive ) echo "Configuration of streamly 0.10.1:";;
1290 esac
1290 esac
1291 cat <<\_ACEOF
1291 cat <<\_ACEOF
1292
1292
@@ -1372,7 +1372,7 @@ fi
1372test -n "$ac_init_help" && exit $ac_status
1372test -n "$ac_init_help" && exit $ac_status
1373if $ac_init_version; then
1373if $ac_init_version; then
1374 cat <<\_ACEOF
1374 cat <<\_ACEOF
1375−streamly configure 0.10.0
1375+streamly configure 0.10.1
1376generated by GNU Autoconf 2.71
1376generated by GNU Autoconf 2.71
1377
1377
1378Copyright (C) 2021 Free Software Foundation, Inc.
1378Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1500,7 +1500,7 @@ cat >config.log <<_ACEOF
1500This file contains any messages produced by compilers while
1500This file contains any messages produced by compilers while
1501running configure, to aid debugging if configure makes a mistake.
1501running configure, to aid debugging if configure makes a mistake.
1502
1502
1503−It was created by streamly $as_me 0.10.0, which was
1503+It was created by streamly $as_me 0.10.1, which was
1504generated by GNU Autoconf 2.71. Invocation command line was
1504generated by GNU Autoconf 2.71. Invocation command line was
1505
1505
1506 $ $0$ac_configure_args_raw
1506 $ $0$ac_configure_args_raw
@@ -3800,7 +3800,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
3800# report actual input values of CONFIG_FILES etc. instead of their
3800# report actual input values of CONFIG_FILES etc. instead of their
3801# values after options handling.
3801# values after options handling.
3802ac_log="
3802ac_log="
3803−This file was extended by streamly $as_me 0.10.0, which was
3803+This file was extended by streamly $as_me 0.10.1, which was
3804generated by GNU Autoconf 2.71. Invocation command line was
3804generated by GNU Autoconf 2.71. Invocation command line was
3805
3805
3806 CONFIG_FILES = $CONFIG_FILES
3806 CONFIG_FILES = $CONFIG_FILES
@@ -3856,7 +3856,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
3856cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3856cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3857ac_cs_config='$ac_cs_config_escaped'
3857ac_cs_config='$ac_cs_config_escaped'
3858ac_cs_version="\\
3858ac_cs_version="\\
3859−streamly config.status 0.10.0
3859+streamly config.status 0.10.1
3860configured by $0, generated by GNU Autoconf 2.71,
3860configured by $0, generated by GNU Autoconf 2.71,
3861 with options \\"\$ac_cs_config\\"
3861 with options \\"\$ac_cs_config\\"
3862
3862
configure.ac+1−1
@@ -3,7 +3,7 @@
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
4# the macros used in this file.
4# the macros used in this file.
5
5
6−AC_INIT([streamly], [0.10.0], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
6+AC_INIT([streamly], [0.10.1], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
7
7
8# To suppress "WARNING: unrecognized options: --with-compiler"
8# To suppress "WARNING: unrecognized options: --with-compiler"
9AC_ARG_WITH([compiler], [GHC])
9AC_ARG_WITH([compiler], [GHC])
core/configure+9−9
@@ -1,6 +1,6 @@
1#! /bin/sh
1#! /bin/sh
2# Guess values for system-dependent variables and create Makefiles.
2# Guess values for system-dependent variables and create Makefiles.
3−# Generated by GNU Autoconf 2.71 for streamly-core 0.2.0.
3+# Generated by GNU Autoconf 2.71 for streamly-core 0.2.2.
4#
4#
5# Report bugs to <streamly@composewell.com>.
5# Report bugs to <streamly@composewell.com>.
6#
6#
@@ -610,8 +610,8 @@ MAKEFLAGS=
610# Identity of this package.
610# Identity of this package.
611PACKAGE_NAME='streamly-core'
611PACKAGE_NAME='streamly-core'
612PACKAGE_TARNAME='streamly-core'
612PACKAGE_TARNAME='streamly-core'
613−PACKAGE_VERSION='0.2.0'
613+PACKAGE_VERSION='0.2.2'
614−PACKAGE_STRING='streamly-core 0.2.0'
614+PACKAGE_STRING='streamly-core 0.2.2'
615PACKAGE_BUGREPORT='streamly@composewell.com'
615PACKAGE_BUGREPORT='streamly@composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
617
617
@@ -1256,7 +1256,7 @@ if test "$ac_init_help" = "long"; then
1256 # Omit some internal or obsolete options to make the list less imposing.
1256 # Omit some internal or obsolete options to make the list less imposing.
1257 # This message is too long to be a string in the A/UX 3.1 sh.
1257 # This message is too long to be a string in the A/UX 3.1 sh.
1258 cat <<_ACEOF
1258 cat <<_ACEOF
1259−\`configure' configures streamly-core 0.2.0 to adapt to many kinds of systems.
1259+\`configure' configures streamly-core 0.2.2 to adapt to many kinds of systems.
1260
1260
1261Usage: $0 [OPTION]... [VAR=VALUE]...
1261Usage: $0 [OPTION]... [VAR=VALUE]...
1262
1262
@@ -1318,7 +1318,7 @@ fi
1318
1318
1319if test -n "$ac_init_help"; then
1319if test -n "$ac_init_help"; then
1320 case $ac_init_help in
1320 case $ac_init_help in
1321− short | recursive ) echo "Configuration of streamly-core 0.2.0:";;
1321+ short | recursive ) echo "Configuration of streamly-core 0.2.2:";;
1322 esac
1322 esac
1323 cat <<\_ACEOF
1323 cat <<\_ACEOF
1324
1324
@@ -1404,7 +1404,7 @@ fi
1404test -n "$ac_init_help" && exit $ac_status
1404test -n "$ac_init_help" && exit $ac_status
1405if $ac_init_version; then
1405if $ac_init_version; then
1406 cat <<\_ACEOF
1406 cat <<\_ACEOF
1407−streamly-core configure 0.2.0
1407+streamly-core configure 0.2.2
1408generated by GNU Autoconf 2.71
1408generated by GNU Autoconf 2.71
1409
1409
1410Copyright (C) 2021 Free Software Foundation, Inc.
1410Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1622,7 +1622,7 @@ cat >config.log <<_ACEOF
1622This file contains any messages produced by compilers while
1622This file contains any messages produced by compilers while
1623running configure, to aid debugging if configure makes a mistake.
1623running configure, to aid debugging if configure makes a mistake.
1624
1624
1625−It was created by streamly-core $as_me 0.2.0, which was
1625+It was created by streamly-core $as_me 0.2.2, which was
1626generated by GNU Autoconf 2.71. Invocation command line was
1626generated by GNU Autoconf 2.71. Invocation command line was
1627
1627
1628 $ $0$ac_configure_args_raw
1628 $ $0$ac_configure_args_raw
@@ -3832,7 +3832,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
3832# report actual input values of CONFIG_FILES etc. instead of their
3832# report actual input values of CONFIG_FILES etc. instead of their
3833# values after options handling.
3833# values after options handling.
3834ac_log="
3834ac_log="
3835−This file was extended by streamly-core $as_me 0.2.0, which was
3835+This file was extended by streamly-core $as_me 0.2.2, which was
3836generated by GNU Autoconf 2.71. Invocation command line was
3836generated by GNU Autoconf 2.71. Invocation command line was
3837
3837
3838 CONFIG_FILES = $CONFIG_FILES
3838 CONFIG_FILES = $CONFIG_FILES
@@ -3888,7 +3888,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
3888cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3888cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3889ac_cs_config='$ac_cs_config_escaped'
3889ac_cs_config='$ac_cs_config_escaped'
3890ac_cs_version="\\
3890ac_cs_version="\\
3891−streamly-core config.status 0.2.0
3891+streamly-core config.status 0.2.2
3892configured by $0, generated by GNU Autoconf 2.71,
3892configured by $0, generated by GNU Autoconf 2.71,
3893 with options \\"\$ac_cs_config\\"
3893 with options \\"\$ac_cs_config\\"
3894
3894
core/configure.ac+1−1
@@ -3,7 +3,7 @@
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
4# the macros used in this file.
4# the macros used in this file.
5
5
6−AC_INIT([streamly-core], [0.2.0], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
6+AC_INIT([streamly-core], [0.2.2], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
7
7
8# To suppress "WARNING: unrecognized options: --with-compiler"
8# To suppress "WARNING: unrecognized options: --with-compiler"
9AC_ARG_WITH([compiler], [GHC])
9AC_ARG_WITH([compiler], [GHC])
core/docs/ApiChangelogs/0.1.0-0.2.0.txtnew file+1471
@@ -0,0 +1,1471 @@
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.txtnew file+306
@@ -0,0 +1,306 @@
1+---------------------------------
2+API Annotations
3+---------------------------------
4+
5+[A] : Added
6+[R] : Removed
7+[C] : Changed
8+[O] : Old definition
9+[N] : New definition
10+[D] : Deprecated
11+
12+---------------------------------
13+API diff
14+---------------------------------
15+
16+[C] Streamly.Data.Stream
17+ [A] (FixityR,5)
18+ [A] (FixityR,5)
19+[C] Streamly.Data.MutArray.Generic
20+ [A] emptyOf :: MonadIO m => Int -> m (MutArray a)
21+ [A] createOf :: MonadIO m => Int -> Fold m a (MutArray a)
22+ [A] create :: MonadIO m => Fold m a (MutArray a)
23+[C] Streamly.Data.MutArray
24+ [A] pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
25+ [A] emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
26+ [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
27+ [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
28+ [A] appendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
29+ [A] append :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
30+[C] Streamly.Data.Array.Generic
31+ [A] createOf :: MonadIO m => Int -> Fold m a (Array a)
32+ [A] create :: MonadIO m => Fold m a (Array a)
33+[C] Streamly.Data.Array
34+ [A] class Serialize a
35+ [A] serializeAt :: Serialize a => Int -> MutByteArray -> a -> IO Int
36+ [A] pinnedSerialize :: Serialize a => a -> Array Word8
37+ [A] deserializeAt :: Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
38+ [A] deserialize :: Serialize a => Array Word8 -> a
39+ [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
40+ [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
41+ [A] addSizeTo :: Serialize a => Int -> a -> Int
42+
43+---------------------------------
44+Internal API diff
45+---------------------------------
46+
47+[C] Streamly.Internal.Unicode.Stream
48+ [A] encodeUtf16le' :: Stream m Char -> Stream m Word16
49+ [A] decodeUtf16le' :: Stream m Word16 -> Stream m Char
50+[A] Streamly.Internal.FileSystem.Path
51+ [A] class IsPath a
52+ [A] Rel
53+ [A] File
54+ [A] Dir
55+ [A] Abs
56+ [A] Streamly.Internal.FileSystem.Path.IsPath
57+ [A] instance Streamly.Internal.FileSystem.Path.IsPath Streamly.Internal.FileSystem.Path.Path
58+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel Streamly.Internal.FileSystem.Path.Path)
59+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path))
60+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path))
61+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path)
62+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path)
63+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs Streamly.Internal.FileSystem.Path.Path)
64+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path))
65+ [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path))
66+ [A] GHC.Show.Show
67+ [A] instance GHC.Show.Show Streamly.Internal.FileSystem.Path.PathException
68+ [A] GHC.Exception.Type.Exception
69+ [A] instance GHC.Exception.Type.Exception Streamly.Internal.FileSystem.Path.PathException
70+ [A] GHC.Classes.Eq
71+ [A] instance GHC.Classes.Eq Streamly.Internal.FileSystem.Path.PathException
72+ [A] Path
73+ [A] Path :: Array Word8 -> Path
74+ [A] toString :: Path -> [Char]
75+ [A] toPath :: IsPath a => a -> Path
76+ [A] toChunk :: Path -> Array Word8
77+ [A] toChars :: Monad m => Path -> Stream m Char
78+ [A] relfile :: QuasiQuoter
79+ [A] reldir :: QuasiQuoter
80+ [A] rel :: QuasiQuoter
81+ [A] primarySeparator :: Char
82+ [A] path :: QuasiQuoter
83+ [A] mkRelFile :: String -> Q Exp
84+ [A] mkRelDir :: String -> Q Exp
85+ [A] mkRel :: String -> Q Exp
86+ [A] mkPath :: String -> Q Exp
87+ [A] mkFile :: String -> Q Exp
88+ [A] mkDir :: String -> Q Exp
89+ [A] mkAbsFile :: String -> Q Exp
90+ [A] mkAbsDir :: String -> Q Exp
91+ [A] mkAbs :: String -> Q Exp
92+ [A] isSeparator :: Char -> Bool
93+ [A] fromString :: MonadThrow m => [Char] -> m Path
94+ [A] fromPathUnsafe :: IsPath a => Path -> a
95+ [A] fromPath :: (IsPath a, MonadThrow m) => Path -> m a
96+ [A] fromChunkUnsafe :: Array Word8 -> Path
97+ [A] fromChunk :: MonadThrow m => Array Word8 -> m Path
98+ [A] fromChars :: MonadThrow m => Stream Identity Char -> m Path
99+ [A] file :: QuasiQuoter
100+ [A] extendPath :: Path -> Path -> Path
101+ [A] extendDir :: (IsPath (a (Dir Path)), IsPath b, IsPath (a b)) => a (Dir Path) -> Rel b -> a b
102+ [A] dir :: QuasiQuoter
103+ [A] adaptPath :: (MonadThrow m, IsPath a, IsPath b) => a -> m b
104+ [A] absfile :: QuasiQuoter
105+ [A] absdir :: QuasiQuoter
106+ [A] abs :: QuasiQuoter
107+[C] Streamly.Internal.Data.Stream
108+ [A] (FixityR,5)
109+ [A] (FixityR,5)
110+ [C] splitInnerBySuffix
111+ [O] splitInnerBySuffix :: (Monad m, Eq (f a), Monoid (f a)) => (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
112+ [N] splitInnerBySuffix :: Monad m => (f a -> Bool) -> (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
113+ [D] sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
114+ [A] indexOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
115+[C] Streamly.Internal.Data.MutByteArray
116+ [A] unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
117+ [A] unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
118+ [D] nil :: MutByteArray
119+ [A] empty :: MutByteArray
120+ [D] asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
121+[D] Streamly.Internal.Data.MutArray.Stream
122+ [D] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
123+ [D] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
124+ [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
125+ [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
126+[C] Streamly.Internal.Data.MutArray.Generic
127+ [D] writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
128+ [D] writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
129+ [A] unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
130+ [A] emptyOf :: MonadIO m => Int -> m (MutArray a)
131+ [A] createWith :: MonadIO m => Int -> Fold m a (MutArray a)
132+ [A] createOf :: MonadIO m => Int -> Fold m a (MutArray a)
133+ [A] create :: MonadIO m => Fold m a (MutArray a)
134+[C] Streamly.Internal.Data.MutArray
135+ [A] SpliceState
136+ [A] SpliceYielding :: arr -> SpliceState s arr -> SpliceState s arr
137+ [A] SpliceInitial :: s -> SpliceState s arr
138+ [A] SpliceFinish :: SpliceState s arr
139+ [A] SpliceBuffering :: s -> arr -> SpliceState s arr
140+ [R] MutByteArray
141+ [D] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
142+ [D] writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
143+ [D] writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
144+ [D] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
145+ [D] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
146+ [D] writeAppendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
147+ [D] writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
148+ [A] unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
149+ [A] unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
150+ [A] unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
151+ [A] unsafeCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
152+ [A] unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
153+ [A] unsafeAppendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
154+ [A] toStreamWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
155+ [A] toStreamRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
156+ [R] toStreamDWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
157+ [R] toStreamDRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
158+ [A] slicerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
159+ [A] sliceIndexerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
160+ [A] revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
161+ [D] resizeExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
162+ [D] resize :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
163+ [A] pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
164+ [A] pokeAppendMay :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> a -> m (Maybe (MutArray Word8))
165+ [A] pokeAppend :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> a -> m (MutArray Word8)
166+ [D] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
167+ [D] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
168+ [D] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
169+ [D] pinnedNewBytes :: MonadIO m => Int -> m (MutArray a)
170+ [A] pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
171+ [A] pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
172+ [A] pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
173+ [A] pinnedCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
174+ [A] peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> m (a, MutArray Word8)
175+ [A] peekUncons :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> m (Maybe a, MutArray Word8)
176+ [A] peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
177+ [A] pPinnedCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Parser (MutArray a) m (MutArray a)
178+ [A] pCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Parser (MutArray a) m (MutArray a)
179+ [D] nil :: MutArray a
180+ [A] lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
181+ [A] lCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
182+ [A] indexReaderWith :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
183+ [A] indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
184+ [A] growExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
185+ [A] grow :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
186+ [D] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
187+ [R] getIndicesD :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
188+ [D] getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
189+ [D] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
190+ [A] fromStreamN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
191+ [D] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
192+ [D] fromStreamD :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
193+ [A] fromPureStreamN :: (MonadIO m, Unbox a) => Int -> Stream Identity a -> m (MutArray a)
194+ [A] fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
195+ [A] fromChunksRealloced :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> m (MutArray a)
196+ [A] fromChunksK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
197+ [A] fromByteStr# :: MonadIO m => Addr# -> m (MutArray Word8)
198+ [D] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
199+ [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
200+ [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
201+ [A] fPinnedCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) (MutArray a)
202+ [A] fCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) (MutArray a)
203+ [A] emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
204+ [A] empty :: MutArray a
205+ [A] createWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
206+ [A] createOfWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
207+ [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
208+ [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
209+ [A] concatWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m (MutArray a) -> Stream m a
210+ [A] concatRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m (MutArray a) -> Stream m a
211+ [A] concatRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
212+ [A] concat :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
213+ [A] compactOnByteSuffix :: MonadIO m => Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
214+ [A] compactOnByte :: MonadIO m => Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
215+ [A] compactLeAs :: forall m a. (MonadIO m, Unbox a) => PinnedState -> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
216+ [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
217+ [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
218+ [A] compactEQ :: Int -> Stream m (MutArray a) -> Stream m (MutArray a)
219+ [D] cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
220+ [A] byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
221+ [A] byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
222+ [A] buildChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
223+ [D] asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
224+ [A] appendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
225+ [A] appendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
226+ [A] append :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
227+[D] Streamly.Internal.Data.Array.Stream
228+ [C] interposeSuffix
229+ [O] interposeSuffix :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
230+ [N] interposeSuffix :: forall m a. (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
231+ [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
232+ [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
233+ [C] concatRev
234+ [O] concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
235+ [N] concatRev :: forall m a. (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
236+ [D] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
237+[C] Streamly.Internal.Data.Array.Generic
238+ [A] createOf :: MonadIO m => Int -> Fold m a (Array a)
239+ [A] create :: MonadIO m => Fold m a (Array a)
240+[C] Streamly.Internal.Data.Array
241+ [R] ArrayUnsafe
242+ [D] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
243+ [D] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
244+ [A] unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
245+ [A] unsafePinnedAsPtr :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
246+ [A] unsafeCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
247+ [D] toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
248+ [D] toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
249+ [C] splice
250+ [O] splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
251+ [N] splice :: MonadIO m => Array a -> Array a -> m (Array a)
252+ [A] slicerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Array a)
253+ [A] sliceIndexerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Int, Int)
254+ [D] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
255+ [D] pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> Fold m a (Array a)
256+ [D] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
257+ [D] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
258+ [A] pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
259+ [A] pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
260+ [A] pinnedCompactLE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
261+ [A] parseBreakChunksK :: forall m a b. (MonadIO m, Unbox a) => Parser a m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
262+ [D] nil :: Array a
263+ [A] lPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
264+ [A] lCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
265+ [A] interposeSuffix :: forall m a. (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
266+ [A] interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
267+ [A] intercalateSuffix :: (Monad m, Unbox a) => Array a -> Stream m (Array a) -> Stream m a
268+ [A] indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
269+ [A] indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
270+ [A] indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
271+ [D] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Array a)
272+ [R] getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
273+ [D] getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
274+ [D] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Int, Int)
275+ [D] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
276+ [D] fromStreamD :: forall m a. (MonadIO m, Unbox a) => Stream m a -> m (Array a)
277+ [A] fromPureStreamN :: Unbox a => Int -> Stream Identity a -> Array a
278+ [A] fromPtrN :: Int -> Ptr Word8 -> Array Word8
279+ [A] fromChunksK :: (MonadIO m, Unbox a) => StreamK m (Array a) -> m (Array a)
280+ [A] fromChunks :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
281+ [A] fromByteStr :: Ptr Word8 -> Array Word8
282+ [A] foldChunks :: (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m b
283+ [A] foldBreakChunksK :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
284+ [A] foldBreakChunks :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
285+ [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
286+ [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
287+ [C] findIndicesOf
288+ [O] findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
289+ [N] findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
290+ [A] fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
291+ [A] fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
292+ [A] empty :: Array a
293+ [A] createWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
294+ [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
295+ [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
296+ [A] concatRev :: forall m a. (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
297+ [A] concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
298+ [A] compactOnByteSuffix :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
299+ [A] compactOnByte :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
300+ [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
301+ [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
302+ [A] byteEq :: Array a -> Array a -> Bool
303+ [A] byteCmp :: Array a -> Array a -> Ordering
304+ [A] buildChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
305+ [D] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
306+ [D] asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
core/docs/Changelog.md+58−16
@@ -1,31 +1,73 @@
1# Changelog
1# Changelog
2
2
3−## Unreleased
3+## 0.2.2 (Jan 2024)
4
4
5−* Arrays are now created unpinned by default, they were created pinned
5+* Add fixities `infixr 5` for `cons` and `consM` functions.
6− earlier. During IO operations unpinned arrays are automatically copied
6+* Fix a bug in Array `Eq` instance when the type is a sum type with
7− to pinned memory. When arrays are directly passed to IO operations
7+ differently sized constructors.
8− programmers can choose to create them pinned to avoid a copy. To
8+* lpackArraysChunksOf, compact, writeChunksWith, putChunksWith now take the
9− create pinned arrays, use the internal APIs with the `pinned*` prefix.
9+ buffer size in number of array elements instead of bytes.
10
10
11−* Changed the signature of 'Streamly.Data.Stream.handle' to make the exception
11+## 0.2.1 (Dec 2023)
12− handler monadic.
13−* Rethrow the exception promptly in bracketIO.
14
12
15−### Breaking
13+* Make the serialization of the unit constructor deterministic.
14+* Expose `pinnedSerialize` & `deserialize` via `Streamly.Data.Array`.
16
15
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+
17−* `ParserK` in `Streamly.Data.ParserK` is not specialized to arrays anymore. To
24+* `ParserK` in `Streamly.Data.ParserK` is not implicitly specialized
18− adapt to the new code, change `ParserK a m b` to `ParserK (Array a) m b` where
25+ to arrays anymore. To adapt to the new code, change `ParserK a m
19− `Array` comes from `Streamly.Data.Array`.
26+ b` to `ParserK (Array a) m b` where the `Array` type comes from
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.
20
46
21### Deprecations
47### Deprecations
22
48
23−* `Streamly.Data.MutArray.newUnpinned` is renamed to
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)
24− `Streamly.Data.MutArray.pinnedNew`
50+for a full list of deprecations.
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
25
67
26## 0.1.0 (March 2023)
68## 0.1.0 (March 2023)
27
69
28−Also see [streamly-core-0.1.0 API Changelog](/core/docs/ApiChangelogs/0.1.0.txt) or
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
29https://hackage.haskell.org/package/streamly-core-0.1.0/docs/docs/ApiChangelogs/0.1.0.txt
71https://hackage.haskell.org/package/streamly-core-0.1.0/docs/docs/ApiChangelogs/0.1.0.txt
30
72
31`streamly` package is split into two packages, (1) `streamly-core` that
73`streamly` package is split into two packages, (1) `streamly-core` that
core/src/DocTestDataArray.hs+3
@@ -11,9 +11,12 @@
11
11
12>>> import qualified Streamly.Data.Array as Array
12>>> import qualified Streamly.Data.Array as Array
13>>> import qualified Streamly.Data.Fold as Fold
13>>> import qualified Streamly.Data.Fold as Fold
14+>>> import qualified Streamly.Data.ParserK as ParserK
14>>> import qualified Streamly.Data.Stream as Stream
15>>> import qualified Streamly.Data.Stream as Stream
16+>>> import qualified Streamly.Data.StreamK as StreamK
15
17
16For APIs that have not been released yet.
18For APIs that have not been released yet.
17
19
18>>> import qualified Streamly.Internal.Data.Array as Array
20>>> import qualified Streamly.Internal.Data.Array as Array
21+>>> import qualified Streamly.Internal.Data.Stream as Stream
19-}
22-}
core/src/DocTestDataParserK.hsnew file+15
@@ -0,0 +1,15 @@
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,6 +6,7 @@
6>>> import Control.Monad.IO.Class (MonadIO (liftIO))
6>>> import Control.Monad.IO.Class (MonadIO (liftIO))
7>>> import Control.Monad.Trans.Class (lift)
7>>> import Control.Monad.Trans.Class (lift)
8>>> import Control.Monad.Trans.Identity (runIdentityT)
8>>> import Control.Monad.Trans.Identity (runIdentityT)
9+>>> import Data.Char (isSpace)
9>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
10>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
10>>> import Data.Maybe (fromJust, isJust)
11>>> import Data.Maybe (fromJust, isJust)
11>>> import Data.Function (fix, (&))
12>>> import Data.Function (fix, (&))
@@ -32,6 +33,7 @@ For APIs that have not been released yet.
32>>> import qualified Streamly.Internal.Data.Fold as Fold
33>>> import qualified Streamly.Internal.Data.Fold as Fold
33>>> import qualified Streamly.Internal.Data.Parser as Parser
34>>> import qualified Streamly.Internal.Data.Parser as Parser
34>>> import qualified Streamly.Internal.Data.Stream as Stream
35>>> import qualified Streamly.Internal.Data.Stream as Stream
36+>>> import qualified Streamly.Internal.Data.StreamK as StreamK
35>>> import qualified Streamly.Internal.Data.Unfold as Unfold
37>>> import qualified Streamly.Internal.Data.Unfold as Unfold
36>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
38>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
37-}
39-}
core/src/DocTestFileSystemHandle.hs+1−1
@@ -8,7 +8,7 @@
8
8
9For APIs that have not been released yet.
9For APIs that have not been released yet.
10
10
11−>>> import qualified Streamly.Internal.Data.Array as Array (writeNUnsafe)
11+>>> import qualified Streamly.Internal.Data.Array as Array (unsafeCreateOf)
12>>> import qualified Streamly.Internal.Data.Unfold as Unfold (first)
12>>> import qualified Streamly.Internal.Data.Unfold as Unfold (first)
13>>> import qualified Streamly.Internal.FileSystem.Handle as Handle
13>>> import qualified Streamly.Internal.FileSystem.Handle as Handle
14>>> import qualified Streamly.Internal.System.IO as IO (defaultChunkSize)
14>>> import qualified Streamly.Internal.System.IO as IO (defaultChunkSize)
core/src/Streamly/Console/Stdio.hs+1−27
@@ -24,33 +24,7 @@ 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
31 )
27 )
32where
28where
33
29
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−
39−import Streamly.Internal.Console.Stdio hiding (read, readChunks)
30+import Streamly.Internal.Console.Stdio
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+40−39
@@ -31,28 +31,45 @@ module Streamly.Data.Array
31 -- * The Array Type
31 -- * The Array Type
32 Array
32 Array
33
33
34+ -- * Pinning & Unpinning
35+ -- | Arrays are created unpinned by default unless pinned versions of
36+ -- creation APIs are used. Look for APIs with @pinned@ prefix in
37+ -- "Streamly.Internal.Data.Array" for some unreleased pinned creation APIs.
38+ -- If an array is to be sent to the OS without any further modification
39+ -- then it should be created pinned in the first place instead of pinning
40+ -- it later. Pinning an unpinned array has a copy overhead. OS interfacing
41+ -- APIs create a pinned array directly or convert an unpinned array to
42+ -- pinned array before sending it to the OS.
43+ , pin
44+ , unpin
45+ , isPinned
46+
34 -- * Construction
47 -- * Construction
35 -- | When performance matters, the fastest way to generate an array is
48 -- | When performance matters, the fastest way to generate an array is
36− -- 'writeN'. 'IsList' and 'IsString' instances can be
49+ -- 'createOf'. 'IsList' and 'IsString' instances can be
37 -- used to conveniently construct arrays from literal values.
50 -- used to conveniently construct arrays from literal values.
38 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
51 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
39 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
52 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
40 -- 'fromList' can be used to construct an array from a string literal.
53 -- 'fromList' can be used to construct an array from a string literal.
41
54
55+ -- ** From Stream
56+ , createOf
57+ , create
58+ , writeLastN -- drop old (ring buffer)
59+
42− -- Pure List APIs
60+ -- ** From List
43 , fromListN
61 , fromListN
44 , fromList
62 , fromList
45
63
46− -- Monadic APIs
64+ -- * To List
47− , writeN -- drop new
48− , write -- full buffer
49− , writeLastN -- drop old (ring buffer)
50−
51− -- * Conversion
52 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
65 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
53 -- list.
66 -- list.
54 , toList
67 , toList
55
68
69+ -- * To Stream
70+ , read
71+ , readRev
72+
56 -- * Unfolds
73 -- * Unfolds
57 , reader
74 , reader
58 , readerRev
75 , readerRev
@@ -66,25 +83,24 @@ module Streamly.Data.Array
66 -- , (!!)
83 -- , (!!)
67 , getIndex
84 , getIndex
68
85
69− -- * Unbox Type Class
86+ -- * Serialization
70− , Unbox (..)
87+ , pinnedSerialize
88+ , deserialize
71
89
72− -- * Pinning & Unpinning
90+ -- * Re-exports
73− , pin
91+ , Unbox (..)
74− , unpin
92+ , Serialize(..)
75− , isPinned
76
93
77 -- * Deprecated
94 -- * Deprecated
78− , read
95+ , writeN -- drop new
79− , readRev
96+ , write -- full buffer
80 )
97 )
81where
98where
82
99
83#include "inline.hs"
100#include "inline.hs"
84
101
85−import Streamly.Internal.Data.Array hiding (read, readRev)
102+import Streamly.Internal.Data.Array
86−import Streamly.Internal.Data.Unbox (Unbox (..))
103+import Streamly.Internal.Data.MutByteArray (Unbox(..), Serialize(..))
87−import Streamly.Internal.Data.Unfold (Unfold)
88
104
89import Prelude hiding (read, length)
105import Prelude hiding (read, length)
90
106
@@ -102,7 +118,7 @@ import Prelude hiding (read, length)
102--
118--
103-- Convert array to stream, and fold the stream:
119-- Convert array to stream, and fold the stream:
104--
120--
105−-- >>> fold f arr = Stream.unfold Array.reader arr & Stream.fold f
121+-- >>> fold f arr = Array.read arr & Stream.fold f
106-- >>> fold Fold.sum (Array.fromList [1,2,3::Int])
122-- >>> fold Fold.sum (Array.fromList [1,2,3::Int])
107-- 6
123-- 6
108--
124--
@@ -110,7 +126,7 @@ import Prelude hiding (read, length)
110--
126--
111-- Convert array to stream, transform, and fold back to array:
127-- Convert array to stream, transform, and fold back to array:
112--
128--
113−-- >>> amap f arr = Stream.unfold Array.reader arr & fmap f & Stream.fold Array.write
129+-- >>> amap f arr = Array.read arr & fmap f & Stream.fold (Array.createOf (Array.length arr))
114-- >>> amap (+1) (Array.fromList [1,2,3::Int])
130-- >>> amap (+1) (Array.fromList [1,2,3::Int])
115-- fromList [2,3,4]
131-- fromList [2,3,4]
116--
132--
@@ -137,12 +153,11 @@ import Prelude hiding (read, length)
137-- See the 'fromPureStream' unreleased API to generate an array from an
153-- See the 'fromPureStream' unreleased API to generate an array from an
138-- Identity stream safely without using MonadIO constraint.
154-- Identity stream safely without using MonadIO constraint.
139--
155--
140−--
141-- Note that 'Identity' streams can be generalized to IO streams:
156-- Note that 'Identity' streams can be generalized to IO streams:
142--
157--
143−-- >>> pure = Stream.fromList [1,2,3] :: Stream Identity Int
158+-- >>> stream = Stream.fromList [1,2,3] :: Stream Identity Int
144−-- >>> generally = Stream.morphInner (return . runIdentity)
159+-- >>> pure2IO s = Stream.morphInner (return . runIdentity) s :: Stream IO Int
145−-- >>> Stream.fold Array.write (generally pure :: Stream IO Int)
160+-- >>> Stream.fold Array.create (pure2IO stream)
146-- fromList [1,2,3]
161-- fromList [1,2,3]
147--
162--
148-- == Programming Tips
163-- == Programming Tips
@@ -150,17 +165,3 @@ import Prelude hiding (read, length)
150-- This module is designed to be imported qualified:
165-- This module is designed to be imported qualified:
151--
166--
152-- >>> import qualified Streamly.Data.Array as Array
167-- >>> 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+16−13
@@ -15,34 +15,37 @@ module Streamly.Data.Array.Generic
15 ( Array
15 ( Array
16
16
17 -- * Construction
17 -- * Construction
18− , A.fromListN
18+ , fromListN
19− , A.fromList
19+ , fromList
20
20
21 -- MonadicAPIs
21 -- MonadicAPIs
22− , A.writeN
22+ , createOf
23− , A.write
23+ , create
24
24
25 -- * Conversion
25 -- * Conversion
26− , A.toList
26+ , toList
27
27
28 -- * Streams
28 -- * Streams
29− , A.read
29+ , read
30− , A.readRev
30+ , readRev
31
31
32 -- * Unfolds
32 -- * Unfolds
33− , A.reader
33+ , reader
34 -- , A.readerRev
34 -- , A.readerRev
35
35
36 -- * Random Access
36 -- * Random Access
37− , A.length
37+ , length
38− , A.getIndex
38+ , getIndex
39
39
40 -- -- * Folding Arrays
40 -- -- * Folding Arrays
41 -- , A.streamFold
41 -- , A.streamFold
42 -- , A.fold
42 -- , A.fold
43+
44+ -- * Deprecated
45+ , writeN
46+ , write
43 )
47 )
44where
48where
45
49
46−import Streamly.Internal.Data.Array.Generic (Array)
50+import Streamly.Internal.Data.Array.Generic
47−
51+import Prelude hiding (length, read)
48−import qualified Streamly.Internal.Data.Array.Generic as A
core/src/Streamly/Data/Fold.hs+150−118
@@ -10,6 +10,156 @@
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+--
13-- Please refer to "Streamly.Internal.Data.Fold" for more functions that have
163-- Please refer to "Streamly.Internal.Data.Fold" for more functions that have
14-- not yet been released.
164-- not yet been released.
15
165
@@ -21,9 +171,6 @@ module Streamly.Data.Fold
21 --
171 --
22 -- $setup
172 -- $setup
23
173
24− -- * Overview
25− -- $overview
26−
27 -- * Running A Fold
174 -- * Running A Fold
28 drive
175 drive
29 -- XXX Should we have a stream returning function in fold module?
176 -- XXX Should we have a stream returning function in fold module?
@@ -258,121 +405,6 @@ import Streamly.Internal.Data.Fold
258
405
259#include "DocTestDataFold.hs"
406#include "DocTestDataFold.hs"
260
407
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−
376--------------------------------------------------------------------------------
408--------------------------------------------------------------------------------
377-- Deprecated
409-- Deprecated
378--------------------------------------------------------------------------------
410--------------------------------------------------------------------------------
core/src/Streamly/Data/MutArray.hs+18−12
@@ -32,22 +32,27 @@ module Streamly.Data.MutArray
32 -- * Construction
32 -- * Construction
33
33
34 -- Uninitialized Arrays
34 -- Uninitialized Arrays
35− , new
35+ , emptyOf
36− , pinnedNew
36+ , pinnedEmptyOf
37
37
38 -- From containers
38 -- From containers
39 , fromListN
39 , fromListN
40 , fromList
40 , fromList
41− , writeN -- drop new
41+ , createOf
42− , write -- full buffer
42+ , create
43 -- writeLastN
43 -- writeLastN
44
44
45+ -- * Pinning & Unpinning
46+ , pin
47+ , unpin
48+ , isPinned
49+
45 -- * Appending elements
50 -- * Appending elements
46 , snoc
51 , snoc
47
52
48 -- * Appending streams
53 -- * Appending streams
49− , writeAppendN -- XXX Rename to writeSnocN?
54+ , appendN
50− , writeAppend -- XXX Rename to writeSnoc?
55+ , append
51
56
52 -- * Inplace mutation
57 -- * Inplace mutation
53 , putIndex
58 , putIndex
@@ -78,16 +83,17 @@ module Streamly.Data.MutArray
78 -- * Size
83 -- * Size
79 , length
84 , length
80
85
81− -- * Unbox Type Class
86+ -- * Re-exports
82 , Unbox (..)
87 , Unbox (..)
83
88
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
91 )
97 )
92where
98where
93
99
core/src/Streamly/Data/MutArray/Generic.hs+8−3
@@ -23,11 +23,11 @@ module Streamly.Data.MutArray.Generic
23 MutArray
23 MutArray
24
24
25 -- * Construction
25 -- * Construction
26− , new
26+ , emptyOf
27 , fromListN
27 , fromListN
28 , fromList
28 , fromList
29− , writeN
29+ , createOf
30− , write
30+ , create
31
31
32 -- * Appending elements
32 -- * Appending elements
33 , snoc
33 , snoc
@@ -56,6 +56,11 @@ module Streamly.Data.MutArray.Generic
56
56
57 -- * Size
57 -- * Size
58 , length
58 , length
59+
60+ -- * Deprecated
61+ , new
62+ , writeN
63+ , write
59 )
64 )
60where
65where
61
66
core/src/Streamly/Data/MutByteArray.hsnew file+106
@@ -0,0 +1,106 @@
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+130−60
@@ -7,12 +7,137 @@
7-- Stability : pre-release
7-- Stability : pre-release
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10−-- Fast, composable stream consumers with ability to terminate, backtrack and
10+-- Parsers are stream consumers like folds with the following differences:
11−-- fail, supporting stream fusion. Parsers are a natural extension of
12−-- "Streamly.Data.Fold". Parsers and folds can be interconverted.
13--
11--
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+--
14−-- Please refer to "Streamly.Internal.Data.Parser" for functions that have
139+-- Please refer to "Streamly.Internal.Data.Parser" for functions that have not
15−-- not yet been released.
140+-- yet been released.
16--
141--
17module Streamly.Data.Parser
142module Streamly.Data.Parser
18 (
143 (
@@ -22,9 +147,6 @@ module Streamly.Data.Parser
22 --
147 --
23 -- $setup
148 -- $setup
24
149
25− -- * Overview
26− -- $overview
27−
28 -- * Parser Type
150 -- * Parser Type
29 Parser
151 Parser
30
152
@@ -123,55 +245,3 @@ import Streamly.Internal.Data.Parser
123import Prelude hiding (dropWhile, takeWhile, filter)
245import Prelude hiding (dropWhile, takeWhile, filter)
124
246
125#include "DocTestDataParser.hs"
247#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+89−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1-- |
2-- |
2-- Module : Streamly.Data.ParserK
3-- Module : Streamly.Data.ParserK
3-- Copyright : (c) 2023 Composewell Technologies
4-- Copyright : (c) 2023 Composewell Technologies
@@ -6,19 +7,102 @@
6-- Stability : pre-release
7-- Stability : pre-release
7-- Portability : GHC
8-- Portability : GHC
8--
9--
10+-- See the general notes about parsing in the "Streamly.Data.Parser" module.
9−-- Parsers using Continuation Passing Style (CPS). See notes in
11+-- This module implements a using Continuation Passing Style (CPS) wrapper over
10−-- "Streamly.Data.Parser" module to know when to use this module.
12+-- the "Streamly.Data.Parser" module. It is as fast or faster than attoparsec.
11--
13--
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+--
12−-- To run a 'ParserK' use 'Streamly.Data.StreamK.parseChunks'.
34+-- 'Streamly.Data.StreamK.parseChunks' runs a parser on a stream of unboxed
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.
13--
89--
14module Streamly.Data.ParserK
90module Streamly.Data.ParserK
15 (
91 (
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+
16 -- * Parser Type
98 -- * Parser Type
17 ParserK
99 ParserK
18
100
19 -- * Parsers
101 -- * Parsers
20 -- ** Conversions
102 -- ** Conversions
103+ , adapt
21 , adaptC
104 , adaptC
105+ , adaptCG
22 -- , toParser
106 -- , toParser
23
107
24 -- ** Without Input
108 -- ** Without Input
@@ -41,6 +125,8 @@ import qualified Streamly.Internal.Data.Parser as ParserD
41
125
42import Streamly.Internal.Data.ParserK.Type
126import Streamly.Internal.Data.ParserK.Type
43
127
128+#include "DocTestDataParserK.hs"
129+
44{-# DEPRECATED fromFold "Please use \"ParserK.adaptC . Parser.fromFold\" instead." #-}
130{-# DEPRECATED fromFold "Please use \"ParserK.adaptC . Parser.fromFold\" instead." #-}
45{-# INLINE fromFold #-}
131{-# INLINE fromFold #-}
46fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
132fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK (Array a) m b
core/src/Streamly/Data/Serialize.hsdeleted−50
@@ -1,50 +0,0 @@
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+131−36
@@ -70,6 +70,15 @@ module Streamly.Data.Stream
70
70
71 -- ** From Values
71 -- ** From Values
72 -- | Generate a monadic stream from a seed value or values.
72 -- | Generate a monadic stream from a seed value or values.
73+ --
74+ -- Non-empty pure streams can be cycled using repeat and unfold:
75+ --
76+ -- >>> cycle = Stream.unfoldMany Unfold.fromList . Stream.repeat
77+ --
78+ -- Non-empty StreamK can be cycled using append:
79+ --
80+ -- >>> cycle xs = let ys = xs `StreamK.append` ys in ys
81+ --
73 , fromPure
82 , fromPure
74 , fromEffect
83 , fromEffect
75 , repeat
84 , repeat
@@ -212,21 +221,57 @@ module Streamly.Data.Stream
212 -- operations like mapping a function over the stream.
221 -- operations like mapping a function over the stream.
213 , foldrM
222 , foldrM
214 , foldr
223 , foldr
224+ -- foldr1
215
225
216 -- ** Specific Folds
226 -- ** Specific Folds
217− -- | Usually you can use the folds in "Streamly.Data.Fold". However, some
227+ -- | Streams are folded using folds in "Streamly.Data.Fold". Here are some
218− -- folds that may be commonly used or may have an edge in performance in
228+ -- idioms and equivalents of Data.List APIs using folds:
219− -- some cases are provided here.
220− --
221− -- Useful idioms:
222 --
229 --
223 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
230 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
224− -- >>> foldl1 f = Stream.fold (Fold.foldl1' f)
231+ -- >>> foldl1' f = Stream.fold (Fold.foldl1' f)
225 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
232 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
226 -- >>> drain = Stream.fold Fold.drain
233 -- >>> drain = Stream.fold Fold.drain
227 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
234 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
228 -- >>> length = Stream.fold Fold.length
235 -- >>> length = Stream.fold Fold.length
236+ -- >>> genericLength = Stream.fold Fold.lengthGeneric
229 -- >>> head = Stream.fold Fold.one
237 -- >>> head = Stream.fold Fold.one
238+ -- >>> last = Stream.fold Fold.latest
239+ -- >>> null = Stream.fold Fold.null
240+ -- >>> and = Stream.fold Fold.and
241+ -- >>> or = Stream.fold Fold.or
242+ -- >>> any p = Stream.fold (Fold.any p)
243+ -- >>> all p = Stream.fold (Fold.all p)
244+ -- >>> sum = Stream.fold Fold.sum
245+ -- >>> product = Stream.fold Fold.product
246+ -- >>> maximum = Stream.fold Fold.maximum
247+ -- >>> maximumBy cmp = Stream.fold (Fold.maximumBy cmp)
248+ -- >>> minimum = Stream.fold Fold.minimum
249+ -- >>> minimumBy cmp = Stream.fold (Fold.minimumBy cmp)
250+ -- >>> elem x = Stream.fold (Fold.elem x)
251+ -- >>> notElem x = Stream.fold (Fold.notElem x)
252+ -- >>> lookup x = Stream.fold (Fold.lookup x)
253+ -- >>> find p = Stream.fold (Fold.find p)
254+ -- >>> (!?) i = Stream.fold (Fold.index i)
255+ -- >>> genericIndex i = Stream.fold (Fold.indexGeneric i)
256+ -- >>> elemIndex x = Stream.fold (Fold.elemIndex x)
257+ -- >>> findIndex p = Stream.fold (Fold.findIndex p)
258+ --
259+ -- Some equivalents of Data.List APIs from the Stream module:
260+ --
261+ -- >>> head = fmap (fmap fst) . Stream.uncons
262+ -- >>> tail = fmap (fmap snd) . Stream.uncons
263+ -- >>> tail = Stream.tail -- unreleased API
264+ -- >>> init = Stream.init -- unreleased API
265+ --
266+ -- A Stream based toList fold implementation is provided below because it
267+ -- has a better performance compared to the fold.
268+
269+ -- Functions in Data.List, missing here:
270+ -- unsnoc = Stream.parseBreak (Parser.init Fold.toList)
271+ -- genericTake
272+ -- genericDrop
273+ -- genericSplitAt
274+ -- genericReplicate
230 , toList
275 , toList
231
276
232 -- * Mapping
277 -- * Mapping
@@ -280,6 +325,15 @@ module Streamly.Data.Stream
280 , scan
325 , scan
281 , postscan
326 , postscan
282 -- XXX postscan1 can be implemented using Monoids or Refolds.
327 -- XXX postscan1 can be implemented using Monoids or Refolds.
328+ -- The following scans from Data.List are not provided.
329+ -- XXX scanl
330+ -- XXX scanl1
331+ -- XXX scanr
332+ -- XXX scanr1
333+ -- XXX mapAccumL
334+ -- XXX mapAccumR
335+ -- XXX inits
336+ -- XXX tails
283
337
284 -- ** Specific scans
338 -- ** Specific scans
285 -- Indexing can be considered as a special type of zipping where we zip a
339 -- Indexing can be considered as a special type of zipping where we zip a
@@ -288,6 +342,8 @@ module Streamly.Data.Stream
288
342
289 -- * Insertion
343 -- * Insertion
290 -- | Add elements to the stream.
344 -- | Add elements to the stream.
345+ --
346+ -- >>> insert = Stream.insertBy compare
291
347
292 -- Inserting elements is a special case of interleaving/merging streams.
348 -- Inserting elements is a special case of interleaving/merging streams.
293 , insertBy
349 , insertBy
@@ -323,12 +379,15 @@ module Streamly.Data.Stream
323 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
379 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
324 -- perform stateful filtering operations in general.
380 -- perform stateful filtering operations in general.
325 --
381 --
326− -- Useful idioms:
382+ -- Idioms and equivalents of Data.List APIs:
327 --
383 --
328 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
384 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
385+ -- >>> deleteBy = Stream.deleteBy -- unreleased API
386+ -- >>> delete = deleteBy (==)
329 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
387 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
330 -- >>> elemIndices a = findIndices (== a)
388 -- >>> elemIndices a = findIndices (== a)
331 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
389 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
390+ -- >>> partition p = Stream.fold (Fold.partition Fold.toList Fold.toList) . fmap (if p then Left else Right)
332 , scanMaybe
391 , scanMaybe
333 , take
392 , take
334 , takeWhile
393 , takeWhile
@@ -336,6 +395,8 @@ module Streamly.Data.Stream
336 , drop
395 , drop
337 , dropWhile
396 , dropWhile
338 , dropWhileM
397 , dropWhileM
398+ -- XXX write to an array in reverse and then read in reverse
399+ -- > dropWhileEnd = reverse . dropWhile p . reverse
339
400
340 -- XXX These are available as scans in folds. We need to check the
401 -- XXX These are available as scans in folds. We need to check the
341 -- performance though. If these are common and we need convenient stream
402 -- performance though. If these are common and we need convenient stream
@@ -372,6 +433,9 @@ module Streamly.Data.Stream
372 -- >>> s = s1 `Stream.append` s2
433 -- >>> s = s1 `Stream.append` s2
373
434
374 -- ** Appending
435 -- ** Appending
436+ -- | Equivalent of Data.List append:
437+ --
438+ -- >>> (++) = Stream.append
375 , append
439 , append
376
440
377 -- ** Interleaving
441 -- ** Interleaving
@@ -382,8 +446,14 @@ module Streamly.Data.Stream
382 , mergeByM
446 , mergeByM
383
447
384 -- ** Zipping
448 -- ** Zipping
449+ -- | Idioms and equivalents of Data.List APIs:
450+ --
451+ -- >>> zip = Stream.zipWith (,)
452+ -- >>> unzip = Stream.fold (Fold.unzip Fold.toList Fold.toList)
385 , zipWith
453 , zipWith
386 , zipWithM
454 , zipWithM
455+ -- XXX zipWith3,4,5,6,7
456+ -- XXX unzip3,4,5,6,7
387 -- , ZipStream (..)
457 -- , ZipStream (..)
388
458
389 -- ** Cross Product
459 -- ** Cross Product
@@ -416,48 +486,89 @@ module Streamly.Data.Stream
416 -- One dimension loops are just a special case of nested loops. For
486 -- One dimension loops are just a special case of nested loops. For
417 -- example, 'concatMap' can degenerate to a simple map operation:
487 -- example, 'concatMap' can degenerate to a simple map operation:
418 --
488 --
419− -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
489+ -- >>> map f m = Stream.concatMap (\x -> Stream.fromPure (f x)) m
420 --
490 --
421 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
491 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
422 -- 'nil' stream:
492 -- 'nil' stream:
423 --
493 --
424− -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
494+ -- >>> filter p m = Stream.concatMap (\x -> if p x then Stream.fromPure x else Stream.nil) m
425 --
495 --
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 " "
426
503
427 , concatEffect
504 , concatEffect
428 , concatMap
505 , concatMap
429 , concatMapM
506 , concatMapM
430
507
431 -- * Repeated Fold
508 -- * Repeated Fold
432− -- | Useful idioms:
509+ -- | Idioms and equivalents of Data.List APIs:
433 --
510 --
434− -- >>> splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
511+ -- >>> groupsOf n = Stream.foldMany (Fold.take n Fold.toList)
435− -- >>> splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
512+ -- >>> groupBy eq = Stream.groupsWhile eq Fold.toList
436− -- >>> groupsBy eq f = Stream.parseMany (Parser.groupBy eq f)
513+ -- >>> groupBy eq = Stream.parseMany (Parser.groupBy eq Fold.toList)
437− -- >>> groupsByRolling eq f = Stream.parseMany (Parser.groupByRolling eq f)
514+ -- >>> groupsByRolling eq = Stream.parseMany (Parser.groupByRolling eq Fold.toList)
438− -- >>> groupsOf n f = Stream.foldMany (Fold.take n f)
515+ -- >>> groups = groupBy (==)
439 , foldMany -- XXX Rename to foldRepeat
516 , foldMany -- XXX Rename to foldRepeat
440 , groupsOf
517 , groupsOf
441 , parseMany
518 , parseMany
442
519
443 -- * Splitting
520 -- * Splitting
521+ -- | Idioms and equivalents of Data.List APIs:
522+ --
523+ -- >>> splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
524+ -- >>> splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
525+ -- >>> lines = splitOnSuffix (== '\n')
526+ -- >>> words = Stream.wordsBy isSpace
527+ -- >>> splitAt n = Stream.fold (Fold.splitAt n Fold.toList Fold.toList)
528+ -- >>> span p = Parser.splitWith (,) (Parser.takeWhile p Fold.toList) (Parser.fromFold Fold.toList)
529+ -- >>> break p = span (not . p)
444 , splitOn
530 , splitOn
445 , wordsBy
531 , wordsBy
446
532
447 -- * Buffered Operations
533 -- * Buffered Operations
448 -- | Operations that require buffering of the stream.
534 -- | Operations that require buffering of the stream.
449 -- Reverse is essentially a left fold followed by an unfold.
535 -- Reverse is essentially a left fold followed by an unfold.
536+ --
537+ -- Idioms and equivalents of Data.List APIs:
538+ --
539+ -- >>> nub = Stream.fold Fold.toList . Stream.scanMaybe Fold.nub
540+ -- >>> nub = Stream.ordNub -- unreleased API
541+ -- >>> sortBy = StreamK.sortBy
542+ -- >>> sortOn f = StreamK.sortOn -- unreleased API
543+ -- >>> deleteFirstsBy = Stream.deleteFirstsBy -- unreleased
544+ -- >>> (\\) = Stream.deleteFirstsBy (==) -- unreleased
545+ -- >>> intersectBy = Stream.intersectBy -- unreleased
546+ -- >>> intersect = Stream.intersectBy (==) -- unreleased
547+ -- >>> unionBy = Stream.unionBy -- unreleased
548+ -- >>> union = Stream.unionBy (==) -- unreleased
549+ --
450 , reverse
550 , reverse
551+ -- XXX transpose: write the streams to arrays and then stream transposed.
552+ -- XXX subsequences
553+ -- XXX permutations
554+ -- , nub
555+ -- , ordNub
556+ -- , nubBy
451
557
452 -- * Multi-Stream folds
558 -- * Multi-Stream folds
453 -- | Operations that consume multiple streams at the same time.
559 -- | Operations that consume multiple streams at the same time.
454 , eqBy
560 , eqBy
455 , cmpBy
561 , cmpBy
456 , isPrefixOf
562 , isPrefixOf
563+ , isInfixOf
564+ -- , isSuffixOf
565+ -- , isSuffixOfUnbox
457 , isSubsequenceOf
566 , isSubsequenceOf
458
567
459 -- trimming sequences
568 -- trimming sequences
460− , stripPrefix
569+ -- , stripPrefix
570+ -- , stripSuffix
571+ -- , stripSuffixUnbox
461
572
462 -- Exceptions and resource management depend on the "exceptions" package
573 -- Exceptions and resource management depend on the "exceptions" package
463 -- XXX We can have IO Stream operations not depending on "exceptions"
574 -- XXX We can have IO Stream operations not depending on "exceptions"
@@ -511,25 +622,20 @@ module Streamly.Data.Stream
511 , runReaderT
622 , runReaderT
512 , runStateT
623 , runStateT
513
624
625+ -- XXX Arrays could be different types, therefore, this should be in
626+ -- specific array module. Or maybe we should abstract over array types.
514 -- * Stream of Arrays
627 -- * Stream of Arrays
515 , Array.chunksOf
628 , Array.chunksOf
516− , chunksSplitOn
517 )
629 )
518where
630where
519
631
520−import Control.Monad.IO.Class (MonadIO)
521−import Data.Word (Word8)
522−import Streamly.Data.Array (Array)
523import Streamly.Internal.Data.Stream
632import Streamly.Internal.Data.Stream
524import Prelude
633import Prelude
525 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
634 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,
528− reverse, iterate, init, and, or, lookup, foldr1, (!!),
635+ mapM, sequence, reverse, iterate, foldr1, repeat, replicate,
529− scanl, scanl1, repeat, replicate, concatMap, span)
636+ concatMap)
530
637
531import qualified Streamly.Internal.Data.Array.Type as Array
638import qualified Streamly.Internal.Data.Array.Type as Array
532−import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
533
639
534#include "DocTestDataStream.hs"
640#include "DocTestDataStream.hs"
535
641
@@ -638,14 +744,3 @@ import qualified Streamly.Internal.Data.Stream.Chunked as ArrayStream
638--
744--
639-- 'Stream' and 'StreamK' types can be interconverted. See
745-- 'Stream' and 'StreamK' types can be interconverted. See
640-- "Streamly.Data.StreamK" module for conversion operations.
746-- "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+2−1
@@ -95,7 +95,8 @@ module Streamly.Data.StreamK
95 -- , foldBreak
95 -- , foldBreak
96
96
97 -- ** Parsing
97 -- ** Parsing
98+ , parse
98− -- , parseBreak
99+ , parseBreak
99 , parseBreakChunks
100 , parseBreakChunks
100 , parseChunks
101 , parseChunks
101
102
core/src/Streamly/Data/Unfold.hs+2
@@ -65,6 +65,8 @@ module Streamly.Data.Unfold
65 -- ** Mapping on Input
65 -- ** Mapping on Input
66 , lmap
66 , lmap
67 , lmapM
67 , lmapM
68+ , first
69+ , second
68
70
69 -- ** Mapping on Output
71 -- ** Mapping on Output
70 , mapM
72 , mapM
core/src/Streamly/FileSystem/Handle.hs+7−30
@@ -1,5 +1,4 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2−#include "inline.hs"
3
2
4-- |
3-- |
5-- Module : Streamly.FileSystem.Handle
4-- Module : Streamly.FileSystem.Handle
@@ -82,13 +81,13 @@ module Streamly.FileSystem.Handle
82 -- position of the file handle. The stream ends as soon as EOF is
81 -- position of the file handle. The stream ends as soon as EOF is
83 -- encountered.
82 -- encountered.
84
83
85− -- -- *** Streams
84+ -- *** Streams
86− -- , read
85+ , read
87− -- , readWith
86+ , readWith
88− -- , readChunks
87+ , readChunks
89− -- , readChunksWith
88+ , readChunksWith
90
89
91− -- -- *** Unfolds
90+ -- *** Unfolds
92 , reader
91 , reader
93 , readerWith
92 , readerWith
94 , chunkReader
93 , chunkReader
@@ -105,36 +104,14 @@ module Streamly.FileSystem.Handle
105 , writeChunks
104 , writeChunks
106
105
107 -- * Deprecated
106 -- * Deprecated
108− , read
109 , readWithBufferOf
107 , readWithBufferOf
110− , readChunks
111 , readChunksWithBufferOf
108 , readChunksWithBufferOf
112 , writeChunksWithBufferOf
109 , writeChunksWithBufferOf
113 , writeWithBufferOf
110 , writeWithBufferOf
114 )
111 )
115where
112where
116
113
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−
123−import Streamly.Internal.FileSystem.Handle hiding (read, readChunks)
114+import Streamly.Internal.FileSystem.Handle
124import Prelude hiding (read)
115import Prelude hiding (read)
125
116
126#include "DocTestFileSystemHandle.hs"
117#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+608−135
@@ -2,7 +2,6 @@
2-- |
2-- |
3-- Module : Streamly.Internal.Data.Array
3-- Module : Streamly.Internal.Data.Array
4-- Copyright : (c) 2019 Composewell Technologies
4-- Copyright : (c) 2019 Composewell Technologies
5−--
6-- License : BSD3
5-- License : BSD3
7-- Maintainer : streamly@composewell.com
6-- Maintainer : streamly@composewell.com
8-- Stability : experimental
7-- Stability : experimental
@@ -20,33 +19,21 @@ module Streamly.Internal.Data.Array
20 module Streamly.Internal.Data.Array.Type
19 module Streamly.Internal.Data.Array.Type
21
20
22 -- * Construction
21 -- * Construction
23− -- Stream Folds
24− , fromStreamN
25− , fromStream
26−
27 -- Monadic Folds
22 -- Monadic Folds
28 , writeLastN
23 , writeLastN
29
24
30− -- * Elimination
31− -- ** Conversion
32−
33− -- ** Unfolds
34− , reader
35− , readerUnsafe
36− , producer -- experimental
37−
38 -- * Random Access
25 -- * Random Access
39 -- , (!!)
26 -- , (!!)
40 , getIndex
27 , getIndex
41 , getIndexRev
28 , getIndexRev
42− , last -- XXX getIndexLast?
29+ , last -- XXX getLastIndex?
43− , getIndices
44− , getIndicesFromThenTo
45 -- , getIndicesFrom -- read from a given position to the end of file
30 -- , getIndicesFrom -- read from a given position to the end of file
46 -- , getIndicesUpto -- read from beginning up to the given position
31 -- , getIndicesUpto -- read from beginning up to the given position
47 -- , getIndicesFromTo
32 -- , getIndicesFromTo
48 -- , getIndicesFromRev -- read from a given position to the beginning of file
33 -- , getIndicesFromRev -- read from a given position to the beginning of file
49 -- , getIndicesUptoRev -- read from end to the given position in file
34 -- , getIndicesUptoRev -- read from end to the given position in file
35+ , indexReader
36+ , indexReaderFromThenTo
50
37
51 -- * Size
38 -- * Size
52 , null
39 , null
@@ -54,6 +41,8 @@ module Streamly.Internal.Data.Array
54 -- * Search
41 -- * Search
55 , binarySearch
42 , binarySearch
56 , findIndicesOf
43 , findIndicesOf
44+ -- getIndicesOf
45+ , indexFinder -- see splitOn
57 -- , findIndexOf
46 -- , findIndexOf
58 -- , find
47 -- , find
59
48
@@ -66,51 +55,89 @@ module Streamly.Internal.Data.Array
66 -- * Subarrays
55 -- * Subarrays
67 , getSliceUnsafe
56 , getSliceUnsafe
68 -- , getSlice
57 -- , getSlice
69− , genSlicesFromLen
58+ , sliceIndexerFromLen
70− , getSlicesFromLen
59+ , slicerFromLen
71 , splitOn
60 , splitOn
72
61
73 -- * Streaming Operations
62 -- * Streaming Operations
74 , streamTransform
63 , streamTransform
75
64
76− -- ** Folding
65+ -- * Folding
77 , streamFold
66 , streamFold
78 , fold
67 , 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
79 )
97 )
80where
98where
81
99
100+#include "assert.hs"
82#include "inline.hs"
101#include "inline.hs"
83#include "ArrayMacros.h"
102#include "ArrayMacros.h"
84
103
85−import Control.Exception (assert)
86−import Control.Monad (when)
87import Control.Monad.IO.Class (MonadIO(..))
104import Control.Monad.IO.Class (MonadIO(..))
105+-- import Data.Bifunctor (first)
106+-- import Data.Either (fromRight)
88import Data.Functor.Identity (Identity)
107import Data.Functor.Identity (Identity)
89import Data.Proxy (Proxy(..))
108import Data.Proxy (Proxy(..))
90import Data.Word (Word8)
109import Data.Word (Word8)
91import Foreign.C.String (CString)
110import Foreign.C.String (CString)
92import Foreign.Ptr (castPtr)
111import Foreign.Ptr (castPtr)
93import Foreign.Storable (Storable)
112import Foreign.Storable (Storable)
113+import GHC.Types (SPEC(..))
94import Streamly.Internal.Data.Unbox (Unbox(..))
114import Streamly.Internal.Data.Unbox (Unbox(..))
95import Prelude hiding (length, null, last, map, (!!), read, concat)
115import Prelude hiding (length, null, last, map, (!!), read, concat)
96
116
117+import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..), MutByteArray)
118+import Streamly.Internal.Data.Serialize.Type (Serialize)
97import Streamly.Internal.Data.Fold.Type (Fold(..))
119import Streamly.Internal.Data.Fold.Type (Fold(..))
98−import Streamly.Internal.Data.Producer.Type (Producer(..))
120+import Streamly.Internal.Data.Parser (Parser(..), Initial(..), ParseError(..))
99−import Streamly.Internal.Data.Stream (Stream)
121+import Streamly.Internal.Data.Stream (Stream(..))
122+import Streamly.Internal.Data.StreamK (StreamK)
123+import Streamly.Internal.Data.SVar.Type (adaptState, defState)
100−import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
124+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3Fused'(..))
101import Streamly.Internal.Data.Unfold.Type (Unfold(..))
125import Streamly.Internal.Data.Unfold.Type (Unfold(..))
102import Streamly.Internal.System.IO (unsafeInlineIO)
126import Streamly.Internal.System.IO (unsafeInlineIO)
103
127
104−import qualified Streamly.Internal.Data.MutArray.Type as MA
128+import qualified Streamly.Internal.Data.Fold.Type as Fold
129+import qualified Streamly.Internal.Data.Serialize.Type as Serialize
130+import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
105import qualified Streamly.Internal.Data.MutArray as MA
131import qualified Streamly.Internal.Data.MutArray as MA
106−import qualified Streamly.Internal.Data.Array.Type as A
107import qualified Streamly.Internal.Data.Fold as FL
132import 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
110import qualified Streamly.Internal.Data.Ring as RB
133import qualified Streamly.Internal.Data.Ring as RB
134+import qualified Streamly.Internal.Data.Parser as Parser
135+-- import qualified Streamly.Internal.Data.ParserK as ParserK
111import qualified Streamly.Internal.Data.Stream as D
136import qualified Streamly.Internal.Data.Stream as D
112import qualified Streamly.Internal.Data.Stream as Stream
137import qualified Streamly.Internal.Data.Stream as Stream
138+import qualified Streamly.Internal.Data.StreamK as StreamK
113import qualified Streamly.Internal.Data.Unfold as Unfold
139import qualified Streamly.Internal.Data.Unfold as Unfold
140+import qualified Prelude
114
141
115import Streamly.Internal.Data.Array.Type
142import Streamly.Internal.Data.Array.Type
116
143
@@ -139,82 +166,10 @@ import Streamly.Internal.Data.Array.Type
139-- if we use one array for each chunk. This is still significant to add
166-- if we use one array for each chunk. This is still significant to add
140-- pressure to GC.
167-- pressure to GC.
141
168
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−
171-------------------------------------------------------------------------------
169-------------------------------------------------------------------------------
172-- Elimination
170-- Elimination
173-------------------------------------------------------------------------------
171-------------------------------------------------------------------------------
174
172
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−
218-- |
173-- |
219--
174--
220-- >>> null arr = Array.byteLength arr == 0
175-- >>> null arr = Array.byteLength arr == 0
@@ -222,7 +177,7 @@ readerUnsafe = Unfold step inject
222-- /Pre-release/
177-- /Pre-release/
223{-# INLINE null #-}
178{-# INLINE null #-}
224null :: Array a -> Bool
179null :: Array a -> Bool
225−null arr = A.byteLength arr == 0
180+null arr = byteLength arr == 0
226
181
227-- | Like 'getIndex' but indexes the array in reverse from the end.
182-- | Like 'getIndex' but indexes the array in reverse from the end.
228--
183--
@@ -234,7 +189,7 @@ getIndexRev i arr =
234 $ do
189 $ do
235 let elemPtr = RINDEX_OF(arrEnd arr, i, a)
190 let elemPtr = RINDEX_OF(arrEnd arr, i, a)
236 if i >= 0 && elemPtr >= arrStart arr
191 if i >= 0 && elemPtr >= arrStart arr
237− then Just <$> peekByteIndex elemPtr (arrContents arr)
192+ then Just <$> peekAt elemPtr (arrContents arr)
238 else return Nothing
193 else return Nothing
239
194
240-- |
195-- |
@@ -250,6 +205,8 @@ last = getIndexRev 0
250-- Folds with Array as the container
205-- Folds with Array as the container
251-------------------------------------------------------------------------------
206-------------------------------------------------------------------------------
252
207
208+-- XXX We should generate this from Ring.
209+
253-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
210-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
254-- stream to an 'Array'.
211-- stream to an 'Array'.
255--
212--
@@ -258,7 +215,7 @@ writeLastN ::
258 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
215 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
259writeLastN n
216writeLastN n
260 | n <= 0 = fmap (const mempty) FL.drain
217 | n <= 0 = fmap (const mempty) FL.drain
261− | otherwise = A.unsafeFreeze <$> Fold step initial done
218+ | otherwise = unsafeFreeze <$> Fold step initial done done
262
219
263 where
220 where
264
221
@@ -271,11 +228,9 @@ writeLastN n
271 in fmap f $ liftIO $ RB.new n
228 in fmap f $ liftIO $ RB.new n
272
229
273 done (Tuple3Fused' rb rh i) = do
230 done (Tuple3Fused' rb rh i) = do
274− arr <- liftIO $ MA.new n
231+ arr <- MA.new n
275− foldFunc i rh snoc' arr rb
276−
277− -- XXX We should write a read unfold for ring.
232+ -- XXX We should write a read unfold for ring.
278− snoc' b a = liftIO $ MA.snocUnsafe b a
233+ foldFunc i rh MA.snocUnsafe arr rb
279
234
280 foldFunc i
235 foldFunc i
281 | i < n = RB.unsafeFoldRingM
236 | i < n = RB.unsafeFoldRingM
@@ -301,19 +256,26 @@ binarySearch = undefined
301-- compared to streams by using SIMD instructions.
256-- compared to streams by using SIMD instructions.
302-- We can also return a bit array instead.
257-- We can also return a bit array instead.
303
258
259+-- Can use SIMD.
260+
304-- | Perform a linear search to find all the indices where a given element is
261-- | Perform a linear search to find all the indices where a given element is
305-- present in an array.
262-- present in an array.
306--
263--
307-- /Unimplemented/
264-- /Unimplemented/
308−findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
265+indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
309−findIndicesOf = undefined
266+indexFinder = undefined
267+
268+-- |
269+-- /Unimplemented/
270+findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
271+findIndicesOf p = Stream.unfold (indexFinder p)
310
272
311{-
273{-
312findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
274findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
313−findIndexOf p = Unfold.fold Fold.one . Stream.unfold (findIndicesOf p)
275+findIndexOf p = Unfold.fold Fold.one . Stream.unfold (indexFinder p)
314
276
315find :: (a -> Bool) -> Array a -> Bool
277find :: (a -> Bool) -> Array a -> Bool
316−find = Unfold.fold Fold.null . Stream.unfold (findIndicesOf p)
278+find = Unfold.fold Fold.null . Stream.unfold (indexFinder p)
317-}
279-}
318
280
319-------------------------------------------------------------------------------
281-------------------------------------------------------------------------------
@@ -355,29 +317,45 @@ splitOn :: (Monad m, Unbox a) =>
355 (a -> Bool) -> Array a -> Stream m (Array a)
317 (a -> Bool) -> Array a -> Stream m (Array a)
356splitOn predicate arr =
318splitOn predicate arr =
357 fmap (\(i, len) -> getSliceUnsafe i len arr)
319 fmap (\(i, len) -> getSliceUnsafe i len arr)
358− $ D.sliceOnSuffix predicate (A.toStreamD arr)
320+ $ D.indexOnSuffix predicate (read 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)
359
329
330+{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
360{-# INLINE genSlicesFromLen #-}
331{-# INLINE genSlicesFromLen #-}
361genSlicesFromLen :: forall m a. (Monad m, Unbox a)
332genSlicesFromLen :: forall m a. (Monad m, Unbox a)
362 => Int -- ^ from index
333 => Int -- ^ from index
363 -> Int -- ^ length of the slice
334 -> Int -- ^ length of the slice
364 -> Unfold m (Array a) (Int, Int)
335 -> Unfold m (Array a) (Int, Int)
365−genSlicesFromLen from len =
336+genSlicesFromLen = sliceIndexerFromLen
366− Unfold.lmap A.unsafeThaw (MA.genSlicesFromLen from len)
367
337
368-- | Generate a stream of slices of specified length from an array, starting
338-- | Generate a stream of slices of specified length from an array, starting
369-- from the supplied array index. The last slice may be shorter than the
339-- from the supplied array index. The last slice may be shorter than the
370-- requested length.
340-- requested length.
371--
341--
372-- /Pre-release//
342-- /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." #-}
373{-# INLINE getSlicesFromLen #-}
353{-# INLINE getSlicesFromLen #-}
374getSlicesFromLen :: forall m a. (Monad m, Unbox a)
354getSlicesFromLen :: forall m a. (Monad m, Unbox a)
375 => Int -- ^ from index
355 => Int -- ^ from index
376 -> Int -- ^ length of the slice
356 -> Int -- ^ length of the slice
377 -> Unfold m (Array a) (Array a)
357 -> Unfold m (Array a) (Array a)
378−getSlicesFromLen from len =
358+getSlicesFromLen = slicerFromLen
379− fmap A.unsafeFreeze
380− $ Unfold.lmap A.unsafeThaw (MA.getSlicesFromLen from len)
381
359
382-------------------------------------------------------------------------------
360-------------------------------------------------------------------------------
383-- Random reads and writes
361-- Random reads and writes
@@ -395,7 +373,7 @@ getIndex i arr =
395 $ do
373 $ do
396 let elemPtr = INDEX_OF(arrStart arr, i, a)
374 let elemPtr = INDEX_OF(arrStart arr, i, a)
397 if i >= 0 && INDEX_VALID(elemPtr, arrEnd arr, a)
375 if i >= 0 && INDEX_VALID(elemPtr, arrEnd arr, a)
398− then Just <$> peekByteIndex elemPtr (arrContents arr)
376+ then Just <$> peekAt elemPtr (arrContents arr)
399 else return Nothing
377 else return Nothing
400
378
401-- | Given a stream of array indices, read the elements on those indices from
379-- | Given a stream of array indices, read the elements on those indices from
@@ -407,19 +385,25 @@ getIndex i arr =
407-- @
385-- @
408-- read =
386-- read =
409-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
387-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
410−-- in Unfold.lmap f (getIndices arr)
388+-- in Unfold.lmap f (indexReader arr)
411--
389--
412-- readRev =
390-- readRev =
413-- let i = length arr - 1
391-- let i = length arr - 1
414−-- in Unfold.lmap f (getIndicesFromThenTo i (i - 1) 0)
392+-- in Unfold.lmap f (indexReaderFromThenTo i (i - 1) 0)
415-- @
393-- @
416--
394--
417-- /Pre-release/
395-- /Pre-release/
396+{-# INLINE indexReader #-}
397+indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
398+indexReader m =
399+ let unf = MA.indexReaderWith (return . unsafeInlineIO) m
400+ in Unfold.lmap unsafeThaw unf
401+
402+-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
403+{-# DEPRECATED getIndices "Please use getIndices instead." #-}
418{-# INLINE getIndices #-}
404{-# INLINE getIndices #-}
419getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
405getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
420−getIndices m =
406+getIndices = indexReader
421− let unf = MA.getIndicesD (return . unsafeInlineIO) m
422− in Unfold.lmap A.unsafeThaw unf
423
407
424-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
408-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
425-- element is the array value from the index @from@ and the successive elements
409-- element is the array value from the index @from@ and the successive elements
@@ -435,9 +419,9 @@ getIndices m =
435-- @
419-- @
436--
420--
437-- /Unimplemented/
421-- /Unimplemented/
438−{-# INLINE getIndicesFromThenTo #-}
422+{-# INLINE indexReaderFromThenTo #-}
439−getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
423+indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
440−getIndicesFromThenTo = undefined
424+indexReaderFromThenTo = undefined
441
425
442-------------------------------------------------------------------------------
426-------------------------------------------------------------------------------
443-- Transform via stream operations
427-- Transform via stream operations
@@ -454,7 +438,7 @@ getIndicesFromThenTo = undefined
454{-# INLINE runPipe #-}
438{-# INLINE runPipe #-}
455runPipe :: (MonadIO m, Unbox a, Unbox b)
439runPipe :: (MonadIO m, Unbox a, Unbox b)
456 => Pipe m a b -> Array a -> m (Array b)
440 => Pipe m a b -> Array a -> m (Array b)
457−runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
441+runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
458-}
442-}
459
443
460-- XXX For transformations that cannot change the number of elements e.g. "map"
444-- XXX For transformations that cannot change the number of elements e.g. "map"
@@ -468,7 +452,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
468streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
452streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
469 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
453 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
470streamTransform f arr =
454streamTransform f arr =
471− Stream.fold (A.writeWith (length arr)) $ f (A.read arr)
455+ Stream.fold (createWith (length arr)) $ f (read arr)
472
456
473-------------------------------------------------------------------------------
457-------------------------------------------------------------------------------
474-- Casts
458-- Casts
@@ -502,7 +486,7 @@ asBytes = castUnsafe
502--
486--
503cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
487cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
504cast arr =
488cast arr =
505− let len = A.byteLength arr
489+ let len = byteLength arr
506 r = len `mod` SIZE_OF(b)
490 r = len `mod` SIZE_OF(b)
507 in if r /= 0
491 in if r /= 0
508 then Nothing
492 then Nothing
@@ -520,9 +504,9 @@ cast arr =
520--
504--
521asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
505asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
522asCStringUnsafe arr act = do
506asCStringUnsafe arr act = do
523− let arr1 = asBytes arr <> A.fromList [0]
507+ let arr1 = asBytes arr <> fromList [0]
524− -- asPtrUnsafe makes sure the array is pinned
508+ -- unsafePinnedAsPtr makes sure the array is pinned
525− asPtrUnsafe arr1 $ \ptr -> act (castPtr ptr)
509+ unsafePinnedAsPtr arr1 $ \ptr -> act (castPtr ptr)
526
510
527-------------------------------------------------------------------------------
511-------------------------------------------------------------------------------
528-- Folds
512-- Folds
@@ -535,11 +519,500 @@ asCStringUnsafe arr act = do
535-- /Pre-release/
519-- /Pre-release/
536{-# INLINE fold #-}
520{-# INLINE fold #-}
537fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
521fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
538−fold f arr = Stream.fold f (A.read arr)
522+fold f arr = Stream.fold f (read arr)
539
523
540-- | Fold an array using a stream fold operation.
524-- | Fold an array using a stream fold operation.
541--
525--
542-- /Pre-release/
526-- /Pre-release/
543{-# INLINE streamFold #-}
527{-# INLINE streamFold #-}
544streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
528streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
545−streamFold f arr = f (A.read arr)
529+streamFold f arr = f (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+22−6
@@ -11,8 +11,8 @@ module Streamly.Internal.Data.Array.Generic
11
11
12 -- * Construction
12 -- * Construction
13 , nil
13 , nil
14− , writeN
14+ , createOf
15− , write
15+ , create
16 , writeWith
16 , writeWith
17 , writeLastN
17 , writeLastN
18
18
@@ -44,6 +44,10 @@ module Streamly.Internal.Data.Array.Generic
44 , getIndex
44 , getIndex
45 , getSliceUnsafe
45 , getSliceUnsafe
46 , strip
46 , strip
47+
48+ -- * Deprecated
49+ , writeN
50+ , write
47 )
51 )
48where
52where
49
53
@@ -104,21 +108,33 @@ nil = unsafePerformIO $ unsafeFreeze <$> MArray.nil
104-- Construction - Folds
108-- Construction - Folds
105-------------------------------------------------------------------------------
109-------------------------------------------------------------------------------
106
110
107−{-# INLINE_NORMAL writeN #-}
111+{-# INLINE_NORMAL createOf #-}
112+createOf :: MonadIO m => Int -> Fold m a (Array a)
113+createOf = fmap unsafeFreeze <$> MArray.createOf
114+
115+-- XXX Deprecate in major
116+-- {-# DEPRECATED writeN "Please use createOf instead." #-}
117+{-# INLINE writeN #-}
108writeN :: MonadIO m => Int -> Fold m a (Array a)
118writeN :: MonadIO m => Int -> Fold m a (Array a)
109−writeN = fmap unsafeFreeze <$> MArray.writeN
119+writeN = createOf
110
120
111{-# INLINE_NORMAL writeWith #-}
121{-# INLINE_NORMAL writeWith #-}
112writeWith :: MonadIO m => Int -> Fold m a (Array a)
122writeWith :: MonadIO m => Int -> Fold m a (Array a)
113−writeWith elemCount = unsafeFreeze <$> MArray.writeWith elemCount
123+writeWith elemCount = unsafeFreeze <$> MArray.createWith elemCount
114
124
115-- | Fold the whole input to a single array.
125-- | Fold the whole input to a single array.
116--
126--
117-- /Caution! Do not use this on infinite streams./
127-- /Caution! Do not use this on infinite streams./
118--
128--
129+{-# INLINE create #-}
130+create :: MonadIO m => Fold m a (Array a)
131+create = fmap unsafeFreeze MArray.create
132+
133+-- XXX Deprecate in major
134+-- {-# DEPRECATED write "Please use create instead." #-}
119{-# INLINE write #-}
135{-# INLINE write #-}
120write :: MonadIO m => Fold m a (Array a)
136write :: MonadIO m => Fold m a (Array a)
121−write = fmap unsafeFreeze MArray.write
137+write = create
122
138
123fromPureStream :: Stream Identity a -> Array a
139fromPureStream :: Stream Identity a -> Array a
124fromPureStream x =
140fromPureStream x =
core/src/Streamly/Internal/Data/Stream/Chunked.hs → core/src/Streamly/Internal/Data/Array/Stream.hsrenamed+74−586
@@ -1,5 +1,6 @@
1+{-# OPTIONS_GHC -Wno-deprecations #-}
1-- |
2-- |
2−-- Module : Streamly.Internal.Data.Stream.Chunked
3+-- Module : Streamly.Internal.Data.Array.Stream
3-- Copyright : (c) 2019 Composewell Technologies
4-- Copyright : (c) 2019 Composewell Technologies
4-- License : BSD3-3-Clause
5-- License : BSD3-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Maintainer : streamly@composewell.com
@@ -7,17 +8,25 @@
7--
8--
8-- Combinators to efficiently manipulate streams of immutable arrays.
9-- Combinators to efficiently manipulate streams of immutable arrays.
9--
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+--
10−module Streamly.Internal.Data.Stream.Chunked
14+module Streamly.Internal.Data.Array.Stream
15+{-# DEPRECATED "Please use \"Streamly.Internal.Data.Array\" instead." #-}
11 (
16 (
12 -- * Creation
17 -- * Creation
13− chunksOf
18+ Array.chunksOf
19+ , Array.pinnedChunksOf
20+ , Array.bufferChunks
14
21
15 -- * Flattening to elements
22 -- * Flattening to elements
16− , concat
23+ , Array.concat
24+ , Array.flattenArrays
17− , concatRev
25+ , Array.concatRev
26+ , Array.flattenArraysRev
18− , interpose
27+ , Array.interpose
19− , interposeSuffix
28+ , Array.interposeSuffix
20− , intercalateSuffix
29+ , Array.intercalateSuffix
21 , unlines
30 , unlines
22
31
23 -- * Elimination
32 -- * Elimination
@@ -26,24 +35,27 @@ module Streamly.Internal.Data.Stream.Chunked
26 -- can flatten the stream to byte stream and use that. But if we want the
35 -- can flatten the stream to byte stream and use that. But if we want the
27 -- remaining stream to be a chunk stream then this could be handy. But it
36 -- remaining stream to be a chunk stream then this could be handy. But it
28 -- could also be implemented using parseBreak.
37 -- could also be implemented using parseBreak.
29− , foldBreak -- StreamK.foldBreakChunks
38+ , foldBreak
30 , foldBreakD
39 , foldBreakD
31− -- The byte level parseBreak cannot work efficiently. Because the stream
40+ -- This is chunked parseBreak. A byte level parseBreak cannot work
41+ -- efficiently. Because the stream will have to be a StreamK for
32− -- will have to be a StreamK for backtracking, StreamK at byte level would
42+ -- backtracking, StreamK at byte level would not be efficient.
33− -- not be efficient.
34− , parseBreak -- StreamK.parseBreakChunks
43+ -- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
44+ , parseBreak
35 -- , parseBreakD
45 -- , parseBreakD
36 -- , foldManyChunks
46 -- , foldManyChunks
37 -- , parseManyChunks
47 -- , parseManyChunks
48+ , K.parseBreakChunks
49+ , K.parseChunks
38
50
39 -- ** Array Folds
51 -- ** Array Folds
40− -- XXX Use Parser.Chunked instead, need only chunkedParseBreak,
52+ -- XXX Use parseBreakChunks/parseChunks instead
41 -- foldBreak can be implemented using parseBreak. Use StreamK.
53 -- foldBreak can be implemented using parseBreak. Use StreamK.
42 , runArrayFold
54 , runArrayFold
43 , runArrayFoldBreak
55 , runArrayFoldBreak
44 -- , parseArr
56 -- , parseArr
45− , runArrayParserDBreak -- StreamK.chunkedParseBreak
57+ , runArrayParserDBreak -- StreamK.parseBreakChunks
46− , runArrayFoldMany -- StreamK.chunkedParseMany
58+ , runArrayFoldMany
47
59
48 , toArray
60 , toArray
49
61
@@ -67,6 +79,8 @@ where
67import Data.Bifunctor (second)
79import Data.Bifunctor (second)
68import Control.Exception (assert)
80import Control.Exception (assert)
69import Control.Monad.IO.Class (MonadIO(..))
81import Control.Monad.IO.Class (MonadIO(..))
82+-- import Data.Bifunctor (first)
83+-- import Data.Either (fromRight)
70import Data.Proxy (Proxy(..))
84import Data.Proxy (Proxy(..))
71import Data.Word (Word8)
85import Data.Word (Word8)
72import Streamly.Internal.Data.Unbox (Unbox(..))
86import Streamly.Internal.Data.Unbox (Unbox(..))
@@ -82,142 +96,32 @@ import Streamly.Internal.Data.Parser (ParseError(..))
82import Streamly.Internal.Data.Stream (Stream)
96import Streamly.Internal.Data.Stream (Stream)
83import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
97import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
84import Streamly.Internal.Data.SVar.Type (adaptState, defState)
98import Streamly.Internal.Data.SVar.Type (adaptState, defState)
85−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
86
99
87−import qualified Streamly.Data.Fold as FL
88import qualified Streamly.Internal.Data.Array as A
100import qualified Streamly.Internal.Data.Array as A
89import qualified Streamly.Internal.Data.Array as Array
101import 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(..))
93import qualified Streamly.Internal.Data.Parser as PR
102import qualified Streamly.Internal.Data.Parser as PR
94import qualified Streamly.Internal.Data.Parser as PRD
103import qualified Streamly.Internal.Data.Parser as PRD
95 (Parser(..), Initial(..))
104 (Parser(..), Initial(..))
105+-- import qualified Streamly.Internal.Data.ParserK as ParserK
96import qualified Streamly.Internal.Data.Stream as D
106import qualified Streamly.Internal.Data.Stream as D
97import qualified Streamly.Internal.Data.StreamK as K
107import qualified Streamly.Internal.Data.StreamK as K
98
108
99-- XXX Since these are immutable arrays MonadIO constraint can be removed from
109-- XXX Since these are immutable arrays MonadIO constraint can be removed from
100-- most places.
110-- most places.
101
111
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−
149-------------------------------------------------------------------------------
112-------------------------------------------------------------------------------
150-- Intersperse and append
113-- Intersperse and append
151-------------------------------------------------------------------------------
114-------------------------------------------------------------------------------
152
115
153−-- | Flatten a stream of arrays after inserting the given element between
154−-- arrays.
155−--
156−-- /Pre-release/
157−{-# INLINE interpose #-}
158−interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
159−interpose x = D.interpose x A.reader
160−
161−{-# INLINE intercalateSuffix #-}
162−intercalateSuffix :: (Monad m, Unbox a)
163− => Array a -> Stream m (Array a) -> Stream m a
164−intercalateSuffix = D.intercalateSuffix A.reader
165−
166−-- | Flatten a stream of arrays appending the given element after each
167−-- array.
168−--
169−-- @since 0.7.0
170−{-# INLINE interposeSuffix #-}
171−interposeSuffix :: (Monad m, Unbox a)
172− => a -> Stream m (Array a) -> Stream m a
173−-- interposeSuffix x = fromStreamD . A.unlines x . toStreamD
174−interposeSuffix x = D.interposeSuffix x A.reader
175−
176−data FlattenState s =
177− OuterLoop s
178− | InnerLoop s !MA.MutableByteArray !Int !Int
179−
180−-- XXX This is a special case of interposeSuffix, can be removed.
181−-- XXX Remove monadIO constraint
182{-# INLINE_NORMAL unlines #-}
116{-# INLINE_NORMAL unlines #-}
183unlines :: forall m a. (MonadIO m, Unbox a)
117unlines :: forall m a. (MonadIO m, Unbox a)
184 => a -> D.Stream m (Array a) -> D.Stream m a
118 => a -> D.Stream m (Array a) -> D.Stream m a
185−unlines sep (D.Stream step state) = D.Stream step' (OuterLoop state)
119+unlines = Array.interposeSuffix
186− where
187− {-# INLINE_LATE step' #-}
188− step' gst (OuterLoop st) = do
189− r <- step (adaptState gst) st
190− return $ case r of
191− D.Yield Array{..} s ->
192− D.Skip (InnerLoop s arrContents arrStart arrEnd)
193− D.Skip s -> D.Skip (OuterLoop s)
194− D.Stop -> D.Stop
195−
196− step' _ (InnerLoop st _ p end) | p == end =
197− return $ D.Yield sep $ OuterLoop st
198−
199− step' _ (InnerLoop st contents p end) = do
200− x <- liftIO $ peekByteIndex p contents
201− return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
202
120
203-------------------------------------------------------------------------------
121-------------------------------------------------------------------------------
204-- Compact
122-- Compact
205-------------------------------------------------------------------------------
123-------------------------------------------------------------------------------
206
124
207−-- XXX These would not be needed once we implement compactLEFold, see
208−-- module Streamly.Internal.Data.Stream.MutChunked
209−--
210−-- XXX Note that this thaws immutable arrays for appending, that may be
211−-- problematic if multiple users do the same thing, however, immutable arrays
212−-- would usually have no capacity to append, therefore, a copy will be forced
213−-- anyway. Confirm this. We can forcefully trim the array capacity before thaw
214−-- to ensure this.
215−{-# INLINE_NORMAL packArraysChunksOf #-}
216−packArraysChunksOf :: (MonadIO m, Unbox a)
217− => Int -> D.Stream m (Array a) -> D.Stream m (Array a)
218−packArraysChunksOf n str =
219− D.map A.unsafeFreeze $ AS.packArraysChunksOf n $ D.map A.unsafeThaw str
220−
221-- XXX instead of writing two different versions of this operation, we should
125-- XXX instead of writing two different versions of this operation, we should
222-- write it as a pipe.
126-- write it as a pipe.
223--
127--
@@ -225,8 +129,7 @@ packArraysChunksOf n str =
225{-# INLINE_NORMAL lpackArraysChunksOf #-}
129{-# INLINE_NORMAL lpackArraysChunksOf #-}
226lpackArraysChunksOf :: (MonadIO m, Unbox a)
130lpackArraysChunksOf :: (MonadIO m, Unbox a)
227 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
131 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
228−lpackArraysChunksOf n fld =
132+lpackArraysChunksOf = Array.lCompactGE
229− FL.lmap A.unsafeThaw $ AS.lpackArraysChunksOf n (FL.lmap A.unsafeFreeze fld)
230
133
231-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
134-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
232-- maximum specified size in bytes.
135-- maximum specified size in bytes.
@@ -235,68 +138,19 @@ lpackArraysChunksOf n fld =
235{-# INLINE compact #-}
138{-# INLINE compact #-}
236compact :: (MonadIO m, Unbox a)
139compact :: (MonadIO m, Unbox a)
237 => Int -> Stream m (Array a) -> Stream m (Array a)
140 => Int -> Stream m (Array a) -> Stream m (Array a)
238−compact = packArraysChunksOf
141+compact = Array.compactLE
239
142
240−-------------------------------------------------------------------------------
143+-- | Given a stream of arrays, splice them all together to generate a single
241−-- Split
144+-- array. The stream must be /finite/.
242−-------------------------------------------------------------------------------
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--
145--
254-- @since 0.7.0
146-- @since 0.7.0
255−{-# INLINE_NORMAL _splitOn #-}
147+{-# INLINE toArray #-}
256−_splitOn
257− :: MonadIO m
258− => Word8
259− -> D.Stream m (Array Word8)
148+toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
260− -> D.Stream m (Array Word8)
149+toArray = Array.fromChunks
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
150
298− step' _ (Yielding arr next) = return $ D.Yield arr next
151+-------------------------------------------------------------------------------
299− step' _ Finishing = return D.Stop
152+-- Split
153+-------------------------------------------------------------------------------
300
154
301-- XXX Remove MonadIO constraint.
155-- XXX Remove MonadIO constraint.
302-- | Split a stream of arrays on a given separator byte, dropping the separator
156-- | Split a stream of arrays on a given separator byte, dropping the separator
@@ -309,7 +163,7 @@ splitOn
309 => Word8
163 => Word8
310 -> Stream m (Array Word8)
164 -> Stream m (Array Word8)
311 -> Stream m (Array Word8)
165 -> Stream m (Array Word8)
312−splitOn byte = D.splitInnerBy (A.breakOn byte) A.splice
166+splitOn = Array.compactOnByte
313
167
314{-# INLINE splitOnSuffix #-}
168{-# INLINE splitOnSuffix #-}
315splitOnSuffix
169splitOnSuffix
@@ -317,8 +171,7 @@ splitOnSuffix
317 => Word8
171 => Word8
318 -> Stream m (Array Word8)
172 -> Stream m (Array Word8)
319 -> Stream m (Array Word8)
173 -> Stream m (Array Word8)
320−-- splitOn byte s = fromStreamD $ A.splitOn byte $ toStreamD s
174+splitOnSuffix = Array.compactOnByteSuffix
321−splitOnSuffix byte = D.splitInnerBySuffix (A.breakOn byte) A.splice
322
175
323-------------------------------------------------------------------------------
176-------------------------------------------------------------------------------
324-- Elimination - Running folds
177-- Elimination - Running folds
@@ -327,77 +180,24 @@ splitOnSuffix byte = D.splitInnerBySuffix (A.breakOn byte) A.splice
327{-# INLINE_NORMAL foldBreakD #-}
180{-# INLINE_NORMAL foldBreakD #-}
328foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
181foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
329 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
182 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
330−foldBreakD (FL.Fold fstep initial extract) stream@(D.Stream step state) = do
183+foldBreakD = Array.foldBreakChunks
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
395
184
396-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
185-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
397-- and the unconsumed stream.
186-- and the unconsumed stream.
398--
187--
399-- > foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
188-- > foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
400--
189--
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+--
401-- /Internal/
201-- /Internal/
402--
202--
403{-# INLINE_NORMAL foldBreak #-}
203{-# INLINE_NORMAL foldBreak #-}
@@ -406,14 +206,20 @@ foldBreak ::
406 => Fold m a b
206 => Fold m a b
407 -> StreamK m (A.Array a)
207 -> StreamK m (A.Array a)
408 -> m (b, StreamK m (A.Array a))
208 -> m (b, StreamK m (A.Array a))
209+foldBreak = Array.foldBreakChunksK
210+--
409-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
211-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
212+--
410−foldBreak = foldBreakK
213+-- foldBreak f s =
214+-- fmap (first (fromRight undefined))
215+-- $ K.parseBreakChunks (ParserK.adaptC (PR.fromFold f)) s
216+--
411-- If foldBreak performs better than runArrayFoldBreak we can use a rewrite
217-- If foldBreak performs better than runArrayFoldBreak we can use a rewrite
412-- rule to rewrite runArrayFoldBreak to fold.
218-- rule to rewrite runArrayFoldBreak to fold.
413-- foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
219-- foldBreak f = runArrayFoldBreak (ChunkFold.fromFold f)
414
220
415-------------------------------------------------------------------------------
221-------------------------------------------------------------------------------
416−-- Fold to a single Array
222+-- Elimination - running element parsers
417-------------------------------------------------------------------------------
223-------------------------------------------------------------------------------
418
224
419-- When we have to take an array partially, take the last part of the array.
225-- When we have to take an array partially, take the last part of the array.
@@ -459,341 +265,22 @@ splitAtArrayListRev n ls
459 arr1 = Array contents end1 end
265 arr1 = Array contents end1 end
460 in ([arr1], arr2:xs)
266 in ([arr1], arr2:xs)
461
267
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−
559-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
268-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
560-- to make a newtype.
269-- to make a newtype.
561{-# ANN type List NoSpecConstr #-}
270{-# ANN type List NoSpecConstr #-}
562newtype List a = List {getList :: [a]}
271newtype List a = List {getList :: [a]}
563
272
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−
794-- | Parse an array stream using the supplied 'Parser'. Returns the parse
273-- | Parse an array stream using the supplied 'Parser'. Returns the parse
795-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
274-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
796--
275--
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+--
797-- /Internal/
284-- /Internal/
798--
285--
799{-# INLINE_NORMAL parseBreak #-}
286{-# INLINE_NORMAL parseBreak #-}
@@ -806,7 +293,8 @@ parseBreak ::
806parseBreak p s =
293parseBreak p s =
807 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
294 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
808-}
295-}
809−parseBreak = parseBreakK
296+parseBreak = Array.parseBreakChunksK
297+-- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
810
298
811-------------------------------------------------------------------------------
299-------------------------------------------------------------------------------
812-- Elimination - Running Array Folds and parsers
300-- Elimination - Running Array Folds and parsers
core/src/Streamly/Internal/Data/Array/Type.hs+517−109
@@ -1,8 +1,11 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE TypeFamilies #-}
3+-- Must come after TypeFamilies, otherwise it is re-enabled.
4+-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
5+{-# LANGUAGE NoMonoLocalBinds #-}
2-- |
6-- |
3-- Module : Streamly.Internal.Data.Array.Type
7-- Module : Streamly.Internal.Data.Array.Type
4-- Copyright : (c) 2020 Composewell Technologies
8-- Copyright : (c) 2020 Composewell Technologies
5−--
6-- License : BSD3-3-Clause
9-- License : BSD3-3-Clause
7-- Maintainer : streamly@composewell.com
10-- Maintainer : streamly@composewell.com
8-- Stability : experimental
11-- Stability : experimental
@@ -10,86 +13,146 @@
10--
13--
11-- See notes in "Streamly.Internal.Data.MutArray.Type"
14-- See notes in "Streamly.Internal.Data.MutArray.Type"
12--
15--
16+
13module Streamly.Internal.Data.Array.Type
17module Streamly.Internal.Data.Array.Type
14 (
18 (
19+ -- ** Type
15 -- $arrayNotes
20 -- $arrayNotes
16 Array (..)
21 Array (..)
17− , asPtrUnsafe
18− , nil
19
22
20− -- * Freezing and Thawing
23+ -- ** Conversion
24+ -- *** Mutable and Immutable
21 , unsafeFreeze
25 , unsafeFreeze
22 , unsafeFreezeWithShrink
26 , unsafeFreezeWithShrink
23 , unsafeThaw
27 , unsafeThaw
24
28
25− -- * Pinning and Unpinning
29+ -- *** Pinned and Unpinned
26 , pin
30 , pin
27 , unpin
31 , unpin
28 , isPinned
32 , isPinned
29
33
30− -- * Construction
34+ -- *** Casting
31− , splice
35+ , unsafePinnedAsPtr
32
36
33− , fromList
37+ -- ** Construction
34− , pinnedFromList
38+ , empty
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+
50+ -- *** Stream Folds
51+ , unsafeMakePure
52+ , createOf
53+ , pinnedCreateOf
54+ , unsafeCreateOf
55+ , unsafePinnedCreateOf
56+ , create
57+ , pinnedCreate
58+ , createWith
59+
60+ -- *** From containers
35 , fromListN
61 , fromListN
36 , pinnedFromListN
62 , pinnedFromListN
37− , fromListRev
63+ , fromList
64+ , pinnedFromList
38 , fromListRevN
65 , fromListRevN
39− , fromStreamDN
66+ , fromListRev
40− , fromStreamD
67+ , fromStreamN
68+ , fromStream
69+ , fromPureStreamN
41 , fromPureStream
70 , fromPureStream
42 , fromByteStr#
71 , fromByteStr#
72+ , fromByteStr
73+ , fromPtrN
74+ , fromChunks
75+ , fromChunksK
43
76
44− -- * Split
77+ -- ** Reading
45− , breakOn
46
78
47− -- ** Cloning arrays
79+ -- *** Indexing
48− , clone
80+ , unsafeIndexIO -- XXX unsafeGetIndexIO
49− , pinnedClone
81+ , getIndexUnsafe -- XXX unsafeGetIndex
50
82
51− -- * Elimination
83+ -- *** To Streams
52− , unsafeIndexIO
84+ , read
53− , getIndexUnsafe
85+ , readRev
54− , byteLength
86+ , toStreamK
87+ , toStreamKRev
88+
89+ -- *** To Containers
90+ , toList
91+
92+ -- *** Unfolds
93+ , producer -- experimental
94+ , readerUnsafe
95+ , reader
96+ , readerRev
97+
98+ -- *** Size
55 , length
99 , length
100+ , byteLength
56
101
102+ -- ** Folding
57 , foldl'
103 , foldl'
58 , foldr
104 , foldr
59− , splitAt
105+ , byteCmp
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
60
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+
134+ -- ** Deprecated
135+ , asPtrUnsafe
136+ , unsafeIndex
137+ , bufferChunks
138+ , flattenArrays
139+ , flattenArraysRev
140+ , fromArrayStreamK
141+ , fromStreamDN
142+ , fromStreamD
61 , toStreamD
143 , toStreamD
62 , toStreamDRev
144 , toStreamDRev
63− , toStreamK
64− , toStreamKRev
65 , toStream
145 , toStream
66 , toStreamRev
146 , toStreamRev
67− , read
147+ , nil
68− , readRev
69− , readerRev
70− , toList
71−
72− -- * Folds
73 , writeWith
148 , writeWith
74 , writeN
149 , writeN
75 , pinnedWriteN
150 , pinnedWriteN
76 , writeNUnsafe
151 , writeNUnsafe
77 , pinnedWriteNUnsafe
152 , pinnedWriteNUnsafe
78− , MA.ArrayUnsafe (..)
79 , pinnedWriteNAligned
153 , pinnedWriteNAligned
80 , write
154 , write
81 , pinnedWrite
155 , pinnedWrite
82− , unsafeMakePure
83−
84− -- * Streams of arrays
85− , chunksOf
86− , pinnedChunksOf
87− , bufferChunks
88− , flattenArrays
89− , flattenArraysRev
90−
91− -- * Deprecated
92− , unsafeIndex
93 )
156 )
94where
157where
95
158
@@ -97,31 +160,36 @@ where
97#include "inline.hs"
160#include "inline.hs"
98
161
99import Control.Exception (assert)
162import Control.Exception (assert)
100−import Control.Monad (replicateM)
163+import Control.Monad (replicateM, when)
101import Control.Monad.IO.Class (MonadIO(..))
164import Control.Monad.IO.Class (MonadIO(..))
102import Data.Functor.Identity (Identity(..))
165import Data.Functor.Identity (Identity(..))
166+import Data.Int (Int8, Int16, Int32, Int64)
103import Data.Proxy (Proxy(..))
167import Data.Proxy (Proxy(..))
104−import Data.Word (Word8)
168+import Data.Word (Word8, Word16, Word32, Word64)
105import GHC.Base (build)
169import GHC.Base (build)
106import GHC.Exts (IsList, IsString(..), Addr#)
170import GHC.Exts (IsList, IsString(..), Addr#)
107
171
108import GHC.IO (unsafePerformIO)
172import GHC.IO (unsafePerformIO)
109import GHC.Ptr (Ptr(..))
173import GHC.Ptr (Ptr(..))
110−import Streamly.Internal.Data.MutArray.Type (MutArray(..), MutableByteArray)
174+import Streamly.Internal.Data.Producer.Type (Producer(..))
175+import Streamly.Internal.Data.MutArray.Type (MutArray(..))
176+import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
111import Streamly.Internal.Data.Fold.Type (Fold(..))
177import Streamly.Internal.Data.Fold.Type (Fold(..))
112import Streamly.Internal.Data.Stream.Type (Stream)
178import Streamly.Internal.Data.Stream.Type (Stream)
179+import Streamly.Internal.Data.StreamK.Type (StreamK)
113import Streamly.Internal.Data.Unbox (Unbox(..))
180import Streamly.Internal.Data.Unbox (Unbox(..))
114import Streamly.Internal.Data.Unfold.Type (Unfold(..))
181import Streamly.Internal.Data.Unfold.Type (Unfold(..))
115import Text.Read (readPrec)
182import Text.Read (readPrec)
116
183
117−import Prelude hiding (Foldable(..), read, unlines, splitAt)
184+import Prelude hiding (Foldable(..), concat, read, unlines, splitAt)
118
185
119import qualified GHC.Exts as Exts
186import qualified GHC.Exts as Exts
187+import qualified Streamly.Internal.Data.Fold.Type as Fold
120import qualified Streamly.Internal.Data.MutArray.Type as MA
188import qualified Streamly.Internal.Data.MutArray.Type as MA
121import qualified Streamly.Internal.Data.Stream.Type as D
189import qualified Streamly.Internal.Data.Stream.Type as D
122−import qualified Streamly.Internal.Data.Stream.Generate as D
123import qualified Streamly.Internal.Data.StreamK.Type as K
190import qualified Streamly.Internal.Data.StreamK.Type as K
124−import qualified Streamly.Internal.Data.Unbox as Unboxed
191+import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
192+import qualified Streamly.Internal.Data.Producer as Producer
125import qualified Streamly.Internal.Data.Unfold.Type as Unfold
193import qualified Streamly.Internal.Data.Unfold.Type as Unfold
126import qualified Text.ParserCombinators.ReadPrec as ReadPrec
194import qualified Text.ParserCombinators.ReadPrec as ReadPrec
127
195
@@ -164,7 +232,7 @@ data Array a =
164#endif
232#endif
165 -- All offsets are in terms of bytes from the start of arraycontents
233 -- All offsets are in terms of bytes from the start of arraycontents
166 Array
234 Array
167− { arrContents :: {-# UNPACK #-} !MutableByteArray
235+ { arrContents :: {-# UNPACK #-} !MutByteArray
168 , arrStart :: {-# UNPACK #-} !Int -- offset
236 , arrStart :: {-# UNPACK #-} !Int -- offset
169 , arrEnd :: {-# UNPACK #-} !Int -- offset + len
237 , arrEnd :: {-# UNPACK #-} !Int -- offset + len
170 }
238 }
@@ -175,15 +243,20 @@ data Array a =
175
243
176-- | Use an @Array a@ as @Ptr a@.
244-- | Use an @Array a@ as @Ptr a@.
177--
245--
178−-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
246+-- See 'MA.unsafePinnedAsPtr' in the Mutable array module for more details.
179--
247--
180-- /Unsafe/
248-- /Unsafe/
181--
249--
182-- /Pre-release/
250-- /Pre-release/
183--
251--
252+{-# INLINE unsafePinnedAsPtr #-}
253+unsafePinnedAsPtr :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
254+unsafePinnedAsPtr arr = MA.unsafePinnedAsPtr (unsafeThaw arr)
255+
256+{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
184{-# INLINE asPtrUnsafe #-}
257{-# INLINE asPtrUnsafe #-}
185asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
258asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
186−asPtrUnsafe arr = MA.asPtrUnsafe (unsafeThaw arr)
259+asPtrUnsafe = unsafePinnedAsPtr
187
260
188-------------------------------------------------------------------------------
261-------------------------------------------------------------------------------
189-- Freezing and Thawing
262-- Freezing and Thawing
@@ -230,18 +303,19 @@ unsafeThaw (Array ac as ae) = MutArray ac as ae ae
230-- Pinning & Unpinning
303-- Pinning & Unpinning
231-------------------------------------------------------------------------------
304-------------------------------------------------------------------------------
232
305
233−-- | Copy the 'Array' to pinned memory if unpinned, else do nothing. The
306+-- | Return a copy of the 'Array' in pinned memory if unpinned, else return the
234−-- overhead is a copy if the input array is unpinned.
307+-- original array.
235{-# INLINE pin #-}
308{-# INLINE pin #-}
236pin :: Array a -> IO (Array a)
309pin :: Array a -> IO (Array a)
237pin = fmap unsafeFreeze . MA.pin . unsafeThaw
310pin = fmap unsafeFreeze . MA.pin . unsafeThaw
238
311
239−-- | Copy the 'Array' to unpinned memory if pinned, else do nothing. The
312+-- | Return a copy of the 'Array' in unpinned memory if pinned, else return the
240−-- overhead is a copy if the input array is pinned.
313+-- original array.
241{-# INLINE unpin #-}
314{-# INLINE unpin #-}
242unpin :: Array a -> IO (Array a)
315unpin :: Array a -> IO (Array a)
243unpin = fmap unsafeFreeze . MA.unpin . unsafeThaw
316unpin = fmap unsafeFreeze . MA.unpin . unsafeThaw
244
317
318+-- | Return 'True' if the array is allocated in pinned memory.
245{-# INLINE isPinned #-}
319{-# INLINE isPinned #-}
246isPinned :: Array a -> Bool
320isPinned :: Array a -> Bool
247isPinned = MA.isPinned . unsafeThaw
321isPinned = MA.isPinned . unsafeThaw
@@ -250,11 +324,14 @@ isPinned = MA.isPinned . unsafeThaw
250-- Construction
324-- Construction
251-------------------------------------------------------------------------------
325-------------------------------------------------------------------------------
252
326
253−-- Splice two immutable arrays creating a new array.
327+-- | Copy two immutable arrays into a new array. If you want to splice more
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.
254{-# INLINE splice #-}
331{-# INLINE splice #-}
255−splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
332+splice :: MonadIO m => Array a -> Array a -> m (Array a)
256splice arr1 arr2 =
333splice arr1 arr2 =
257− unsafeFreeze <$> MA.splice (unsafeThaw arr1) (unsafeThaw arr2)
334+ unsafeFreeze <$> MA.spliceCopy (unsafeThaw arr1) (unsafeThaw arr2)
258
335
259-- | Create an 'Array' from the first N elements of a list. The array is
336-- | Create an 'Array' from the first N elements of a list. The array is
260-- allocated to size N, if the list terminates before N elements then the
337-- allocated to size N, if the list terminates before N elements then the
@@ -298,36 +375,83 @@ pinnedFromList xs = unsafePerformIO $ unsafeFreeze <$> MA.pinnedFromList xs
298fromListRev :: Unbox a => [a] -> Array a
375fromListRev :: Unbox a => [a] -> Array a
299fromListRev xs = unsafePerformIO $ unsafeFreeze <$> MA.fromListRev xs
376fromListRev xs = unsafePerformIO $ unsafeFreeze <$> MA.fromListRev xs
300
377
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/
301−{-# INLINE_NORMAL fromStreamDN #-}
385+{-# INLINE_NORMAL fromStreamN #-}
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." #-}
302fromStreamDN :: forall m a. (MonadIO m, Unbox a)
393fromStreamDN :: forall m a. (MonadIO m, Unbox a)
303 => Int -> D.Stream m a -> m (Array a)
394 => Int -> D.Stream m a -> m (Array a)
304−fromStreamDN limit str = unsafeFreeze <$> MA.fromStreamDN limit str
395+fromStreamDN = fromStreamN
305
396
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/
306{-# INLINE_NORMAL fromStreamD #-}
408{-# 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." #-}
307fromStreamD :: forall m a. (MonadIO m, Unbox a)
414fromStreamD :: forall m a. (MonadIO m, Unbox a)
308 => D.Stream m a -> m (Array a)
415 => D.Stream m a -> m (Array a)
309−fromStreamD str = unsafeFreeze <$> MA.fromStreamD str
416+fromStreamD = fromStream
310
417
311-------------------------------------------------------------------------------
418-------------------------------------------------------------------------------
312-- Cloning
419-- Cloning
313-------------------------------------------------------------------------------
420-------------------------------------------------------------------------------
314
421
315{-# INLINE clone #-}
422{-# INLINE clone #-}
423+clone ::
424+ ( MonadIO m
425+#ifdef DEVBUILD
426+ , Unbox a
427+#endif
428+ )
316−clone :: MonadIO m => Array a -> m (Array a)
429+ => Array a -> m (Array a)
317clone = fmap unsafeFreeze . MA.clone . unsafeThaw
430clone = fmap unsafeFreeze . MA.clone . unsafeThaw
318
431
319{-# INLINE pinnedClone #-}
432{-# INLINE pinnedClone #-}
433+pinnedClone ::
434+ ( MonadIO m
435+#ifdef DEVBUILD
436+ , Unbox a
437+#endif
438+ )
320−pinnedClone :: MonadIO m => Array a -> m (Array a)
439+ => Array a -> m (Array a)
321pinnedClone = fmap unsafeFreeze . MA.pinnedClone . unsafeThaw
440pinnedClone = fmap unsafeFreeze . MA.pinnedClone . unsafeThaw
322
441
323-------------------------------------------------------------------------------
442-------------------------------------------------------------------------------
324-- Streams of arrays
443-- Streams of arrays
325-------------------------------------------------------------------------------
444-------------------------------------------------------------------------------
326
445
327−{-# INLINE bufferChunks #-}
446+{-# INLINE buildChunks #-}
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." #-}
328bufferChunks :: (MonadIO m, Unbox a) =>
452bufferChunks :: (MonadIO m, Unbox a) =>
329 D.Stream m a -> m (K.StreamK m (Array a))
453 D.Stream m a -> m (K.StreamK m (Array a))
330−bufferChunks m = D.foldr K.cons K.nil $ chunksOf defaultChunkSize m
454+bufferChunks = buildChunks
331
455
332-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
456-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
333-- @n@ elements each.
457-- @n@ elements each.
@@ -348,27 +472,100 @@ pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
348 => Int -> D.Stream m a -> D.Stream m (Array a)
472 => Int -> D.Stream m a -> D.Stream m (Array a)
349pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
473pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
350
474
351−-- | Use the "read" unfold instead.
475+-- | Convert a stream of arrays into a stream of their elements.
352--
476--
353−-- @flattenArrays = unfoldMany read@
477+-- >>> concat = Stream.unfoldMany Array.reader
354--
478--
355−-- We can try this if there are any fusion issues in the unfold.
479+{-# INLINE_NORMAL concat #-}
356−--
480+concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
481+-- XXX this requires MonadIO whereas the unfoldMany version does not
482+concat = MA.concatWith (pure . unsafeInlineIO) . D.map unsafeThaw
483+-- concat = D.unfoldMany reader
484+
485+{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
357−{-# INLINE_NORMAL flattenArrays #-}
486+{-# INLINE flattenArrays #-}
358flattenArrays :: forall m a. (MonadIO m, Unbox a)
487flattenArrays :: forall m a. (MonadIO m, Unbox a)
359 => D.Stream m (Array a) -> D.Stream m a
488 => D.Stream m (Array a) -> D.Stream m a
360−flattenArrays = MA.flattenArrays . D.map unsafeThaw
489+flattenArrays = concat
361
490
362−-- | Use the "readRev" unfold instead.
491+-- | Convert a stream of arrays into a stream of their elements reversing the
363−--
492+-- contents of each array before flattening.
364−-- @flattenArrays = unfoldMany readRev@
365--
493--
366−-- We can try this if there are any fusion issues in the unfold.
494+-- >>> concatRev = Stream.unfoldMany Array.readerRev
367--
495--
496+{-# INLINE_NORMAL concatRev #-}
497+concatRev :: forall m a. (Monad m, Unbox a)
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." #-}
368−{-# INLINE_NORMAL flattenArraysRev #-}
504+{-# INLINE flattenArraysRev #-}
369flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
505flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
370 => D.Stream m (Array a) -> D.Stream m a
506 => D.Stream m (Array a) -> D.Stream m a
371−flattenArraysRev = MA.flattenArraysRev . D.map unsafeThaw
507+flattenArraysRev = concatRev
508+
509+-------------------------------------------------------------------------------
510+-- Compact
511+-------------------------------------------------------------------------------
512+
513+-- XXX Note that this thaws immutable arrays for appending, that may be
514+-- problematic if multiple users do the same thing, however, thawed immutable
515+-- arrays would have no capacity to append, therefore, a copy will be forced
516+-- anyway.
517+
518+-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
519+-- until the size becomes greater than or equal to n.
520+--
521+-- Generates unpinned arrays irrespective of the pinning status of input
522+-- arrays.
523+{-# INLINE_NORMAL fCompactGE #-}
524+fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
525+fCompactGE n = fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fCompactGE n
526+
527+-- | PInned version of 'fCompactGE'.
528+{-# INLINE_NORMAL fPinnedCompactGE #-}
529+fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
530+fPinnedCompactGE n =
531+ fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fPinnedCompactGE n
532+
533+-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
534+-- the size becomes greater than or equal to @n@.
535+--
536+-- >>> compactGE n = Stream.foldMany (Array.fCompactGE n)
537+--
538+-- Generates unpinned arrays irrespective of the pinning status of input
539+-- arrays.
540+{-# INLINE compactGE #-}
541+compactGE ::
542+ (MonadIO m, Unbox a)
543+ => Int -> Stream m (Array a) -> Stream m (Array a)
544+compactGE n stream =
545+ D.map unsafeFreeze $ MA.compactGE n $ D.map unsafeThaw stream
546+
547+-- | Like 'compactGE' but for transforming folds instead of stream.
548+--
549+-- >>> lCompactGE n = Fold.many (Array.fCompactGE n)
550+--
551+-- Generates unpinned arrays irrespective of the pinning status of input
552+-- arrays.
553+{-# INLINE_NORMAL lCompactGE #-}
554+lCompactGE :: (MonadIO m, Unbox a)
555+ => Int -> Fold m (Array a) () -> Fold m (Array a) ()
556+lCompactGE n fld =
557+ Fold.lmap unsafeThaw $ MA.lCompactGE n (Fold.lmap unsafeFreeze fld)
558+
559+-- | Pinned version of 'lCompactGE'.
560+{-# INLINE_NORMAL lPinnedCompactGE #-}
561+lPinnedCompactGE :: (MonadIO m, Unbox a)
562+ => Int -> Fold m (Array a) () -> Fold m (Array a) ()
563+lPinnedCompactGE n fld =
564+ Fold.lmap unsafeThaw $ MA.lPinnedCompactGE n (Fold.lmap unsafeFreeze fld)
565+
566+-------------------------------------------------------------------------------
567+-- Splitting
568+-------------------------------------------------------------------------------
372
569
373-- Drops the separator byte
570-- Drops the separator byte
374{-# INLINE breakOn #-}
571{-# INLINE breakOn #-}
@@ -412,24 +609,68 @@ byteLength = MA.byteLength . unsafeThaw
412length :: Unbox a => Array a -> Int
609length :: Unbox a => Array a -> Int
413length arr = MA.length (unsafeThaw arr)
610length arr = MA.length (unsafeThaw arr)
414
611
612+{-# INLINE_NORMAL producer #-}
613+producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
614+producer =
615+ Producer.translate unsafeThaw unsafeFreeze
616+ $ MA.producerWith (return . unsafeInlineIO)
617+
618+-- | Unfold an array into a stream.
619+--
620+{-# INLINE_NORMAL reader #-}
621+reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
622+reader = Producer.simplify producer
623+
624+-- | Unfold an array into a stream, does not check the end of the array, the
625+-- user is responsible for terminating the stream within the array bounds. For
626+-- high performance application where the end condition can be determined by
627+-- a terminating fold.
628+--
629+-- Written in the hope that it may be faster than "read", however, in the case
630+-- for which this was written, "read" proves to be faster even though the core
631+-- generated with unsafeRead looks simpler.
632+--
633+-- /Pre-release/
634+--
635+{-# INLINE_NORMAL readerUnsafe #-}
636+readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
637+readerUnsafe = Unfold step inject
638+ where
639+
640+ inject (Array contents start end) =
641+ return (MA.ArrayUnsafe contents end start)
642+
643+ {-# INLINE_LATE step #-}
644+ step (MA.ArrayUnsafe contents end p) = do
645+ -- unsafeInlineIO allows us to run this in Identity monad for pure
646+ -- toList/foldr case which makes them much faster due to not
647+ -- accumulating the list and fusing better with the pure consumers.
648+ --
649+ -- This should be safe as the array contents are guaranteed to be
650+ -- evaluated/written to before we peek at them.
651+ let !x = unsafeInlineIO $ peekAt p contents
652+ let !p1 = INDEX_NEXT(p,a)
653+ return $ D.Yield x (MA.ArrayUnsafe contents end p1)
654+
415-- | Unfold an array into a stream in reverse order.
655-- | Unfold an array into a stream in reverse order.
416--
656--
417{-# INLINE_NORMAL readerRev #-}
657{-# INLINE_NORMAL readerRev #-}
418readerRev :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
658readerRev :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
419readerRev = Unfold.lmap unsafeThaw $ MA.readerRevWith (return . unsafeInlineIO)
659readerRev = Unfold.lmap unsafeThaw $ MA.readerRevWith (return . unsafeInlineIO)
420
660
661+{-# DEPRECATED toStreamD "Please use 'read' instead." #-}
421{-# INLINE_NORMAL toStreamD #-}
662{-# INLINE_NORMAL toStreamD #-}
422toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
663toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
423−toStreamD arr = MA.toStreamDWith (return . unsafeInlineIO) (unsafeThaw arr)
664+toStreamD = read
424
665
425{-# INLINE toStreamK #-}
666{-# INLINE toStreamK #-}
426toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
667toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
427toStreamK arr = MA.toStreamKWith (return . unsafeInlineIO) (unsafeThaw arr)
668toStreamK arr = MA.toStreamKWith (return . unsafeInlineIO) (unsafeThaw arr)
428
669
670+{-# DEPRECATED toStreamDRev "Please use 'readRev' instead." #-}
429{-# INLINE_NORMAL toStreamDRev #-}
671{-# INLINE_NORMAL toStreamDRev #-}
430toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
672toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
431−toStreamDRev arr =
673+toStreamDRev = readRev
432− MA.toStreamDRevWith (return . unsafeInlineIO) (unsafeThaw arr)
433
674
434{-# INLINE toStreamKRev #-}
675{-# INLINE toStreamKRev #-}
435toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
676toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
@@ -441,7 +682,7 @@ toStreamKRev arr =
441-- /Pre-release/
682-- /Pre-release/
442{-# INLINE_EARLY read #-}
683{-# INLINE_EARLY read #-}
443read :: (Monad m, Unbox a) => Array a -> Stream m a
684read :: (Monad m, Unbox a) => Array a -> Stream m a
444−read = toStreamD
685+read arr = MA.toStreamWith (return . unsafeInlineIO) (unsafeThaw arr)
445
686
446-- | Same as 'read'
687-- | Same as 'read'
447--
688--
@@ -458,7 +699,7 @@ toStream = read
458-- /Pre-release/
699-- /Pre-release/
459{-# INLINE_EARLY readRev #-}
700{-# INLINE_EARLY readRev #-}
460readRev :: (Monad m, Unbox a) => Array a -> Stream m a
701readRev :: (Monad m, Unbox a) => Array a -> Stream m a
461−readRev = toStreamDRev
702+readRev arr = MA.toStreamRevWith (return . unsafeInlineIO) (unsafeThaw arr)
462
703
463-- | Same as 'readRev'
704-- | Same as 'readRev'
464--
705--
@@ -482,6 +723,7 @@ foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
482-- | Create two slices of an array without copying the original array. The
723-- | Create two slices of an array without copying the original array. The
483-- specified index @i@ is the first index of the second slice.
724-- specified index @i@ is the first index of the second slice.
484--
725--
726+{-# INLINE splitAt #-}
485splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
727splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
486splitAt i arr = (unsafeFreeze a, unsafeFreeze b)
728splitAt i arr = (unsafeFreeze a, unsafeFreeze b)
487 where
729 where
@@ -501,8 +743,8 @@ toListFB c n Array{..} = go arrStart
501 -- accumulating the list and fusing better with the pure consumers.
743 -- accumulating the list and fusing better with the pure consumers.
502 --
744 --
503 -- This should be safe as the array contents are guaranteed to be
745 -- This should be safe as the array contents are guaranteed to be
504− -- evaluated/written to before we peekByteIndex at them.
746+ -- evaluated/written to before we peekAt at them.
505− let !x = unsafeInlineIO $ peekByteIndex p arrContents
747+ let !x = unsafeInlineIO $ peekAt p arrContents
506 in c x (go (INDEX_NEXT(p,a)))
748 in c x (go (INDEX_NEXT(p,a)))
507
749
508-- | Convert an 'Array' into a list.
750-- | Convert an 'Array' into a list.
@@ -515,17 +757,28 @@ toList s = build (\c n -> toListFB c n s)
515-- Folds
757-- Folds
516-------------------------------------------------------------------------------
758-------------------------------------------------------------------------------
517
759
518−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
760+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
519-- 'Array'.
761-- 'Array'.
520--
762--
521−{-# INLINE_NORMAL writeN #-}
763+{-# INLINE_NORMAL createOf #-}
764+createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
765+createOf = fmap unsafeFreeze . MA.createOf
766+
767+-- XXX Deprecate in major
768+-- {-# DEPRECATED writeN "Please use createOf instead." #-}
769+{-# INLINE writeN #-}
522writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
770writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
523−writeN = fmap unsafeFreeze . MA.writeN
771+writeN = createOf
524
772
525−-- | Like 'fromListN' but creates a pinned array.
773+-- | Like 'createOf' but creates a pinned array.
774+{-# INLINE_NORMAL pinnedCreateOf #-}
775+pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
776+pinnedCreateOf = fmap unsafeFreeze . MA.pinnedCreateOf
777+
778+{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
526−{-# INLINE_NORMAL pinnedWriteN #-}
779+{-# INLINE pinnedWriteN #-}
527pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
780pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
528−pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
781+pinnedWriteN = pinnedCreateOf
529
782
530-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
783-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
531-- stream to an 'Array' aligned to the given size.
784-- stream to an 'Array' aligned to the given size.
@@ -533,44 +786,74 @@ pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
533-- /Pre-release/
786-- /Pre-release/
534--
787--
535{-# INLINE_NORMAL pinnedWriteNAligned #-}
788{-# INLINE_NORMAL pinnedWriteNAligned #-}
789+{-# DEPRECATED pinnedWriteNAligned "To be removed." #-}
536pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
790pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
537 => Int -> Int -> Fold m a (Array a)
791 => Int -> Int -> Fold m a (Array a)
538pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
792pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
539
793
540−-- | Like 'writeN' but does not check the array bounds when writing. The fold
794+-- | Like 'createOf' but does not check the array bounds when writing. The fold
541-- driver must not call the step function more than 'n' times otherwise it will
795-- driver must not call the step function more than 'n' times otherwise it will
542-- corrupt the memory and crash. This function exists mainly because any
796-- corrupt the memory and crash. This function exists mainly because any
543-- conditional in the step function blocks fusion causing 10x performance
797-- conditional in the step function blocks fusion causing 10x performance
544-- slowdown.
798-- slowdown.
545--
799--
800+{-# INLINE_NORMAL unsafeCreateOf #-}
801+unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
802+ => Int -> Fold m a (Array a)
803+unsafeCreateOf n = unsafeFreeze <$> MA.unsafeCreateOf n
804+
805+{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
546−{-# INLINE_NORMAL writeNUnsafe #-}
806+{-# INLINE writeNUnsafe #-}
547writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
807writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
548 => Int -> Fold m a (Array a)
808 => Int -> Fold m a (Array a)
549−writeNUnsafe n = unsafeFreeze <$> MA.writeNUnsafe n
809+writeNUnsafe = unsafeCreateOf
550
810
811+{-# INLINE_NORMAL unsafePinnedCreateOf #-}
812+unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a)
813+ => Int -> Fold m a (Array a)
814+unsafePinnedCreateOf n = unsafeFreeze <$> MA.unsafePinnedCreateOf n
815+
816+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
551−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
817+{-# INLINE pinnedWriteNUnsafe #-}
552pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
818pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
553 => Int -> Fold m a (Array a)
819 => Int -> Fold m a (Array a)
554−pinnedWriteNUnsafe n = unsafeFreeze <$> MA.pinnedWriteNUnsafe n
820+pinnedWriteNUnsafe = unsafePinnedCreateOf
821+
822+{-# INLINE_NORMAL createWith #-}
823+createWith :: forall m a. (MonadIO m, Unbox a)
824+ => Int -> Fold m a (Array a)
825+-- createWith n = FL.rmapM spliceArrays $ toArraysOf n
826+createWith elemCount = unsafeFreeze <$> MA.createWith elemCount
555
827
828+{-# DEPRECATED writeWith "Please use createWith instead." #-}
556−{-# INLINE_NORMAL writeWith #-}
829+{-# INLINE writeWith #-}
557writeWith :: forall m a. (MonadIO m, Unbox a)
830writeWith :: forall m a. (MonadIO m, Unbox a)
558 => Int -> Fold m a (Array a)
831 => Int -> Fold m a (Array a)
559−-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
832+writeWith = createWith
560−writeWith elemCount = unsafeFreeze <$> MA.writeWith elemCount
561
833
562-- | Fold the whole input to a single array.
834-- | Fold the whole input to a single array.
563--
835--
564-- /Caution! Do not use this on infinite streams./
836-- /Caution! Do not use this on infinite streams./
565--
837--
838+{-# INLINE create #-}
839+create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
840+create = fmap unsafeFreeze MA.create
841+
842+-- XXX Deprecate in major
843+-- {-# DEPRECATED write "Please use create instead." #-}
566{-# INLINE write #-}
844{-# INLINE write #-}
567write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
845write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
568−write = fmap unsafeFreeze MA.write
846+write = create
569
847
570−-- | Like 'write' but creates a pinned array.
848+-- | Like 'create' but creates a pinned array.
849+{-# INLINE pinnedCreate #-}
850+pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
851+pinnedCreate = fmap unsafeFreeze MA.pinnedCreate
852+
853+{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
571{-# INLINE pinnedWrite #-}
854{-# INLINE pinnedWrite #-}
572pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
855pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
573−pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
856+pinnedWrite = pinnedCreate
574
857
575-- | Fold "step" has a dependency on "initial", and each step is dependent on
858-- | Fold "step" has a dependency on "initial", and each step is dependent on
576-- the previous invocation of step due to state passing, finally extract
859-- the previous invocation of step due to state passing, finally extract
@@ -596,10 +879,16 @@ pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
596--
879--
597{-# INLINE unsafeMakePure #-}
880{-# INLINE unsafeMakePure #-}
598unsafeMakePure :: Monad m => Fold IO a b -> Fold m a b
881unsafeMakePure :: Monad m => Fold IO a b -> Fold m a b
599−unsafeMakePure (Fold step initial extract) =
882+unsafeMakePure (Fold step initial extract final) =
600 Fold (\x a -> return $! unsafeInlineIO (step x a))
883 Fold (\x a -> return $! unsafeInlineIO (step x a))
601 (return $! unsafePerformIO initial)
884 (return $! unsafePerformIO initial)
602 (\s -> return $! unsafeInlineIO $ extract s)
885 (\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)
603
892
604-- | Convert a pure stream in Identity monad to an immutable array.
893-- | Convert a pure stream in Identity monad to an immutable array.
605--
894--
@@ -612,6 +901,19 @@ fromPureStream x = unsafePerformIO $ fmap (unsafeFreeze) (MA.fromPureStream x)
612-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
901-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
613-- fromPureStream = fromList . runIdentity . D.toList
902-- fromPureStream = fromList . runIdentity . D.toList
614
903
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+
615-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
917-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
616--
918--
617-- /Unsafe:/ The caller is responsible for safe addressing.
919-- /Unsafe:/ The caller is responsible for safe addressing.
@@ -622,8 +924,46 @@ fromPureStream x = unsafePerformIO $ fmap (unsafeFreeze) (MA.fromPureStream x)
622-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
924-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
623-- [1,2,3]
925-- [1,2,3]
624--
926--
927+-- Note that this should be evaluated strictly to ensure that we do not hold
928+-- the reference to the pointer in a lazy thunk.
625fromByteStr# :: Addr# -> Array Word8
929fromByteStr# :: Addr# -> Array Word8
626−fromByteStr# addr = fromPureStream (D.fromByteStr# addr)
930+fromByteStr# addr = unsafePerformIO $ fmap unsafeFreeze (MA.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
627
967
628-------------------------------------------------------------------------------
968-------------------------------------------------------------------------------
629-- Instances
969-- Instances
@@ -655,12 +995,66 @@ instance Unbox a => IsList (Array a) where
655 {-# INLINE toList #-}
995 {-# INLINE toList #-}
656 toList = toList
996 toList = toList
657
997
658−-- XXX we are assuming that Unboxed equality means element equality. This may
998+-- | Byte compare two arrays. Compare the length of the arrays. If the length
659−-- or may not be correct? arrcmp is 40% faster compared to stream equality.
999+-- is equal, compare the lexicographical ordering of two underlying byte arrays
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+--
660−instance (Unbox a, Eq a) => Eq (Array a) where
1048+instance {-# OVERLAPPABLE #-} (Unbox a, Eq a) => Eq (Array a) where
661 {-# INLINE (==) #-}
1049 {-# INLINE (==) #-}
662 arr1 == arr2 =
1050 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.
663− (==) EQ $ unsafeInlineIO $! unsafeThaw arr1 `MA.cmp` unsafeThaw arr2
1056+ -- (==) EQ $ unsafeInlineIO $! unsafeThaw arr1 `MA.cmp` unsafeThaw arr2
1057+ (toStreamD arr1 :: Stream Identity a) == toStreamD arr2
664
1058
665instance (Unbox a, Ord a) => Ord (Array a) where
1059instance (Unbox a, Ord a) => Ord (Array a) where
666 {-# INLINE compare #-}
1060 {-# INLINE compare #-}
@@ -702,7 +1096,7 @@ _toStreamD_ size Array{..} = D.Stream step arrStart
702 {-# INLINE_LATE step #-}
1096 {-# INLINE_LATE step #-}
703 step _ p | p == arrEnd = return D.Stop
1097 step _ p | p == arrEnd = return D.Stop
704 step _ p = liftIO $ do
1098 step _ p = liftIO $ do
705− x <- peekByteIndex p arrContents
1099+ x <- peekAt p arrContents
706 return $ D.Yield x (p + size)
1100 return $ D.Yield x (p + size)
707
1101
708{-
1102{-
@@ -725,15 +1119,29 @@ instance Foldable Array where
725-- Semigroup and Monoid
1119-- Semigroup and Monoid
726-------------------------------------------------------------------------------
1120-------------------------------------------------------------------------------
727
1121
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.
728instance Unbox a => Semigroup (Array a) where
1128instance Unbox a => Semigroup (Array a) where
729 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
1129 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
730
1130
1131+empty ::
1132+#ifdef DEVBUILD
1133+ Unbox a =>
1134+#endif
1135+ Array a
1136+empty = Array Unboxed.empty 0 0
1137+
1138+{-# DEPRECATED nil "Please use empty instead." #-}
731nil ::
1139nil ::
732#ifdef DEVBUILD
1140#ifdef DEVBUILD
733 Unbox a =>
1141 Unbox a =>
734#endif
1142#endif
735 Array a
1143 Array a
736−nil = Array Unboxed.nil 0 0
1144+nil = empty
737
1145
738instance Unbox a => Monoid (Array a) where
1146instance Unbox a => Monoid (Array a) where
739 mempty = nil
1147 mempty = nil
core/src/Streamly/Internal/Serialize/FromBytes.hs → core/src/Streamly/Internal/Data/Binary/Parser.hsrenamed+8−2
@@ -1,13 +1,19 @@
1-- |
1-- |
2−-- Module : Streamly.Internal.Serialize.FromBytes
2+-- Module : Streamly.Internal.Data.Binary.Parser
3-- Copyright : (c) 2020 Composewell Technologies
3-- Copyright : (c) 2020 Composewell Technologies
4-- License : BSD-3-Clause
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
6-- Portability : GHC
6-- Portability : GHC
7--
7--
8-- Decode Haskell data types from byte streams.
8-- Decode Haskell data types from byte streams.
9+--
10+-- It would be inefficient to use this to compose parsers for general algebraic
11+-- data types. For general deserialization of ADTs please use the Serialize
12+-- type class instances. The fastest way to deserialize byte streams
13+-- representing Haskell data types is to write them to arrays and deserialize
14+-- the array using the Serialize type class.
9
15
10−module Streamly.Internal.Serialize.FromBytes
16+module Streamly.Internal.Data.Binary.Parser
11 (
17 (
12 -- * Type class
18 -- * Type class
13 FromBytes (..)
19 FromBytes (..)
core/src/Streamly/Internal/Serialize/ToBytes.hs → core/src/Streamly/Internal/Data/Binary/Stream.hsrenamed+2−2
@@ -1,5 +1,5 @@
1-- |
1-- |
2−-- Module : Streamly.Internal.Serialize.ToBytes
2+-- Module : Streamly.Internal.Data.Binary.Stream
3-- Copyright : (c) 2022 Composewell Technologies
3-- Copyright : (c) 2022 Composewell Technologies
4-- License : BSD-3-Clause
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
@@ -17,7 +17,7 @@
17
17
18-- XXX remove unit, bool, ordering, and the type class as well
18-- XXX remove unit, bool, ordering, and the type class as well
19
19
20−module Streamly.Internal.Serialize.ToBytes
20+module Streamly.Internal.Data.Binary.Stream
21 (
21 (
22 -- * Type class
22 -- * Type class
23 ToBytes (..)
23 ToBytes (..)
core/src/Streamly/Internal/Data/Fold/Chunked.hs+16−15
@@ -6,7 +6,7 @@
6-- Stability : experimental
6-- Stability : experimental
7-- Portability : GHC
7-- Portability : GHC
8--
8--
9−-- Use "Streamly.Data.Parser.Chunked" instead.
9+-- Use "Streamly.Data.Parser" 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,18 +19,19 @@
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.Stream.Chunked as ArrayStream
23+-- >> import qualified Streamly.Internal.Data.Array.Stream 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." #-}
34 (
35 (
35 ChunkFold (..)
36 ChunkFold (..)
36
37
@@ -67,7 +68,6 @@ import Data.Bifunctor (first)
67import Data.Proxy (Proxy(..))
68import Data.Proxy (Proxy(..))
68import Streamly.Internal.Data.Unbox (Unbox(..))
69import Streamly.Internal.Data.Unbox (Unbox(..))
69import GHC.Types (SPEC(..))
70import GHC.Types (SPEC(..))
70−import Streamly.Internal.Data.MutArray.Type (touch)
71import Streamly.Internal.Data.Array (Array(..))
71import Streamly.Internal.Data.Array (Array(..))
72import Streamly.Internal.Data.Parser (Initial(..), Step(..))
72import Streamly.Internal.Data.Parser (Initial(..), Step(..))
73import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
73import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
@@ -103,8 +103,8 @@ newtype ChunkFold m a b = ChunkFold (ParserD.Parser (Array a) m b)
103{-# INLINE fromFold #-}
103{-# INLINE fromFold #-}
104fromFold :: forall m a b. (MonadIO m, Unbox a) =>
104fromFold :: forall m a b. (MonadIO m, Unbox a) =>
105 Fold.Fold m a b -> ChunkFold m a b
105 Fold.Fold m a b -> ChunkFold m a b
106−fromFold (Fold.Fold fstep finitial fextract) =
106+fromFold (Fold.Fold fstep finitial _ ffinal) =
107− ChunkFold (ParserD.Parser step initial (fmap (Done 0) . fextract))
107+ ChunkFold (ParserD.Parser step initial extract)
108
108
109 where
109 where
110
110
@@ -124,7 +124,7 @@ fromFold (Fold.Fold fstep finitial fextract) =
124 assert (cur == end) (return ())
124 assert (cur == end) (return ())
125 return $ Partial 0 fs
125 return $ Partial 0 fs
126 goArray !_ !cur !fs = do
126 goArray !_ !cur !fs = do
127− x <- liftIO $ peekByteIndex cur contents
127+ x <- liftIO $ peekAt cur contents
128 res <- fstep fs x
128 res <- fstep fs x
129 let elemSize = SIZE_OF(a)
129 let elemSize = SIZE_OF(a)
130 next = INDEX_NEXT(cur,a)
130 next = INDEX_NEXT(cur,a)
@@ -134,6 +134,8 @@ fromFold (Fold.Fold fstep finitial fextract) =
134 Fold.Partial fs1 ->
134 Fold.Partial fs1 ->
135 goArray SPEC next fs1
135 goArray SPEC next fs1
136
136
137+ extract = fmap (Done 0) . ffinal
138+
137-- | Convert an element 'ParserD.Parser' into an array stream fold. If the
139-- | Convert an element 'ParserD.Parser' into an array stream fold. If the
138-- parser fails the fold would throw an exception.
140-- parser fails the fold would throw an exception.
139--
141--
@@ -161,8 +163,7 @@ fromParserD (ParserD.Parser step1 initial1 extract1) =
161 else return $ st (arrRem + n) fs1
163 else return $ st (arrRem + n) fs1
162
164
163 goArray !_ !cur !fs = do
165 goArray !_ !cur !fs = do
164− x <- liftIO $ peekByteIndex cur contents
166+ x <- liftIO $ peekAt cur contents
165− liftIO $ touch contents
166 res <- step1 fs x
167 res <- step1 fs x
167 let elemSize = SIZE_OF(a)
168 let elemSize = SIZE_OF(a)
168 next = INDEX_NEXT(cur,a)
169 next = INDEX_NEXT(cur,a)
core/src/Streamly/Internal/Data/Fold/Combinators.hs+81−137
@@ -30,8 +30,6 @@ module Streamly.Internal.Data.Fold.Combinators
30 -- *** Reducers
30 -- *** Reducers
31 , drainMapM
31 , drainMapM
32 , the
32 , the
33− , length
34− , lengthGeneric
35 , mean
33 , mean
36 , rollingHash
34 , rollingHash
37 , defaultSalt
35 , defaultSalt
@@ -166,8 +164,6 @@ module Streamly.Internal.Data.Fold.Combinators
166 -- ** Trimming
164 -- ** Trimming
167
165
168 -- By elements
166 -- By elements
169− , takeEndBy
170− , takeEndBy_
171 , takeEndBySeq
167 , takeEndBySeq
172 , takeEndBySeq_
168 , takeEndBySeq_
173 {-
169 {-
@@ -443,8 +439,8 @@ trace f = lmapM (tracing f)
443-- /Pre-release/
439-- /Pre-release/
444{-# INLINE transform #-}
440{-# INLINE transform #-}
445transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
441transform :: Monad m => Pipe m a b -> Fold m b c -> Fold m a c
446−transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
442+transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract ffinal) =
447− Fold step initial extract
443+ Fold step initial extract final
448
444
449 where
445 where
450
446
@@ -477,10 +473,14 @@ transform (Pipe pstep1 pstep2 pinitial) (Fold fstep finitial fextract) =
477
473
478 extract (Tuple' _ fs) = fextract fs
474 extract (Tuple' _ fs) = fextract fs
479
475
476+ final (Tuple' _ fs) = ffinal fs
477+
480{-# INLINE scanWith #-}
478{-# INLINE scanWith #-}
481scanWith :: Monad m => Bool -> Fold m a b -> Fold m b c -> Fold m a c
479scanWith :: Monad m => Bool -> Fold m a b -> Fold m b c -> Fold m a c
480+scanWith isMany
482−scanWith isMany (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
481+ (Fold stepL initialL extractL finalL)
482+ (Fold stepR initialR extractR finalR) =
483− Fold step initial extract
483+ Fold step initial extract final
484
484
485 where
485 where
486
486
@@ -494,15 +494,14 @@ scanWith isMany (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
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 <$> extractR sR1
497+ else Done <$> finalR 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
503− $ case rR of
502+ case rR of
504− Partial sR1 -> Partial (sL, sR1)
503+ Partial sR1 -> return $ Partial (sL, sR1)
505− Done bR -> Done bR
504+ Done bR -> finalL sL >> return (Done bR)
506
505
507 initial = do
506 initial = do
508 r <- initialR
507 r <- initialR
@@ -514,6 +513,8 @@ scanWith isMany (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
514
513
515 extract = extractR . snd
514 extract = extractR . snd
516
515
516+ final (sL, sR) = finalL sL *> finalR sR
517+
517-- | Scan the input of a 'Fold' to change it in a stateful manner using another
518-- | Scan the input of a 'Fold' to change it in a stateful manner using another
518-- 'Fold'. The scan stops as soon as the fold terminates.
519-- 'Fold'. The scan stops as soon as the fold terminates.
519--
520--
@@ -565,7 +566,7 @@ deleteBy eq x0 = fmap extract $ foldl' step (Tuple' False Nothing)
565--
566--
566{-# INLINE slide2 #-}
567{-# INLINE slide2 #-}
567slide2 :: Monad m => Fold m (a, Maybe a) b -> Fold m a b
568slide2 :: Monad m => Fold m (a, Maybe a) b -> Fold m a b
568−slide2 (Fold step1 initial1 extract1) = Fold step initial extract
569+slide2 (Fold step1 initial1 extract1 final1) = Fold step initial extract final
569
570
570 where
571 where
571
572
@@ -577,6 +578,8 @@ slide2 (Fold step1 initial1 extract1) = Fold step initial extract
577
578
578 extract (Tuple' _ s) = extract1 s
579 extract (Tuple' _ s) = extract1 s
579
580
581+ final (Tuple' _ s) = final1 s
582+
580-- | Return the latest unique element using the supplied comparison function.
583-- | Return the latest unique element using the supplied comparison function.
581-- Returns 'Nothing' if the current element is same as the last element
584-- Returns 'Nothing' if the current element is same as the last element
582-- otherwise returns 'Just'.
585-- otherwise returns 'Just'.
@@ -702,30 +705,6 @@ the = foldt' step initial id
702-- To Summary
705-- To Summary
703------------------------------------------------------------------------------
706------------------------------------------------------------------------------
704
707
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−
729-- | Determine the sum of all elements of a stream of numbers. Returns additive
708-- | Determine the sum of all elements of a stream of numbers. Returns additive
730-- identity (@0@) when the stream is empty. Note that this is not numerically
709-- identity (@0@) when the stream is empty. Note that this is not numerically
731-- stable for floating point numbers.
710-- stable for floating point numbers.
@@ -932,7 +911,7 @@ rollingHashFirstN n = take n rollingHash
932--
911--
933{-# INLINE rollingMapM #-}
912{-# INLINE rollingMapM #-}
934rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Fold m a b
913rollingMapM :: Monad m => (Maybe a -> a -> m b) -> Fold m a b
935−rollingMapM f = Fold step initial extract
914+rollingMapM f = Fold step initial extract extract
936
915
937 where
916 where
938
917
@@ -1173,7 +1152,8 @@ head = one
1173-- /Pre-release/
1152-- /Pre-release/
1174{-# INLINE findM #-}
1153{-# INLINE findM #-}
1175findM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1154findM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1155+findM predicate =
1176−findM predicate = Fold step (return $ Partial ()) (const $ return Nothing)
1156+ Fold step (return $ Partial ()) extract extract
1177
1157
1178 where
1158 where
1179
1159
@@ -1184,6 +1164,8 @@ findM predicate = Fold step (return $ Partial ()) (const $ return Nothing)
1184 else Partial ()
1164 else Partial ()
1185 in f <$> predicate a
1165 in f <$> predicate a
1186
1166
1167+ extract = const $ return Nothing
1168+
1187-- | Returns the first element that satisfies the given predicate.
1169-- | Returns the first element that satisfies the given predicate.
1188--
1170--
1189{-# INLINE find #-}
1171{-# INLINE find #-}
@@ -1426,7 +1408,7 @@ splitAt n fld = splitWith (,) (take n fld)
1426
1408
1427{-# INLINE takingEndByM #-}
1409{-# INLINE takingEndByM #-}
1428takingEndByM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1410takingEndByM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1429−takingEndByM p = Fold step initial (return . toMaybe)
1411+takingEndByM p = Fold step initial extract extract
1430
1412
1431 where
1413 where
1432
1414
@@ -1439,6 +1421,8 @@ takingEndByM p = Fold step initial (return . toMaybe)
1439 then Done $ Just a
1421 then Done $ Just a
1440 else Partial $ Just' a
1422 else Partial $ Just' a
1441
1423
1424+ extract = return . toMaybe
1425+
1442-- |
1426-- |
1443--
1427--
1444-- >>> takingEndBy p = Fold.takingEndByM (return . p)
1428-- >>> takingEndBy p = Fold.takingEndByM (return . p)
@@ -1449,7 +1433,7 @@ takingEndBy p = takingEndByM (return . p)
1449
1433
1450{-# INLINE takingEndByM_ #-}
1434{-# INLINE takingEndByM_ #-}
1451takingEndByM_ :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1435takingEndByM_ :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1452−takingEndByM_ p = Fold step initial (return . toMaybe)
1436+takingEndByM_ p = Fold step initial extract extract
1453
1437
1454 where
1438 where
1455
1439
@@ -1462,6 +1446,8 @@ takingEndByM_ p = Fold step initial (return . toMaybe)
1462 then Done Nothing
1446 then Done Nothing
1463 else Partial $ Just' a
1447 else Partial $ Just' a
1464
1448
1449+ extract = return . toMaybe
1450+
1465-- |
1451-- |
1466--
1452--
1467-- >>> takingEndBy_ p = Fold.takingEndByM_ (return . p)
1453-- >>> takingEndBy_ p = Fold.takingEndByM_ (return . p)
@@ -1472,7 +1458,7 @@ takingEndBy_ p = takingEndByM_ (return . p)
1472
1458
1473{-# INLINE droppingWhileM #-}
1459{-# INLINE droppingWhileM #-}
1474droppingWhileM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1460droppingWhileM :: Monad m => (a -> m Bool) -> Fold m a (Maybe a)
1475−droppingWhileM p = Fold step initial (return . toMaybe)
1461+droppingWhileM p = Fold step initial extract extract
1476
1462
1477 where
1463 where
1478
1464
@@ -1487,6 +1473,8 @@ droppingWhileM p = Fold step initial (return . toMaybe)
1487 else Just' a
1473 else Just' a
1488 step _ a = return $ Partial $ Just' a
1474 step _ a = return $ Partial $ Just' a
1489
1475
1476+ extract = return . toMaybe
1477+
1490-- |
1478-- |
1491-- >>> droppingWhile p = Fold.droppingWhileM (return . p)
1479-- >>> droppingWhile p = Fold.droppingWhileM (return . p)
1492--
1480--
@@ -1494,70 +1482,6 @@ droppingWhileM p = Fold step initial (return . toMaybe)
1494droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1482droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
1495droppingWhile p = droppingWhileM (return . p)
1483droppingWhile p = droppingWhileM (return . p)
1496
1484
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−
1561------------------------------------------------------------------------------
1485------------------------------------------------------------------------------
1562-- Binary splitting on a separator
1486-- Binary splitting on a separator
1563------------------------------------------------------------------------------
1487------------------------------------------------------------------------------
@@ -1590,8 +1514,8 @@ takeEndBySeq :: forall m a b. (MonadIO m, Storable a, Unbox a, Enum a, Eq a) =>
1590 Array.Array a
1514 Array.Array a
1591 -> Fold m a b
1515 -> Fold m a b
1592 -> Fold m a b
1516 -> Fold m a b
1593−takeEndBySeq patArr (Fold fstep finitial fextract) =
1517+takeEndBySeq patArr (Fold fstep finitial fextract ffinal) =
1594− Fold step initial extract
1518+ Fold step initial extract final
1595
1519
1596 where
1520 where
1597
1521
@@ -1604,7 +1528,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1604 | patLen == 0 ->
1528 | patLen == 0 ->
1605 -- XXX Should we match nothing or everything on empty
1529 -- XXX Should we match nothing or everything on empty
1606 -- pattern?
1530 -- pattern?
1607− -- Done <$> fextract acc
1531+ -- Done <$> ffinal acc
1608 return $ Partial $ SplitOnSeqEmpty acc
1532 return $ Partial $ SplitOnSeqEmpty acc
1609 | patLen == 1 -> do
1533 | patLen == 1 -> do
1610 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
1534 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
@@ -1655,7 +1579,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1655 case res of
1579 case res of
1656 Partial s1
1580 Partial s1
1657 | pat /= x -> return $ Partial $ SplitOnSeqSingle s1 pat
1581 | pat /= x -> return $ Partial $ SplitOnSeqSingle s1 pat
1658− | otherwise -> Done <$> fextract s1
1582+ | otherwise -> Done <$> ffinal s1
1659 Done b -> return $ Done b
1583 Done b -> return $ Done b
1660 step (SplitOnSeqWord s idx wrd) x = do
1584 step (SplitOnSeqWord s idx wrd) x = do
1661 res <- fstep s x
1585 res <- fstep s x
@@ -1664,7 +1588,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1664 Partial s1
1588 Partial s1
1665 | idx == maxIndex -> do
1589 | idx == maxIndex -> do
1666 if wrd1 .&. wordMask == wordPat
1590 if wrd1 .&. wordMask == wordPat
1667− then Done <$> fextract s1
1591+ then Done <$> ffinal s1
1668 else return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1592 else return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1669 | otherwise ->
1593 | otherwise ->
1670 return $ Partial $ SplitOnSeqWord s1 (idx + 1) wrd1
1594 return $ Partial $ SplitOnSeqWord s1 (idx + 1) wrd1
@@ -1675,7 +1599,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1675 case res of
1599 case res of
1676 Partial s1
1600 Partial s1
1677 | wrd1 .&. wordMask == wordPat ->
1601 | wrd1 .&. wordMask == wordPat ->
1678− Done <$> fextract s1
1602+ Done <$> ffinal s1
1679 | otherwise ->
1603 | otherwise ->
1680 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1604 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1681 Done b -> return $ Done b
1605 Done b -> return $ Done b
@@ -1689,7 +1613,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1689 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1613 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1690 let !ringHash = fld addCksum 0 rb
1614 let !ringHash = fld addCksum 0 rb
1691 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1615 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1692− then Done <$> fextract s1
1616+ then Done <$> ffinal s1
1693 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1617 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1694 else
1618 else
1695 return $ Partial $ SplitOnSeqKR s1 (idx + 1) rb rh1
1619 return $ Partial $ SplitOnSeqKR s1 (idx + 1) rb rh1
@@ -1702,11 +1626,11 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1702 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1626 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1703 let ringHash = deltaCksum cksum old x
1627 let ringHash = deltaCksum cksum old x
1704 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1628 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1705− then Done <$> fextract s1
1629+ then Done <$> ffinal s1
1706 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1630 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1707 Done b -> return $ Done b
1631 Done b -> return $ Done b
1708
1632
1709− extract state =
1633+ extractFunc fex state =
1710 let st =
1634 let st =
1711 case state of
1635 case state of
1712 SplitOnSeqEmpty s -> s
1636 SplitOnSeqEmpty s -> s
@@ -1715,7 +1639,11 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
1715 SplitOnSeqWordLoop s _ -> s
1639 SplitOnSeqWordLoop s _ -> s
1716 SplitOnSeqKR s _ _ _ -> s
1640 SplitOnSeqKR s _ _ _ -> s
1717 SplitOnSeqKRLoop s _ _ _ -> s
1641 SplitOnSeqKRLoop s _ _ _ -> s
1718− in fextract st
1642+ in fex st
1643+
1644+ extract state = extractFunc fextract state
1645+
1646+ final state = extractFunc ffinal state
1719
1647
1720-- | Like 'takeEndBySeq' but discards the matched sequence.
1648-- | Like 'takeEndBySeq' but discards the matched sequence.
1721--
1649--
@@ -1726,8 +1654,8 @@ takeEndBySeq_ :: forall m a b. (MonadIO m, Storable a, Unbox a, Enum a, Eq a) =>
1726 Array.Array a
1654 Array.Array a
1727 -> Fold m a b
1655 -> Fold m a b
1728 -> Fold m a b
1656 -> Fold m a b
1729−takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1657+takeEndBySeq_ patArr (Fold fstep finitial fextract ffinal) =
1730− Fold step initial extract
1658+ Fold step initial extract final
1731
1659
1732 where
1660 where
1733
1661
@@ -1740,7 +1668,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1740 | patLen == 0 ->
1668 | patLen == 0 ->
1741 -- XXX Should we match nothing or everything on empty
1669 -- XXX Should we match nothing or everything on empty
1742 -- pattern?
1670 -- pattern?
1743− -- Done <$> fextract acc
1671+ -- Done <$> ffinal acc
1744 return $ Partial $ SplitOnSeqEmpty acc
1672 return $ Partial $ SplitOnSeqEmpty acc
1745 | patLen == 1 -> do
1673 | patLen == 1 -> do
1746 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
1674 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
@@ -1797,13 +1725,13 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1797 case res of
1725 case res of
1798 Partial s1 -> return $ Partial $ SplitOnSeqSingle s1 pat
1726 Partial s1 -> return $ Partial $ SplitOnSeqSingle s1 pat
1799 Done b -> return $ Done b
1727 Done b -> return $ Done b
1800− else Done <$> fextract s
1728+ else Done <$> ffinal s
1801 step (SplitOnSeqWord s idx wrd) x = do
1729 step (SplitOnSeqWord s idx wrd) x = do
1802 let wrd1 = addToWord wrd x
1730 let wrd1 = addToWord wrd x
1803 if idx == maxIndex
1731 if idx == maxIndex
1804 then do
1732 then do
1805 if wrd1 .&. wordMask == wordPat
1733 if wrd1 .&. wordMask == wordPat
1806− then Done <$> fextract s
1734+ then Done <$> ffinal s
1807 else return $ Partial $ SplitOnSeqWordLoop s wrd1
1735 else return $ Partial $ SplitOnSeqWordLoop s wrd1
1808 else return $ Partial $ SplitOnSeqWord s (idx + 1) wrd1
1736 else return $ Partial $ SplitOnSeqWord s (idx + 1) wrd1
1809 step (SplitOnSeqWordLoop s wrd) x = do
1737 step (SplitOnSeqWordLoop s wrd) x = do
@@ -1814,7 +1742,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1814 case res of
1742 case res of
1815 Partial s1
1743 Partial s1
1816 | wrd1 .&. wordMask == wordPat ->
1744 | wrd1 .&. wordMask == wordPat ->
1817− Done <$> fextract s1
1745+ Done <$> ffinal s1
1818 | otherwise ->
1746 | otherwise ->
1819 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1747 return $ Partial $ SplitOnSeqWordLoop s1 wrd1
1820 Done b -> return $ Done b
1748 Done b -> return $ Done b
@@ -1825,7 +1753,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1825 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1753 let fld = Ring.unsafeFoldRing (Ring.ringBound rb)
1826 let !ringHash = fld addCksum 0 rb
1754 let !ringHash = fld addCksum 0 rb
1827 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1755 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1828− then Done <$> fextract s
1756+ then Done <$> ffinal s
1829 else return $ Partial $ SplitOnSeqKRLoop s ringHash rb rh1
1757 else return $ Partial $ SplitOnSeqKRLoop s ringHash rb rh1
1830 else return $ Partial $ SplitOnSeqKR s (idx + 1) rb rh1
1758 else return $ Partial $ SplitOnSeqKR s (idx + 1) rb rh1
1831 step (SplitOnSeqKRLoop s cksum rb rh) x = do
1759 step (SplitOnSeqKRLoop s cksum rb rh) x = do
@@ -1836,7 +1764,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1836 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1764 rh1 <- liftIO $ Ring.unsafeInsert rb rh x
1837 let ringHash = deltaCksum cksum old x
1765 let ringHash = deltaCksum cksum old x
1838 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1766 if ringHash == patHash && Ring.unsafeEqArray rb rh1 patArr
1839− then Done <$> fextract s1
1767+ then Done <$> ffinal s1
1840 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1768 else return $ Partial $ SplitOnSeqKRLoop s1 ringHash rb rh1
1841 Done b -> return $ Done b
1769 Done b -> return $ Done b
1842
1770
@@ -1844,10 +1772,10 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1844 -- terminates early inside extract, we may still have buffered data
1772 -- terminates early inside extract, we may still have buffered data
1845 -- remaining which will be lost if we do not communicate that to the
1773 -- remaining which will be lost if we do not communicate that to the
1846 -- driver.
1774 -- driver.
1847− extract state = do
1775+ extractFunc fex state = do
1848 let consumeWord s n wrd = do
1776 let consumeWord s n wrd = do
1849 if n == 0
1777 if n == 0
1850− then fextract s
1778+ then fex s
1851 else do
1779 else do
1852 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
1780 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
1853 r <- fstep s (toEnum $ fromIntegral old)
1781 r <- fstep s (toEnum $ fromIntegral old)
@@ -1857,7 +1785,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1857
1785
1858 let consumeRing s n rb rh =
1786 let consumeRing s n rb rh =
1859 if n == 0
1787 if n == 0
1860− then fextract s
1788+ then fex s
1861 else do
1789 else do
1862 old <- liftIO $ peek rh
1790 old <- liftIO $ peek rh
1863 let rh1 = Ring.advance rb rh
1791 let rh1 = Ring.advance rb rh
@@ -1867,13 +1795,17 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
1867 Done b -> return b
1795 Done b -> return b
1868
1796
1869 case state of
1797 case state of
1870− SplitOnSeqEmpty s -> fextract s
1798+ SplitOnSeqEmpty s -> fex s
1871− SplitOnSeqSingle s _ -> fextract s
1799+ SplitOnSeqSingle s _ -> fex s
1872 SplitOnSeqWord s idx wrd -> consumeWord s idx wrd
1800 SplitOnSeqWord s idx wrd -> consumeWord s idx wrd
1873 SplitOnSeqWordLoop s wrd -> consumeWord s patLen wrd
1801 SplitOnSeqWordLoop s wrd -> consumeWord s patLen wrd
1874 SplitOnSeqKR s idx rb _ -> consumeRing s idx rb (Ring.startOf rb)
1802 SplitOnSeqKR s idx rb _ -> consumeRing s idx rb (Ring.startOf rb)
1875 SplitOnSeqKRLoop s _ rb rh -> consumeRing s patLen rb rh
1803 SplitOnSeqKRLoop s _ rb rh -> consumeRing s patLen rb rh
1876
1804
1805+ extract state = extractFunc fextract state
1806+
1807+ final state = extractFunc ffinal state
1808+
1877------------------------------------------------------------------------------
1809------------------------------------------------------------------------------
1878-- Distributing
1810-- Distributing
1879------------------------------------------------------------------------------
1811------------------------------------------------------------------------------
@@ -2317,8 +2249,8 @@ toStreamRev = fmap StreamD.fromList toListRev
2317-- /Pre-release/
2249-- /Pre-release/
2318{-# INLINE unfoldMany #-}
2250{-# INLINE unfoldMany #-}
2319unfoldMany :: Monad m => Unfold m a b -> Fold m b c -> Fold m a c
2251unfoldMany :: Monad m => Unfold m a b -> Fold m b c -> Fold m a c
2320−unfoldMany (Unfold ustep inject) (Fold fstep initial extract) =
2252+unfoldMany (Unfold ustep inject) (Fold fstep initial extract final) =
2321− Fold consume initial extract
2253+ Fold consume initial extract final
2322
2254
2323 where
2255 where
2324
2256
@@ -2345,7 +2277,7 @@ bottomBy :: (MonadIO m, Unbox a) =>
2345 (a -> a -> Ordering)
2277 (a -> a -> Ordering)
2346 -> Int
2278 -> Int
2347 -> Fold m a (MutArray a)
2279 -> Fold m a (MutArray a)
2348−bottomBy cmp n = Fold step initial extract
2280+bottomBy cmp n = Fold step initial extract extract
2349
2281
2350 where
2282 where
2351
2283
@@ -2440,8 +2372,8 @@ intersperseWithQuotes
2440 quote
2372 quote
2441 esc
2373 esc
2442 separator
2374 separator
2443− (Fold stepL initialL extractL)
2375+ (Fold stepL initialL _ finalL)
2444− (Fold stepR initialR extractR) = Fold step initial extract
2376+ (Fold stepR initialR extractR finalR) = Fold step initial extract final
2445
2377
2446 where
2378 where
2447
2379
@@ -2484,11 +2416,13 @@ intersperseWithQuotes
2484 r <- stepL sL a
2416 r <- stepL sL a
2485 case r of
2417 case r of
2486 Partial s -> return $ Partial (nextState sR s)
2418 Partial s -> return $ Partial (nextState sR s)
2419+ Done _ -> do
2420+ _ <- finalR sR
2487− Done _ -> error "Collecting fold finished inside quote"
2421+ error "Collecting fold finished inside quote"
2488
2422
2489 step (IntersperseQUnquoted sR sL) a
2423 step (IntersperseQUnquoted sR sL) a
2490 | a == separator = do
2424 | a == separator = do
2491− b <- extractL sL
2425+ b <- finalL sL
2492 collect IntersperseQUnquoted sR b
2426 collect IntersperseQUnquoted sR b
2493 | a == quote = processQuoted a sL sR IntersperseQQuoted
2427 | a == quote = processQuoted a sL sR IntersperseQQuoted
2494 | otherwise = process a sL sR IntersperseQUnquoted
2428 | otherwise = process a sL sR IntersperseQUnquoted
@@ -2506,3 +2440,13 @@ intersperseWithQuotes
2506 error "intersperseWithQuotes: finished inside quote"
2440 error "intersperseWithQuotes: finished inside quote"
2507 extract (IntersperseQQuotedEsc _ _) =
2441 extract (IntersperseQQuotedEsc _ _) =
2508 error "intersperseWithQuotes: finished inside quote, at escape char"
2442 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+73−28
@@ -270,14 +270,15 @@ 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 = fmap extract $ foldlM' step initial
273+demuxGeneric getKey getFold =
274+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
274
275
275 where
276 where
276
277
277 initial = return $ Tuple' IsMap.mapEmpty Nothing
278 initial = return $ Tuple' IsMap.mapEmpty Nothing
278
279
279 {-# INLINE runFold #-}
280 {-# INLINE runFold #-}
280− runFold kv (Fold step1 initial1 extract1) (k, a) = do
281+ runFold kv (Fold step1 initial1 extract1 final1) (k, a) = do
281 res <- initial1
282 res <- initial1
282 case res of
283 case res of
283 Partial s -> do
284 Partial s -> do
@@ -285,7 +286,7 @@ demuxGeneric getKey getFold = fmap extract $ foldlM' step initial
285 return
286 return
286 $ case res1 of
287 $ case res1 of
287 Partial _ ->
288 Partial _ ->
288− let fld = Fold step1 (return res1) extract1
289+ let fld = Fold step1 (return res1) extract1 final1
289 in Tuple' (IsMap.mapInsert k fld kv) Nothing
290 in Tuple' (IsMap.mapInsert k fld kv) Nothing
290 Done b -> Tuple' (IsMap.mapDelete k kv) (Just (k, b))
291 Done b -> Tuple' (IsMap.mapDelete k kv) (Just (k, b))
291 Done b -> return $ Tuple' kv (Just (k, b))
292 Done b -> return $ Tuple' kv (Just (k, b))
@@ -298,15 +299,25 @@ demuxGeneric getKey getFold = fmap extract $ foldlM' step initial
298 runFold kv fld (k, a)
299 runFold kv fld (k, a)
299 Just f -> runFold kv f (k, a)
300 Just f -> runFold kv f (k, a)
300
301
301− extract (Tuple' kv x) = (Prelude.mapM f kv, x)
302+ extract (Tuple' kv x) = return (Prelude.mapM f kv, x)
302
303
303 where
304 where
304
305
305− f (Fold _ i e) = do
306+ f (Fold _ i e _) = do
306 r <- i
307 r <- i
307 case r of
308 case r of
308 Partial s -> e s
309 Partial s -> e s
309− Done b -> return b
310+ _ -> error "demuxGeneric: unreachable code"
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"
310
321
311-- | @demux getKey getFold@: In a key value stream, fold values corresponding
322-- | @demux getKey getFold@: In a key value stream, fold values corresponding
312-- to each key using a key specific fold. @getFold@ is invoked to generate a
323-- to each key using a key specific fold. @getFold@ is invoked to generate a
@@ -348,35 +359,36 @@ demuxGenericIO :: (MonadIO m, IsMap f, Traversable f) =>
348 (a -> Key f)
359 (a -> Key f)
349 -> (a -> m (Fold m a b))
360 -> (a -> m (Fold m a b))
350 -> Fold m a (m (f b), Maybe (Key f, b))
361 -> Fold m a (m (f b), Maybe (Key f, b))
351−demuxGenericIO getKey getFold = fmap extract $ foldlM' step initial
362+demuxGenericIO getKey getFold =
363+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
352
364
353 where
365 where
354
366
355 initial = return $ Tuple' IsMap.mapEmpty Nothing
367 initial = return $ Tuple' IsMap.mapEmpty Nothing
356
368
357 {-# INLINE initFold #-}
369 {-# INLINE initFold #-}
358− initFold kv (Fold step1 initial1 extract1) (k, a) = do
370+ initFold kv (Fold step1 initial1 extract1 final1) (k, a) = do
359 res <- initial1
371 res <- initial1
360 case res of
372 case res of
361 Partial s -> do
373 Partial s -> do
362 res1 <- step1 s a
374 res1 <- step1 s a
363 case res1 of
375 case res1 of
364 Partial _ -> do
376 Partial _ -> do
365− let fld = Fold step1 (return res1) extract1
377+ let fld = Fold step1 (return res1) extract1 final1
366 ref <- liftIO $ newIORef fld
378 ref <- liftIO $ newIORef fld
367 return $ Tuple' (IsMap.mapInsert k ref kv) Nothing
379 return $ Tuple' (IsMap.mapInsert k ref kv) Nothing
368 Done b -> return $ Tuple' kv (Just (k, b))
380 Done b -> return $ Tuple' kv (Just (k, b))
369 Done b -> return $ Tuple' kv (Just (k, b))
381 Done b -> return $ Tuple' kv (Just (k, b))
370
382
371 {-# INLINE runFold #-}
383 {-# INLINE runFold #-}
372− runFold kv ref (Fold step1 initial1 extract1) (k, a) = do
384+ runFold kv ref (Fold step1 initial1 extract1 final1) (k, a) = do
373 res <- initial1
385 res <- initial1
374 case res of
386 case res of
375 Partial s -> do
387 Partial s -> do
376 res1 <- step1 s a
388 res1 <- step1 s a
377 case res1 of
389 case res1 of
378 Partial _ -> do
390 Partial _ -> do
379− let fld = Fold step1 (return res1) extract1
391+ let fld = Fold step1 (return res1) extract1 final1
380 liftIO $ writeIORef ref fld
392 liftIO $ writeIORef ref fld
381 return $ Tuple' kv Nothing
393 return $ Tuple' kv Nothing
382 Done b ->
394 Done b ->
@@ -394,16 +406,27 @@ demuxGenericIO getKey getFold = fmap extract $ foldlM' step initial
394 f <- liftIO $ readIORef ref
406 f <- liftIO $ readIORef ref
395 runFold kv ref f (k, a)
407 runFold kv ref f (k, a)
396
408
397− extract (Tuple' kv x) = (Prelude.mapM f kv, x)
409+ extract (Tuple' kv x) = return (Prelude.mapM f kv, x)
398
410
399 where
411 where
400
412
401 f ref = do
413 f ref = do
402− (Fold _ i e) <- liftIO $ readIORef ref
414+ Fold _ i e _ <- liftIO $ readIORef ref
403 r <- i
415 r <- i
404 case r of
416 case r of
405 Partial s -> e s
417 Partial s -> e s
406− Done b -> return b
418+ _ -> error "demuxGenericIO: unreachable code"
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"
407
430
408-- | This is specialized version of 'demux' that uses mutable IO cells as
431-- | This is specialized version of 'demux' that uses mutable IO cells as
409-- fold accumulators for better performance.
432-- fold accumulators for better performance.
@@ -418,6 +441,13 @@ demuxIO :: (MonadIO m, Ord k) =>
418 -> Fold m a (m (Map k b), Maybe (k, b))
441 -> Fold m a (m (Map k b), Maybe (k, b))
419demuxIO = demuxGenericIO
442demuxIO = demuxGenericIO
420
443
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+
421{-# INLINE demuxToContainer #-}
451{-# INLINE demuxToContainer #-}
422demuxToContainer :: (Monad m, IsMap f, Traversable f) =>
452demuxToContainer :: (Monad m, IsMap f, Traversable f) =>
423 (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
453 (a -> Key f) -> (a -> m (Fold m a b)) -> Fold m a (f b)
@@ -505,8 +535,8 @@ classifyGeneric :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
505 -- for that use case. We return an action because we want it to be lazy so
535 -- for that use case. We return an action because we want it to be lazy so
506 -- that the downstream consumers can choose to process or discard it.
536 -- that the downstream consumers can choose to process or discard it.
507 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
537 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
508−classifyGeneric f (Fold step1 initial1 extract1) =
538+classifyGeneric f (Fold step1 initial1 extract1 final1) =
509− fmap extract $ foldlM' step initial
539+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
510
540
511 where
541 where
512
542
@@ -543,7 +573,16 @@ classifyGeneric f (Fold step1 initial1 extract1) =
543 let kv1 = IsMap.mapDelete k kv
573 let kv1 = IsMap.mapDelete k kv
544 in Tuple3' kv1 (Set.insert k set) (Just (k, b))
574 in Tuple3' kv1 (Set.insert k set) (Just (k, b))
545
575
546− extract (Tuple3' kv _ x) = (Prelude.mapM extract1 kv, x)
576+ extract (Tuple3' kv _ x) = return (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
547
586
548-- | Folds the values for each key using the supplied fold. When scanning, as
587-- | Folds the values for each key using the supplied fold. When scanning, as
549-- soon as the fold is complete, its result is available in the second
588-- soon as the fold is complete, its result is available in the second
@@ -568,8 +607,8 @@ classify = classifyGeneric
568{-# INLINE classifyGenericIO #-}
607{-# INLINE classifyGenericIO #-}
569classifyGenericIO :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) =>
608classifyGenericIO :: (MonadIO m, IsMap f, Traversable f, Ord (Key f)) =>
570 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
609 (a -> Key f) -> Fold m a b -> Fold m a (m (f b), Maybe (Key f, b))
571−classifyGenericIO f (Fold step1 initial1 extract1) =
610+classifyGenericIO f (Fold step1 initial1 extract1 final1) =
572− fmap extract $ foldlM' step initial
611+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) extract final
573
612
574 where
613 where
575
614
@@ -608,8 +647,21 @@ classifyGenericIO f (Fold step1 initial1 extract1) =
608 in return
647 in return
609 $ Tuple3' kv1 (Set.insert k set) (Just (k, b))
648 $ Tuple3' kv1 (Set.insert k set) (Just (k, b))
610
649
611− extract (Tuple3' kv _ x) =
650+ extract (Tuple3' kv _ x) = return (Prelude.mapM g kv, x)
651+
652+ where
653+
612− (Prelude.mapM (\ref -> liftIO (readIORef ref) >>= extract1) kv, x)
654+ g ref = liftIO (readIORef ref) >>= extract1
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
613
665
614-- | Same as classify except that it uses mutable IORef cells in the
666-- | Same as classify except that it uses mutable IORef cells in the
615-- Map providing better performance. Be aware that if this is used as a scan,
667-- Map providing better performance. Be aware that if this is used as a scan,
@@ -624,13 +676,6 @@ classifyIO :: (MonadIO m, Ord k) =>
624 (a -> k) -> Fold m a b -> Fold m a (m (Map k b), Maybe (k, b))
676 (a -> k) -> Fold m a b -> Fold m a (m (Map k b), Maybe (k, b))
625classifyIO = classifyGenericIO
677classifyIO = classifyGenericIO
626
678
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−
634{-# INLINE toContainer #-}
679{-# INLINE toContainer #-}
635toContainer :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
680toContainer :: (Monad m, IsMap f, Traversable f, Ord (Key f)) =>
636 (a -> Key f) -> Fold m a b -> Fold m a (f b)
681 (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 'Partial' and 'second' maps over 'Done'.
43+-- | 'first' maps over the fold state and 'second' maps over the fold result.
44--
44--
45instance Bifunctor Step where
45instance Bifunctor Step where
46 {-# INLINE bimap #-}
46 {-# INLINE bimap #-}
core/src/Streamly/Internal/Data/Fold/Type.hs+336−114
@@ -367,6 +367,8 @@ module Streamly.Internal.Data.Fold.Type
367 , toList
367 , toList
368 , toStreamK
368 , toStreamK
369 , toStreamKRev
369 , toStreamKRev
370+ , lengthGeneric
371+ , length
370
372
371 -- * Combinators
373 -- * Combinators
372
374
@@ -391,6 +393,8 @@ module Streamly.Internal.Data.Fold.Type
391 -- ** Trimming
393 -- ** Trimming
392 , take
394 , take
393 , taking
395 , taking
396+ , takeEndBy_
397+ , takeEndBy
394 , dropping
398 , dropping
395
399
396 -- ** Sequential application
400 -- ** Sequential application
@@ -445,7 +449,7 @@ where
445#if !MIN_VERSION_base(4,18,0)
449#if !MIN_VERSION_base(4,18,0)
446import Control.Applicative (liftA2)
450import Control.Applicative (liftA2)
447#endif
451#endif
448−import Control.Monad ((>=>))
452+import Control.Monad ((>=>), void)
449import Data.Bifunctor (Bifunctor(..))
453import Data.Bifunctor (Bifunctor(..))
450import Data.Either (fromLeft, fromRight, isLeft, isRight)
454import Data.Either (fromLeft, fromRight, isLeft, isRight)
451import Data.Functor.Identity (Identity(..))
455import Data.Functor.Identity (Identity(..))
@@ -471,23 +475,64 @@ import Streamly.Internal.Data.Fold.Step
471-- The type @b@ is the accumulator of the writer. That's the reason the
475-- The type @b@ is the accumulator of the writer. That's the reason the
472-- default folds in various modules are called "write".
476-- default folds in various modules are called "write".
473
477
474−-- | The type @Fold m a b@ having constructor @Fold step initial extract@
478+-- An alternative to using an "extract" function is to use "Partial s b" style
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+
475−-- represents a fold over an input stream of values of type @a@ to a final
500+-- | The type @Fold m a b@ represents a consumer of an input stream of values
476−-- value of type @b@ in 'Monad' @m@.
501+-- of type @a@ and returning a final value of type @b@ in 'Monad' @m@. The
502+-- constructor of a fold is @Fold step initial extract final@.
477−--
503+--
478−-- The fold uses an intermediate state @s@ as accumulator, the type @s@ is
479−-- internal to the specific fold definition. The initial value of the fold
504+-- The fold uses an internal state of type @s@. The initial value of the state
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+--
480−-- state @s@ is returned by @initial@. The @step@ function consumes an input
509+-- The @step@ function is called on each input, it consumes an input and
481−-- and either returns the final result @b@ if the fold is done or the next
482−-- intermediate state (see 'Step'). At any point the fold driver can extract
510+-- returns the next intermediate state (see 'Step') or the final result @b@ if
483−-- the result from the intermediate state using the @extract@ function.
511+-- the fold terminates.
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.
484--
529--
485-- NOTE: The constructor is not yet released, smart constructors are provided
530-- NOTE: The constructor is not yet released, smart constructors are provided
486-- to create folds.
531-- to create folds.
487--
532--
488data Fold m a b =
533data Fold m a b =
489− -- | @Fold @ @ step @ @ initial @ @ extract@
534+ -- | @Fold@ @step@ @initial@ @extract@ @final@
490− forall s. Fold (s -> a -> m (Step s b)) (m (Step s b)) (s -> m b)
535+ forall s. Fold (s -> a -> m (Step s b)) (m (Step s b)) (s -> m b) (s -> m b)
491
536
492------------------------------------------------------------------------------
537------------------------------------------------------------------------------
493-- Mapping on the output
538-- Mapping on the output
@@ -497,7 +542,8 @@ data Fold m a b =
497--
542--
498{-# INLINE rmapM #-}
543{-# INLINE rmapM #-}
499rmapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
544rmapM :: Monad m => (b -> m c) -> Fold m a b -> Fold m a c
500−rmapM f (Fold step initial extract) = Fold step1 initial1 (extract >=> f)
545+rmapM f (Fold step initial extract final) =
546+ Fold step1 initial1 (extract >=> f) (final >=> f)
501
547
502 where
548 where
503
549
@@ -528,6 +574,7 @@ foldl' step initial =
528 (\s a -> return $ Partial $ step s a)
574 (\s a -> return $ Partial $ step s a)
529 (return (Partial initial))
575 (return (Partial initial))
530 return
576 return
577+ return
531
578
532-- | Make a fold from a left fold style monadic step function and initial value
579-- | Make a fold from a left fold style monadic step function and initial value
533-- of the accumulator.
580-- of the accumulator.
@@ -542,7 +589,7 @@ foldl' step initial =
542{-# INLINE foldlM' #-}
589{-# INLINE foldlM' #-}
543foldlM' :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
590foldlM' :: Monad m => (b -> a -> m b) -> m b -> Fold m a b
544foldlM' step initial =
591foldlM' step initial =
545− Fold (\s a -> Partial <$> step s a) (Partial <$> initial) return
592+ Fold (\s a -> Partial <$> step s a) (Partial <$> initial) return return
546
593
547-- | Make a strict left fold, for non-empty streams, using first element as the
594-- | Make a strict left fold, for non-empty streams, using first element as the
548-- starting value. Returns Nothing if the stream is empty.
595-- starting value. Returns Nothing if the stream is empty.
@@ -640,7 +687,11 @@ foldrM' g z =
640{-# INLINE foldt' #-}
687{-# INLINE foldt' #-}
641foldt' :: Monad m => (s -> a -> Step s b) -> Step s b -> (s -> b) -> Fold m a b
688foldt' :: Monad m => (s -> a -> Step s b) -> Step s b -> (s -> b) -> Fold m a b
642foldt' step initial extract =
689foldt' step initial extract =
690+ Fold
643− Fold (\s a -> return $ step s a) (return initial) (return . extract)
691+ (\s a -> return $ step s a)
692+ (return initial)
693+ (return . extract)
694+ (return . extract)
644
695
645-- | Make a terminating fold with an effectful step function and initial state,
696-- | Make a terminating fold with an effectful step function and initial state,
646-- and a state extraction function.
697-- and a state extraction function.
@@ -653,7 +704,7 @@ foldt' step initial extract =
653--
704--
654{-# INLINE foldtM' #-}
705{-# INLINE foldtM' #-}
655foldtM' :: (s -> a -> m (Step s b)) -> m (Step s b) -> (s -> m b) -> Fold m a b
706foldtM' :: (s -> a -> m (Step s b)) -> m (Step s b) -> (s -> m b) -> Fold m a b
656−foldtM' = Fold
707+foldtM' step initial extract = Fold step initial extract extract
657
708
658------------------------------------------------------------------------------
709------------------------------------------------------------------------------
659-- Refold
710-- Refold
@@ -667,7 +718,7 @@ foldtM' = Fold
667-- /Internal/
718-- /Internal/
668fromRefold :: Refold m c a b -> c -> Fold m a b
719fromRefold :: Refold m c a b -> c -> Fold m a b
669fromRefold (Refold step inject extract) c =
720fromRefold (Refold step inject extract) c =
670− Fold step (inject c) extract
721+ Fold step (inject c) extract extract
671
722
672------------------------------------------------------------------------------
723------------------------------------------------------------------------------
673-- Basic Folds
724-- Basic Folds
@@ -720,6 +771,29 @@ toStreamKRev = foldl' (flip K.cons) K.nil
720toStreamK :: Monad m => Fold m a (K.StreamK n a)
771toStreamK :: Monad m => Fold m a (K.StreamK n a)
721toStreamK = foldr K.cons K.nil
772toStreamK = foldr K.cons K.nil
722
773
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+
723------------------------------------------------------------------------------
797------------------------------------------------------------------------------
724-- Instances
798-- Instances
725------------------------------------------------------------------------------
799------------------------------------------------------------------------------
@@ -727,7 +801,8 @@ toStreamK = foldr K.cons K.nil
727-- | Maps a function on the output of the fold (the type @b@).
801-- | Maps a function on the output of the fold (the type @b@).
728instance Functor m => Functor (Fold m a) where
802instance Functor m => Functor (Fold m a) where
729 {-# INLINE fmap #-}
803 {-# INLINE fmap #-}
730− fmap f (Fold step1 initial1 extract) = Fold step initial (fmap2 f extract)
804+ fmap f (Fold step1 initial1 extract final) =
805+ Fold step initial (fmap2 f extract) (fmap2 f final)
731
806
732 where
807 where
733
808
@@ -762,7 +837,7 @@ instance Functor m => Functor (Fold m a) where
762--
837--
763{-# INLINE fromPure #-}
838{-# INLINE fromPure #-}
764fromPure :: Applicative m => b -> Fold m a b
839fromPure :: Applicative m => b -> Fold m a b
765−fromPure b = Fold undefined (pure $ Done b) pure
840+fromPure b = Fold undefined (pure $ Done b) pure pure
766
841
767-- | Make a fold that yields the result of the supplied effectful action
842-- | Make a fold that yields the result of the supplied effectful action
768-- without consuming any further input.
843-- without consuming any further input.
@@ -771,7 +846,7 @@ fromPure b = Fold undefined (pure $ Done b) pure
771--
846--
772{-# INLINE fromEffect #-}
847{-# INLINE fromEffect #-}
773fromEffect :: Applicative m => m b -> Fold m a b
848fromEffect :: Applicative m => m b -> Fold m a b
774−fromEffect b = Fold undefined (Done <$> b) pure
849+fromEffect b = Fold undefined (Done <$> b) pure pure
775
850
776{-# ANN type SeqFoldState Fuse #-}
851{-# ANN type SeqFoldState Fuse #-}
777data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
852data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
@@ -796,16 +871,20 @@ data SeqFoldState sl f sr = SeqFoldL !sl | SeqFoldR !f !sr
796-- complexity, because each composition adds a new branch that each subsequent
871-- complexity, because each composition adds a new branch that each subsequent
797-- fold's input element has to traverse, therefore, it cannot scale to a large
872-- fold's input element has to traverse, therefore, it cannot scale to a large
798-- number of compositions. After around 100 compositions the performance starts
873-- number of compositions. After around 100 compositions the performance starts
799−-- dipping rapidly compared to a CPS style implementation. When you need
874+-- dipping rapidly compared to a CPS style implementation.
800−-- scaling use parser monad instead.
875+--
876+-- For larger number of compositions you can convert the fold to a parser and
877+-- use ParserK.
801--
878--
802-- /Time: O(n^2) where n is the number of compositions./
879-- /Time: O(n^2) where n is the number of compositions./
803--
880--
804{-# INLINE splitWith #-}
881{-# INLINE splitWith #-}
805splitWith :: Monad m =>
882splitWith :: Monad m =>
806 (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
883 (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
807−splitWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
884+splitWith func
885+ (Fold stepL initialL _ finalL)
886+ (Fold stepR initialR _ finalR) =
808− Fold step initial extract
887+ Fold step initial extract final
809
888
810 where
889 where
811
890
@@ -822,13 +901,18 @@ splitWith func (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
822 step (SeqFoldL st) a = runL (stepL st a)
901 step (SeqFoldL st) a = runL (stepL st a)
823 step (SeqFoldR f st) a = runR (stepR st a) f
902 step (SeqFoldR f st) a = runR (stepR st a) f
824
903
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+
825− extract (SeqFoldR f sR) = fmap f (extractR sR)
909+ final (SeqFoldR f sR) = fmap f (finalR sR)
826− extract (SeqFoldL sL) = do
910+ final (SeqFoldL sL) = do
827− rL <- extractL sL
911+ rL <- finalL sL
828 res <- initialR
912 res <- initialR
829 fmap (func rL)
913 fmap (func rL)
830 $ case res of
914 $ case res of
831− Partial sR -> extractR sR
915+ Partial sR -> finalR sR
832 Done rR -> return rR
916 Done rR -> return rR
833
917
834{-# DEPRECATED serialWith "Please use \"splitWith\" instead" #-}
918{-# DEPRECATED serialWith "Please use \"splitWith\" instead" #-}
@@ -848,8 +932,8 @@ data SeqFoldState_ sl sr = SeqFoldL_ !sl | SeqFoldR_ !sr
848--
932--
849{-# INLINE split_ #-}
933{-# INLINE split_ #-}
850split_ :: Monad m => Fold m x a -> Fold m x b -> Fold m x b
934split_ :: Monad m => Fold m x a -> Fold m x b -> Fold m x b
851−split_ (Fold stepL initialL _) (Fold stepR initialR extractR) =
935+split_ (Fold stepL initialL _ finalL) (Fold stepR initialR _ finalR) =
852− Fold step initial extract
936+ Fold step initial extract final
853
937
854 where
938 where
855
939
@@ -872,11 +956,16 @@ split_ (Fold stepL initialL _) (Fold stepR initialR extractR) =
872 resR <- stepR st a
956 resR <- stepR st a
873 return $ first SeqFoldR_ resR
957 return $ first SeqFoldR_ resR
874
958
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+
875− extract (SeqFoldR_ sR) = extractR sR
963+ final (SeqFoldR_ sR) = finalR sR
876− extract (SeqFoldL_ _) = do
964+ final (SeqFoldL_ sL) = do
965+ _ <- finalL sL
877 res <- initialR
966 res <- initialR
878 case res of
967 case res of
879− Partial sR -> extractR sR
968+ Partial sR -> finalR sR
880 Done rR -> return rR
969 Done rR -> return rR
881
970
882-- | 'Applicative' form of 'splitWith'. Split the input serially over two
971-- | 'Applicative' form of 'splitWith'. Split the input serially over two
@@ -924,8 +1013,10 @@ data TeeState sL sR bL bR
924--
1013--
925{-# INLINE teeWith #-}
1014{-# INLINE teeWith #-}
926teeWith :: Monad m => (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
1015teeWith :: Monad m => (a -> b -> c) -> Fold m x a -> Fold m x b -> Fold m x c
1016+teeWith f
927−teeWith f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1017+ (Fold stepL initialL extractL finalL)
1018+ (Fold stepR initialR extractR finalR) =
928− Fold step initial extract
1019+ Fold step initial extract final
929
1020
930 where
1021 where
931
1022
@@ -952,6 +1043,10 @@ teeWith f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
952 extract (TeeLeft bR sL) = (`f` bR) <$> extractL sL
1043 extract (TeeLeft bR sL) = (`f` bR) <$> extractL sL
953 extract (TeeRight bL sR) = f bL <$> extractR sR
1044 extract (TeeRight bL sR) = f bL <$> extractR sR
954
1045
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+
955{-# ANN type TeeFstState Fuse #-}
1050{-# ANN type TeeFstState Fuse #-}
956data TeeFstState sL sR b
1051data TeeFstState sL sR b
957 = TeeFstBoth !sL !sR
1052 = TeeFstBoth !sL !sR
@@ -964,8 +1059,10 @@ data TeeFstState sL sR b
964{-# INLINE teeWithFst #-}
1059{-# INLINE teeWithFst #-}
965teeWithFst :: Monad m =>
1060teeWithFst :: Monad m =>
966 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1061 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1062+teeWithFst f
967−teeWithFst f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1063+ (Fold stepL initialL extractL finalL)
1064+ (Fold stepR initialR extractR finalR) =
968− Fold step initial extract
1065+ Fold step initial extract final
969
1066
970 where
1067 where
971
1068
@@ -984,7 +1081,7 @@ teeWithFst f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
984 Done bl -> do
1081 Done bl -> do
985 Done . f bl <$>
1082 Done . f bl <$>
986 case resR of
1083 case resR of
987− Partial sr -> extractR sr
1084+ Partial sr -> finalR sr
988 Done br -> return br
1085 Done br -> return br
989
1086
990 initial = runBoth initialL initialR
1087 initial = runBoth initialL initialR
@@ -995,6 +1092,9 @@ teeWithFst f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
995 extract (TeeFstBoth sL sR) = f <$> extractL sL <*> extractR sR
1092 extract (TeeFstBoth sL sR) = f <$> extractL sL <*> extractR sR
996 extract (TeeFstLeft bR sL) = (`f` bR) <$> extractL sL
1093 extract (TeeFstLeft bR sL) = (`f` bR) <$> extractL sL
997
1094
1095+ final (TeeFstBoth sL sR) = f <$> finalL sL <*> finalR sR
1096+ final (TeeFstLeft bR sL) = (`f` bR) <$> finalL sL
1097+
998-- | Like 'teeWith' but terminates as soon as any one of the two folds
1098-- | Like 'teeWith' but terminates as soon as any one of the two folds
999-- terminates.
1099-- terminates.
1000--
1100--
@@ -1003,8 +1103,10 @@ teeWithFst f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1003{-# INLINE teeWithMin #-}
1103{-# INLINE teeWithMin #-}
1004teeWithMin :: Monad m =>
1104teeWithMin :: Monad m =>
1005 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1105 (b -> c -> d) -> Fold m a b -> Fold m a c -> Fold m a d
1106+teeWithMin f
1006−teeWithMin f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1107+ (Fold stepL initialL extractL finalL)
1108+ (Fold stepR initialR extractR finalR) =
1007− Fold step initial extract
1109+ Fold step initial extract final
1008
1110
1009 where
1111 where
1010
1112
@@ -1016,12 +1118,12 @@ teeWithMin f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1016 Partial sl -> do
1118 Partial sl -> do
1017 case resR of
1119 case resR of
1018 Partial sr -> return $ Partial $ Tuple' sl sr
1120 Partial sr -> return $ Partial $ Tuple' sl sr
1019− Done br -> Done . (`f` br) <$> extractL sl
1121+ Done br -> Done . (`f` br) <$> finalL sl
1020
1122
1021 Done bl -> do
1123 Done bl -> do
1022 Done . f bl <$>
1124 Done . f bl <$>
1023 case resR of
1125 case resR of
1024− Partial sr -> extractR sr
1126+ Partial sr -> finalR sr
1025 Done br -> return br
1127 Done br -> return br
1026
1128
1027 initial = runBoth initialL initialR
1129 initial = runBoth initialL initialR
@@ -1030,6 +1132,8 @@ teeWithMin f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1030
1132
1031 extract (Tuple' sL sR) = f <$> extractL sL <*> extractR sR
1133 extract (Tuple' sL sR) = f <$> extractL sL <*> extractR sR
1032
1134
1135+ final (Tuple' sL sR) = f <$> finalL sL <*> finalR sR
1136+
1033-- | Shortest alternative. Apply both folds in parallel but choose the result
1137-- | Shortest alternative. Apply both folds in parallel but choose the result
1034-- from the one which consumed least input i.e. take the shortest succeeding
1138-- from the one which consumed least input i.e. take the shortest succeeding
1035-- fold.
1139-- fold.
@@ -1041,8 +1145,8 @@ teeWithMin f (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1041--
1145--
1042{-# INLINE shortest #-}
1146{-# INLINE shortest #-}
1043shortest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1147shortest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1044−shortest (Fold stepL initialL extractL) (Fold stepR initialR _) =
1148+shortest (Fold stepL initialL extractL finalL) (Fold stepR initialR _ finalR) =
1045− Fold step initial extract
1149+ Fold step initial extract final
1046
1150
1047 where
1151 where
1048
1152
@@ -1050,10 +1154,16 @@ shortest (Fold stepL initialL extractL) (Fold stepR initialR _) =
1050 runBoth actionL actionR = do
1154 runBoth actionL actionR = do
1051 resL <- actionL
1155 resL <- actionL
1052 resR <- actionR
1156 resR <- actionR
1053− return $
1054− case resL of
1157+ case resL of
1055− Partial sL -> bimap (Tuple' sL) Right resR
1158+ Partial sL ->
1159+ case resR of
1160+ Partial sR -> return $ Partial $ Tuple' sL sR
1161+ Done bR -> finalL sL >> return (Done (Right bR))
1056− Done bL -> Done $ Left bL
1162+ Done bL -> do
1163+ case resR of
1164+ Partial sR -> void (finalR sR)
1165+ Done _ -> return ()
1166+ return (Done (Left bL))
1057
1167
1058 initial = runBoth initialL initialR
1168 initial = runBoth initialL initialR
1059
1169
@@ -1061,6 +1171,8 @@ shortest (Fold stepL initialL extractL) (Fold stepR initialR _) =
1061
1171
1062 extract (Tuple' sL _) = Left <$> extractL sL
1172 extract (Tuple' sL _) = Left <$> extractL sL
1063
1173
1174+ final (Tuple' sL sR) = Left <$> finalL sL <* finalR sR
1175+
1064{-# ANN type LongestState Fuse #-}
1176{-# ANN type LongestState Fuse #-}
1065data LongestState sL sR
1177data LongestState sL sR
1066 = LongestBoth !sL !sR
1178 = LongestBoth !sL !sR
@@ -1078,8 +1190,10 @@ data LongestState sL sR
1078--
1190--
1079{-# INLINE longest #-}
1191{-# INLINE longest #-}
1080longest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1192longest :: Monad m => Fold m x a -> Fold m x b -> Fold m x (Either a b)
1193+longest
1081−longest (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1194+ (Fold stepL initialL _ finalL)
1195+ (Fold stepR initialR _ finalR) =
1082− Fold step initial extract
1196+ Fold step initial extract final
1083
1197
1084 where
1198 where
1085
1199
@@ -1102,14 +1216,18 @@ longest (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1102 step (LongestLeft sL) a = bimap LongestLeft Left <$> stepL sL a
1216 step (LongestLeft sL) a = bimap LongestLeft Left <$> stepL sL a
1103 step (LongestRight sR) a = bimap LongestRight Right <$> stepR sR a
1217 step (LongestRight sR) a = bimap LongestRight Right <$> stepR sR a
1104
1218
1105− left sL = Left <$> extractL sL
1219+ -- XXX Scan with this may not make sense as we cannot determine the longest
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+
1106− extract (LongestLeft sL) = left sL
1224+ final (LongestLeft sL) = Left <$> finalL sL
1107− extract (LongestRight sR) = Right <$> extractR sR
1225+ final (LongestRight sR) = Right <$> finalR sR
1108− extract (LongestBoth sL _) = left sL
1226+ final (LongestBoth sL sR) = Left <$> finalL sL <* finalR sR
1109
1227
1110−data ConcatMapState m sa a c
1228+data ConcatMapState m sa a b c
1111− = B !sa
1229+ = B !sa (sa -> m b)
1112− | forall s. C (s -> a -> m (Step s c)) !s (s -> m c)
1230+ | forall s. C (s -> a -> m (Step s c)) !s (s -> m c) (s -> m c)
1113
1231
1114-- | Map a 'Fold' returning function on the result of a 'Fold' and run the
1232-- | Map a 'Fold' returning function on the result of a 'Fold' and run the
1115-- returned fold. This operation can be used to express data dependencies
1233-- returned fold. This operation can be used to express data dependencies
@@ -1132,43 +1250,47 @@ data ConcatMapState m sa a c
1132--
1250--
1133{-# INLINE concatMap #-}
1251{-# INLINE concatMap #-}
1134concatMap :: Monad m => (b -> Fold m a c) -> Fold m a b -> Fold m a c
1252concatMap :: Monad m => (b -> Fold m a c) -> Fold m a b -> Fold m a c
1135−concatMap f (Fold stepa initiala extracta) = Fold stepc initialc extractc
1253+concatMap f (Fold stepa initiala _ finala) =
1254+ Fold stepc initialc extractc finalc
1136 where
1255 where
1137 initialc = do
1256 initialc = do
1138 r <- initiala
1257 r <- initiala
1139 case r of
1258 case r of
1140− Partial s -> return $ Partial (B s)
1259+ Partial s -> return $ Partial (B s finala)
1141 Done b -> initInnerFold (f b)
1260 Done b -> initInnerFold (f b)
1142
1261
1143− stepc (B s) a = do
1262+ stepc (B s fin) a = do
1144 r <- stepa s a
1263 r <- stepa s a
1145 case r of
1264 case r of
1146− Partial s1 -> return $ Partial (B s1)
1265+ Partial s1 -> return $ Partial (B s1 fin)
1147 Done b -> initInnerFold (f b)
1266 Done b -> initInnerFold (f b)
1148
1267
1149− stepc (C stepInner s extractInner) a = do
1268+ stepc (C stepInner s extractInner fin) a = do
1150 r <- stepInner s a
1269 r <- stepInner s a
1151 return $ case r of
1270 return $ case r of
1152− Partial sc -> Partial (C stepInner sc extractInner)
1271+ Partial sc -> Partial (C stepInner sc extractInner fin)
1153 Done c -> Done c
1272 Done c -> Done c
1154
1273
1155− extractc (B s) = do
1274+ -- XXX Cannot use for scanning
1156− r <- extracta s
1275+ extractc _ = error "concatMap: cannot be used for scanning"
1157− initExtract (f r)
1158− extractc (C _ sInner extractInner) = extractInner sInner
1159
1276
1160− initInnerFold (Fold step i e) = do
1277+ initInnerFold (Fold step i e fin) = do
1161 r <- i
1278 r <- i
1162 return $ case r of
1279 return $ case r of
1163− Partial s -> Partial (C step s e)
1280+ Partial s -> Partial (C step s e fin)
1164 Done c -> Done c
1281 Done c -> Done c
1165
1282
1166− initExtract (Fold _ i e) = do
1283+ initFinalize (Fold _ i _ fin) = do
1167 r <- i
1284 r <- i
1168 case r of
1285 case r of
1169− Partial s -> e s
1286+ Partial s -> fin s
1170 Done c -> return c
1287 Done c -> return c
1171
1288
1289+ finalc (B s fin) = do
1290+ r <- fin s
1291+ initFinalize (f r)
1292+ finalc (C _ sInner _ fin) = fin sInner
1293+
1172------------------------------------------------------------------------------
1294------------------------------------------------------------------------------
1173-- Mapping on input
1295-- Mapping on input
1174------------------------------------------------------------------------------
1296------------------------------------------------------------------------------
@@ -1187,7 +1309,7 @@ concatMap f (Fold stepa initiala extracta) = Fold stepc initialc extractc
1187--
1309--
1188{-# INLINE lmap #-}
1310{-# INLINE lmap #-}
1189lmap :: (a -> b) -> Fold m b r -> Fold m a r
1311lmap :: (a -> b) -> Fold m b r -> Fold m a r
1190−lmap f (Fold step begin done) = Fold step' begin done
1312+lmap f (Fold step begin done final) = Fold step' begin done final
1191 where
1313 where
1192 step' x a = step x (f a)
1314 step' x a = step x (f a)
1193
1315
@@ -1195,7 +1317,7 @@ lmap f (Fold step begin done) = Fold step' begin done
1195--
1317--
1196{-# INLINE lmapM #-}
1318{-# INLINE lmapM #-}
1197lmapM :: Monad m => (a -> m b) -> Fold m b r -> Fold m a r
1319lmapM :: Monad m => (a -> m b) -> Fold m b r -> Fold m a r
1198−lmapM f (Fold step begin done) = Fold step' begin done
1320+lmapM f (Fold step begin done final) = Fold step' begin done final
1199 where
1321 where
1200 step' x a = f a >>= step x
1322 step' x a = f a >>= step x
1201
1323
@@ -1207,8 +1329,10 @@ lmapM f (Fold step begin done) = Fold step' begin done
1207-- /Pre-release/
1329-- /Pre-release/
1208{-# INLINE postscan #-}
1330{-# INLINE postscan #-}
1209postscan :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1331postscan :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1332+postscan
1210−postscan (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1333+ (Fold stepL initialL extractL finalL)
1334+ (Fold stepR initialR extractR finalR) =
1211− Fold step initial extract
1335+ Fold step initial extract final
1212
1336
1213 where
1337 where
1214
1338
@@ -1219,30 +1343,32 @@ postscan (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1219 Done bL -> do
1343 Done bL -> do
1220 rR <- stepR sR bL
1344 rR <- stepR sR bL
1221 case rR of
1345 case rR of
1222− Partial sR1 -> Done <$> extractR sR1
1346+ Partial sR1 -> Done <$> finalR sR1
1223 Done bR -> return $ Done bR
1347 Done bR -> return $ Done bR
1224 Partial sL -> do
1348 Partial sL -> do
1225 !b <- extractL sL
1349 !b <- extractL sL
1226 rR <- stepR sR b
1350 rR <- stepR sR b
1227− return
1228− $ case rR of
1351+ case rR of
1229− Partial sR1 -> Partial (sL, sR1)
1352+ Partial sR1 -> return $ Partial (sL, sR1)
1230− Done bR -> Done bR
1353+ Done bR -> finalL sL >> return (Done bR)
1231
1354
1232 initial = do
1355 initial = do
1233− r <- initialR
1356+ rR <- initialR
1234− rL <- initialL
1235− case r of
1357+ case rR of
1236− Partial sR ->
1358+ Partial sR -> do
1359+ rL <- initialL
1237 case rL of
1360 case rL of
1238− Done _ -> Done <$> extractR sR
1361+ Done _ -> Done <$> finalR sR
1239 Partial sL -> return $ Partial (sL, sR)
1362 Partial sL -> return $ Partial (sL, sR)
1240 Done b -> return $ Done b
1363 Done b -> return $ Done b
1241
1364
1365+ -- XXX should use Tuple'
1242 step (sL, sR) x = runStep (stepL sL x) sR
1366 step (sL, sR) x = runStep (stepL sL x) sR
1243
1367
1244 extract = extractR . snd
1368 extract = extractR . snd
1245
1369
1370+ final (sL, sR) = finalL sL *> finalR sR
1371+
1246------------------------------------------------------------------------------
1372------------------------------------------------------------------------------
1247-- Filtering
1373-- Filtering
1248------------------------------------------------------------------------------
1374------------------------------------------------------------------------------
@@ -1255,7 +1381,7 @@ postscan (Fold stepL initialL extractL) (Fold stepR initialR extractR) =
1255--
1381--
1256{-# INLINE_NORMAL catMaybes #-}
1382{-# INLINE_NORMAL catMaybes #-}
1257catMaybes :: Monad m => Fold m a b -> Fold m (Maybe a) b
1383catMaybes :: Monad m => Fold m a b -> Fold m (Maybe a) b
1258−catMaybes (Fold step initial extract) = Fold step1 initial extract
1384+catMaybes (Fold step initial extract final) = Fold step1 initial extract final
1259
1385
1260 where
1386 where
1261
1387
@@ -1295,7 +1421,7 @@ filtering f = foldl' step Nothing
1295{-# INLINE filter #-}
1421{-# INLINE filter #-}
1296filter :: Monad m => (a -> Bool) -> Fold m a r -> Fold m a r
1422filter :: Monad m => (a -> Bool) -> Fold m a r -> Fold m a r
1297-- filter p = scanMaybe (filtering p)
1423-- filter p = scanMaybe (filtering p)
1298−filter f (Fold step begin done) = Fold step' begin done
1424+filter f (Fold step begin extract final) = Fold step' begin extract final
1299 where
1425 where
1300 step' x a = if f a then step x a else return $ Partial x
1426 step' x a = if f a then step x a else return $ Partial x
1301
1427
@@ -1306,7 +1432,7 @@ filter f (Fold step begin done) = Fold step' begin done
1306--
1432--
1307{-# INLINE filterM #-}
1433{-# INLINE filterM #-}
1308filterM :: Monad m => (a -> m Bool) -> Fold m a r -> Fold m a r
1434filterM :: Monad m => (a -> m Bool) -> Fold m a r -> Fold m a r
1309−filterM f (Fold step begin done) = Fold step' begin done
1435+filterM f (Fold step begin extract final) = Fold step' begin extract final
1310 where
1436 where
1311 step' x a = do
1437 step' x a = do
1312 use <- f a
1438 use <- f a
@@ -1395,7 +1521,7 @@ dropping n = foldt' step initial extract
1395{-# INLINE take #-}
1521{-# INLINE take #-}
1396take :: Monad m => Int -> Fold m a b -> Fold m a b
1522take :: Monad m => Int -> Fold m a b -> Fold m a b
1397-- take n = scanMaybe (taking n)
1523-- take n = scanMaybe (taking n)
1398−take n (Fold fstep finitial fextract) = Fold step initial extract
1524+take n (Fold fstep finitial fextract ffinal) = Fold step initial extract final
1399
1525
1400 where
1526 where
1401
1527
@@ -1407,7 +1533,7 @@ take n (Fold fstep finitial fextract) = Fold step initial extract
1407 s1 = Tuple'Fused i1 s
1533 s1 = Tuple'Fused i1 s
1408 if i1 < n
1534 if i1 < n
1409 then return $ Partial s1
1535 then return $ Partial s1
1410− else Done <$> fextract s
1536+ else Done <$> ffinal s
1411 Done b -> return $ Done b
1537 Done b -> return $ Done b
1412
1538
1413 initial = finitial >>= next (-1)
1539 initial = finitial >>= next (-1)
@@ -1416,6 +1542,72 @@ take n (Fold fstep finitial fextract) = Fold step initial extract
1416
1542
1417 extract (Tuple'Fused _ r) = fextract r
1543 extract (Tuple'Fused _ r) = fextract r
1418
1544
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+
1419------------------------------------------------------------------------------
1611------------------------------------------------------------------------------
1420-- Nesting
1612-- Nesting
1421------------------------------------------------------------------------------
1613------------------------------------------------------------------------------
@@ -1433,8 +1625,8 @@ take n (Fold fstep finitial fextract) = Fold step initial extract
1433-- /Pre-release/
1625-- /Pre-release/
1434{-# INLINE duplicate #-}
1626{-# INLINE duplicate #-}
1435duplicate :: Monad m => Fold m a b -> Fold m a (Fold m a b)
1627duplicate :: Monad m => Fold m a b -> Fold m a (Fold m a b)
1436−duplicate (Fold step1 initial1 extract1) =
1628+duplicate (Fold step1 initial1 extract1 final1) =
1437− Fold step initial (\s -> pure $ Fold step1 (pure $ Partial s) extract1)
1629+ Fold step initial extract final
1438
1630
1439 where
1631 where
1440
1632
@@ -1442,6 +1634,11 @@ duplicate (Fold step1 initial1 extract1) =
1442
1634
1443 step s a = second fromPure <$> step1 s a
1635 step s a = second fromPure <$> step1 s a
1444
1636
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+
1445-- If there were a finalize/flushing action in the stream type that would be
1642-- If there were a finalize/flushing action in the stream type that would be
1446-- equivalent to running initialize in Fold. But we do not have a flushing
1643-- equivalent to running initialize in Fold. But we do not have a flushing
1447-- action in streams.
1644-- action in streams.
@@ -1453,9 +1650,9 @@ duplicate (Fold step1 initial1 extract1) =
1453-- /Pre-release/
1650-- /Pre-release/
1454{-# INLINE reduce #-}
1651{-# INLINE reduce #-}
1455reduce :: Monad m => Fold m a b -> m (Fold m a b)
1652reduce :: Monad m => Fold m a b -> m (Fold m a b)
1456−reduce (Fold step initial extract) = do
1653+reduce (Fold step initial extract final) = do
1457 i <- initial
1654 i <- initial
1458− return $ Fold step (return i) extract
1655+ return $ Fold step (return i) extract final
1459
1656
1460-- This is the dual of Stream @cons@.
1657-- This is the dual of Stream @cons@.
1461
1658
@@ -1465,7 +1662,8 @@ reduce (Fold step initial extract) = do
1465-- /Pre-release/
1662-- /Pre-release/
1466{-# INLINE snoclM #-}
1663{-# INLINE snoclM #-}
1467snoclM :: Monad m => Fold m a b -> m a -> Fold m a b
1664snoclM :: Monad m => Fold m a b -> m a -> Fold m a b
1468−snoclM (Fold fstep finitial fextract) action = Fold fstep initial fextract
1665+snoclM (Fold fstep finitial fextract ffinal) action =
1666+ Fold fstep initial fextract ffinal
1469
1667
1470 where
1668 where
1471
1669
@@ -1492,7 +1690,8 @@ snoclM (Fold fstep finitial fextract) action = Fold fstep initial fextract
1492{-# INLINE snocl #-}
1690{-# INLINE snocl #-}
1493snocl :: Monad m => Fold m a b -> a -> Fold m a b
1691snocl :: Monad m => Fold m a b -> a -> Fold m a b
1494-- snocl f = snoclM f . return
1692-- snocl f = snoclM f . return
1495−snocl (Fold fstep finitial fextract) a = Fold fstep initial fextract
1693+snocl (Fold fstep finitial fextract ffinal) a =
1694+ Fold fstep initial fextract ffinal
1496
1695
1497 where
1696 where
1498
1697
@@ -1512,12 +1711,12 @@ snocl (Fold fstep finitial fextract) a = Fold fstep initial fextract
1512-- /Pre-release/
1711-- /Pre-release/
1513{-# INLINE snocM #-}
1712{-# INLINE snocM #-}
1514snocM :: Monad m => Fold m a b -> m a -> m (Fold m a b)
1713snocM :: Monad m => Fold m a b -> m a -> m (Fold m a b)
1515−snocM (Fold step initial extract) action = do
1714+snocM (Fold step initial extract final) action = do
1516 res <- initial
1715 res <- initial
1517 r <- case res of
1716 r <- case res of
1518 Partial fs -> action >>= step fs
1717 Partial fs -> action >>= step fs
1519 Done _ -> return res
1718 Done _ -> return res
1520− return $ Fold step (return r) extract
1719+ return $ Fold step (return r) extract final
1521
1720
1522-- Definitions:
1721-- Definitions:
1523--
1722--
@@ -1536,12 +1735,12 @@ snocM (Fold step initial extract) action = do
1536-- /Pre-release/
1735-- /Pre-release/
1537{-# INLINE snoc #-}
1736{-# INLINE snoc #-}
1538snoc :: Monad m => Fold m a b -> a -> m (Fold m a b)
1737snoc :: Monad m => Fold m a b -> a -> m (Fold m a b)
1539−snoc (Fold step initial extract) a = do
1738+snoc (Fold step initial extract final) a = do
1540 res <- initial
1739 res <- initial
1541 r <- case res of
1740 r <- case res of
1542 Partial fs -> step fs a
1741 Partial fs -> step fs a
1543 Done _ -> return res
1742 Done _ -> return res
1544− return $ Fold step (return r) extract
1743+ return $ Fold step (return r) extract final
1545
1744
1546-- | Append a singleton value to the fold.
1745-- | Append a singleton value to the fold.
1547--
1746--
@@ -1569,7 +1768,7 @@ addOne = flip snoc
1569-- /Pre-release/
1768-- /Pre-release/
1570{-# INLINE extractM #-}
1769{-# INLINE extractM #-}
1571extractM :: Monad m => Fold m a b -> m b
1770extractM :: Monad m => Fold m a b -> m b
1572−extractM (Fold _ initial extract) = do
1771+extractM (Fold _ initial extract _) = do
1573 res <- initial
1772 res <- initial
1574 case res of
1773 case res of
1575 Partial fs -> extract fs
1774 Partial fs -> extract fs
@@ -1578,14 +1777,15 @@ extractM (Fold _ initial extract) = do
1578-- | Close a fold so that it does not accept any more input.
1777-- | Close a fold so that it does not accept any more input.
1579{-# INLINE close #-}
1778{-# INLINE close #-}
1580close :: Monad m => Fold m a b -> Fold m a b
1779close :: Monad m => Fold m a b -> Fold m a b
1780+close (Fold _ initial1 _ final1) =
1581−close (Fold _ initial1 extract1) = Fold undefined initial undefined
1781+ Fold undefined initial undefined undefined
1582
1782
1583 where
1783 where
1584
1784
1585 initial = do
1785 initial = do
1586 res <- initial1
1786 res <- initial1
1587 case res of
1787 case res of
1588− Partial s -> Done <$> extract1 s
1788+ Partial s -> Done <$> final1 s
1589 Done b -> return $ Done b
1789 Done b -> return $ Done b
1590
1790
1591-- Corresponds to the null check for streams.
1791-- Corresponds to the null check for streams.
@@ -1595,7 +1795,7 @@ close (Fold _ initial1 extract1) = Fold undefined initial undefined
1595-- /Pre-release/
1795-- /Pre-release/
1596{-# INLINE isClosed #-}
1796{-# INLINE isClosed #-}
1597isClosed :: Monad m => Fold m a b -> m Bool
1797isClosed :: Monad m => Fold m a b -> m Bool
1598−isClosed (Fold _ initial _) = do
1798+isClosed (Fold _ initial _ _) = do
1599 res <- initial
1799 res <- initial
1600 return $ case res of
1800 return $ case res of
1601 Partial _ -> False
1801 Partial _ -> False
@@ -1629,8 +1829,10 @@ data ManyState s1 s2
1629--
1829--
1630{-# INLINE many #-}
1830{-# INLINE many #-}
1631many :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1831many :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1832+many
1632−many (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1833+ (Fold sstep sinitial sextract sfinal)
1834+ (Fold cstep cinitial cextract cfinal) =
1633− Fold step initial extract
1835+ Fold step initial extract final
1634
1836
1635 where
1837 where
1636
1838
@@ -1679,6 +1881,13 @@ many (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1679 Partial s -> cextract s
1881 Partial s -> cextract s
1680 Done b -> return b
1882 Done b -> return b
1681
1883
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+
1682-- | Like many, but the "first" fold emits an output at the end even if no
1891-- | Like many, but the "first" fold emits an output at the end even if no
1683-- input is received.
1892-- input is received.
1684--
1893--
@@ -1688,8 +1897,10 @@ many (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1688--
1897--
1689{-# INLINE manyPost #-}
1898{-# INLINE manyPost #-}
1690manyPost :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1899manyPost :: Monad m => Fold m a b -> Fold m b c -> Fold m a c
1900+manyPost
1691−manyPost (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1901+ (Fold sstep sinitial sextract sfinal)
1902+ (Fold cstep cinitial cextract cfinal) =
1692− Fold step initial extract
1903+ Fold step initial extract final
1693
1904
1694 where
1905 where
1695
1906
@@ -1725,6 +1936,12 @@ manyPost (Fold sstep sinitial sextract) (Fold cstep cinitial cextract) =
1725 Partial s -> cextract s
1936 Partial s -> cextract s
1726 Done b -> return b
1937 Done b -> return b
1727
1938
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+
1728-- | @groupsOf n split collect@ repeatedly applies the @split@ fold to chunks
1945-- | @groupsOf n split collect@ repeatedly applies the @split@ fold to chunks
1729-- of @n@ items in the input stream and supplies the result to the @collect@
1946-- of @n@ items in the input stream and supplies the result to the @collect@
1730-- fold.
1947-- fold.
@@ -1753,7 +1970,10 @@ groupsOf n split = many (take n split)
1753--
1970--
1754{-# INLINE refoldMany #-}
1971{-# INLINE refoldMany #-}
1755refoldMany :: Monad m => Fold m a b -> Refold m x b c -> Refold m x a c
1972refoldMany :: 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
1756−refoldMany (Fold sstep sinitial sextract) (Refold cstep cinject cextract) =
1976+ (Refold cstep cinject cextract) =
1757 Refold step inject extract
1977 Refold step inject extract
1758
1978
1759 where
1979 where
@@ -1804,7 +2024,9 @@ data ConsumeManyState x cs ss = ConsumeMany x cs (Either ss ss)
1804-- /Internal/
2024-- /Internal/
1805{-# INLINE refoldMany1 #-}
2025{-# INLINE refoldMany1 #-}
1806refoldMany1 :: Monad m => Refold m x a b -> Fold m b c -> Refold m x a c
2026refoldMany1 :: Monad m => Refold m x a b -> Fold m b c -> Refold m x a c
2027+refoldMany1
1807−refoldMany1 (Refold sstep sinject sextract) (Fold cstep cinitial cextract) =
2028+ (Refold sstep sinject sextract)
2029+ (Fold cstep cinitial cextract _cfinal) =
1808 Refold step inject extract
2030 Refold step inject extract
1809
2031
1810 where
2032 where
@@ -1855,7 +2077,7 @@ refoldMany1 (Refold sstep sinject sextract) (Fold cstep cinitial cextract) =
1855{-# INLINE refold #-}
2077{-# INLINE refold #-}
1856refold :: Monad m => Refold m b a c -> Fold m a b -> Fold m a c
2078refold :: Monad m => Refold m b a c -> Fold m a b -> Fold m a c
1857refold (Refold step inject extract) f =
2079refold (Refold step inject extract) f =
1858− Fold step (extractM f >>= inject) extract
2080+ Fold step (extractM f >>= inject) extract extract
1859
2081
1860------------------------------------------------------------------------------
2082------------------------------------------------------------------------------
1861-- morphInner
2083-- morphInner
@@ -1865,8 +2087,8 @@ refold (Refold step inject extract) f =
1865--
2087--
1866-- /Pre-release/
2088-- /Pre-release/
1867morphInner :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
2089morphInner :: (forall x. m x -> n x) -> Fold m a b -> Fold n a b
1868−morphInner f (Fold step initial extract) =
2090+morphInner f (Fold step initial extract final) =
1869− Fold (\x a -> f $ step x a) (f initial) (f . extract)
2091+ Fold (\x a -> f $ step x a) (f initial) (f . extract) (f . final)
1870
2092
1871-- | Adapt a pure fold to any monad.
2093-- | Adapt a pure fold to any monad.
1872--
2094--
core/src/Streamly/Internal/Data/Fold/Window.hs+10−4
@@ -65,6 +65,8 @@ 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+
68import qualified Streamly.Internal.Data.Fold.Type as Fold
70import qualified Streamly.Internal.Data.Fold.Type as Fold
69import qualified Streamly.Internal.Data.Ring as Ring
71import qualified Streamly.Internal.Data.Ring as Ring
70
72
@@ -148,7 +150,7 @@ windowRollingMap f = Fold.foldl' f1 initial
148--
150--
149{-# INLINE windowSumInt #-}
151{-# INLINE windowSumInt #-}
150windowSumInt :: forall m a. (Monad m, Integral a) => Fold m (a, Maybe a) a
152windowSumInt :: forall m a. (Monad m, Integral a) => Fold m (a, Maybe a) a
151−windowSumInt = Fold step initial extract
153+windowSumInt = Fold step initial extract extract
152
154
153 where
155 where
154
156
@@ -182,7 +184,7 @@ windowSumInt = Fold step initial extract
182--
184--
183{-# INLINE windowSum #-}
185{-# INLINE windowSum #-}
184windowSum :: forall m a. (Monad m, Num a) => Fold m (a, Maybe a) a
186windowSum :: forall m a. (Monad m, Num a) => Fold m (a, Maybe a) a
185−windowSum = Fold step initial extract
187+windowSum = Fold step initial extract extract
186
188
187 where
189 where
188
190
@@ -267,7 +269,7 @@ windowPowerSumFrac p = windowLmap (** p) windowSum
267--
269--
268{-# INLINE windowRange #-}
270{-# INLINE windowRange #-}
269windowRange :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe (a, a))
271windowRange :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (Maybe (a, a))
270−windowRange n = Fold step initial extract
272+windowRange n = Fold step initial extract extract
271
273
272 where
274 where
273
275
@@ -300,7 +302,11 @@ windowRange n = Fold step initial extract
300 if i == 0
302 if i == 0
301 then return Nothing
303 then return Nothing
302 else do
304 else do
303− x <- liftIO $ peek rh
305+ -- Here we use "ringStart" over "ringHead" as "ringHead" will be
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))
304 let accum (mn, mx) a = return (min mn a, max mx a)
310 let accum (mn, mx) a = return (min mn a, max mx a)
305 fmap Just $ foldFunc i rh accum (x, x) rb
311 fmap Just $ foldFunc i rh accum (x, x) rb
306
312
core/src/Streamly/Internal/Data/IORef/Unboxed.hs+22−19
@@ -23,34 +23,31 @@ 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− , toStreamD
35+ , pollIntIORef
36 )
36 )
37where
37where
38
38
39#include "inline.hs"
39#include "inline.hs"
40
40
41−import Data.Proxy (Proxy(..))
42import Control.Monad.IO.Class (MonadIO(..))
41import Control.Monad.IO.Class (MonadIO(..))
42+import Data.Proxy (Proxy(..))
43−import Streamly.Internal.Data.Unbox
43+import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
44− ( MutableByteArray(..)
44+import Streamly.Internal.Data.Unbox (Unbox(..), sizeOf)
45− , Unbox(..)
46− , newBytes
47− , sizeOf
48− )
49
45
46+import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
50import qualified Streamly.Internal.Data.Stream.Type as D
47import qualified Streamly.Internal.Data.Stream.Type as D
51
48
52-- | An 'IORef' holds a single 'Unbox'-able value.
49-- | An 'IORef' holds a single 'Unbox'-able value.
53−newtype IORef a = IORef MutableByteArray
50+newtype IORef a = IORef MutByteArray
54
51
55-- | Create a new 'IORef'.
52-- | Create a new 'IORef'.
56--
53--
@@ -58,8 +55,8 @@ newtype IORef a = IORef MutableByteArray
58{-# INLINE newIORef #-}
55{-# INLINE newIORef #-}
59newIORef :: forall a. Unbox a => a -> IO (IORef a)
56newIORef :: forall a. Unbox a => a -> IO (IORef a)
60newIORef x = do
57newIORef x = do
61− var <- newBytes (sizeOf (Proxy :: Proxy a))
58+ var <- MBA.new (sizeOf (Proxy :: Proxy a))
62− pokeByteIndex 0 var x
59+ pokeAt 0 var x
63 return $ IORef var
60 return $ IORef var
64
61
65-- | Write a value to an 'IORef'.
62-- | Write a value to an 'IORef'.
@@ -67,14 +64,14 @@ newIORef x = do
67-- /Pre-release/
64-- /Pre-release/
68{-# INLINE writeIORef #-}
65{-# INLINE writeIORef #-}
69writeIORef :: Unbox a => IORef a -> a -> IO ()
66writeIORef :: Unbox a => IORef a -> a -> IO ()
70−writeIORef (IORef var) = pokeByteIndex 0 var
67+writeIORef (IORef var) = pokeAt 0 var
71
68
72-- | Read a value from an 'IORef'.
69-- | Read a value from an 'IORef'.
73--
70--
74-- /Pre-release/
71-- /Pre-release/
75{-# INLINE readIORef #-}
72{-# INLINE readIORef #-}
76readIORef :: Unbox a => IORef a -> IO a
73readIORef :: Unbox a => IORef a -> IO a
77−readIORef (IORef var) = peekByteIndex 0 var
74+readIORef (IORef var) = peekAt 0 var
78
75
79-- | Modify the value of an 'IORef' using a function with strict application.
76-- | Modify the value of an 'IORef' using a function with strict application.
80--
77--
@@ -87,10 +84,16 @@ modifyIORef' var g = do
87
84
88-- | Generate a stream by continuously reading the IORef.
85-- | Generate a stream by continuously reading the IORef.
89--
86--
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+--
90-- /Pre-release/
93-- /Pre-release/
91−{-# INLINE_NORMAL toStreamD #-}
94+{-# INLINE_NORMAL pollIntIORef #-}
92−toStreamD :: (MonadIO m, Unbox a) => IORef a -> D.Stream m a
95+pollIntIORef :: (MonadIO m, Unbox a) => IORef a -> D.Stream m a
93−toStreamD var = D.Stream step ()
96+pollIntIORef var = D.Stream step ()
94
97
95 where
98 where
96
99
core/src/Streamly/Internal/Data/IsMap.hs+8
@@ -1,3 +1,7 @@
1+{-# LANGUAGE TypeFamilies #-}
2+-- Must come after TypeFamilies, otherwise it is re-enabled.
3+-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4+{-# LANGUAGE NoMonoLocalBinds #-}
1-- |
5-- |
2-- Module : Streamly.Internal.Data.IsMap
6-- Module : Streamly.Internal.Data.IsMap
3-- Copyright : (c) 2022 Composewell Technologies
7-- Copyright : (c) 2022 Composewell Technologies
@@ -28,6 +32,8 @@ class IsMap f where
28 mapDelete :: Key f -> f a -> f a
32 mapDelete :: Key f -> f a -> f a
29 mapUnion :: f a -> f a -> f a
33 mapUnion :: f a -> f a -> f a
30 mapNull :: f a -> Bool
34 mapNull :: f a -> Bool
35+ mapTraverseWithKey ::
36+ Applicative t => (Key f -> a -> t b) -> f a -> t (f b)
31
37
32instance Ord k => IsMap (Map k) where
38instance Ord k => IsMap (Map k) where
33 type Key (Map k) = k
39 type Key (Map k) = k
@@ -39,6 +45,7 @@ instance Ord k => IsMap (Map k) where
39 mapDelete = Map.delete
45 mapDelete = Map.delete
40 mapUnion = Map.union
46 mapUnion = Map.union
41 mapNull = Map.null
47 mapNull = Map.null
48+ mapTraverseWithKey = Map.traverseWithKey
42
49
43instance IsMap IntMap.IntMap where
50instance IsMap IntMap.IntMap where
44 type Key IntMap.IntMap = Int
51 type Key IntMap.IntMap = Int
@@ -50,3 +57,4 @@ instance IsMap IntMap.IntMap where
50 mapDelete = IntMap.delete
57 mapDelete = IntMap.delete
51 mapUnion = IntMap.union
58 mapUnion = IntMap.union
52 mapNull = IntMap.null
59 mapNull = IntMap.null
60+ mapTraverseWithKey = IntMap.traverseWithKey
core/src/Streamly/Internal/Data/MutArray.hs+154−33
@@ -8,79 +8,200 @@
8--
8--
9module Streamly.Internal.Data.MutArray
9module Streamly.Internal.Data.MutArray
10 (
10 (
11+ -- * MutArray.Type module
11 module Streamly.Internal.Data.MutArray.Type
12 module Streamly.Internal.Data.MutArray.Type
12− , splitOn
13+ -- * MutArray module
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
13 , genSlicesFromLen
24 , genSlicesFromLen
14 , getSlicesFromLen
25 , getSlicesFromLen
15− , fromStream
16 )
26 )
17where
27where
18
28
19#include "inline.hs"
29#include "inline.hs"
20
30
21import Control.Monad.IO.Class (MonadIO(..))
31import 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)
22import Streamly.Internal.Data.Unbox (Unbox)
35import Streamly.Internal.Data.Unbox (Unbox)
23−import Streamly.Internal.Data.Stream (Stream)
24import Streamly.Internal.Data.Unfold.Type (Unfold(..))
36import Streamly.Internal.Data.Unfold.Type (Unfold(..))
25
37
26−import qualified Streamly.Internal.Data.Stream as D
38+import qualified Streamly.Internal.Data.Stream.Type as Stream
39+import qualified Streamly.Internal.Data.Stream.Nesting as Stream
40+-- import qualified Streamly.Internal.Data.Stream.Transform as Stream
27import qualified Streamly.Internal.Data.Unfold as Unfold
41import qualified Streamly.Internal.Data.Unfold as Unfold
28
42
29import Prelude hiding (foldr, length, read, splitAt)
43import Prelude hiding (foldr, length, read, splitAt)
30import Streamly.Internal.Data.MutArray.Type
44import Streamly.Internal.Data.MutArray.Type
31−
45+import Streamly.Internal.Data.IORef.Unboxed
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)
42
46
43-- | Generate a stream of array slice descriptors ((index, len)) of specified
47-- | Generate a stream of array slice descriptors ((index, len)) of specified
44-- length from an array, starting from the supplied array index. The last slice
48-- length from an array, starting from the supplied array index. The last slice
45-- may be shorter than the requested length depending on the array length.
49-- may be shorter than the requested length depending on the array length.
46--
50--
47-- /Pre-release/
51-- /Pre-release/
48−{-# INLINE genSlicesFromLen #-}
52+{-# INLINE sliceIndexerFromLen #-}
49−genSlicesFromLen :: forall m a. (Monad m, Unbox a)
53+sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
50 => Int -- ^ from index
54 => Int -- ^ from index
51 -> Int -- ^ length of the slice
55 -> Int -- ^ length of the slice
52 -> Unfold m (MutArray a) (Int, Int)
56 -> Unfold m (MutArray a) (Int, Int)
53−genSlicesFromLen from len =
57+sliceIndexerFromLen from len =
54 let fromThenTo n = (from, from + len, n - 1)
58 let fromThenTo n = (from, from + len, n - 1)
55 mkSlice n i = return (i, min len (n - i))
59 mkSlice n i = return (i, min len (n - i))
56 in Unfold.lmap length
60 in Unfold.lmap length
57 $ Unfold.mapM2 mkSlice
61 $ Unfold.mapM2 mkSlice
58 $ Unfold.lmap fromThenTo Unfold.enumerateFromThenTo
62 $ Unfold.lmap fromThenTo Unfold.enumerateFromThenTo
59
63
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+
60-- | Generate a stream of slices of specified length from an array, starting
71-- | Generate a stream of slices of specified length from an array, starting
61-- from the supplied array index. The last slice may be shorter than the
72-- from the supplied array index. The last slice may be shorter than the
62-- requested length depending on the array length.
73-- requested length depending on the array length.
63--
74--
64-- /Pre-release/
75-- /Pre-release/
65−{-# INLINE getSlicesFromLen #-}
76+{-# INLINE slicerFromLen #-}
66−getSlicesFromLen :: forall m a. (Monad m, Unbox a)
77+slicerFromLen :: forall m a. (Monad m, Unbox a)
67 => Int -- ^ from index
78 => Int -- ^ from index
68 -> Int -- ^ length of the slice
79 -> Int -- ^ length of the slice
69 -> Unfold m (MutArray a) (MutArray a)
80 -> Unfold m (MutArray a) (MutArray a)
70−getSlicesFromLen from len =
81+slicerFromLen from len =
71 let mkSlice arr (i, n) = return $ getSliceUnsafe i n arr
82 let mkSlice arr (i, n) = return $ getSliceUnsafe i n arr
72− in Unfold.mapM2 mkSlice (genSlicesFromLen from len)
83+ in Unfold.mapM2 mkSlice (sliceIndexerFromLen from len)
84+
85+{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
86+getSlicesFromLen :: forall m a. (Monad m, Unbox a)
87+ => Int -- ^ from index
88+ -> Int -- ^ length of the slice
89+ -> Unfold m (MutArray a) (MutArray a)
90+getSlicesFromLen = slicerFromLen
73
91
74−-- | Create an 'Array' from a stream. This is useful when we want to create a
92+-------------------------------------------------------------------------------
75−-- single array from a stream of unknown size. 'writeN' is at least twice
93+-- Compacting Streams of Arrays
76−-- as efficient when the size is already known.
94+-------------------------------------------------------------------------------
95+
96+-- | @compactLE maxElems@ coalesces adjacent arrays in the input stream
97+-- only if the combined size would be less than or equal to @maxElems@
98+-- elements. Note that it won't split an array if the original array is already
99+-- larger than maxElems.
77--
100--
78−-- Note that if the input stream is too large memory allocation for the array
101+-- @maxElems@ must be greater than 0.
79−-- may fail. When the stream size is not known, `chunksOf` followed by
80−-- processing of indvidual arrays in the resulting stream should be preferred.
81--
102--
82−-- /Pre-release/
103+-- Generates unpinned arrays irrespective of the pinning status of input
83−{-# INLINE fromStream #-}
104+-- arrays.
105+{-# INLINE compactLE #-}
106+compactLE :: (MonadIO m, Unbox a) =>
84−fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
107+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
85−fromStream = fromStreamD
108+-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
86−-- fromStream (Stream m) = P.fold write m
109+-- to implement it.
110+compactLE = compactLeAs Unpinned
111+-- The parser version turns out to be a little bit slower.
112+-- compactLE n = Stream.catRights . Stream.parseManyD (pCompactLE n)
113+
114+-- | Pinned version of 'compactLE'.
115+{-# INLINE pinnedCompactLE #-}
116+pinnedCompactLE :: forall m a. (MonadIO m, Unbox a)
117+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
118+pinnedCompactLE = compactLeAs Pinned
119+-- pinnedCompactLE n = Stream.catRights . Stream.parseManyD (pPinnedCompactLE n)
120+
121+data SplitState s arr
122+ = Initial s
123+ | Buffering s arr
124+ | Splitting s arr
125+ | Yielding arr (SplitState s arr)
126+ | Finishing
127+
128+-- | Split a stream of arrays on a given separator byte, dropping the separator
129+-- and coalescing all the arrays between two separators into a single array.
130+--
131+{-# INLINE_NORMAL _compactOnByteCustom #-}
132+_compactOnByteCustom
133+ :: MonadIO m
134+ => Word8
135+ -> Stream m (MutArray Word8)
136+ -> Stream m (MutArray Word8)
137+_compactOnByteCustom byte (Stream.Stream step state) =
138+ Stream.Stream step' (Initial state)
139+
140+ where
141+
142+ {-# INLINE_LATE step' #-}
143+ step' gst (Initial st) = do
144+ r <- step gst st
145+ case r of
146+ Stream.Yield arr s -> do
147+ (arr1, marr2) <- breakOn byte arr
148+ return $ case marr2 of
149+ Nothing -> Stream.Skip (Buffering s arr1)
150+ Just arr2 -> Stream.Skip (Yielding arr1 (Splitting s arr2))
151+ Stream.Skip s -> return $ Stream.Skip (Initial s)
152+ Stream.Stop -> return Stream.Stop
153+
154+ step' gst (Buffering st buf) = do
155+ r <- step gst st
156+ case r of
157+ Stream.Yield arr s -> do
158+ (arr1, marr2) <- breakOn byte arr
159+ -- XXX Use spliceExp instead and then rightSize?
160+ buf1 <- splice buf arr1
161+ return $ case marr2 of
162+ Nothing -> Stream.Skip (Buffering s buf1)
163+ Just x -> Stream.Skip (Yielding buf1 (Splitting s x))
164+ Stream.Skip s -> return $ Stream.Skip (Buffering s buf)
165+ Stream.Stop -> return $
166+ if byteLength buf == 0
167+ then Stream.Stop
168+ else Stream.Skip (Yielding buf Finishing)
169+
170+ step' _ (Splitting st buf) = do
171+ (arr1, marr2) <- breakOn byte buf
172+ return $ case marr2 of
173+ Nothing -> Stream.Skip $ Buffering st arr1
174+ Just arr2 -> Stream.Skip $ Yielding arr1 (Splitting st arr2)
175+
176+ step' _ (Yielding arr next) = return $ Stream.Yield arr next
177+ step' _ Finishing = return Stream.Stop
178+
179+-- XXX implement predicate based version of this
180+-- XXX Naming of predicate based vs custom version
181+
182+-- | Split a stream of arrays on a given separator byte, dropping the separator
183+-- and coalescing all the arrays between two separators into a single array.
184+--
185+{-# INLINE compactOnByte #-}
186+compactOnByte
187+ :: (MonadIO m)
188+ => Word8
189+ -> Stream m (MutArray Word8)
190+ -> Stream m (MutArray Word8)
191+-- XXX compare perf of custom vs idiomatic version
192+-- compactOnByte = _compactOnByteCustom
193+-- XXX use spliceExp and rightSize?
194+compactOnByte byte = Stream.splitInnerBy (breakOn byte) splice
195+
196+-- | Like 'compactOnByte' considers the separator in suffix position instead of
197+-- infix position.
198+{-# INLINE compactOnByteSuffix #-}
199+compactOnByteSuffix
200+ :: (MonadIO m)
201+ => Word8
202+ -> Stream m (MutArray Word8)
203+ -> Stream m (MutArray Word8)
204+compactOnByteSuffix byte =
205+ -- XXX use spliceExp and rightSize?
206+ Stream.splitInnerBySuffix
207+ (\arr -> byteLength arr == 0) (breakOn byte) splice
core/src/Streamly/Internal/Data/MutArray/Generic.hs+65−30
@@ -19,14 +19,14 @@ module Streamly.Internal.Data.MutArray.Generic
19 , nil
19 , nil
20
20
21 -- *** Uninitialized Arrays
21 -- *** Uninitialized Arrays
22− , new
22+ , emptyOf
23 -- , newArrayWith
23 -- , newArrayWith
24
24
25 -- *** From streams
25 -- *** From streams
26− , writeNUnsafe
26+ , unsafeCreateOf
27− , writeN
27+ , createOf
28− , writeWith
28+ , createWith -- createOfMin/createMin/createGE?
29− , write
29+ , create
30 , fromStreamN
30 , fromStreamN
31 , fromStream
31 , fromStream
32 , fromPureStream
32 , fromPureStream
@@ -160,6 +160,13 @@ module Streamly.Internal.Data.MutArray.Generic
160 -- , appendSliceFrom
160 -- , appendSliceFrom
161
161
162 , clone
162 , clone
163+
164+ -- * Deprecated
165+ , new
166+ , writeNUnsafe
167+ , writeN
168+ , writeWith
169+ , write
163 )
170 )
164where
171where
165
172
@@ -236,13 +243,13 @@ bottomElement =
236-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
243-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
237-- that we do not have to write undefined or error in the whole array.
244-- that we do not have to write undefined or error in the whole array.
238
245
239−-- | @new count@ allocates a zero length array that can be extended to hold
246+-- | @emptyOf count@ allocates a zero length array that can be extended to hold
240-- up to 'count' items without reallocating.
247-- up to 'count' items without reallocating.
241--
248--
242-- /Pre-release/
249-- /Pre-release/
243−{-# INLINE new #-}
250+{-# INLINE emptyOf #-}
244−new :: MonadIO m => Int -> m (MutArray a)
251+emptyOf :: MonadIO m => Int -> m (MutArray a)
245−new n@(I# n#) =
252+emptyOf n@(I# n#) =
246 liftIO
253 liftIO
247 $ IO
254 $ IO
248 $ \s# ->
255 $ \s# ->
@@ -251,6 +258,12 @@ new n@(I# n#) =
251 let ma = MutArray arr# 0 0 n
258 let ma = MutArray arr# 0 0 n
252 in (# s1#, ma #)
259 in (# s1#, ma #)
253
260
261+-- XXX Deprecate in major
262+-- {-# DEPRECATED new "Please use emptyOf instead." #-}
263+{-# INLINE new #-}
264+new :: MonadIO m => Int -> m (MutArray a)
265+new = emptyOf
266+
254-- XXX This could be pure?
267-- XXX This could be pure?
255
268
256-- |
269-- |
@@ -318,7 +331,7 @@ putIndices arr = FL.foldlM' step (return ())
318
331
319 where
332 where
320
333
321− step () (i, x) = liftIO (putIndex i arr x)
334+ step () (i, x) = putIndex i arr x
322
335
323-- | Modify a given index of an array using a modifier function without checking
336-- | Modify a given index of an array using a modifier function without checking
324-- the bounds.
337-- the bounds.
@@ -589,16 +602,16 @@ readRev arr@MutArray{..} =
589arrayChunkSize :: Int
602arrayChunkSize :: Int
590arrayChunkSize = 1024
603arrayChunkSize = 1024
591
604
592−-- | Like 'writeN' but does not check the array bounds when writing. The fold
605+-- | Like 'createOf' but does not check the array bounds when writing. The fold
593-- driver must not call the step function more than 'n' times otherwise it will
606-- driver must not call the step function more than 'n' times otherwise it will
594-- corrupt the memory and crash. This function exists mainly because any
607-- corrupt the memory and crash. This function exists mainly because any
595-- conditional in the step function blocks fusion causing 10x performance
608-- conditional in the step function blocks fusion causing 10x performance
596-- slowdown.
609-- slowdown.
597--
610--
598-- /Pre-release/
611-- /Pre-release/
599−{-# INLINE_NORMAL writeNUnsafe #-}
612+{-# INLINE_NORMAL unsafeCreateOf #-}
600−writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
613+unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
601−writeNUnsafe n = Fold step initial return
614+unsafeCreateOf n = Fold step initial return return
602
615
603 where
616 where
604
617
@@ -606,59 +619,81 @@ writeNUnsafe n = Fold step initial return
606
619
607 step arr x = FL.Partial <$> snocUnsafe arr x
620 step arr x = FL.Partial <$> snocUnsafe arr x
608
621
622+{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
623+{-# INLINE writeNUnsafe #-}
624+writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
625+writeNUnsafe = unsafeCreateOf
626+
609−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
627+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
610-- 'Array'.
628-- 'Array'.
611--
629--
612−-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
630+-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
613--
631--
614-- /Pre-release/
632-- /Pre-release/
615−{-# INLINE_NORMAL writeN #-}
633+{-# INLINE_NORMAL createOf #-}
634+createOf :: MonadIO m => Int -> Fold m a (MutArray a)
635+createOf n = FL.take n $ unsafeCreateOf n
636+
637+-- XXX Deprecate in major
638+-- {-# DEPRECATED writeN "Please use createOf instead." #-}
639+{-# INLINE writeN #-}
616writeN :: MonadIO m => Int -> Fold m a (MutArray a)
640writeN :: MonadIO m => Int -> Fold m a (MutArray a)
617−writeN n = FL.take n $ writeNUnsafe n
641+writeN = createOf
618
642
619-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
643-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
620-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
644-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
621-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
645-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
622
646
623−-- | @writeWith minCount@ folds the whole input to a single array. The array
647+-- | @createWith minCount@ folds the whole input to a single array. The array
624-- starts at a size big enough to hold minCount elements, the size is doubled
648-- starts at a size big enough to hold minCount elements, the size is doubled
625-- every time the array needs to be grown.
649-- every time the array needs to be grown.
626--
650--
627-- /Caution! Do not use this on infinite streams./
651-- /Caution! Do not use this on infinite streams./
628--
652--
629-- /Pre-release/
653-- /Pre-release/
630−{-# INLINE_NORMAL writeWith #-}
654+{-# INLINE_NORMAL createWith #-}
631−writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
655+createWith :: MonadIO m => Int -> Fold m a (MutArray a)
632-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
656-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
633−writeWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
657+createWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
634
658
635 where
659 where
636
660
637 initial = do
661 initial = do
638− when (elemCount < 0) $ error "writeWith: elemCount is negative"
662+ when (elemCount < 0) $ error "createWith: elemCount is negative"
639− liftIO $ new elemCount
663+ new elemCount
640
664
641 step arr@(MutArray _ start end bound) x
665 step arr@(MutArray _ start end bound) x
642 | end == bound = do
666 | end == bound = do
643 let oldSize = end - start
667 let oldSize = end - start
644 newSize = max (oldSize * 2) 1
668 newSize = max (oldSize * 2) 1
645− arr1 <- liftIO $ realloc newSize arr
669+ arr1 <- realloc newSize arr
646 snocUnsafe arr1 x
670 snocUnsafe arr1 x
647 step arr x = snocUnsafe arr x
671 step arr x = snocUnsafe arr x
648
672
649− -- extract = liftIO . rightSize
673+ -- extract = rightSize
650 extract = return
674 extract = return
651
675
676+{-# DEPRECATED writeWith "Please use createWith instead." #-}
677+{-# INLINE writeWith #-}
678+writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
679+writeWith = createWith
680+
652-- | Fold the whole input to a single array.
681-- | Fold the whole input to a single array.
653--
682--
654−-- Same as 'writeWith' using an initial array size of 'arrayChunkSize' bytes
683+-- Same as 'createWith' using an initial array size of 'arrayChunkSize' bytes
655-- rounded up to the element size.
684-- rounded up to the element size.
656--
685--
657-- /Caution! Do not use this on infinite streams./
686-- /Caution! Do not use this on infinite streams./
658--
687--
688+{-# INLINE create #-}
689+create :: MonadIO m => Fold m a (MutArray a)
690+create = writeWith arrayChunkSize
691+
692+-- XXX Deprecate in major
693+-- {-# DEPRECATED write "Please use create instead." #-}
659{-# INLINE write #-}
694{-# INLINE write #-}
660write :: MonadIO m => Fold m a (MutArray a)
695write :: MonadIO m => Fold m a (MutArray a)
661−write = writeWith arrayChunkSize
696+write = create
662
697
663-- | Create a 'MutArray' from the first @n@ elements of a stream. The
698-- | Create a 'MutArray' from the first @n@ elements of a stream. The
664-- array is allocated to size @n@, if the stream terminates before @n@
699-- array is allocated to size @n@, if the stream terminates before @n@
@@ -683,7 +718,7 @@ fromList xs = fromStream $ D.fromList xs
683{-# INLINABLE fromPureStream #-}
718{-# INLINABLE fromPureStream #-}
684fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
719fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
685fromPureStream xs =
720fromPureStream xs =
686− liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
721+ D.fold write $ D.morphInner (return . runIdentity) xs
687
722
688-------------------------------------------------------------------------------
723-------------------------------------------------------------------------------
689-- Chunking
724-- Chunking
@@ -815,7 +850,7 @@ putSliceUnsafe src srcStart dst dstStart len = liftIO $ do
815
850
816{-# INLINE clone #-}
851{-# INLINE clone #-}
817clone :: MonadIO m => MutArray a -> m (MutArray a)
852clone :: MonadIO m => MutArray a -> m (MutArray a)
818−clone src = liftIO $ do
853+clone src = do
819 let len = arrLen src
854 let len = arrLen src
820 dst <- new len
855 dst <- new len
821 putSliceUnsafe src 0 dst 0 len
856 putSliceUnsafe src 0 dst 0 len
core/src/Streamly/Internal/Data/MutArray/Stream.hsnew file+145
@@ -0,0 +1,145 @@
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+1271−417
@@ -28,57 +28,80 @@
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− , MutableByteArray
34+
35− , touch
35+ -- ** Conversion
36+ -- *** Pinned and Unpinned
36 , pin
37 , pin
37 , unpin
38 , unpin
38 , isPinned
39 , isPinned
39
40
40− -- * Constructing and Writing
41+ -- ** Casting
42+ , cast
43+ , castUnsafe -- XXX unsafeCast
44+ , asBytes
45+ , unsafePinnedAsPtr
46+ , unsafeAsPtr
47+
41 -- ** Construction
48 -- ** Construction
42− , nil
49+ , empty
50+
51+ -- *** New
52+ -- | New arrays are always empty arrays with some reserve capacity to
53+ -- extend the length without reallocating.
54+ , emptyOf
55+ , newArrayWith -- emptyAlignedWith
56+ , pinnedEmptyOf
57+ , pinnedNewAligned -- XXX not required
58+ -- , new -- uninitialized array of specified length
59+
60+ -- *** Cloning
61+ , clone
62+ , pinnedClone
43
63
44− -- *** Uninitialized Arrays
64+ -- *** Slicing
45− , pinnedNew
65+ -- | Get a subarray without copying
46− , pinnedNewBytes
66+ , getSliceUnsafe -- XXX unsafeGetSlice
47− , pinnedNewAligned
67+ , getSlice
48− , new
68+ , splitAt -- XXX should be able to express using getSlice
49− , newArrayWith
69+ , breakOn
50
70
51− -- *** From streams
71+ -- *** Stream Folds
52 , ArrayUnsafe (..)
72 , ArrayUnsafe (..)
53− , writeNWithUnsafe
73+ , unsafeCreateOfWith
54− , writeNWith
74+ , unsafeCreateOf
55− , writeNUnsafe
75+ , unsafePinnedCreateOf
56− , pinnedWriteNUnsafe
76+ , pinnedCreateOf
57− , writeN
77+ , createOfWith
58− , pinnedWriteN
78+ , createOf
59− , pinnedWriteNAligned
79+ , revCreateOf
60−
80+
61− , writeWith
81+ , pinnedCreate
62− , write
82+ , createWith
63− , pinnedWrite
83+ , create
64−
84+ -- , revCreate
65− , writeRevN
85+
66− -- , writeRev
67−
68− -- ** From containers
86+ -- *** From containers
69 , fromListN
87 , fromListN
70 , pinnedFromListN
88 , pinnedFromListN
71 , fromList
89 , fromList
72 , pinnedFromList
90 , pinnedFromList
73 , fromListRevN
91 , fromListRevN
74 , fromListRev
92 , fromListRev
75− , fromStreamDN
93+ , fromStreamN
76− , fromStreamD
94+ , fromStream
95+ , fromPureStreamN
77 , fromPureStream
96 , fromPureStream
97+ , fromByteStr#
98+ , fromPtrN
99+ , fromChunksK
100+ , fromChunksRealloced -- fromSmallChunks
78
101
79− -- * Random writes
102+ -- ** Random writes
80 , putIndex
103 , putIndex
81− , putIndexUnsafe
104+ , putIndexUnsafe -- XXX unsafePutIndex
82 , putIndices
105 , putIndices
83 -- , putFromThenTo
106 -- , putFromThenTo
84 -- , putFrom -- start writing at the given position
107 -- , putFrom -- start writing at the given position
@@ -86,78 +109,71 @@ module Streamly.Internal.Data.MutArray.Type
86 -- , putFromTo
109 -- , putFromTo
87 -- , putFromRev
110 -- , putFromRev
88 -- , putUptoRev
111 -- , putUptoRev
89− , modifyIndexUnsafe
112+ , modifyIndexUnsafe -- XXX unsafeModifyIndex
90 , modifyIndex
113 , modifyIndex
91 , modifyIndices
114 , modifyIndices
92 , modify
115 , modify
93 , swapIndices
116 , swapIndices
94 , unsafeSwapIndices
117 , unsafeSwapIndices
95
118
96− -- * Growing and Shrinking
119+ -- ** Reading
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.
100−
101− -- ** Appending elements
102− , snocWith
103− , snoc
104− , snocLinear
105− , snocMay
106− , snocUnsafe
107−
108− -- ** Appending streams
109− , writeAppendNUnsafe
110− , writeAppendN
111− , writeAppendWith
112− , writeAppend
113
120
114− -- * Eliminating and Reading
121+ -- *** Indexing
115−
122+ , getIndex
116− -- ** To streams
123+ , getIndexUnsafe -- XXX unsafeGetIndex
117− , reader
124+ -- , getFromThenTo
118− , readerRevWith
125+ , getIndexRev -- getRevIndex?
119− , readerRev
126+ , indexReader
127+ , indexReaderWith
120
128
121− -- ** To containers
129+ -- *** To Streams
122− , toStreamDWith
123− , toStreamDRevWith
124− , toStreamKWith
125− , toStreamKRevWith
126 , read
130 , read
127 , readRev
131 , readRev
132+ , toStreamWith
133+ , toStreamRevWith
128 , toStreamK
134 , toStreamK
135+ , toStreamKWith
129 , toStreamKRev
136 , toStreamKRev
137+ , toStreamKRevWith
138+
139+ -- *** To Containers
130 , toList
140 , toList
131
141
142+ -- *** Unfolds
132 -- experimental
143 -- experimental
133 , producerWith
144 , producerWith
134 , producer
145 , producer
135
146
136− -- ** Random reads
147+ , reader
137− , getIndex
148+ , readerRevWith
138− , getIndexUnsafe
149+ , readerRev
139− , getIndices
140− , getIndicesD
141− -- , getFromThenTo
142− , getIndexRev
143−
144− -- * Memory Management
145− , blockSize
146− , arrayChunkBytes
147− , allocBytesToElemCount
148− , realloc
149− , resize
150− , resizeExp
151− , rightSize
152
150
151+ -- ** Size and Capacity
153− -- * Size
152+ -- *** Size
154 , length
153 , length
155 , byteLength
154 , byteLength
155+
156+ -- *** Capacity
156 -- , capacity
157 -- , capacity
157 , byteCapacity
158 , byteCapacity
158 , bytesFree
159 , bytesFree
159
160
161+ -- *** Capacity Management
162+ , blockSize
163+ , arrayChunkBytes
164+ , allocBytesToElemCount
165+ , realloc -- this is "resize"
166+ , grow
167+ , growExp
168+ , rightSize
169+
170+ -- ** Folding
171+ , foldl'
172+ , foldr
173+ , byteCmp
174+ , byteEq
175+
160− -- * In-place Mutation Algorithms
176+ -- ** In-place Mutation Algorithms
161 , strip
177 , strip
162 , reverse
178 , reverse
163 , permute
179 , permute
@@ -167,62 +183,121 @@ module Streamly.Internal.Data.MutArray.Type
167 , mergeBy
183 , mergeBy
168 , bubble
184 , bubble
169
185
170− -- * Casting
186+ -- ** Growing and Shrinking
171− , cast
187+ -- | Arrays grow only at the end, though it is possible to grow on both
172− , castUnsafe
188+ -- sides and therefore have a cons as well as snoc. But that will require
173− , asBytes
189+ -- both lower and upper bound in the array representation.
174− , asPtrUnsafe
175−
176− -- * Folding
177− , foldl'
178− , foldr
179− , cmp
180−
181− -- * Arrays of arrays
182− -- We can add dimensionality parameter to the array type to get
183− -- multidimensional arrays. Multidimensional arrays would just be a
184− -- convenience wrapper on top of single dimensional arrays.
185
190
186− -- | Operations dealing with multiple arrays, streams of arrays or
191+ -- *** Appending elements
187− -- multidimensional array representations.
192+ , snocWith
188−
193+ , snoc
189− -- ** Construct from streams
194+ , snocLinear
190− , chunksOf
195+ , snocMay
191− , pinnedChunksOf
196+ , snocUnsafe -- XXX unsafeSnoc
192− , writeChunks
193−
194− -- ** Eliminate to streams
195− , flattenArrays
196− , flattenArraysRev
197− , fromArrayStreamK
198−
199− -- ** Construct from arrays
200− -- get chunks without copying
201− , getSliceUnsafe
202− , getSlice
203− -- , getSlicesFromLenN
204− , splitAt -- XXX should be able to express using getSlice
205− , breakOn
206
197
207− -- ** Cloning arrays
198+ -- *** Appending streams
208− , clone
199+ , unsafeAppendN
209− , pinnedClone
200+ , appendN
201+ , appendWith
202+ , append
210
203
211− -- ** Appending arrays
204+ -- *** Appending arrays
212 , spliceCopy
205 , spliceCopy
213 , spliceWith
206 , spliceWith
214 , splice
207 , splice
215 , spliceExp
208 , spliceExp
216− , spliceUnsafe
209+ , spliceUnsafe -- XXX unsafeSplice
217 -- , putSlice
210 -- , putSlice
218 -- , appendSlice
211 -- , appendSlice
219 -- , appendSliceFrom
212 -- , appendSliceFrom
220
213
214+ -- ** Serialization using Unbox
215+ , pokeAppend
216+ , pokeAppendMay
217+ , pokeSkipUnsafe -- unsafePokeSkip
218+
219+ -- ** Deserialization using Unbox
220+ , peekUncons
221+ , peekUnconsUnsafe -- unsafePeekUncons
222+ , peekSkipUnsafe -- unsafePeekSkip
223+
224+ -- Arrays of arrays
225+ -- We can add dimensionality parameter to the array type to get
226+ -- multidimensional arrays. Multidimensional arrays would just be a
227+ -- convenience wrapper on top of single dimensional arrays.
228+
229+ -- ** Streams of Arrays
230+ -- *** Chunk
231+ -- | Group a stream into arrays.
232+ , chunksOf
233+ , pinnedChunksOf
234+ , buildChunks
235+
236+ -- *** Split
237+ -- | Split an array into slices.
238+
239+ -- , getSlicesFromLenN
240+ , splitOn
241+ -- , slicesOf
242+
243+ -- *** Concat
244+ -- | Append the arrays in a stream to form a stream of elements.
245+ , concatWith
246+ , concatRevWith
247+ , concat
248+ , concatRev
249+
250+ -- *** Compact
251+ -- | Append the arrays in a stream to form a stream of larger arrays.
252+ , SpliceState (..)
253+ , pCompactLE
254+ , pPinnedCompactLE
255+ , compactLeAs
256+ , fCompactGE
257+ , fPinnedCompactGE
258+ , lCompactGE
259+ , lPinnedCompactGE
260+ , compactGE
261+ , compactEQ
262+
221− -- * Utilities
263+ -- ** Utilities
222 , roundUpToPower2
264 , roundUpToPower2
223 , memcpy
265 , memcpy
224 , memcmp
266 , memcmp
225 , c_memchr
267 , 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
226 )
301 )
227where
302where
228
303
@@ -233,49 +308,52 @@ where
233
308
234import Control.Monad (when, void)
309import Control.Monad (when, void)
235import Control.Monad.IO.Class (MonadIO(..))
310import Control.Monad.IO.Class (MonadIO(..))
311+import Data.Bifunctor (first)
236import Data.Bits (shiftR, (.|.), (.&.))
312import Data.Bits (shiftR, (.|.), (.&.))
237import Data.Functor.Identity (Identity(..))
313import Data.Functor.Identity (Identity(..))
238import Data.Proxy (Proxy(..))
314import Data.Proxy (Proxy(..))
239import Data.Word (Word8)
315import Data.Word (Word8)
240import Foreign.C.Types (CSize(..), CInt(..))
316import Foreign.C.Types (CSize(..), CInt(..))
241import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
317import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
242−import Streamly.Internal.Data.Unbox
318+import Streamly.Internal.Data.MutByteArray.Type
243− ( MutableByteArray(..)
319+ ( MutByteArray(..)
244− , Unbox(..)
245 , PinnedState(..)
320 , PinnedState(..)
246 , getMutableByteArray#
321 , getMutableByteArray#
247− , touch
248 , putSliceUnsafe
322 , putSliceUnsafe
249 )
323 )
324+import Streamly.Internal.Data.Unbox (Unbox(..))
250import GHC.Base
325import GHC.Base
251 ( IO(..)
326 ( IO(..)
252 , Int(..)
327 , Int(..)
253− , byteArrayContents#
254 , compareByteArrays#
328 , compareByteArrays#
255 , copyMutableByteArray#
329 , copyMutableByteArray#
256 )
330 )
257import GHC.Base (noinline)
331import GHC.Base (noinline)
258−import GHC.Exts (unsafeCoerce#)
332+import GHC.Exts (unsafeCoerce#, Addr#)
259import GHC.Ptr (Ptr(..))
333import GHC.Ptr (Ptr(..))
260
334
261import Streamly.Internal.Data.Fold.Type (Fold(..))
335import Streamly.Internal.Data.Fold.Type (Fold(..))
262import Streamly.Internal.Data.Producer.Type (Producer (..))
336import Streamly.Internal.Data.Producer.Type (Producer (..))
263import Streamly.Internal.Data.Stream.Type (Stream)
337import Streamly.Internal.Data.Stream.Type (Stream)
338+import Streamly.Internal.Data.Parser.Type (Parser (..))
264import Streamly.Internal.Data.StreamK.Type (StreamK)
339import Streamly.Internal.Data.StreamK.Type (StreamK)
265import Streamly.Internal.Data.SVar.Type (adaptState, defState)
340import Streamly.Internal.Data.SVar.Type (adaptState, defState)
341+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
266import Streamly.Internal.Data.Unfold.Type (Unfold(..))
342import Streamly.Internal.Data.Unfold.Type (Unfold(..))
267import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
343import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
268
344
269import qualified Streamly.Internal.Data.Fold.Type as FL
345import 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
270import qualified Streamly.Internal.Data.Producer as Producer
349import qualified Streamly.Internal.Data.Producer as Producer
271import qualified Streamly.Internal.Data.Stream.Type as D
350import qualified Streamly.Internal.Data.Stream.Type as D
272import qualified Streamly.Internal.Data.Stream.Lift as D
351import qualified Streamly.Internal.Data.Stream.Lift as D
273import qualified Streamly.Internal.Data.StreamK.Type as K
352import qualified Streamly.Internal.Data.StreamK.Type as K
274−import qualified Streamly.Internal.Data.Unbox as Unboxed
275import qualified Prelude
353import qualified Prelude
276
354
277import Prelude hiding
355import Prelude hiding
278− (Foldable(..), read, unlines, splitAt, reverse, truncate)
356+ (Foldable(..), concat, read, unlines, splitAt, reverse, truncate)
279
357
280#include "DocTestDataMutArray.hs"
358#include "DocTestDataMutArray.hs"
281
359
@@ -283,6 +361,7 @@ import Prelude hiding
283-- Foreign helpers
361-- Foreign helpers
284-------------------------------------------------------------------------------
362-------------------------------------------------------------------------------
285
363
364+-- NOTE: Have to be "ccall unsafe" so that we can pass unpinned memory to these
286foreign import ccall unsafe "string.h memcpy" c_memcpy
365foreign import ccall unsafe "string.h memcpy" c_memcpy
287 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
366 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
288
367
@@ -292,6 +371,9 @@ foreign import ccall unsafe "string.h memchr" c_memchr
292foreign import ccall unsafe "string.h memcmp" c_memcmp
371foreign import ccall unsafe "string.h memcmp" c_memcmp
293 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
372 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
294
373
374+foreign import ccall unsafe "string.h strlen" c_strlen
375+ :: Ptr Word8 -> IO CSize
376+
295-- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
377-- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
296-- how many elements of that type will completely fit in those bytes.
378-- how many elements of that type will completely fit in those bytes.
297--
379--
@@ -346,7 +428,7 @@ data MutArray a =
346 -- The array is a range into arrContents. arrContents may be a superset of
428 -- The array is a range into arrContents. arrContents may be a superset of
347 -- the slice represented by the array. All offsets are in bytes.
429 -- the slice represented by the array. All offsets are in bytes.
348 MutArray
430 MutArray
349− { arrContents :: {-# UNPACK #-} !MutableByteArray
431+ { arrContents :: {-# UNPACK #-} !MutByteArray
350 , arrStart :: {-# UNPACK #-} !Int -- ^ index into arrContents
432 , arrStart :: {-# UNPACK #-} !Int -- ^ index into arrContents
351 , arrEnd :: {-# UNPACK #-} !Int -- ^ index into arrContents
433 , arrEnd :: {-# UNPACK #-} !Int -- ^ index into arrContents
352 -- Represents the first invalid index of
434 -- Represents the first invalid index of
@@ -358,8 +440,8 @@ data MutArray a =
358-- Pinning & Unpinning
440-- Pinning & Unpinning
359-------------------------------------------------------------------------------
441-------------------------------------------------------------------------------
360
442
361−-- | Copy the 'MutArray' to pinned memory if unpinned, else do nothing. The
443+-- | Return a copy of the array in pinned memory if unpinned, else return the
362−-- overhead is a copy if the input array is unpinned.
444+-- original array.
363{-# INLINE pin #-}
445{-# INLINE pin #-}
364pin :: MutArray a -> IO (MutArray a)
446pin :: MutArray a -> IO (MutArray a)
365pin arr@MutArray{..} =
447pin arr@MutArray{..} =
@@ -367,8 +449,8 @@ pin arr@MutArray{..} =
367 then pure arr
449 then pure arr
368 else pinnedClone arr
450 else pinnedClone arr
369
451
370−-- | Copy the 'MutArray' to unpinned memory if pinned, else do nothing. The
452+-- | Return a copy of the array in unpinned memory if pinned, else return the
371−-- overhead is a copy if the input array is pinned.
453+-- original array.
372{-# INLINE unpin #-}
454{-# INLINE unpin #-}
373unpin :: MutArray a -> IO (MutArray a)
455unpin :: MutArray a -> IO (MutArray a)
374unpin arr@MutArray{..} =
456unpin arr@MutArray{..} =
@@ -376,6 +458,7 @@ unpin arr@MutArray{..} =
376 then clone arr
458 then clone arr
377 else pure arr
459 else pure arr
378
460
461+-- | Return 'True' if the array is allocated in pinned memory.
379{-# INLINE isPinned #-}
462{-# INLINE isPinned #-}
380isPinned :: MutArray a -> Bool
463isPinned :: MutArray a -> Bool
381isPinned MutArray{..} = Unboxed.isPinned arrContents
464isPinned MutArray{..} = Unboxed.isPinned arrContents
@@ -396,6 +479,8 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
396-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
479-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
397-- allocatePinned in GHC source.
480-- allocatePinned in GHC source.
398
481
482+-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
483+
399-- | @newArrayWith allocator alignment count@ allocates a new array of zero
484-- | @newArrayWith allocator alignment count@ allocates a new array of zero
400-- length and with a capacity to hold @count@ elements, using @allocator
485-- length and with a capacity to hold @count@ elements, using @allocator
401-- size alignment@ as the memory allocator function.
486-- size alignment@ as the memory allocator function.
@@ -408,7 +493,7 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
408-- /Pre-release/
493-- /Pre-release/
409{-# INLINE newArrayWith #-}
494{-# INLINE newArrayWith #-}
410newArrayWith :: forall m a. (MonadIO m, Unbox a)
495newArrayWith :: forall m a. (MonadIO m, Unbox a)
411− => (Int -> Int -> m MutableByteArray) -> Int -> Int -> m (MutArray a)
496+ => (Int -> Int -> m MutByteArray) -> Int -> Int -> m (MutArray a)
412newArrayWith alloc alignSize count = do
497newArrayWith alloc alignSize count = do
413 let size = max (count * SIZE_OF(a)) 0
498 let size = max (count * SIZE_OF(a)) 0
414 contents <- alloc size alignSize
499 contents <- alloc size alignSize
@@ -419,12 +504,25 @@ newArrayWith alloc alignSize count = do
419 , arrBound = size
504 , arrBound = size
420 }
505 }
421
506
507+-- For arrays "nil" sounds a bit odd. empty is better. The only problem with
508+-- empty is that it is also used by the Alternative type class. But assuming we
509+-- will mostly import the Array module qualified this should be fine.
510+
511+-- | Create an empty array.
512+empty ::
513+#ifdef DEVBUILD
514+ Unbox a =>
515+#endif
516+ MutArray a
517+empty = MutArray Unboxed.empty 0 0 0
518+
519+{-# DEPRECATED nil "Please use empty instead." #-}
422nil ::
520nil ::
423#ifdef DEVBUILD
521#ifdef DEVBUILD
424 Unbox a =>
522 Unbox a =>
425#endif
523#endif
426 MutArray a
524 MutArray a
427−nil = MutArray Unboxed.nil 0 0 0
525+nil = empty
428
526
429{-# INLINE newBytesAs #-}
527{-# INLINE newBytesAs #-}
430newBytesAs :: MonadIO m =>
528newBytesAs :: MonadIO m =>
@@ -441,12 +539,13 @@ newBytesAs ps bytes = do
441 , arrBound = bytes
539 , arrBound = bytes
442 }
540 }
443
541
444−-- | Allocates a pinned empty array that can hold 'count' items. The memory of
542+-- | Allocates a pinned empty array that with a reserved capacity of bytes.
445−-- the array is uninitialized and the allocation is aligned as per the
543+-- The memory of the array is uninitialized and the allocation is aligned as
446−-- 'Unboxed' instance of the type.
544+-- per the 'Unboxed' instance of the type.
447--
545--
448-- /Pre-release/
546-- /Pre-release/
449{-# INLINE pinnedNewBytes #-}
547{-# INLINE pinnedNewBytes #-}
548+{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
450pinnedNewBytes :: MonadIO m =>
549pinnedNewBytes :: MonadIO m =>
451#ifdef DEVBUILD
550#ifdef DEVBUILD
452 Unbox a =>
551 Unbox a =>
@@ -471,21 +570,31 @@ newAs ps =
471 (error "new: alignment is not used in unpinned arrays.")
570 (error "new: alignment is not used in unpinned arrays.")
472
571
473-- XXX can unaligned allocation be more efficient when alignment is not needed?
572-- XXX can unaligned allocation be more efficient when alignment is not needed?
474−--
573+
475−-- | Allocates an empty pinned array that can hold 'count' items. The memory of
574+-- | Allocates a pinned array of zero length but growable to the specified
476−-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
575+-- capacity without reallocation.
477−-- instance of the type.
576+{-# INLINE pinnedEmptyOf #-}
478−--
577+pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
578+pinnedEmptyOf = newAs Pinned
579+
580+-- XXX Deprecate in major
581+-- {-# DEPRECATED pinnedNew "Please use pinnedEmptyOf instead." #-}
479{-# INLINE pinnedNew #-}
582{-# INLINE pinnedNew #-}
480pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
583pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
481−pinnedNew = newAs Pinned
584+pinnedNew = pinnedEmptyOf
482
585
483−-- | Allocates an empty unpinned array that can hold 'count' items. The memory
586+-- | Allocates an unpinned array of zero length but growable to the specified
484−-- of the array is uninitialized.
587+-- capacity without reallocation.
485--
588--
589+{-# INLINE emptyOf #-}
590+emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
591+emptyOf = newAs Unpinned
592+
593+-- XXX Deprecate in major
594+-- {-# DEPRECATED new "Please use emptyOf instead." #-}
486{-# INLINE new #-}
595{-# INLINE new #-}
487new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
596new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
488−new = newAs Unpinned
597+new = emptyOf
489
598
490-------------------------------------------------------------------------------
599-------------------------------------------------------------------------------
491-- Random writes
600-- Random writes
@@ -501,7 +610,7 @@ putIndexUnsafe :: forall m a. (MonadIO m, Unbox a)
501putIndexUnsafe i MutArray{..} x = do
610putIndexUnsafe i MutArray{..} x = do
502 let index = INDEX_OF(arrStart, i, a)
611 let index = INDEX_OF(arrStart, i, a)
503 assert (i >= 0 && INDEX_VALID(index, arrEnd, a)) (return ())
612 assert (i >= 0 && INDEX_VALID(index, arrEnd, a)) (return ())
504− liftIO $ pokeByteIndex index arrContents x
613+ liftIO $ pokeAt index arrContents x
505
614
506invalidIndex :: String -> Int -> a
615invalidIndex :: String -> Int -> a
507invalidIndex label i =
616invalidIndex label i =
@@ -519,7 +628,7 @@ putIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m ()
519putIndex i MutArray{..} x = do
628putIndex i MutArray{..} x = do
520 let index = INDEX_OF(arrStart,i,a)
629 let index = INDEX_OF(arrStart,i,a)
521 if i >= 0 && INDEX_VALID(index,arrEnd,a)
630 if i >= 0 && INDEX_VALID(index,arrEnd,a)
522− then liftIO $ pokeByteIndex index arrContents x
631+ then liftIO $ pokeAt index arrContents x
523 else invalidIndex "putIndex" i
632 else invalidIndex "putIndex" i
524
633
525-- | Write an input stream of (index, value) pairs to an array. Throws an
634-- | Write an input stream of (index, value) pairs to an array. Throws an
@@ -533,7 +642,7 @@ putIndices arr = FL.foldlM' step (return ())
533
642
534 where
643 where
535
644
536− step () (i, x) = liftIO (putIndex i arr x)
645+ step () (i, x) = putIndex i arr x
537
646
538-- | Modify a given index of an array using a modifier function.
647-- | Modify a given index of an array using a modifier function.
539--
648--
@@ -545,9 +654,9 @@ modifyIndexUnsafe :: forall m a b. (MonadIO m, Unbox a) =>
545modifyIndexUnsafe i MutArray{..} f = liftIO $ do
654modifyIndexUnsafe i MutArray{..} f = liftIO $ do
546 let index = INDEX_OF(arrStart,i,a)
655 let index = INDEX_OF(arrStart,i,a)
547 assert (i >= 0 && INDEX_NEXT(index,a) <= arrEnd) (return ())
656 assert (i >= 0 && INDEX_NEXT(index,a) <= arrEnd) (return ())
548− r <- peekByteIndex index arrContents
657+ r <- peekAt index arrContents
549 let (x, res) = f r
658 let (x, res) = f r
550− pokeByteIndex index arrContents x
659+ pokeAt index arrContents x
551 return res
660 return res
552
661
553-- | Modify a given index of an array using a modifier function.
662-- | Modify a given index of an array using a modifier function.
@@ -559,9 +668,9 @@ modifyIndex i MutArray{..} f = do
559 let index = INDEX_OF(arrStart,i,a)
668 let index = INDEX_OF(arrStart,i,a)
560 if i >= 0 && INDEX_VALID(index,arrEnd,a)
669 if i >= 0 && INDEX_VALID(index,arrEnd,a)
561 then liftIO $ do
670 then liftIO $ do
562− r <- peekByteIndex index arrContents
671+ r <- peekAt index arrContents
563 let (x, res) = f r
672 let (x, res) = f r
564− pokeByteIndex index arrContents x
673+ pokeAt index arrContents x
565 return res
674 return res
566 else invalidIndex "modifyIndex" i
675 else invalidIndex "modifyIndex" i
567
676
@@ -595,8 +704,8 @@ modify MutArray{..} f = liftIO $
595
704
596 go i =
705 go i =
597 when (INDEX_VALID(i,arrEnd,a)) $ do
706 when (INDEX_VALID(i,arrEnd,a)) $ do
598− r <- peekByteIndex i arrContents
707+ r <- peekAt i arrContents
599− pokeByteIndex i arrContents (f r)
708+ pokeAt i arrContents (f r)
600 go (INDEX_NEXT(i,a))
709 go (INDEX_NEXT(i,a))
601
710
602-- XXX We could specify the number of bytes to swap instead of Proxy. Need
711-- XXX We could specify the number of bytes to swap instead of Proxy. Need
@@ -605,15 +714,15 @@ modify MutArray{..} f = liftIO $
605swapArrayByteIndices ::
714swapArrayByteIndices ::
606 forall a. Unbox a
715 forall a. Unbox a
607 => Proxy a
716 => Proxy a
608− -> MutableByteArray
717+ -> MutByteArray
609 -> Int
718 -> Int
610 -> Int
719 -> Int
611 -> IO ()
720 -> IO ()
612swapArrayByteIndices _ arrContents i1 i2 = do
721swapArrayByteIndices _ arrContents i1 i2 = do
613− r1 <- peekByteIndex i1 arrContents
722+ r1 <- peekAt i1 arrContents
614− r2 <- peekByteIndex i2 arrContents
723+ r2 <- peekAt i2 arrContents
615− pokeByteIndex i1 arrContents (r2 :: a)
724+ pokeAt i1 arrContents (r2 :: a)
616− pokeByteIndex i2 arrContents (r1 :: a)
725+ pokeAt i2 arrContents (r1 :: a)
617
726
618-- | Swap the elements at two indices without validating the indices.
727-- | Swap the elements at two indices without validating the indices.
619--
728--
@@ -729,26 +838,23 @@ arrayChunkBytes = 1024
729roundDownTo :: Int -> Int -> Int
838roundDownTo :: Int -> Int -> Int
730roundDownTo elemSize size = size - (size `mod` elemSize)
839roundDownTo elemSize size = size - (size `mod` elemSize)
731
840
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−--
735-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
841-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
736-- Since this is not inlined Unboxed consrraint leads to dictionary passing
842-- Since this is not inlined Unboxed consrraint leads to dictionary passing
737-- which complicates some inspection tests.
843-- which complicates some inspection tests.
738--
844--
739−{-# NOINLINE reallocExplicit #-}
845+{-# NOINLINE reallocExplicitAs #-}
740−reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
846+reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
741−reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
847+reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
742 assertM(arrEnd <= arrBound)
848 assertM(arrEnd <= arrBound)
743
849
744 -- Allocate new array
850 -- Allocate new array
745 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
851 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
746 contents <-
852 contents <-
747− if Unboxed.isPinned arrContents
853+ if ps == Pinned
748− then Unboxed.pinnedNewBytes newCapMaxInBytes
854+ then Unboxed.pinnedNew newCapMaxInBytes
749− else Unboxed.newBytes newCapMaxInBytes
855+ else Unboxed.new newCapMaxInBytes
750− let !(MutableByteArray mbarrFrom#) = arrContents
856+ let !(MutByteArray mbarrFrom#) = arrContents
751− !(MutableByteArray mbarrTo#) = contents
857+ !(MutByteArray mbarrTo#) = contents
752
858
753 -- Copy old data
859 -- Copy old data
754 let oldStart = arrStart
860 let oldStart = arrStart
@@ -769,6 +875,10 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
769 , arrBound = newCapInBytes
875 , arrBound = newCapInBytes
770 }
876 }
771
877
878+-- XXX Should these be called reallocBytes etc?
879+-- XXX We may also need reallocAs to allocate as pinned/unpinned explicitly. In
880+-- fact clone/pinnedClone can be implemented using reallocAs.
881+
772-- | @realloc newCapacity array@ reallocates the array to the specified
882-- | @realloc newCapacity array@ reallocates the array to the specified
773-- capacity in bytes.
883-- capacity in bytes.
774--
884--
@@ -780,7 +890,12 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
780-- If the original array is pinned, the newly allocated array is also pinned.
890-- If the original array is pinned, the newly allocated array is also pinned.
781{-# INLINABLE realloc #-}
891{-# INLINABLE realloc #-}
782realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
892realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
893+realloc bytes arr =
894+ let ps =
895+ if isPinned arr
896+ then Pinned
897+ else Unpinned
783−realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
898+ in liftIO $ reallocExplicitAs ps (SIZE_OF(a)) bytes arr
784
899
785-- | @reallocWith label capSizer minIncrBytes array@. The label is used
900-- | @reallocWith label capSizer minIncrBytes array@. The label is used
786-- in error messages and the capSizer is used to determine the capacity of the
901-- in error messages and the capSizer is used to determine the capacity of the
@@ -803,14 +918,14 @@ reallocWith label capSizer minIncrBytes arr = do
803 where
918 where
804
919
805 badSize newSize =
920 badSize newSize =
806− concat
921+ Prelude.concat
807 [ label
922 [ label
808 , ": new array size (in bytes) is less than required size "
923 , ": new array size (in bytes) is less than required size "
809 , show newSize
924 , show newSize
810 , ". Please check the sizing function passed."
925 , ". Please check the sizing function passed."
811 ]
926 ]
812
927
813−-- | @resize newCapacity array@ changes the total capacity of the array so that
928+-- | @grow newCapacity array@ changes the total capacity of the array so that
814-- it is enough to hold the specified number of elements. Nothing is done if
929-- it is enough to hold the specified number of elements. Nothing is done if
815-- the specified capacity is less than the length of the array.
930-- the specified capacity is less than the length of the array.
816--
931--
@@ -818,34 +933,46 @@ reallocWith label capSizer minIncrBytes arr = do
818-- the block size (4K).
933-- the block size (4K).
819--
934--
820-- /Pre-release/
935-- /Pre-release/
821−{-# INLINE resize #-}
936+{-# INLINE grow #-}
822−resize :: forall m a. (MonadIO m, Unbox a) =>
937+grow :: forall m a. (MonadIO m, Unbox a) =>
823 Int -> MutArray a -> m (MutArray a)
938 Int -> MutArray a -> m (MutArray a)
824−resize nElems arr@MutArray{..} = do
939+grow nElems arr@MutArray{..} = do
825 let req = SIZE_OF(a) * nElems
940 let req = SIZE_OF(a) * nElems
826− len = arrEnd - arrStart
941+ cap = arrBound - arrStart
827− if req < len
942+ if req < cap
828 then return arr
943 then return arr
829 else realloc req arr
944 else realloc req arr
830
945
946+{-# DEPRECATED resize "Please use grow instead." #-}
947+{-# INLINE resize #-}
948+resize :: forall m a. (MonadIO m, Unbox a) =>
949+ Int -> MutArray a -> m (MutArray a)
950+resize = grow
951+
831−-- | Like 'resize' but if the byte capacity is more than 'largeObjectThreshold'
952+-- | Like 'grow' but if the requested byte capacity is more than
832−-- then it is rounded up to the closest power of 2.
953+-- 'largeObjectThreshold' then it is rounded up to the closest power of 2.
833--
954--
834-- /Pre-release/
955-- /Pre-release/
835−{-# INLINE resizeExp #-}
956+{-# INLINE growExp #-}
836−resizeExp :: forall m a. (MonadIO m, Unbox a) =>
957+growExp :: forall m a. (MonadIO m, Unbox a) =>
837 Int -> MutArray a -> m (MutArray a)
958 Int -> MutArray a -> m (MutArray a)
838−resizeExp nElems arr@MutArray{..} = do
959+growExp nElems arr@MutArray{..} = do
839 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
960 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
840 req1 =
961 req1 =
841 if req > largeObjectThreshold
962 if req > largeObjectThreshold
842 then roundUpToPower2 req
963 then roundUpToPower2 req
843 else req
964 else req
844− len = arrEnd - arrStart
965+ cap = arrBound - arrStart
845− if req1 < len
966+ if req1 < cap
846 then return arr
967 then return arr
847 else realloc req1 arr
968 else realloc req1 arr
848
969
970+{-# DEPRECATED resizeExp "Please use growExp instead." #-}
971+{-# INLINE resizeExp #-}
972+resizeExp :: forall m a. (MonadIO m, Unbox a) =>
973+ Int -> MutArray a -> m (MutArray a)
974+resizeExp = growExp
975+
849-- | Resize the allocated memory to drop any reserved free space at the end of
976-- | Resize the allocated memory to drop any reserved free space at the end of
850-- the array and reallocate it to reduce wastage.
977-- the array and reallocate it to reduce wastage.
851--
978--
@@ -890,7 +1017,7 @@ rightSize arr@MutArray{..} = do
890snocNewEnd :: (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m (MutArray a)
1017snocNewEnd :: (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m (MutArray a)
891snocNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1018snocNewEnd newEnd arr@MutArray{..} x = liftIO $ do
892 assert (newEnd <= arrBound) (return ())
1019 assert (newEnd <= arrBound) (return ())
893− pokeByteIndex arrEnd arrContents x
1020+ pokeAt arrEnd arrContents x
894 return $ arr {arrEnd = newEnd}
1021 return $ arr {arrEnd = newEnd}
895
1022
896-- | Really really unsafe, appends the element into the first array, may
1023-- | Really really unsafe, appends the element into the first array, may
@@ -910,7 +1037,7 @@ snocUnsafe arr@MutArray{..} = snocNewEnd (INDEX_NEXT(arrEnd,a)) arr
910{-# INLINE snocMay #-}
1037{-# INLINE snocMay #-}
911snocMay :: forall m a. (MonadIO m, Unbox a) =>
1038snocMay :: forall m a. (MonadIO m, Unbox a) =>
912 MutArray a -> a -> m (Maybe (MutArray a))
1039 MutArray a -> a -> m (Maybe (MutArray a))
913−snocMay arr@MutArray{..} x = liftIO $ do
1040+snocMay arr@MutArray{..} x = do
914 let newEnd = INDEX_NEXT(arrEnd,a)
1041 let newEnd = INDEX_NEXT(arrEnd,a)
915 if newEnd <= arrBound
1042 if newEnd <= arrBound
916 then Just <$> snocNewEnd newEnd arr x
1043 then Just <$> snocNewEnd newEnd arr x
@@ -924,7 +1051,7 @@ snocWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
924 -> a
1051 -> a
925 -> m (MutArray a)
1052 -> m (MutArray a)
926snocWithRealloc sizer arr x = do
1053snocWithRealloc sizer arr x = do
927− arr1 <- liftIO $ reallocWith "snocWith" sizer (SIZE_OF(a)) arr
1054+ arr1 <- reallocWith "snocWith" sizer (SIZE_OF(a)) arr
928 snocUnsafe arr1 x
1055 snocUnsafe arr1 x
929
1056
930-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
1057-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
@@ -946,7 +1073,7 @@ snocWith :: forall m a. (MonadIO m, Unbox a) =>
946 -> MutArray a
1073 -> MutArray a
947 -> a
1074 -> a
948 -> m (MutArray a)
1075 -> m (MutArray a)
949−snocWith allocSize arr x = liftIO $ do
1076+snocWith allocSize arr x = do
950 let newEnd = INDEX_NEXT(arrEnd arr,a)
1077 let newEnd = INDEX_NEXT(arrEnd arr,a)
951 if newEnd <= arrBound arr
1078 if newEnd <= arrBound arr
952 then snocNewEnd newEnd arr x
1079 then snocNewEnd newEnd arr x
@@ -990,6 +1117,126 @@ snoc = snocWith f
990 then oldSize * 2
1117 then oldSize * 2
991 else roundUpToPower2 oldSize * 2
1118 else roundUpToPower2 oldSize * 2
992
1119
1120+-------------------------------------------------------------------------------
1121+-- Serialization/Deserialization
1122+-------------------------------------------------------------------------------
1123+
1124+{-# INLINE pokeNewEnd #-}
1125+pokeNewEnd :: (MonadIO m, Unbox a) =>
1126+ Int -> MutArray Word8 -> a -> m (MutArray Word8)
1127+pokeNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1128+ assert (newEnd <= arrBound) (return ())
1129+ liftIO $ pokeAt arrEnd arrContents x
1130+ return $ arr {arrEnd = newEnd}
1131+
1132+-- | Really really unsafe, unboxes a Haskell type and appends the resulting
1133+-- bytes to the byte array, may cause silent data corruption or if you are
1134+-- lucky a segfault if the array does not have enough space to append the
1135+-- element.
1136+--
1137+-- /Internal/
1138+{-# INLINE pokeAppendUnsafe #-}
1139+pokeAppendUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1140+ MutArray Word8 -> a -> m (MutArray Word8)
1141+pokeAppendUnsafe arr@MutArray{..} = pokeNewEnd (arrEnd + SIZE_OF(a)) arr
1142+
1143+-- | Skip the specified number of bytes in the array. The data in the skipped
1144+-- region remains uninitialzed.
1145+{-# INLINE pokeSkipUnsafe #-}
1146+pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1147+pokeSkipUnsafe n arr@MutArray{..} = do
1148+ let newEnd = arrEnd + n
1149+ in assert (newEnd <= arrBound) (arr {arrEnd = newEnd})
1150+
1151+-- | Like 'pokeAppend' but does not grow the array when pre-allocated array
1152+-- capacity becomes full.
1153+--
1154+-- /Internal/
1155+{-# INLINE pokeAppendMay #-}
1156+pokeAppendMay :: forall m a. (MonadIO m, Unbox a) =>
1157+ MutArray Word8 -> a -> m (Maybe (MutArray Word8))
1158+pokeAppendMay arr@MutArray{..} x = liftIO $ do
1159+ let newEnd = arrEnd + SIZE_OF(a)
1160+ if newEnd <= arrBound
1161+ then Just <$> pokeNewEnd newEnd arr x
1162+ else return Nothing
1163+
1164+{-# NOINLINE pokeWithRealloc #-}
1165+pokeWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1166+ (Int -> Int)
1167+ -> MutArray Word8
1168+ -> a
1169+ -> m (MutArray Word8)
1170+pokeWithRealloc sizer arr x = do
1171+ arr1 <- liftIO $ reallocWith "pokeWithRealloc" sizer (SIZE_OF(a)) arr
1172+ pokeAppendUnsafe arr1 x
1173+
1174+{-# INLINE pokeAppendWith #-}
1175+pokeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1176+ (Int -> Int)
1177+ -> MutArray Word8
1178+ -> a
1179+ -> m (MutArray Word8)
1180+pokeAppendWith allocSize arr x = liftIO $ do
1181+ let newEnd = arrEnd arr + SIZE_OF(a)
1182+ if newEnd <= arrBound arr
1183+ then pokeNewEnd newEnd arr x
1184+ else pokeWithRealloc allocSize arr x
1185+
1186+-- | Unbox a Haskell type and append the resulting bytes to a mutable byte
1187+-- array. The array is grown exponentially when more space is needed.
1188+--
1189+-- Definition:
1190+--
1191+-- >>> pokeAppend arr x = MutArray.castUnsafe <$> MutArray.snoc (MutArray.castUnsafe arr) x
1192+--
1193+{-# INLINE pokeAppend #-}
1194+pokeAppend :: forall m a. (MonadIO m, Unbox a) =>
1195+ MutArray Word8 -> a -> m (MutArray Word8)
1196+pokeAppend = pokeAppendWith f
1197+
1198+ where
1199+
1200+ f oldSize =
1201+ if isPower2 oldSize
1202+ then oldSize * 2
1203+ else roundUpToPower2 oldSize * 2
1204+
1205+-- | Really really unsafe, create a Haskell value from an unboxed byte array,
1206+-- does not check if the array is big enough, may return garbage or if you are
1207+-- lucky may cause a segfault.
1208+--
1209+-- /Internal/
1210+{-# INLINE peekUnconsUnsafe #-}
1211+peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1212+ MutArray Word8 -> m (a, MutArray Word8)
1213+peekUnconsUnsafe MutArray{..} = do
1214+ let start1 = arrStart + SIZE_OF(a)
1215+ assert (start1 <= arrEnd) (return ())
1216+ liftIO $ do
1217+ r <- peekAt arrStart arrContents
1218+ return (r, MutArray arrContents start1 arrEnd arrBound)
1219+
1220+-- | Discard the specified number of bytes in the array.
1221+{-# INLINE peekSkipUnsafe #-}
1222+peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1223+peekSkipUnsafe n MutArray{..} =
1224+ let start1 = arrStart + n
1225+ in assert (start1 <= arrEnd) (MutArray arrContents start1 arrEnd arrBound)
1226+
1227+-- | Create a Haskell value from its unboxed representation from the head of a
1228+-- byte array, return the value and the remaining array.
1229+{-# INLINE peekUncons #-}
1230+peekUncons :: forall m a. (MonadIO m, Unbox a) =>
1231+ MutArray Word8 -> m (Maybe a, MutArray Word8)
1232+peekUncons arr@MutArray{..} = do
1233+ let start1 = arrStart + SIZE_OF(a)
1234+ if start1 > arrEnd
1235+ then return (Nothing, arr)
1236+ else liftIO $ do
1237+ r <- peekAt arrStart arrContents
1238+ return (Just r, MutArray arrContents start1 arrEnd arrBound)
1239+
993-------------------------------------------------------------------------------
1240-------------------------------------------------------------------------------
994-- Random reads
1241-- Random reads
995-------------------------------------------------------------------------------
1242-------------------------------------------------------------------------------
@@ -1004,7 +1251,7 @@ getIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1004getIndexUnsafe i MutArray{..} = do
1251getIndexUnsafe i MutArray{..} = do
1005 let index = INDEX_OF(arrStart,i,a)
1252 let index = INDEX_OF(arrStart,i,a)
1006 assert (i >= 0 && INDEX_VALID(index,arrEnd,a)) (return ())
1253 assert (i >= 0 && INDEX_VALID(index,arrEnd,a)) (return ())
1007− liftIO $ peekByteIndex index arrContents
1254+ liftIO $ peekAt index arrContents
1008
1255
1009-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
1256-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
1010--
1257--
@@ -1013,7 +1260,7 @@ getIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (Maybe a)
1013getIndex i MutArray{..} = do
1260getIndex i MutArray{..} = do
1014 let index = INDEX_OF(arrStart,i,a)
1261 let index = INDEX_OF(arrStart,i,a)
1015 if i >= 0 && INDEX_VALID(index,arrEnd,a)
1262 if i >= 0 && INDEX_VALID(index,arrEnd,a)
1016− then liftIO $ Just <$> peekByteIndex index arrContents
1263+ then liftIO $ Just <$> peekAt index arrContents
1017 else return Nothing
1264 else return Nothing
1018
1265
1019-- | /O(1)/ Lookup the element at the given index from the end of the array.
1266-- | /O(1)/ Lookup the element at the given index from the end of the array.
@@ -1026,21 +1273,16 @@ getIndexRev :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1026getIndexRev i MutArray{..} = do
1273getIndexRev i MutArray{..} = do
1027 let index = RINDEX_OF(arrEnd,i,a)
1274 let index = RINDEX_OF(arrEnd,i,a)
1028 if i >= 0 && index >= arrStart
1275 if i >= 0 && index >= arrStart
1029− then liftIO $ peekByteIndex index arrContents
1276+ then liftIO $ peekAt index arrContents
1030 else invalidIndex "getIndexRev" i
1277 else invalidIndex "getIndexRev" i
1031
1278
1032data GetIndicesState contents start end st =
1279data GetIndicesState contents start end st =
1033 GetIndicesState contents start end st
1280 GetIndicesState contents start end st
1034
1281
1035−-- | Given an unfold that generates array indices, read the elements on those
1282+{-# INLINE indexReaderWith #-}
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 #-}
1041−getIndicesD :: (Monad m, Unbox a) =>
1283+indexReaderWith :: (Monad m, Unbox a) =>
1042 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1284 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1043−getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
1285+indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
1044
1286
1045 where
1287 where
1046
1288
@@ -1059,9 +1301,26 @@ getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
1059 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1301 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1060 D.Stop -> return D.Stop
1302 D.Stop -> return D.Stop
1061
1303
1304+{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1305+{-# INLINE getIndicesWith #-}
1306+getIndicesWith :: (Monad m, Unbox a) =>
1307+ (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1308+getIndicesWith = indexReaderWith
1309+
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." #-}
1062{-# INLINE getIndices #-}
1321{-# INLINE getIndices #-}
1063getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1322getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1064−getIndices = getIndicesD liftIO
1323+getIndices = indexReader
1065
1324
1066-------------------------------------------------------------------------------
1325-------------------------------------------------------------------------------
1067-- Subarrays
1326-- Subarrays
@@ -1166,7 +1425,7 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1166
1425
1167 -- Invariant low < high on entry, and on return as well
1426 -- Invariant low < high on entry, and on return as well
1168 moveHigh low high = do
1427 moveHigh low high = do
1169− h <- peekByteIndex high arrContents
1428+ h <- peekAt high arrContents
1170 if f h
1429 if f h
1171 then
1430 then
1172 -- Correctly classified, continue the loop
1431 -- Correctly classified, continue the loop
@@ -1186,7 +1445,7 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1186 -- low <= high
1445 -- low <= high
1187 -- Both low and high are valid locations within the array
1446 -- Both low and high are valid locations within the array
1188 go low high = do
1447 go low high = do
1189− l <- peekByteIndex low arrContents
1448+ l <- peekAt low arrContents
1190 if f l
1449 if f l
1191 then
1450 then
1192 -- low is wrongly classified
1451 -- low is wrongly classified
@@ -1197,8 +1456,8 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1197 case r of
1456 case r of
1198 Nothing -> return low
1457 Nothing -> return low
1199 Just (high1, h) -> do -- low < high1
1458 Just (high1, h) -> do -- low < high1
1200− pokeByteIndex low arrContents h
1459+ pokeAt low arrContents h
1201− pokeByteIndex high1 arrContents l
1460+ pokeAt high1 arrContents l
1202 let low1 = INDEX_NEXT(low,a)
1461 let low1 = INDEX_NEXT(low,a)
1203 high2 = INDEX_PREV(high1,a)
1462 high2 = INDEX_PREV(high1,a)
1204 if low1 <= high2
1463 if low1 <= high2
@@ -1332,7 +1591,7 @@ chunksOfAs ps n (D.Stream step state) =
1332 r <- step (adaptState gst) st
1591 r <- step (adaptState gst) st
1333 case r of
1592 case r of
1334 D.Yield x s -> do
1593 D.Yield x s -> do
1335− liftIO $ pokeByteIndex end contents x
1594+ liftIO $ pokeAt end contents x
1336 let end1 = INDEX_NEXT(end,a)
1595 let end1 = INDEX_NEXT(end,a)
1337 return $
1596 return $
1338 if end1 >= bound
1597 if end1 >= bound
@@ -1351,10 +1610,12 @@ chunksOfAs ps n (D.Stream step state) =
1351
1610
1352 step' _ GroupFinish = return D.Stop
1611 step' _ GroupFinish = return D.Stop
1353
1612
1354−-- | @chunksOf n stream@ groups the input stream into a stream of
1613+-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
1355−-- arrays of size n.
1614+-- @n@ elements each.
1615+--
1616+-- Same as the following but may be more efficient:
1356--
1617--
1357−-- @chunksOf n = StreamD.foldMany (MutArray.writeN n)@
1618+-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1358--
1619--
1359-- /Pre-release/
1620-- /Pre-release/
1360{-# INLINE_NORMAL chunksOf #-}
1621{-# INLINE_NORMAL chunksOf #-}
@@ -1363,17 +1624,29 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
1363-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1624-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1364-- benchmark. It seems it has difficulty producing optimized code when
1625-- benchmark. It seems it has difficulty producing optimized code when
1365-- converting to StreamK. Investigate GHC optimizations.
1626-- converting to StreamK. Investigate GHC optimizations.
1366−-- chunksOf n = D.foldMany (writeN n)
1627+-- chunksOf n = D.foldMany (createOf n)
1367chunksOf = chunksOfAs Unpinned
1628chunksOf = chunksOfAs Unpinned
1368
1629
1369-- | Like 'chunksOf' but creates pinned arrays.
1630-- | Like 'chunksOf' but creates pinned arrays.
1370{-# INLINE_NORMAL pinnedChunksOf #-}
1631{-# INLINE_NORMAL pinnedChunksOf #-}
1371pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1632pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1372 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1633 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1373−-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
1634+-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1374pinnedChunksOf = chunksOfAs Pinned
1635pinnedChunksOf = chunksOfAs Pinned
1375
1636
1376−-- XXX This should take a PinnedState
1637+-- | When we are buffering a stream of unknown size into an array we do not
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+
1377-- XXX buffer to a list instead?
1650-- XXX buffer to a list instead?
1378-- | Buffer the stream into arrays in memory.
1651-- | Buffer the stream into arrays in memory.
1379{-# INLINE arrayStreamKFromStreamDAs #-}
1652{-# INLINE arrayStreamKFromStreamDAs #-}
@@ -1391,16 +1664,10 @@ data FlattenState s contents a =
1391 OuterLoop s
1664 OuterLoop s
1392 | InnerLoop s contents !Int !Int
1665 | InnerLoop s contents !Int !Int
1393
1666
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−--
1400−{-# INLINE_NORMAL flattenArrays #-}
1667+{-# INLINE_NORMAL concatWith #-}
1401−flattenArrays :: forall m a. (MonadIO m, Unbox a)
1668+concatWith :: forall m a. (Monad m, Unbox a)
1402− => D.Stream m (MutArray a) -> D.Stream m a
1669+ => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1403−flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
1670+concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1404
1671
1405 where
1672 where
1406
1673
@@ -1417,19 +1684,30 @@ flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
1417 return $ D.Skip $ OuterLoop st
1684 return $ D.Skip $ OuterLoop st
1418
1685
1419 step' _ (InnerLoop st contents p end) = do
1686 step' _ (InnerLoop st contents p end) = do
1420− x <- liftIO $ peekByteIndex p contents
1687+ x <- liftio $ peekAt p contents
1421 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1688 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1422
1689
1423−-- | Use the "readerRev" unfold instead.
1690+-- | Use the "reader" unfold instead.
1424--
1691--
1425−-- @flattenArrays = unfoldMany readerRev@
1692+-- @concat = unfoldMany reader@
1426--
1693--
1427-- We can try this if there are any fusion issues in the unfold.
1694-- We can try this if there are any fusion issues in the unfold.
1428--
1695--
1429−{-# INLINE_NORMAL flattenArraysRev #-}
1696+{-# INLINE_NORMAL concat #-}
1430−flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1697+concat :: forall m a. (MonadIO m, Unbox a)
1431 => D.Stream m (MutArray a) -> D.Stream m 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)
1704+ => D.Stream m (MutArray a) -> D.Stream m a
1705+flattenArrays = concat
1706+
1707+{-# INLINE_NORMAL concatRevWith #-}
1708+concatRevWith :: forall m a. (Monad m, Unbox a)
1709+ => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1432−flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1710+concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1433
1711
1434 where
1712 where
1435
1713
@@ -1447,16 +1725,33 @@ flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1447 return $ D.Skip $ OuterLoop st
1725 return $ D.Skip $ OuterLoop st
1448
1726
1449 step' _ (InnerLoop st contents p start) = do
1727 step' _ (InnerLoop st contents p start) = do
1450− x <- liftIO $ peekByteIndex p contents
1728+ x <- liftio $ peekAt p contents
1451 let cur = INDEX_PREV(p,a)
1729 let cur = INDEX_PREV(p,a)
1452 return $ D.Yield x (InnerLoop st contents cur start)
1730 return $ D.Yield x (InnerLoop st contents cur start)
1453
1731
1732+-- | Use the "readerRev" unfold instead.
1733+--
1734+-- @concat = unfoldMany readerRev@
1735+--
1736+-- We can try this if there are any fusion issues in the unfold.
1737+--
1738+{-# INLINE_NORMAL concatRev #-}
1739+concatRev :: forall m a. (MonadIO m, Unbox a)
1740+ => D.Stream m (MutArray a) -> D.Stream m a
1741+concatRev = concatRevWith liftIO
1742+
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+
1454-------------------------------------------------------------------------------
1749-------------------------------------------------------------------------------
1455-- Unfolds
1750-- Unfolds
1456-------------------------------------------------------------------------------
1751-------------------------------------------------------------------------------
1457
1752
1458data ArrayUnsafe a = ArrayUnsafe
1753data ArrayUnsafe a = ArrayUnsafe
1459− {-# UNPACK #-} !MutableByteArray -- contents
1754+ {-# UNPACK #-} !MutByteArray -- contents
1460 {-# UNPACK #-} !Int -- index 1
1755 {-# UNPACK #-} !Int -- index 1
1461 {-# UNPACK #-} !Int -- index 2
1756 {-# UNPACK #-} !Int -- index 2
1462
1757
@@ -1486,7 +1781,7 @@ producerWith liftio = Producer step (return . toArrayUnsafe) extract
1486 -- few actions for correctness and execution order sanity. We want
1781 -- few actions for correctness and execution order sanity. We want
1487 -- the peek to occur right here and not lazily at some later point
1782 -- the peek to occur right here and not lazily at some later point
1488 -- because we want the peek to be ordered with respect to the touch.
1783 -- because we want the peek to be ordered with respect to the touch.
1489− !x <- liftio $ peekByteIndex cur contents
1784+ !x <- liftio $ peekAt cur contents
1490 return $ D.Yield x (ArrayUnsafe contents (INDEX_NEXT(cur,a)) end)
1785 return $ D.Yield x (ArrayUnsafe contents (INDEX_NEXT(cur,a)) end)
1491
1786
1492 extract = return . fromArrayUnsafe
1787 extract = return . fromArrayUnsafe
@@ -1517,7 +1812,7 @@ readerRevWith liftio = Unfold step inject
1517 {-# INLINE_LATE step #-}
1812 {-# INLINE_LATE step #-}
1518 step (ArrayUnsafe _ start p) | p < start = return D.Stop
1813 step (ArrayUnsafe _ start p) | p < start = return D.Stop
1519 step (ArrayUnsafe contents start p) = do
1814 step (ArrayUnsafe contents start p) = do
1520− !x <- liftio $ peekByteIndex p contents
1815+ !x <- liftio $ peekAt p contents
1521 return $ D.Yield x (ArrayUnsafe contents start (INDEX_PREV(p,a)))
1816 return $ D.Yield x (ArrayUnsafe contents start (INDEX_PREV(p,a)))
1522
1817
1523-- | Unfold an array into a stream in reverse order.
1818-- | Unfold an array into a stream in reverse order.
@@ -1548,7 +1843,7 @@ toListFB c n MutArray{..} = go arrStart
1548 -- evaluated/written to before we peek at them.
1843 -- evaluated/written to before we peek at them.
1549 -- XXX
1844 -- XXX
1550 let !x = unsafeInlineIO $ do
1845 let !x = unsafeInlineIO $ do
1551− r <- peekByteIndex arrContents p
1846+ r <- peekAt arrContents p
1552 return r
1847 return r
1553 in c x (go (PTR_NEXT(p,a)))
1848 in c x (go (PTR_NEXT(p,a)))
1554-}
1849-}
@@ -1565,21 +1860,21 @@ toList MutArray{..} = liftIO $ go arrStart
1565
1860
1566 go p | assert (p <= arrEnd) (p == arrEnd) = return []
1861 go p | assert (p <= arrEnd) (p == arrEnd) = return []
1567 go p = do
1862 go p = do
1568− x <- peekByteIndex p arrContents
1863+ x <- peekAt p arrContents
1569 (:) x <$> go (INDEX_NEXT(p,a))
1864 (:) x <$> go (INDEX_NEXT(p,a))
1570
1865
1571−{-# INLINE_NORMAL toStreamDWith #-}
1866+{-# INLINE_NORMAL toStreamWith #-}
1572−toStreamDWith ::
1867+toStreamWith ::
1573 forall m a. (Monad m, Unbox a)
1868 forall m a. (Monad m, Unbox a)
1574 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1869 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1575−toStreamDWith liftio MutArray{..} = D.Stream step arrStart
1870+toStreamWith liftio MutArray{..} = D.Stream step arrStart
1576
1871
1577 where
1872 where
1578
1873
1579 {-# INLINE_LATE step #-}
1874 {-# INLINE_LATE step #-}
1580 step _ p | assert (p <= arrEnd) (p == arrEnd) = return D.Stop
1875 step _ p | assert (p <= arrEnd) (p == arrEnd) = return D.Stop
1581 step _ p = liftio $ do
1876 step _ p = liftio $ do
1582− r <- peekByteIndex p arrContents
1877+ r <- peekAt p arrContents
1583 return $ D.Yield r (INDEX_NEXT(p,a))
1878 return $ D.Yield r (INDEX_NEXT(p,a))
1584
1879
1585-- | Convert a 'MutArray' into a stream.
1880-- | Convert a 'MutArray' into a stream.
@@ -1588,7 +1883,7 @@ toStreamDWith liftio MutArray{..} = D.Stream step arrStart
1588--
1883--
1589{-# INLINE_NORMAL read #-}
1884{-# INLINE_NORMAL read #-}
1590read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1885read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1591−read = toStreamDWith liftIO
1886+read = toStreamWith liftIO
1592
1887
1593{-# INLINE toStreamKWith #-}
1888{-# INLINE toStreamKWith #-}
1594toStreamKWith ::
1889toStreamKWith ::
@@ -1600,18 +1895,18 @@ toStreamKWith liftio MutArray{..} = go arrStart
1600
1895
1601 go p | assert (p <= arrEnd) (p == arrEnd) = K.nil
1896 go p | assert (p <= arrEnd) (p == arrEnd) = K.nil
1602 | otherwise =
1897 | otherwise =
1603− let elemM = peekByteIndex p arrContents
1898+ let elemM = peekAt p arrContents
1604 in liftio elemM `K.consM` go (INDEX_NEXT(p,a))
1899 in liftio elemM `K.consM` go (INDEX_NEXT(p,a))
1605
1900
1606{-# INLINE toStreamK #-}
1901{-# INLINE toStreamK #-}
1607toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1902toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1608toStreamK = toStreamKWith liftIO
1903toStreamK = toStreamKWith liftIO
1609
1904
1610−{-# INLINE_NORMAL toStreamDRevWith #-}
1905+{-# INLINE_NORMAL toStreamRevWith #-}
1611−toStreamDRevWith ::
1906+toStreamRevWith ::
1612 forall m a. (Monad m, Unbox a)
1907 forall m a. (Monad m, Unbox a)
1613 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1908 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1614−toStreamDRevWith liftio MutArray{..} =
1909+toStreamRevWith liftio MutArray{..} =
1615 let p = INDEX_PREV(arrEnd,a)
1910 let p = INDEX_PREV(arrEnd,a)
1616 in D.Stream step p
1911 in D.Stream step p
1617
1912
@@ -1620,7 +1915,7 @@ toStreamDRevWith liftio MutArray{..} =
1620 {-# INLINE_LATE step #-}
1915 {-# INLINE_LATE step #-}
1621 step _ p | p < arrStart = return D.Stop
1916 step _ p | p < arrStart = return D.Stop
1622 step _ p = liftio $ do
1917 step _ p = liftio $ do
1623− r <- peekByteIndex p arrContents
1918+ r <- peekAt p arrContents
1624 return $ D.Yield r (INDEX_PREV(p,a))
1919 return $ D.Yield r (INDEX_PREV(p,a))
1625
1920
1626-- | Convert a 'MutArray' into a stream in reverse order.
1921-- | Convert a 'MutArray' into a stream in reverse order.
@@ -1629,7 +1924,7 @@ toStreamDRevWith liftio MutArray{..} =
1629--
1924--
1630{-# INLINE_NORMAL readRev #-}
1925{-# INLINE_NORMAL readRev #-}
1631readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1926readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1632−readRev = toStreamDRevWith liftIO
1927+readRev = toStreamRevWith liftIO
1633
1928
1634{-# INLINE toStreamKRevWith #-}
1929{-# INLINE toStreamKRevWith #-}
1635toStreamKRevWith ::
1930toStreamKRevWith ::
@@ -1643,7 +1938,7 @@ toStreamKRevWith liftio MutArray {..} =
1643
1938
1644 go p | p < arrStart = K.nil
1939 go p | p < arrStart = K.nil
1645 | otherwise =
1940 | otherwise =
1646− let elemM = peekByteIndex p arrContents
1941+ let elemM = peekAt p arrContents
1647 in liftio elemM `K.consM` go (INDEX_PREV(p,a))
1942 in liftio elemM `K.consM` go (INDEX_PREV(p,a))
1648
1943
1649{-# INLINE toStreamKRev #-}
1944{-# INLINE toStreamKRev #-}
@@ -1678,7 +1973,7 @@ foldr f z arr = D.foldr f z $ read arr
1678
1973
1679-- XXX Keep the bound intact to not lose any free space? Perf impact?
1974-- XXX Keep the bound intact to not lose any free space? Perf impact?
1680
1975
1681−-- | @writeAppendNUnsafe n arr@ appends up to @n@ input items to the supplied
1976+-- | @unsafeAppendN n arr@ appends up to @n@ input items to the supplied
1682-- array.
1977-- array.
1683--
1978--
1684-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
1979-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
@@ -1687,13 +1982,12 @@ foldr f z arr = D.foldr f z $ read arr
1687-- Any free space left in the array after appending @n@ elements is lost.
1982-- Any free space left in the array after appending @n@ elements is lost.
1688--
1983--
1689-- /Internal/
1984-- /Internal/
1690−{-# INLINE_NORMAL writeAppendNUnsafe #-}
1985+{-# INLINE_NORMAL unsafeAppendN #-}
1691−writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1986+unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1692 Int
1987 Int
1693 -> m (MutArray a)
1988 -> m (MutArray a)
1694 -> Fold m a (MutArray a)
1989 -> Fold m a (MutArray a)
1695−writeAppendNUnsafe n action =
1696− fmap fromArrayUnsafe $ FL.foldlM' step initial
1990+unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
1697
1991
1698 where
1992 where
1699
1993
@@ -1706,38 +2000,59 @@ writeAppendNUnsafe n action =
1706 -- otherwise we lose that space.
2000 -- otherwise we lose that space.
1707 arr1 <-
2001 arr1 <-
1708 if free < needed
2002 if free < needed
1709− then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
2003+ then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1710 else return arr
2004 else return arr
1711 return $ toArrayUnsafe arr1
2005 return $ toArrayUnsafe arr1
1712
2006
1713 step (ArrayUnsafe contents start end) x = do
2007 step (ArrayUnsafe contents start end) x = do
1714− liftIO $ pokeByteIndex end contents x
2008+ liftIO $ pokeAt end contents x
1715 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2009 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1716
2010
2011+{-# DEPRECATED writeAppendNUnsafe "Please use unsafeAppendN instead." #-}
2012+{-# INLINE writeAppendNUnsafe #-}
2013+writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
2014+ Int
2015+ -> m (MutArray a)
2016+ -> Fold m a (MutArray a)
2017+writeAppendNUnsafe = unsafeAppendN
2018+
1717-- | Append @n@ elements to an existing array. Any free space left in the array
2019-- | Append @n@ elements to an existing array. Any free space left in the array
1718-- after appending @n@ elements is lost.
2020-- after appending @n@ elements is lost.
1719--
2021--
1720−-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
2022+-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1721--
2023--
1722−{-# INLINE_NORMAL writeAppendN #-}
2024+{-# INLINE_NORMAL appendN #-}
2025+appendN :: forall m a. (MonadIO m, Unbox a) =>
2026+ Int -> m (MutArray a) -> Fold m a (MutArray a)
2027+appendN n initial = FL.take n (unsafeAppendN n initial)
2028+
2029+-- XXX Deprecate in major
2030+-- {-# DEPRECATED writeAppendN "Please use appendN instead." #-}
2031+{-# INLINE writeAppendN #-}
1723writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
2032writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1724 Int -> m (MutArray a) -> Fold m a (MutArray a)
2033 Int -> m (MutArray a) -> Fold m a (MutArray a)
1725−writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
2034+writeAppendN = appendN
1726
2035
1727−-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
2036+-- | @appendWith realloc action@ mutates the array generated by @action@ to
1728-- append the input stream. If there is no reserved space available in the
2037-- append the input stream. If there is no reserved space available in the
1729-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
2038-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
1730-- where @oldSize@ is the current size of the array in bytes.
2039-- where @oldSize@ is the current size of the array in bytes.
1731--
2040--
1732-- Note that the returned array may be a mutated version of original array.
2041-- Note that the returned array may be a mutated version of original array.
1733--
2042--
1734−-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
2043+-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1735--
2044--
1736-- /Pre-release/
2045-- /Pre-release/
2046+{-# INLINE appendWith #-}
2047+appendWith :: forall m a. (MonadIO m, Unbox a) =>
2048+ (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2049+appendWith sizer = FL.foldlM' (snocWith sizer)
2050+
2051+{-# DEPRECATED writeAppendWith "Please use appendWith instead." #-}
1737{-# INLINE writeAppendWith #-}
2052{-# INLINE writeAppendWith #-}
1738writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
2053writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1739 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2054 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
1740−writeAppendWith sizer = FL.foldlM' (snocWith sizer)
2055+writeAppendWith = appendWith
1741
2056
1742-- | @append action@ mutates the array generated by @action@ to append the
2057-- | @append action@ mutates the array generated by @action@ to append the
1743-- input stream. If there is no reserved space available in the array it is
2058-- input stream. If there is no reserved space available in the array it is
@@ -1745,70 +2060,101 @@ writeAppendWith sizer = FL.foldlM' (snocWith sizer)
1745--
2060--
1746-- Note that the returned array may be a mutated version of original array.
2061-- Note that the returned array may be a mutated version of original array.
1747--
2062--
1748−-- >>> writeAppend = MutArray.writeAppendWith (* 2)
2063+-- >>> append = MutArray.appendWith (* 2)
1749--
2064--
2065+{-# INLINE append #-}
2066+append :: forall m a. (MonadIO m, Unbox a) =>
2067+ m (MutArray a) -> Fold m a (MutArray a)
2068+append = appendWith (* 2)
2069+
2070+-- XXX Deprecate in major
2071+-- {-# DEPRECATED writeAppend "Please use append instead." #-}
1750{-# INLINE writeAppend #-}
2072{-# INLINE writeAppend #-}
1751writeAppend :: forall m a. (MonadIO m, Unbox a) =>
2073writeAppend :: forall m a. (MonadIO m, Unbox a) =>
1752 m (MutArray a) -> Fold m a (MutArray a)
2074 m (MutArray a) -> Fold m a (MutArray a)
1753−writeAppend = writeAppendWith (* 2)
2075+writeAppend = append
1754
2076
1755-- XXX We can carry bound as well in the state to make sure we do not lose the
2077-- XXX We can carry bound as well in the state to make sure we do not lose the
1756-- remaining capacity. Need to check perf impact.
2078-- remaining capacity. Need to check perf impact.
1757--
2079--
1758−-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
2080+-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
1759−-- as argument.
2081+-- function as argument.
1760--
2082--
1761−-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
2083+-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1762--
2084--
1763-- /Pre-release/
2085-- /Pre-release/
1764−{-# INLINE_NORMAL writeNWithUnsafe #-}
2086+{-# INLINE_NORMAL unsafeCreateOfWith #-}
1765−writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2087+unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1766 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2088 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1767−writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2089+unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1768
2090
1769 where
2091 where
1770
2092
1771 initial = toArrayUnsafe <$> alloc (max n 0)
2093 initial = toArrayUnsafe <$> alloc (max n 0)
1772
2094
1773 step (ArrayUnsafe contents start end) x = do
2095 step (ArrayUnsafe contents start end) x = do
1774− liftIO $ pokeByteIndex end contents x
2096+ liftIO $ pokeAt end contents x
1775 return
2097 return
1776 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2098 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1777
2099
2100+{-# DEPRECATED writeNWithUnsafe "Please use unsafeCreateOfWith instead." #-}
2101+{-# INLINE writeNWithUnsafe #-}
2102+writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2103+ => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2104+writeNWithUnsafe = unsafeCreateOfWith
2105+
1778{-# INLINE_NORMAL writeNUnsafeAs #-}
2106{-# INLINE_NORMAL writeNUnsafeAs #-}
1779writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
2107writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
1780 => PinnedState -> Int -> Fold m a (MutArray a)
2108 => PinnedState -> Int -> Fold m a (MutArray a)
1781−writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
2109+writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
1782
2110
1783−-- | Like 'writeN' but does not check the array bounds when writing. The fold
2111+-- | Like 'createOf' but does not check the array bounds when writing. The fold
1784-- driver must not call the step function more than 'n' times otherwise it will
2112-- driver must not call the step function more than 'n' times otherwise it will
1785-- corrupt the memory and crash. This function exists mainly because any
2113-- corrupt the memory and crash. This function exists mainly because any
1786-- conditional in the step function blocks fusion causing 10x performance
2114-- conditional in the step function blocks fusion causing 10x performance
1787-- slowdown.
2115-- slowdown.
1788--
2116--
1789−-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
2117+-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
1790--
2118--
2119+{-# INLINE_NORMAL unsafeCreateOf #-}
2120+unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
2121+ => Int -> Fold m a (MutArray a)
2122+unsafeCreateOf = writeNUnsafeAs Unpinned
2123+
2124+{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
1791−{-# INLINE_NORMAL writeNUnsafe #-}
2125+{-# INLINE writeNUnsafe #-}
1792writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
2126writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
1793 => Int -> Fold m a (MutArray a)
2127 => Int -> Fold m a (MutArray a)
1794−writeNUnsafe = writeNUnsafeAs Unpinned
2128+writeNUnsafe = unsafeCreateOf
1795
2129
1796−-- | Like 'writeNUnsafe' but creates a pinned array.
2130+-- | Like 'unsafeCreateOf' but creates a pinned array.
2131+{-# INLINE_NORMAL unsafePinnedCreateOf #-}
2132+unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a)
2133+ => Int -> Fold m a (MutArray a)
2134+unsafePinnedCreateOf = writeNUnsafeAs Pinned
2135+
2136+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
1797−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
2137+{-# INLINE pinnedWriteNUnsafe #-}
1798pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
2138pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
1799 => Int -> Fold m a (MutArray a)
2139 => Int -> Fold m a (MutArray a)
1800−pinnedWriteNUnsafe = writeNUnsafeAs Pinned
2140+pinnedWriteNUnsafe = unsafePinnedCreateOf
1801
2141
1802−-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
2142+-- | @createOfWith alloc n@ folds a maximum of @n@ elements into an array
1803-- allocated using the @alloc@ function.
2143-- allocated using the @alloc@ function.
1804--
2144--
1805−-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
2145+-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
1806−-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
2146+-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
1807--
2147--
1808−{-# INLINE_NORMAL writeNWith #-}
2148+{-# INLINE_NORMAL createOfWith #-}
2149+createOfWith :: forall m a. (MonadIO m, Unbox a)
2150+ => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2151+createOfWith alloc n = FL.take n (unsafeCreateOfWith alloc n)
2152+
2153+-- {-# DEPRECATED writeNWith "Please use createOfWith instead." #-}
2154+{-# INLINE writeNWith #-}
1809writeNWith :: forall m a. (MonadIO m, Unbox a)
2155writeNWith :: forall m a. (MonadIO m, Unbox a)
1810 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2156 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1811−writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
2157+writeNWith = createOfWith
1812
2158
1813{-# INLINE_NORMAL writeNAs #-}
2159{-# INLINE_NORMAL writeNAs #-}
1814writeNAs ::
2160writeNAs ::
@@ -1816,28 +2162,42 @@ writeNAs ::
1816 => PinnedState
2162 => PinnedState
1817 -> Int
2163 -> Int
1818 -> Fold m a (MutArray a)
2164 -> Fold m a (MutArray a)
1819−writeNAs ps = writeNWith (newAs ps)
2165+writeNAs ps = createOfWith (newAs ps)
1820
2166
1821−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
2167+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
1822-- 'MutArray'.
2168-- 'MutArray'.
1823--
2169--
1824−-- >>> writeN = MutArray.writeNWith MutArray.new
2170+-- >>> createOf = MutArray.createOfWith MutArray.new
1825−-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
2171+-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
1826−-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
2172+-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
1827--
2173--
1828−{-# INLINE_NORMAL writeN #-}
2174+{-# INLINE_NORMAL createOf #-}
2175+createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2176+createOf = writeNAs Unpinned
2177+
2178+-- XXX Deprecate in major
2179+-- {-# DEPRECATED writeN "Please use createOf instead." #-}
2180+{-# INLINE writeN #-}
1829writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2181writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1830−writeN = writeNAs Unpinned
2182+writeN = createOf
2183+
2184+-- | Like 'createOf' but creates a pinned array.
2185+{-# INLINE_NORMAL pinnedCreateOf #-}
2186+pinnedCreateOf ::
2187+ forall m a. (MonadIO m, Unbox a)
2188+ => Int
2189+ -> Fold m a (MutArray a)
2190+pinnedCreateOf = writeNAs Pinned
1831
2191
1832−-- | Like 'writeN' but creates a pinned array.
2192+{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
1833−{-# INLINE_NORMAL pinnedWriteN #-}
2193+{-# INLINE pinnedWriteN #-}
1834pinnedWriteN ::
2194pinnedWriteN ::
1835 forall m a. (MonadIO m, Unbox a)
2195 forall m a. (MonadIO m, Unbox a)
1836 => Int
2196 => Int
1837 -> Fold m a (MutArray a)
2197 -> Fold m a (MutArray a)
1838−pinnedWriteN = writeNAs Pinned
2198+pinnedWriteN = pinnedCreateOf
1839
2199
1840−-- | Like writeNWithUnsafe but writes the array in reverse order.
2200+-- | Like unsafeCreateOfWith but writes the array in reverse order.
1841--
2201--
1842-- /Internal/
2202-- /Internal/
1843{-# INLINE_NORMAL writeRevNWithUnsafe #-}
2203{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -1854,11 +2214,11 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1854
2214
1855 step (ArrayUnsafe contents start end) x = do
2215 step (ArrayUnsafe contents start end) x = do
1856 let ptr = INDEX_PREV(start,a)
2216 let ptr = INDEX_PREV(start,a)
1857− liftIO $ pokeByteIndex ptr contents x
2217+ liftIO $ pokeAt ptr contents x
1858 return
2218 return
1859 $ ArrayUnsafe contents ptr end
2219 $ ArrayUnsafe contents ptr end
1860
2220
1861−-- | Like writeNWith but writes the array in reverse order.
2221+-- | Like createOfWith but writes the array in reverse order.
1862--
2222--
1863-- /Internal/
2223-- /Internal/
1864{-# INLINE_NORMAL writeRevNWith #-}
2224{-# INLINE_NORMAL writeRevNWith #-}
@@ -1866,31 +2226,36 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
1866 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2226 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1867writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
2227writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
1868
2228
1869−-- | Like writeN but writes the array in reverse order.
2229+-- | Like 'createOf' but writes the array in reverse order.
1870--
2230--
1871-- /Pre-release/
2231-- /Pre-release/
1872−{-# INLINE_NORMAL writeRevN #-}
2232+{-# INLINE_NORMAL revCreateOf #-}
2233+revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2234+revCreateOf = writeRevNWith new
2235+
2236+{-# DEPRECATED writeRevN "Please use revCreateOf instead." #-}
2237+{-# INLINE writeRevN #-}
1873writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2238writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1874−writeRevN = writeRevNWith new
2239+writeRevN = revCreateOf
1875
2240
1876-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
2241-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
1877-- input stream to a 'MutArray' aligned to the given size.
2242-- input stream to a 'MutArray' aligned to the given size.
1878--
2243--
1879−-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
2244+-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
1880−-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
2245+-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
1881--
2246--
1882-- /Pre-release/
2247-- /Pre-release/
1883--
2248--
1884{-# INLINE_NORMAL pinnedWriteNAligned #-}
2249{-# INLINE_NORMAL pinnedWriteNAligned #-}
1885pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
2250pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
1886 => Int -> Int -> Fold m a (MutArray a)
2251 => Int -> Int -> Fold m a (MutArray a)
1887−pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
2252+pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
1888
2253
1889-- XXX Buffer to a list instead?
2254-- XXX Buffer to a list instead?
1890−--
2255+
1891-- | Buffer a stream into a stream of arrays.
2256-- | Buffer a stream into a stream of arrays.
1892--
2257--
1893−-- >>> writeChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
2258+-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
1894--
2259--
1895-- Breaking an array into an array stream can be useful to consume a large
2260-- Breaking an array into an array stream can be useful to consume a large
1896-- array sequentially such that memory of the array is released incrementatlly.
2261-- array sequentially such that memory of the array is released incrementatlly.
@@ -1899,37 +2264,43 @@ pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
1899--
2264--
1900-- /Unimplemented/
2265-- /Unimplemented/
1901--
2266--
1902−{-# INLINE_NORMAL writeChunks #-}
2267+{-# INLINE_NORMAL buildChunks #-}
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 #-}
1903writeChunks :: (MonadIO m, Unbox a) =>
2274writeChunks :: (MonadIO m, Unbox a) =>
1904 Int -> Fold m a (StreamK n (MutArray a))
2275 Int -> Fold m a (StreamK n (MutArray a))
1905−writeChunks n = FL.many (writeN n) FL.toStreamK
2276+writeChunks = buildChunks
1906
2277
1907{-# INLINE_NORMAL writeWithAs #-}
2278{-# INLINE_NORMAL writeWithAs #-}
1908writeWithAs :: forall m a. (MonadIO m, Unbox a)
2279writeWithAs :: forall m a. (MonadIO m, Unbox a)
1909 => PinnedState -> Int -> Fold m a (MutArray a)
2280 => PinnedState -> Int -> Fold m a (MutArray a)
1910−-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
2281+-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
1911writeWithAs ps elemCount =
2282writeWithAs ps elemCount =
1912 FL.rmapM extract $ FL.foldlM' step initial
2283 FL.rmapM extract $ FL.foldlM' step initial
1913
2284
1914 where
2285 where
1915
2286
1916 initial = do
2287 initial = do
1917− when (elemCount < 0) $ error "writeWith: elemCount is negative"
2288+ when (elemCount < 0) $ error "createWith: elemCount is negative"
1918− liftIO $ newAs ps elemCount
2289+ newAs ps elemCount
1919
2290
1920 step arr@(MutArray _ start end bound) x
2291 step arr@(MutArray _ start end bound) x
1921 | INDEX_NEXT(end,a) > bound = do
2292 | INDEX_NEXT(end,a) > bound = do
1922 let oldSize = end - start
2293 let oldSize = end - start
1923 newSize = max (oldSize * 2) 1
2294 newSize = max (oldSize * 2) 1
1924− arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
2295+ arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
1925 snocUnsafe arr1 x
2296 snocUnsafe arr1 x
1926 step arr x = snocUnsafe arr x
2297 step arr x = snocUnsafe arr x
1927
2298
1928 extract = liftIO . rightSize
2299 extract = liftIO . rightSize
1929
2300
1930−-- XXX Compare writeWith with fromStreamD which uses an array of streams
2301+-- XXX Compare createWith with fromStreamD which uses an array of streams
1931−-- implementation. We can write this using writeChunks above if that is faster.
2302+-- implementation. We can write this using buildChunks above if that is faster.
1932−-- If writeWith is faster then we should use that to implement
2303+-- If createWith is faster then we should use that to implement
1933-- fromStreamD.
2304-- fromStreamD.
1934--
2305--
1935-- XXX The realloc based implementation needs to make one extra copy if we use
2306-- XXX The realloc based implementation needs to make one extra copy if we use
@@ -1944,39 +2315,56 @@ writeWithAs ps elemCount =
1944-- XXX check if GHC's memory allocator is efficient enough. We can try the C
2315-- XXX check if GHC's memory allocator is efficient enough. We can try the C
1945-- malloc to compare against.
2316-- malloc to compare against.
1946
2317
1947−-- | @writeWith minCount@ folds the whole input to a single array. The array
2318+-- | @createWith minCount@ folds the whole input to a single array. The array
1948-- starts at a size big enough to hold minCount elements, the size is doubled
2319-- starts at a size big enough to hold minCount elements, the size is doubled
1949-- every time the array needs to be grown.
2320-- every time the array needs to be grown.
1950--
2321--
1951-- /Caution! Do not use this on infinite streams./
2322-- /Caution! Do not use this on infinite streams./
1952--
2323--
1953−-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2324+-- >>> f n = MutArray.appendWith (* 2) (MutArray.emptyOf n)
1954−-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2325+-- >>> createWith n = Fold.rmapM MutArray.rightSize (f n)
1955−-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
2326+-- >>> createWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
1956--
2327--
1957-- /Pre-release/
2328-- /Pre-release/
1958−{-# INLINE_NORMAL writeWith #-}
2329+{-# INLINE_NORMAL createWith #-}
2330+createWith :: forall m a. (MonadIO m, Unbox a)
2331+ => Int -> Fold m a (MutArray a)
2332+-- createWith n = FL.rmapM rightSize $ appendWith (* 2) (emptyOf n)
2333+createWith = writeWithAs Unpinned
2334+
2335+{-# DEPRECATED writeWith "Please use createWith instead." #-}
2336+{-# INLINE writeWith #-}
1959writeWith :: forall m a. (MonadIO m, Unbox a)
2337writeWith :: forall m a. (MonadIO m, Unbox a)
1960 => Int -> Fold m a (MutArray a)
2338 => Int -> Fold m a (MutArray a)
1961−-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
2339+writeWith = createWith
1962−writeWith = writeWithAs Unpinned
1963
2340
1964-- | Fold the whole input to a single array.
2341-- | Fold the whole input to a single array.
1965--
2342--
1966−-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
2343+-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
1967-- rounded up to the element size.
2344-- rounded up to the element size.
1968--
2345--
1969-- /Caution! Do not use this on infinite streams./
2346-- /Caution! Do not use this on infinite streams./
1970--
2347--
2348+{-# INLINE create #-}
2349+create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2350+create = createWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2351+
2352+-- XXX Deprecate in major
2353+-- {-# DEPRECATED write "Please use create instead." #-}
1971{-# INLINE write #-}
2354{-# INLINE write #-}
1972write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2355write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
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 =
1973−write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2362+ writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
1974
2363
1975−-- | Like 'write' but creates a pinned array.
2364+{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
1976{-# INLINE pinnedWrite #-}
2365{-# INLINE pinnedWrite #-}
1977pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2366pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1978−pinnedWrite =
2367+pinnedWrite = pinnedCreate
1979− writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
1980
2368
1981-------------------------------------------------------------------------------
2369-------------------------------------------------------------------------------
1982-- construct from streams, known size
2370-- construct from streams, known size
@@ -1986,25 +2374,31 @@ pinnedWrite =
1986fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
2374fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
1987 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
2375 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
1988fromStreamDNAs ps limit str = do
2376fromStreamDNAs ps limit str = do
1989− (arr :: MutArray a) <- liftIO $ newAs ps limit
2377+ (arr :: MutArray a) <- newAs ps limit
1990 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
2378 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
1991 return $ arr {arrEnd = end}
2379 return $ arr {arrEnd = end}
1992
2380
1993 where
2381 where
1994
2382
1995 fwrite arrContents ptr x = do
2383 fwrite arrContents ptr x = do
1996− liftIO $ pokeByteIndex ptr arrContents x
2384+ liftIO $ pokeAt ptr arrContents x
1997 return $ INDEX_NEXT(ptr,a)
2385 return $ INDEX_NEXT(ptr,a)
1998
2386
1999−-- | Use the 'writeN' fold instead.
2387+-- | Use the 'createOf' fold instead.
2000--
2388--
2001−-- >>> fromStreamDN n = Stream.fold (MutArray.writeN n)
2389+-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2002--
2390--
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." #-}
2003−{-# INLINE_NORMAL fromStreamDN #-}
2398+{-# INLINE fromStreamDN #-}
2004fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2399fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2005 => Int -> D.Stream m a -> m (MutArray a)
2400 => Int -> D.Stream m a -> m (MutArray a)
2006−-- fromStreamDN n = D.fold (writeN n)
2401+fromStreamDN = fromStreamN
2007−fromStreamDN = fromStreamDNAs Unpinned
2008
2402
2009-- | Create a 'MutArray' from the first N elements of a list. The array is
2403-- | Create a 'MutArray' from the first N elements of a list. The array is
2010-- allocated to size N, if the list terminates before N elements then the
2404-- allocated to size N, if the list terminates before N elements then the
@@ -2024,16 +2418,70 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
2024-- /Pre-release/
2418-- /Pre-release/
2025{-# INLINE fromListRevN #-}
2419{-# INLINE fromListRevN #-}
2026fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2420fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2027−fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
2421+fromListRevN n xs = D.fold (revCreateOf 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
2028
2429
2029-- | Convert a pure stream in Identity monad to a mutable array.
2430-- | Convert a pure stream in Identity monad to a mutable array.
2030{-# INLINABLE fromPureStream #-}
2431{-# INLINABLE fromPureStream #-}
2031fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2432fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2032fromPureStream xs =
2433fromPureStream xs =
2033− liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
2434+ D.fold create $ 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})
2034
2461
2035-------------------------------------------------------------------------------
2462-------------------------------------------------------------------------------
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+-------------------------------------------------------------------------------
2036−-- convert stream to a single array
2484+-- convert a stream of arrays to a single array by buffering arrays first
2037-------------------------------------------------------------------------------
2485-------------------------------------------------------------------------------
2038
2486
2039{-# INLINE arrayStreamKLength #-}
2487{-# INLINE arrayStreamKLength #-}
@@ -2043,34 +2491,72 @@ arrayStreamKLength as = K.foldl' (+) 0 (K.map length as)
2043-- | Convert an array stream to an array. Note that this requires peak memory
2491-- | Convert an array stream to an array. Note that this requires peak memory
2044-- that is double the size of the array stream.
2492-- that is double the size of the array stream.
2045--
2493--
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." #-}
2046{-# INLINE fromArrayStreamK #-}
2518{-# INLINE fromArrayStreamK #-}
2047fromArrayStreamK :: (Unbox a, MonadIO m) =>
2519fromArrayStreamK :: (Unbox a, MonadIO m) =>
2048 StreamK m (MutArray a) -> m (MutArray a)
2520 StreamK m (MutArray a) -> m (MutArray a)
2049−fromArrayStreamK as = do
2521+fromArrayStreamK = fromChunksK
2050− len <- arrayStreamKLength as
2051− fromStreamDN len $ D.unfoldMany reader $ D.fromStreamK as
2052
2522
2053{-# INLINE fromStreamDAs #-}
2523{-# INLINE fromStreamDAs #-}
2054fromStreamDAs ::
2524fromStreamDAs ::
2055 (MonadIO m, Unbox a) => PinnedState -> D.Stream m a -> m (MutArray a)
2525 (MonadIO m, Unbox a) => PinnedState -> D.Stream m a -> m (MutArray a)
2526+fromStreamDAs ps m =
2056−fromStreamDAs ps m = arrayStreamKFromStreamDAs ps m >>= fromArrayStreamK
2527+ arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2057
2528
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
2058-- CAUTION: a very large number (millions) of arrays can degrade performance
2543-- CAUTION: a very large number (millions) of arrays can degrade performance
2059-- due to GC overhead because we need to buffer the arrays before we flatten
2544-- due to GC overhead because we need to buffer the arrays before we flatten
2060-- all the arrays.
2545-- all the arrays.
2061--
2546--
2062−-- XXX Compare if this is faster or "fold write".
2547+-- XXX Compare if this is faster or "fold create".
2063--
2548--
2064-- | We could take the approach of doubling the memory allocation on each
2549-- | We could take the approach of doubling the memory allocation on each
2065-- overflow. This would result in more or less the same amount of copying as in
2550-- overflow. This would result in more or less the same amount of copying as in
2066-- the chunking approach. However, if we have to shrink in the end then it may
2551-- the chunking approach. However, if we have to shrink in the end then it may
2067-- result in an extra copy of the entire data.
2552-- result in an extra copy of the entire data.
2068--
2553--
2069−-- >>> fromStreamD = StreamD.fold MutArray.write
2554+-- >>> fromStreamD = StreamD.fold MutArray.create
2070--
2555--
2071{-# INLINE fromStreamD #-}
2556{-# INLINE fromStreamD #-}
2557+{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
2072fromStreamD :: (MonadIO m, Unbox a) => D.Stream m a -> m (MutArray a)
2558fromStreamD :: (MonadIO m, Unbox a) => D.Stream m a -> m (MutArray a)
2073−fromStreamD = fromStreamDAs Unpinned
2559+fromStreamD = fromStream
2074
2560
2075-- | Create a 'MutArray' from a list. The list must be of finite size.
2561-- | Create a 'MutArray' from a list. The list must be of finite size.
2076--
2562--
@@ -2095,22 +2581,44 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
2095-- Cloning
2581-- Cloning
2096-------------------------------------------------------------------------------
2582-------------------------------------------------------------------------------
2097
2583
2584+-- Arrays are aligned on 64-bit boundaries. The fastest way to copy an array is
2585+-- to unsafeCast it to Word64, read it, write it to Word64 array and unsafeCast
2586+-- it again. We can use SIMD read/write as well.
2587+
2098{-# INLINE cloneAs #-}
2588{-# INLINE cloneAs #-}
2589+cloneAs ::
2590+ ( MonadIO m
2591+#ifdef DEVBUILD
2592+ , Unbox a
2593+#endif
2594+ )
2099−cloneAs :: MonadIO m => PinnedState -> MutArray a -> m (MutArray a)
2595+ => PinnedState -> MutArray a -> m (MutArray a)
2100cloneAs ps src =
2596cloneAs ps src =
2101− liftIO $ do
2597+ do
2102 let startSrc = arrStart src
2598 let startSrc = arrStart src
2103 srcLen = arrEnd src - startSrc
2599 srcLen = arrEnd src - startSrc
2104− newArrContents <- Unboxed.newBytesAs ps srcLen
2600+ newArrContents <-
2105− putSliceUnsafe (arrContents src) startSrc newArrContents 0 srcLen
2601+ Unboxed.cloneSliceUnsafeAs ps startSrc srcLen (arrContents src)
2106 return $ MutArray newArrContents 0 srcLen srcLen
2602 return $ MutArray newArrContents 0 srcLen srcLen
2107
2603
2108{-# INLINE clone #-}
2604{-# INLINE clone #-}
2605+clone ::
2606+ ( MonadIO m
2607+#ifdef DEVBUILD
2608+ , Unbox a
2609+#endif
2610+ )
2109−clone :: MonadIO m => MutArray a -> m (MutArray a)
2611+ => MutArray a -> m (MutArray a)
2110clone = cloneAs Unpinned
2612clone = cloneAs Unpinned
2111
2613
2112{-# INLINE pinnedClone #-}
2614{-# INLINE pinnedClone #-}
2615+pinnedClone ::
2616+ ( MonadIO m
2617+#ifdef DEVBUILD
2618+ , Unbox a
2619+#endif
2620+ )
2113−pinnedClone :: MonadIO m => MutArray a -> m (MutArray a)
2621+ => MutArray a -> m (MutArray a)
2114pinnedClone = cloneAs Pinned
2622pinnedClone = cloneAs Pinned
2115
2623
2116-------------------------------------------------------------------------------
2624-------------------------------------------------------------------------------
@@ -2125,17 +2633,16 @@ spliceCopy :: forall m a. MonadIO m =>
2125 Unbox a =>
2633 Unbox a =>
2126#endif
2634#endif
2127 MutArray a -> MutArray a -> m (MutArray a)
2635 MutArray a -> MutArray a -> m (MutArray a)
2128−spliceCopy arr1 arr2 = liftIO $ do
2636+spliceCopy arr1 arr2 = do
2129 let start1 = arrStart arr1
2637 let start1 = arrStart arr1
2130 start2 = arrStart arr2
2638 start2 = arrStart arr2
2131 len1 = arrEnd arr1 - start1
2639 len1 = arrEnd arr1 - start1
2132 len2 = arrEnd arr2 - start2
2640 len2 = arrEnd arr2 - start2
2133− let newLen = len1 + len2
2641+ let len = len1 + len2
2134 newArrContents <-
2642 newArrContents <-
2135 if Unboxed.isPinned (arrContents arr1)
2643 if Unboxed.isPinned (arrContents arr1)
2136− then Unboxed.pinnedNewBytes newLen
2644+ then liftIO $ Unboxed.pinnedNew len
2137− else Unboxed.newBytes newLen
2645+ else liftIO $ Unboxed.new len
2138− let len = len1 + len2
2139 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2646 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2140 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2647 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2141 return $ MutArray newArrContents 0 len len
2648 return $ MutArray newArrContents 0 len len
@@ -2147,7 +2654,7 @@ spliceCopy arr1 arr2 = liftIO $ do
2147spliceUnsafe :: MonadIO m =>
2654spliceUnsafe :: MonadIO m =>
2148 MutArray a -> MutArray a -> m (MutArray a)
2655 MutArray a -> MutArray a -> m (MutArray a)
2149spliceUnsafe dst src =
2656spliceUnsafe dst src =
2150− liftIO $ do
2657+ do
2151 let startSrc = arrStart src
2658 let startSrc = arrStart src
2152 srcLen = arrEnd src - startSrc
2659 srcLen = arrEnd src - startSrc
2153 endDst = arrEnd dst
2660 endDst = arrEnd dst
@@ -2169,7 +2676,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
2169 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2676 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2170spliceWith sizer dst@(MutArray _ start end bound) src = do
2677spliceWith sizer dst@(MutArray _ start end bound) src = do
2171{-
2678{-
2172− let f = writeAppendWith (`sizer` byteLength src) (return dst)
2679+ let f = appendWith (`sizer` byteLength src) (return dst)
2173 in D.fold f (toStreamD src)
2680 in D.fold f (toStreamD src)
2174-}
2681-}
2175 assert (end <= bound) (return ())
2682 assert (end <= bound) (return ())
@@ -2185,7 +2692,7 @@ spliceWith sizer dst@(MutArray _ start end bound) src = do
2185 $ "splice: newSize is less than the total size "
2692 $ "splice: newSize is less than the total size "
2186 ++ "of arrays being appended. Please check the "
2693 ++ "of arrays being appended. Please check the "
2187 ++ "sizer function passed."
2694 ++ "sizer function passed."
2188− liftIO $ realloc newSizeInBytes dst
2695+ realloc newSizeInBytes dst
2189 else return dst
2696 else return dst
2190 spliceUnsafe dst1 src
2697 spliceUnsafe dst1 src
2191
2698
@@ -2222,14 +2729,24 @@ spliceExp = spliceWith (\l1 l2 -> max (l1 * 2) (l1 + l2))
2222-- Splitting
2729-- Splitting
2223-------------------------------------------------------------------------------
2730-------------------------------------------------------------------------------
2224
2731
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+
2225-- | Drops the separator byte
2743-- | Drops the separator byte
2226{-# INLINE breakOn #-}
2744{-# INLINE breakOn #-}
2227breakOn :: MonadIO m
2745breakOn :: MonadIO m
2228 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2746 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2229−breakOn sep arr@MutArray{..} = asPtrUnsafe arr $ \p -> liftIO $ do
2747+breakOn sep arr@MutArray{..} = unsafeAsPtr 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).
2232 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2748 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2749+ -- Need efficient stream based primitives that work on Word64.
2233 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2750 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2234 let sepIndex = loc `minusPtr` p
2751 let sepIndex = loc `minusPtr` p
2235 return $
2752 return $
@@ -2250,32 +2767,41 @@ breakOn sep arr@MutArray{..} = asPtrUnsafe arr $ \p -> liftIO $ do
2250 }
2767 }
2251 )
2768 )
2252
2769
2770+-- | Like 'splitAt' but does not check whether the index is valid.
2771+--
2772+{-# INLINE unsafeSplitAt #-}
2773+unsafeSplitAt :: forall a. Unbox a =>
2774+ Int -> MutArray a -> (MutArray a, MutArray a)
2775+unsafeSplitAt i MutArray{..} =
2776+ let off = i * SIZE_OF(a)
2777+ p = arrStart + off
2778+ in ( MutArray
2779+ { arrContents = arrContents
2780+ , arrStart = arrStart
2781+ , arrEnd = p
2782+ , arrBound = p
2783+ }
2784+ , MutArray
2785+ { arrContents = arrContents
2786+ , arrStart = p
2787+ , arrEnd = arrEnd
2788+ , arrBound = arrBound
2789+ }
2790+ )
2791+
2253-- | Create two slices of an array without copying the original array. The
2792-- | Create two slices of an array without copying the original array. The
2254-- specified index @i@ is the first index of the second slice.
2793-- specified index @i@ is the first index of the second slice.
2255--
2794--
2795+{-# INLINE splitAt #-}
2256splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2796splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2257−splitAt i arr@MutArray{..} =
2797+splitAt i arr =
2258 let maxIndex = length arr - 1
2798 let maxIndex = length arr - 1
2259 in if i < 0
2799 in if i < 0
2260 then error "sliceAt: negative array index"
2800 then error "sliceAt: negative array index"
2261 else if i > maxIndex
2801 else if i > maxIndex
2262 then error $ "sliceAt: specified array index " ++ show i
2802 then error $ "sliceAt: specified array index " ++ show i
2263 ++ " is beyond the maximum index " ++ show maxIndex
2803 ++ " is beyond the maximum index " ++ show maxIndex
2264− else let off = i * SIZE_OF(a)
2804+ else unsafeSplitAt i arr
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− )
2279
2805
2280-------------------------------------------------------------------------------
2806-------------------------------------------------------------------------------
2281-- Casting
2807-- Casting
@@ -2325,13 +2851,16 @@ cast arr =
2325-- guarantees that unsafe calls will be performed in the calling thread. Making
2851-- guarantees that unsafe calls will be performed in the calling thread. Making
2326-- it safe to pass heap-allocated objects to unsafe functions.
2852-- it safe to pass heap-allocated objects to unsafe functions.
2327
2853
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
2330−-- asPtr, the unsafety is implicit for any pointer operations. And we are safe
2854+-- XXX Should we just name it asPtr, the unsafety is implicit for any pointer
2331−-- from Haskell perspective because we will be pinning the memory.
2855+-- operations. And we are safe from Haskell perspective because we will be
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.
2332
2861
2333−-- | Use an @MutArray a@ as @Ptr a@. This is useful when we want to pass an array
2862+-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
2334−-- as a pointer to some operating system call or to a "safe" FFI call.
2863+-- array as a pointer to some operating system call or to a "safe" FFI call.
2335--
2864--
2336-- If the array is not pinned it is copied to pinned memory before passing it
2865-- If the array is not pinned it is copied to pinned memory before passing it
2337-- to the monadic action.
2866-- to the monadic action.
@@ -2341,57 +2870,382 @@ cast arr =
2341-- opportunistically before this operation occurs, to avoid the cost of a copy
2870-- opportunistically before this operation occurs, to avoid the cost of a copy
2342-- if possible.
2871-- if possible.
2343--
2872--
2344−-- /Unsafe/
2873+-- /Unsafe/ because of direct pointer operations. The user must ensure that
2874+-- they are writing within the legal bounds of the array.
2345--
2875--
2346-- /Pre-release/
2876-- /Pre-release/
2347--
2877--
2878+{-# INLINE unsafePinnedAsPtr #-}
2879+unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2880+unsafePinnedAsPtr arr f =
2881+ Unboxed.unsafePinnedAsPtr
2882+ (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2883+
2884+{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
2348{-# INLINE asPtrUnsafe #-}
2885{-# INLINE asPtrUnsafe #-}
2349asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2886asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2350−asPtrUnsafe arr f = do
2887+asPtrUnsafe = unsafePinnedAsPtr
2351− contents <- liftIO $ Unboxed.pin $ arrContents arr
2352− let !ptr = Ptr (byteArrayContents#
2353− (unsafeCoerce# (getMutableByteArray# contents)))
2354
2888
2889+{-# INLINE unsafeAsPtr #-}
2890+unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2891+unsafeAsPtr arr f =
2892+ Unboxed.unsafeAsPtr
2355− r <- f (ptr `plusPtr` arrStart arr)
2893+ (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2356− liftIO $ touch contents
2357− return r
2358
2894
2359-------------------------------------------------------------------------------
2895-------------------------------------------------------------------------------
2360-- Equality
2896-- Equality
2361-------------------------------------------------------------------------------
2897-------------------------------------------------------------------------------
2362
2898
2363−-- | Compare the length of the arrays. If the length is equal, compare the
2899+-- | Byte compare two arrays. Compare the length of the arrays. If the length
2364−-- lexicographical ordering of two underlying byte arrays otherwise return the
2900+-- is equal, compare the lexicographical ordering of two underlying byte arrays
2365−-- result of length comparison.
2901+-- otherwise return the 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.
2366--
2906--
2367-- /Pre-release/
2907-- /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+
2368{-# INLINE cmp #-}
2931{-# INLINE cmp #-}
2932+{-# DEPRECATED cmp "Please use byteCmp instead." #-}
2369cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2933cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2370−cmp arr1 arr2 =
2934+cmp = byteCmp
2371− liftIO
2935+
2372− $ do
2936+-- | Byte equality of two arrays.
2373− let marr1 = getMutableByteArray# (arrContents arr1)
2937+--
2374− marr2 = getMutableByteArray# (arrContents arr2)
2938+-- >>> byteEq arr1 arr2 = (==) EQ $ MArray.byteCmp arr1 arr2
2375− !(I# st1#) = arrStart arr1
2939+--
2376− !(I# st2#) = arrStart arr2
2940+-- /Unsafe/: See 'byteCmp'.
2377− !(I# len#) = byteLength arr1
2941+{-# INLINE byteEq #-}
2378− case compare (byteLength arr1) (byteLength arr2) of
2942+byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
2379− EQ -> do
2943+byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2380− r <- liftIO $ IO $ \s# ->
2944+
2381− let res =
2945+-------------------------------------------------------------------------------
2382− I#
2946+-- Compact
2383− (compareByteArrays#
2947+-------------------------------------------------------------------------------
2384− (unsafeCoerce# marr1)
2948+
2385− st1#
2949+-- Note: LE versions avoid an extra copy compared to GE. LE parser trades
2386− (unsafeCoerce# marr2)
2950+-- backtracking one array in lieu of avoiding a copy. However, LE and GE both
2387− st2#
2951+-- can leave some memory unused. They can split the last array to fit it
2388− len#)
2952+-- exactly in the space.
2389− in (# s#, res #)
2953+
2390− return $ compare r 0
2954+{-# INLINE_NORMAL pCompactLeAs #-}
2391− x -> return x
2955+pCompactLeAs ::
2956+ forall m a. (MonadIO m, Unbox a)
2957+ => PinnedState -> Int -> Parser (MutArray a) m (MutArray a)
2958+pCompactLeAs ps maxElems = Parser step initial extract
2959+
2960+ where
2961+
2962+ maxBytes = maxElems * SIZE_OF(a)
2963+
2964+ functionName = "Streamly.Internal.Data.MutArray.pCompactLE"
2965+
2966+ initial =
2967+ return
2968+ $ if maxElems <= 0
2969+ then error
2970+ $ functionName
2971+ ++ ": the size of arrays ["
2972+ ++ show maxElems ++ "] must be a natural number"
2973+ else Parser.IPartial Nothing
2974+
2975+ step Nothing arr =
2976+ return
2977+ $ let len = byteLength arr
2978+ in if len >= maxBytes
2979+ then Parser.Done 0 arr
2980+ else Parser.Partial 0 (Just arr)
2981+ -- XXX Split the last array to use the space more compactly.
2982+ step (Just buf) arr =
2983+ let len = byteLength buf + byteLength arr
2984+ in if len > maxBytes
2985+ then return $ Parser.Done 1 buf
2986+ else do
2987+ buf1 <-
2988+ if byteCapacity buf < maxBytes
2989+ then liftIO $ reallocExplicitAs
2990+ ps (SIZE_OF(a)) maxBytes buf
2991+ else return buf
2992+ buf2 <- spliceUnsafe buf1 arr
2993+ return $ Parser.Partial 0 (Just buf2)
2994+
2995+ extract Nothing = return $ Parser.Done 0 nil
2996+ extract (Just buf) = return $ Parser.Done 0 buf
2997+
2998+-- | Parser @pCompactLE maxElems@ coalesces adjacent arrays in the input stream
2999+-- only if the combined size would be less than or equal to @maxElems@
3000+-- elements. Note that it won't split an array if the original array is already
3001+-- larger than maxElems.
3002+--
3003+-- @maxElems@ must be greater than 0.
3004+--
3005+-- Generates unpinned arrays irrespective of the pinning status of input
3006+-- arrays.
3007+--
3008+-- /Internal/
3009+{-# INLINE pCompactLE #-}
3010+pCompactLE ::
3011+ forall m a. (MonadIO m, Unbox a)
3012+ => Int -> Parser (MutArray a) m (MutArray a)
3013+pCompactLE = pCompactLeAs Unpinned
3014+
3015+-- | Pinned version of 'pCompactLE'.
3016+{-# INLINE pPinnedCompactLE #-}
3017+pPinnedCompactLE ::
3018+ forall m a. (MonadIO m, Unbox a)
3019+ => Int -> Parser (MutArray a) m (MutArray a)
3020+pPinnedCompactLE = pCompactLeAs Pinned
3021+
3022+data SpliceState s arr
3023+ = SpliceInitial s
3024+ | SpliceBuffering s arr
3025+ | SpliceYielding arr (SpliceState s arr)
3026+ | SpliceFinish
3027+
3028+-- This mutates the first array (if it has space) to append values from the
3029+-- second one. This would work for immutable arrays as well because an
3030+-- immutable array never has additional space so a new array is allocated
3031+-- instead of mutating it.
3032+
3033+{-# INLINE_NORMAL compactLeAs #-}
3034+compactLeAs :: forall m a. (MonadIO m, Unbox a)
3035+ => PinnedState -> Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
3036+compactLeAs ps maxElems (D.Stream step state) =
3037+ D.Stream step' (SpliceInitial state)
3038+
3039+ where
3040+
3041+ maxBytes = maxElems * SIZE_OF(a)
3042+
3043+ functionName = "Streamly.Internal.Data.MutArray.rCompactLE"
3044+
3045+ {-# INLINE_LATE step' #-}
3046+ step' gst (SpliceInitial st) = do
3047+ when (maxElems <= 0) $
3048+ -- XXX we can pass the module string from the higher level API
3049+ error $ functionName ++ ": the size of arrays [" ++ show maxElems
3050+ ++ "] must be a natural number"
3051+ r <- step gst st
3052+ case r of
3053+ D.Yield arr s -> return $
3054+ let len = byteLength arr
3055+ in if len >= maxBytes
3056+ then D.Skip (SpliceYielding arr (SpliceInitial s))
3057+ else D.Skip (SpliceBuffering s arr)
3058+ D.Skip s -> return $ D.Skip (SpliceInitial s)
3059+ D.Stop -> return D.Stop
3060+
3061+ -- XXX Split the last array to use the space more compactly.
3062+ step' gst (SpliceBuffering st buf) = do
3063+ r <- step gst st
3064+ case r of
3065+ D.Yield arr s -> do
3066+ let len = byteLength buf + byteLength arr
3067+ if len > maxBytes
3068+ then return $
3069+ D.Skip (SpliceYielding buf (SpliceBuffering s arr))
3070+ else do
3071+ buf1 <- if byteCapacity buf < maxBytes
3072+ then liftIO $ reallocExplicitAs
3073+ ps (SIZE_OF(a)) maxBytes buf
3074+ else return buf
3075+ buf2 <- spliceUnsafe buf1 arr
3076+ return $ D.Skip (SpliceBuffering s buf2)
3077+ D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
3078+ D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
3079+
3080+ step' _ SpliceFinish = return D.Stop
3081+
3082+ step' _ (SpliceYielding arr next) = return $ D.Yield arr next
3083+
3084+
3085+{-# INLINE_NORMAL fCompactGeAs #-}
3086+fCompactGeAs ::
3087+ forall m a. (MonadIO m, Unbox a)
3088+ => PinnedState -> Int -> FL.Fold m (MutArray a) (MutArray a)
3089+fCompactGeAs ps minElems = Fold step initial extract extract
3090+
3091+ where
3092+
3093+ minBytes = minElems * SIZE_OF(a)
3094+
3095+ functionName = "Streamly.Internal.Data.MutArray.fCompactGE"
3096+
3097+ initial =
3098+ return
3099+ $ if minElems < 0
3100+ then error
3101+ $ functionName
3102+ ++ ": the size of arrays ["
3103+ ++ show minElems ++ "] must be a natural number"
3104+ else FL.Partial Nothing
3105+
3106+ step Nothing arr =
3107+ return
3108+ $ let len = byteLength arr
3109+ in if len >= minBytes
3110+ then FL.Done arr
3111+ else FL.Partial (Just arr)
3112+ -- XXX Buffer arrays as a list to avoid copy and reallocations
3113+ step (Just buf) arr = do
3114+ let len = byteLength buf + byteLength arr
3115+ buf1 <-
3116+ if byteCapacity buf < len
3117+ then liftIO $ reallocExplicitAs
3118+ ps (SIZE_OF(a)) (max minBytes len) buf
3119+ else return buf
3120+ buf2 <- spliceUnsafe buf1 arr
3121+ if len >= minBytes
3122+ then return $ FL.Done buf2
3123+ else return $ FL.Partial (Just buf2)
3124+
3125+ extract Nothing = return nil
3126+ extract (Just buf) = return buf
3127+
3128+-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
3129+-- until the size becomes greater than or equal to @minElems@.
3130+--
3131+-- Generates unpinned arrays irrespective of the pinning status of input
3132+-- arrays.
3133+{-# INLINE fCompactGE #-}
3134+fCompactGE ::
3135+ forall m a. (MonadIO m, Unbox a)
3136+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3137+fCompactGE = fCompactGeAs Unpinned
3138+
3139+-- | Pinned version of 'fCompactGE'.
3140+{-# INLINE fPinnedCompactGE #-}
3141+fPinnedCompactGE ::
3142+ forall m a. (MonadIO m, Unbox a)
3143+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3144+fPinnedCompactGE = fCompactGeAs Pinned
3145+
3146+{-# INLINE_NORMAL lCompactGeAs #-}
3147+lCompactGeAs :: forall m a. (MonadIO m, Unbox a)
3148+ => PinnedState -> Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3149+-- The fold version turns out to be a little bit slower.
3150+-- lCompactGeAs ps n = FL.many (fCompactGeAs ps n)
3151+lCompactGeAs ps minElems (Fold step1 initial1 _ final1) =
3152+ Fold step initial extract final
3153+
3154+ where
3155+
3156+ minBytes = minElems * SIZE_OF(a)
3157+
3158+ functionName = "Streamly.Internal.Data.MutArray.lCompactGE"
3159+
3160+ initial = do
3161+ when (minElems <= 0) $
3162+ -- XXX we can pass the module string from the higher level API
3163+ error $ functionName ++ ": the size of arrays ["
3164+ ++ show minElems ++ "] must be a natural number"
3165+
3166+ r <- initial1
3167+ return $ first (Tuple' Nothing) r
3168+
3169+ {-# INLINE runInner #-}
3170+ runInner len acc buf =
3171+ if len >= minBytes
3172+ then do
3173+ r <- step1 acc buf
3174+ case r of
3175+ FL.Done _ -> return $ FL.Done ()
3176+ FL.Partial s -> do
3177+ _ <- final1 s
3178+ res <- initial1
3179+ return $ first (Tuple' Nothing) res
3180+ else return $ FL.Partial $ Tuple' (Just buf) acc
3181+
3182+ step (Tuple' Nothing r1) arr =
3183+ runInner (byteLength arr) r1 arr
3184+
3185+ -- XXX Buffer arrays as a list to avoid copy and reallocations
3186+ step (Tuple' (Just buf) r1) arr = do
3187+ let len = byteLength buf + byteLength arr
3188+ buf1 <- if byteCapacity buf < len
3189+ then liftIO $ reallocExplicitAs
3190+ ps (SIZE_OF(a)) (max minBytes len) buf
3191+ else return buf
3192+ buf2 <- spliceUnsafe buf1 arr
3193+ runInner len r1 buf2
3194+
3195+ -- XXX Several folds do extract >=> final, therefore, we need to make final
3196+ -- return "m b" rather than using extract post it if we want extract to be
3197+ -- partial.
3198+ --
3199+ -- extract forces the pending buffer to be sent to the fold which is not
3200+ -- what we want.
3201+ extract _ = error "lCompactGE: not designed for scanning"
3202+
3203+ final (Tuple' Nothing r1) = final1 r1
3204+ final (Tuple' (Just buf) r1) = do
3205+ r <- step1 r1 buf
3206+ case r of
3207+ FL.Partial rr -> final1 rr
3208+ FL.Done _ -> return ()
3209+
3210+-- | Like 'compactGE' but for transforming folds instead of stream.
3211+--
3212+-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
3213+--
3214+-- Generates unpinned arrays irrespective of the pinning status of input
3215+-- arrays.
3216+{-# INLINE lCompactGE #-}
3217+lCompactGE :: forall m a. (MonadIO m, Unbox a)
3218+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3219+lCompactGE = lCompactGeAs Unpinned
3220+
3221+-- | Pinned version of 'lCompactGE'.
3222+{-# INLINE lPinnedCompactGE #-}
3223+lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a)
3224+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3225+lPinnedCompactGE = lCompactGeAs Pinned
3226+
3227+-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
3228+-- the size becomes greater than or equal to @n@.
3229+--
3230+-- >>> compactGE n = Stream.foldMany (MutArray.fCompactGE n)
3231+--
3232+{-# INLINE compactGE #-}
3233+compactGE ::
3234+ (MonadIO m, Unbox a)
3235+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3236+compactGE n = D.foldMany (fCompactGE n)
3237+
3238+-- | 'compactEQ n' coalesces adajacent arrays in the input stream to
3239+-- arrays of exact size @n@.
3240+--
3241+-- /Unimplemented/
3242+{-# INLINE compactEQ #-}
3243+compactEQ :: -- (MonadIO m, Unbox a) =>
3244+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3245+compactEQ _n = undefined -- D.parseManyD (pCompactEQ n)
2392
3246
2393-------------------------------------------------------------------------------
3247-------------------------------------------------------------------------------
2394−-- NFData
3248+-- In-place mutation algorithms
2395-------------------------------------------------------------------------------
3249-------------------------------------------------------------------------------
2396
3250
2397-- | Strip elements which match with predicate from both ends.
3251-- | Strip elements which match with predicate from both ends.
@@ -2420,7 +3274,7 @@ strip eq arr@MutArray{..} = liftIO $ do
2420 getStart cur = do
3274 getStart cur = do
2421 if cur < arrEnd
3275 if cur < arrEnd
2422 then do
3276 then do
2423− r <- peekByteIndex cur arrContents
3277+ r <- peekAt cur arrContents
2424 if eq r
3278 if eq r
2425 then getStart (INDEX_NEXT(cur,a))
3279 then getStart (INDEX_NEXT(cur,a))
2426 else return cur
3280 else return cur
@@ -2430,7 +3284,7 @@ strip eq arr@MutArray{..} = liftIO $ do
2430 if cur > low
3284 if cur > low
2431 then do
3285 then do
2432 let prev = INDEX_PREV(cur,a)
3286 let prev = INDEX_PREV(cur,a)
2433− r <- peekByteIndex prev arrContents
3287+ r <- peekAt prev arrContents
2434 if eq r
3288 if eq r
2435 then getLast prev low
3289 then getLast prev low
2436 else return cur
3290 else return cur
core/src/Streamly/Internal/Data/MutByteArray.hsnew file+251
@@ -0,0 +1,251 @@
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.hsnew file+321
@@ -0,0 +1,321 @@
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+122−117
@@ -10,6 +10,9 @@
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+ --
13 -- $setup
16 -- $setup
14
17
15 module Streamly.Internal.Data.Parser.Type
18 module Streamly.Internal.Data.Parser.Type
@@ -281,7 +284,7 @@ import Prelude hiding
281--
284--
282{-# INLINE toFold #-}
285{-# INLINE toFold #-}
283toFold :: Monad m => Parser a m b -> Fold m a b
286toFold :: Monad m => Parser a m b -> Fold m a b
284−toFold (Parser pstep pinitial pextract) = Fold step initial extract
287+toFold (Parser pstep pinitial pextract) = Fold step initial extract final
285
288
286 where
289 where
287
290
@@ -309,7 +312,9 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract
309 Done n _ -> derror n
312 Done n _ -> derror n
310 Error err -> eerror err
313 Error err -> eerror err
311
314
315+ extract = error "toFold: parser cannot be used for scanning"
316+
312− extract st = do
317+ final st = do
313 r <- pextract st
318 r <- pextract st
314 case r of
319 case r of
315 Done 0 b -> return b
320 Done 0 b -> return b
@@ -327,7 +332,7 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract
327--
332--
328{-# INLINE fromFold #-}
333{-# INLINE fromFold #-}
329fromFold :: Monad m => Fold m a b -> Parser a m b
334fromFold :: Monad m => Fold m a b -> Parser a m b
330−fromFold (Fold fstep finitial fextract) = Parser step initial extract
335+fromFold (Fold fstep finitial _ ffinal) = Parser step initial extract
331
336
332 where
337 where
333
338
@@ -345,7 +350,7 @@ fromFold (Fold fstep finitial fextract) = Parser step initial extract
345 FL.Partial s1 -> Partial 0 s1
350 FL.Partial s1 -> Partial 0 s1
346 FL.Done b -> Done 0 b
351 FL.Done b -> Done 0 b
347
352
348− extract = fmap (Done 0) . fextract
353+ extract = fmap (Done 0) . ffinal
349
354
350-- | Convert a Maybe returning fold to an error returning parser. The first
355-- | Convert a Maybe returning fold to an error returning parser. The first
351-- argument is the error message that the parser would return when the fold
356-- argument is the error message that the parser would return when the fold
@@ -355,7 +360,7 @@ fromFold (Fold fstep finitial fextract) = Parser step initial extract
355--
360--
356{-# INLINE fromFoldMaybe #-}
361{-# INLINE fromFoldMaybe #-}
357fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
362fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
358−fromFoldMaybe errMsg (Fold fstep finitial fextract) =
363+fromFoldMaybe errMsg (Fold fstep finitial _ ffinal) =
359 Parser step initial extract
364 Parser step initial extract
360
365
361 where
366 where
@@ -381,7 +386,7 @@ fromFoldMaybe errMsg (Fold fstep finitial fextract) =
381 Nothing -> Error errMsg
386 Nothing -> Error errMsg
382
387
383 extract s = do
388 extract s = do
384− res <- fextract s
389+ res <- ffinal s
385 case res of
390 case res of
386 Just x -> return $ Done 0 x
391 Just x -> return $ Done 0 x
387 Nothing -> return $ Error errMsg
392 Nothing -> return $ Error errMsg
@@ -630,7 +635,7 @@ data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
630--
635--
631{-# INLINE takeBetween #-}
636{-# INLINE takeBetween #-}
632takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
637takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
633−takeBetween low high (Fold fstep finitial fextract) =
638+takeBetween low high (Fold fstep finitial _ ffinal) =
634
639
635 Parser step initial (extract streamErr)
640 Parser step initial (extract streamErr)
636
641
@@ -685,7 +690,7 @@ takeBetween low high (Fold fstep finitial fextract) =
685 then return $ Continue 0 s1
690 then return $ Continue 0 s1
686 else if i1 < high
691 else if i1 < high
687 then return $ Partial 0 s1
692 then return $ Partial 0 s1
688− else fmap (Done 0) (fextract s)
693+ else fmap (Done 0) (ffinal s)
689 FL.Done b ->
694 FL.Done b ->
690 return
695 return
691 $ if i1 >= low
696 $ if i1 >= low
@@ -695,12 +700,12 @@ takeBetween low high (Fold fstep finitial fextract) =
695 step (Tuple'Fused i s) a = fstep s a >>= snext i
700 step (Tuple'Fused i s) a = fstep s a >>= snext i
696
701
697 extract f (Tuple'Fused i s)
702 extract f (Tuple'Fused i s)
698− | i >= low && i <= high = fmap (Done 0) (fextract s)
703+ | i >= low && i <= high = fmap (Done 0) (ffinal s)
699 | otherwise = return $ Error (f i)
704 | otherwise = return $ Error (f i)
700
705
701 -- XXX Need to make Initial return type Step to deduplicate this
706 -- XXX Need to make Initial return type Step to deduplicate this
702 iextract f (Tuple'Fused i s)
707 iextract f (Tuple'Fused i s)
703− | i >= low && i <= high = fmap IDone (fextract s)
708+ | i >= low && i <= high = fmap IDone (ffinal s)
704 | otherwise = return $ IError (f i)
709 | otherwise = return $ IError (f i)
705
710
706-- | Stops after taking exactly @n@ input elements.
711-- | Stops after taking exactly @n@ input elements.
@@ -717,7 +722,7 @@ takeBetween low high (Fold fstep finitial fextract) =
717--
722--
718{-# INLINE takeEQ #-}
723{-# INLINE takeEQ #-}
719takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
724takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
720−takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
725+takeEQ n (Fold fstep finitial _ ffinal) = Parser step initial extract
721
726
722 where
727 where
723
728
@@ -727,7 +732,7 @@ takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
727 FL.Partial s ->
732 FL.Partial s ->
728 if n > 0
733 if n > 0
729 then return $ IPartial $ Tuple'Fused 1 s
734 then return $ IPartial $ Tuple'Fused 1 s
730− else fmap IDone (fextract s)
735+ else fmap IDone (ffinal s)
731 FL.Done b -> return $
736 FL.Done b -> return $
732 if n > 0
737 if n > 0
733 then IError
738 then IError
@@ -751,7 +756,7 @@ takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
751 -- assert (n == i1)
756 -- assert (n == i1)
752 Done 0
757 Done 0
753 <$> case res of
758 <$> case res of
754− FL.Partial s -> fextract s
759+ FL.Partial s -> ffinal s
755 FL.Done b -> return b
760 FL.Done b -> return b
756
761
757 extract (Tuple'Fused i _) =
762 extract (Tuple'Fused i _) =
@@ -783,7 +788,7 @@ data TakeGEState s =
783--
788--
784{-# INLINE takeGE #-}
789{-# INLINE takeGE #-}
785takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
790takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
786−takeGE n (Fold fstep finitial fextract) = Parser step initial extract
791+takeGE n (Fold fstep finitial _ ffinal) = Parser step initial extract
787
792
788 where
793 where
789
794
@@ -831,7 +836,7 @@ takeGE n (Fold fstep finitial fextract) = Parser step initial extract
831 $ Error
836 $ Error
832 $ "takeGE: Expecting at least " ++ show n
837 $ "takeGE: Expecting at least " ++ show n
833 ++ " elements, input terminated on " ++ show (i - 1)
838 ++ " elements, input terminated on " ++ show (i - 1)
834− extract (TakeGEGE r) = fmap (Done 0) $ fextract r
839+ extract (TakeGEGE r) = fmap (Done 0) $ ffinal r
835
840
836-------------------------------------------------------------------------------
841-------------------------------------------------------------------------------
837-- Conditional splitting
842-- Conditional splitting
@@ -892,7 +897,7 @@ takeWhileP predicate (Parser pstep pinitial pextract) =
892{-# INLINE takeWhile #-}
897{-# INLINE takeWhile #-}
893takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
898takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
894-- takeWhile cond f = takeWhileP cond (fromFold f)
899-- takeWhile cond f = takeWhileP cond (fromFold f)
895−takeWhile predicate (Fold fstep finitial fextract) =
900+takeWhile predicate (Fold fstep finitial _ ffinal) =
896 Parser step initial extract
901 Parser step initial extract
897
902
898 where
903 where
@@ -911,9 +916,9 @@ takeWhile predicate (Fold fstep finitial fextract) =
911 $ case fres of
916 $ case fres of
912 FL.Partial s1 -> Partial 0 s1
917 FL.Partial s1 -> Partial 0 s1
913 FL.Done b -> Done 0 b
918 FL.Done b -> Done 0 b
914− else Done 1 <$> fextract s
919+ else Done 1 <$> ffinal s
915
920
916− extract s = fmap (Done 0) (fextract s)
921+ extract s = fmap (Done 0) (ffinal s)
917
922
918{-
923{-
919-- XXX This may not be composable because of the b argument. We can instead
924-- XXX This may not be composable because of the b argument. We can instead
@@ -933,7 +938,7 @@ takeWhile1 acc cond f = undefined
933{-# INLINE takeWhile1 #-}
938{-# INLINE takeWhile1 #-}
934takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
939takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
935-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
940-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
936−takeWhile1 predicate (Fold fstep finitial fextract) =
941+takeWhile1 predicate (Fold fstep finitial _ ffinal) =
937 Parser step initial extract
942 Parser step initial extract
938
943
939 where
944 where
@@ -963,11 +968,11 @@ takeWhile1 predicate (Fold fstep finitial fextract) =
963 if predicate a
968 if predicate a
964 then process s a
969 then process s a
965 else do
970 else do
966− b <- fextract s
971+ b <- ffinal s
967 return $ Done 1 b
972 return $ Done 1 b
968
973
969 extract (Left' _) = return $ Error "takeWhile1: end of input"
974 extract (Left' _) = return $ Error "takeWhile1: end of input"
970− extract (Right' s) = fmap (Done 0) (fextract s)
975+ extract (Right' s) = fmap (Done 0) (ffinal s)
971
976
972-- | Drain the input as long as the predicate succeeds, running the effects and
977-- | Drain the input as long as the predicate succeeds, running the effects and
973-- discarding the results.
978-- discarding the results.
@@ -996,7 +1001,7 @@ takeFramedByGeneric :: Monad m =>
996 -> Maybe (a -> Bool) -- is frame end?
1001 -> Maybe (a -> Bool) -- is frame end?
997 -> Fold m a b
1002 -> Fold m a b
998 -> Parser a m b
1003 -> Parser a m b
999−takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
1004+takeFramedByGeneric esc begin end (Fold fstep finitial _ ffinal) =
1000
1005
1001 Parser step initial extract
1006 Parser step initial extract
1002
1007
@@ -1028,20 +1033,20 @@ takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
1028 if isEnd a
1033 if isEnd a
1029 then
1034 then
1030 if n == 0
1035 if n == 0
1031− then Done 0 <$> fextract s
1036+ then Done 0 <$> ffinal s
1032 else process s a (n - 1)
1037 else process s a (n - 1)
1033 else
1038 else
1034 let n1 = if isBegin a then n + 1 else n
1039 let n1 = if isBegin a then n + 1 else n
1035 in process s a n1
1040 in process s a n1
1036 Nothing -> -- takeEndBy case
1041 Nothing -> -- takeEndBy case
1037 if isEnd a
1042 if isEnd a
1038− then Done 0 <$> fextract s
1043+ then Done 0 <$> ffinal s
1039 else process s a n
1044 else process s a n
1040 Nothing -> -- takeStartBy case
1045 Nothing -> -- takeStartBy case
1041 case begin of
1046 case begin of
1042 Just isBegin ->
1047 Just isBegin ->
1043 if isBegin a
1048 if isBegin a
1044− then Done 0 <$> fextract s
1049+ then Done 0 <$> ffinal s
1045 else process s a n
1050 else process s a n
1046 Nothing ->
1051 Nothing ->
1047 error $ "takeFramedByGeneric: "
1052 error $ "takeFramedByGeneric: "
@@ -1066,7 +1071,7 @@ takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
1066 case end of
1071 case end of
1067 Just isEnd ->
1072 Just isEnd ->
1068 if isEnd a
1073 if isEnd a
1069− then Done 0 <$> fextract s
1074+ then Done 0 <$> ffinal s
1070 else processCheckEsc s a 0
1075 else processCheckEsc s a 0
1071 Nothing ->
1076 Nothing ->
1072 error "Both begin and end frame predicate missing"
1077 error "Both begin and end frame predicate missing"
@@ -1081,7 +1086,7 @@ takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
1081 case begin of
1086 case begin of
1082 Just _ ->
1087 Just _ ->
1083 case end of
1088 case end of
1084− Nothing -> fmap (Done 0) $ fextract s
1089+ Nothing -> fmap (Done 0) $ ffinal s
1085 Just _ -> err "takeFramedByGeneric: missing frame end"
1090 Just _ -> err "takeFramedByGeneric: missing frame end"
1086 Nothing -> err "takeFramedByGeneric: missing closing frame"
1091 Nothing -> err "takeFramedByGeneric: missing closing frame"
1087 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
1092 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
@@ -1120,7 +1125,7 @@ blockWithQuotes :: (Monad m, Eq a) =>
1120 -> Fold m a b
1125 -> Fold m a b
1121 -> Parser a m b
1126 -> Parser a m b
1122blockWithQuotes isEsc isQuote bopen bclose
1127blockWithQuotes isEsc isQuote bopen bclose
1123− (Fold fstep finitial fextract) =
1128+ (Fold fstep finitial _ ffinal) =
1124 Parser step initial extract
1129 Parser step initial extract
1125
1130
1126 where
1131 where
@@ -1150,7 +1155,7 @@ blockWithQuotes isEsc isQuote bopen bclose
1150 | a == bopen = process s a (BlockUnquoted (level + 1))
1155 | a == bopen = process s a (BlockUnquoted (level + 1))
1151 | a == bclose =
1156 | a == bclose =
1152 if level == 1
1157 if level == 1
1153− then fmap (Done 0) (fextract s)
1158+ then fmap (Done 0) (ffinal s)
1154 else process s a (BlockUnquoted (level - 1))
1159 else process s a (BlockUnquoted (level - 1))
1155 | isQuote a = process s a (BlockQuoted level)
1160 | isQuote a = process s a (BlockQuoted level)
1156 | otherwise = process s a (BlockUnquoted level)
1161 | otherwise = process s a (BlockUnquoted level)
@@ -1164,7 +1169,7 @@ blockWithQuotes isEsc isQuote bopen bclose
1164
1169
1165 err = return . Error
1170 err = return . Error
1166
1171
1167− extract (BlockInit s) = fmap (Done 0) $ fextract s
1172+ extract (BlockInit s) = fmap (Done 0) $ ffinal s
1168 extract (BlockUnquoted level _) =
1173 extract (BlockUnquoted level _) =
1169 err $ "blockWithQuotes: finished at block nest level " ++ show level
1174 err $ "blockWithQuotes: finished at block nest level " ++ show level
1170 extract (BlockQuoted level _) =
1175 extract (BlockQuoted level _) =
@@ -1299,7 +1304,7 @@ takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
1299--
1304--
1300{-# INLINE takeStartBy #-}
1305{-# INLINE takeStartBy #-}
1301takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1306takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1302−takeStartBy cond (Fold fstep finitial fextract) =
1307+takeStartBy cond (Fold fstep finitial _ ffinal) =
1303
1308
1304 Parser step initial extract
1309 Parser step initial extract
1305
1310
@@ -1327,10 +1332,10 @@ takeStartBy cond (Fold fstep finitial fextract) =
1327 step (Right' s) a =
1332 step (Right' s) a =
1328 if not (cond a)
1333 if not (cond a)
1329 then process s a
1334 then process s a
1330− else Done 1 <$> fextract s
1335+ else Done 1 <$> ffinal s
1331
1336
1332− extract (Left' s) = fmap (Done 0) $ fextract s
1337+ extract (Left' s) = fmap (Done 0) $ ffinal s
1333− extract (Right' s) = fmap (Done 0) $ fextract s
1338+ extract (Right' s) = fmap (Done 0) $ ffinal s
1334
1339
1335-- | Like 'takeStartBy' but drops the separator.
1340-- | Like 'takeStartBy' but drops the separator.
1336--
1341--
@@ -1366,7 +1371,7 @@ takeFramedByEsc_ :: Monad m =>
1366 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1371 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1367-- takeFramedByEsc_ isEsc isEnd p =
1372-- takeFramedByEsc_ isEsc isEnd p =
1368-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
1373-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
1369−takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial fextract) =
1374+takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial _ ffinal ) =
1370
1375
1371 Parser step initial extract
1376 Parser step initial extract
1372
1377
@@ -1402,7 +1407,7 @@ takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial fextract) =
1402 in process s a n1
1407 in process s a n1
1403 else
1408 else
1404 if n == 0
1409 if n == 0
1405− then Done 0 <$> fextract s
1410+ then Done 0 <$> ffinal s
1406 else process s a (n - 1)
1411 else process s a (n - 1)
1407 step (FrameEscEsc s n) a = process s a n
1412 step (FrameEscEsc s n) a = process s a n
1408
1413
@@ -1424,7 +1429,7 @@ takeFramedBy_ :: Monad m =>
1424 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1429 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1425-- takeFramedBy_ isBegin isEnd =
1430-- takeFramedBy_ isBegin isEnd =
1426-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
1431-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
1427−takeFramedBy_ isBegin isEnd (Fold fstep finitial fextract) =
1432+takeFramedBy_ isBegin isEnd (Fold fstep finitial _ ffinal) =
1428
1433
1429 Parser step initial extract
1434 Parser step initial extract
1430
1435
@@ -1454,7 +1459,7 @@ takeFramedBy_ isBegin isEnd (Fold fstep finitial fextract) =
1454 | not (isEnd a) =
1459 | not (isEnd a) =
1455 let n1 = if isBegin a then n + 1 else n
1460 let n1 = if isBegin a then n + 1 else n
1456 in process s a n1
1461 in process s a n1
1457− | n == 0 = Done 0 <$> fextract s
1462+ | n == 0 = Done 0 <$> ffinal s
1458 | otherwise = process s a (n - 1)
1463 | otherwise = process s a (n - 1)
1459
1464
1460 err = return . Error
1465 err = return . Error
@@ -1489,7 +1494,7 @@ data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
1489--
1494--
1490{-# INLINE wordBy #-}
1495{-# INLINE wordBy #-}
1491wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1496wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1492−wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
1497+wordBy predicate (Fold fstep finitial _ ffinal) = Parser step initial extract
1493
1498
1494 where
1499 where
1495
1500
@@ -1516,7 +1521,7 @@ wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
1516 if not (predicate a)
1521 if not (predicate a)
1517 then worder s a
1522 then worder s a
1518 else do
1523 else do
1519− b <- fextract s
1524+ b <- ffinal s
1520 return $ Partial 0 $ WBRight b
1525 return $ Partial 0 $ WBRight b
1521 step (WBRight b) a =
1526 step (WBRight b) a =
1522 return
1527 return
@@ -1524,8 +1529,8 @@ wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
1524 then Done 1 b
1529 then Done 1 b
1525 else Partial 0 $ WBRight b
1530 else Partial 0 $ WBRight b
1526
1531
1527− extract (WBLeft s) = fmap (Done 0) $ fextract s
1532+ extract (WBLeft s) = fmap (Done 0) $ ffinal s
1528− extract (WBWord s) = fmap (Done 0) $ fextract s
1533+ extract (WBWord s) = fmap (Done 0) $ ffinal s
1529 extract (WBRight b) = return (Done 0 b)
1534 extract (WBRight b) = return (Done 0 b)
1530
1535
1531data WordFramedState s b =
1536data WordFramedState s b =
@@ -1562,7 +1567,7 @@ wordFramedBy :: Monad m =>
1562 -> Fold m a b
1567 -> Fold m a b
1563 -> Parser a m b
1568 -> Parser a m b
1564wordFramedBy isEsc isBegin isEnd isSep
1569wordFramedBy isEsc isBegin isEnd isSep
1565− (Fold fstep finitial fextract) =
1570+ (Fold fstep finitial _ ffinal) =
1566 Parser step initial extract
1571 Parser step initial extract
1567
1572
1568 where
1573 where
@@ -1593,7 +1598,7 @@ wordFramedBy isEsc isBegin isEnd isSep
1593 step (WordFramedWord s n) a
1598 step (WordFramedWord s n) a
1594 | isEsc a = return $ Continue 0 $ WordFramedEsc s n
1599 | isEsc a = return $ Continue 0 $ WordFramedEsc s n
1595 | n == 0 && isSep a = do
1600 | n == 0 && isSep a = do
1596− b <- fextract s
1601+ b <- ffinal s
1597 return $ Partial 0 $ WordFramedSkipPost b
1602 return $ Partial 0 $ WordFramedSkipPost b
1598 | otherwise = do
1603 | otherwise = do
1599 -- We need to use different order for checking begin and end for
1604 -- We need to use different order for checking begin and end for
@@ -1626,10 +1631,10 @@ wordFramedBy isEsc isBegin isEnd isSep
1626
1631
1627 err = return . Error
1632 err = return . Error
1628
1633
1629− extract (WordFramedSkipPre s) = fmap (Done 0) $ fextract s
1634+ extract (WordFramedSkipPre s) = fmap (Done 0) $ ffinal s
1630 extract (WordFramedWord s n) =
1635 extract (WordFramedWord s n) =
1631 if n == 0
1636 if n == 0
1632− then fmap (Done 0) $ fextract s
1637+ then fmap (Done 0) $ ffinal s
1633 else err "wordFramedBy: missing frame end"
1638 else err "wordFramedBy: missing frame end"
1634 extract (WordFramedEsc _ _) =
1639 extract (WordFramedEsc _ _) =
1635 err "wordFramedBy: trailing escape"
1640 err "wordFramedBy: trailing escape"
@@ -1716,7 +1721,7 @@ wordWithQuotes :: (Monad m, Eq a) =>
1716 -> Fold m a b
1721 -> Fold m a b
1717 -> Parser a m b
1722 -> Parser a m b
1718wordWithQuotes keepQuotes tr escChar toRight isSep
1723wordWithQuotes keepQuotes tr escChar toRight isSep
1719− (Fold fstep finitial fextract) =
1724+ (Fold fstep finitial _ ffinal) =
1720 Parser step initial extract
1725 Parser step initial extract
1721
1726
1722 where
1727 where
@@ -1767,7 +1772,7 @@ wordWithQuotes keepQuotes tr escChar toRight isSep
1767 step (WordUnquotedWord s) a
1772 step (WordUnquotedWord s) a
1768 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1773 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1769 | isSep a = do
1774 | isSep a = do
1770− b <- fextract s
1775+ b <- ffinal s
1771 return $ Partial 0 $ WordQuotedSkipPost b
1776 return $ Partial 0 $ WordQuotedSkipPost b
1772 | otherwise = do
1777 | otherwise = do
1773 case toRight a of
1778 case toRight a of
@@ -1815,11 +1820,11 @@ wordWithQuotes keepQuotes tr escChar toRight isSep
1815
1820
1816 err = return . Error
1821 err = return . Error
1817
1822
1818− extract (WordQuotedSkipPre s) = fmap (Done 0) $ fextract s
1823+ extract (WordQuotedSkipPre s) = fmap (Done 0) $ ffinal s
1819− extract (WordUnquotedWord s) = fmap (Done 0) $ fextract s
1824+ extract (WordUnquotedWord s) = fmap (Done 0) $ ffinal s
1820 extract (WordQuotedWord s n _ _) =
1825 extract (WordQuotedWord s n _ _) =
1821 if n == 0
1826 if n == 0
1822− then fmap (Done 0) $ fextract s
1827+ then fmap (Done 0) $ ffinal s
1823 else err "wordWithQuotes: missing frame end"
1828 else err "wordWithQuotes: missing frame end"
1824 extract WordQuotedEsc {} =
1829 extract WordQuotedEsc {} =
1825 err "wordWithQuotes: trailing escape"
1830 err "wordWithQuotes: trailing escape"
@@ -1897,7 +1902,7 @@ data GroupByState a s
1897--
1902--
1898{-# INLINE groupBy #-}
1903{-# INLINE groupBy #-}
1899groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1904groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1900−groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
1905+groupBy eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1901
1906
1902 where
1907 where
1903
1908
@@ -1920,10 +1925,10 @@ groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
1920 step (GroupByGrouping a0 s) a =
1925 step (GroupByGrouping a0 s) a =
1921 if eq a0 a
1926 if eq a0 a
1922 then grouper s a0 a
1927 then grouper s a0 a
1923− else Done 1 <$> fextract s
1928+ else Done 1 <$> ffinal s
1924
1929
1925− extract (GroupByInit s) = fmap (Done 0) $ fextract s
1930+ extract (GroupByInit s) = fmap (Done 0) $ ffinal s
1926− extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
1931+ extract (GroupByGrouping _ s) = fmap (Done 0) $ ffinal s
1927
1932
1928-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
1933-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
1929-- successive elements in the input stream. Assuming the input stream
1934-- successive elements in the input stream. Assuming the input stream
@@ -1957,7 +1962,7 @@ groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
1957--
1962--
1958{-# INLINE groupByRolling #-}
1963{-# INLINE groupByRolling #-}
1959groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1964groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1960−groupByRolling eq (Fold fstep finitial fextract) = Parser step initial extract
1965+groupByRolling eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1961
1966
1962 where
1967 where
1963
1968
@@ -1980,10 +1985,10 @@ groupByRolling eq (Fold fstep finitial fextract) = Parser step initial extract
1980 step (GroupByGrouping a0 s) a =
1985 step (GroupByGrouping a0 s) a =
1981 if eq a0 a
1986 if eq a0 a
1982 then grouper s a
1987 then grouper s a
1983− else Done 1 <$> fextract s
1988+ else Done 1 <$> ffinal s
1984
1989
1985− extract (GroupByInit s) = fmap (Done 0) $ fextract s
1990+ extract (GroupByInit s) = fmap (Done 0) $ ffinal s
1986− extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
1991+ extract (GroupByGrouping _ s) = fmap (Done 0) $ ffinal s
1987
1992
1988{-# ANN type GroupByStatePair Fuse #-}
1993{-# ANN type GroupByStatePair Fuse #-}
1989data GroupByStatePair a s1 s2
1994data GroupByStatePair a s1 s2
@@ -2007,8 +2012,8 @@ groupByRollingEither :: Monad m =>
2007 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
2012 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
2008groupByRollingEither
2013groupByRollingEither
2009 eq
2014 eq
2010− (Fold fstep1 finitial1 fextract1)
2015+ (Fold fstep1 finitial1 _ ffinal1)
2011− (Fold fstep2 finitial2 fextract2) = Parser step initial extract
2016+ (Fold fstep2 finitial2 _ ffinal2) = Parser step initial extract
2012
2017
2013 where
2018 where
2014
2019
@@ -2067,21 +2072,21 @@ groupByRollingEither
2067 step (GroupByGroupingPairL a0 s1 s2) a =
2072 step (GroupByGroupingPairL a0 s1 s2) a =
2068 if not (eq a0 a)
2073 if not (eq a0 a)
2069 then grouperL2 s1 s2 a
2074 then grouperL2 s1 s2 a
2070− else Done 1 . Left <$> fextract1 s1
2075+ else Done 1 . Left <$> ffinal1 s1
2071
2076
2072 step (GroupByGroupingPairR a0 s1 s2) a =
2077 step (GroupByGroupingPairR a0 s1 s2) a =
2073 if eq a0 a
2078 if eq a0 a
2074 then grouperR2 s1 s2 a
2079 then grouperR2 s1 s2 a
2075− else Done 1 . Right <$> fextract2 s2
2080+ else Done 1 . Right <$> ffinal2 s2
2076
2081
2077− extract (GroupByInitPair s1 _) = Done 0 . Left <$> fextract1 s1
2082+ extract (GroupByInitPair s1 _) = Done 0 . Left <$> ffinal1 s1
2078− extract (GroupByGroupingPairL _ s1 _) = Done 0 . Left <$> fextract1 s1
2083+ extract (GroupByGroupingPairL _ s1 _) = Done 0 . Left <$> ffinal1 s1
2079− extract (GroupByGroupingPairR _ _ s2) = Done 0 . Right <$> fextract2 s2
2084+ extract (GroupByGroupingPairR _ _ s2) = Done 0 . Right <$> ffinal2 s2
2080 extract (GroupByGroupingPair a s1 _) = do
2085 extract (GroupByGroupingPair a s1 _) = do
2081 res <- fstep1 s1 a
2086 res <- fstep1 s1 a
2082 case res of
2087 case res of
2083 FL.Done b -> return $ Done 0 (Left b)
2088 FL.Done b -> return $ Done 0 (Left b)
2084− FL.Partial s11 -> Done 0 . Left <$> fextract1 s11
2089+ FL.Partial s11 -> Done 0 . Left <$> ffinal1 s11
2085
2090
2086-- XXX use an Unfold instead of a list?
2091-- XXX use an Unfold instead of a list?
2087-- XXX custom combinators for matching list, array and stream?
2092-- XXX custom combinators for matching list, array and stream?
@@ -2234,7 +2239,7 @@ postscan = undefined
2234{-# INLINE zipWithM #-}
2239{-# INLINE zipWithM #-}
2235zipWithM :: Monad m =>
2240zipWithM :: Monad m =>
2236 (a -> b -> m c) -> D.Stream m a -> Fold m c x -> Parser b m x
2241 (a -> b -> m c) -> D.Stream m a -> Fold m c x -> Parser b m x
2237−zipWithM zf (D.Stream sstep state) (Fold fstep finitial fextract) =
2242+zipWithM zf (D.Stream sstep state) (Fold fstep finitial _ ffinal) =
2238 Parser step initial extract
2243 Parser step initial extract
2239
2244
2240 where
2245 where
@@ -2247,7 +2252,7 @@ zipWithM zf (D.Stream sstep state) (Fold fstep finitial fextract) =
2247 case r of
2252 case r of
2248 D.Yield x s -> return $ IPartial (Just' x, s, fs)
2253 D.Yield x s -> return $ IPartial (Just' x, s, fs)
2249 D.Stop -> do
2254 D.Stop -> do
2250− x <- fextract fs
2255+ x <- ffinal fs
2251 return $ IDone x
2256 return $ IDone x
2252 -- Need Skip/Continue in initial to loop right here
2257 -- Need Skip/Continue in initial to loop right here
2253 D.Skip s -> return $ IPartial (Nothing', s, fs)
2258 D.Skip s -> return $ IPartial (Nothing', s, fs)
@@ -2262,7 +2267,7 @@ zipWithM zf (D.Stream sstep state) (Fold fstep finitial fextract) =
2262 case r of
2267 case r of
2263 D.Yield x1 s -> return $ Continue 0 (Just' x1, s, fs1)
2268 D.Yield x1 s -> return $ Continue 0 (Just' x1, s, fs1)
2264 D.Stop -> do
2269 D.Stop -> do
2265− x <- fextract fs1
2270+ x <- ffinal fs1
2266 return $ Done 0 x
2271 return $ Done 0 x
2267 D.Skip s -> return $ Continue 1 (Nothing', s, fs1)
2272 D.Skip s -> return $ Continue 1 (Nothing', s, fs1)
2268 FL.Done x -> return $ Done 0 x
2273 FL.Done x -> return $ Done 0 x
@@ -2277,7 +2282,7 @@ zipWithM zf (D.Stream sstep state) (Fold fstep finitial fextract) =
2277 return $ Continue 0 (Nothing', s, fs1)
2282 return $ Continue 0 (Nothing', s, fs1)
2278 FL.Done x -> return $ Done 0 x
2283 FL.Done x -> return $ Done 0 x
2279 D.Stop -> do
2284 D.Stop -> do
2280− x <- fextract fs
2285+ x <- ffinal fs
2281 return $ Done 1 x
2286 return $ Done 1 x
2282 D.Skip s -> return $ Continue 1 (Nothing', s, fs)
2287 D.Skip s -> return $ Continue 1 (Nothing', s, fs)
2283
2288
@@ -2561,7 +2566,7 @@ deintercalateAll :: Monad m =>
2561deintercalateAll
2566deintercalateAll
2562 (Parser stepL initialL extractL)
2567 (Parser stepL initialL extractL)
2563 (Parser stepR initialR _)
2568 (Parser stepR initialR _)
2564− (Fold fstep finitial fextract) = Parser step initial extract
2569+ (Fold fstep finitial _ ffinal) = Parser step initial extract
2565
2570
2566 where
2571 where
2567
2572
@@ -2632,9 +2637,9 @@ deintercalateAll
2632 extractResult n fs r = do
2637 extractResult n fs r = do
2633 res <- fstep fs r
2638 res <- fstep fs r
2634 case res of
2639 case res of
2635− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2640+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2636 FL.Done c -> return (Done n c)
2641 FL.Done c -> return (Done n c)
2637− extract (DeintercalateAllInitL fs) = fmap (Done 0) $ fextract fs
2642+ extract (DeintercalateAllInitL fs) = fmap (Done 0) $ ffinal fs
2638 extract (DeintercalateAllL fs sL) = do
2643 extract (DeintercalateAllL fs sL) = do
2639 r <- extractL sL
2644 r <- extractL sL
2640 case r of
2645 case r of
@@ -2642,7 +2647,7 @@ deintercalateAll
2642 Error err -> return $ Error err
2647 Error err -> return $ Error err
2643 Continue n s -> return $ Continue n (DeintercalateAllL fs s)
2648 Continue n s -> return $ Continue n (DeintercalateAllL fs s)
2644 Partial _ _ -> error "Partial in extract"
2649 Partial _ _ -> error "Partial in extract"
2645− extract (DeintercalateAllInitR fs) = fmap (Done 0) $ fextract fs
2650+ extract (DeintercalateAllInitR fs) = fmap (Done 0) $ ffinal fs
2646 extract (DeintercalateAllR _ _) =
2651 extract (DeintercalateAllR _ _) =
2647 return $ Error "deintercalateAll: input ended at 'Right' value"
2652 return $ Error "deintercalateAll: input ended at 'Right' value"
2648
2653
@@ -2685,7 +2690,7 @@ deintercalate :: Monad m =>
2685deintercalate
2690deintercalate
2686 (Parser stepL initialL extractL)
2691 (Parser stepL initialL extractL)
2687 (Parser stepR initialR _)
2692 (Parser stepR initialR _)
2688− (Fold fstep finitial fextract) = Parser step initial extract
2693+ (Fold fstep finitial _ ffinal) = Parser step initial extract
2689
2694
2690 where
2695 where
2691
2696
@@ -2716,7 +2721,7 @@ deintercalate
2716 Done n b ->
2721 Done n b ->
2717 processL (fstep fs (Left b)) n DeintercalateInitR
2722 processL (fstep fs (Left b)) n DeintercalateInitR
2718 Error _ -> do
2723 Error _ -> do
2719− xs <- fextract fs
2724+ xs <- ffinal fs
2720 return $ Done cnt1 xs
2725 return $ Done cnt1 xs
2721
2726
2722 {-# INLINE processR #-}
2727 {-# INLINE processR #-}
@@ -2736,7 +2741,7 @@ deintercalate
2736 Continue n s -> return $ Continue n (DeintercalateR (cnt1 - n) fs s)
2741 Continue n s -> return $ Continue n (DeintercalateR (cnt1 - n) fs s)
2737 Done n b -> processR (cnt1 - n) b fs n
2742 Done n b -> processR (cnt1 - n) b fs n
2738 Error _ -> do
2743 Error _ -> do
2739− xs <- fextract fs
2744+ xs <- ffinal fs
2740 return $ Done cnt1 xs
2745 return $ Done cnt1 xs
2741
2746
2742 step (DeintercalateInitL fs) a = do
2747 step (DeintercalateInitL fs) a = do
@@ -2771,17 +2776,17 @@ deintercalate
2771 -- XXX We could have the fold accept pairs of (bR, bL)
2776 -- XXX We could have the fold accept pairs of (bR, bL)
2772 FL.Done _ -> error "Fold terminated consuming partial input"
2777 FL.Done _ -> error "Fold terminated consuming partial input"
2773 Error _ -> do
2778 Error _ -> do
2774− xs <- fextract fs
2779+ xs <- ffinal fs
2775 return $ Done cnt1 xs
2780 return $ Done cnt1 xs
2776
2781
2777 {-# INLINE extractResult #-}
2782 {-# INLINE extractResult #-}
2778 extractResult n fs r = do
2783 extractResult n fs r = do
2779 res <- fstep fs r
2784 res <- fstep fs r
2780 case res of
2785 case res of
2781− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2786+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2782 FL.Done c -> return (Done n c)
2787 FL.Done c -> return (Done n c)
2783
2788
2784− extract (DeintercalateInitL fs) = fmap (Done 0) $ fextract fs
2789+ extract (DeintercalateInitL fs) = fmap (Done 0) $ ffinal fs
2785 extract (DeintercalateL cnt fs sL) = do
2790 extract (DeintercalateL cnt fs sL) = do
2786 r <- extractL sL
2791 r <- extractL sL
2787 case r of
2792 case r of
@@ -2789,10 +2794,10 @@ deintercalate
2789 Continue n s -> return $ Continue n (DeintercalateL (cnt - n) fs s)
2794 Continue n s -> return $ Continue n (DeintercalateL (cnt - n) fs s)
2790 Partial _ _ -> error "Partial in extract"
2795 Partial _ _ -> error "Partial in extract"
2791 Error _ -> do
2796 Error _ -> do
2792− xs <- fextract fs
2797+ xs <- ffinal fs
2793 return $ Done cnt xs
2798 return $ Done cnt xs
2794− extract (DeintercalateInitR fs) = fmap (Done 0) $ fextract fs
2799+ extract (DeintercalateInitR fs) = fmap (Done 0) $ ffinal fs
2795− extract (DeintercalateR cnt fs _) = fmap (Done cnt) $ fextract fs
2800+ extract (DeintercalateR cnt fs _) = fmap (Done cnt) $ ffinal fs
2796 extract (DeintercalateRL cnt bR fs sL) = do
2801 extract (DeintercalateRL cnt bR fs sL) = do
2797 r <- extractL sL
2802 r <- extractL sL
2798 case r of
2803 case r of
@@ -2804,7 +2809,7 @@ deintercalate
2804 Continue n s -> return $ Continue n (DeintercalateRL (cnt - n) bR fs s)
2809 Continue n s -> return $ Continue n (DeintercalateRL (cnt - n) bR fs s)
2805 Partial _ _ -> error "Partial in extract"
2810 Partial _ _ -> error "Partial in extract"
2806 Error _ -> do
2811 Error _ -> do
2807− xs <- fextract fs
2812+ xs <- ffinal fs
2808 return $ Done cnt xs
2813 return $ Done cnt xs
2809
2814
2810{-# ANN type Deintercalate1State Fuse #-}
2815{-# ANN type Deintercalate1State Fuse #-}
@@ -2841,7 +2846,7 @@ deintercalate1 :: Monad m =>
2841deintercalate1
2846deintercalate1
2842 (Parser stepL initialL extractL)
2847 (Parser stepL initialL extractL)
2843 (Parser stepR initialR _)
2848 (Parser stepR initialR _)
2844− (Fold fstep finitial fextract) = Parser step initial extract
2849+ (Fold fstep finitial _ ffinal) = Parser step initial extract
2845
2850
2846 where
2851 where
2847
2852
@@ -2895,7 +2900,7 @@ deintercalate1
2895 Continue n s -> return $ Continue n (Deintercalate1R (cnt1 - n) fs s)
2900 Continue n s -> return $ Continue n (Deintercalate1R (cnt1 - n) fs s)
2896 Done n b -> processR (cnt1 - n) b fs n
2901 Done n b -> processR (cnt1 - n) b fs n
2897 Error _ -> do
2902 Error _ -> do
2898− xs <- fextract fs
2903+ xs <- ffinal fs
2899 return $ Done cnt1 xs
2904 return $ Done cnt1 xs
2900
2905
2901 step (Deintercalate1InitL cnt fs sL) a = runStepInitL cnt fs sL a
2906 step (Deintercalate1InitL cnt fs sL) a = runStepInitL cnt fs sL a
@@ -2924,14 +2929,14 @@ deintercalate1
2924 -- XXX We could have the fold accept pairs of (bR, bL)
2929 -- XXX We could have the fold accept pairs of (bR, bL)
2925 FL.Done _ -> error "Fold terminated consuming partial input"
2930 FL.Done _ -> error "Fold terminated consuming partial input"
2926 Error _ -> do
2931 Error _ -> do
2927− xs <- fextract fs
2932+ xs <- ffinal fs
2928 return $ Done cnt1 xs
2933 return $ Done cnt1 xs
2929
2934
2930 {-# INLINE extractResult #-}
2935 {-# INLINE extractResult #-}
2931 extractResult n fs r = do
2936 extractResult n fs r = do
2932 res <- fstep fs r
2937 res <- fstep fs r
2933 case res of
2938 case res of
2934− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2939+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2935 FL.Done c -> return (Done n c)
2940 FL.Done c -> return (Done n c)
2936
2941
2937 extract (Deintercalate1InitL cnt fs sL) = do
2942 extract (Deintercalate1InitL cnt fs sL) = do
@@ -2941,8 +2946,8 @@ deintercalate1
2941 Continue n s -> return $ Continue n (Deintercalate1InitL (cnt - n) fs s)
2946 Continue n s -> return $ Continue n (Deintercalate1InitL (cnt - n) fs s)
2942 Partial _ _ -> error "Partial in extract"
2947 Partial _ _ -> error "Partial in extract"
2943 Error err -> return $ Error err
2948 Error err -> return $ Error err
2944− extract (Deintercalate1InitR fs) = fmap (Done 0) $ fextract fs
2949+ extract (Deintercalate1InitR fs) = fmap (Done 0) $ ffinal fs
2945− extract (Deintercalate1R cnt fs _) = fmap (Done cnt) $ fextract fs
2950+ extract (Deintercalate1R cnt fs _) = fmap (Done cnt) $ ffinal fs
2946 extract (Deintercalate1RL cnt bR fs sL) = do
2951 extract (Deintercalate1RL cnt bR fs sL) = do
2947 r <- extractL sL
2952 r <- extractL sL
2948 case r of
2953 case r of
@@ -2954,7 +2959,7 @@ deintercalate1
2954 Continue n s -> return $ Continue n (Deintercalate1RL (cnt - n) bR fs s)
2959 Continue n s -> return $ Continue n (Deintercalate1RL (cnt - n) bR fs s)
2955 Partial _ _ -> error "Partial in extract"
2960 Partial _ _ -> error "Partial in extract"
2956 Error _ -> do
2961 Error _ -> do
2957− xs <- fextract fs
2962+ xs <- ffinal fs
2958 return $ Done cnt xs
2963 return $ Done cnt xs
2959
2964
2960{-# ANN type SepByState Fuse #-}
2965{-# ANN type SepByState Fuse #-}
@@ -2997,7 +3002,7 @@ sepBy :: Monad m =>
2997sepBy
3002sepBy
2998 (Parser stepL initialL extractL)
3003 (Parser stepL initialL extractL)
2999 (Parser stepR initialR _)
3004 (Parser stepR initialR _)
3000− (Fold fstep finitial fextract) = Parser step initial extract
3005+ (Fold fstep finitial _ ffinal) = Parser step initial extract
3001
3006
3002 where
3007 where
3003
3008
@@ -3028,7 +3033,7 @@ sepBy
3028 Done n b ->
3033 Done n b ->
3029 processL (fstep fs b) n SepByInitR
3034 processL (fstep fs b) n SepByInitR
3030 Error _ -> do
3035 Error _ -> do
3031− xs <- fextract fs
3036+ xs <- ffinal fs
3032 return $ Done cnt1 xs
3037 return $ Done cnt1 xs
3033
3038
3034 {-# INLINE processR #-}
3039 {-# INLINE processR #-}
@@ -3048,7 +3053,7 @@ sepBy
3048 Continue n s -> return $ Continue n (SepByR (cnt1 - n) fs s)
3053 Continue n s -> return $ Continue n (SepByR (cnt1 - n) fs s)
3049 Done n _ -> processR (cnt1 - n) fs n
3054 Done n _ -> processR (cnt1 - n) fs n
3050 Error _ -> do
3055 Error _ -> do
3051− xs <- fextract fs
3056+ xs <- ffinal fs
3052 return $ Done cnt1 xs
3057 return $ Done cnt1 xs
3053
3058
3054 step (SepByInitL fs) a = do
3059 step (SepByInitL fs) a = do
@@ -3070,10 +3075,10 @@ sepBy
3070 extractResult n fs r = do
3075 extractResult n fs r = do
3071 res <- fstep fs r
3076 res <- fstep fs r
3072 case res of
3077 case res of
3073− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3078+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3074 FL.Done c -> return (Done n c)
3079 FL.Done c -> return (Done n c)
3075
3080
3076− extract (SepByInitL fs) = fmap (Done 0) $ fextract fs
3081+ extract (SepByInitL fs) = fmap (Done 0) $ ffinal fs
3077 extract (SepByL cnt fs sL) = do
3082 extract (SepByL cnt fs sL) = do
3078 r <- extractL sL
3083 r <- extractL sL
3079 case r of
3084 case r of
@@ -3081,10 +3086,10 @@ sepBy
3081 Continue n s -> return $ Continue n (SepByL (cnt - n) fs s)
3086 Continue n s -> return $ Continue n (SepByL (cnt - n) fs s)
3082 Partial _ _ -> error "Partial in extract"
3087 Partial _ _ -> error "Partial in extract"
3083 Error _ -> do
3088 Error _ -> do
3084− xs <- fextract fs
3089+ xs <- ffinal fs
3085 return $ Done cnt xs
3090 return $ Done cnt xs
3086− extract (SepByInitR fs) = fmap (Done 0) $ fextract fs
3091+ extract (SepByInitR fs) = fmap (Done 0) $ ffinal fs
3087− extract (SepByR cnt fs _) = fmap (Done cnt) $ fextract fs
3092+ extract (SepByR cnt fs _) = fmap (Done cnt) $ ffinal fs
3088
3093
3089-- | Non-backtracking version of sepBy. Several times faster.
3094-- | Non-backtracking version of sepBy. Several times faster.
3090{-# INLINE sepByAll #-}
3095{-# INLINE sepByAll #-}
@@ -3139,7 +3144,7 @@ sepBy1 :: Monad m =>
3139sepBy1
3144sepBy1
3140 (Parser stepL initialL extractL)
3145 (Parser stepL initialL extractL)
3141 (Parser stepR initialR _)
3146 (Parser stepR initialR _)
3142− (Fold fstep finitial fextract) = Parser step initial extract
3147+ (Fold fstep finitial _ ffinal) = Parser step initial extract
3143
3148
3144 where
3149 where
3145
3150
@@ -3186,7 +3191,7 @@ sepBy1
3186 Done n b ->
3191 Done n b ->
3187 processL (fstep fs b) n SepBy1InitR
3192 processL (fstep fs b) n SepBy1InitR
3188 Error _ -> do
3193 Error _ -> do
3189− xs <- fextract fs
3194+ xs <- ffinal fs
3190 return $ Done cnt1 xs
3195 return $ Done cnt1 xs
3191
3196
3192 {-# INLINE processR #-}
3197 {-# INLINE processR #-}
@@ -3206,7 +3211,7 @@ sepBy1
3206 Continue n s -> return $ Continue n (SepBy1R (cnt1 - n) fs s)
3211 Continue n s -> return $ Continue n (SepBy1R (cnt1 - n) fs s)
3207 Done n _ -> processR (cnt1 - n) fs n
3212 Done n _ -> processR (cnt1 - n) fs n
3208 Error _ -> do
3213 Error _ -> do
3209− xs <- fextract fs
3214+ xs <- ffinal fs
3210 return $ Done cnt1 xs
3215 return $ Done cnt1 xs
3211
3216
3212 step (SepBy1InitL cnt fs sL) a = runStepInitL cnt fs sL a
3217 step (SepBy1InitL cnt fs sL) a = runStepInitL cnt fs sL a
@@ -3223,7 +3228,7 @@ sepBy1
3223 extractResult n fs r = do
3228 extractResult n fs r = do
3224 res <- fstep fs r
3229 res <- fstep fs r
3225 case res of
3230 case res of
3226− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3231+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3227 FL.Done c -> return (Done n c)
3232 FL.Done c -> return (Done n c)
3228
3233
3229 extract (SepBy1InitL cnt fs sL) = do
3234 extract (SepBy1InitL cnt fs sL) = do
@@ -3240,10 +3245,10 @@ sepBy1
3240 Continue n s -> return $ Continue n (SepBy1L (cnt - n) fs s)
3245 Continue n s -> return $ Continue n (SepBy1L (cnt - n) fs s)
3241 Partial _ _ -> error "Partial in extract"
3246 Partial _ _ -> error "Partial in extract"
3242 Error _ -> do
3247 Error _ -> do
3243− xs <- fextract fs
3248+ xs <- ffinal fs
3244 return $ Done cnt xs
3249 return $ Done cnt xs
3245− extract (SepBy1InitR fs) = fmap (Done 0) $ fextract fs
3250+ extract (SepBy1InitR fs) = fmap (Done 0) $ ffinal fs
3246− extract (SepBy1R cnt fs _) = fmap (Done cnt) $ fextract fs
3251+ extract (SepBy1R cnt fs _) = fmap (Done cnt) $ ffinal fs
3247
3252
3248-------------------------------------------------------------------------------
3253-------------------------------------------------------------------------------
3249-- Interleaving a collection of parsers
3254-- Interleaving a collection of parsers
@@ -3273,7 +3278,7 @@ roundRobin _ps _f = undefined
3273{-# INLINE sequence #-}
3278{-# INLINE sequence #-}
3274sequence :: Monad m =>
3279sequence :: Monad m =>
3275 D.Stream m (Parser a m b) -> Fold m b c -> Parser a m c
3280 D.Stream m (Parser a m b) -> Fold m b c -> Parser a m c
3276−sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
3281+sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3277 Parser step initial extract
3282 Parser step initial extract
3278
3283
3279 where
3284 where
@@ -3291,7 +3296,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
3291 case sres of
3296 case sres of
3292 D.Yield p ss1 -> return $ Continue 1 (Just' p, ss1, fs)
3297 D.Yield p ss1 -> return $ Continue 1 (Just' p, ss1, fs)
3293 D.Stop -> do
3298 D.Stop -> do
3294− c <- fextract fs
3299+ c <- ffinal fs
3295 return $ Done 1 c
3300 return $ Done 1 c
3296 D.Skip ss1 -> return $ Continue 1 (Nothing', ss1, fs)
3301 D.Skip ss1 -> return $ Continue 1 (Nothing', ss1, fs)
3297
3302
@@ -3327,7 +3332,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
3327 FL.Done c -> return $ Done 1 c
3332 FL.Done c -> return $ Done 1 c
3328 IError err -> return $ Error err
3333 IError err -> return $ Error err
3329
3334
3330− extract (Nothing', _, fs) = fmap (Done 0) $ fextract fs
3335+ extract (Nothing', _, fs) = fmap (Done 0) $ ffinal fs
3331 extract (Just' (Parser pstep pinit pextr), ss, fs) = do
3336 extract (Just' (Parser pstep pinit pextr), ss, fs) = do
3332 ps <- pinit
3337 ps <- pinit
3333 case ps of
3338 case ps of
@@ -3337,7 +3342,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
3337 Done n b -> do
3342 Done n b -> do
3338 res <- fstep fs b
3343 res <- fstep fs b
3339 case res of
3344 case res of
3340− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3345+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3341 FL.Done c -> return (Done n c)
3346 FL.Done c -> return (Done n c)
3342 Error err -> return $ Error err
3347 Error err -> return $ Error err
3343 Continue n s -> return $ Continue n (Just' (Parser pstep (return (IPartial s)) pextr), ss, fs)
3348 Continue n s -> return $ Continue n (Just' (Parser pstep (return (IPartial s)) pextr), ss, fs)
@@ -3345,7 +3350,7 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
3345 IDone b -> do
3350 IDone b -> do
3346 fres <- fstep fs b
3351 fres <- fstep fs b
3347 case fres of
3352 case fres of
3348− FL.Partial fs1 -> fmap (Done 0) $ fextract fs1
3353+ FL.Partial fs1 -> fmap (Done 0) $ ffinal fs1
3349 FL.Done c -> return (Done 0 c)
3354 FL.Done c -> return (Done 0 c)
3350 IError err -> return $ Error err
3355 IError err -> return $ Error err
3351
3356
@@ -3480,7 +3485,7 @@ manyTill :: Monad m
3480 => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3485 => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3481manyTill (Parser stepL initialL extractL)
3486manyTill (Parser stepL initialL extractL)
3482 (Parser stepR initialR _)
3487 (Parser stepR initialR _)
3483− (Fold fstep finitial fextract) =
3488+ (Fold fstep finitial _ ffinal) =
3484 Parser step initial extract
3489 Parser step initial extract
3485
3490
3486 where
3491 where
@@ -3502,7 +3507,7 @@ manyTill (Parser stepL initialL extractL)
3502 resR <- initialR
3507 resR <- initialR
3503 case resR of
3508 case resR of
3504 IPartial sr -> return $ p (ManyTillR 0 fs sr)
3509 IPartial sr -> return $ p (ManyTillR 0 fs sr)
3505− IDone _ -> d <$> fextract fs
3510+ IDone _ -> d <$> ffinal fs
3506 IError _ -> scrutL fs p c d e
3511 IError _ -> scrutL fs p c d e
3507
3512
3508 initial = do
3513 initial = do
@@ -3519,7 +3524,7 @@ manyTill (Parser stepL initialL extractL)
3519 assertM(cnt + 1 - n >= 0)
3524 assertM(cnt + 1 - n >= 0)
3520 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
3525 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
3521 Done n _ -> do
3526 Done n _ -> do
3522− b <- fextract fs
3527+ b <- ffinal fs
3523 return $ Done n b
3528 return $ Done n b
3524 Error _ -> do
3529 Error _ -> do
3525 resL <- initialL
3530 resL <- initialL
@@ -3558,12 +3563,12 @@ manyTill (Parser stepL initialL extractL)
3558 Done n b -> do
3563 Done n b -> do
3559 r <- fstep fs b
3564 r <- fstep fs b
3560 case r of
3565 case r of
3561− FL.Partial fs1 -> fmap (Done n) $ fextract fs1
3566+ FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3562 FL.Done c -> return (Done n c)
3567 FL.Done c -> return (Done n c)
3563 Error err -> return $ Error err
3568 Error err -> return $ Error err
3564 Continue n s -> return $ Continue n (ManyTillL fs s)
3569 Continue n s -> return $ Continue n (ManyTillL fs s)
3565 Partial _ _ -> error "Partial in extract"
3570 Partial _ _ -> error "Partial in extract"
3566− extract (ManyTillR _ fs _) = fmap (Done 0) $ fextract fs
3571+ extract (ManyTillR _ fs _) = fmap (Done 0) $ ffinal fs
3567
3572
3568-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
3573-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
3569-- collects the output in the supplied fold. If the the parser @collect@ fails,
3574-- collects the output in the supplied fold. If the the parser @collect@ fails,
core/src/Streamly/Internal/Data/Parser/Type.hs+89−69
@@ -175,9 +175,6 @@
175
175
176module Streamly.Internal.Data.Parser.Type
176module Streamly.Internal.Data.Parser.Type
177 (
177 (
178− -- * Setup
179− -- $setup
180−
181 -- * Types
178 -- * Types
182 Initial (..)
179 Initial (..)
183 , Step (..)
180 , Step (..)
@@ -441,6 +438,7 @@ newtype ParseError = ParseError String
441instance Exception ParseError where
438instance Exception ParseError where
442 displayException (ParseError err) = err
439 displayException (ParseError err) = err
443
440
441+-- | Map a function on the result i.e. on @b@ in @Parser a m b@.
444instance Functor m => Functor (Parser a m) where
442instance Functor m => Functor (Parser a m) where
445 {-# INLINE fmap #-}
443 {-# INLINE fmap #-}
446 fmap f (Parser step1 initial1 extract) =
444 fmap f (Parser step1 initial1 extract) =
@@ -507,26 +505,30 @@ data SeqParseState sl f sr = SeqParseL !sl | SeqParseR !f !sr
507-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and
505-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and
508-- zips the results.
506-- zips the results.
509
507
510−-- | Sequential parser application.
508+-- | Sequential parser application. Apply two parsers sequentially to an input
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.
511--
513--
512−-- Apply two parsers sequentially to an input stream. The first parser runs and
514+-- This combinator delivers high performance by stream fusion but it comes with
513−-- processes the input, the remaining input is then passed to the second
515+-- some limitations. For those cases use the 'Applicative' instance of
514−-- parser. If both parsers succeed, their outputs are combined using the
516+-- 'Streamly.Data.ParserK.ParserK'.
515−-- supplied function. If either parser fails, the operation fails.
516--
517--
517−-- This implementation is strict in the second argument, therefore, the
518+-- CAVEAT 1: NO RECURSION. This function is strict in both arguments. As a
518−-- following will fail:
519+-- result, if a parser is defined recursively using this, it may cause an
520+-- infintie loop. The following example checks the strictness:
519--
521--
520−-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
522+-- >>> p = Parser.splitWith const (Parser.satisfy (> 0)) undefined
523+-- >>> Stream.parse p $ Stream.fromList [1]
521-- *** Exception: Prelude.undefined
524-- *** Exception: Prelude.undefined
522-- ...
525-- ...
523--
526--
524−-- Although this implementation allows stream fusion, it has quadratic
527+-- CAVEAT 2: QUADRATIC TIME COMPLEXITY. Static composition is fast due to
525−-- complexity, making it suitable only for a small number of compositions.
528+-- stream fusion, but it works well only for limited (e.g. up to 8)
526−-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
529+-- compositions, use "Streamly.Data.ParserK" for larger compositions.
527--
530--
528−-- Below are some common idioms that can be expressed using 'splitWith' and
531+-- Below are some common idioms that can be expressed using 'splitWith':
529−-- other parser primitives:
530--
532--
531-- >>> span p f1 f2 = Parser.splitWith (,) (Parser.takeWhile p f1) (Parser.fromFold f2)
533-- >>> span p f1 f2 = Parser.splitWith (,) (Parser.takeWhile p f1) (Parser.fromFold f2)
532-- >>> spanBy eq f1 f2 = Parser.splitWith (,) (Parser.groupBy eq f1) (Parser.fromFold f2)
534-- >>> spanBy eq f1 f2 = Parser.splitWith (,) (Parser.groupBy eq f1) (Parser.fromFold f2)
@@ -615,7 +617,12 @@ splitWith func (Parser stepL initialL extractL)
615-- We can use the compiler to automatically annotate accumulators, terminating
617-- We can use the compiler to automatically annotate accumulators, terminating
616-- folds, non-failing parsers and failing parsers.
618-- folds, non-failing parsers and failing parsers.
617
619
620+-- | Better performance 'splitWith' for non-failing parsers.
621+--
618−-- | Works correctly only if both the parsers are guaranteed to never fail.
622+-- Does not work correctly for parsers that can fail.
623+--
624+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
625+--
619{-# INLINE noErrorUnsafeSplitWith #-}
626{-# INLINE noErrorUnsafeSplitWith #-}
620noErrorUnsafeSplitWith :: Monad m
627noErrorUnsafeSplitWith :: Monad m
621 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
628 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
@@ -686,6 +693,8 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
686-- second parser. The output of the parser is the output of the second parser.
693-- second parser. The output of the parser is the output of the second parser.
687-- The operation fails if any of the parsers fail.
694-- The operation fails if any of the parsers fail.
688--
695--
696+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
697+--
689-- This implementation is strict in the second argument, therefore, the
698-- This implementation is strict in the second argument, therefore, the
690-- following will fail:
699-- following will fail:
691--
700--
@@ -693,10 +702,6 @@ data SeqAState sl sr = SeqAL !sl | SeqAR !sr
693-- *** Exception: Prelude.undefined
702-- *** Exception: Prelude.undefined
694-- ...
703-- ...
695--
704--
696−-- Although this implementation allows stream fusion, it has quadratic
697−-- complexity, making it suitable only for a small number of compositions.
698−-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
699−--
700-- /Pre-release/
705-- /Pre-release/
701--
706--
702{-# INLINE split_ #-}
707{-# INLINE split_ #-}
@@ -752,7 +757,12 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
752 Partial _ _ -> error "split_: Partial"
757 Partial _ _ -> error "split_: Partial"
753 Continue n s -> return $ Continue n (SeqAL s)
758 Continue n s -> return $ Continue n (SeqAL s)
754
759
755−-- For backtracking folds
760+-- | Better performance 'split_' for non-failing parsers.
761+--
762+-- Does not work correctly for parsers that can fail.
763+--
764+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
765+--
756{-# INLINE noErrorUnsafeSplit_ #-}
766{-# INLINE noErrorUnsafeSplit_ #-}
757noErrorUnsafeSplit_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
767noErrorUnsafeSplit_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
758noErrorUnsafeSplit_
768noErrorUnsafeSplit_
@@ -807,7 +817,11 @@ noErrorUnsafeSplit_
807 Partial _ _ -> error "split_: Partial"
817 Partial _ _ -> error "split_: Partial"
808 Continue n s -> return $ Continue n (SeqAL s)
818 Continue n s -> return $ Continue n (SeqAL s)
809
819
820+-- | READ THE CAVEATS in 'splitWith' before using this instance.
821+--
822+-- >>> pure = Parser.fromPure
810−-- | 'Applicative' form of 'splitWith'.
823+-- >>> (<*>) = Parser.splitWith id
824+-- >>> (*>) = Parser.split_
811instance Monad m => Applicative (Parser a m) where
825instance Monad m => Applicative (Parser a m) where
812 {-# INLINE pure #-}
826 {-# INLINE pure #-}
813 pure = fromPure
827 pure = fromPure
@@ -833,20 +847,26 @@ data AltParseState sl sr = AltParseL !Int !sl | AltParseR !sr
833-- each subsequent alternative's input element has to go through, therefore, it
847-- each subsequent alternative's input element has to go through, therefore, it
834-- cannot scale to a large number of compositions
848-- cannot scale to a large number of compositions
835
849
836−-- | Sequential alternative. The input is first passed to the first parser, and
850+-- | Sequential alternative. The input is first passed to the first parser,
837-- if it succeeds, the result is returned. However, if the first parser fails,
851-- if it succeeds, the result is returned. However, if the first parser fails,
838−-- the parser driver backtracks and tries the same input on the second parser,
852+-- the parser driver backtracks and tries the same input on the second
839−-- returning the result if it succeeds.
853+-- (alternative) parser, 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'.
840--
858--
841−-- Note: This implementation is not lazy in the second argument. The following
859+-- CAVEAT 1: NO RECURSION. This function is strict in both arguments. As a
842−-- will fail:
860+-- result, if a parser is defined recursively using this, it may cause an
861+-- infintie loop. The following example checks the strictness:
843--
862--
844−-- >> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
863+-- >>> p = Parser.satisfy (> 0) `Parser.alt` undefined
864+-- >>> Stream.parse p $ Stream.fromList [1..10]
845-- *** Exception: Prelude.undefined
865-- *** Exception: Prelude.undefined
846--
866--
847−-- Although this implementation allows stream fusion, it has quadratic
867+-- CAVEAT 2: QUADRATIC TIME COMPLEXITY. Static composition is fast due to
848−-- complexity, making it suitable only for a small number of compositions.
868+-- stream fusion, but it works well only for limited (e.g. up to 8)
849−-- As a thumb rule use it for less than 8 compositions, use ParserK otherwise.
869+-- compositions, use "Streamly.Data.ParserK" for larger compositions.
850--
870--
851-- /Time Complexity:/ O(n^2) where n is the number of compositions.
871-- /Time Complexity:/ O(n^2) where n is the number of compositions.
852--
872--
@@ -927,7 +947,7 @@ data Fused3 a b c = Fused3 !a !b !c
927--
947--
928{-# INLINE splitMany #-}
948{-# INLINE splitMany #-}
929splitMany :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
949splitMany :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
930−splitMany (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
950+splitMany (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
931 Parser step initial extract
951 Parser step initial extract
932
952
933 where
953 where
@@ -943,7 +963,7 @@ splitMany (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
943 IPartial ps -> return $ partial $ Fused3 ps 0 fs
963 IPartial ps -> return $ partial $ Fused3 ps 0 fs
944 IDone pb ->
964 IDone pb ->
945 runCollectorWith (handleCollect partial done) fs pb
965 runCollectorWith (handleCollect partial done) fs pb
946− IError _ -> done <$> fextract fs
966+ IError _ -> done <$> ffinal fs
947 FL.Done fb -> return $ done fb
967 FL.Done fb -> return $ done fb
948
968
949 runCollectorWith cont fs pb = fstep fs pb >>= cont
969 runCollectorWith cont fs pb = fstep fs pb >>= cont
@@ -967,19 +987,19 @@ splitMany (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
967 assertM(cnt1 - n >= 0)
987 assertM(cnt1 - n >= 0)
968 fstep fs b >>= handleCollect (Partial n) (Done n)
988 fstep fs b >>= handleCollect (Partial n) (Done n)
969 Error _ -> do
989 Error _ -> do
970− xs <- fextract fs
990+ xs <- ffinal fs
971 return $ Done cnt xs
991 return $ Done cnt xs
972
992
973− extract (Fused3 _ 0 fs) = fmap (Done 0) (fextract fs)
993+ extract (Fused3 _ 0 fs) = fmap (Done 0) (ffinal fs)
974 extract (Fused3 s cnt fs) = do
994 extract (Fused3 s cnt fs) = do
975 r <- extract1 s
995 r <- extract1 s
976 case r of
996 case r of
977− Error _ -> fmap (Done cnt) (fextract fs)
997+ Error _ -> fmap (Done cnt) (ffinal fs)
978 Done n b -> do
998 Done n b -> do
979 assertM(n <= cnt)
999 assertM(n <= cnt)
980 fs1 <- fstep fs b
1000 fs1 <- fstep fs b
981 case fs1 of
1001 case fs1 of
982− FL.Partial s1 -> fmap (Done n) (fextract s1)
1002+ FL.Partial s1 -> fmap (Done n) (ffinal s1)
983 FL.Done b1 -> return (Done n b1)
1003 FL.Done b1 -> return (Done n b1)
984 Partial _ _ -> error "splitMany: Partial in extract"
1004 Partial _ _ -> error "splitMany: Partial in extract"
985 Continue n s1 -> do
1005 Continue n s1 -> do
@@ -993,7 +1013,7 @@ splitMany (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
993--
1013--
994{-# INLINE splitManyPost #-}
1014{-# INLINE splitManyPost #-}
995splitManyPost :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1015splitManyPost :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
996−splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1016+splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
997 Parser step initial extract
1017 Parser step initial extract
998
1018
999 where
1019 where
@@ -1009,7 +1029,7 @@ splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1009 IPartial ps -> return $ partial $ Fused3 ps 0 fs
1029 IPartial ps -> return $ partial $ Fused3 ps 0 fs
1010 IDone pb ->
1030 IDone pb ->
1011 runCollectorWith (handleCollect partial done) fs pb
1031 runCollectorWith (handleCollect partial done) fs pb
1012− IError _ -> done <$> fextract fs
1032+ IError _ -> done <$> ffinal fs
1013 FL.Done fb -> return $ done fb
1033 FL.Done fb -> return $ done fb
1014
1034
1015 runCollectorWith cont fs pb = fstep fs pb >>= cont
1035 runCollectorWith cont fs pb = fstep fs pb >>= cont
@@ -1031,18 +1051,18 @@ splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1031 assertM(cnt1 - n >= 0)
1051 assertM(cnt1 - n >= 0)
1032 fstep fs b >>= handleCollect (Partial n) (Done n)
1052 fstep fs b >>= handleCollect (Partial n) (Done n)
1033 Error _ -> do
1053 Error _ -> do
1034− xs <- fextract fs
1054+ xs <- ffinal fs
1035 return $ Done cnt1 xs
1055 return $ Done cnt1 xs
1036
1056
1037 extract (Fused3 s cnt fs) = do
1057 extract (Fused3 s cnt fs) = do
1038 r <- extract1 s
1058 r <- extract1 s
1039 case r of
1059 case r of
1040− Error _ -> fmap (Done cnt) (fextract fs)
1060+ Error _ -> fmap (Done cnt) (ffinal fs)
1041 Done n b -> do
1061 Done n b -> do
1042 assertM(n <= cnt)
1062 assertM(n <= cnt)
1043 fs1 <- fstep fs b
1063 fs1 <- fstep fs b
1044 case fs1 of
1064 case fs1 of
1045− FL.Partial s1 -> fmap (Done n) (fextract s1)
1065+ FL.Partial s1 -> fmap (Done n) (ffinal s1)
1046 FL.Done b1 -> return (Done n b1)
1066 FL.Done b1 -> return (Done n b1)
1047 Partial _ _ -> error "splitMany: Partial in extract"
1067 Partial _ _ -> error "splitMany: Partial in extract"
1048 Continue n s1 -> do
1068 Continue n s1 -> do
@@ -1055,7 +1075,7 @@ splitManyPost (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1055--
1075--
1056{-# INLINE splitSome #-}
1076{-# INLINE splitSome #-}
1057splitSome :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1077splitSome :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1058−splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1078+splitSome (Parser step1 initial1 extract1) (Fold fstep finitial _ ffinal) =
1059 Parser step initial extract
1079 Parser step initial extract
1060
1080
1061 where
1081 where
@@ -1071,7 +1091,7 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1071 IPartial ps -> return $ partial $ Fused3 ps 0 $ Right fs
1091 IPartial ps -> return $ partial $ Fused3 ps 0 $ Right fs
1072 IDone pb ->
1092 IDone pb ->
1073 runCollectorWith (handleCollect partial done) fs pb
1093 runCollectorWith (handleCollect partial done) fs pb
1074− IError _ -> done <$> fextract fs
1094+ IError _ -> done <$> ffinal fs
1075 FL.Done fb -> return $ done fb
1095 FL.Done fb -> return $ done fb
1076
1096
1077 runCollectorWith cont fs pb = fstep fs pb >>= cont
1097 runCollectorWith cont fs pb = fstep fs pb >>= cont
@@ -1121,7 +1141,7 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1121 Done n b -> do
1141 Done n b -> do
1122 assertM(cnt1 - n >= 0)
1142 assertM(cnt1 - n >= 0)
1123 fstep fs b >>= handleCollect (Partial n) (Done n)
1143 fstep fs b >>= handleCollect (Partial n) (Done n)
1124− Error _ -> Done cnt1 <$> fextract fs
1144+ Error _ -> Done cnt1 <$> ffinal fs
1125
1145
1126 extract (Fused3 s cnt (Left fs)) = do
1146 extract (Fused3 s cnt (Left fs)) = do
1127 r <- extract1 s
1147 r <- extract1 s
@@ -1131,7 +1151,7 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1131 assertM(n <= cnt)
1151 assertM(n <= cnt)
1132 fs1 <- fstep fs b
1152 fs1 <- fstep fs b
1133 case fs1 of
1153 case fs1 of
1134− FL.Partial s1 -> fmap (Done n) (fextract s1)
1154+ FL.Partial s1 -> fmap (Done n) (ffinal s1)
1135 FL.Done b1 -> return (Done n b1)
1155 FL.Done b1 -> return (Done n b1)
1136 Partial _ _ -> error "splitSome: Partial in extract"
1156 Partial _ _ -> error "splitSome: Partial in extract"
1137 Continue n s1 -> do
1157 Continue n s1 -> do
@@ -1140,12 +1160,12 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
1140 extract (Fused3 s cnt (Right fs)) = do
1160 extract (Fused3 s cnt (Right fs)) = do
1141 r <- extract1 s
1161 r <- extract1 s
1142 case r of
1162 case r of
1143− Error _ -> fmap (Done cnt) (fextract fs)
1163+ Error _ -> fmap (Done cnt) (ffinal fs)
1144 Done n b -> do
1164 Done n b -> do
1145 assertM(n <= cnt)
1165 assertM(n <= cnt)
1146 fs1 <- fstep fs b
1166 fs1 <- fstep fs b
1147 case fs1 of
1167 case fs1 of
1148− FL.Partial s1 -> fmap (Done n) (fextract s1)
1168+ FL.Partial s1 -> fmap (Done n) (ffinal s1)
1149 FL.Done b1 -> return (Done n b1)
1169 FL.Done b1 -> return (Done n b1)
1150 Partial _ _ -> error "splitSome: Partial in extract"
1170 Partial _ _ -> error "splitSome: Partial in extract"
1151 Continue n s1 -> do
1171 Continue n s1 -> do
@@ -1176,23 +1196,12 @@ dieM err = Parser undefined (IError <$> err) undefined
1176-- Note: With the direct style parser type, the list in "some" and "many" is
1196-- Note: With the direct style parser type, the list in "some" and "many" is
1177-- accumulated strictly, it cannot be consumed lazily.
1197-- accumulated strictly, it cannot be consumed lazily.
1178
1198
1179−-- | Sequential alternative. The input is first passed to the first parser, and
1199+-- | READ THE CAVEATS in 'alt' before using this instance.
1180−-- if it succeeds, the result is returned. However, if the first parser fails,
1181−-- the parser driver backtracks and tries the same input on the second parser,
1182−-- returning the result if it succeeds.
1183−--
1184−-- Note: The implementation of '<|>' is not lazy in the second
1185−-- argument. The following code will fail:
1186−--
1187−-- >>> Stream.parse (Parser.satisfy (> 0) <|> undefined) $ Stream.fromList [1..10]
1188−-- *** Exception: Prelude.undefined
1189−-- ...
1190--
1200--
1191−-- WARNING! this is not suitable for large scale use. As a thumb rule stream
1201+-- >>> empty = Parser.die "empty"
1192−-- fusion works well for less than 8 compositions of this operation, otherwise
1202+-- >>> (<|>) = Parser.alt
1193−-- consider using 'ParserK'. Do not use recursive parser implementations based
1203+-- >>> many = flip Parser.many Fold.toList
1194−-- on this Alternative instance.
1204+-- >>> some = flip Parser.some Fold.toList
1195−
1196instance Monad m => Alternative (Parser a m) where
1205instance Monad m => Alternative (Parser a m) where
1197 {-# INLINE empty #-}
1206 {-# INLINE empty #-}
1198 empty = die "empty"
1207 empty = die "empty"
@@ -1211,8 +1220,13 @@ data ConcatParseState sl m a b =
1211 ConcatParseL !sl
1220 ConcatParseL !sl
1212 | forall s. ConcatParseR (s -> a -> m (Step s b)) s (s -> m (Step s b))
1221 | forall s. ConcatParseR (s -> a -> m (Step s b)) s (s -> m (Step s b))
1213
1222
1223+-- XXX Does it fuse completely? Check and update, it cannot fuse the
1224+-- dynamically generated parser.
1225+
1214-- | Map a 'Parser' returning function on the result of a 'Parser'.
1226-- | Map a 'Parser' returning function on the result of a 'Parser'.
1215--
1227--
1228+-- ALL THE CAVEATS IN 'splitWith' APPLY HERE AS WELL.
1229+--
1216-- /Pre-release/
1230-- /Pre-release/
1217--
1231--
1218{-# INLINE concatMap #-}
1232{-# INLINE concatMap #-}
@@ -1282,6 +1296,12 @@ concatMap func (Parser stepL initialL extractL) = Parser step initial extract
1282 Partial _ _ -> error "concatMap: extract Partial"
1296 Partial _ _ -> error "concatMap: extract Partial"
1283 Continue n s -> return $ Continue n (ConcatParseL s)
1297 Continue n s -> return $ Continue n (ConcatParseL s)
1284
1298
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+--
1285{-# INLINE noErrorUnsafeConcatMap #-}
1305{-# INLINE noErrorUnsafeConcatMap #-}
1286noErrorUnsafeConcatMap :: Monad m =>
1306noErrorUnsafeConcatMap :: Monad m =>
1287 (b -> Parser a m c) -> Parser a m b -> Parser a m c
1307 (b -> Parser a m c) -> Parser a m b -> Parser a m c
@@ -1354,11 +1374,9 @@ noErrorUnsafeConcatMap func (Parser stepL initialL extractL) =
1354-- for small number of compositions but for a scalable implementation we need a
1374-- for small number of compositions but for a scalable implementation we need a
1355-- CPS version.
1375-- CPS version.
1356
1376
1357−-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
1377+-- | READ THE CAVEATS in 'concatMap' before using this instance.
1358--
1378--
1359−-- Although this implementation allows stream fusion, it has quadratic
1379+-- >>> (>>=) = flip Parser.concatMap
1360−-- complexity, making it suitable only for a small number of compositions. As a
1361−-- thumb rule use it for less than 8 compositions, use 'ParserK' otherwise.
1362--
1380--
1363instance Monad m => Monad (Parser a m) where
1381instance Monad m => Monad (Parser a m) where
1364 {-# INLINE return #-}
1382 {-# INLINE return #-}
@@ -1370,6 +1388,7 @@ instance Monad m => Monad (Parser a m) where
1370 {-# INLINE (>>) #-}
1388 {-# INLINE (>>) #-}
1371 (>>) = (*>)
1389 (>>) = (*>)
1372
1390
1391+-- | >>> fail = Parser.die
1373instance Monad m => Fail.MonadFail (Parser a m) where
1392instance Monad m => Fail.MonadFail (Parser a m) where
1374 {-# INLINE fail #-}
1393 {-# INLINE fail #-}
1375 fail = die
1394 fail = die
@@ -1385,6 +1404,7 @@ instance Monad m => MonadPlus (Parser a m) where
1385 mplus = alt
1404 mplus = alt
1386-}
1405-}
1387
1406
1407+-- | >>> liftIO = Parser.fromEffect . liftIO
1388instance (MonadIO m) => MonadIO (Parser a m) where
1408instance (MonadIO m) => MonadIO (Parser a m) where
1389 {-# INLINE liftIO #-}
1409 {-# INLINE liftIO #-}
1390 liftIO = fromEffect . liftIO
1410 liftIO = fromEffect . liftIO
core/src/Streamly/Internal/Data/ParserK/Type.hs+24−64
@@ -168,8 +168,8 @@ newtype ParserK a m b = MkParser
168-------------------------------------------------------------------------------
168-------------------------------------------------------------------------------
169
169
170-- XXX rewrite this using ParserD, expose rmapM from ParserD.
170-- XXX rewrite this using ParserD, expose rmapM from ParserD.
171−-- | Maps a function over the output of the parser.
171+
172−--
172+-- | Map a function on the result i.e. on @b@ in @Parser a m b@.
173instance Functor m => Functor (ParserK a m) where
173instance Functor m => Functor (ParserK a m) where
174 {-# INLINE fmap #-}
174 {-# INLINE fmap #-}
175 fmap f parser = MkParser $ \k n st arr ->
175 fmap f parser = MkParser $ \k n st arr ->
@@ -181,7 +181,7 @@ instance Functor m => Functor (ParserK a m) where
181-------------------------------------------------------------------------------
181-------------------------------------------------------------------------------
182
182
183-- This is the dual of stream "fromPure".
183-- This is the dual of stream "fromPure".
184−--
184+
185-- | A parser that always yields a pure value without consuming any input.
185-- | A parser that always yields a pure value without consuming any input.
186--
186--
187-- /Pre-release/
187-- /Pre-release/
@@ -199,9 +199,11 @@ fromEffect :: Monad m => m b -> ParserK a m b
199fromEffect eff =
199fromEffect eff =
200 MkParser $ \k n st arr -> eff >>= \b -> k (Success n b) st arr
200 MkParser $ \k n st arr -> eff >>= \b -> k (Success n b) st arr
201
201
202−-- | 'Applicative' form of 'Streamly.Internal.Data.Parser.splitWith'. Note that
202+-- | @f \<$> p1 \<*> p2@ applies parsers p1 and p2 sequentially to an input
203−-- this operation does not fuse, use 'Streamly.Internal.Data.Parser.splitWith'
203+-- stream. The first parser runs and processes the input, the remaining input
204−-- when fusion is important.
204+-- is then passed to the second parser. If both parsers succeed, their outputs
205+-- are applied to the function @f@. If either parser fails, the operation
206+-- fails.
205--
207--
206instance Monad m => Applicative (ParserK a m) where
208instance Monad m => Applicative (ParserK a m) where
207 {-# INLINE pure #-}
209 {-# INLINE pure #-}
@@ -243,48 +245,8 @@ instance Monad m => Applicative (ParserK a m) where
243die :: String -> ParserK a m b
245die :: String -> ParserK a m b
244die err = MkParser (\k n st arr -> k (Failure n err) st arr)
246die err = MkParser (\k n st arr -> k (Failure n err) st arr)
245
247
246−-- | Monad composition can be used for lookbehind parsers, we can make the
248+-- | Monad composition can be used for lookbehind parsers, we can dynamically
247−-- future parses depend on the previously parsed values.
249+-- compose new parsers based on the results of the previously parsed values.
248−--
249−-- If we have to parse "a9" or "9a" but not "99" or "aa" we can use the
250−-- following parser:
251−--
252−-- @
253−-- backtracking :: MonadCatch m => PR.Parser Char m String
254−-- backtracking =
255−-- sequence [PR.satisfy isDigit, PR.satisfy isAlpha]
256−-- '<|>'
257−-- sequence [PR.satisfy isAlpha, PR.satisfy isDigit]
258−-- @
259−--
260−-- We know that if the first parse resulted in a digit at the first place then
261−-- the second parse is going to fail. However, we waste that information and
262−-- parse the first character again in the second parse only to know that it is
263−-- not an alphabetic char. By using lookbehind in a 'Monad' composition we can
264−-- avoid redundant work:
265−--
266−-- @
267−-- data DigitOrAlpha = Digit Char | Alpha Char
268−--
269−-- lookbehind :: MonadCatch m => PR.Parser Char m String
270−-- lookbehind = do
271−-- x1 \<- Digit '<$>' PR.satisfy isDigit
272−-- '<|>' Alpha '<$>' PR.satisfy isAlpha
273−--
274−-- -- Note: the parse depends on what we parsed already
275−-- x2 <- case x1 of
276−-- Digit _ -> PR.satisfy isAlpha
277−-- Alpha _ -> PR.satisfy isDigit
278−--
279−-- return $ case x1 of
280−-- Digit x -> [x,x2]
281−-- Alpha x -> [x,x2]
282−-- @
283−--
284−-- See also 'Streamly.Internal.Data.Parser.concatMap'. This monad instance
285−-- does not fuse, use 'Streamly.Internal.Data.Parser.concatMap' when you need
286−-- fusion.
287−--
288instance Monad m => Monad (ParserK a m) where
250instance Monad m => Monad (ParserK a m) where
289 {-# INLINE return #-}
251 {-# INLINE return #-}
290 return = pure
252 return = pure
@@ -316,18 +278,10 @@ instance MonadIO m => MonadIO (ParserK a m) where
316-- Alternative
278-- Alternative
317-------------------------------------------------------------------------------
279-------------------------------------------------------------------------------
318
280
319−-- | 'Alternative' form of 'Streamly.Internal.Data.Parser.alt'. Backtrack and
281+-- | @p1 \<|> p2@ passes the input to parser p1, if it succeeds, the result is
320−-- run the second parser if the first one fails.
282+-- returned. However, if p1 fails, the parser driver backtracks and tries the
321−--
283+-- same input on the alternative parser p2, returning the result if it
322−-- The "some" and "many" operations of alternative accumulate results in a pure
284+-- succeeds.
323−-- list which is not scalable and streaming. Instead use
324−-- 'Streamly.Internal.Data.Parser.some' and
325−-- 'Streamly.Internal.Data.Parser.many' for fusible operations with composable
326−-- accumulation of results.
327−--
328−-- See also 'Streamly.Internal.Data.Parser.alt'. This 'Alternative' instance
329−-- does not fuse, use 'Streamly.Internal.Data.Parser.alt' when you need
330−-- fusion.
331--
285--
332instance Monad m => Alternative (ParserK a m) where
286instance Monad m => Alternative (ParserK a m) where
333 {-# INLINE empty #-}
287 {-# INLINE empty #-}
@@ -450,7 +404,7 @@ adaptCWith pstep initial extract cont !offset0 !usedCount !input = do
450 go !_ !cur !pst | cur >= end =
404 go !_ !cur !pst | cur >= end =
451 onContinue ((end - start) `div` SIZE_OF(a)) pst
405 onContinue ((end - start) `div` SIZE_OF(a)) pst
452 go !_ !cur !pst = do
406 go !_ !cur !pst = do
453− let !x = unsafeInlineIO $ peekByteIndex cur contents
407+ let !x = unsafeInlineIO $ peekAt cur contents
454 pRes <- pstep pst x
408 pRes <- pstep pst x
455 let elemSize = SIZE_OF(a)
409 let elemSize = SIZE_OF(a)
456 next = INDEX_NEXT(cur,a)
410 next = INDEX_NEXT(cur,a)
@@ -507,7 +461,8 @@ adaptCWith pstep initial extract cont !offset0 !usedCount !input = do
507 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
461 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
508 parseCont !cnt !pst None = parseContNothing cnt pst
462 parseCont !cnt !pst None = parseContNothing cnt pst
509
463
510−-- | Convert a raw byte 'Parser' to a chunked 'ParserK'.
464+-- | Convert an element 'Parser' to a chunked 'ParserK'. A chunked parser is
465+-- more efficient than an element parser.
511--
466--
512-- /Pre-release/
467-- /Pre-release/
513--
468--
@@ -609,7 +564,9 @@ adaptWith pstep initial extract cont !relPos !usedCount !input = do
609 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt pst arr
564 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt pst arr
610 parseCont !cnt !pst None = parseContNothing cnt pst
565 parseCont !cnt !pst None = parseContNothing cnt pst
611
566
612−-- | Similar to "adaptC" but for non-chunked input.
567+-- | Convert a 'Parser' to 'ParserK'.
568+--
569+-- /Pre-release/
613--
570--
614{-# INLINE_LATE adapt #-}
571{-# INLINE_LATE adapt #-}
615adapt :: Monad m => ParserD.Parser a m b -> ParserK a m b
572adapt :: Monad m => ParserD.Parser a m b -> ParserK a m b
@@ -737,7 +694,10 @@ adaptCGWith pstep initial extract cont !offset0 !usedCount !input = do
737 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
694 parseCont !cnt !pst (Chunk arr) = parseContChunk cnt 0 pst arr
738 parseCont !cnt !pst None = parseContNothing cnt pst
695 parseCont !cnt !pst None = parseContNothing cnt pst
739
696
740−-- | Similar to "adaptC" but is not constrained.
697+-- | A generic 'adaptC'. Similar to 'adaptC' but is not constrained to 'Unbox'
698+-- types.
699+--
700+-- /Pre-release/
741--
701--
742{-# INLINE_LATE adaptCG #-}
702{-# INLINE_LATE adaptCG #-}
743adaptCG ::
703adaptCG ::
core/src/Streamly/Internal/Data/Ring.hs+7−4
@@ -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(peekByteIndex))
82+import Streamly.Internal.Data.Unbox as Unboxed (Unbox(peekAt))
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 <- peekByteIndex i w8Contents
414+ aelem <- peekAt 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 <- peekByteIndex i w8Contents
448+ aelem <- peekAt 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,7 +558,8 @@ 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) = Fold step initial extract
561+slidingWindowWith n (Fold step1 initial1 extract1 final1) =
562+ Fold step initial extract final
562
563
563 where
564 where
564
565
@@ -601,6 +602,8 @@ slidingWindowWith n (Fold step1 initial1 extract1) = Fold step initial extract
601
602
602 extract (Tuple4' _ _ _ st) = extract1 st
603 extract (Tuple4' _ _ _ st) = extract1 st
603
604
605+ final (Tuple4' _ _ _ st) = final1 st
606+
604-- | @slidingWindow collector@ is an incremental sliding window
607-- | @slidingWindow collector@ is an incremental sliding window
605-- fold that does not require all the intermediate elements in a computation.
608-- fold that does not require all the intermediate elements in a computation.
606-- This maintains @n@ elements in the window, when a new element comes it slides
609-- 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
72+writeLastN n = Fold step initial extract extract
73
73
74 where
74 where
75
75
core/src/Streamly/Internal/Data/Serialize.hsdeleted−122
@@ -1,122 +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.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+113−96
@@ -7,12 +7,23 @@
7-- Maintainer : streamly@composewell.com
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
8-- Stability : experimental
9-- Portability : GHC
9-- Portability : GHC
10−--
10+
11+-- XXX Instead of applying the product constructor in one go can we apply it
12+-- one at a time in case of too many arguments, compiler may not have to save
13+-- them in local vars.
14+
11module Streamly.Internal.Data.Serialize.TH
15module Streamly.Internal.Data.Serialize.TH
16+ (
17+ -- Deriving
12− ( deriveSerialize
18+ deriveSerialize
13− , Config(..)
14− , defaultConfig
15 , deriveSerializeWith
19 , 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
16 ) where
27 ) where
17
28
18--------------------------------------------------------------------------------
29--------------------------------------------------------------------------------
@@ -29,7 +40,6 @@ import Streamly.Internal.Data.Serialize.Type
29import Streamly.Internal.Data.Unbox.TH
40import Streamly.Internal.Data.Unbox.TH
30 ( DataCon(..)
41 ( DataCon(..)
31 , DataType(..)
42 , DataType(..)
32− , appsT
33 , reifyDataType
43 , reifyDataType
34 )
44 )
35
45
@@ -37,13 +47,14 @@ import qualified Streamly.Internal.Data.Serialize.TH.RecHeader as RecHeader
37
47
38import Streamly.Internal.Data.Serialize.TH.Bottom
48import Streamly.Internal.Data.Serialize.TH.Bottom
39import Streamly.Internal.Data.Serialize.TH.Common
49import Streamly.Internal.Data.Serialize.TH.Common
50+import Streamly.Internal.Data.Serialize.TH.RecHeader
40
51
41--------------------------------------------------------------------------------
52--------------------------------------------------------------------------------
42-- Domain specific helpers
53-- Domain specific helpers
43--------------------------------------------------------------------------------
54--------------------------------------------------------------------------------
44
55
45exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
56exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
46−exprGetSize acc (i, _) = [|size $(acc) $(varE (mkFieldName i))|]
57+exprGetSize acc (i, _) = [|addSizeTo $(acc) $(varE (mkFieldName i))|]
47
58
48getTagSize :: Int -> Int
59getTagSize :: Int -> Int
49getTagSize numConstructors
60getTagSize numConstructors
@@ -148,22 +159,25 @@ mkSizeOfExpr False False tyOfTy =
148 [varP _acc, varP _x]
159 [varP _acc, varP _x]
149 (caseE (varE _x) (fmap (matchCons acc) cons))
160 (caseE (varE _x) (fmap (matchCons acc) cons))
150
161
151−mkSizeOfExpr False True (TheType con) = RecHeader.mkSizeOfExpr con
162+mkSizeOfExpr False True (TheType con) = RecHeader.mkRecSizeOfExpr con
152
163
153mkSizeOfExpr _ _ _ = errorUnimplemented
164mkSizeOfExpr _ _ _ = errorUnimplemented
154
165
155−mkSizeDec :: Config -> Type -> [DataCon] -> Q [Dec]
166+mkSizeDec :: SerializeConfig -> Type -> [DataCon] -> Q [Dec]
156−mkSizeDec (Config {..}) headTy cons = do
167+mkSizeDec (SerializeConfig {..}) headTy cons = do
157 -- INLINE on sizeOf actually worsens some benchmarks, and improves none
168 -- INLINE on sizeOf actually worsens some benchmarks, and improves none
158 sizeOfMethod <-
169 sizeOfMethod <-
159 mkSizeOfExpr
170 mkSizeOfExpr
160− constructorTagAsString
171+ cfgConstructorTagAsString
161− recordSyntaxWithHeader
172+ cfgRecordSyntaxWithHeader
162 (typeOfType headTy cons)
173 (typeOfType headTy cons)
163 pure
174 pure
175+ ( maybe
176+ []
164− [ PragmaD (InlineP 'size inlineSize FunLike AllPhases)
177+ (\x -> [PragmaD (InlineP 'addSizeTo x FunLike AllPhases)])
178+ cfgInlineSize
165− , FunD 'size [Clause [] (NormalB sizeOfMethod) []]
179+ ++ [FunD 'addSizeTo [Clause [] (NormalB sizeOfMethod) []]]
166− ]
180+ )
167
181
168--------------------------------------------------------------------------------
182--------------------------------------------------------------------------------
169-- Peek
183-- Peek
@@ -182,7 +196,7 @@ mkDeserializeExpr True False headTy tyOfTy =
182 conLen <- newName "conLen"
196 conLen <- newName "conLen"
183 off1 <- newName "off1"
197 off1 <- newName "off1"
184 [|do ($(varP off1), $(varP conLen) :: Word8) <-
198 [|do ($(varP off1), $(varP conLen) :: Word8) <-
185− deserialize
199+ deserializeAt
186 $(varE _initialOffset)
200 $(varE _initialOffset)
187 $(varE _arr)
201 $(varE _arr)
188 $(varE _endOffset)
202 $(varE _endOffset)
@@ -202,18 +216,19 @@ mkDeserializeExpr True False headTy tyOfTy =
202 [|($(litIntegral lenCname) == $(varE conLen))
216 [|($(litIntegral lenCname) == $(varE conLen))
203 && $(xorCmp tag off _arr)|]
217 && $(xorCmp tag off _arr)|]
204 [|let $(varP (makeI 0)) = $(varE off) + $(litIntegral lenCname)
218 [|let $(varP (makeI 0)) = $(varE off) + $(litIntegral lenCname)
205− in $(mkDeserializeExprOne 'deserialize con)|]
219+ in $(mkDeserializeExprOne 'deserializeAt con)|]
206
220
207mkDeserializeExpr False False headTy tyOfTy =
221mkDeserializeExpr False False headTy tyOfTy =
208 case tyOfTy of
222 case tyOfTy of
209 -- Unit constructor
223 -- Unit constructor
224+ -- XXX Should we peek and check if the byte value is 0?
210 UnitType cname ->
225 UnitType cname ->
211 [|pure ($(varE _initialOffset) + 1, $(conE cname))|]
226 [|pure ($(varE _initialOffset) + 1, $(conE cname))|]
212 -- Product type
227 -- Product type
213 TheType con ->
228 TheType con ->
214 letE
229 letE
215 [valD (varP (mkName "i0")) (normalB (varE _initialOffset)) []]
230 [valD (varP (mkName "i0")) (normalB (varE _initialOffset)) []]
216− (mkDeserializeExprOne 'deserialize con)
231+ (mkDeserializeExprOne 'deserializeAt con)
217 -- Sum type
232 -- Sum type
218 MultiType cons -> do
233 MultiType cons -> do
219 let lenCons = length cons
234 let lenCons = length cons
@@ -221,7 +236,7 @@ mkDeserializeExpr False False headTy tyOfTy =
221 doE
236 doE
222 [ bindS
237 [ bindS
223 (tupP [varP (mkName "i0"), varP _tag])
238 (tupP [varP (mkName "i0"), varP _tag])
224− [|deserialize $(varE _initialOffset) $(varE _arr) $(varE _endOffset)|]
239+ [|deserializeAt $(varE _initialOffset) $(varE _arr) $(varE _endOffset)|]
225 , noBindS
240 , noBindS
226 (caseE
241 (caseE
227 (sigE (varE _tag) (conT tagType))
242 (sigE (varE _tag) (conT tagType))
@@ -231,7 +246,7 @@ mkDeserializeExpr False False headTy tyOfTy =
231 peekMatch (i, con) =
246 peekMatch (i, con) =
232 match
247 match
233 (litP (IntegerL i))
248 (litP (IntegerL i))
234− (normalB (mkDeserializeExprOne 'deserialize con)) []
249+ (normalB (mkDeserializeExprOne 'deserializeAt con)) []
235 peekErr =
250 peekErr =
236 match
251 match
237 wildP
252 wildP
@@ -250,7 +265,7 @@ mkDeserializeExpr False True _ (TheType con@(SimpleDataCon _ fields)) = do
250 RecHeader.mkDeserializeKeysDec deserializeWithKeys updateFunc con
265 RecHeader.mkDeserializeKeysDec deserializeWithKeys updateFunc con
251 letE
266 letE
252 (pure <$> (deserializeWithKeysDec ++ updateFuncDec))
267 (pure <$> (deserializeWithKeysDec ++ updateFuncDec))
253− (RecHeader.mkDeserializeExpr
268+ (RecHeader.mkRecDeserializeExpr
254 _initialOffset
269 _initialOffset
255 _endOffset
270 _endOffset
256 deserializeWithKeys
271 deserializeWithKeys
@@ -258,26 +273,31 @@ mkDeserializeExpr False True _ (TheType con@(SimpleDataCon _ fields)) = do
258
273
259mkDeserializeExpr _ _ _ _ = errorUnimplemented
274mkDeserializeExpr _ _ _ _ = errorUnimplemented
260
275
261−mkDeserializeDec :: Config -> Type -> [DataCon] -> Q [Dec]
276+mkDeserializeDec :: SerializeConfig -> Type -> [DataCon] -> Q [Dec]
262−mkDeserializeDec (Config {..}) headTy cons = do
277+mkDeserializeDec (SerializeConfig {..}) headTy cons = do
263 peekMethod <-
278 peekMethod <-
264 mkDeserializeExpr
279 mkDeserializeExpr
265− constructorTagAsString
280+ cfgConstructorTagAsString
266− recordSyntaxWithHeader
281+ cfgRecordSyntaxWithHeader
267 headTy
282 headTy
268 (typeOfType headTy cons)
283 (typeOfType headTy cons)
269 pure
284 pure
285+ ( maybe
286+ []
270− [ PragmaD (InlineP 'deserialize inlineDeserialize FunLike AllPhases)
287+ (\x -> [PragmaD (InlineP 'deserializeAt x FunLike AllPhases)])
288+ cfgInlineDeserialize
289+ ++
271− , FunD
290+ [ FunD
272− 'deserialize
291+ 'deserializeAt
273 [ Clause
292 [ Clause
274− (if isUnitType cons && not constructorTagAsString
293+ (if isUnitType cons && not cfgConstructorTagAsString
275 then [VarP _initialOffset, WildP, WildP]
294 then [VarP _initialOffset, WildP, WildP]
276 else [VarP _initialOffset, VarP _arr, VarP _endOffset])
295 else [VarP _initialOffset, VarP _arr, VarP _endOffset])
277 (NormalB peekMethod)
296 (NormalB peekMethod)
278 []
297 []
279 ]
298 ]
280− ]
299+ ]
300+ )
281
301
282--------------------------------------------------------------------------------
302--------------------------------------------------------------------------------
283-- Poke
303-- Poke
@@ -285,7 +305,7 @@ mkDeserializeDec (Config {..}) headTy cons = do
285
305
286mkSerializeExprTag :: Name -> Int -> Q Exp
306mkSerializeExprTag :: Name -> Int -> Q Exp
287mkSerializeExprTag tagType tagVal =
307mkSerializeExprTag tagType tagVal =
288− [|serialize
308+ [|serializeAt
289 $(varE _initialOffset)
309 $(varE _initialOffset)
290 $(varE _arr)
310 $(varE _arr)
291 $((sigE (litE (IntegerL (fromIntegral tagVal))) (conT tagType)))|]
311 $((sigE (litE (IntegerL (fromIntegral tagVal))) (conT tagType)))|]
@@ -320,13 +340,14 @@ mkSerializeExpr True False tyOfTy =
320 (doE [ bindS
340 (doE [ bindS
321 (varP (mkName "i0"))
341 (varP (mkName "i0"))
322 (serializeW8List _initialOffset _arr conEnc)
342 (serializeW8List _initialOffset _arr conEnc)
323− , noBindS (mkSerializeExprFields 'serialize fields)
343+ , noBindS (mkSerializeExprFields 'serializeAt fields)
324 ])
344 ])
325
345
326mkSerializeExpr False False tyOfTy =
346mkSerializeExpr False False tyOfTy =
327 case tyOfTy of
347 case tyOfTy of
328 -- Unit type
348 -- Unit type
349+ UnitType _ ->
329− UnitType _ -> [|pure ($(varE _initialOffset) + 1)|]
350+ [|serializeAt $(varE _initialOffset) $(varE _arr) (0 :: Word8)|]
330 -- Product type
351 -- Product type
331 (TheType (SimpleDataCon cname fields)) ->
352 (TheType (SimpleDataCon cname fields)) ->
332 letE
353 letE
@@ -336,7 +357,7 @@ mkSerializeExpr False False tyOfTy =
336 [ matchConstructor
357 [ matchConstructor
337 cname
358 cname
338 (length fields)
359 (length fields)
339− (mkSerializeExprFields 'serialize fields)
360+ (mkSerializeExprFields 'serializeAt fields)
340 ])
361 ])
341 -- Sum type
362 -- Sum type
342 (MultiType cons) -> do
363 (MultiType cons) -> do
@@ -353,35 +374,40 @@ mkSerializeExpr False False tyOfTy =
353 (mkSerializeExprTag tagType tagVal)
374 (mkSerializeExprTag tagType tagVal)
354 , noBindS
375 , noBindS
355 (mkSerializeExprFields
376 (mkSerializeExprFields
356− 'serialize
377+ 'serializeAt
357 fields)
378 fields)
358 ]))
379 ]))
359 (zip [0 ..] cons))
380 (zip [0 ..] cons))
360
381
361mkSerializeExpr False True (TheType con) =
382mkSerializeExpr False True (TheType con) =
362− RecHeader.mkSerializeExpr _initialOffset con
383+ RecHeader.mkRecSerializeExpr _initialOffset con
363
384
364mkSerializeExpr _ _ _ = errorUnimplemented
385mkSerializeExpr _ _ _ = errorUnimplemented
365
386
366−mkSerializeDec :: Config -> Type -> [DataCon] -> Q [Dec]
387+mkSerializeDec :: SerializeConfig -> Type -> [DataCon] -> Q [Dec]
367−mkSerializeDec (Config {..}) headTy cons = do
388+mkSerializeDec (SerializeConfig {..}) headTy cons = do
368 pokeMethod <-
389 pokeMethod <-
369 mkSerializeExpr
390 mkSerializeExpr
370− constructorTagAsString
391+ cfgConstructorTagAsString
371− recordSyntaxWithHeader
392+ cfgRecordSyntaxWithHeader
372 (typeOfType headTy cons)
393 (typeOfType headTy cons)
373 pure
394 pure
395+ ( maybe
396+ []
374− [ PragmaD (InlineP 'serialize inlineSerialize FunLike AllPhases)
397+ (\x -> [PragmaD (InlineP 'serializeAt x FunLike AllPhases)])
398+ cfgInlineSerialize
399+ ++
375− , FunD
400+ [FunD
376− 'serialize
401+ 'serializeAt
377− [ Clause
402+ [ Clause
378− (if isUnitType cons && not constructorTagAsString
403+ (if isUnitType cons && not cfgConstructorTagAsString
379− then [VarP _initialOffset, WildP, WildP]
404+ then [VarP _initialOffset, VarP _arr, WildP]
380− else [VarP _initialOffset, VarP _arr, VarP _val])
405+ else [VarP _initialOffset, VarP _arr, VarP _val])
381− (NormalB pokeMethod)
406+ (NormalB pokeMethod)
382− []
407+ []
383− ]
408+ ]
384− ]
409+ ]
410+ )
385
411
386--------------------------------------------------------------------------------
412--------------------------------------------------------------------------------
387-- Main
413-- Main
@@ -403,7 +429,7 @@ mkSerializeDec (Config {..}) headTy cons = do
403-- Usage:
429-- Usage:
404-- @
430-- @
405-- $(deriveSerializeInternal
431-- $(deriveSerializeInternal
406−-- defaultConfig
432+-- serializeConfig
407-- [AppT (ConT ''Serialize) (VarT (mkName "b"))]
433-- [AppT (ConT ''Serialize) (VarT (mkName "b"))]
408-- (AppT
434-- (AppT
409-- (AppT (ConT ''CustomDataType) (VarT (mkName "a")))
435-- (AppT (ConT ''CustomDataType) (VarT (mkName "a")))
@@ -418,7 +444,7 @@ mkSerializeDec (Config {..}) headTy cons = do
418-- ])
444-- ])
419-- @
445-- @
420deriveSerializeInternal ::
446deriveSerializeInternal ::
421− Config -> Type -> [DataCon] -> ([Dec] -> Q [Dec]) -> Q [Dec]
447+ SerializeConfig -> Type -> [DataCon] -> ([Dec] -> Q [Dec]) -> Q [Dec]
422deriveSerializeInternal conf headTy cons next = do
448deriveSerializeInternal conf headTy cons next = do
423 sizeDec <- mkSizeDec conf headTy cons
449 sizeDec <- mkSizeDec conf headTy cons
424 peekDec <- mkDeserializeDec conf headTy cons
450 peekDec <- mkDeserializeDec conf headTy cons
@@ -426,30 +452,41 @@ deriveSerializeInternal conf headTy cons next = do
426 let methods = concat [sizeDec, peekDec, pokeDec]
452 let methods = concat [sizeDec, peekDec, pokeDec]
427 next methods
453 next methods
428
454
429−-- | Similar to 'deriveSerialize' but take a 'Config' to control how the
455+-- | @deriveSerializeWith config-modifier instance-dec@ generates a template
430−-- instance is generated.
456+-- Haskell splice consisting of a declaration of a 'Serialize' instance.
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.
431--
464--
432-- Usage:
465-- Usage:
466+--
433-- @
467-- @
434−-- $(deriveSerializeWith
468+-- \$(deriveSerializeWith
435−-- config
469+-- ( inlineSerializeAt (Just NoInline)
470+-- . inlineDeserializeAt (Just NoInline)
471+-- )
436-- [d|instance Serialize a => Serialize (Maybe a)|])
472-- [d|instance Serialize a => Serialize (Maybe a)|])
437-- @
473-- @
438−deriveSerializeWith :: Config -> Q [Dec] -> Q [Dec]
474+deriveSerializeWith ::
475+ (SerializeConfig -> SerializeConfig) -> Q [Dec] -> Q [Dec]
439−deriveSerializeWith conf mDecs = do
476+deriveSerializeWith modifier mDecs = do
440 dec <- mDecs
477 dec <- mDecs
441 case dec of
478 case dec of
442− [inst@(InstanceD _ _ headTyWC [])] -> do
479+ [InstanceD mo preds headTyWC []] -> do
443 let headTy = unwrap dec headTyWC
480 let headTy = unwrap dec headTyWC
444 dt <- reifyDataType (getMainTypeName dec headTy)
481 dt <- reifyDataType (getMainTypeName dec headTy)
445 let cons = dtCons dt
482 let cons = dtCons dt
446− deriveSerializeInternal conf headTy cons (next inst)
483+ deriveSerializeInternal
484+ (modifier serializeConfig) headTy cons (next mo preds headTyWC)
447− _ -> errorUnsupported (errorMessage dec)
485+ _ -> errorMessage dec
486+
448− where
487+ where
449
488
450− next (InstanceD mo preds headTyWC []) methods =
451− pure [InstanceD mo preds headTyWC methods]
489+ next mo preds headTyWC methods = pure [InstanceD mo preds headTyWC methods]
452− next dec _ = errorUnsupported (errorMessage dec)
453
490
454 errorMessage dec =
491 errorMessage dec =
455 error $ unlines
492 error $ unlines
@@ -457,8 +494,8 @@ deriveSerializeWith conf mDecs = do
457 , ""
494 , ""
458 , ">> " ++ pprint dec
495 , ">> " ++ pprint dec
459 , ""
496 , ""
460− , "The above is not a valid instance declaration."
497+ , "The supplied declaration is not a valid instance declaration."
461− , "Any haskell instance declaration without a body is valid."
498+ , "Provide a valid Haskell instance declaration without a body."
462 , ""
499 , ""
463 , "Examples:"
500 , "Examples:"
464 , "instance Serialize (Proxy a)"
501 , "instance Serialize (Proxy a)"
@@ -477,37 +514,17 @@ deriveSerializeWith conf mDecs = do
477 go (AppT l _) = go l
514 go (AppT l _) = go l
478 go _ = errorMessage dec
515 go _ = errorMessage dec
479
516
480−
517+-- | Given an 'Serialize' instance declaration splice without the methods (e.g.
481−-- | Template haskell helper to create instances of 'Serialize' automatically.
518+-- @[d|instance Serialize a => Serialize (Maybe a)|]@), generate an instance
519+-- declaration including all the type class method implementations.
482--
520--
483−-- Consider the datatype:
521+-- >>> deriveSerialize = deriveSerializeWith id
484−-- @
485−-- data CustomDataType a b c = ...
486−-- @
487--
522--
488−-- Usage: @$(deriveSerialize ''CustomDataType)@
523+-- Usage:
489--
524--
490−-- Note: All type variables automatcally get an "Serialize" constraint.
491−-- The derived code will look like the following,
492-- @
525-- @
526+-- \$(deriveSerialize
493−-- instance (Serialize a, Serialize b, Serialize c) => Serialize (CustomDataType a b c) where
527+-- [d|instance Serialize a => Serialize (Maybe a)|])
494−-- ...
495-- @
528-- @
496−--
497−-- To control which type variables don't get the Serialize constraint, use
498−-- 'deriveSerializeWith'.
499−deriveSerialize :: Name -> Q [Dec]
529+deriveSerialize :: Q [Dec] -> Q [Dec]
500−deriveSerialize name = do
530+deriveSerialize = deriveSerializeWith id
501− dt <- reifyDataType name
502− let preds = map (unboxPred . VarT) (dtTvs dt)
503− headTy = appsT (ConT name) (map VarT (dtTvs dt))
504− cons = dtCons dt
505− deriveSerializeInternal defaultConfig headTy cons (next preds headTy)
506−
507−
508− where
509−
510− next preds headTy methods =
511− pure [InstanceD Nothing preds (AppT (ConT ''Serialize) headTy) methods]
512−
513− unboxPred ty = AppT (ConT ''Serialize) ty
core/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs+143−48
@@ -9,8 +9,17 @@
9-- Portability : GHC
9-- Portability : GHC
10--
10--
11module Streamly.Internal.Data.Serialize.TH.Bottom
11module Streamly.Internal.Data.Serialize.TH.Bottom
12+ (
12− ( Config(..)
13+ -- ** Config
13− , defaultConfig
14+ SerializeConfig(..)
15+ , serializeConfig
16+ , inlineAddSizeTo
17+ , inlineSerializeAt
18+ , inlineDeserializeAt
19+ , encodeConstrNames
20+ , encodeRecordFields
21+
22+ -- ** Other Utilities
14 , TypeOfType(..)
23 , TypeOfType(..)
15 , typeOfType
24 , typeOfType
16 , SimpleDataCon(..)
25 , SimpleDataCon(..)
@@ -65,48 +74,134 @@ import Streamly.Internal.Data.Unbox.TH (DataCon(..))
65-- Config
74-- Config
66--------------------------------------------------------------------------------
75--------------------------------------------------------------------------------
67
76
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+
68−-- | Config to control how the 'Serialize' instance is generated.
83+-- | Configuration to control how the 'Serialize' instance is generated. The
69−data Config =
84+-- configuration is opaque and is modified by composing config modifier
70− Config
85+-- functions, for example:
71− { inlineSize :: Inline
86+--
72− -- ^ Inline value for 'size'. Default is Inline.
87+-- >>> (inlineSerializeAt (Just NoInline)) . (inlineSerializeAt (Just Inlinable))
73− , inlineSerialize :: Inline
88+--
74− -- ^ Inline value for 'serialize'. Default is Inline.
89+-- The default configuration settings are:
75− , inlineDeserialize :: Inline
90+--
76− -- ^ Inline value for 'deserialize'. Default is Inline.
91+-- * 'inlineAddSizeTo' Nothing
77− , constructorTagAsString :: Bool
92+-- * 'inlineSerializeAt' (Just Inline)
78− -- ^ __Experimental__
93+-- * 'inlineDeserializeAt' (Just Inline)
79− --
94+--
80− -- If True, encode constructors using the constructor names as Latin-1
95+-- The following experimental options are also available:
81− -- byte sequence.
96+--
82− , recordSyntaxWithHeader :: Bool
97+-- * 'encodeConstrNames' False
83− -- ^ __Experimental__
98+-- * 'encodeRecordFields' False
84− --
99+--
85− -- If True, encode the keys of the record as a header and then
100+data SerializeConfig =
86− -- serialize the data. Multiple constructors are not supported with
101+ SerializeConfig
87− -- @recordSyntaxWithHeader@ enabled.
102+ { cfgInlineSize :: Maybe Inline
88− --
103+ , cfgInlineSerialize :: Maybe Inline
89− -- __Performance Notes:__
104+ , cfgInlineDeserialize :: Maybe Inline
90− --
105+ , cfgConstructorTagAsString :: Bool
91− -- There is a constant regression proportional to
106+ , cfgRecordSyntaxWithHeader :: Bool
92− -- @sum (map length keyList) + length keyList@ where @keyList@ is the
93− -- list of keys of that record as strings.
94− --
95− -- As an example, @keyList@ of,
96− -- @
97− -- data RecordType = RecordType { field0 :: Int, field2 :: Char }
98− -- @
99− -- is @["field0", "field1"]@
100 }
107 }
101
108
102−defaultConfig :: Config
109+-- | How should we inline the 'addSizeTo' function? The default is 'Nothing'
103−defaultConfig =
110+-- which means left to the compiler. Forcing inline on @addSizeTo@ function
104− Config
111+-- actually worsens some benchmarks and improves none.
105− { inlineSize = Inline
112+inlineAddSizeTo :: Maybe Inline -> SerializeConfig -> SerializeConfig
106− , inlineSerialize = Inline
113+inlineAddSizeTo v cfg = cfg {cfgInlineSize = v}
107− , inlineDeserialize = Inline
114+
108− , constructorTagAsString = False
115+-- XXX Should we make the default Inlinable instead?
109− , recordSyntaxWithHeader = False
116+
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
110 }
205 }
111
206
112--------------------------------------------------------------------------------
207--------------------------------------------------------------------------------
@@ -252,7 +347,7 @@ xorCmp tag off arr =
252 go8 i = do
347 go8 i = do
253 let wIntegral = litIntegral i
348 let wIntegral = litIntegral i
254 [|xor (unsafeInlineIO
349 [|xor (unsafeInlineIO
255− (Unbox.peekByteIndex
350+ (Unbox.peekAt
256 ($(varE off) + $(litIntegral i))
351 ($(varE off) + $(litIntegral i))
257 $(varE arr)))
352 $(varE arr)))
258 ($(wIntegral) :: Word8) .|.
353 ($(wIntegral) :: Word8) .|.
@@ -266,7 +361,7 @@ xorCmp tag off arr =
266 litIntegral
361 litIntegral
267 (shiftAdd w8_w16 [tag !! i, tag !! (i + 1)] :: Word16)
362 (shiftAdd w8_w16 [tag !! i, tag !! (i + 1)] :: Word16)
268 [|xor (unsafeInlineIO
363 [|xor (unsafeInlineIO
269− (Unbox.peekByteIndex
364+ (Unbox.peekAt
270 ($(varE off) + $(litIntegral i))
365 ($(varE off) + $(litIntegral i))
271 $(varE arr)))
366 $(varE arr)))
272 ($(wIntegral) :: Word16) .|.
367 ($(wIntegral) :: Word16) .|.
@@ -286,7 +381,7 @@ xorCmp tag off arr =
286 , tag !! (i + 3)
381 , tag !! (i + 3)
287 ] :: Word32)
382 ] :: Word32)
288 [|xor (unsafeInlineIO
383 [|xor (unsafeInlineIO
289− (Unbox.peekByteIndex
384+ (Unbox.peekAt
290 ($(varE off) + $(litIntegral i))
385 ($(varE off) + $(litIntegral i))
291 $(varE arr)))
386 $(varE arr)))
292 ($(wIntegral) :: Word32) .|.
387 ($(wIntegral) :: Word32) .|.
@@ -310,7 +405,7 @@ xorCmp tag off arr =
310 , tag !! (i + 7)
405 , tag !! (i + 7)
311 ])
406 ])
312 [|xor (unsafeInlineIO
407 [|xor (unsafeInlineIO
313− (Unbox.peekByteIndex
408+ (Unbox.peekAt
314 ($(varE off) + $(litIntegral i))
409 ($(varE off) + $(litIntegral i))
315 $(varE arr)))
410 $(varE arr)))
316 ($(wIntegral) :: Word64) .|.
411 ($(wIntegral) :: Word64) .|.
@@ -336,7 +431,7 @@ serializeW8List off arr w8List = do
336 makeBind i =
431 makeBind i =
337 bindS
432 bindS
338 (varP (makeN (i + 1)))
433 (varP (makeN (i + 1)))
339− [|$(varE 'serialize)
434+ [|$(varE 'serializeAt)
340 $(varE (makeN i))
435 $(varE (makeN i))
341 $(varE arr)
436 $(varE arr)
342 ($(litIntegral (w8List !! i)) :: Word8)|]
437 ($(litIntegral (w8List !! i)) :: Word8)|]
@@ -361,7 +456,7 @@ errorUnsupported err =
361 $ unlines
456 $ unlines
362 [ "Unsupported"
457 [ "Unsupported"
363 , "==========="
458 , "==========="
364− , "There is improper use of the library."
459+ , "This is improper use of the library."
365 , "This case is unsupported."
460 , "This case is unsupported."
366 , "Please contact the developer if this case is of interest."
461 , "Please contact the developer if this case is of interest."
367 , ""
462 , ""
core/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs+37−37
@@ -9,9 +9,9 @@
9-- Portability : GHC
9-- Portability : GHC
10--
10--
11module Streamly.Internal.Data.Serialize.TH.RecHeader
11module Streamly.Internal.Data.Serialize.TH.RecHeader
12− ( mkSerializeExpr
12+ ( mkRecSerializeExpr
13− , mkDeserializeExpr
13+ , mkRecDeserializeExpr
14− , mkSizeOfExpr
14+ , mkRecSizeOfExpr
15 , conUpdateFuncDec
15 , conUpdateFuncDec
16 , mkDeserializeKeysDec
16 , mkDeserializeKeysDec
17 ) where
17 ) where
@@ -27,7 +27,7 @@ import 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.Unbox (MutableByteArray)
30+import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
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
@@ -103,36 +103,36 @@ newtype CompactList a =
103-- the list is 255.
103-- the list is 255.
104instance forall a. Serialize a => Serialize (CompactList a) where
104instance forall a. Serialize a => Serialize (CompactList a) where
105
105
106− -- {-# INLINE size #-}
106+ -- {-# INLINE addSizeTo #-}
107− size acc (CompactList xs) =
107+ addSizeTo acc (CompactList xs) =
108− foldl' size (acc + (Unbox.sizeOf (Proxy :: Proxy Word8))) xs
108+ foldl' addSizeTo (acc + (Unbox.sizeOf (Proxy :: Proxy Word8))) xs
109
109
110 -- Inlining this causes large compilation times for tests
110 -- Inlining this causes large compilation times for tests
111− {-# INLINABLE deserialize #-}
111+ {-# INLINABLE deserializeAt #-}
112− deserialize off arr sz = do
112+ deserializeAt off arr sz = do
113− (off1, len8) <- deserialize off arr sz :: IO (Int, Word8)
113+ (off1, len8) <- deserializeAt off arr sz :: IO (Int, Word8)
114 let len = w8_int len8
114 let len = w8_int len8
115 peekList f o i | i >= 3 = do
115 peekList f o i | i >= 3 = do
116 -- Unfold the loop three times
116 -- Unfold the loop three times
117− (o1, x1) <- deserialize o arr sz
117+ (o1, x1) <- deserializeAt o arr sz
118− (o2, x2) <- deserialize o1 arr sz
118+ (o2, x2) <- deserializeAt o1 arr sz
119− (o3, x3) <- deserialize o2 arr sz
119+ (o3, x3) <- deserializeAt o2 arr sz
120 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
120 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
121 peekList f o 0 = pure (o, f [])
121 peekList f o 0 = pure (o, f [])
122 peekList f o i = do
122 peekList f o i = do
123− (o1, x) <- deserialize o arr sz
123+ (o1, x) <- deserializeAt o arr sz
124 peekList (f . (x:)) o1 (i - 1)
124 peekList (f . (x:)) o1 (i - 1)
125 (nextOff, lst) <- peekList id off1 len
125 (nextOff, lst) <- peekList id off1 len
126 pure (nextOff, CompactList lst)
126 pure (nextOff, CompactList lst)
127
127
128 -- Inlining this causes large compilation times for tests
128 -- Inlining this causes large compilation times for tests
129− {-# INLINABLE serialize #-}
129+ {-# INLINABLE serializeAt #-}
130− serialize off arr (CompactList val) = do
130+ serializeAt off arr (CompactList val) = do
131− void $ serialize off arr (int_w8 (length val) :: Word8)
131+ void $ serializeAt off arr (int_w8 (length val) :: Word8)
132 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Word8)
132 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Word8)
133 let pokeList o [] = pure o
133 let pokeList o [] = pure o
134 pokeList o (x:xs) = do
134 pokeList o (x:xs) = do
135− o1 <- serialize o arr x
135+ o1 <- serializeAt o arr x
136 pokeList o1 xs
136 pokeList o1 xs
137 pokeList off1 val
137 pokeList off1 val
138
138
@@ -154,7 +154,7 @@ isMaybeType _ = False
154-- We add 4 here because we use 'serializeWithSize' for serializing.
154-- We add 4 here because we use 'serializeWithSize' for serializing.
155exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
155exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
156exprGetSize acc (i, _) =
156exprGetSize acc (i, _) =
157− [|size $(acc) $(varE (mkFieldName i)) + 4|]
157+ [|addSizeTo $(acc) $(varE (mkFieldName i)) + 4|]
158
158
159sizeOfHeader :: SimpleDataCon -> Int
159sizeOfHeader :: SimpleDataCon -> Int
160sizeOfHeader (SimpleDataCon _ fields) =
160sizeOfHeader (SimpleDataCon _ fields) =
@@ -171,8 +171,8 @@ sizeOfHeader (SimpleDataCon _ fields) =
171 sizeForNumFields = 1 -- At max 255 fields in the record constructor
171 sizeForNumFields = 1 -- At max 255 fields in the record constructor
172 sizeForFieldLen = 1 -- At max 255 letters in the key
172 sizeForFieldLen = 1 -- At max 255 letters in the key
173
173
174−mkSizeOfExpr :: SimpleDataCon -> Q Exp
174+mkRecSizeOfExpr :: SimpleDataCon -> Q Exp
175−mkSizeOfExpr con = do
175+mkRecSizeOfExpr con = do
176 n_acc <- newName "acc"
176 n_acc <- newName "acc"
177 n_x <- newName "x"
177 n_x <- newName "x"
178 (lamE
178 (lamE
@@ -225,27 +225,27 @@ headerValue (SimpleDataCon _ fields) =
225-- its type. We encode the size as 'Word32' hence there is a 4 bytes increase
225-- its type. We encode the size as 'Word32' hence there is a 4 bytes increase
226-- in size.
226-- in size.
227{-# INLINE serializeWithSize #-}
227{-# INLINE serializeWithSize #-}
228−serializeWithSize :: Serialize a => Int -> MutableByteArray -> a -> IO Int
228+serializeWithSize :: Serialize a => Int -> MutByteArray -> a -> IO Int
229serializeWithSize off arr val = do
229serializeWithSize off arr val = do
230− off1 <- serialize (off + 4) arr val
230+ off1 <- serializeAt (off + 4) arr val
231− Unbox.pokeByteIndex off arr (int_w32 (off1 - off - 4) :: Word32)
231+ Unbox.pokeAt off arr (int_w32 (off1 - off - 4) :: Word32)
232 pure off1
232 pure off1
233
233
234−mkSerializeExpr :: Name -> SimpleDataCon -> Q Exp
234+mkRecSerializeExpr :: Name -> SimpleDataCon -> Q Exp
235−mkSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
235+mkRecSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
236 afterHLen <- newName "afterHLen"
236 afterHLen <- newName "afterHLen"
237 -- Encoding the header length is required.
237 -- Encoding the header length is required.
238 -- We first compare the header length encoded and the current header
238 -- We first compare the header length encoded and the current header
239 -- length. Only if the header lengths match, we compare the headers.
239 -- length. Only if the header lengths match, we compare the headers.
240 [|do $(varP afterHLen) <-
240 [|do $(varP afterHLen) <-
241− serialize
241+ serializeAt
242 ($(varE initialOffset) + 4)
242 ($(varE initialOffset) + 4)
243 $(varE _arr)
243 $(varE _arr)
244 ($(litIntegral hlen) :: Word32)
244 ($(litIntegral hlen) :: Word32)
245 $(varP (makeI 0)) <- $(serializeW8List afterHLen _arr hval)
245 $(varP (makeI 0)) <- $(serializeW8List afterHLen _arr hval)
246 let $(openConstructor cname (length fields)) = $(varE _val)
246 let $(openConstructor cname (length fields)) = $(varE _val)
247 finalOff <- $(mkSerializeExprFields 'serializeWithSize fields)
247 finalOff <- $(mkSerializeExprFields 'serializeWithSize fields)
248− Unbox.pokeByteIndex
248+ Unbox.pokeAt
249 $(varE initialOffset)
249 $(varE initialOffset)
250 $(varE _arr)
250 $(varE _arr)
251 ((fromIntegral :: Int -> Word32)
251 ((fromIntegral :: Int -> Word32)
@@ -263,8 +263,8 @@ mkSerializeExpr initialOffset (con@(SimpleDataCon cname fields)) = do
263
263
264{-# INLINE deserializeWithSize #-}
264{-# INLINE deserializeWithSize #-}
265deserializeWithSize ::
265deserializeWithSize ::
266− Serialize a => Int -> MutableByteArray -> Int -> IO (Int, a)
266+ Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
267−deserializeWithSize off arr endOff = deserialize (off + 4) arr endOff
267+deserializeWithSize off arr endOff = deserializeAt (off + 4) arr endOff
268
268
269conUpdateFuncDec :: Name -> [Field] -> Q [Dec]
269conUpdateFuncDec :: Name -> [Field] -> Q [Dec]
270conUpdateFuncDec funcName fields = do
270conUpdateFuncDec funcName fields = do
@@ -282,7 +282,7 @@ conUpdateFuncDec funcName fields = do
282 wildP
282 wildP
283 (normalB
283 (normalB
284 [|do (valOff, valLen :: Word32) <-
284 [|do (valOff, valLen :: Word32) <-
285− deserialize
285+ deserializeAt
286 $(varE curOff)
286 $(varE curOff)
287 $(varE arr)
287 $(varE arr)
288 $(varE endOff)
288 $(varE endOff)
@@ -317,7 +317,7 @@ conUpdateFuncDec funcName fields = do
317 (litP fnameLit)
317 (litP fnameLit)
318 (normalB
318 (normalB
319 [|do (valOff, valLen :: Word32) <-
319 [|do (valOff, valLen :: Word32) <-
320− deserialize
320+ deserializeAt
321 $(varE currOff)
321 $(varE currOff)
322 $(varE arr)
322 $(varE arr)
323 $(varE endOff)
323 $(varE endOff)
@@ -345,7 +345,7 @@ mkDeserializeKeysDec funcName updateFunc (SimpleDataCon cname fields) = do
345 errorUnsupported "The datatype should use record syntax."
345 errorUnsupported "The datatype should use record syntax."
346 method <-
346 method <-
347 [|do (dataOff, hlist :: CompactList (CompactList Word8)) <-
347 [|do (dataOff, hlist :: CompactList (CompactList Word8)) <-
348− deserialize $(varE hOff) $(varE arr) $(varE endOff)
348+ deserializeAt $(varE hOff) $(varE arr) $(varE endOff)
349 let keys = wListToString . unCompactList <$> unCompactList hlist
349 let keys = wListToString . unCompactList <$> unCompactList hlist
350 ($(varP kvEncoded), _) <-
350 ($(varP kvEncoded), _) <-
351 foldlM
351 foldlM
@@ -383,16 +383,16 @@ mkDeserializeKeysDec funcName updateFunc (SimpleDataCon cname fields) = do
383 else [|error $(litE (StringL (nameBase k ++ " is not found.")))|]
383 else [|error $(litE (StringL (nameBase k ++ " is not found.")))|]
384
384
385
385
386−mkDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
386+mkRecDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
387−mkDeserializeExpr initialOff endOff deserializeWithKeys con = do
387+mkRecDeserializeExpr initialOff endOff deserializeWithKeys con = do
388 hOff <- newName "hOff"
388 hOff <- newName "hOff"
389 let sizeForFinalOff = 4 -- Word32
389 let sizeForFinalOff = 4 -- Word32
390 sizeForHeaderLength = 4 -- Word32
390 sizeForHeaderLength = 4 -- Word32
391 sizePreData = sizeForFinalOff + sizeForHeaderLength + hlen
391 sizePreData = sizeForFinalOff + sizeForHeaderLength + hlen
392 [|do (hlenOff, encLen :: Word32) <-
392 [|do (hlenOff, encLen :: Word32) <-
393− deserialize $(varE initialOff) $(varE _arr) $(varE endOff)
393+ deserializeAt $(varE initialOff) $(varE _arr) $(varE endOff)
394 ($(varP hOff), hlen1 :: Word32) <-
394 ($(varP hOff), hlen1 :: Word32) <-
395− deserialize hlenOff $(varE _arr) $(varE endOff)
395+ deserializeAt hlenOff $(varE _arr) $(varE endOff)
396 if (hlen1 == $(litIntegral hlen)) && $(xorCmp hval hOff _arr)
396 if (hlen1 == $(litIntegral hlen)) && $(xorCmp hval hOff _arr)
397 then do
397 then do
398 let $(varP (makeI 0)) =
398 let $(varP (makeI 0)) =
core/src/Streamly/Internal/Data/Serialize/Type.hs+140−137
@@ -7,37 +7,27 @@
7--
7--
8
8
9module Streamly.Internal.Data.Serialize.Type
9module Streamly.Internal.Data.Serialize.Type
10+ (
10− ( Serialize(..)
11+ Serialize(..)
11− , encode
12− , pinnedEncode
13− , decode
14 ) where
12 ) where
15
13
16--------------------------------------------------------------------------------
14--------------------------------------------------------------------------------
17-- Imports
15-- Imports
18--------------------------------------------------------------------------------
16--------------------------------------------------------------------------------
19
17
20−#include "assert.hs"
21−
22−#ifdef DEBUG
23−import Control.Exception (assert)
18+import Control.Monad (when)
24−#endif
25−
26import Data.List (foldl')
19import Data.List (foldl')
27import Data.Proxy (Proxy (..))
20import Data.Proxy (Proxy (..))
28−import Streamly.Internal.Data.Unbox
21+import Streamly.Internal.Data.Unbox (Unbox)
29− ( MutableByteArray(..)
22+import Streamly.Internal.Data.MutByteArray.Type (MutByteArray(..))
30− , PinnedState(..)
31− , Unbox
32− )
33import Streamly.Internal.Data.Array.Type (Array(..))
23import Streamly.Internal.Data.Array.Type (Array(..))
34−import Streamly.Internal.System.IO (unsafeInlineIO)
35import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
24import GHC.Int (Int16(..), Int32(..), Int64(..), Int8(..))
36import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
25import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
37import GHC.Stable (StablePtr(..))
26import GHC.Stable (StablePtr(..))
38
27
28+import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
39import qualified Streamly.Internal.Data.Unbox as Unbox
29import qualified Streamly.Internal.Data.Unbox as Unbox
40−import qualified Streamly.Internal.Data.Array as Array
30+import qualified Streamly.Internal.Data.Array.Type as Array
41import qualified Streamly.Internal.Data.MutArray as MutArray
31import qualified Streamly.Internal.Data.MutArray as MutArray
42
32
43import GHC.Exts
33import GHC.Exts
@@ -59,21 +49,33 @@ import GHC.Exts
59-- Types
49-- Types
60--------------------------------------------------------------------------------
50--------------------------------------------------------------------------------
61
51
62−-- | A type implementing the 'Serialize' interface supplies operations for
52+-- | The 'Serialize' type class provides operations for serialization and
63−-- reading and writing the type from and to a mutable byte array (an unboxed
53+-- deserialization of general Haskell data types to and from their byte stream
64−-- representation of the type) in memory. The read operation 'deserialize'
54+-- representation.
65−-- deserializes the boxed type from the mutable byte array. The write operation
55+--
66−-- 'serialize' serializes the boxed type to the mutable byte array.
56+-- Unlike 'Unbox', 'Serialize' uses variable length encoding, therefore, it can
57+-- serialize recursive and variable length data types like lists, or variable
58+-- length sum types where the length of the value may vary depending on a
59+-- particular constructor. For variable length data types the length is encoded
60+-- along with the data.
67--
61--
68−-- IMPORTANT: The serialized data's byte ordering is not normalized, which means
62+-- The 'deserializeAt' operation reads bytes from the mutable byte array and
69−-- it remains the same as the machine's byte order where the function is
63+-- builds a Haskell data type from these bytes, the number of bytes it reads
70−-- executed. Consequently, it may not be compatible across machines with
64+-- depends on the type and the encoded value it is reading. 'serializeAt'
71−-- different byte ordering.
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'.
72--
70--
73−-- 'Serialize' contains enough information to serialize and deserialize variable
71+-- IMPORTANT: The serialized data's byte ordering remains the same as the host
74−-- length types.
72+-- machine's byte order. Therefore, it can not be deserialized from host
73+-- machines with a different byte ordering.
75--
74--
76−-- >>> import Streamly.Internal.Data.Serialize.Type (Serialize(..))
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:
77--
79--
78-- >>> :{
80-- >>> :{
79-- data Object = Object
81-- data Object = Object
@@ -82,16 +84,30 @@ import GHC.Exts
82-- }
84-- }
83-- :}
85-- :}
84--
86--
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+--
85-- >>> :{
100-- >>> :{
86-- instance Serialize Object where
101-- instance Serialize Object where
87−-- size acc obj = size (size acc (_obj1 obj)) (_obj2 obj)
102+-- addSizeTo acc obj = addSizeTo (addSizeTo acc (_obj1 obj)) (_obj2 obj)
88−-- deserialize i arr len = do
103+-- deserializeAt i arr len = do
104+-- -- Check the array bounds before reading
89−-- (i1, x0) <- deserialize i arr len
105+-- (i1, x0) <- deserializeAt i arr len
90−-- (i2, x1) <- deserialize i1 arr len
106+-- (i2, x1) <- deserializeAt i1 arr len
91-- pure (i2, Object x0 x1)
107-- pure (i2, Object x0 x1)
92−-- serialize i arr (Object x0 x1) = do
108+-- serializeAt i arr (Object x0 x1) = do
93−-- i1 <- serialize i arr x0
109+-- i1 <- serializeAt i arr x0
94−-- i2 <- serialize i1 arr x1
110+-- i2 <- serializeAt i1 arr x1
95-- pure i2
111-- pure i2
96-- :}
112-- :}
97--
113--
@@ -102,44 +118,50 @@ class Serialize a where
102 -- It is of the form @Int -> a -> Int@ because you can have tail-recursive
118 -- It is of the form @Int -> a -> Int@ because you can have tail-recursive
103 -- traversal of the structures.
119 -- traversal of the structures.
104
120
105− -- | Get the size, in bytes, reqired to store the serialized
121+ -- | @addSizeTo accum value@ returns @accum@ incremented by the size of the
106− -- representation of the type. Size cannot be zero.
122+ -- serialized representation of @value@ in bytes. Size cannot be zero. It
123+ -- should be at least 1 byte.
107− size :: Int -> a -> Int
124+ addSizeTo :: Int -> a -> Int
108
125
109 -- We can implement the following functions without returning the `Int`
126 -- We can implement the following functions without returning the `Int`
110 -- offset but that may require traversing the Haskell structure again to get
127 -- offset but that may require traversing the Haskell structure again to get
111 -- the size. Therefore, this is a performance optimization.
128 -- the size. Therefore, this is a performance optimization.
112
129
113− -- | @deserialize offset array arrayLen@ deserializes a value from the
130+ -- | @deserializeAt byte-offset array arrayLen@ deserializes a value from
114− -- given byte-index in the array. Returns a tuple of the next byte-index
131+ -- the given byte-offset in the array. Returns a tuple consisting of the
115− -- and the deserialized value.
132+ -- next byte-offset and the deserialized value.
116− deserialize :: Int -> MutableByteArray -> Int -> IO (Int, a)
133+ --
117−
134+ -- The arrayLen passed is the entire length of the input buffer. It is to
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
118− -- | Write the serialized representation of the value in the array at the
142+ -- representation of the @value@ in the array at the given byte-offset.
119− -- given byte-index. Returns the next byte-index. This is an unsafe
143+ -- Returns the next byte-offset.
144+ --
120− -- operation, the programmer must ensure that the array has enough space
145+ -- This is an unsafe operation, the programmer must ensure that the array
121− -- available in the array to serialize the value as determined by the
146+ -- has enough space available to serialize the value as determined by the
122− -- @size@ operation.
147+ -- @addSizeTo@ operation.
123− serialize :: Int -> MutableByteArray -> a -> IO Int
148+ serializeAt :: Int -> MutByteArray -> a -> IO Int
124
149
125--------------------------------------------------------------------------------
150--------------------------------------------------------------------------------
126-- Instances
151-- Instances
127--------------------------------------------------------------------------------
152--------------------------------------------------------------------------------
128
153
129−-- XXX We do not need to pass the end of data offset, we can just check the
154+-- _size is the length from array start to the last accessed byte.
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−--
133#ifdef DEBUG
155#ifdef DEBUG
134{-# INLINE checkBounds #-}
156{-# INLINE checkBounds #-}
135−checkBounds :: String -> Int -> MutableByteArray -> IO ()
157+checkBounds :: String -> Int -> MutByteArray -> IO ()
136−checkBounds _label _off _arr = do
158+checkBounds _label _size _arr = do
137− sz <- sizeOfMutableByteArray _arr
159+ sz <- MBA.sizeOfMutableByteArray _arr
138− if (_off > sz)
160+ if (_size > sz)
139 then error
161 then error
140 $ _label
162 $ _label
141 ++ ": accessing array at offset = "
163 ++ ": accessing array at offset = "
142− ++ show (_off - 1)
164+ ++ show (_size - 1)
143 ++ " max valid offset = " ++ show (sz - 1)
165 ++ " max valid offset = " ++ show (sz - 1)
144 else return ()
166 else return ()
145#endif
167#endif
@@ -162,39 +184,39 @@ checkBounds _label _off _arr = do
162-- single array for deserializing. But that can also be done by framing the
184-- single array for deserializing. But that can also be done by framing the
163-- serialized value with a size header.
185-- serialized value with a size header.
164--
186--
165−{-# INLINE deserializeUnsafe #-}
187+{-# INLINE deserializeChecked #-}
166−deserializeUnsafe :: forall a. Unbox a => Int -> MutableByteArray -> Int -> IO (Int, a)
188+deserializeChecked :: forall a. Unbox a => Int -> MutByteArray -> Int -> IO (Int, a)
167−deserializeUnsafe off arr sz =
189+deserializeChecked off arr sz =
168 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
190 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
169 in do
191 in do
170 -- Keep likely path in the straight branch.
192 -- Keep likely path in the straight branch.
171 if (next <= sz)
193 if (next <= sz)
172− then Unbox.peekByteIndex off arr >>= \val -> pure (next, val)
194+ then Unbox.peekAt off arr >>= \val -> pure (next, val)
173 else error
195 else error
174− $ "deserialize: accessing array at offset = "
196+ $ "deserializeAt: accessing array at offset = "
175 ++ show (next - 1)
197 ++ show (next - 1)
176 ++ " max valid offset = " ++ show (sz - 1)
198 ++ " max valid offset = " ++ show (sz - 1)
177
199
178{-# INLINE serializeUnsafe #-}
200{-# INLINE serializeUnsafe #-}
179−serializeUnsafe :: forall a. Unbox a => Int -> MutableByteArray -> a -> IO Int
201+serializeUnsafe :: forall a. Unbox a => Int -> MutByteArray -> a -> IO Int
180serializeUnsafe off arr val =
202serializeUnsafe off arr val =
181 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
203 let next = off + Unbox.sizeOf (Proxy :: Proxy a)
182 in do
204 in do
183#ifdef DEBUG
205#ifdef DEBUG
184− checkBounds "serialize" next arr
206+ checkBounds "serializeAt" next arr
185#endif
207#endif
186− Unbox.pokeByteIndex off arr val
208+ Unbox.pokeAt off arr val
187 pure next
209 pure next
188
210
189#define DERIVE_SERIALIZE_FROM_UNBOX(_type) \
211#define DERIVE_SERIALIZE_FROM_UNBOX(_type) \
190instance Serialize _type where \
212instance Serialize _type where \
191−; {-# INLINE size #-} \
213+; {-# INLINE addSizeTo #-} \
192−; size acc _ = acc + Unbox.sizeOf (Proxy :: Proxy _type) \
214+; addSizeTo acc _ = acc + Unbox.sizeOf (Proxy :: Proxy _type) \
193−; {-# INLINE deserialize #-} \
215+; {-# INLINE deserializeAt #-} \
194−; deserialize off arr end = deserializeUnsafe off arr end :: IO (Int, _type) \
216+; deserializeAt off arr end = deserializeChecked off arr end :: IO (Int, _type) \
195−; {-# INLINE serialize #-} \
217+; {-# INLINE serializeAt #-} \
196−; serialize = \
218+; serializeAt = \
197− serializeUnsafe :: Int -> MutableByteArray -> _type -> IO Int
219+ serializeUnsafe :: Int -> MutByteArray -> _type -> IO Int
198
220
199DERIVE_SERIALIZE_FROM_UNBOX(())
221DERIVE_SERIALIZE_FROM_UNBOX(())
200DERIVE_SERIALIZE_FROM_UNBOX(Bool)
222DERIVE_SERIALIZE_FROM_UNBOX(Bool)
@@ -217,98 +239,79 @@ DERIVE_SERIALIZE_FROM_UNBOX((FunPtr a))
217
239
218instance forall a. Serialize a => Serialize [a] where
240instance forall a. Serialize a => Serialize [a] where
219
241
220− -- {-# INLINE size #-}
242+ -- {-# INLINE addSizeTo #-}
243+ addSizeTo acc xs =
221− size acc xs = foldl' size (acc + (Unbox.sizeOf (Proxy :: Proxy Int))) xs
244+ foldl' addSizeTo (acc + (Unbox.sizeOf (Proxy :: Proxy Int))) xs
222
245
223 -- Inlining this causes large compilation times for tests
246 -- Inlining this causes large compilation times for tests
224− {-# INLINABLE deserialize #-}
247+ {-# INLINABLE deserializeAt #-}
225− deserialize off arr sz = do
248+ deserializeAt off arr sz = do
226− (off1, len64) <- deserialize off arr sz :: IO (Int, Int64)
249+ (off1, len64) <- deserializeAt off arr sz :: IO (Int, Int64)
227 let len = (fromIntegral :: Int64 -> Int) len64
250 let len = (fromIntegral :: Int64 -> Int) len64
228 peekList f o i | i >= 3 = do
251 peekList f o i | i >= 3 = do
229 -- Unfold the loop three times
252 -- Unfold the loop three times
230− (o1, x1) <- deserialize o arr sz
253+ (o1, x1) <- deserializeAt o arr sz
231− (o2, x2) <- deserialize o1 arr sz
254+ (o2, x2) <- deserializeAt o1 arr sz
232− (o3, x3) <- deserialize o2 arr sz
255+ (o3, x3) <- deserializeAt o2 arr sz
233 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
256 peekList (f . (\xs -> x1:x2:x3:xs)) o3 (i - 3)
234 peekList f o 0 = pure (o, f [])
257 peekList f o 0 = pure (o, f [])
235 peekList f o i = do
258 peekList f o i = do
236− (o1, x) <- deserialize o arr sz
259+ (o1, x) <- deserializeAt o arr sz
237 peekList (f . (x:)) o1 (i - 1)
260 peekList (f . (x:)) o1 (i - 1)
238 peekList id off1 len
261 peekList id off1 len
239
262
240 -- Inlining this causes large compilation times for tests
263 -- Inlining this causes large compilation times for tests
241− {-# INLINABLE serialize #-}
264+ {-# INLINABLE serializeAt #-}
242− serialize off arr val = do
265+ serializeAt off arr val = do
243 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Int64)
266 let off1 = off + Unbox.sizeOf (Proxy :: Proxy Int64)
244 let pokeList acc o [] =
267 let pokeList acc o [] =
245− Unbox.pokeByteIndex off arr (acc :: Int64) >> pure o
268+ Unbox.pokeAt off arr (acc :: Int64) >> pure o
246 pokeList acc o (x:xs) = do
269 pokeList acc o (x:xs) = do
247− o1 <- serialize o arr x
270+ o1 <- serializeAt o arr x
248 pokeList (acc + 1) o1 xs
271 pokeList (acc + 1) o1 xs
249 pokeList 0 off1 val
272 pokeList 0 off1 val
250
273
274+instance
275+#ifdef DEVBUILD
276+ Unbox a =>
277+#endif
251−instance Serialize (Array a) where
278+ Serialize (Array a) where
252− {-# INLINE size #-}
279+ {-# INLINE addSizeTo #-}
253− size i (Array {..}) = i + (arrEnd - arrStart) + 8
280+ addSizeTo i (Array {..}) = i + (arrEnd - arrStart) + 8
254
281
255− {-# INLINE deserialize #-}
282+ {-# INLINE deserializeAt #-}
256− deserialize off arr end = do
283+ deserializeAt off arr len = do
257− (off1, byteLen) <- deserialize off arr end :: IO (Int, Int)
284+ (off1, byteLen) <- deserializeAt off arr len :: IO (Int, Int)
258 let off2 = off1 + byteLen
285 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
259 let slice = MutArray.MutArray arr off1 off2 off2
292 let slice = MutArray.MutArray arr off1 off2 off2
260 newArr <- MutArray.clone slice
293 newArr <- MutArray.clone slice
261 pure (off2, Array.unsafeFreeze newArr)
294 pure (off2, Array.unsafeFreeze newArr)
262
295
263− {-# INLINE serialize #-}
296+ {-# INLINE serializeAt #-}
264− serialize off arr (Array {..}) = do
297+ serializeAt off arr (Array {..}) = do
265 let arrLen = arrEnd - arrStart
298 let arrLen = arrEnd - arrStart
266− off1 <- serialize off arr arrLen
299+ off1 <- serializeAt off arr arrLen
267− Unbox.putSliceUnsafe arrContents arrStart arr off1 arrLen
300+ MBA.putSliceUnsafe arrContents arrStart arr off1 arrLen
268 pure (off1 + arrLen)
301 pure (off1 + arrLen)
269
302
270instance (Serialize a, Serialize b) => Serialize (a, b) where
303instance (Serialize a, Serialize b) => Serialize (a, b) where
271
304
272− {-# INLINE size #-}
305+ {-# INLINE addSizeTo #-}
273− size acc (a, b) = size (size acc a) b
306+ addSizeTo acc (a, b) = addSizeTo (addSizeTo acc a) b
274
307
275− {-# INLINE serialize #-}
308+ {-# INLINE serializeAt #-}
276− serialize off arr (a, b) = do
309+ serializeAt off arr (a, b) = do
277− off1 <- serialize off arr a
310+ off1 <- serializeAt off arr a
278− serialize off1 arr b
311+ serializeAt off1 arr b
279
312
280− {-# INLINE deserialize #-}
313+ {-# INLINE deserializeAt #-}
281− deserialize off arr end = do
314+ deserializeAt off arr end = do
282− (off1, a) <- deserialize off arr end
315+ (off1, a) <- deserializeAt off arr end
283− (off2, b) <- deserialize off1 arr end
316+ (off2, b) <- deserializeAt off1 arr end
284 pure (off2, (a, b))
317 pure (off2, (a, b))
285−
286−--------------------------------------------------------------------------------
287−-- High level functions
288−--------------------------------------------------------------------------------
289−
290−{-# INLINE encodeAs #-}
291−encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
292−encodeAs ps a =
293− unsafeInlineIO $ do
294− let len = size 0 a
295− mbarr <- Unbox.newBytesAs ps len
296− off <- serialize 0 mbarr a
297− assertM(len == off)
298− pure $ Array mbarr 0 off
299−
300−{-# INLINE encode #-}
301−encode :: Serialize a => a -> Array Word8
302−encode = encodeAs Unpinned
303−
304−{-# INLINE pinnedEncode #-}
305−pinnedEncode :: Serialize a => a -> Array Word8
306−pinnedEncode = encodeAs Pinned
307−
308−{-# INLINE decode #-}
309−decode :: Serialize a => Array Word8 -> a
310−decode arr@(Array {..}) = unsafeInlineIO $ do
311− let lenArr = Array.length arr
312− (off, val) <- deserialize arrStart arrContents (arrStart + lenArr)
313− assertM(off == arrStart + lenArr)
314− pure val
core/src/Streamly/Internal/Data/Stream/Container.hs+56−48
@@ -11,16 +11,17 @@
11
11
12module Streamly.Internal.Data.Stream.Container
12module Streamly.Internal.Data.Stream.Container
13 (
13 (
14− nub
14+ -- * Deduplication
15+ ordNub
15
16
16− -- * Joins for unconstrained types
17+ -- * Joins
17− , joinLeftGeneric
18+ , leftJoin
18− , joinOuterGeneric
19+ , outerJoin
19
20
20− -- * Joins with Ord constraint
21+ -- * Ord Joins
21− , joinInner
22+ , innerOrdJoin
22− , joinLeft
23+ , leftOrdJoin
23− , joinOuter
24+ , outerOrdJoin
24 )
25 )
25where
26where
26
27
@@ -47,12 +48,15 @@ import qualified Streamly.Internal.Data.Stream.Transformer as Stream
47
48
48#include "DocTestDataStream.hs"
49#include "DocTestDataStream.hs"
49
50
51+-- | @nub@ specialized to 'Ord' types for better performance. Returns a
52+-- subsequence of the stream removing any duplicate elements.
53+--
50−-- | The memory used is proportional to the number of unique elements in the
54+-- The memory used is proportional to the number of unique elements in the
51−-- stream. If we want to limit the memory we can just use "take" to limit the
55+-- stream. One way to limit the memory is to use @take@ on the resulting
52−-- uniq elements in the stream.
56+-- stream to limit the unique elements in the stream.
53−{-# INLINE_NORMAL nub #-}
57+{-# INLINE_NORMAL ordNub #-}
54−nub :: (Monad m, Ord a) => Stream m a -> Stream m a
58+ordNub :: (Monad m, Ord a) => Stream m a -> Stream m a
55−nub (Stream step1 state1) = Stream step (Set.empty, state1)
59+ordNub (Stream step1 state1) = Stream step (Set.empty, state1)
56
60
57 where
61 where
58
62
@@ -78,8 +82,8 @@ toMap =
78--
82--
79-- XXX An IntMap may be faster when the keys are Int.
83-- XXX An IntMap may be faster when the keys are Int.
80-- XXX Use hashmap instead of map?
84-- XXX Use hashmap instead of map?
81−--
85+
82−-- | Like 'joinInner' but uses a 'Map' for efficiency.
86+-- | 'innerJoin' specialized to 'Ord' types for better performance.
83--
87--
84-- If the input streams have duplicate keys, the behavior is undefined.
88-- If the input streams have duplicate keys, the behavior is undefined.
85--
89--
@@ -90,10 +94,10 @@ toMap =
90-- Time: O(m + n)
94-- Time: O(m + n)
91--
95--
92-- /Pre-release/
96-- /Pre-release/
93−{-# INLINE joinInner #-}
97+{-# INLINE innerOrdJoin #-}
94−joinInner :: (Monad m, Ord k) =>
98+innerOrdJoin :: (Monad m, Ord k) =>
95 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
99 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
96−joinInner s1 s2 =
100+innerOrdJoin s1 s2 =
97 Stream.concatEffect $ do
101 Stream.concatEffect $ do
98 km <- toMap s2
102 km <- toMap s2
99 pure $ Stream.mapMaybe (joinAB km) s1
103 pure $ Stream.mapMaybe (joinAB km) s1
@@ -106,32 +110,33 @@ joinInner s1 s2 =
106 Nothing -> Nothing
110 Nothing -> Nothing
107
111
108-- XXX We can do this concurrently.
112-- XXX We can do this concurrently.
113+-- XXX Check performance of StreamD vs StreamK
109-- XXX If the second stream is sorted and passed as an Array or a seek capable
114-- XXX If the second stream is sorted and passed as an Array or a seek capable
110-- stream then we could use binary search if we have an Ord instance or
115-- stream then we could use binary search if we have an Ord instance or
111-- Ordering returning function. The time complexity would then become (m x log
116-- Ordering returning function. The time complexity would then become (m x log
112-- n).
117-- n).
113
118
114−-- XXX Check performance of StreamD vs StreamK
119+-- | Like 'innerJoin' but emits @(a, Just b)@ whenever a and b are equal, for
115−
116−-- | Like 'joinInner' but emit @(a, Just b)@, and additionally, for those @a@'s
117−-- that are not equal to any @b@ emit @(a, Nothing)@.
120+-- those @a@'s that are not equal to any @b@ emits @(a, Nothing)@.
118--
121--
119−-- The second stream is evaluated multiple times. If the stream is a
122+-- This is a generalization of 'innerJoin' to include all elements from the
120−-- consume-once stream then the caller should cache it in an 'Data.Array.Array'
123+-- left stream and not just those which have an equal in the right stream. This
121−-- before calling this function. Caching may also improve performance if the
124+-- is not a commutative operation, the order of the stream arguments matters.
122−-- stream is expensive to evaluate.
123--
125--
124−-- >>> joinRightGeneric eq = flip (Stream.joinLeftGeneric eq)
126+-- All the caveats mentioned in 'innerJoin' apply here as well. Right join is
127+-- not provided because it is just a flipped left join:
128+--
129+-- >>> rightJoin eq = flip (Stream.leftJoin eq)
125--
130--
126-- Space: O(n) assuming the second stream is cached in memory.
131-- Space: O(n) assuming the second stream is cached in memory.
127--
132--
128-- Time: O(m x n)
133-- Time: O(m x n)
129--
134--
130-- /Unimplemented/
135-- /Unimplemented/
131−{-# INLINE joinLeftGeneric #-}
136+{-# INLINE leftJoin #-}
132−joinLeftGeneric :: Monad m =>
137+leftJoin :: Monad m =>
133 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
138 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
134−joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
139+leftJoin eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
135 a <- mkCross (Stream.liftInner s1)
140 a <- mkCross (Stream.liftInner s1)
136 -- XXX should we use StreamD monad here?
141 -- XXX should we use StreamD monad here?
137 -- XXX Is there a better way to perform some action at the end of a loop
142 -- XXX Is there a better way to perform some action at the end of a loop
@@ -152,19 +157,17 @@ joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
152 else mkCross Stream.nil
157 else mkCross Stream.nil
153 Nothing -> return (a, Nothing)
158 Nothing -> return (a, Nothing)
154
159
155−-- XXX rename to joinLeftOrd?
160+-- | 'leftJoin' specialized to 'Ord' types for better performance.
156−
157−-- | A more efficient 'joinLeft' using a hashmap for efficiency.
158--
161--
159-- Space: O(n)
162-- Space: O(n)
160--
163--
161-- Time: O(m + n)
164-- Time: O(m + n)
162--
165--
163-- /Pre-release/
166-- /Pre-release/
164−{-# INLINE joinLeft #-}
167+{-# INLINE leftOrdJoin #-}
165−joinLeft :: (Ord k, Monad m) =>
168+leftOrdJoin :: (Ord k, Monad m) =>
166 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
169 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
167−joinLeft s1 s2 =
170+leftOrdJoin s1 s2 =
168 Stream.concatEffect $ do
171 Stream.concatEffect $ do
169 km <- toMap s2
172 km <- toMap s2
170 return $ fmap (joinAB km) s1
173 return $ fmap (joinAB km) s1
@@ -177,14 +180,19 @@ joinLeft s1 s2 =
177 Nothing -> (k, a, Nothing)
180 Nothing -> (k, a, Nothing)
178
181
179-- XXX We can do this concurrently.
182-- XXX We can do this concurrently.
183+-- XXX Check performance of StreamD vs StreamK cross operation.
180
184
181−-- XXX Check performance of StreamD vs StreamK
182−
183−-- | Like 'joinLeft' but emits a @(Just a, Just b)@. Like 'joinLeft', for those
185+-- | Like 'leftJoin' but emits a @(Just a, Just b)@. Like 'leftJoin', for those
184-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
186-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
185-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
187-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
186-- Just b)@.
188-- Just b)@.
187--
189--
190+-- This is a generalization of left join to include all the elements from the
191+-- right stream as well, in other words it is a combination of left and right
192+-- joins. This is a commutative operation. The order of stream arguments can be
193+-- changed without affecting results, except for the ordering of elements in
194+-- the resulting tuple.
195+--
188-- For space efficiency use the smaller stream as the second stream.
196-- For space efficiency use the smaller stream as the second stream.
189--
197--
190-- Space: O(n)
198-- Space: O(n)
@@ -192,15 +200,15 @@ joinLeft s1 s2 =
192-- Time: O(m x n)
200-- Time: O(m x n)
193--
201--
194-- /Pre-release/
202-- /Pre-release/
195−{-# INLINE joinOuterGeneric #-}
203+{-# INLINE outerJoin #-}
196−joinOuterGeneric :: MonadIO m =>
204+outerJoin :: MonadIO m =>
197 (a -> b -> Bool)
205 (a -> b -> Bool)
198 -> Stream m a
206 -> Stream m a
199 -> Stream m b
207 -> Stream m b
200 -> Stream m (Maybe a, Maybe b)
208 -> Stream m (Maybe a, Maybe b)
201−joinOuterGeneric eq s1 s =
209+outerJoin eq s1 s2 =
202 Stream.concatEffect $ do
210 Stream.concatEffect $ do
203− inputArr <- Array.fromStream s
211+ inputArr <- Array.fromStream s2
204 let len = Array.length inputArr
212 let len = Array.length inputArr
205 foundArr <-
213 foundArr <-
206 Stream.fold
214 Stream.fold
@@ -254,18 +262,18 @@ joinOuterGeneric eq s1 s =
254-- a flag. At the end go through @Stream m b@ and find those that are not in that
262-- a flag. At the end go through @Stream m b@ and find those that are not in that
255-- hash to return (Nothing, b).
263-- hash to return (Nothing, b).
256
264
257−-- | Like 'joinOuter' but uses a 'Map' for efficiency.
265+-- | 'outerJoin' specialized to 'Ord' types for better performance.
258--
266--
259-- Space: O(m + n)
267-- Space: O(m + n)
260--
268--
261-- Time: O(m + n)
269-- Time: O(m + n)
262--
270--
263-- /Pre-release/
271-- /Pre-release/
264−{-# INLINE joinOuter #-}
272+{-# INLINE outerOrdJoin #-}
265−joinOuter ::
273+outerOrdJoin ::
266 (Ord k, MonadIO m) =>
274 (Ord k, MonadIO m) =>
267 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
275 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
268−joinOuter s1 s2 =
276+outerOrdJoin s1 s2 =
269 Stream.concatEffect $ do
277 Stream.concatEffect $ do
270 km1 <- kvFold s1
278 km1 <- kvFold s1
271 km2 <- kvFold s2
279 km2 <- kvFold s2
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+33−25
@@ -13,36 +13,24 @@
13--
13--
14module Streamly.Internal.Data.Stream.Eliminate
14module Streamly.Internal.Data.Stream.Eliminate
15 (
15 (
16− -- * Running a 'Fold'
16+ -- * Running a Parser
17− fold
18−
19− -- -- * Running a 'Parser'
20− , parse
17+ parse
21 , parseD
18 , parseD
22 , parseBreak
19 , parseBreak
23 , parseBreakD
20 , parseBreakD
24
21
25− -- * Stream Deconstruction
22+ -- * Deconstruction
26 , uncons
23 , uncons
27
24
28 -- * Right Folds
25 -- * Right Folds
29− , foldrM
30− , foldr
31− , foldrMx
32 , foldr1
26 , foldr1
33
27
34− -- * Left Folds
35− , foldlM'
36− , foldl'
37− , foldlMx'
38− , foldlx'
39−
40 -- * Specific Fold Functions
28 -- * Specific Fold Functions
41− , drain
42 , mapM_ -- Map and Fold
29 , mapM_ -- Map and Fold
43 , null
30 , null
44 , head
31 , head
45 , headElse
32 , headElse
33+ , init
46 , tail
34 , tail
47 , last
35 , last
48 , elem
36 , elem
@@ -60,16 +48,9 @@ module Streamly.Internal.Data.Stream.Eliminate
60 , the
48 , the
61
49
62 -- * To containers
50 -- * To containers
63− , toList
64 , toListRev
51 , toListRev
65
52
66 -- * Multi-Stream Folds
53 -- * Multi-Stream Folds
67− -- ** Comparisons
68− -- | These should probably be expressed using zipping operations.
69− , eqBy
70− , cmpBy
71−
72− -- ** Substreams
73 -- | These should probably be expressed using parsers.
54 -- | These should probably be expressed using parsers.
74 , isPrefixOf
55 , isPrefixOf
75 , isInfixOf
56 , isInfixOf
@@ -90,7 +71,7 @@ import Foreign.Storable (Storable)
90import GHC.Exts (SpecConstrAnnotation(..))
71import GHC.Exts (SpecConstrAnnotation(..))
91import GHC.Types (SPEC(..))
72import GHC.Types (SPEC(..))
92import Streamly.Internal.Data.Parser (ParseError(..))
73import Streamly.Internal.Data.Parser (ParseError(..))
93−import Streamly.Internal.Data.SVar.Type (defState)
74+import Streamly.Internal.Data.SVar.Type (adaptState, defState)
94import Streamly.Internal.Data.Unbox (Unbox)
75import Streamly.Internal.Data.Unbox (Unbox)
95
76
96import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
77import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
@@ -105,7 +86,7 @@ import qualified Streamly.Internal.Data.Stream.Transform as StreamD
105
86
106import Prelude hiding
87import Prelude hiding
107 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
88 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
108− , notElem, splitAt, tail, (!!))
89+ , notElem, splitAt, init, tail, (!!))
109import Data.Foldable (length)
90import Data.Foldable (length)
110import Streamly.Internal.Data.Stream.Type
91import Streamly.Internal.Data.Stream.Type
111
92
@@ -391,9 +372,35 @@ head = foldrM (\x _ -> return (Just x)) (return Nothing)
391headElse :: Monad m => a -> Stream m a -> m a
372headElse :: Monad m => a -> Stream m a -> m a
392headElse a = foldrM (\x _ -> return x) (return a)
373headElse a = foldrM (\x _ -> return x) (return a)
393
374
375+{-# INLINE_NORMAL init #-}
376+init :: Monad m => Stream m a -> m (Maybe (Stream m a))
377+init stream = do
378+ r <- uncons stream
379+ case r of
380+ Nothing -> return Nothing
381+ Just (h, Stream step1 state1) ->
382+ return $ Just $ Stream step (h, state1)
383+
384+ where
385+
386+ step gst (a, s1) = do
387+ res <- step1 (adaptState gst) s1
388+ return $
389+ case res of
390+ Yield x s -> Yield a (x, s)
391+ Skip s -> Skip (a, s)
392+ Stop -> Stop
393+
394+-- | Same as:
395+--
396+-- >>> tail = fmap (fmap snd) . Stream.uncons
397+--
394-- Does not fuse, has the same performance as the StreamK version.
398-- Does not fuse, has the same performance as the StreamK version.
399+--
395{-# INLINE_NORMAL tail #-}
400{-# INLINE_NORMAL tail #-}
396tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
401tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
402+tail = fmap (fmap snd) . uncons
403+{-
397tail (UnStream step state) = go SPEC state
404tail (UnStream step state) = go SPEC state
398 where
405 where
399 go !_ st = do
406 go !_ st = do
@@ -402,6 +409,7 @@ tail (UnStream step state) = go SPEC state
402 Yield _ s -> return (Just $ Stream step s)
409 Yield _ s -> return (Just $ Stream step s)
403 Skip s -> go SPEC s
410 Skip s -> go SPEC s
404 Stop -> return Nothing
411 Stop -> return Nothing
412+-}
405
413
406-- XXX will it fuse? need custom impl?
414-- XXX will it fuse? need custom impl?
407{-# INLINE_NORMAL last #-}
415{-# INLINE_NORMAL last #-}
core/src/Streamly/Internal/Data/Stream/Exception.hs+9−6
@@ -9,17 +9,20 @@
9
9
10module Streamly.Internal.Data.Stream.Exception
10module Streamly.Internal.Data.Stream.Exception
11 (
11 (
12− gbracket_
12+ -- * Resources
13− , gbracket
14− , before
13+ before
15− , afterUnsafe
16 , afterIO
14 , afterIO
15+ , afterUnsafe
16+ , finallyIO
17+ , finallyUnsafe
18+ , gbracket_
19+ , gbracket
17 , bracketUnsafe
20 , bracketUnsafe
18 , bracketIO3
21 , bracketIO3
19 , bracketIO
22 , bracketIO
23+
24+ -- * Exceptions
20 , onException
25 , onException
21− , finallyUnsafe
22− , finallyIO
23 , ghandle
26 , ghandle
24 , handle
27 , handle
25 )
28 )
core/src/Streamly/Internal/Data/Stream/Generate.hs+2−12
@@ -16,20 +16,13 @@ module Streamly.Internal.Data.Stream.Generate
16 (
16 (
17 -- * Primitives
17 -- * Primitives
18 nil
18 nil
19− , nilM
20 , cons
19 , cons
21− , consM
22−
23− -- * From 'Unfold'
24− , unfold
25
20
26 -- * Unfolding
21 -- * Unfolding
27 , unfoldr
22 , unfoldr
28 , unfoldrM
23 , unfoldrM
29
24
30 -- * From Values
25 -- * From Values
31− , fromPure
32− , fromEffect
33 , repeat
26 , repeat
34 , repeatM
27 , repeatM
35 , replicate
28 , replicate
@@ -95,7 +88,6 @@ module Streamly.Internal.Data.Stream.Generate
95 -- * From Containers
88 -- * From Containers
96 -- | Transform an input structure into a stream.
89 -- | Transform an input structure into a stream.
97
90
98− , fromList
99 , fromListM
91 , fromListM
100 , fromFoldable
92 , fromFoldable
101 , fromFoldableM
93 , fromFoldableM
@@ -104,10 +96,6 @@ module Streamly.Internal.Data.Stream.Generate
104 , fromPtr
96 , fromPtr
105 , fromPtrN
97 , fromPtrN
106 , fromByteStr#
98 , fromByteStr#
107−
108− -- * Conversions
109− , fromStreamK
110− , toStreamK
111 )
99 )
112where
100where
113
101
@@ -154,6 +142,8 @@ import Streamly.Internal.Data.Stream.Type
154nil :: Applicative m => Stream m a
142nil :: Applicative m => Stream m a
155nil = Stream (\_ _ -> pure Stop) ()
143nil = Stream (\_ _ -> pure Stop) ()
156
144
145+infixr 5 `cons`
146+
157-- XXX implement in terms of consM?
147-- XXX implement in terms of consM?
158-- cons x = consM (return x)
148-- cons x = consM (return x)
159-- From an implementation perspective, StreamK.cons translates into a
149-- From an implementation perspective, StreamK.cons translates into a
core/src/Streamly/Internal/Data/Stream/MutChunked.hsdeleted−323
@@ -1,323 +0,0 @@
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+86−202
@@ -55,11 +55,6 @@ module Streamly.Internal.Data.Stream.Nesting
55 -- yields an element. A special case of unfoldRoundRobin.
55 -- yields an element. A special case of unfoldRoundRobin.
56 , roundRobin -- interleaveFair?/ParallelFair
56 , roundRobin -- interleaveFair?/ParallelFair
57
57
58− -- *** Zipping
59− -- | Zip corresponding elements of two streams.
60− , zipWith
61− , zipWithM
62−
63 -- *** Merging
58 -- *** Merging
64 -- | Interleave elements from two streams based on a condition.
59 -- | Interleave elements from two streams based on a condition.
65 , mergeBy
60 , mergeBy
@@ -76,17 +71,10 @@ module Streamly.Internal.Data.Stream.Nesting
76 -- unfoldMany: Unfold m a b -> t m a -> t m b
71 -- unfoldMany: Unfold m a b -> t m a -> t m b
77 -- @
72 -- @
78
73
79− -- *** ConcatMap
80− -- | Generate streams by mapping a stream generator on each element of an
81− -- input stream, append the resulting streams and flatten.
82− , concatMap
83− , concatMapM
84−
85 -- *** ConcatUnfold
74 -- *** ConcatUnfold
86 -- | Generate streams by using an unfold on each element of an input
75 -- | Generate streams by using an unfold on each element of an input
87 -- stream, append the resulting streams and flatten. A special case of
76 -- stream, append the resulting streams and flatten. A special case of
88 -- gintercalate.
77 -- gintercalate.
89− , unfoldMany
90 , ConcatUnfoldInterleaveState (..)
78 , ConcatUnfoldInterleaveState (..)
91 , unfoldInterleave
79 , unfoldInterleave
92 , unfoldRoundRobin
80 , unfoldRoundRobin
@@ -118,11 +106,8 @@ module Streamly.Internal.Data.Stream.Nesting
118
106
119 -- ** Folding
107 -- ** Folding
120 -- | Apply folds on a stream.
108 -- | Apply folds on a stream.
121− , foldMany
122− , refoldMany
123 , foldSequence
109 , foldSequence
124 , foldIterateM
110 , foldIterateM
125− , refoldIterateM
126
111
127 -- ** Parsing
112 -- ** Parsing
128 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
113 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
@@ -139,7 +124,6 @@ module Streamly.Internal.Data.Stream.Nesting
139
124
140 -- ** Grouping
125 -- ** Grouping
141 -- | Group segments of a stream and fold. Special case of parsing.
126 -- | Group segments of a stream and fold. Special case of parsing.
142− , groupsOf
143 , groupsBy
127 , groupsBy
144 , groupsWhile
128 , groupsWhile
145 , groupsRollingBy
129 , groupsRollingBy
@@ -147,9 +131,8 @@ module Streamly.Internal.Data.Stream.Nesting
147 -- ** Splitting
131 -- ** Splitting
148 -- | A special case of parsing.
132 -- | A special case of parsing.
149 , wordsBy
133 , wordsBy
150− , splitOnSeq
134+ , splitOnSeq -- XXX splitOnSeg
151− , splitOnSuffixSeq
135+ , splitOnSuffixSeq -- XXX splitOnSegSuffix, splitOnTrailer
152− , sliceOnSuffix
153
136
154 -- XXX Implement these as folds or parsers instead.
137 -- XXX Implement these as folds or parsers instead.
155 , splitOnSuffixSeqAny
138 , splitOnSuffixSeqAny
@@ -158,9 +141,8 @@ module Streamly.Internal.Data.Stream.Nesting
158
141
159 -- * Transform (Nested Containers)
142 -- * Transform (Nested Containers)
160 -- | Opposite to compact in ArrayStream
143 -- | Opposite to compact in ArrayStream
161− , splitInnerBy
144+ , splitInnerBy -- XXX innerSplitOn
162− , splitInnerBySuffix
145+ , splitInnerBySuffix -- XXX innerSplitOnSuffix
163− , intersectBySorted
164
146
165 -- * Reduce By Streams
147 -- * Reduce By Streams
166 , dropPrefix
148 , dropPrefix
@@ -182,12 +164,9 @@ import Fusion.Plugin.Types (Fuse(..))
182import GHC.Types (SPEC(..))
164import GHC.Types (SPEC(..))
183
165
184import Streamly.Internal.Data.Array.Type (Array(..))
166import Streamly.Internal.Data.Array.Type (Array(..))
185−import Streamly.Internal.Data.Fold.Step (Step(..))
186import Streamly.Internal.Data.Fold.Type (Fold(..))
167import Streamly.Internal.Data.Fold.Type (Fold(..))
187import Streamly.Internal.Data.Parser (ParseError(..))
168import Streamly.Internal.Data.Parser (ParseError(..))
188−import Streamly.Internal.Data.Refold.Type (Refold(..))
189import Streamly.Internal.Data.SVar.Type (adaptState)
169import Streamly.Internal.Data.SVar.Type (adaptState)
190−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
191import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
170import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
192import Streamly.Internal.Data.Unfold.Type (Unfold(..))
171import Streamly.Internal.Data.Unfold.Type (Unfold(..))
193
172
@@ -613,49 +592,6 @@ mergeFstBy :: -- Monad m =>
613mergeFstBy _f _m1 _m2 = undefined
592mergeFstBy _f _m1 _m2 = undefined
614 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
593 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
615
594
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−
659------------------------------------------------------------------------------
595------------------------------------------------------------------------------
660-- Combine N Streams - unfoldMany
596-- Combine N Streams - unfoldMany
661------------------------------------------------------------------------------
597------------------------------------------------------------------------------
@@ -1242,6 +1178,7 @@ foldSequence _f _m = undefined
1242data FIterState s f m a b
1178data FIterState s f m a b
1243 = FIterInit s f
1179 = FIterInit s f
1244 | forall fs. FIterStream s (fs -> a -> m (FL.Step fs b)) fs (fs -> m b)
1180 | forall fs. FIterStream s (fs -> a -> m (FL.Step fs b)) fs (fs -> m b)
1181+ (fs -> m b)
1245 | FIterYield b (FIterState s f m a b)
1182 | FIterYield b (FIterState s f m a b)
1246 | FIterStop
1183 | FIterStop
1247
1184
@@ -1269,101 +1206,30 @@ foldIterateM func seed0 (Stream step state) =
1269 where
1206 where
1270
1207
1271 {-# INLINE iterStep #-}
1208 {-# INLINE iterStep #-}
1272− iterStep from st fstep extract = do
1209+ iterStep from st fstep extract final = do
1273 res <- from
1210 res <- from
1274 return
1211 return
1275 $ Skip
1212 $ Skip
1276 $ case res of
1213 $ case res of
1277− FL.Partial fs -> FIterStream st fstep fs extract
1214+ FL.Partial fs -> FIterStream st fstep fs extract final
1278 FL.Done fb -> FIterYield fb $ FIterInit st (return fb)
1215 FL.Done fb -> FIterYield fb $ FIterInit st (return fb)
1279
1216
1280 {-# INLINE_LATE stepOuter #-}
1217 {-# INLINE_LATE stepOuter #-}
1281 stepOuter _ (FIterInit st seed) = do
1218 stepOuter _ (FIterInit st seed) = do
1282− (FL.Fold fstep initial extract) <- seed >>= func
1219+ (FL.Fold fstep initial extract final) <- seed >>= func
1283− iterStep initial st fstep extract
1220+ iterStep initial st fstep extract final
1284− stepOuter gst (FIterStream st fstep fs extract) = do
1221+ stepOuter gst (FIterStream st fstep fs extract final) = do
1285 r <- step (adaptState gst) st
1222 r <- step (adaptState gst) st
1286 case r of
1223 case r of
1287 Yield x s -> do
1224 Yield x s -> do
1288− iterStep (fstep fs x) s fstep extract
1225+ iterStep (fstep fs x) s fstep extract final
1289− Skip s -> return $ Skip $ FIterStream s fstep fs extract
1226+ Skip s -> return $ Skip $ FIterStream s fstep fs extract final
1290 Stop -> do
1227 Stop -> do
1291− b <- extract fs
1228+ b <- final fs
1292 return $ Skip $ FIterYield b FIterStop
1229 return $ Skip $ FIterYield b FIterStop
1293 stepOuter _ (FIterYield a next) = return $ Yield a next
1230 stepOuter _ (FIterYield a next) = return $ Yield a next
1294 stepOuter _ FIterStop = return Stop
1231 stepOuter _ FIterStop = return Stop
1295
1232
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−
1367------------------------------------------------------------------------------
1233------------------------------------------------------------------------------
1368-- Parsing
1234-- Parsing
1369------------------------------------------------------------------------------
1235------------------------------------------------------------------------------
@@ -1916,7 +1782,7 @@ groupsWhile :: Monad m
1916{-
1782{-
1917groupsWhile eq fld = parseMany (PRD.groupBy eq fld)
1783groupsWhile eq fld = parseMany (PRD.groupBy eq fld)
1918-}
1784-}
1919−groupsWhile cmp (Fold fstep initial done) (Stream step state) =
1785+groupsWhile cmp (Fold fstep initial _ final) (Stream step state) =
1920 Stream stepOuter (GroupingInit state)
1786 Stream stepOuter (GroupingInit state)
1921
1787
1922 where
1788 where
@@ -1939,7 +1805,7 @@ groupsWhile cmp (Fold fstep initial done) (Stream step state) =
1939 FL.Partial fs1 -> go SPEC x s fs1
1805 FL.Partial fs1 -> go SPEC x s fs1
1940 FL.Done b -> return $ Yield b (GroupingInit s)
1806 FL.Done b -> return $ Yield b (GroupingInit s)
1941 Skip s -> return $ Skip $ GroupingDo s fs
1807 Skip s -> return $ Skip $ GroupingDo s fs
1942− Stop -> return Stop
1808+ Stop -> final fs >> return Stop
1943
1809
1944 where
1810 where
1945
1811
@@ -1954,10 +1820,12 @@ groupsWhile cmp (Fold fstep initial done) (Stream step state) =
1954 FL.Partial fs1 -> go SPEC prev s fs1
1820 FL.Partial fs1 -> go SPEC prev s fs1
1955 FL.Done b -> return $ Yield b (GroupingInit s)
1821 FL.Done b -> return $ Yield b (GroupingInit s)
1956 else do
1822 else do
1957− r <- done acc
1823+ r <- final acc
1958 return $ Yield r (GroupingInitWith s x)
1824 return $ Yield r (GroupingInitWith s x)
1959 Skip s -> go SPEC prev s acc
1825 Skip s -> go SPEC prev s acc
1826+ Stop -> do
1827+ r <- final acc
1960− Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1828+ return $ Yield r GroupingDone
1961 stepOuter _ (GroupingInitWith st x) = do
1829 stepOuter _ (GroupingInitWith st x) = do
1962 res <- initial
1830 res <- initial
1963 return
1831 return
@@ -1984,10 +1852,12 @@ groupsWhile cmp (Fold fstep initial done) (Stream step state) =
1984 FL.Partial fs1 -> go SPEC s fs1
1852 FL.Partial fs1 -> go SPEC s fs1
1985 FL.Done b -> return $ Yield b (GroupingInit s)
1853 FL.Done b -> return $ Yield b (GroupingInit s)
1986 else do
1854 else do
1987− r <- done acc
1855+ r <- final acc
1988 return $ Yield r (GroupingInitWith s x)
1856 return $ Yield r (GroupingInitWith s x)
1989 Skip s -> go SPEC s acc
1857 Skip s -> go SPEC s acc
1858+ Stop -> do
1859+ r <- final acc
1990− Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1860+ return $ Yield r GroupingDone
1991 stepOuter _ (GroupingYield _ _) = error "groupsWhile: Unreachable"
1861 stepOuter _ (GroupingYield _ _) = error "groupsWhile: Unreachable"
1992 stepOuter _ GroupingDone = return Stop
1862 stepOuter _ GroupingDone = return Stop
1993
1863
@@ -2009,7 +1879,7 @@ groupsRollingBy :: Monad m
2009{-
1879{-
2010groupsRollingBy eq fld = parseMany (PRD.groupByRolling eq fld)
1880groupsRollingBy eq fld = parseMany (PRD.groupByRolling eq fld)
2011-}
1881-}
2012−groupsRollingBy cmp (Fold fstep initial done) (Stream step state) =
1882+groupsRollingBy cmp (Fold fstep initial _ final) (Stream step state) =
2013 Stream stepOuter (GroupingInit state)
1883 Stream stepOuter (GroupingInit state)
2014
1884
2015 where
1885 where
@@ -2032,7 +1902,7 @@ groupsRollingBy cmp (Fold fstep initial done) (Stream step state) =
2032 FL.Partial fs1 -> go SPEC x s fs1
1902 FL.Partial fs1 -> go SPEC x s fs1
2033 FL.Done fb -> return $ Yield fb (GroupingInit s)
1903 FL.Done fb -> return $ Yield fb (GroupingInit s)
2034 Skip s -> return $ Skip $ GroupingDo s fs
1904 Skip s -> return $ Skip $ GroupingDo s fs
2035− Stop -> return Stop
1905+ Stop -> final fs >> return Stop
2036
1906
2037 where
1907 where
2038
1908
@@ -2047,10 +1917,12 @@ groupsRollingBy cmp (Fold fstep initial done) (Stream step state) =
2047 FL.Partial fs1 -> go SPEC x s fs1
1917 FL.Partial fs1 -> go SPEC x s fs1
2048 FL.Done b -> return $ Yield b (GroupingInit s)
1918 FL.Done b -> return $ Yield b (GroupingInit s)
2049 else do
1919 else do
2050− r <- done acc
1920+ r <- final acc
2051 return $ Yield r (GroupingInitWith s x)
1921 return $ Yield r (GroupingInitWith s x)
2052 Skip s -> go SPEC prev s acc
1922 Skip s -> go SPEC prev s acc
1923+ Stop -> do
1924+ r <- final acc
2053− Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1925+ return $ Yield r GroupingDone
2054 stepOuter _ (GroupingInitWith st x) = do
1926 stepOuter _ (GroupingInitWith st x) = do
2055 res <- initial
1927 res <- initial
2056 return
1928 return
@@ -2081,7 +1953,7 @@ groupsRollingBy cmp (Fold fstep initial done) (Stream step state) =
2081 FL.Done b -> return $ Yield b (GroupingInit st)
1953 FL.Done b -> return $ Yield b (GroupingInit st)
2082 else do
1954 else do
2083 {-
1955 {-
2084− r <- done acc
1956+ r <- final acc
2085 return $ Yield r (GroupingInitWith s x)
1957 return $ Yield r (GroupingInitWith s x)
2086 -}
1958 -}
2087 -- The code above does not let groupBy fuse. We use the
1959 -- The code above does not let groupBy fuse. We use the
@@ -2090,14 +1962,16 @@ groupsRollingBy cmp (Fold fstep initial done) (Stream step state) =
2090 -- GroupingInitWith state here to help GHC with stream
1962 -- GroupingInitWith state here to help GHC with stream
2091 -- fusion.
1963 -- fusion.
2092 result <- initial
1964 result <- initial
2093− r <- done acc
1965+ r <- final acc
2094 return
1966 return
2095 $ Yield r
1967 $ Yield r
2096 $ case result of
1968 $ case result of
2097 FL.Partial fsi -> GroupingDoWith s fsi x
1969 FL.Partial fsi -> GroupingDoWith s fsi x
2098 FL.Done b -> GroupingYield b (GroupingInit s)
1970 FL.Done b -> GroupingYield b (GroupingInit s)
2099 Skip s -> go SPEC prev s acc
1971 Skip s -> go SPEC prev s acc
1972+ Stop -> do
1973+ r <- final acc
2100− Stop -> done acc >>= \r -> return $ Yield r GroupingDone
1974+ return $ Yield r GroupingDone
2101 stepOuter _ (GroupingYield r next) = return $ Yield r next
1975 stepOuter _ (GroupingYield r next) = return $ Yield r next
2102 stepOuter _ GroupingDone = return Stop
1976 stepOuter _ GroupingDone = return Stop
2103
1977
@@ -2119,7 +1993,7 @@ data WordsByState st fs b
2119
1993
2120{-# INLINE_NORMAL wordsBy #-}
1994{-# INLINE_NORMAL wordsBy #-}
2121wordsBy :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
1995wordsBy :: Monad m => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
2122−wordsBy predicate (Fold fstep initial done) (Stream step state) =
1996+wordsBy predicate (Fold fstep initial _ final) (Stream step state) =
2123 Stream stepOuter (WordsByInit state)
1997 Stream stepOuter (WordsByInit state)
2124
1998
2125 where
1999 where
@@ -2149,7 +2023,7 @@ wordsBy predicate (Fold fstep initial done) (Stream step state) =
2149 FL.Partial fs1 -> go SPEC s fs1
2023 FL.Partial fs1 -> go SPEC s fs1
2150 FL.Done b -> return $ Yield b (WordsByInit s)
2024 FL.Done b -> return $ Yield b (WordsByInit s)
2151 Skip s -> return $ Skip $ WordsByDo s fs
2025 Skip s -> return $ Skip $ WordsByDo s fs
2152− Stop -> return Stop
2026+ Stop -> final fs >> return Stop
2153
2027
2154 where
2028 where
2155
2029
@@ -2160,7 +2034,7 @@ wordsBy predicate (Fold fstep initial done) (Stream step state) =
2160 if predicate x
2034 if predicate x
2161 then do
2035 then do
2162 {-
2036 {-
2163− r <- done acc
2037+ r <- final acc
2164 return $ Yield r (WordsByInit s)
2038 return $ Yield r (WordsByInit s)
2165 -}
2039 -}
2166 -- The above code does not fuse well. Need to check why
2040 -- The above code does not fuse well. Need to check why
@@ -2169,7 +2043,7 @@ wordsBy predicate (Fold fstep initial done) (Stream step state) =
2169 -- state always, we directly go to WordsByDo state in
2043 -- state always, we directly go to WordsByDo state in
2170 -- the common case of Partial.
2044 -- the common case of Partial.
2171 resi <- initial
2045 resi <- initial
2172− r <- done acc
2046+ r <- final acc
2173 return
2047 return
2174 $ Yield r
2048 $ Yield r
2175 $ case resi of
2049 $ case resi of
@@ -2181,7 +2055,9 @@ wordsBy predicate (Fold fstep initial done) (Stream step state) =
2181 FL.Partial fs1 -> go SPEC s fs1
2055 FL.Partial fs1 -> go SPEC s fs1
2182 FL.Done b -> return $ Yield b (WordsByInit s)
2056 FL.Done b -> return $ Yield b (WordsByInit s)
2183 Skip s -> go SPEC s acc
2057 Skip s -> go SPEC s acc
2058+ Stop -> do
2059+ r <- final acc
2184− Stop -> done acc >>= \r -> return $ Yield r WordsByDone
2060+ return $ Yield r WordsByDone
2185
2061
2186 stepOuter _ WordsByDone = return Stop
2062 stepOuter _ WordsByDone = return Stop
2187
2063
@@ -2239,7 +2115,7 @@ splitOnSeq
2239 -> Fold m a b
2115 -> Fold m a b
2240 -> Stream m a
2116 -> Stream m a
2241 -> Stream m b
2117 -> Stream m b
2242−splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2118+splitOnSeq patArr (Fold fstep initial _ final) (Stream step state) =
2243 Stream stepOuter SplitOnSeqInit
2119 Stream stepOuter SplitOnSeqInit
2244
2120
2245 where
2121 where
@@ -2322,12 +2198,12 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2322 r <- fstep acc x
2198 r <- fstep acc x
2323 b1 <-
2199 b1 <-
2324 case r of
2200 case r of
2325− FL.Partial acc1 -> done acc1
2201+ FL.Partial acc1 -> final acc1
2326 FL.Done b -> return b
2202 FL.Done b -> return b
2327 let jump c = SplitOnSeqEmpty c s
2203 let jump c = SplitOnSeqEmpty c s
2328 in yieldProceed jump b1
2204 in yieldProceed jump b1
2329 Skip s -> skip (SplitOnSeqEmpty acc s)
2205 Skip s -> skip (SplitOnSeqEmpty acc s)
2330− Stop -> return Stop
2206+ Stop -> final acc >> return Stop
2331
2207
2332 -----------------
2208 -----------------
2333 -- Done
2209 -- Done
@@ -2345,7 +2221,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2345 Yield x s -> do
2221 Yield x s -> do
2346 let jump c = SplitOnSeqSingle c s pat
2222 let jump c = SplitOnSeqSingle c s pat
2347 if pat == x
2223 if pat == x
2348− then done fs >>= yieldProceed jump
2224+ then final fs >>= yieldProceed jump
2349 else do
2225 else do
2350 r <- fstep fs x
2226 r <- fstep fs x
2351 case r of
2227 case r of
@@ -2353,7 +2229,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2353 FL.Done b -> yieldProceed jump b
2229 FL.Done b -> yieldProceed jump b
2354 Skip s -> return $ Skip $ SplitOnSeqSingle fs s pat
2230 Skip s -> return $ Skip $ SplitOnSeqSingle fs s pat
2355 Stop -> do
2231 Stop -> do
2356− r <- done fs
2232+ r <- final fs
2357 return $ Skip $ SplitOnSeqYield r SplitOnSeqDone
2233 return $ Skip $ SplitOnSeqYield r SplitOnSeqDone
2358
2234
2359 ---------------------------
2235 ---------------------------
@@ -2361,7 +2237,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2361 ---------------------------
2237 ---------------------------
2362
2238
2363 stepOuter _ (SplitOnSeqWordDone 0 fs _) = do
2239 stepOuter _ (SplitOnSeqWordDone 0 fs _) = do
2364− r <- done fs
2240+ r <- final fs
2365 skip $ SplitOnSeqYield r SplitOnSeqDone
2241 skip $ SplitOnSeqYield r SplitOnSeqDone
2366 stepOuter _ (SplitOnSeqWordDone n fs wrd) = do
2242 stepOuter _ (SplitOnSeqWordDone n fs wrd) = do
2367 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
2243 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
@@ -2388,7 +2264,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2388 if wrd1 .&. wordMask == wordPat
2264 if wrd1 .&. wordMask == wordPat
2389 then do
2265 then do
2390 let jump c = SplitOnSeqWordInit c s
2266 let jump c = SplitOnSeqWordInit c s
2391− done fs >>= yieldProceed jump
2267+ final fs >>= yieldProceed jump
2392 else skip $ SplitOnSeqWordLoop wrd1 s fs
2268 else skip $ SplitOnSeqWordLoop wrd1 s fs
2393 else go SPEC (idx + 1) wrd1 s
2269 else go SPEC (idx + 1) wrd1 s
2394 Skip s -> go SPEC idx wrd s
2270 Skip s -> go SPEC idx wrd s
@@ -2396,7 +2272,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2396 if idx /= 0
2272 if idx /= 0
2397 then skip $ SplitOnSeqWordDone idx fs wrd
2273 then skip $ SplitOnSeqWordDone idx fs wrd
2398 else do
2274 else do
2399− r <- done fs
2275+ r <- final fs
2400 skip $ SplitOnSeqYield r SplitOnSeqDone
2276 skip $ SplitOnSeqYield r SplitOnSeqDone
2401
2277
2402 stepOuter gst (SplitOnSeqWordLoop wrd0 st0 fs0) =
2278 stepOuter gst (SplitOnSeqWordLoop wrd0 st0 fs0) =
@@ -2417,7 +2293,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2417 case r of
2293 case r of
2418 FL.Partial fs1 -> do
2294 FL.Partial fs1 -> do
2419 if wrd1 .&. wordMask == wordPat
2295 if wrd1 .&. wordMask == wordPat
2420− then done fs1 >>= yieldProceed jump
2296+ then final fs1 >>= yieldProceed jump
2421 else go SPEC wrd1 s fs1
2297 else go SPEC wrd1 s fs1
2422 FL.Done b -> yieldProceed jump b
2298 FL.Done b -> yieldProceed jump b
2423 Skip s -> go SPEC wrd s fs
2299 Skip s -> go SPEC wrd s fs
@@ -2502,14 +2378,14 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2502 stepOuter _ (SplitOnSeqKRCheck fs st rb rh) = do
2378 stepOuter _ (SplitOnSeqKRCheck fs st rb rh) = do
2503 if RB.unsafeEqArray rb rh patArr
2379 if RB.unsafeEqArray rb rh patArr
2504 then do
2380 then do
2505− r <- done fs
2381+ r <- final fs
2506 let rst = RB.startOf rb
2382 let rst = RB.startOf rb
2507 jump c = SplitOnSeqKRInit 0 c st rb rst
2383 jump c = SplitOnSeqKRInit 0 c st rb rst
2508 yieldProceed jump r
2384 yieldProceed jump r
2509 else skip $ SplitOnSeqKRLoop fs st rb rh patHash
2385 else skip $ SplitOnSeqKRLoop fs st rb rh patHash
2510
2386
2511 stepOuter _ (SplitOnSeqKRDone 0 fs _ _) = do
2387 stepOuter _ (SplitOnSeqKRDone 0 fs _ _) = do
2512− r <- done fs
2388+ r <- final fs
2513 skip $ SplitOnSeqYield r SplitOnSeqDone
2389 skip $ SplitOnSeqYield r SplitOnSeqDone
2514 stepOuter _ (SplitOnSeqKRDone n fs rb rh) = do
2390 stepOuter _ (SplitOnSeqKRDone n fs rb rh) = do
2515 old <- liftIO $ peek rh
2391 old <- liftIO $ peek rh
@@ -2553,7 +2429,7 @@ splitOnSuffixSeq
2553 -> Fold m a b
2429 -> Fold m a b
2554 -> Stream m a
2430 -> Stream m a
2555 -> Stream m b
2431 -> Stream m b
2556−splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2432+splitOnSuffixSeq withSep patArr (Fold fstep initial _ final) (Stream step state) =
2557 Stream stepOuter SplitOnSuffixSeqInit
2433 Stream stepOuter SplitOnSuffixSeqInit
2558
2434
2559 where
2435 where
@@ -2593,7 +2469,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2593 r <- if withSep then fstep fs x else return $ FL.Partial fs
2469 r <- if withSep then fstep fs x else return $ FL.Partial fs
2594 b1 <-
2470 b1 <-
2595 case r of
2471 case r of
2596− FL.Partial fs1 -> done fs1
2472+ FL.Partial fs1 -> final fs1
2597 FL.Done b -> return b
2473 FL.Done b -> return b
2598 yieldProceed jump b1
2474 yieldProceed jump b1
2599 else do
2475 else do
@@ -2656,11 +2532,11 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2656 r <- fstep acc x
2532 r <- fstep acc x
2657 b1 <-
2533 b1 <-
2658 case r of
2534 case r of
2659− FL.Partial fs -> done fs
2535+ FL.Partial fs -> final fs
2660 FL.Done b -> return b
2536 FL.Done b -> return b
2661 yieldProceed jump b1
2537 yieldProceed jump b1
2662 Skip s -> skip (SplitOnSuffixSeqEmpty acc s)
2538 Skip s -> skip (SplitOnSuffixSeqEmpty acc s)
2663− Stop -> return Stop
2539+ Stop -> final acc >> return Stop
2664
2540
2665 -----------------
2541 -----------------
2666 -- Done
2542 -- Done
@@ -2677,7 +2553,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2677 case res of
2553 case res of
2678 Yield x s -> processYieldSingle pat x s fs
2554 Yield x s -> processYieldSingle pat x s fs
2679 Skip s -> skip $ SplitOnSuffixSeqSingleInit fs s pat
2555 Skip s -> skip $ SplitOnSuffixSeqSingleInit fs s pat
2680− Stop -> return Stop
2556+ Stop -> final fs >> return Stop
2681
2557
2682 stepOuter gst (SplitOnSuffixSeqSingle fs st pat) = do
2558 stepOuter gst (SplitOnSuffixSeqSingle fs st pat) = do
2683 res <- step (adaptState gst) st
2559 res <- step (adaptState gst) st
@@ -2685,7 +2561,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2685 Yield x s -> processYieldSingle pat x s fs
2561 Yield x s -> processYieldSingle pat x s fs
2686 Skip s -> skip $ SplitOnSuffixSeqSingle fs s pat
2562 Skip s -> skip $ SplitOnSuffixSeqSingle fs s pat
2687 Stop -> do
2563 Stop -> do
2688− r <- done fs
2564+ r <- final fs
2689 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2565 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2690
2566
2691 ---------------------------
2567 ---------------------------
@@ -2693,7 +2569,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2693 ---------------------------
2569 ---------------------------
2694
2570
2695 stepOuter _ (SplitOnSuffixSeqWordDone 0 fs _) = do
2571 stepOuter _ (SplitOnSuffixSeqWordDone 0 fs _) = do
2696− r <- done fs
2572+ r <- final fs
2697 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2573 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2698 stepOuter _ (SplitOnSuffixSeqWordDone n fs wrd) = do
2574 stepOuter _ (SplitOnSuffixSeqWordDone n fs wrd) = do
2699 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
2575 let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
@@ -2716,7 +2592,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2716 let jump c = SplitOnSuffixSeqWordInit c s
2592 let jump c = SplitOnSuffixSeqWordInit c s
2717 yieldProceed jump b
2593 yieldProceed jump b
2718 Skip s -> skip (SplitOnSuffixSeqWordInit fs0 s)
2594 Skip s -> skip (SplitOnSuffixSeqWordInit fs0 s)
2719− Stop -> return Stop
2595+ Stop -> final fs0 >> return Stop
2720
2596
2721 where
2597 where
2722
2598
@@ -2734,7 +2610,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2734 then go SPEC (idx + 1) wrd1 s fs1
2610 then go SPEC (idx + 1) wrd1 s fs1
2735 else if wrd1 .&. wordMask /= wordPat
2611 else if wrd1 .&. wordMask /= wordPat
2736 then skip $ SplitOnSuffixSeqWordLoop wrd1 s fs1
2612 then skip $ SplitOnSuffixSeqWordLoop wrd1 s fs1
2737− else do done fs >>= yieldProceed jump
2613+ else do final fs >>= yieldProceed jump
2738 FL.Done b -> yieldProceed jump b
2614 FL.Done b -> yieldProceed jump b
2739 Skip s -> go SPEC idx wrd s fs
2615 Skip s -> go SPEC idx wrd s fs
2740 Stop -> skip $ SplitOnSuffixSeqWordDone idx fs wrd
2616 Stop -> skip $ SplitOnSuffixSeqWordDone idx fs wrd
@@ -2760,16 +2636,16 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2760 case r of
2636 case r of
2761 FL.Partial fs1 ->
2637 FL.Partial fs1 ->
2762 if wrd1 .&. wordMask == wordPat
2638 if wrd1 .&. wordMask == wordPat
2763− then done fs1 >>= yieldProceed jump
2639+ then final fs1 >>= yieldProceed jump
2764 else go SPEC wrd1 s fs1
2640 else go SPEC wrd1 s fs1
2765 FL.Done b -> yieldProceed jump b
2641 FL.Done b -> yieldProceed jump b
2766 Skip s -> go SPEC wrd s fs
2642 Skip s -> go SPEC wrd s fs
2767 Stop ->
2643 Stop ->
2768 if wrd .&. wordMask == wordPat
2644 if wrd .&. wordMask == wordPat
2769− then return Stop
2645+ then final fs >> return Stop
2770 else if withSep
2646 else if withSep
2771 then do
2647 then do
2772− r <- done fs
2648+ r <- final fs
2773 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2649 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2774 else skip $ SplitOnSuffixSeqWordDone patLen fs wrd
2650 else skip $ SplitOnSuffixSeqWordDone patLen fs wrd
2775
2651
@@ -2791,7 +2667,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2791 jump c = SplitOnSuffixSeqKRInit 0 c s rb rst
2667 jump c = SplitOnSuffixSeqKRInit 0 c s rb rst
2792 yieldProceed jump b
2668 yieldProceed jump b
2793 Skip s -> skip $ SplitOnSuffixSeqKRInit idx0 fs s rb rh0
2669 Skip s -> skip $ SplitOnSuffixSeqKRInit idx0 fs s rb rh0
2794− Stop -> return Stop
2670+ Stop -> final fs >> return Stop
2795
2671
2796 stepOuter gst (SplitOnSuffixSeqKRInit1 fs0 st0 rb rh0) = do
2672 stepOuter gst (SplitOnSuffixSeqKRInit1 fs0 st0 rb rh0) = do
2797 go SPEC 1 rh0 st0 fs0
2673 go SPEC 1 rh0 st0 fs0
@@ -2823,10 +2699,10 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2823 Stop -> do
2699 Stop -> do
2824 -- do not issue a blank segment when we end at pattern
2700 -- do not issue a blank segment when we end at pattern
2825 if (idx == maxIndex) && RB.unsafeEqArray rb rh patArr
2701 if (idx == maxIndex) && RB.unsafeEqArray rb rh patArr
2826− then return Stop
2702+ then final fs >> return Stop
2827 else if withSep
2703 else if withSep
2828 then do
2704 then do
2829− r <- done fs
2705+ r <- final fs
2830 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2706 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2831 else skip $ SplitOnSuffixSeqKRDone idx fs rb (RB.startOf rb)
2707 else skip $ SplitOnSuffixSeqKRDone idx fs rb (RB.startOf rb)
2832
2708
@@ -2855,24 +2731,24 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
2855 Skip s -> go SPEC fs s rh cksum
2731 Skip s -> go SPEC fs s rh cksum
2856 Stop ->
2732 Stop ->
2857 if RB.unsafeEqArray rb rh patArr
2733 if RB.unsafeEqArray rb rh patArr
2858− then return Stop
2734+ then final fs >> return Stop
2859 else if withSep
2735 else if withSep
2860 then do
2736 then do
2861− r <- done fs
2737+ r <- final fs
2862 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2738 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2863 else skip $ SplitOnSuffixSeqKRDone patLen fs rb rh
2739 else skip $ SplitOnSuffixSeqKRDone patLen fs rb rh
2864
2740
2865 stepOuter _ (SplitOnSuffixSeqKRCheck fs st rb rh) = do
2741 stepOuter _ (SplitOnSuffixSeqKRCheck fs st rb rh) = do
2866 if RB.unsafeEqArray rb rh patArr
2742 if RB.unsafeEqArray rb rh patArr
2867 then do
2743 then do
2868− r <- done fs
2744+ r <- final fs
2869 let rst = RB.startOf rb
2745 let rst = RB.startOf rb
2870 jump c = SplitOnSuffixSeqKRInit 0 c st rb rst
2746 jump c = SplitOnSuffixSeqKRInit 0 c st rb rst
2871 yieldProceed jump r
2747 yieldProceed jump r
2872 else skip $ SplitOnSuffixSeqKRLoop fs st rb rh patHash
2748 else skip $ SplitOnSuffixSeqKRLoop fs st rb rh patHash
2873
2749
2874 stepOuter _ (SplitOnSuffixSeqKRDone 0 fs _ _) = do
2750 stepOuter _ (SplitOnSuffixSeqKRDone 0 fs _ _) = do
2875− r <- done fs
2751+ r <- final fs
2876 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2752 skip $ SplitOnSuffixSeqYield r SplitOnSuffixSeqDone
2877 stepOuter _ (SplitOnSuffixSeqKRDone n fs rb rh) = do
2753 stepOuter _ (SplitOnSuffixSeqKRDone n fs rb rh) = do
2878 old <- liftIO $ peek rh
2754 old <- liftIO $ peek rh
@@ -3054,12 +2930,13 @@ splitInnerBy splitter joiner (Stream step1 state1) =
3054-- | Performs infix separator style splitting.
2930-- | Performs infix separator style splitting.
3055{-# INLINE_NORMAL splitInnerBySuffix #-}
2931{-# INLINE_NORMAL splitInnerBySuffix #-}
3056splitInnerBySuffix
2932splitInnerBySuffix
3057− :: (Monad m, Eq (f a), Monoid (f a))
2933+ :: Monad m
2934+ => (f a -> Bool) -- isEmpty?
3058− => (f a -> m (f a, Maybe (f a))) -- splitter
2935+ -> (f a -> m (f a, Maybe (f a))) -- splitter
3059 -> (f a -> f a -> m (f a)) -- joiner
2936 -> (f a -> f a -> m (f a)) -- joiner
3060 -> Stream m (f a)
2937 -> Stream m (f a)
3061 -> Stream m (f a)
2938 -> Stream m (f a)
3062−splitInnerBySuffix splitter joiner (Stream step1 state1) =
2939+splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
3063 Stream step (SplitInitial state1)
2940 Stream step (SplitInitial state1)
3064
2941
3065 where
2942 where
@@ -3086,10 +2963,11 @@ splitInnerBySuffix splitter joiner (Stream step1 state1) =
3086 Nothing -> Skip (SplitBuffering s buf')
2963 Nothing -> Skip (SplitBuffering s buf')
3087 Just x2 -> Skip (SplitYielding buf' (SplitSplitting s x2))
2964 Just x2 -> Skip (SplitYielding buf' (SplitSplitting s x2))
3088 Skip s -> return $ Skip (SplitBuffering s buf)
2965 Skip s -> return $ Skip (SplitBuffering s buf)
2966+ Stop ->
3089− Stop -> return $
2967+ return $
3090− if buf == mempty
2968+ if isEmpty buf
3091− then Stop
2969+ then Stop
3092− else Skip (SplitYielding buf SplitFinishing)
2970+ else Skip (SplitYielding buf SplitFinishing)
3093
2971
3094 step _ (SplitSplitting st buf) = do
2972 step _ (SplitSplitting st buf) = do
3095 (x1, mx2) <- splitter buf
2973 (x1, mx2) <- splitter buf
@@ -3108,6 +2986,8 @@ splitInnerBySuffix splitter joiner (Stream step1 state1) =
3108--
2986--
3109-- Space: @O(1)@
2987-- Space: @O(1)@
3110--
2988--
2989+-- See also stripPrefix.
2990+--
3111-- /Unimplemented/
2991-- /Unimplemented/
3112{-# INLINE dropPrefix #-}
2992{-# INLINE dropPrefix #-}
3113dropPrefix ::
2993dropPrefix ::
@@ -3120,6 +3000,8 @@ dropPrefix = error "Not implemented yet!"
3120--
3000--
3121-- Space: @O(n)@ where n is the length of the infix.
3001-- Space: @O(n)@ where n is the length of the infix.
3122--
3002--
3003+-- See also stripInfix.
3004+--
3123-- /Unimplemented/
3005-- /Unimplemented/
3124{-# INLINE dropInfix #-}
3006{-# INLINE dropInfix #-}
3125dropInfix ::
3007dropInfix ::
@@ -3132,6 +3014,8 @@ dropInfix = error "Not implemented yet!"
3132--
3014--
3133-- Space: @O(n)@ where n is the length of the suffix.
3015-- Space: @O(n)@ where n is the length of the suffix.
3134--
3016--
3017+-- See also stripSuffix.
3018+--
3135-- /Unimplemented/
3019-- /Unimplemented/
3136{-# INLINE dropSuffix #-}
3020{-# INLINE dropSuffix #-}
3137dropSuffix ::
3021dropSuffix ::
core/src/Streamly/Internal/Data/Stream/Top.hs+243−116
@@ -8,38 +8,73 @@
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10-- Top level module that can depend on all other lower level Stream modules.
10-- Top level module that can depend on all other lower level Stream modules.
11+--
12+-- Design notes:
13+--
14+-- The order of arguments in the join operations should ideally be opposite. It
15+-- should be such that the infinite stream is the last one. The transformation
16+-- should be on the last argument, so if you curry the functions with all other
17+-- arguments we get a @Stream -> Stream@ function. The first stream argument
18+-- may be considered as a config or modifier for the operation.
19+--
20+-- Benefit of changing the order is that we get a more intuitive Stream ->
21+-- Stream transformation after currying all other arguments. The inner loop
22+-- streams become arguments for the transformation, more like local modifiers
23+-- for the global outer stream as the last argument. Thus we can continue using
24+-- transformations on the outer stream in a composed pipeline. Otherwise we can
25+-- use flip to flip the order.
26+--
27+-- The fact that the inner stream can be used in the loop multiple times also
28+-- tells that this is not the real effectful stream, it is more like a pure
29+-- stream or an array. In fact we may consider using an Identity streams as
30+-- inner streams in which case these functions will not look nice.
31+--
32+-- Downsides:
33+--
34+-- * Maybe less intuitive to think about, because we usually think the first
35+-- stream as the outer loop and second as the inner.
36+-- * Zip and merge operations will continue using the opposite order.
37+-- * Need to change the order of cross, crossWith operations as well
38+-- * It will be inconsistent with Data.List. The functions cannot be used as
39+-- intuitive operators.
40+--
41+-- The choice is similar to concatMap vs bind. concatMap is pipeline
42+-- composition friendly but bind is user intuition friendly. Another option is
43+-- to have other functions with a different argument order e.g. flippedCross
44+-- instead of cross.
45+--
46+-- If we change the order we have to make sure that we have a consistent
47+-- convention for set-like and the cross join operations.
11
48
12module Streamly.Internal.Data.Stream.Top
49module Streamly.Internal.Data.Stream.Top
13 (
50 (
14− -- * Transformation
15− -- ** Sampling
51+ -- * Sampling
16 -- | Value agnostic filtering.
52 -- | Value agnostic filtering.
17 strideFromThen
53 strideFromThen
18
54
19− -- * Nesting
55+ -- * Straight Joins
20− -- ** Set like operations
21− -- | These are not exactly set operations because streams are not
56+ -- | These are set-like operations but not exactly set operations because
22− -- necessarily sets, they may have duplicated elements. These operations
57+ -- streams are not necessarily sets, they may have duplicated elements.
23− -- are generic i.e. they work on streams of unconstrained types, therefore,
58+ -- These operations are generic i.e. they work on streams of unconstrained
24− -- they have quadratic performance characterstics. For better performance
59+ -- types, therefore, they have quadratic performance characterstics. For
60+ -- better performance using Set or Map structures see the
25− -- using Set structures see the Streamly.Internal.Data.Stream.Container
61+ -- Streamly.Internal.Data.Stream.Container module.
26− -- module.
62+ , intersectBy
27− , filterInStreamGenericBy
63+ , deleteFirstsBy
28− , deleteInStreamGenericBy
64+ , unionBy
29− , unionWithStreamGenericBy
65+
30−
31− -- ** Set like operations on sorted streams
66+ -- Set like operations on sorted streams
32− , filterInStreamAscBy
67+ , sortedIntersectBy
33− , deleteInStreamAscBy
68+ , sortedDeleteFirstsBy
34− , unionWithStreamAscBy
69+ , sortedUnionBy
35−
70+
36− -- ** Join operations
71+ -- * Cross Joins
37− , joinInnerGeneric
72+ , innerJoin
38−
73+
39− -- * Joins on sorted stream
74+ -- Joins on sorted stream
40− , joinInnerAscBy
75+ , innerSortedJoin
41− , joinLeftAscBy
76+ , leftSortedJoin
42− , joinOuterAscBy
77+ , outerSortedJoin
43 )
78 )
44where
79where
45
80
@@ -48,8 +83,7 @@ where
48import Control.Monad.IO.Class (MonadIO(..))
83import Control.Monad.IO.Class (MonadIO(..))
49import Data.IORef (newIORef, readIORef, modifyIORef')
84import Data.IORef (newIORef, readIORef, modifyIORef')
50import Streamly.Internal.Data.Fold.Type (Fold)
85import Streamly.Internal.Data.Fold.Type (Fold)
51−import Streamly.Internal.Data.Stream.Common ()
86+import Streamly.Internal.Data.Stream.Type (Stream(..), Step(..), cross)
52−import Streamly.Internal.Data.Stream.Type (Stream, cross)
53
87
54import qualified Data.List as List
88import qualified Data.List as List
55import qualified Streamly.Internal.Data.Fold as Fold
89import qualified Streamly.Internal.Data.Fold as Fold
@@ -111,29 +145,40 @@ strideFromThen offset stride =
111-- binary search if we have an Ord instance or Ordering returning function. The
145-- binary search if we have an Ord instance or Ordering returning function. The
112-- time complexity would then become (m x log n).
146-- time complexity would then become (m x log n).
113
147
114−-- | Like 'cross' but emits only those tuples where @a == b@ using the
148+-- | Like 'cross' but emits only those tuples where @a == b@ using the supplied
115−-- supplied equality predicate.
149+-- equality predicate. This is essentially a @cross intersection@ of two
150+-- streams.
116--
151--
117-- Definition:
152-- Definition:
118--
153--
119−-- >>> joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ Stream.cross s1 s2
154+-- >>> innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ Stream.cross s1 s2
155+--
156+-- The second (inner) stream must be finite. Moreover, it must be either pure
157+-- or capable of multiple evaluations. If not then the caller should cache it
158+-- in an 'Data.Array.Array', if the type does not have an 'Unbox' instance then
159+-- use the Generic 'Data.Array.Generic.Array'. Convert the array to stream
160+-- before calling this function. Caching may also improve performance if the
161+-- stream is expensive to evaluate.
120--
162--
121−-- You should almost always prefer @joinInnerOrd@ over 'joinInnerGeneric' if
163+-- If you care about performance this function should be your last choice among
164+-- all inner joins. 'Streamly.Internal.Data.Unfold.innerJoin' is a much faster
165+-- fused alternative. 'innerSortedJoin' is a faster alternative when streams
122−-- possible. @joinInnerOrd@ is an order of magnitude faster but may take more
166+-- are sorted. 'innerOrdJoin' is an order of magnitude faster alternative when
123−-- space for caching the second stream.
167+-- the type has an 'Ord' instance.
124--
168--
125−-- See 'Streamly.Internal.Data.Unfold.joinInnerGeneric' for a much faster fused
169+-- Note: Conceptually, this is a commutative operation. Result includes all the
126−-- alternative.
170+-- elements from the left and the right stream. The order of streams can be
171+-- changed without affecting results, except for the ordering within the tuple.
127--
172--
128-- Time: O(m x n)
173-- Time: O(m x n)
129--
174--
130-- /Pre-release/
175-- /Pre-release/
131−{-# INLINE joinInnerGeneric #-}
176+{-# INLINE innerJoin #-}
132−joinInnerGeneric :: Monad m =>
177+innerJoin :: Monad m =>
133 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
178 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
134−joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
179+innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
135{-
180{-
136−joinInnerGeneric eq s1 s2 = do
181+innerJoin eq s1 s2 = do
137 -- ConcatMap works faster than bind
182 -- ConcatMap works faster than bind
138 Stream.concatMap (\a ->
183 Stream.concatMap (\a ->
139 Stream.concatMap (\b ->
184 Stream.concatMap (\b ->
@@ -144,44 +189,44 @@ joinInnerGeneric eq s1 s2 = do
144 ) s1
189 ) s1
145-}
190-}
146
191
147−-- | A more efficient 'joinInner' for sorted streams.
192+-- | A more efficient 'innerJoin' for sorted streams.
148--
193--
149-- Space: O(1)
194-- Space: O(1)
150--
195--
151-- Time: O(m + n)
196-- Time: O(m + n)
152--
197--
153-- /Unimplemented/
198-- /Unimplemented/
154−{-# INLINE joinInnerAscBy #-}
199+{-# INLINE innerSortedJoin #-}
155−joinInnerAscBy ::
200+innerSortedJoin ::
156 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
201 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
157−joinInnerAscBy = undefined
202+innerSortedJoin = undefined
158
203
159−-- | A more efficient 'joinLeft' for sorted streams.
204+-- | A more efficient 'leftJoin' for sorted streams.
160--
205--
161-- Space: O(1)
206-- Space: O(1)
162--
207--
163-- Time: O(m + n)
208-- Time: O(m + n)
164--
209--
165-- /Unimplemented/
210-- /Unimplemented/
166−{-# INLINE joinLeftAscBy #-}
211+{-# INLINE leftSortedJoin #-}
167−joinLeftAscBy :: -- Monad m =>
212+leftSortedJoin :: -- Monad m =>
168 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
213 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
169−joinLeftAscBy _eq _s1 _s2 = undefined
214+leftSortedJoin _eq _s1 _s2 = undefined
170
215
171−-- | A more efficient 'joinOuter' for sorted streams.
216+-- | A more efficient 'outerJoin' for sorted streams.
172--
217--
173-- Space: O(1)
218-- Space: O(1)
174--
219--
175-- Time: O(m + n)
220-- Time: O(m + n)
176--
221--
177-- /Unimplemented/
222-- /Unimplemented/
178−{-# INLINE joinOuterAscBy #-}
223+{-# INLINE outerSortedJoin #-}
179−joinOuterAscBy :: -- Monad m =>
224+outerSortedJoin :: -- Monad m =>
180 (a -> b -> Ordering)
225 (a -> b -> Ordering)
181 -> Stream m a
226 -> Stream m a
182 -> Stream m b
227 -> Stream m b
183 -> Stream m (Maybe a, Maybe b)
228 -> Stream m (Maybe a, Maybe b)
184−joinOuterAscBy _eq _s1 _s2 = undefined
229+outerSortedJoin _eq _s1 _s2 = undefined
185
230
186------------------------------------------------------------------------------
231------------------------------------------------------------------------------
187-- Set operations (special joins)
232-- Set operations (special joins)
@@ -191,8 +236,8 @@ joinOuterAscBy _eq _s1 _s2 = undefined
191-- the best would be to use an Array with linear search. If the second stream
236-- the best would be to use an Array with linear search. If the second stream
192-- is sorted we can also use a binary search, using Ord constraint.
237-- is sorted we can also use a binary search, using Ord constraint.
193
238
194−-- | Keep only those elements in the second stream that are present in the
239+-- | Keep only those elements in the first stream that are present in the
195−-- first stream too. The first stream is folded to a container using the
240+-- second stream too. The second stream is folded to a container using the
196-- supplied fold and then the elements in the container are looked up using the
241-- supplied fold and then the elements in the container are looked up using the
197-- supplied lookup function.
242-- supplied lookup function.
198--
243--
@@ -207,23 +252,30 @@ filterStreamWith :: Monad m =>
207filterStreamWith fld member s1 s2 =
252filterStreamWith fld member s1 s2 =
208 Stream.concatEffect
253 Stream.concatEffect
209 $ do
254 $ do
210− xs <- Stream.fold fld s1
255+ xs <- Stream.fold fld s2
211− return $ Stream.filter (`member` xs) s2
256+ return $ Stream.filter (`member` xs) s1
212
257
213−-- | 'filterInStreamGenericBy' retains only those elements in the second stream that
258+-- XXX instead of folding the second stream to a list we could use it directly.
214−-- are present in the first stream.
259+-- If the user wants they can generate the stream from an array and also call
215−--
260+-- uniq or nub on it. We can provide a convenience Stream -> Stream to cache
216−-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [2,1,1,3])
261+-- a finite stream in an array and serve it from the cache. The user can decide
217−-- [2,1,1]
262+-- what is best based on the context. They can also choose to use a boxed or
218−--
263+-- unboxed array for caching. To force caching we can make the second stream
219−-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [2,1,1,3]) (Stream.fromList [1,2,2,4])
264+-- monad type Identity. But that may be less flexible. One option is to use
220−-- [1,2,2]
265+-- cachedIntersectBy etc for automatic caching.
266+
267+-- | 'intersectBy' returns a subsequence of the first stream which intersects
268+-- with the second stream. Note that this is not a commutative operation unlike
269+-- a set intersection, because of duplicate elements in the stream the order of
270+-- the streams matters. This is similar to 'Data.List.intersectBy'. Note that
271+-- intersectBy is a special case of 'innerJoin'.
221--
272--
222−-- Similar to the list intersectBy operation but with the stream argument order
273+-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.intersectBy (==) (Stream.fromList s1) (Stream.fromList s2)
223−-- flipped.
274+-- >>> f [1,3,4,4,5]) [2,3,4,5,5]
275+-- [3,4,4,5]
224--
276--
225−-- The first stream must be finite and must not block. Second stream is
277+-- First stream can be infinite, the second stream must be finite and must be
226−-- processed only after the first stream is fully realized.
278+-- capable of multiple evaluations.
227--
279--
228-- Space: O(n) where @n@ is the number of elements in the second stream.
280-- Space: O(n) where @n@ is the number of elements in the second stream.
229--
281--
@@ -231,46 +283,87 @@ filterStreamWith fld member s1 s2 =
231-- @n@ is the number of elements in the second stream.
283-- @n@ is the number of elements in the second stream.
232--
284--
233-- /Pre-release/
285-- /Pre-release/
234−{-# INLINE filterInStreamGenericBy #-}
286+{-# INLINE intersectBy #-}
235−filterInStreamGenericBy :: Monad m =>
287+intersectBy :: Monad m =>
236 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
288 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
237−filterInStreamGenericBy eq =
289+intersectBy eq =
238 -- XXX Use an (unboxed) array instead.
290 -- XXX Use an (unboxed) array instead.
239 filterStreamWith
291 filterStreamWith
240 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
292 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
241 (List.any . eq)
293 (List.any . eq)
242
294
295+-------------------------------------------------------------------------------
296+-- Intersection of sorted streams
297+-------------------------------------------------------------------------------
298+
299+-- XXX The sort order is not important as long both the streams have the same
300+-- sort order. We need to move only in one direction in each stream.
301+-- XXX Fix the argument order to use the same behavior as intersectBy.
302+
243−-- | Like 'filterInStreamGenericBy' but assumes that the input streams are sorted in
303+-- | Like 'intersectBy' but assumes that the input streams are sorted in
244-- ascending order. To use it on streams sorted in descending order pass an
304-- ascending order. To use it on streams sorted in descending order pass an
245-- inverted comparison function returning GT for less than and LT for greater
305-- inverted comparison function returning GT for less than and LT for greater
246-- than.
306-- than.
247--
307--
308+-- Both streams can be infinite.
309+--
248-- Space: O(1)
310-- Space: O(1)
249--
311--
250-- Time: O(m+n)
312-- Time: O(m+n)
251--
313--
252-- /Pre-release/
314-- /Pre-release/
253−{-# INLINE filterInStreamAscBy #-}
315+{-# INLINE_NORMAL sortedIntersectBy #-}
254−filterInStreamAscBy :: Monad m =>
316+sortedIntersectBy :: Monad m =>
255 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
317 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
256−filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
318+sortedIntersectBy cmp (Stream stepa ta) (Stream stepb tb) =
319+ Stream step
320+ ( ta -- left stream state
321+ , tb -- right stream state
322+ , Nothing -- left value
323+ , Nothing -- right value
324+ )
257
325
258−-- | Delete all elements of the first stream from the seconds stream. If an
326+ where
259−-- element occurs multiple times in the first stream as many occurrences of it
327+
260−-- are deleted from the second stream.
328+ {-# INLINE_LATE step #-}
261−--
329+ -- step 1, fetch the first value
262−-- >>> Stream.fold Fold.toList $ Stream.deleteInStreamGenericBy (==) (Stream.fromList [1,2,3]) (Stream.fromList [1,2,2])
330+ step gst (sa, sb, Nothing, b) = do
263−-- [2]
331+ r <- stepa gst sa
332+ return $ case r of
333+ Yield a sa' -> Skip (sa', sb, Just a, b) -- step 2/3
334+ Skip sa' -> Skip (sa', sb, Nothing, b)
335+ Stop -> Stop
336+
337+ -- step 2, fetch the second value
338+ step gst (sa, sb, a@(Just _), Nothing) = do
339+ r <- stepb gst sb
340+ return $ case r of
341+ Yield b sb' -> Skip (sa, sb', a, Just b) -- step 3
342+ Skip sb' -> Skip (sa, sb', a, Nothing)
343+ Stop -> Stop
344+
345+ -- step 3, compare the two values
346+ step _ (sa, sb, Just a, Just b) = do
347+ let res = cmp a b
348+ return $ case res of
349+ GT -> Skip (sa, sb, Just a, Nothing) -- step 2
350+ LT -> Skip (sa, sb, Nothing, Just b) -- step 1
351+ EQ -> Yield a (sa, sb, Nothing, Just b) -- step 1
352+
353+-- | Returns a subsequence of the first stream, deleting first occurrences of
354+-- those elements that are present in the second stream. Note that this is not
355+-- a commutative operation. This is similar to the 'Data.List.deleteFirstsBy'.
264--
356--
265−-- The following laws hold:
357+-- >>> f xs ys = Stream.fold Fold.toList $ Stream.deleteFirstsBy (==) (Stream.fromList xs) (Stream.fromList ys)
358+-- >>> f [1,2,2,3,3,5] [1,2,2,3,4]
359+-- [2,3,5]
266--
360--
267−-- > deleteInStreamGenericBy (==) s1 (s1 `append` s2) === s2
361+-- The following holds:
268−-- > deleteInStreamGenericBy (==) s1 (s1 `interleave` s2) === s2
269--
362--
270−-- Same as the list 'Data.List.//' operation but with argument order flipped.
363+-- > deleteFirstsBy (==) (Stream.nub s2 `append` s1) s2 === s1
364+-- > deleteFirstsBy (==) (Stream.nub s2 `interleave` s1) s2 === s1
271--
365--
272−-- The first stream must be finite and must not block. Second stream is
366+-- First stream can be infinite, second stream must be finite.
273−-- processed only after the first stream is fully realized.
274--
367--
275-- Space: O(m) where @m@ is the number of elements in the first stream.
368-- Space: O(m) where @m@ is the number of elements in the first stream.
276--
369--
@@ -278,58 +371,83 @@ filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
278-- @n@ is the number of elements in the second stream.
371-- @n@ is the number of elements in the second stream.
279--
372--
280-- /Pre-release/
373-- /Pre-release/
281−{-# INLINE deleteInStreamGenericBy #-}
374+{-# INLINE deleteFirstsBy #-}
282−deleteInStreamGenericBy :: Monad m =>
375+deleteFirstsBy :: Monad m =>
283 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
376 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
284−deleteInStreamGenericBy eq s1 s2 =
377+deleteFirstsBy eq s2 s1 =
285− Stream.concatEffect
378+ -- XXX s2 can be a sorted mutable array and we can use binary
286− $ do
379+ -- search to find. Mark the element deleted, count the deletions
287− -- This may work well if s1 is small
380+ -- and reconsolidate the array when a min number of elements is
288− -- If s1 is big we can go through s1, deleting elements from s2 and
381+ -- deleted.
289− -- not emitting an element if it was successfully deleted from s2.
290− -- we will need a deleteBy that can return whether the element was
291− -- deleted or not.
292− xs <- Stream.fold Fold.toList s2
293− let f = Fold.foldl' (flip (List.deleteBy eq)) xs
294− fmap Stream.fromList $ Stream.fold f s1
295
382
383+ -- XXX Use StreamK or list as second argument instead of Stream to avoid
384+ -- concatEffect?
385+ Stream.concatEffect $ do
386+ xs <- Stream.toList s1
387+ -- It reverses the list but that is fine.
388+ let del x =
389+ List.foldl' (\(ys,res) y ->
390+ if x `eq` y
391+ then (ys, True)
392+ else (x:ys, res)) ([], False)
393+ g (ys,_) x =
394+ let (ys1, deleted) = del x ys
395+ in if deleted
396+ then (ys1, Nothing)
397+ else (ys1, Just x)
398+ in return
399+ $ Stream.catMaybes
400+ $ fmap snd
401+ $ Stream.postscanl' g (xs, Nothing) s2
402+
296−-- | A more efficient 'deleteInStreamGenericBy' for streams sorted in ascending order.
403+-- | A more efficient 'deleteFirstsBy' for streams sorted in ascending order.
404+--
405+-- Both streams can be infinite.
297--
406--
298-- Space: O(1)
407-- Space: O(1)
299--
408--
300-- /Unimplemented/
409-- /Unimplemented/
301−{-# INLINE deleteInStreamAscBy #-}
410+{-# INLINE sortedDeleteFirstsBy #-}
302−deleteInStreamAscBy :: -- (Monad m) =>
411+sortedDeleteFirstsBy :: -- (Monad m) =>
303 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
412 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
304−deleteInStreamAscBy _eq _s1 _s2 = undefined
413+sortedDeleteFirstsBy _eq _s1 _s2 = undefined
305
414
306-- XXX Remove the MonadIO constraint. We can just cache one stream and then
415-- XXX Remove the MonadIO constraint. We can just cache one stream and then
307-- implement using differenceEqBy.
416-- implement using differenceEqBy.
308
417
309−-- | This essentially appends to the second stream all the occurrences of
418+-- | Returns the first stream appended with those unique elements from the
310−-- elements in the first stream that are not already present in the second
419+-- second stream that are not already present in the first stream. Note that
311−-- stream.
420+-- this is not a commutative operation unlike a set union, argument order
421+-- matters. The behavior is similar to the 'Data.List.unionBy'.
312--
422--
313-- Equivalent to the following except that @s2@ is evaluated only once:
423-- Equivalent to the following except that @s2@ is evaluated only once:
314--
424--
315−-- >>> unionWithStreamGenericBy eq s1 s2 = s2 `Stream.append` (Stream.deleteInStreamGenericBy eq s2 s1)
425+-- >>> unionBy eq s1 s2 = s1 `Stream.append` Stream.deleteFirstsBy eq s1 (Stream.nub s2)
316--
426--
317-- Example:
427-- Example:
318--
428--
319−-- >>> Stream.fold Fold.toList $ Stream.unionWithStreamGenericBy (==) (Stream.fromList [1,1,2,3]) (Stream.fromList [1,2,2,4])
429+-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.unionBy (==) (Stream.fromList s1) (Stream.fromList s2)
430+-- >>> f [1,2,2,4] [1,1,2,3,3]
320-- [1,2,2,4,3]
431-- [1,2,2,4,3]
321--
432--
433+-- First stream can be infinite, but second stream must be finite. Note that if
434+-- the first stream is infinite the union means just the first stream. Thus
435+-- union is useful only when both streams are finite. See 'sortedUnionBy' where
436+-- union can work on infinite streams if they are sorted.
437+--
322-- Space: O(n)
438-- Space: O(n)
323--
439--
324-- Time: O(m x n)
440-- Time: O(m x n)
325--
441--
326-- /Pre-release/
442-- /Pre-release/
327−{-# INLINE unionWithStreamGenericBy #-}
443+{-# INLINE unionBy #-}
328−unionWithStreamGenericBy :: MonadIO m =>
444+unionBy :: MonadIO m =>
329 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
445 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
330−unionWithStreamGenericBy eq s1 s2 =
446+unionBy eq s2 s1 =
331 Stream.concatEffect
447 Stream.concatEffect
332 $ do
448 $ do
449+ -- XXX use a rewrite rule such that if a list converted to stream
450+ -- is passed to unionBy then this becomes an identity operation.
333 xs <- Stream.fold Fold.toList s1
451 xs <- Stream.fold Fold.toList s1
334 -- XXX we can use postscanlMAfter' instead of IORef
452 -- XXX we can use postscanlMAfter' instead of IORef
335 ref <- liftIO $ newIORef $! List.nubBy eq xs
453 ref <- liftIO $ newIORef $! List.nubBy eq xs
@@ -342,12 +460,21 @@ unionWithStreamGenericBy eq s1 s2 =
342 return $ Stream.fromList xs1
460 return $ Stream.fromList xs1
343 return $ Stream.mapM f s2 `Stream.append` s3
461 return $ Stream.mapM f s2 `Stream.append` s3
344
462
345−-- | A more efficient 'unionWithStreamGenericBy' for sorted streams.
463+-- | A more efficient 'unionBy' for sorted streams.
464+--
465+-- Note that the behavior is different from 'unionBy'. In 'unionBy' we append
466+-- the unique elements from second stream only after exhausting the first one
467+-- whereas in sorted streams we can determine unique elements early even when
468+-- we are going through the first stream. Thus the result is an interleaving of
469+-- the two streams, merging those elements from the second stream that are not
470+-- present in the first.
346--
471--
347-- Space: O(1)
472-- Space: O(1)
348--
473--
474+-- Both streams can be infinite.
475+--
349-- /Unimplemented/
476-- /Unimplemented/
350−{-# INLINE unionWithStreamAscBy #-}
477+{-# INLINE sortedUnionBy #-}
351−unionWithStreamAscBy :: -- (Monad m) =>
478+sortedUnionBy :: -- (Monad m) =>
352 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
479 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
353−unionWithStreamAscBy _eq _s1 _s2 = undefined
480+sortedUnionBy _eq _s1 _s2 = undefined
core/src/Streamly/Internal/Data/Stream/Transform.hs+61−35
@@ -21,8 +21,6 @@ module Streamly.Internal.Data.Stream.Transform
21
21
22 -- * Mapping
22 -- * Mapping
23 -- | Stateless one-to-one maps.
23 -- | Stateless one-to-one maps.
24− , map
25− , mapM
26 , sequence
24 , sequence
27
25
28 -- * Mapping Effects
26 -- * Mapping Effects
@@ -75,7 +73,7 @@ module Streamly.Internal.Data.Stream.Transform
75 , scanMaybe
73 , scanMaybe
76 , filter
74 , filter
77 , filterM
75 , filterM
78− , deleteBy
76+ , deleteBy -- deleteOnceBy?
79 , uniqBy
77 , uniqBy
80 , uniq
78 , uniq
81 , prune
79 , prune
@@ -83,9 +81,8 @@ module Streamly.Internal.Data.Stream.Transform
83
81
84 -- * Trimming
82 -- * Trimming
85 -- | Produce a subset of the stream trimmed at ends.
83 -- | Produce a subset of the stream trimmed at ends.
86− , take
84+ , initNonEmpty
87− , takeWhile
85+ , tailNonEmpty
88− , takeWhileM
89 , takeWhileLast
86 , takeWhileLast
90 , takeWhileAround
87 , takeWhileAround
91 , drop
88 , drop
@@ -132,7 +129,6 @@ module Streamly.Internal.Data.Stream.Transform
132 -- * Searching
129 -- * Searching
133 , findIndices
130 , findIndices
134 , elemIndices
131 , elemIndices
135− , slicesBy
136
132
137 -- * Rolling map
133 -- * Rolling map
138 -- | Map using the previous element.
134 -- | Map using the previous element.
@@ -300,7 +296,7 @@ data TapState fs st a
300--
296--
301{-# INLINE tap #-}
297{-# INLINE tap #-}
302tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
298tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
303−tap (Fold fstep initial extract) (Stream step state) = Stream step' TapInit
299+tap (Fold fstep initial _ final) (Stream step state) = Stream step' TapInit
304
300
305 where
301 where
306
302
@@ -323,7 +319,7 @@ tap (Fold fstep initial extract) (Stream step state) = Stream step' TapInit
323 FL.Done _ -> TapDone s
319 FL.Done _ -> TapDone s
324 Skip s -> return $ Skip (Tapping acc s)
320 Skip s -> return $ Skip (Tapping acc s)
325 Stop -> do
321 Stop -> do
326− void $ extract acc
322+ void $ final acc
327 return Stop
323 return Stop
328 step' gst (TapDone st) = do
324 step' gst (TapDone st) = do
329 r <- step gst st
325 r <- step gst st
@@ -342,7 +338,7 @@ data TapOffState fs s a
342{-# INLINE_NORMAL tapOffsetEvery #-}
338{-# INLINE_NORMAL tapOffsetEvery #-}
343tapOffsetEvery :: Monad m
339tapOffsetEvery :: Monad m
344 => Int -> Int -> Fold m a b -> Stream m a -> Stream m a
340 => Int -> Int -> Fold m a b -> Stream m a -> Stream m a
345−tapOffsetEvery offset n (Fold fstep initial extract) (Stream step state) =
341+tapOffsetEvery offset n (Fold fstep initial _ final) (Stream step state) =
346 Stream step' TapOffInit
342 Stream step' TapOffInit
347
343
348 where
344 where
@@ -372,7 +368,7 @@ tapOffsetEvery offset n (Fold fstep initial extract) (Stream step state) =
372 return $ Yield x next
368 return $ Yield x next
373 Skip s -> return $ Skip (TapOffTapping acc s count)
369 Skip s -> return $ Skip (TapOffTapping acc s count)
374 Stop -> do
370 Stop -> do
375− void $ extract acc
371+ void $ final acc
376 return Stop
372 return Stop
377 step' gst (TapOffDone st) = do
373 step' gst (TapOffDone st) = do
378 r <- step gst st
374 r <- step gst st
@@ -437,7 +433,7 @@ data ScanState s f = ScanInit s | ScanDo s !f | ScanDone
437--
433--
438{-# INLINE_NORMAL postscan #-}
434{-# INLINE_NORMAL postscan #-}
439postscan :: Monad m => FL.Fold m a b -> Stream m a -> Stream m b
435postscan :: Monad m => FL.Fold m a b -> Stream m a -> Stream m b
440−postscan (FL.Fold fstep initial extract) (Stream sstep state) =
436+postscan (FL.Fold fstep initial extract final) (Stream sstep state) =
441 Stream step (ScanInit state)
437 Stream step (ScanInit state)
442
438
443 where
439 where
@@ -460,13 +456,13 @@ postscan (FL.Fold fstep initial extract) (Stream sstep state) =
460 return $ Yield b $ ScanDo s fs1
456 return $ Yield b $ ScanDo s fs1
461 FL.Done b -> return $ Yield b ScanDone
457 FL.Done b -> return $ Yield b ScanDone
462 Skip s -> return $ Skip $ ScanDo s fs
458 Skip s -> return $ Skip $ ScanDo s fs
463− Stop -> return Stop
459+ Stop -> final fs >> return Stop
464 step _ ScanDone = return Stop
460 step _ ScanDone = return Stop
465
461
466{-# INLINE scanWith #-}
462{-# INLINE scanWith #-}
467scanWith :: Monad m
463scanWith :: Monad m
468 => Bool -> Fold m a b -> Stream m a -> Stream m b
464 => Bool -> Fold m a b -> Stream m a -> Stream m b
469−scanWith restart (Fold fstep initial extract) (Stream sstep state) =
465+scanWith restart (Fold fstep initial extract final) (Stream sstep state) =
470 Stream step (ScanInit state)
466 Stream step (ScanInit state)
471
467
472 where
468 where
@@ -489,7 +485,7 @@ scanWith restart (Fold fstep initial extract) (Stream sstep state) =
489 case res of
485 case res of
490 Yield x s -> runStep s (fstep fs x)
486 Yield x s -> runStep s (fstep fs x)
491 Skip s -> return $ Skip $ ScanDo s fs
487 Skip s -> return $ Skip $ ScanDo s fs
492− Stop -> return Stop
488+ Stop -> final fs >> return Stop
493 step _ ScanDone = return Stop
489 step _ ScanDone = return Stop
494
490
495-- XXX It may be useful to have a version of scan where we can keep the
491-- XXX It may be useful to have a version of scan where we can keep the
@@ -1074,6 +1070,55 @@ repeated = undefined
1074-- Trimming
1070-- Trimming
1075------------------------------------------------------------------------------
1071------------------------------------------------------------------------------
1076
1072
1073+-- | init for non-empty streams, fails for empty stream case.
1074+--
1075+{-# INLINE initNonEmpty #-}
1076+initNonEmpty :: Monad m => Stream m a -> Stream m a
1077+initNonEmpty (Stream step1 state1) = Stream step (Nothing, state1)
1078+
1079+ where
1080+
1081+ step gst (Nothing, s1) = do
1082+ r <- step1 (adaptState gst) s1
1083+ return $
1084+ case r of
1085+ Yield x s -> Skip (Just x, s)
1086+ Skip s -> Skip (Nothing, s)
1087+ Stop -> error "initNonEmpty: empty Stream"
1088+
1089+ step gst (Just a, s1) = do
1090+ r <- step1 (adaptState gst) s1
1091+ return $
1092+ case r of
1093+ Yield x s -> Yield a (Just x, s)
1094+ Skip s -> Skip (Just a, s)
1095+ Stop -> Stop
1096+
1097+-- | tail for non-empty streams, fails for empty stream case.
1098+--
1099+-- See also 'tail' for a non-partial version of this function..
1100+{-# INLINE tailNonEmpty #-}
1101+tailNonEmpty :: Monad m => Stream m a -> Stream m a
1102+tailNonEmpty (Stream step1 state1) = Stream step (Nothing, state1)
1103+
1104+ where
1105+
1106+ step gst (Nothing, s1) = do
1107+ r <- step1 (adaptState gst) s1
1108+ return $
1109+ case r of
1110+ Yield x s -> Skip (Just x, s)
1111+ Skip s -> Skip (Nothing, s)
1112+ Stop -> error "tailNonEmpty: empty Stream"
1113+
1114+ step gst (Just a, s1) = do
1115+ r <- step1 (adaptState gst) s1
1116+ return $
1117+ case r of
1118+ Yield x s -> Yield x (Just x, s)
1119+ Skip s -> Skip (Just a, s)
1120+ Stop -> Stop
1121+
1077-- | Take all consecutive elements at the end of the stream for which the
1122-- | Take all consecutive elements at the end of the stream for which the
1078-- predicate is true.
1123-- predicate is true.
1079--
1124--
@@ -1537,7 +1582,7 @@ reverse m = Stream step Nothing
1537{-# INLINE reverseUnbox #-}
1582{-# INLINE reverseUnbox #-}
1538reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1583reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
1539reverseUnbox =
1584reverseUnbox =
1540− A.flattenArraysRev -- unfoldMany A.readRev
1585+ A.concatRev -- unfoldMany A.readerRev
1541 . fromStreamK
1586 . fromStreamK
1542 . K.reverse
1587 . K.reverse
1543 . toStreamK
1588 . toStreamK
@@ -1709,25 +1754,6 @@ findIndices p (Stream step state) = Stream step' (state, 0)
1709elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1754elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1710elemIndices a = findIndices (== a)
1755elemIndices a = findIndices (== a)
1711
1756
1712−{-# INLINE_NORMAL slicesBy #-}
1713−slicesBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
1714−slicesBy p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
1715−
1716− where
1717−
1718− {-# INLINE_LATE step #-}
1719− step gst (Just (st, i, len)) = i `seq` len `seq` do
1720− r <- step1 (adaptState gst) st
1721− return
1722− $ case r of
1723− Yield x s ->
1724− if p x
1725− then Yield (i, len + 1) (Just (s, i + len + 1, 0))
1726− else Skip (Just (s, i, len + 1))
1727− Skip s -> Skip (Just (s, i, len))
1728− Stop -> if len == 0 then Stop else Yield (i, len) Nothing
1729− step _ Nothing = return Stop
1730−
1731------------------------------------------------------------------------------
1757------------------------------------------------------------------------------
1732-- Rolling map
1758-- Rolling map
1733------------------------------------------------------------------------------
1759------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/Transformer.hs+2−1
@@ -11,10 +11,11 @@
11
11
12module Streamly.Internal.Data.Stream.Transformer
12module Streamly.Internal.Data.Stream.Transformer
13 (
13 (
14+ -- * Fold to Transformer Monad
14 foldlT
15 foldlT
15 , foldrT
16 , foldrT
16
17
17− -- * Transform Inner Monad
18+ -- * Inner Monad Operations
18 , liftInner
19 , liftInner
19 , runReaderT
20 , runReaderT
20 , usingReaderT
21 , usingReaderT
core/src/Streamly/Internal/Data/Stream/Type.hs+145−14
@@ -1,5 +1,11 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE PatternSynonyms #-}
3+{-# LANGUAGE TypeFamilies #-}
4+-- Must come after TypeFamilies, otherwise it is re-enabled.
5+-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
6+{-# LANGUAGE NoMonoLocalBinds #-}
2{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
8+{-# LANGUAGE ViewPatterns #-}
3
9
4-- |
10-- |
5-- Module : Streamly.Internal.Data.Stream.Type
11-- Module : Streamly.Internal.Data.Stream.Type
@@ -16,18 +22,18 @@
16
22
17module Streamly.Internal.Data.Stream.Type
23module Streamly.Internal.Data.Stream.Type
18 (
24 (
19− -- * The stream type
25+ -- * Type
20 Step (..)
26 Step (..)
21 -- XXX UnStream is exported to avoid a performance issue in some
27 -- XXX UnStream is exported to avoid a performance issue in some
22 -- combinators if we use the pattern synonym "Stream".
28 -- combinators if we use the pattern synonym "Stream".
23 , Stream (Stream, UnStream)
29 , Stream (Stream, UnStream)
24
30
25− -- * CrossStream type wrapper
31+ -- * CrossStream
26 , CrossStream
32 , CrossStream
27 , unCross
33 , unCross
28 , mkCross
34 , mkCross
29
35
30− -- * Conversion to StreamK
36+ -- * To StreamK
31 , fromStreamK
37 , fromStreamK
32 , toStreamK
38 , toStreamK
33
39
@@ -85,6 +91,7 @@ module Streamly.Internal.Data.Stream.Type
85
91
86 -- * Combining Two Streams
92 -- * Combining Two Streams
87 -- ** Zipping
93 -- ** Zipping
94+ -- | Zip corresponding elements of two streams.
88 , zipWithM
95 , zipWithM
89 , zipWith
96 , zipWith
90
97
@@ -100,6 +107,8 @@ module Streamly.Internal.Data.Stream.Type
100 , unfoldMany
107 , unfoldMany
101
108
102 -- * Concat
109 -- * Concat
110+ -- | Generate streams by mapping a stream generator on each element of an
111+ -- input stream, append the resulting streams and flatten.
103 , concatEffect
112 , concatEffect
104 , concatMap
113 , concatMap
105 , concatMapM
114 , concatMapM
@@ -123,14 +132,22 @@ module Streamly.Internal.Data.Stream.Type
123 , foldManyPost
132 , foldManyPost
124 , groupsOf
133 , groupsOf
125 , refoldMany
134 , refoldMany
135+ , refoldIterateM
126
136
127 -- * Fold Iterate
137 -- * Fold Iterate
128 , reduceIterateBfs
138 , reduceIterateBfs
129 , foldIterateBfs
139 , foldIterateBfs
130
140
141+ -- * Splitting
142+ , indexOnSuffix
143+
131 -- * Multi-stream folds
144 -- * Multi-stream folds
145+ -- | These should probably be expressed using zipping operations.
132 , eqBy
146 , eqBy
133 , cmpBy
147 , cmpBy
148+
149+ -- * Deprecated
150+ , sliceOnSuffix
134 )
151 )
135where
152where
136
153
@@ -162,6 +179,7 @@ import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
162import Streamly.Internal.Data.Refold.Type (Refold(..))
179import Streamly.Internal.Data.Refold.Type (Refold(..))
163import Streamly.Internal.Data.Stream.Step (Step (..))
180import Streamly.Internal.Data.Stream.Step (Step (..))
164import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
181import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
182+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
165import Streamly.Internal.Data.Unfold.Type (Unfold(..))
183import Streamly.Internal.Data.Unfold.Type (Unfold(..))
166
184
167import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
185import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
@@ -212,6 +230,9 @@ pattern Stream step state <- (unShare -> UnStream step state)
212nilM :: Applicative m => m b -> Stream m a
230nilM :: Applicative m => m b -> Stream m a
213nilM m = Stream (\_ _ -> m $> Stop) ()
231nilM m = Stream (\_ _ -> m $> Stop) ()
214
232
233+
234+infixr 5 `consM`
235+
215-- | Like 'cons' but fuses an effect instead of a pure value.
236-- | Like 'cons' but fuses an effect instead of a pure value.
216{-# INLINE_NORMAL consM #-}
237{-# INLINE_NORMAL consM #-}
217consM :: Applicative m => m a -> Stream m a -> Stream m a
238consM :: Applicative m => m a -> Stream m a -> Stream m a
@@ -398,7 +419,7 @@ toStreamK (Stream step state) = go state
398{-# INLINE_NORMAL foldEither #-}
419{-# INLINE_NORMAL foldEither #-}
399foldEither :: Monad m =>
420foldEither :: Monad m =>
400 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
421 Fold m a b -> Stream m a -> m (Either (Fold m a b) (b, Stream m a))
401−foldEither (Fold fstep begin done) (UnStream step state) = do
422+foldEither (Fold fstep begin done final) (UnStream step state) = do
402 res <- begin
423 res <- begin
403 case res of
424 case res of
404 FL.Partial fs -> go SPEC fs state
425 FL.Partial fs -> go SPEC fs state
@@ -416,7 +437,9 @@ foldEither (Fold fstep begin done) (UnStream step state) = do
416 FL.Done b -> return $! Right (b, Stream step s)
437 FL.Done b -> return $! Right (b, Stream step s)
417 FL.Partial fs1 -> go SPEC fs1 s
438 FL.Partial fs1 -> go SPEC fs1 s
418 Skip s -> go SPEC fs s
439 Skip s -> go SPEC fs s
440+ Stop ->
419− Stop -> return $! Left (Fold fstep (return $ FL.Partial fs) done)
441+ let f = Fold fstep (return $ FL.Partial fs) done final
442+ in return $! Left f
420
443
421-- | Like 'fold' but also returns the remaining stream. The resulting stream
444-- | Like 'fold' but also returns the remaining stream. The resulting stream
422-- would be 'Stream.nil' if the stream finished before the fold.
445-- would be 'Stream.nil' if the stream finished before the fold.
@@ -427,12 +450,12 @@ foldBreak fld strm = do
427 r <- foldEither fld strm
450 r <- foldEither fld strm
428 case r of
451 case r of
429 Right res -> return res
452 Right res -> return res
430− Left (Fold _ initial extract) -> do
453+ Left (Fold _ initial _ final) -> do
431 res <- initial
454 res <- initial
432 case res of
455 case res of
433 FL.Done _ -> error "foldBreak: unreachable state"
456 FL.Done _ -> error "foldBreak: unreachable state"
434 FL.Partial s -> do
457 FL.Partial s -> do
435− b <- extract s
458+ b <- final s
436 return (b, nil)
459 return (b, nil)
437
460
438 where
461 where
@@ -475,8 +498,8 @@ fold fld strm = do
475--
498--
476{-# INLINE_NORMAL foldAddLazy #-}
499{-# INLINE_NORMAL foldAddLazy #-}
477foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
500foldAddLazy :: Monad m => Fold m a b -> Stream m a -> Fold m a b
478−foldAddLazy (Fold fstep finitial fextract) (Stream sstep state) =
501+foldAddLazy (Fold fstep finitial fextract ffinal) (Stream sstep state) =
479− Fold fstep initial fextract
502+ Fold fstep initial fextract ffinal
480
503
481 where
504 where
482
505
@@ -549,8 +572,12 @@ foldAdd f =
549-- >>> Stream.foldrM step (return False) s
572-- >>> Stream.foldrM step (return False) s
550-- True
573-- True
551--
574--
575+-- >>> import Control.Monad (join)
576+-- >>> foldrM f z = join $ Stream.foldr f z
577+--
552{-# INLINE_NORMAL foldrM #-}
578{-# INLINE_NORMAL foldrM #-}
553foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
579foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
580+-- foldrM f z = join . Streamly.Internal.Data.Stream.StreamD.Type.foldr f z
554foldrM f z (Stream step state) = go SPEC state
581foldrM f z (Stream step state) = go SPEC state
555 where
582 where
556 {-# INLINE_LATE go #-}
583 {-# INLINE_LATE go #-}
@@ -1796,7 +1823,7 @@ data FoldManyPost s fs b a
1796--
1823--
1797{-# INLINE_NORMAL foldManyPost #-}
1824{-# INLINE_NORMAL foldManyPost #-}
1798foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
1825foldManyPost :: Monad m => Fold m a b -> Stream m a -> Stream m b
1799−foldManyPost (Fold fstep initial extract) (Stream step state) =
1826+foldManyPost (Fold fstep initial _ final) (Stream step state) =
1800 Stream step' (FoldManyPostStart state)
1827 Stream step' (FoldManyPostStart state)
1801
1828
1802 where
1829 where
@@ -1824,7 +1851,7 @@ foldManyPost (Fold fstep initial extract) (Stream step state) =
1824 Yield x s -> consume x s fs
1851 Yield x s -> consume x s fs
1825 Skip s -> return $ Skip (FoldManyPostLoop s fs)
1852 Skip s -> return $ Skip (FoldManyPostLoop s fs)
1826 Stop -> do
1853 Stop -> do
1827− b <- extract fs
1854+ b <- final fs
1828 return $ Skip (FoldManyPostYield b FoldManyPostDone)
1855 return $ Skip (FoldManyPostYield b FoldManyPostDone)
1829 step' _ (FoldManyPostYield b next) = return $ Yield b next
1856 step' _ (FoldManyPostYield b next) = return $ Yield b next
1830 step' _ FoldManyPostDone = return Stop
1857 step' _ FoldManyPostDone = return Stop
@@ -1868,7 +1895,7 @@ data FoldMany s fs b a
1868--
1895--
1869{-# INLINE_NORMAL foldMany #-}
1896{-# INLINE_NORMAL foldMany #-}
1870foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
1897foldMany :: Monad m => Fold m a b -> Stream m a -> Stream m b
1871−foldMany (Fold fstep initial extract) (Stream step state) =
1898+foldMany (Fold fstep initial _ final) (Stream step state) =
1872 Stream step' (FoldManyStart state)
1899 Stream step' (FoldManyStart state)
1873
1900
1874 where
1901 where
@@ -1895,14 +1922,14 @@ foldMany (Fold fstep initial extract) (Stream step state) =
1895 case r of
1922 case r of
1896 Yield x s -> consume x s fs
1923 Yield x s -> consume x s fs
1897 Skip s -> return $ Skip (FoldManyFirst fs s)
1924 Skip s -> return $ Skip (FoldManyFirst fs s)
1898− Stop -> return Stop
1925+ Stop -> final fs >> return Stop
1899 step' gst (FoldManyLoop st fs) = do
1926 step' gst (FoldManyLoop st fs) = do
1900 r <- step (adaptState gst) st
1927 r <- step (adaptState gst) st
1901 case r of
1928 case r of
1902 Yield x s -> consume x s fs
1929 Yield x s -> consume x s fs
1903 Skip s -> return $ Skip (FoldManyLoop s fs)
1930 Skip s -> return $ Skip (FoldManyLoop s fs)
1904 Stop -> do
1931 Stop -> do
1905− b <- extract fs
1932+ b <- final fs
1906 return $ Skip (FoldManyYield b FoldManyDone)
1933 return $ Skip (FoldManyYield b FoldManyDone)
1907 step' _ (FoldManyYield b next) = return $ Yield b next
1934 step' _ (FoldManyYield b next) = return $ Yield b next
1908 step' _ FoldManyDone = return Stop
1935 step' _ FoldManyDone = return Stop
@@ -1969,6 +1996,110 @@ refoldMany (Refold fstep inject extract) action (Stream step state) =
1969 step' _ (FoldManyYield b next) = return $ Yield b next
1996 step' _ (FoldManyYield b next) = return $ Yield b next
1970 step' _ FoldManyDone = return Stop
1997 step' _ FoldManyDone = return Stop
1971
1998
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+
1972------------------------------------------------------------------------------
2103------------------------------------------------------------------------------
1973-- Stream with a cross product style monad instance
2104-- Stream with a cross product style monad instance
1974------------------------------------------------------------------------------
2105------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/StreamK.hs+35−40
@@ -16,16 +16,15 @@ module Streamly.Internal.Data.StreamK
16 --
16 --
17 -- $setup
17 -- $setup
18
18
19− -- * The stream type
20 module Streamly.Internal.Data.StreamK.Type
19 module Streamly.Internal.Data.StreamK.Type
20+ -- * Transformer
21 , module Streamly.Internal.Data.StreamK.Transformer
21 , module Streamly.Internal.Data.StreamK.Transformer
22
22
23− , StreamK(..)
23+ -- * From containers
24 , fromList
24 , fromList
25 , fromStream
25 , fromStream
26− , toStream
27
26
28− -- ** Specialized Generation
27+ -- * Specialized Generation
29 , repeatM
28 , repeatM
30 , replicate
29 , replicate
31 , replicateM
30 , replicateM
@@ -37,8 +36,6 @@ module Streamly.Internal.Data.StreamK
37 -- * Elimination
36 -- * Elimination
38 -- ** General Folds
37 -- ** General Folds
39 , foldr1
38 , foldr1
40− , foldlM'
41− , foldlMx'
42 , fold
39 , fold
43 , foldBreak
40 , foldBreak
44 , foldEither
41 , foldEither
@@ -69,13 +66,13 @@ module Streamly.Internal.Data.StreamK
69 , find
66 , find
70 , (!!)
67 , (!!)
71
68
69+ -- ** To Containers
70+ , toList
71+ , toStream
72+
72 -- ** Map and Fold
73 -- ** Map and Fold
73 , mapM_
74 , mapM_
74
75
75− -- ** Conversions
76− , toList
77− , hoist
78−
79 -- * Transformation
76 -- * Transformation
80 -- ** By folding (scans)
77 -- ** By folding (scans)
81 , scanl'
78 , scanl'
@@ -102,6 +99,7 @@ module Streamly.Internal.Data.StreamK
102
99
103 -- ** Reordering
100 -- ** Reordering
104 , sortBy
101 , sortBy
102+ , sortOn
105
103
106 -- ** Map and Filter
104 -- ** Map and Filter
107 , mapMaybe
105 , mapMaybe
@@ -117,6 +115,9 @@ module Streamly.Internal.Data.StreamK
117 -- ** Transformation comprehensions
115 -- ** Transformation comprehensions
118 , the
116 , the
119
117
118+ -- ** Transforming Inner Monad
119+ , hoist
120+
120 -- * Exceptions
121 -- * Exceptions
121 , handle
122 , handle
122
123
@@ -133,6 +134,7 @@ import Control.Exception (mask_, Exception)
133import Control.Monad (void, join)
134import Control.Monad (void, join)
134import Control.Monad.Catch (MonadCatch)
135import Control.Monad.Catch (MonadCatch)
135import Control.Monad.IO.Class (MonadIO(..))
136import Control.Monad.IO.Class (MonadIO(..))
137+import Data.Ord (comparing)
136import Data.Proxy (Proxy(..))
138import Data.Proxy (Proxy(..))
137import GHC.Types (SPEC(..))
139import GHC.Types (SPEC(..))
138import Streamly.Internal.Data.Array.Type (Array(..))
140import Streamly.Internal.Data.Array.Type (Array(..))
@@ -306,19 +308,6 @@ foldr1 step m = do
306 yieldk a r = fmap (step p) (go a r)
308 yieldk a r = fmap (step p) (go a r)
307 in foldStream defState yieldk single stp m1
309 in foldStream defState yieldk single stp m1
308
310
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−
322-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
311-- | Fold a stream using the supplied left 'Fold' and reducing the resulting
323-- expression strictly at each step. The behavior is similar to 'foldl''. A
312-- expression strictly at each step. The behavior is similar to 'foldl''. A
324-- 'Fold' can terminate early without consuming the full stream. See the
313-- 'Fold' can terminate early without consuming the full stream. See the
@@ -336,7 +325,7 @@ foldlMx' step begin done = go begin
336--
325--
337{-# INLINABLE fold #-}
326{-# INLINABLE fold #-}
338fold :: Monad m => FL.Fold m a b -> StreamK m a -> m b
327fold :: Monad m => FL.Fold m a b -> StreamK m a -> m b
339−fold (FL.Fold step begin done) m = do
328+fold (FL.Fold step begin _ final) m = do
340 res <- begin
329 res <- begin
341 case res of
330 case res of
342 FL.Partial fs -> go fs m
331 FL.Partial fs -> go fs m
@@ -344,10 +333,10 @@ fold (FL.Fold step begin done) m = do
344
333
345 where
334 where
346 go !acc m1 =
335 go !acc m1 =
347− let stop = done acc
336+ let stop = final acc
348 single a = step acc a
337 single a = step acc a
349 >>= \case
338 >>= \case
350− FL.Partial s -> done s
339+ FL.Partial s -> final s
351 FL.Done b1 -> return b1
340 FL.Done b1 -> return b1
352 yieldk a r = step acc a
341 yieldk a r = step acc a
353 >>= \case
342 >>= \case
@@ -365,7 +354,7 @@ fold (FL.Fold step begin done) m = do
365{-# INLINE foldEither #-}
354{-# INLINE foldEither #-}
366foldEither :: Monad m =>
355foldEither :: Monad m =>
367 Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a))
356 Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a))
368−foldEither (FL.Fold step begin done) m = do
357+foldEither (FL.Fold step begin done final) m = do
369 res <- begin
358 res <- begin
370 case res of
359 case res of
371 FL.Partial fs -> go fs m
360 FL.Partial fs -> go fs m
@@ -374,12 +363,15 @@ foldEither (FL.Fold step begin done) m = do
374 where
363 where
375
364
376 go !acc m1 =
365 go !acc m1 =
366+ let stop =
377− let stop = return $ Left (Fold step (return $ FL.Partial acc) done)
367+ let f = Fold step (return $ FL.Partial acc) done final
368+ in return $ Left f
378 single a =
369 single a =
379 step acc a
370 step acc a
380 >>= \case
371 >>= \case
381 FL.Partial s ->
372 FL.Partial s ->
382− return $ Left (Fold step (return $ FL.Partial s) done)
373+ let f = Fold step (return $ FL.Partial s) done final
374+ in return $ Left f
383 FL.Done b1 -> return $ Right (b1, nil)
375 FL.Done b1 -> return $ Right (b1, nil)
384 yieldk a r =
376 yieldk a r =
385 step acc a
377 step acc a
@@ -397,12 +389,12 @@ foldBreak fld strm = do
397 r <- foldEither fld strm
389 r <- foldEither fld strm
398 case r of
390 case r of
399 Right res -> return res
391 Right res -> return res
400− Left (Fold _ initial extract) -> do
392+ Left (Fold _ initial _ final) -> do
401 res <- initial
393 res <- initial
402 case res of
394 case res of
403 FL.Done _ -> error "foldBreak: unreachable state"
395 FL.Done _ -> error "foldBreak: unreachable state"
404 FL.Partial s -> do
396 FL.Partial s -> do
405− b <- extract s
397+ b <- final s
406 return (b, nil)
398 return (b, nil)
407
399
408-- XXX Array folds can be implemented using this.
400-- XXX Array folds can be implemented using this.
@@ -421,7 +413,7 @@ foldConcat :: Monad m =>
421 Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
413 Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a)
422foldConcat
414foldConcat
423 (Producer pstep pinject pextract)
415 (Producer pstep pinject pextract)
424− (Fold fstep begin done)
416+ (Fold fstep begin _ final)
425 stream = do
417 stream = do
426
418
427 res <- begin
419 res <- begin
@@ -433,14 +425,14 @@ foldConcat
433
425
434 go !acc m1 = do
426 go !acc m1 = do
435 let stop = do
427 let stop = do
436− r <- done acc
428+ r <- final acc
437 return (r, nil)
429 return (r, nil)
438 single a = do
430 single a = do
439 st <- pinject a
431 st <- pinject a
440 res <- go1 SPEC acc st
432 res <- go1 SPEC acc st
441 case res of
433 case res of
442 Left fs -> do
434 Left fs -> do
443− r <- done fs
435+ r <- final fs
444 return (r, nil)
436 return (r, nil)
445 Right (b, s) -> do
437 Right (b, s) -> do
446 x <- pextract s
438 x <- pextract s
@@ -467,11 +459,6 @@ foldConcat
467 Stream.Skip s -> go1 SPEC fs s
459 Stream.Skip s -> go1 SPEC fs s
468 Stream.Stop -> return $ Left fs
460 Stream.Stop -> return $ Left fs
469
461
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−
475------------------------------------------------------------------------------
462------------------------------------------------------------------------------
476-- Specialized folds
463-- Specialized folds
477------------------------------------------------------------------------------
464------------------------------------------------------------------------------
@@ -1328,7 +1315,8 @@ parserDone (ParserK.Failure n e) _ _ = pure $ ParserK.Error n e
1328-- using parseBreakChunks. We can also use parseBreak as an alternative to the
1315-- using parseBreakChunks. We can also use parseBreak as an alternative to the
1329-- monad instance of ParserD.
1316-- monad instance of ParserD.
1330
1317
1331−-- | Run a 'ParserK' over a chunked 'StreamK' and return the rest of the Stream.
1318+-- | Run a 'ParserK' over a chunked 'StreamK' and return the parse result and
1319+-- the remaining Stream.
1332{-# INLINE_NORMAL parseBreakChunks #-}
1320{-# INLINE_NORMAL parseBreakChunks #-}
1333parseBreakChunks
1321parseBreakChunks
1334 :: (Monad m, Unbox a)
1322 :: (Monad m, Unbox a)
@@ -1733,3 +1721,10 @@ sortBy cmp =
1733 . Stream.catRights -- its a non-failing backtracking parser
1721 . Stream.catRights -- its a non-failing backtracking parser
1734 . Stream.parseMany (fmap (either id id) p)
1722 . Stream.parseMany (fmap (either id id) p)
1735 . Stream.fromStreamK
1723 . Stream.fromStreamK
1724+
1725+{-# INLINE sortOn #-}
1726+sortOn :: (Monad m, Ord b) => (a -> b) -> StreamK m a -> StreamK m a
1727+sortOn f =
1728+ fmap snd
1729+ . sortBy (comparing fst)
1730+ . fmap (\x -> let y = f x in y `seq` (y, x))
core/src/Streamly/Internal/Data/StreamK/Type.hs+80−11
@@ -1,4 +1,8 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE TypeFamilies #-}
3+-- Must come after TypeFamilies, otherwise it is re-enabled.
4+-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
5+{-# LANGUAGE NoMonoLocalBinds #-}
2{-# LANGUAGE UndecidableInstances #-}
6{-# LANGUAGE UndecidableInstances #-}
3-- |
7-- |
4-- Module : Streamly.Internal.Data.StreamK.Type
8-- Module : Streamly.Internal.Data.StreamK.Type
@@ -84,6 +88,8 @@ module Streamly.Internal.Data.StreamK.Type
84 -- ** Strict Left Folds
88 -- ** Strict Left Folds
85 , Streamly.Internal.Data.StreamK.Type.foldl'
89 , Streamly.Internal.Data.StreamK.Type.foldl'
86 , foldlx'
90 , foldlx'
91+ , foldlMx'
92+ , foldlM'
87
93
88 -- ** Lazy Right Folds
94 -- ** Lazy Right Folds
89 , Streamly.Internal.Data.StreamK.Type.foldr
95 , Streamly.Internal.Data.StreamK.Type.foldr
@@ -91,8 +97,11 @@ module Streamly.Internal.Data.StreamK.Type
91 -- ** Specific Folds
97 -- ** Specific Folds
92 , drain
98 , drain
93 , null
99 , null
100+ , headNonEmpty
94 , tail
101 , tail
102+ , tailNonEmpty
95 , init
103 , init
104+ , initNonEmpty
96
105
97 -- * Mapping
106 -- * Mapping
98 , map
107 , map
@@ -817,6 +826,24 @@ foldlx' step begin done m = get $ go m begin
817foldl' :: Monad m => (b -> a -> b) -> b -> StreamK m a -> m b
826foldl' :: Monad m => (b -> a -> b) -> b -> StreamK m a -> m b
818foldl' step begin = foldlx' step begin id
827foldl' step begin = foldlx' step begin id
819
828
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+
820------------------------------------------------------------------------------
847------------------------------------------------------------------------------
821-- Specialized folds
848-- Specialized folds
822------------------------------------------------------------------------------
849------------------------------------------------------------------------------
@@ -1787,14 +1814,42 @@ iterateMWith cns step = go
1787 !next <- s
1814 !next <- s
1788 foldStreamShared st stp sng yld (return next `cns` go (step next))
1815 foldStreamShared st stp sng yld (return next `cns` go (step next))
1789
1816
1790−{-# INLINE headPartial #-}
1817+-- | head for non-empty streams, fails for empty stream case.
1818+--
1819+{-# INLINE headNonEmpty #-}
1791−headPartial :: Monad m => StreamK m a -> m a
1820+headNonEmpty :: Monad m => StreamK m a -> m a
1792−headPartial = foldrM (\x _ -> return x) (error "head of nil")
1821+headNonEmpty = foldrM (\x _ -> return x) (error "headNonEmpty: empty stream")
1822+
1823+-- | init for non-empty streams, fails for empty stream case.
1824+--
1825+-- See also 'init' for a non-partial version of this function..
1826+{-# INLINE initNonEmpty #-}
1827+initNonEmpty :: Stream m a -> Stream m a
1828+initNonEmpty = go0
1829+
1830+ where
1831+
1832+ go0 m = mkStream $ \st yld sng stp ->
1833+ let stop = error "initNonEmpty: Empty Stream."
1834+ single _ = stp
1835+ yieldk a r = foldStream st yld sng stp (go1 a r)
1836+ in foldStream st yieldk single stop m
1837+
1838+ go1 a r = mkStream $ \st yld sng stp ->
1839+ let stop = stp
1840+ single _ = sng a
1841+ yieldk a1 r1 = yld a (go1 a1 r1)
1842+ in foldStream st yieldk single stop r
1793
1843
1794−{-# INLINE tailPartial #-}
1844+-- | tail for non-empty streams, fails for empty stream case.
1845+--
1846+-- See also 'tail' for a non-partial version of this function..
1847+--
1848+-- Note: this is same as "drop 1" with error on empty stream.
1849+{-# INLINE tailNonEmpty #-}
1795−tailPartial :: StreamK m a -> StreamK m a
1850+tailNonEmpty :: StreamK m a -> StreamK m a
1796−tailPartial m = mkStream $ \st yld sng stp ->
1851+tailNonEmpty m = mkStream $ \st yld sng stp ->
1797− let stop = error "tail of nil"
1852+ let stop = error "tailNonEmpty: empty stream"
1798 single _ = stp
1853 single _ = stp
1799 yieldk _ r = foldStream st yld sng stp r
1854 yieldk _ r = foldStream st yld sng stp r
1800 in foldStream st yieldk single stop m
1855 in foldStream st yieldk single stop m
@@ -1859,10 +1914,10 @@ mfix f = mkStream $ \st yld sng stp ->
1859 where
1914 where
1860
1915
1861 -- fix the head element of the stream
1916 -- fix the head element of the stream
1862− xs = fix (f . headPartial)
1917+ xs = fix (f . headNonEmpty)
1863
1918
1864 -- now fix the tail recursively
1919 -- now fix the tail recursively
1865− ys = mfix (tailPartial . f)
1920+ ys = mfix (tailNonEmpty . f)
1866
1921
1867-------------------------------------------------------------------------------
1922-------------------------------------------------------------------------------
1868-- Conversions
1923-- Conversions
@@ -1893,6 +1948,15 @@ uncons m =
1893 yieldk a r = pure (Just (a, r))
1948 yieldk a r = pure (Just (a, r))
1894 in foldStream defState yieldk single stop m
1949 in foldStream defState yieldk single stop m
1895
1950
1951+-- Note that this is not a StreamK -> StreamK because then we cannot handle the
1952+-- empty stream case without making this a partial function.
1953+--
1954+-- See tailNonEmpty as well above.
1955+
1956+-- | Same as:
1957+--
1958+-- >>> tail = fmap (fmap snd) StreamK.uncons
1959+--
1896{-# INLINE tail #-}
1960{-# INLINE tail #-}
1897tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
1961tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
1898tail =
1962tail =
@@ -1901,9 +1965,14 @@ tail =
1901 yieldk _ r = pure $ Just r
1965 yieldk _ r = pure $ Just r
1902 in foldStream defState yieldk single stop
1966 in foldStream defState yieldk single stop
1903
1967
1904−-- | Extract all but the last element of the stream, if any.
1968+-- Note that this is not a StreamK -> StreamK because then we cannot handle the
1969+-- empty stream case without making this a partial function.
1905--
1970--
1906−-- Note: This will end up buffering the entire stream.
1971+-- XXX How do we implement unsnoc? Make StreamK a monad and return the
1972+-- remaining stream as a result value in the monad?
1973+
1974+-- | Extract all but the last element of the stream, if any. This will end up
1975+-- evaluating the last element as well to find out that it is last.
1907--
1976--
1908-- /Pre-release/
1977-- /Pre-release/
1909{-# INLINE init #-}
1978{-# INLINE init #-}
core/src/Streamly/Internal/Data/Time/Units.hs−4
@@ -1,7 +1,3 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE PolyKinds #-}
3−{-# LANGUAGE UnboxedTuples #-}
4−
5-- |
1-- |
6-- Module : Streamly.Internal.Data.Time.Units
2-- Module : Streamly.Internal.Data.Time.Units
7-- Copyright : (c) 2019 Composewell Technologies
3-- Copyright : (c) 2019 Composewell Technologies
core/src/Streamly/Internal/Data/Unbox.hs+165−289
@@ -1,5 +1,8 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE DefaultSignatures #-}
2+{-# LANGUAGE TypeFamilies #-}
3+-- Must come after TypeFamilies, otherwise it is re-enabled.
4+-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
5+{-# LANGUAGE NoMonoLocalBinds #-}
3{-# LANGUAGE UnboxedTuples #-}
6{-# LANGUAGE UnboxedTuples #-}
4{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
5
8
@@ -12,49 +15,34 @@
12-- Portability : GHC
15-- Portability : GHC
13--
16--
14module Streamly.Internal.Data.Unbox
17module Streamly.Internal.Data.Unbox
15− ( Unbox(..)
18+ (
16− , PinnedState(..)
19+ -- ** Unbox type class
17− , MutableByteArray(..)
20+ Unbox(..)
18− , touch
19− , getMutableByteArray#
20− , sizeOfMutableByteArray
21− , isPinned
22− , pin
23− , unpin
24− , newBytesAs
25− , newBytes
26− , pinnedNewBytes
27− , pinnedNewAlignedBytes
28− , nil
29− , putSliceUnsafe
30−
31− -- * Type Parser and Builder
32− , BoundedPtr (..)
33
21
22+ -- ** Peek and poke utilities
23+ , BoundedPtr (..)
24+ -- Peek
34 , Peeker (..)
25 , Peeker (..)
35 , read
26 , read
36 , readUnsafe
27 , readUnsafe
37 , skipByte
28 , skipByte
38 , runPeeker
29 , runPeeker
39−
30+ -- Poke
40 , pokeBoundedPtrUnsafe
31 , pokeBoundedPtrUnsafe
41 , pokeBoundedPtr
32 , pokeBoundedPtr
42
33
43− -- * Generic Unbox instances
34+ -- ** Generic Deriving
44− , genericSizeOf
45− , genericPeekByteIndex
46− , genericPokeByteIndex
47−
48− -- Classess used for generic deriving.
49 , PeekRep(..)
35 , PeekRep(..)
50 , PokeRep(..)
36 , PokeRep(..)
51 , SizeOfRep(..)
37 , SizeOfRep(..)
38+ , genericSizeOf
39+ , genericPeekByteIndex
40+ , genericPokeByteIndex
52 ) where
41 ) where
53
42
54#include "MachDeps.h"
43#include "MachDeps.h"
55#include "ArrayMacros.h"
44#include "ArrayMacros.h"
56
45
57−import Control.Monad.IO.Class (MonadIO(..))
58import Control.Monad (void, when)
46import Control.Monad (void, when)
59import Data.Complex (Complex((:+)))
47import Data.Complex (Complex((:+)))
60import Data.Functor ((<&>))
48import Data.Functor ((<&>))
@@ -62,9 +50,6 @@ import Data.Functor.Const (Const(..))
62import Data.Functor.Identity (Identity(..))
50import Data.Functor.Identity (Identity(..))
63import Data.Kind (Type)
51import Data.Kind (Type)
64import Data.Proxy (Proxy (..))
52import Data.Proxy (Proxy (..))
65−#ifdef DEBUG
66−import Debug.Trace (trace)
67−#endif
68import Foreign.Ptr (IntPtr(..), WordPtr(..))
53import Foreign.Ptr (IntPtr(..), WordPtr(..))
69import GHC.Base (IO(..))
54import GHC.Base (IO(..))
70import GHC.Fingerprint.Type (Fingerprint(..))
55import GHC.Fingerprint.Type (Fingerprint(..))
@@ -76,172 +61,16 @@ import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
76import GHC.RTS.Flags (IoSubSystem(..))
61import GHC.RTS.Flags (IoSubSystem(..))
77#endif
62#endif
78import Streamly.Internal.Data.Builder (Builder (..))
63import Streamly.Internal.Data.Builder (Builder (..))
79−import System.IO.Unsafe (unsafePerformIO)
80
64
81import GHC.Generics
65import GHC.Generics
82import GHC.Exts
66import GHC.Exts
83import GHC.TypeLits
67import GHC.TypeLits
84import Prelude hiding (read)
68import Prelude hiding (read)
85
69
86−--------------------------------------------------------------------------------
70+import Streamly.Internal.Data.MutByteArray.Type (MutByteArray(..))
87−-- The ArrayContents type
88−--------------------------------------------------------------------------------
89−
90−data PinnedState
91− = Pinned
92− | Unpinned
93−
94−-- XXX can use UnliftedNewtypes
95−data MutableByteArray = MutableByteArray (MutableByteArray# RealWorld)
96−
97−{-# INLINE getMutableByteArray# #-}
98−getMutableByteArray# :: MutableByteArray -> MutableByteArray# RealWorld
99−getMutableByteArray# (MutableByteArray mbarr) = mbarr
100−
101−{-# INLINE touch #-}
102−touch :: MutableByteArray -> IO ()
103−touch (MutableByteArray contents) =
104− IO $ \s -> case touch# contents s of s' -> (# s', () #)
105−
106−-- | Return the size of the array in bytes.
107−{-# INLINE sizeOfMutableByteArray #-}
108−sizeOfMutableByteArray :: MutableByteArray -> IO Int
109−sizeOfMutableByteArray (MutableByteArray arr) =
110− IO $ \s ->
111− case getSizeofMutableByteArray# arr s of
112− (# s1, i #) -> (# s1, I# i #)
113−
114−--------------------------------------------------------------------------------
115−-- Creation
116−--------------------------------------------------------------------------------
117−
118−{-# NOINLINE nil #-}
119−nil :: MutableByteArray
120−nil = unsafePerformIO $ newBytes 0
121−
122−{-# INLINE newBytes #-}
123−newBytes :: Int -> IO MutableByteArray
124−newBytes nbytes | nbytes < 0 =
125− errorWithoutStackTrace "newBytes: size must be >= 0"
126−newBytes (I# nbytes) = IO $ \s ->
127− case newByteArray# nbytes s of
128− (# s', mbarr# #) ->
129− let c = MutableByteArray mbarr#
130− in (# s', c #)
131−
132−{-# INLINE pinnedNewBytes #-}
133−pinnedNewBytes :: Int -> IO MutableByteArray
134−pinnedNewBytes nbytes | nbytes < 0 =
135− errorWithoutStackTrace "pinnedNewBytes: size must be >= 0"
136−pinnedNewBytes (I# nbytes) = IO $ \s ->
137− case newPinnedByteArray# nbytes s of
138− (# s', mbarr# #) ->
139− let c = MutableByteArray mbarr#
140− in (# s', c #)
141−
142−{-# INLINE pinnedNewAlignedBytes #-}
143−pinnedNewAlignedBytes :: Int -> Int -> IO MutableByteArray
144−pinnedNewAlignedBytes nbytes _align | nbytes < 0 =
145− errorWithoutStackTrace "pinnedNewAlignedBytes: size must be >= 0"
146−pinnedNewAlignedBytes (I# nbytes) (I# align) = IO $ \s ->
147− case newAlignedPinnedByteArray# nbytes align s of
148− (# s', mbarr# #) ->
149− let c = MutableByteArray mbarr#
150− in (# s', c #)
151−
152−{-# INLINE newBytesAs #-}
153−newBytesAs :: PinnedState -> Int -> IO MutableByteArray
154−newBytesAs Unpinned = newBytes
155−newBytesAs Pinned = pinnedNewBytes
156−
157−-------------------------------------------------------------------------------
158−-- Copying
159−-------------------------------------------------------------------------------
160−
161−-- | Put a sub range of a source array into a subrange of a destination array.
162−-- This is not safe as it does not check the bounds.
163−{-# INLINE putSliceUnsafe #-}
164−putSliceUnsafe ::
165− MonadIO m
166− => MutableByteArray
167− -> Int
168− -> MutableByteArray
169− -> Int
170− -> Int
171− -> m ()
172−putSliceUnsafe src srcStartBytes dst dstStartBytes lenBytes = liftIO $ do
173#ifdef DEBUG
71#ifdef DEBUG
174− srcLen <- sizeOfMutableByteArray src
72+import Streamly.Internal.Data.MutByteArray.Type (sizeOfMutableByteArray)
175− dstLen <- sizeOfMutableByteArray src
176− when (srcLen - srcStartBytes < lenBytes) $ error "SRC: Insufficient length."
177− when (dstLen - dstStartBytes < lenBytes) $ error "DST: Insufficient length."
178#endif
73#endif
179− let !(I# srcStartBytes#) = srcStartBytes
180− !(I# dstStartBytes#) = dstStartBytes
181− !(I# lenBytes#) = lenBytes
182− let arrS# = getMutableByteArray# src
183− arrD# = getMutableByteArray# dst
184− IO $ \s# -> (# copyMutableByteArray#
185− arrS# srcStartBytes# arrD# dstStartBytes# lenBytes# s#
186− , () #)
187−
188−-------------------------------------------------------------------------------
189−-- Pinning & Unpinning
190−-------------------------------------------------------------------------------
191−
192−{-# INLINE isPinned #-}
193−isPinned :: MutableByteArray -> Bool
194−isPinned (MutableByteArray arr#) =
195− let pinnedInt = I# (isMutableByteArrayPinned# arr#)
196− in pinnedInt /= 0
197−
198−
199−{-# INLINE cloneMutableArrayWith# #-}
200−cloneMutableArrayWith#
201− :: (Int# -> State# RealWorld -> (# State# RealWorld
202− , MutableByteArray# RealWorld #))
203− -> MutableByteArray# RealWorld
204− -> State# RealWorld
205− -> (# State# RealWorld, MutableByteArray# RealWorld #)
206−cloneMutableArrayWith# alloc# arr# s# =
207− case getSizeofMutableByteArray# arr# s# of
208− (# s1#, i# #) ->
209− case alloc# i# s1# of
210− (# s2#, arr1# #) ->
211− case copyMutableByteArray# arr# 0# arr1# 0# i# s2# of
212− s3# -> (# s3#, arr1# #)
213−
214−{-# INLINE pin #-}
215−pin :: MutableByteArray -> IO MutableByteArray
216−pin arr@(MutableByteArray marr#) =
217− if isPinned arr
218− then return arr
219− else
220−#ifdef DEBUG
221− do
222− -- XXX dump stack trace
223− trace ("pin: Copying array") (return ())
224−#endif
225− IO
226− $ \s# ->
227− case cloneMutableArrayWith# newPinnedByteArray# marr# s# of
228− (# s1#, marr1# #) -> (# s1#, MutableByteArray marr1# #)
229−
230−{-# INLINE unpin #-}
231−unpin :: MutableByteArray -> IO MutableByteArray
232−unpin arr@(MutableByteArray marr#) =
233− if not (isPinned arr)
234− then return arr
235− else
236−#ifdef DEBUG
237− do
238− -- XXX dump stack trace
239− trace ("unpin: Copying array") (return ())
240−#endif
241− IO
242− $ \s# ->
243− case cloneMutableArrayWith# newByteArray# marr# s# of
244− (# s1#, marr1# #) -> (# s1#, MutableByteArray marr1# #)
245
74
246--------------------------------------------------------------------------------
75--------------------------------------------------------------------------------
247-- The Unbox type class
76-- The Unbox type class
@@ -327,23 +156,37 @@ unpin arr@(MutableByteArray marr#) =
327-- size fields at each nesting level, aggregating the size upwards.
156-- size fields at each nesting level, aggregating the size upwards.
328
157
329-- | The 'Unbox' type class provides operations for serialization (unboxing)
158-- | The 'Unbox' type class provides operations for serialization (unboxing)
330−-- and deserialization (boxing) of a fixed-length, non-recursive Haskell data
159+-- and deserialization (boxing) of fixed-length, non-recursive Haskell data
331−-- type to and from its unboxed byte representation in a mutable byte array.
160+-- types to and from their byte stream representation.
161+--
332-- Unbox uses fixed size encoding, therefore, size is independent of the value,
162-- Unbox uses fixed size encoding, therefore, size is independent of the value,
333−-- it can be determined solely by the type. This makes types with 'Unbox'
163+-- it must be determined solely by the type. This restriction makes types with
334−-- instances suitable for storing in arrays. Note that sum types may have
164+-- 'Unbox' instances suitable for storing in arrays. Note that sum types may
335−-- multiple constructors of different sizes, the size of the sum type is
165+-- have multiple constructors of different sizes, the size of a sum type is
336-- computed as the maximum required by any constructor.
166-- computed as the maximum required by any constructor.
337--
167--
168+-- The 'peekAt' operation reads as many bytes from the mutable byte
169+-- array as the @size@ of the data type and builds a Haskell data type from
338−-- The 'peekByteIndex' read operation converts a Haskell type from its unboxed
170+-- these bytes. 'pokeAt' operation converts a Haskell data type to its
339−-- representation stored in a mutable byte array, while the 'pokeByteIndex'
171+-- binary representation which consists of @size@ bytes and then stores
340−-- write operation serializes a Haskell data type to its byte representation in
341−-- the mutable byte array. These operations do not check the bounds of the
172+-- these bytes into the mutable byte array. These operations do not check the
342−-- array, the user of the type class is expected to check the bounds before
173+-- bounds of the array, the user of the type class is expected to check the
343−-- peeking or poking.
174+-- bounds before peeking or poking.
344−--
175+--
176+-- IMPORTANT: The serialized data's byte ordering remains the same as the host
177+-- machine's byte order. Therefore, it can not be deserialized from host
178+-- machines with a different byte ordering.
179+--
345−-- Instances can be derived via Generics or Template Haskell. Note that the
180+-- Instances can be derived via Generics, Template Haskell, or written
346−-- data type must be non-recursive.
181+-- manually. Note that the data type must be non-recursive. WARNING! Generic
182+-- and Template Haskell deriving, both hang for recursive data types. Deriving
183+-- via Generics is more convenient but Template Haskell should be preferred
184+-- over Generics for the following reasons:
185+--
186+-- 1. Instances derived via Template Haskell provide better and more reliable
187+-- performance.
188+-- 2. Generic deriving allows only 256 fields or constructor tags whereas
189+-- template Haskell has no limit.
347--
190--
348-- Here is an example, for deriving an instance of this type class using
191-- Here is an example, for deriving an instance of this type class using
349-- generics:
192-- generics:
@@ -356,113 +199,136 @@ unpin arr@(MutableByteArray marr#) =
356-- } deriving Generic
199-- } deriving Generic
357-- :}
200-- :}
358--
201--
202+-- >>> import Streamly.Data.MutByteArray (Unbox(..))
203+-- >>> instance Unbox Object
204+--
359-- To derive the instance via Template Haskell:
205-- To derive the instance via Template Haskell:
360--
206--
361-- @
207-- @
362−-- import Streamly.Data.Serialize (deriveUnbox)
208+-- import Streamly.Data.MutByteArray (deriveUnbox)
363−-- $(deriveUnbox ''Object)
209+-- \$(deriveUnbox [d|instance Unbox Object|])
364-- @
210-- @
365--
211--
366−-- See 'Streamly.Data.Serialize.deriveUnbox' and
212+-- See 'Streamly.Data.MutByteArray.deriveUnbox' for more information on deriving
367−-- 'Streamly.Data.Serialize.deriveUnboxWith' for more information on deriving
368-- using Template Haskell.
213-- using Template Haskell.
369--
214--
370−-- Deriving via Template Haskell should be preferred for the following reasons:
371−-- 1. Instances derived via Template Haskell have more performant routines.
372−-- 2. Template Haskell deriving can handle (maxBound :: Word64) number of
373−-- constructors whereas the Generic deriving can only handle 256.
374−--
375−-- WARNING! Generic and Template Haskell deriving, both hang for recursive data
376−-- types.
377−--
378−-- >>> import Streamly.Data.Array (Unbox(..))
379−-- >>> instance Unbox Object
380−--
381-- If you want to write the instance manually:
215-- If you want to write the instance manually:
382--
216--
383-- >>> :{
217-- >>> :{
384-- instance Unbox Object where
218-- instance Unbox Object where
385-- sizeOf _ = 16
219-- sizeOf _ = 16
386−-- peekByteIndex i arr = do
220+-- peekAt i arr = do
387-- -- Check the array bounds
221-- -- Check the array bounds
388−-- x0 <- peekByteIndex i arr
222+-- x0 <- peekAt i arr
389−-- x1 <- peekByteIndex (i + 8) arr
223+-- x1 <- peekAt (i + 8) arr
390-- return $ Object x0 x1
224-- return $ Object x0 x1
391−-- pokeByteIndex i arr (Object x0 x1) = do
225+-- pokeAt i arr (Object x0 x1) = do
392-- -- Check the array bounds
226-- -- Check the array bounds
393−-- pokeByteIndex i arr x0
227+-- pokeAt i arr x0
394−-- pokeByteIndex (i + 8) arr x1
228+-- pokeAt (i + 8) arr x1
395-- :}
229-- :}
396--
230--
397class Unbox a where
231class Unbox a where
398− -- | Get the size. Size cannot be zero.
232+ -- | Get the size. Size cannot be zero, should be at least 1 byte.
399 sizeOf :: Proxy a -> Int
233 sizeOf :: Proxy a -> Int
400
234
401 {-# INLINE sizeOf #-}
235 {-# INLINE sizeOf #-}
402 default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
236 default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
403 sizeOf = genericSizeOf
237 sizeOf = genericSizeOf
404
238
405− -- | Read an element of type "a" from a MutableByteArray given the byte
239+ -- | @peekAt byte-offset array@ reads an element of type @a@ from the
406− -- index.
240+ -- the given the byte offset in the array.
407 --
241 --
408 -- IMPORTANT: The implementation of this interface may not check the bounds
242 -- IMPORTANT: The implementation of this interface may not check the bounds
409 -- of the array, the caller must not assume that.
243 -- of the array, the caller must not assume that.
410− peekByteIndex :: Int -> MutableByteArray -> IO a
244+ peekAt :: Int -> MutByteArray -> IO a
245+
246+ {-# INLINE peekAt #-}
247+ default peekAt :: (Generic a, PeekRep (Rep a)) =>
248+ Int -> MutByteArray -> IO a
249+ peekAt i arr = genericPeekByteIndex arr i
411
250
412− {-# INLINE peekByteIndex #-}
251+ peekByteIndex :: Int -> MutByteArray -> IO a
413− default peekByteIndex :: (Generic a, PeekRep (Rep a)) =>
414− Int -> MutableByteArray -> IO a
415− peekByteIndex i arr = genericPeekByteIndex arr i
252+ peekByteIndex = peekAt
416
253
417− -- | Write an element of type "a" to a MutableByteArray given the byte
254+ -- | @pokeAt byte-offset array@ writes an element of type @a@ to the
418− -- index.
255+ -- the given the byte offset in the array.
419 --
256 --
420 -- IMPORTANT: The implementation of this interface may not check the bounds
257 -- IMPORTANT: The implementation of this interface may not check the bounds
421 -- of the array, the caller must not assume that.
258 -- of the array, the caller must not assume that.
259+ pokeAt :: Int -> MutByteArray -> a -> IO ()
260+
422− pokeByteIndex :: Int -> MutableByteArray -> a -> IO ()
261+ pokeByteIndex :: Int -> MutByteArray -> a -> IO ()
262+ pokeByteIndex = pokeAt
423
263
424− {-# INLINE pokeByteIndex #-}
264+ {-# INLINE pokeAt #-}
425− default pokeByteIndex :: (Generic a, PokeRep (Rep a)) =>
265+ default pokeAt :: (Generic a, PokeRep (Rep a)) =>
426− Int -> MutableByteArray -> a -> IO ()
266+ Int -> MutByteArray -> a -> IO ()
427− pokeByteIndex i arr = genericPokeByteIndex arr i
267+ pokeAt i arr = genericPokeByteIndex arr i
428
268
429−-- XXX Add asserts to check bounds
269+{-# DEPRECATED peekByteIndex "Use peekAt." #-}
270+{-# DEPRECATED pokeByteIndex "Use pokeAt." #-}
271+
272+-- _size is the length from array start to the last accessed byte.
273+{-# INLINE checkBounds #-}
274+checkBounds :: String -> Int -> MutByteArray -> IO ()
275+checkBounds _label _size _arr = do
276+#ifdef DEBUG
277+ sz <- sizeOfMutableByteArray _arr
278+ if (_size > sz)
279+ then error
280+ $ _label
281+ ++ ": accessing array at offset = "
282+ ++ show (_size - 1)
283+ ++ " max valid offset = " ++ show (sz - 1)
284+ else return ()
285+#else
286+ return ()
287+#endif
430
288
431#define DERIVE_UNBOXED(_type, _constructor, _readArray, _writeArray, _sizeOf) \
289#define DERIVE_UNBOXED(_type, _constructor, _readArray, _writeArray, _sizeOf) \
432−instance Unbox _type where { \
290+instance Unbox _type where { \
433−; {-# INLINE peekByteIndex #-} \
291+; {-# INLINE peekAt #-} \
434−; peekByteIndex (I# n) (MutableByteArray mbarr) = IO $ \s -> \
292+; peekAt off@(I# n) arr@(MutByteArray mbarr) = \
293+ checkBounds "peek" (off + sizeOf (Proxy :: Proxy _type)) arr \
294+ >> (IO $ \s -> \
435− case _readArray mbarr n s of \
295+ case _readArray mbarr n s of \
436− { (# s1, i #) -> (# s1, _constructor i #) } \
296+ { (# s1, i #) -> (# s1, _constructor i #) }) \
437−; {-# INLINE pokeByteIndex #-} \
297+; {-# INLINE pokeAt #-} \
438−; pokeByteIndex (I# n) (MutableByteArray mbarr) (_constructor val) = \
298+; pokeAt off@(I# n) arr@(MutByteArray mbarr) (_constructor val) = \
299+ checkBounds "poke" (off + sizeOf (Proxy :: Proxy _type)) arr \
439− IO $ \s -> (# _writeArray mbarr n val s, () #) \
300+ >> (IO $ \s -> (# _writeArray mbarr n val s, () #)) \
440−; {-# INLINE sizeOf #-} \
301+; {-# INLINE sizeOf #-} \
441−; sizeOf _ = _sizeOf \
302+; sizeOf _ = _sizeOf \
442}
303}
443
304
444#define DERIVE_WRAPPED_UNBOX(_constraint, _type, _constructor, _innerType) \
305#define DERIVE_WRAPPED_UNBOX(_constraint, _type, _constructor, _innerType) \
445instance _constraint Unbox _type where \
306instance _constraint Unbox _type where \
446−; {-# INLINE peekByteIndex #-} \
307+; {-# INLINE peekAt #-} \
308+; peekAt i arr = \
309+ checkBounds "peek" (i + sizeOf (Proxy :: Proxy _type)) arr \
447−; peekByteIndex i arr = _constructor <$> peekByteIndex i arr \
310+ >> _constructor <$> peekAt i arr \
448−; {-# INLINE pokeByteIndex #-} \
311+; {-# INLINE pokeAt #-} \
449−; pokeByteIndex i arr (_constructor a) = pokeByteIndex i arr a \
312+; pokeAt i arr (_constructor a) = \
313+ checkBounds "poke" (i + sizeOf (Proxy :: Proxy _type)) arr \
314+ >> pokeAt i arr a \
450; {-# INLINE sizeOf #-} \
315; {-# INLINE sizeOf #-} \
451; sizeOf _ = SIZE_OF(_innerType)
316; sizeOf _ = SIZE_OF(_innerType)
452
317
453−#define DERIVE_BINARY_UNBOX(_constraint, _type, _constructor, _innerType) \
318+#define DERIVE_BINARY_UNBOX(_constraint, _type, _constructor, _innerType) \
454−instance _constraint Unbox _type where { \
319+instance _constraint Unbox _type where { \
455−; {-# INLINE peekByteIndex #-} \
320+; {-# INLINE peekAt #-} \
456−; peekByteIndex i arr = \
321+; peekAt i arr = \
457− peekByteIndex i arr >>= \
322+ checkBounds "peek" (i + sizeOf (Proxy :: Proxy _type)) arr >> \
323+ peekAt i arr >>= \
458− (\p1 -> peekByteIndex (i + SIZE_OF(_innerType)) arr \
324+ (\p1 -> peekAt (i + SIZE_OF(_innerType)) arr <&> _constructor p1) \
459− <&> _constructor p1) \
325+; {-# INLINE pokeAt #-} \
460−; {-# INLINE pokeByteIndex #-} \
461−; pokeByteIndex i arr (_constructor p1 p2) = \
326+; pokeAt i arr (_constructor p1 p2) = \
462− pokeByteIndex i arr p1 >> \
327+ checkBounds "poke" (i + sizeOf (Proxy :: Proxy _type)) arr >> \
328+ pokeAt i arr p1 >> \
463− pokeByteIndex (i + SIZE_OF(_innerType)) arr p2 \
329+ pokeAt (i + SIZE_OF(_innerType)) arr p2 \
464−; {-# INLINE sizeOf #-} \
330+; {-# INLINE sizeOf #-} \
465−; sizeOf _ = 2 * SIZE_OF(_innerType) \
331+; sizeOf _ = 2 * SIZE_OF(_innerType) \
466}
332}
467
333
468-------------------------------------------------------------------------------
334-------------------------------------------------------------------------------
@@ -582,11 +448,13 @@ DERIVE_BINARY_UNBOX(,Fingerprint,Fingerprint,Word64)
582
448
583instance Unbox () where
449instance Unbox () where
584
450
585− {-# INLINE peekByteIndex #-}
451+ {-# INLINE peekAt #-}
586− peekByteIndex _ _ = return ()
452+ peekAt i arr =
453+ checkBounds "peek ()" (i + sizeOf (Proxy :: Proxy ())) arr >> return ()
587
454
588− {-# INLINE pokeByteIndex #-}
455+ {-# INLINE pokeAt #-}
589− pokeByteIndex _ _ _ = return ()
456+ pokeAt i arr _ =
457+ checkBounds "poke ()" (i + sizeOf (Proxy :: Proxy ())) arr >> return ()
590
458
591 {-# INLINE sizeOf #-}
459 {-# INLINE sizeOf #-}
592 sizeOf _ = 1
460 sizeOf _ = 1
@@ -594,11 +462,17 @@ instance Unbox () where
594#if MIN_VERSION_base(4,15,0)
462#if MIN_VERSION_base(4,15,0)
595instance Unbox IoSubSystem where
463instance Unbox IoSubSystem where
596
464
597− {-# INLINE peekByteIndex #-}
465+ {-# INLINE peekAt #-}
598− peekByteIndex i arr = toEnum <$> peekByteIndex i arr
466+ peekAt i arr =
467+ checkBounds
468+ "peek IoSubSystem" (i + sizeOf (Proxy :: Proxy IoSubSystem)) arr
469+ >> toEnum <$> peekAt i arr
599
470
600− {-# INLINE pokeByteIndex #-}
471+ {-# INLINE pokeAt #-}
472+ pokeAt i arr a =
473+ checkBounds
474+ "poke IoSubSystem" (i + sizeOf (Proxy :: Proxy IoSubSystem)) arr
601− pokeByteIndex i arr a = pokeByteIndex i arr (fromEnum a)
475+ >> pokeAt i arr (fromEnum a)
602
476
603 {-# INLINE sizeOf #-}
477 {-# INLINE sizeOf #-}
604 sizeOf _ = sizeOf (Proxy :: Proxy Int)
478 sizeOf _ = sizeOf (Proxy :: Proxy Int)
@@ -606,16 +480,18 @@ instance Unbox IoSubSystem where
606
480
607instance Unbox Bool where
481instance Unbox Bool where
608
482
609− {-# INLINE peekByteIndex #-}
483+ {-# INLINE peekAt #-}
610− peekByteIndex i arr = do
484+ peekAt i arr = do
485+ checkBounds "peek Bool" (i + sizeOf (Proxy :: Proxy Bool)) arr
611− res <- peekByteIndex i arr
486+ res <- peekAt i arr
612 return $ res /= (0 :: Int8)
487 return $ res /= (0 :: Int8)
613
488
614− {-# INLINE pokeByteIndex #-}
489+ {-# INLINE pokeAt #-}
615− pokeByteIndex i arr a =
490+ pokeAt i arr a =
491+ checkBounds "poke Bool" (i + sizeOf (Proxy :: Proxy Bool)) arr
616− if a
492+ >> if a
617− then pokeByteIndex i arr (1 :: Int8)
493+ then pokeAt i arr (1 :: Int8)
618− else pokeByteIndex i arr (0 :: Int8)
494+ else pokeAt i arr (0 :: Int8)
619
495
620 {-# INLINE sizeOf #-}
496 {-# INLINE sizeOf #-}
621 sizeOf _ = 1
497 sizeOf _ = 1
@@ -630,7 +506,7 @@ instance Unbox Bool where
630-- cheaper to just get the bound using the size of the array whenever needed?
506-- cheaper to just get the bound using the size of the array whenever needed?
631data BoundedPtr =
507data BoundedPtr =
632 BoundedPtr
508 BoundedPtr
633− MutableByteArray -- byte array
509+ MutByteArray -- byte array
634 Int -- current pos
510 Int -- current pos
635 Int -- position after end
511 Int -- position after end
636
512
@@ -658,7 +534,7 @@ readUnsafe = Peeker (Builder step)
658 ++ show next
534 ++ show next
659 ++ " end = " ++ show end
535 ++ " end = " ++ show end
660#endif
536#endif
661− r <- peekByteIndex pos arr
537+ r <- peekAt pos arr
662 return (r, BoundedPtr arr next end)
538 return (r, BoundedPtr arr next end)
663
539
664{-# INLINE read #-}
540{-# INLINE read #-}
@@ -675,7 +551,7 @@ read = Peeker (Builder step)
675 $ error $ "read: reading beyond limit. next = "
551 $ error $ "read: reading beyond limit. next = "
676 ++ show next
552 ++ show next
677 ++ " end = " ++ show end
553 ++ " end = " ++ show end
678− r <- peekByteIndex pos arr
554+ r <- peekAt pos arr
679 return (r, BoundedPtr arr next end)
555 return (r, BoundedPtr arr next end)
680
556
681{-# INLINE skipByte #-}
557{-# INLINE skipByte #-}
@@ -720,7 +596,7 @@ pokeBoundedPtrUnsafe a (BoundedPtr arr pos end) = do
720 ++ show next
596 ++ show next
721 ++ " end = " ++ show end
597 ++ " end = " ++ show end
722#endif
598#endif
723− pokeByteIndex pos arr a
599+ pokeAt pos arr a
724 return (BoundedPtr arr next end)
600 return (BoundedPtr arr next end)
725
601
726{-# INLINE pokeBoundedPtr #-}
602{-# INLINE pokeBoundedPtr #-}
@@ -728,7 +604,7 @@ pokeBoundedPtr :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
728pokeBoundedPtr a (BoundedPtr arr pos end) = do
604pokeBoundedPtr a (BoundedPtr arr pos end) = do
729 let next = pos + sizeOf (Proxy :: Proxy a)
605 let next = pos + sizeOf (Proxy :: Proxy a)
730 when (next > end) $ error "pokeBoundedPtr writing beyond limit"
606 when (next > end) $ error "pokeBoundedPtr writing beyond limit"
731− pokeByteIndex pos arr a
607+ pokeAt pos arr a
732 return (BoundedPtr arr next end)
608 return (BoundedPtr arr next end)
733
609
734--------------------------------------------------------------------------------
610--------------------------------------------------------------------------------
@@ -915,7 +791,7 @@ genericPokeObj a ptr = void $ genericPokeObject a ptr
915
791
916{-# INLINE genericPokeByteIndex #-}
792{-# INLINE genericPokeByteIndex #-}
917genericPokeByteIndex :: (Generic a, PokeRep (Rep a)) =>
793genericPokeByteIndex :: (Generic a, PokeRep (Rep a)) =>
918− MutableByteArray -> Int -> a -> IO ()
794+ MutByteArray -> Int -> a -> IO ()
919genericPokeByteIndex arr index x = do
795genericPokeByteIndex arr index x = do
920 -- XXX Should we use unsafe poke?
796 -- XXX Should we use unsafe poke?
921#ifdef DEBUG
797#ifdef DEBUG
@@ -1021,7 +897,7 @@ genericPeekBoundedPtr = runPeeker genericPeeker
1021
897
1022{-# INLINE genericPeekByteIndex #-}
898{-# INLINE genericPeekByteIndex #-}
1023genericPeekByteIndex :: (Generic a, PeekRep (Rep a)) =>
899genericPeekByteIndex :: (Generic a, PeekRep (Rep a)) =>
1024− MutableByteArray -> Int -> IO a
900+ MutByteArray -> Int -> IO a
1025genericPeekByteIndex arr index = do
901genericPeekByteIndex arr index = do
1026 -- XXX Should we use unsafe peek?
902 -- XXX Should we use unsafe peek?
1027#ifdef DEBUG
903#ifdef DEBUG
core/src/Streamly/Internal/Data/Unbox/TH.hs+74−74
@@ -10,13 +10,11 @@
10--
10--
11module Streamly.Internal.Data.Unbox.TH
11module Streamly.Internal.Data.Unbox.TH
12 ( deriveUnbox
12 ( deriveUnbox
13− , deriveUnboxWith
14
13
15 -- th-helpers
14 -- th-helpers
16 , DataCon(..)
15 , DataCon(..)
17 , DataType(..)
16 , DataType(..)
18 , reifyDataType
17 , reifyDataType
19− , appsT
20 ) where
18 ) where
21
19
22--------------------------------------------------------------------------------
20--------------------------------------------------------------------------------
@@ -25,6 +23,7 @@ module Streamly.Internal.Data.Unbox.TH
25
23
26import Data.Word (Word16, Word32, Word64, Word8)
24import Data.Word (Word16, Word32, Word64, Word8)
27import Data.Proxy (Proxy(..))
25import Data.Proxy (Proxy(..))
26+import Data.List (elemIndex)
28
27
29import Language.Haskell.TH
28import Language.Haskell.TH
30import Language.Haskell.TH.Syntax
29import Language.Haskell.TH.Syntax
@@ -69,10 +68,6 @@ tvName = elimTV id (\n _ -> n)
69tyVarBndrName :: TyVarBndr_ flag -> Name
68tyVarBndrName :: TyVarBndr_ flag -> Name
70tyVarBndrName = tvName
69tyVarBndrName = tvName
71
70
72−appsT :: Type -> [Type] -> Type
73−appsT x [] = x
74−appsT x (y:xs) = appsT (AppT x y) xs
75−
76-- | Simplified info about a 'DataD'. Omits deriving, strictness,
71-- | Simplified info about a 'DataD'. Omits deriving, strictness,
77-- kind info, and whether it's @data@ or @newtype@.
72-- kind info, and whether it's @data@ or @newtype@.
78data DataType = DataType
73data DataType = DataType
@@ -246,6 +241,7 @@ mkSizeOfExpr headTy constructors =
246mkPeekExprOne :: Int -> DataCon -> Q Exp
241mkPeekExprOne :: Int -> DataCon -> Q Exp
247mkPeekExprOne tagSize (DataCon cname _ _ fields) =
242mkPeekExprOne tagSize (DataCon cname _ _ fields) =
248 case fields of
243 case fields of
244+ -- XXX Should we peek and check if the byte value is 0?
249 [] -> [|pure $(conE cname)|]
245 [] -> [|pure $(conE cname)|]
250 _ ->
246 _ ->
251 letE
247 letE
@@ -257,7 +253,7 @@ mkPeekExprOne tagSize (DataCon cname _ _ fields) =
257
253
258 where
254 where
259
255
260− peekField i = [|peekByteIndex $(varE (mkOffsetName i)) $(varE _arr)|]
256+ peekField i = [|peekAt $(varE (mkOffsetName i)) $(varE _arr)|]
261
257
262mkPeekExpr :: Type -> [DataCon] -> Q Exp
258mkPeekExpr :: Type -> [DataCon] -> Q Exp
263mkPeekExpr headTy cons =
259mkPeekExpr headTy cons =
@@ -271,7 +267,7 @@ mkPeekExpr headTy cons =
271 doE
267 doE
272 [ bindS
268 [ bindS
273 (varP _tag)
269 (varP _tag)
274− [|peekByteIndex $(varE _initialOffset) $(varE _arr)|]
270+ [|peekAt $(varE _initialOffset) $(varE _arr)|]
275 , noBindS
271 , noBindS
276 (caseE
272 (caseE
277 (sigE (varE _tag) (conT tagType))
273 (sigE (varE _tag) (conT tagType))
@@ -304,7 +300,7 @@ mkPokeExprTag tagType tagVal = pokeTag
304 where
300 where
305
301
306 pokeTag =
302 pokeTag =
307− [|pokeByteIndex
303+ [|pokeAt
308 $(varE _initialOffset)
304 $(varE _initialOffset)
309 $(varE _arr)
305 $(varE _arr)
310 $((sigE (litE (IntegerL (fromIntegral tagVal))) (conT tagType)))|]
306 $((sigE (litE (IntegerL (fromIntegral tagVal))) (conT tagType)))|]
@@ -322,7 +318,7 @@ mkPokeExprFields tagSize fields = do
322
318
323 numFields = length fields
319 numFields = length fields
324 pokeField i =
320 pokeField i =
325− [|pokeByteIndex
321+ [|pokeAt
326 $(varE (mkOffsetName i))
322 $(varE (mkOffsetName i))
327 $(varE _arr)
323 $(varE _arr)
328 $(varE (mkFieldName i))|]
324 $(varE (mkFieldName i))|]
@@ -341,7 +337,9 @@ mkPokeExpr headTy cons =
341 [|error
337 [|error
342 ("Attempting to poke type with no constructors (" ++
338 ("Attempting to poke type with no constructors (" ++
343 $(lift (pprint headTy)) ++ ")")|]
339 $(lift (pprint headTy)) ++ ")")|]
340+ -- XXX We don't gaurentee encoded equivalilty for Unbox. Does it still
341+ -- make sense to encode a default value for unit constructor?
344− [(DataCon _ _ _ [])] -> [|pure ()|]
342+ [(DataCon _ _ _ [])] -> [|pure ()|] -- mkPokeExprTag ''Word8 0
345 [(DataCon cname _ _ fields)] ->
343 [(DataCon cname _ _ fields)] ->
346 caseE
344 caseE
347 (varE _val)
345 (varE _val)
@@ -397,8 +395,8 @@ mkPokeExpr headTy cons =
397-- [(Nothing, (ConT ''Bool)), (Nothing, (VarT (mkName "b")))]
395-- [(Nothing, (ConT ''Bool)), (Nothing, (VarT (mkName "b")))]
398-- ])
396-- ])
399-- @
397-- @
400−deriveUnboxInternal :: Cxt -> Type -> [DataCon] -> Q [Dec]
398+deriveUnboxInternal :: Type -> [DataCon] -> ([Dec] -> Q [Dec]) -> Q [Dec]
401−deriveUnboxInternal preds headTy cons = do
399+deriveUnboxInternal headTy cons mkDec = do
402 sizeOfMethod <- mkSizeOfExpr headTy cons
400 sizeOfMethod <- mkSizeOfExpr headTy cons
403 peekMethod <- mkPeekExpr headTy cons
401 peekMethod <- mkPeekExpr headTy cons
404 pokeMethod <- mkPokeExpr headTy cons
402 pokeMethod <- mkPokeExpr headTy cons
@@ -407,9 +405,9 @@ deriveUnboxInternal preds headTy cons = do
407 -- none
405 -- none
408 [ -- PragmaD (InlineP 'sizeOf Inline FunLike AllPhases)
406 [ -- PragmaD (InlineP 'sizeOf Inline FunLike AllPhases)
409 FunD 'sizeOf [Clause [WildP] (NormalB sizeOfMethod) []]
407 FunD 'sizeOf [Clause [WildP] (NormalB sizeOfMethod) []]
410− , PragmaD (InlineP 'peekByteIndex Inline FunLike AllPhases)
408+ , PragmaD (InlineP 'peekAt Inline FunLike AllPhases)
411 , FunD
409 , FunD
412− 'peekByteIndex
410+ 'peekAt
413 [ Clause
411 [ Clause
414 (if isUnitType cons
412 (if isUnitType cons
415 then [WildP, WildP]
413 then [WildP, WildP]
@@ -417,9 +415,9 @@ deriveUnboxInternal preds headTy cons = do
417 (NormalB peekMethod)
415 (NormalB peekMethod)
418 []
416 []
419 ]
417 ]
420− , PragmaD (InlineP 'pokeByteIndex Inline FunLike AllPhases)
418+ , PragmaD (InlineP 'pokeAt Inline FunLike AllPhases)
421 , FunD
419 , FunD
422− 'pokeByteIndex
420+ 'pokeAt
423 [ Clause
421 [ Clause
424 (if isUnitType cons
422 (if isUnitType cons
425 then [WildP, WildP, WildP]
423 then [WildP, WildP, WildP]
@@ -428,71 +426,73 @@ deriveUnboxInternal preds headTy cons = do
428 []
426 []
429 ]
427 ]
430 ]
428 ]
431− return [InstanceD Nothing preds (AppT (ConT ''Unbox) headTy) methods]
429+ mkDec methods
432
430
433−-- | Template haskell helper to create instances of 'Unbox' automatically.
431+-- | Given an 'Unbox' instance declaration splice without the methods (e.g.
434−--
432+-- @[d|instance Unbox a => Unbox (Maybe a)|]@), generate an instance
435−-- Consider the datatype:
433+-- declaration including all the type class method implementations.
436−-- @
437−-- data CustomDataType a b c = ...
438−-- @
439--
434--
440−-- Usage: @$(deriveUnbox ''CustomDataType)@
435+-- Usage:
441--
436--
442−-- Note: All type variables automatcally get an "Unbox" constraint.
443−-- The derived code will look like the following,
444-- @
437-- @
445−-- instance (Unbox a, Unbox b, Unbox c) => Unbox (CustomDataType a b c) where
438+-- \$(deriveUnbox [d|instance Unbox a => Unbox (Maybe a)|])
446−-- ...
447-- @
439-- @
448−--
449−-- To control which type variables get the Unbox constraint, use
450−-- 'deriveUnboxWith'.
451−deriveUnbox :: Name -> Q [Dec]
440+deriveUnbox :: Q [Dec] -> Q [Dec]
452−deriveUnbox name = do
441+deriveUnbox mDecs = do
442+ dec <- mDecs
443+ case dec of
444+ [InstanceD mo preds headTyWC []] -> do
445+ let headTy = unwrap dec headTyWC
446+ (mainTyName, subs) = getMainTypeName dec headTy
453− dt <- reifyDataType name
447+ dt <- reifyDataType mainTyName
454− let preds = map (unboxPred . VarT) (dtTvs dt)
448+ let tyVars = dtTvs dt
455− headTy = appsT (ConT name) (map VarT (dtTvs dt))
449+ mapper = mapperWith (VarT <$> tyVars) subs
456− cons = dtCons dt
450+ cons = map (modifyConVariables mapper) (dtCons dt)
457− deriveUnboxInternal preds headTy cons
451+ deriveUnboxInternal headTy cons (mkInst mo preds headTyWC)
452+ _ -> errorMessage dec
458
453
459 where
454 where
460
455
461− unboxPred ty =
456+ mapperWith l1 l2 a =
462−#if MIN_VERSION_template_haskell(2,10,0)
457+ case elemIndex a l1 of
463− AppT (ConT ''Unbox) ty
458+ Nothing -> a
464−#else
459+ -- XXX Capture this case and give a relavant error.
465− ClassP ''Unbox [ty]
460+ Just i -> l2 !! i
466−#endif
461+
462+ mapType f (AppT t1 t2) = AppT (mapType f t1) (mapType f t2)
463+ mapType f (InfixT t1 n t2) = InfixT (mapType f t1) n (mapType f t2)
464+ mapType f (UInfixT t1 n t2) = UInfixT (mapType f t1) n (mapType f t2)
465+ mapType f (ParensT t) = ParensT (mapType f t)
466+ mapType f v = f v
467+
468+ modifyConVariables f con =
469+ con { dcFields = map (\(a, b) -> (a, mapType f b)) (dcFields con) }
470+
471+ mkInst mo preds headTyWC methods =
472+ pure [InstanceD mo preds headTyWC methods]
473+
474+ errorMessage dec =
475+ error $ unlines
476+ [ "Error: deriveUnbox:"
477+ , ""
478+ , ">> " ++ pprint dec
479+ , ""
480+ , "The supplied declaration not a valid instance declaration."
481+ , "Provide a valid Haskell instance declaration without a body."
482+ , ""
483+ , "Examples:"
484+ , "instance Unbox (Proxy a)"
485+ , "instance Unbox a => Unbox (Identity a)"
486+ , "instance Unbox (TableT Identity)"
487+ ]
467
488
468−-- | Like 'deriveUnbox' but control which type variables get the 'Unbox'
489+ unwrap _ (AppT (ConT _) r) = r
469−-- constraint.
490+ unwrap dec _ = errorMessage dec
470−--
471−-- Consider the datatype:
472−-- @
473−-- data CustomDataType a b c = ...
474−-- @
475−--
476−-- Usage: @$(deriveUnboxWith ["a", "c"] ''CustomDataType)@
477−--
478−-- @
479−-- instance (Unbox a, Unbox c) => Unbox (CustomDataType a b c) where
480−-- ...
481−-- @
482−--
483−deriveUnboxWith :: [String] -> Name -> Q [Dec]
484−deriveUnboxWith vars name = do
485− dt <- reifyDataType name
486− let preds = map (unboxPred . VarT) (fmap mkName vars)
487− headTy = appsT (ConT name) (map VarT (dtTvs dt))
488− cons = dtCons dt
489− deriveUnboxInternal preds headTy cons
490
491
491− where
492+ getMainTypeName dec = go []
492
493
493− unboxPred ty =
494+ where
494−#if MIN_VERSION_template_haskell(2,10,0)
495+
495− AppT (ConT ''Unbox) ty
496+ go xs (ConT nm) = (nm, xs)
496−#else
497+ go xs (AppT l r) = go (r:xs) l
497− ClassP ''Unbox [ty]
498+ go _ _ = errorMessage dec
498−#endif
core/src/Streamly/Internal/Data/Unfold.hs+15−13
@@ -82,7 +82,7 @@ module Streamly.Internal.Data.Unfold
82 , dropWhileM
82 , dropWhileM
83
83
84 -- ** Cross product
84 -- ** Cross product
85− , joinInnerGeneric
85+ , innerJoin
86
86
87 -- ** Resource Management
87 -- ** Resource Management
88 -- | 'bracket' is the most general resource management operation, all other
88 -- | 'bracket' is the most general resource management operation, all other
@@ -205,7 +205,7 @@ swap = lmap Tuple.swap
205--
205--
206{-# INLINE_NORMAL fold #-}
206{-# INLINE_NORMAL fold #-}
207fold :: Monad m => Fold m b c -> Unfold m a b -> a -> m c
207fold :: Monad m => Fold m b c -> Unfold m a b -> a -> m c
208−fold (Fold fstep initial extract) (Unfold ustep inject) a = do
208+fold (Fold fstep initial _ final) (Unfold ustep inject) a = do
209 res <- initial
209 res <- initial
210 case res of
210 case res of
211 FL.Partial x -> inject a >>= go SPEC x
211 FL.Partial x -> inject a >>= go SPEC x
@@ -223,7 +223,7 @@ fold (Fold fstep initial extract) (Unfold ustep inject) a = do
223 FL.Partial fs1 -> go SPEC fs1 s
223 FL.Partial fs1 -> go SPEC fs1 s
224 FL.Done c -> return c
224 FL.Done c -> return c
225 Skip s -> go SPEC fs s
225 Skip s -> go SPEC fs s
226− Stop -> extract fs
226+ Stop -> final fs
227
227
228-- {-# ANN type FoldMany Fuse #-}
228-- {-# ANN type FoldMany Fuse #-}
229data FoldMany s fs b a
229data FoldMany s fs b a
@@ -238,7 +238,7 @@ data FoldMany s fs b a
238-- /Pre-release/
238-- /Pre-release/
239{-# INLINE_NORMAL foldMany #-}
239{-# INLINE_NORMAL foldMany #-}
240foldMany :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c
240foldMany :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c
241−foldMany (Fold fstep initial extract) (Unfold ustep inject1) =
241+foldMany (Fold fstep initial _ final) (Unfold ustep inject1) =
242 Unfold step inject
242 Unfold step inject
243
243
244 where
244 where
@@ -269,14 +269,14 @@ foldMany (Fold fstep initial extract) (Unfold ustep inject1) =
269 case r of
269 case r of
270 Yield x s -> consume x s fs
270 Yield x s -> consume x s fs
271 Skip s -> return $ Skip (FoldManyFirst fs s)
271 Skip s -> return $ Skip (FoldManyFirst fs s)
272− Stop -> return Stop
272+ Stop -> final fs >> return Stop
273 step (FoldManyLoop st fs) = do
273 step (FoldManyLoop st fs) = do
274 r <- ustep st
274 r <- ustep st
275 case r of
275 case r of
276 Yield x s -> consume x s fs
276 Yield x s -> consume x s fs
277 Skip s -> return $ Skip (FoldManyLoop s fs)
277 Skip s -> return $ Skip (FoldManyLoop s fs)
278 Stop -> do
278 Stop -> do
279− b <- extract fs
279+ b <- final fs
280 return $ Skip (FoldManyYield b FoldManyDone)
280 return $ Skip (FoldManyYield b FoldManyDone)
281 step (FoldManyYield b next) = return $ Yield b next
281 step (FoldManyYield b next) = return $ Yield b next
282 step FoldManyDone = return Stop
282 step FoldManyDone = return Stop
@@ -317,7 +317,7 @@ either (Unfold stepL injectL) (Unfold stepR injectR) = Unfold step inject
317-- /Pre-release/
317-- /Pre-release/
318{-# INLINE_NORMAL postscan #-}
318{-# INLINE_NORMAL postscan #-}
319postscan :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c
319postscan :: Monad m => Fold m b c -> Unfold m a b -> Unfold m a c
320−postscan (Fold stepF initial extract) (Unfold stepU injectU) =
320+postscan (Fold stepF initial extract final) (Unfold stepU injectU) =
321 Unfold step inject
321 Unfold step inject
322
322
323 where
323 where
@@ -340,7 +340,7 @@ postscan (Fold stepF initial extract) (Unfold stepU injectU) =
340 v <- extract fs1
340 v <- extract fs1
341 return $ Yield v (Just (fs1, s))
341 return $ Yield v (Just (fs1, s))
342 Skip s -> return $ Skip (Just (fs, s))
342 Skip s -> return $ Skip (Just (fs, s))
343− Stop -> return Stop
343+ Stop -> final fs >> return Stop
344
344
345 step Nothing = return Stop
345 step Nothing = return Stop
346
346
@@ -348,7 +348,7 @@ data ScanState s f = ScanInit s | ScanDo s !f | ScanDone
348
348
349{-# INLINE_NORMAL scanWith #-}
349{-# INLINE_NORMAL scanWith #-}
350scanWith :: Monad m => Bool -> Fold m b c -> Unfold m a b -> Unfold m a c
350scanWith :: Monad m => Bool -> Fold m b c -> Unfold m a b -> Unfold m a c
351−scanWith restart (Fold fstep initial extract) (Unfold stepU injectU) =
351+scanWith restart (Fold fstep initial extract final) (Unfold stepU injectU) =
352 Unfold step inject
352 Unfold step inject
353
353
354 where
354 where
@@ -373,7 +373,7 @@ scanWith restart (Fold fstep initial extract) (Unfold stepU injectU) =
373 case res of
373 case res of
374 Yield x s -> runStep s (fstep fs x)
374 Yield x s -> runStep s (fstep fs x)
375 Skip s -> return $ Skip $ ScanDo s fs
375 Skip s -> return $ Skip $ ScanDo s fs
376− Stop -> return Stop
376+ Stop -> final fs >> return Stop
377 step ScanDone = return Stop
377 step ScanDone = return Stop
378
378
379-- | Scan the output of an 'Unfold' to change it in a stateful manner.
379-- | Scan the output of an 'Unfold' to change it in a stateful manner.
@@ -677,10 +677,12 @@ dropWhileM f (Unfold step inject) = Unfold step' inject'
677dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
677dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
678dropWhile f = dropWhileM (return . f)
678dropWhile f = dropWhileM (return . f)
679
679
680+-- | Cross intersection of two unfolds. See
681+-- 'Streamly.Internal.Data.Stream.innerJoin' for more details.
680−{-# INLINE_NORMAL joinInnerGeneric #-}
682+{-# INLINE_NORMAL innerJoin #-}
681−joinInnerGeneric :: Monad m =>
683+innerJoin :: Monad m =>
682 (b -> c -> Bool) -> Unfold m a b -> Unfold m a c -> Unfold m a (b, c)
684 (b -> c -> Bool) -> Unfold m a b -> Unfold m a c -> Unfold m a (b, c)
683−joinInnerGeneric eq s1 s2 = filter (\(a, b) -> a `eq` b) $ cross s1 s2
685+innerJoin eq s1 s2 = filter (\(a, b) -> a `eq` b) $ cross s1 s2
684
686
685------------------------------------------------------------------------------
687------------------------------------------------------------------------------
686-- Exceptions
688-- Exceptions
core/src/Streamly/Internal/FileSystem/File.hs+11−13
@@ -103,15 +103,14 @@ import qualified Control.Monad.Catch as MC
103import qualified System.IO as SIO
103import qualified System.IO as SIO
104
104
105import Streamly.Data.Fold (groupsOf, drain)
105import Streamly.Data.Fold (groupsOf, drain)
106−import Streamly.Internal.Data.Array.Type (Array(..), pinnedWriteNUnsafe)
106+import Streamly.Internal.Data.Array.Type (Array(..))
107import Streamly.Internal.Data.Fold.Type (Fold(..))
107import Streamly.Internal.Data.Fold.Type (Fold(..))
108import Streamly.Data.Stream (Stream)
108import Streamly.Data.Stream (Stream)
109−import Streamly.Internal.Data.Unbox (Unbox)
110import Streamly.Internal.Data.Unfold.Type (Unfold(..))
109import Streamly.Internal.Data.Unfold.Type (Unfold(..))
111-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
110-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
112import Streamly.Internal.System.IO (defaultChunkSize)
111import Streamly.Internal.System.IO (defaultChunkSize)
113
112
114−import qualified Streamly.Data.Array as A
113+import qualified Streamly.Internal.Data.Array as A
115import qualified Streamly.Data.Stream as S
114import qualified Streamly.Data.Stream as S
116import qualified Streamly.Data.Unfold as UF
115import qualified Streamly.Data.Unfold as UF
117import qualified Streamly.Internal.Data.Array.Type as IA (pinnedChunksOf)
116import qualified Streamly.Internal.Data.Array.Type as IA (pinnedChunksOf)
@@ -339,10 +338,6 @@ readWithBufferOf = readerWith
339reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
338reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
340reader = UF.many A.reader (usingFile FH.chunkReader)
339reader = UF.many A.reader (usingFile FH.chunkReader)
341
340
342−{-# INLINE concatChunks #-}
343−concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
344−concatChunks = S.unfoldMany A.reader
345−
346-- | Generate a stream of bytes from a file specified by path. The stream ends
341-- | Generate a stream of bytes from a file specified by path. The stream ends
347-- when EOF is encountered. File is locked using multiple reader and single
342-- when EOF is encountered. File is locked using multiple reader and single
348-- writer locking mode.
343-- writer locking mode.
@@ -351,7 +346,7 @@ concatChunks = S.unfoldMany A.reader
351--
346--
352{-# INLINE read #-}
347{-# INLINE read #-}
353read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
348read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
354−read file = concatChunks $ withFile file ReadMode FH.readChunks
349+read file = A.concat $ withFile file ReadMode FH.readChunks
355
350
356{-# DEPRECATED toBytes "Please use 'read' instead" #-}
351{-# DEPRECATED toBytes "Please use 'read' instead" #-}
357{-# INLINE toBytes #-}
352{-# INLINE toBytes #-}
@@ -438,7 +433,7 @@ write = toHandleWith A.defaultChunkSize
438{-# INLINE writeChunks #-}
433{-# INLINE writeChunks #-}
439writeChunks :: (MonadIO m, MonadCatch m)
434writeChunks :: (MonadIO m, MonadCatch m)
440 => FilePath -> Fold m (Array a) ()
435 => FilePath -> Fold m (Array a) ()
441−writeChunks path = Fold step initial extract
436+writeChunks path = Fold step initial extract final
442 where
437 where
443 initial = do
438 initial = do
444 h <- liftIO (openFile path WriteMode)
439 h <- liftIO (openFile path WriteMode)
@@ -448,12 +443,15 @@ writeChunks path = Fold step initial extract
448 step (fld, h) x = do
443 step (fld, h) x = do
449 r <- FL.snoc fld x `MC.onException` liftIO (hClose h)
444 r <- FL.snoc fld x `MC.onException` liftIO (hClose h)
450 return $ FL.Partial (r, h)
445 return $ FL.Partial (r, h)
446+
447+ extract _ = return ()
448+
451− extract (Fold _ initial1 extract1, h) = do
449+ final (Fold _ initial1 _ final1, h) = do
452 liftIO $ hClose h
450 liftIO $ hClose h
453 res <- initial1
451 res <- initial1
454 case res of
452 case res of
455− FL.Partial fs -> extract1 fs
453+ FL.Partial fs -> final1 fs
456− FL.Done fb -> return fb
454+ FL.Done () -> return ()
457
455
458-- | @writeWith chunkSize handle@ writes the input stream to @handle@.
456-- | @writeWith chunkSize handle@ writes the input stream to @handle@.
459-- Bytes in the input stream are collected into a buffer until we have a chunk
457-- Bytes in the input stream are collected into a buffer until we have a chunk
@@ -464,7 +462,7 @@ writeChunks path = Fold step initial extract
464writeWith :: (MonadIO m, MonadCatch m)
462writeWith :: (MonadIO m, MonadCatch m)
465 => Int -> FilePath -> Fold m Word8 ()
463 => Int -> FilePath -> Fold m Word8 ()
466writeWith n path =
464writeWith n path =
467− groupsOf n (pinnedWriteNUnsafe n) (writeChunks path)
465+ groupsOf n (A.unsafePinnedCreateOf n) (writeChunks path)
468
466
469{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
467{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
470{-# INLINE writeWithBufferOf #-}
468{-# INLINE writeWithBufferOf #-}
core/src/Streamly/Internal/FileSystem/Handle.hs+21−28

This diff is too big to show here.

core/src/Streamly/Internal/FileSystem/Path.hsnew file+515

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+39−11

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+83−35

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+25−2

This diff is too big to show here.

docs/User/Project/ApiChangelogs/0.9.0-0.10.0.txtnew file+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+25−10

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

src/Streamly.hsdeleted−625

This diff is too big to show here.

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

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.hsdeleted−194

This diff is too big to show here.

src/Streamly/Data/Stream/Exception.hsdeleted−25

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

src/Streamly/Data/Stream/Time.hsdeleted−37

This diff is too big to show here.

src/Streamly/Data/Unicode/Stream.hsdeleted−99

This diff is too big to show here.

src/Streamly/Internal/Data/Array/ArrayMacros.hdeleted−40

This diff is too big to show here.

src/Streamly/Internal/Data/Channel.hsnew file+19

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

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.hsnew file+19

This diff is too big to show here.

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

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.

core/src/Streamly/Internal/Data/Stream/Common.hs → src/Streamly/Internal/Data/Stream/Common.hsrenamed+3−3

This diff is too big to show here.

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

This diff is too big to show here.

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

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/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/Exception/Lifted.hs → src/Streamly/Internal/Data/Stream/Lifted.hsrenamed+2−2

This diff is too big to show here.

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

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Prelude.hsnew file+19

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/SVar.hsnew file+18

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+37

This diff is too big to show here.

src/Streamly/Internal/Data/Stream/Zip/Concurrent.hsdeleted−50

This diff is too big to show here.

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

This diff is too big to show here.

src/Streamly/Internal/Data/Unfold/Prelude.hsnew file+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+7−8

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

src/Streamly/Memory/Array.hsdeleted−74

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

streamly.cabal+69−56

This diff is too big to show here.

targets/Targets.hs+4−1

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+7−6

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+8−6

This diff is too big to show here.

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

This diff is too big to show here.

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

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+47−50

This diff is too big to show here.

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

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−3

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+1−1

This diff is too big to show here.

test/streamly-tests.cabal+8−7

This diff is too big to show here.