mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2026-03-17 15:31:05 -04:00
Merge branch 'master' into stable for 0.10
This commit is contained in:
commit
e268f2d10c
48 changed files with 2692 additions and 146 deletions
2
.merlin
2
.merlin
|
|
@ -9,7 +9,6 @@ S src/threads/
|
||||||
S src/misc
|
S src/misc
|
||||||
S src/string
|
S src/string
|
||||||
S src/bigarray
|
S src/bigarray
|
||||||
S src/pervasives
|
|
||||||
S benchs
|
S benchs
|
||||||
S examples
|
S examples
|
||||||
S tests
|
S tests
|
||||||
|
|
@ -24,7 +23,6 @@ B _build/src/threads/
|
||||||
B _build/src/misc
|
B _build/src/misc
|
||||||
B _build/src/string
|
B _build/src/string
|
||||||
B _build/src/bigarray
|
B _build/src/bigarray
|
||||||
B _build/src/pervasives
|
|
||||||
B _build/benchs
|
B _build/benchs
|
||||||
B _build/examples
|
B _build/examples
|
||||||
B _build/tests
|
B _build/tests
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
#use "topfind";;
|
#use "topfind";;
|
||||||
#thread
|
#thread
|
||||||
#require "bigarray";;
|
#require "bigarray";;
|
||||||
|
#require "unix";;
|
||||||
#directory "_build/src/core";;
|
#directory "_build/src/core";;
|
||||||
#directory "_build/src/misc";;
|
#directory "_build/src/misc";;
|
||||||
#directory "_build/src/pervasives/";;
|
#directory "_build/src/pervasives/";;
|
||||||
#directory "_build/src/string";;
|
#directory "_build/src/string";;
|
||||||
#directory "_build/src/io";;
|
#directory "_build/src/io";;
|
||||||
|
#directory "_build/src/unix";;
|
||||||
#directory "_build/src/iter";;
|
#directory "_build/src/iter";;
|
||||||
#directory "_build/src/data";;
|
#directory "_build/src/data";;
|
||||||
#directory "_build/src/sexp";;
|
#directory "_build/src/sexp";;
|
||||||
|
|
@ -16,6 +18,7 @@
|
||||||
#load "containers_iter.cma";;
|
#load "containers_iter.cma";;
|
||||||
#load "containers_data.cma";;
|
#load "containers_data.cma";;
|
||||||
#load "containers_io.cma";;
|
#load "containers_io.cma";;
|
||||||
|
#load "containers_unix.cma";;
|
||||||
#load "containers_sexp.cma";;
|
#load "containers_sexp.cma";;
|
||||||
#load "containers_string.cma";;
|
#load "containers_string.cma";;
|
||||||
#load "containers_pervasives.cma";;
|
#load "containers_pervasives.cma";;
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,4 @@
|
||||||
- Bernardo da Costa
|
- Bernardo da Costa
|
||||||
- Vincent Bernardoff (vbmithr)
|
- Vincent Bernardoff (vbmithr)
|
||||||
- Emmanuel Surleau (emm)
|
- Emmanuel Surleau (emm)
|
||||||
|
- Guillaume Bury (guigui)
|
||||||
|
|
|
||||||
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -1,5 +1,20 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.10
|
||||||
|
|
||||||
|
- add `containers_misc.Puf.iter`
|
||||||
|
- add `CCString.{lines,unlines,concat_gen}`
|
||||||
|
- `CCUnix` (with a small subprocess API)
|
||||||
|
- add `CCList.{sorted_merge_uniq, uniq_succ}`
|
||||||
|
- breaking: fix documentation of `CCList.sorted_merge` (different semantics)
|
||||||
|
- `CCPersistentArray` (credit to @gbury and Jean-Christophe Filliâtre)
|
||||||
|
- `CCIntMap` (big-endian patricia trees) in containers.data
|
||||||
|
- bugfix in `CCFQueue.add_seq_front`
|
||||||
|
- add `CCFQueue.{rev, --}`
|
||||||
|
- add `App_parse` in `containers_string`, experimental applicative parser combinators
|
||||||
|
- remove `containers.pervasives`, add the module `Containers` to core
|
||||||
|
- bugfix in `CCFormat.to_file`
|
||||||
|
|
||||||
## 0.9
|
## 0.9
|
||||||
|
|
||||||
- add `Float`, `Ref`, `Set`, `Format` to `CCPervasives`
|
- add `Float`, `Ref`, `Set`, `Format` to `CCPervasives`
|
||||||
|
|
@ -178,7 +193,7 @@
|
||||||
- renamed threads/future to threads/CCFuture
|
- renamed threads/future to threads/CCFuture
|
||||||
- big upgrade of `RAL` (random access lists)
|
- big upgrade of `RAL` (random access lists)
|
||||||
- `CCList.Ref` to help use references on lists
|
- `CCList.Ref` to help use references on lists
|
||||||
- `CCKList`: group,uniq,sort,sort_uniq,repeat and cycle, infix ops, applicative,product
|
- `CCKList`: `group,uniq,sort,sort_uniq,repeat` and `cycle`, infix ops, applicative,product
|
||||||
- `CCTrie.above/below`: ranges of items
|
- `CCTrie.above/below`: ranges of items
|
||||||
- more functions in `CCPair`
|
- more functions in `CCPair`
|
||||||
- `CCCat`: funny (though useless) definitions inspired from Haskell
|
- `CCCat`: funny (though useless) definitions inspired from Haskell
|
||||||
|
|
@ -192,7 +207,7 @@
|
||||||
- conversions for `CCString`
|
- conversions for `CCString`
|
||||||
- `CCHashtbl`: open-addressing table (Robin-Hood hashing)
|
- `CCHashtbl`: open-addressing table (Robin-Hood hashing)
|
||||||
- registered printers for `CCError`.guard,wrap1,etc.
|
- registered printers for `CCError`.guard,wrap1,etc.
|
||||||
- monadic operator in `CCList`: map_m_par
|
- monadic operator in `CCList`: `map_m_par`
|
||||||
- simple interface to `PrintBox` now more powerful
|
- simple interface to `PrintBox` now more powerful
|
||||||
- constructors for 1 or 2 elements fqueues
|
- constructors for 1 or 2 elements fqueues
|
||||||
- bugfixes in BTree (insertion should work now)
|
- bugfixes in BTree (insertion should work now)
|
||||||
|
|
@ -206,7 +221,7 @@
|
||||||
- `CCopt.pure`
|
- `CCopt.pure`
|
||||||
- updated `CCPersistentHashtbl` with new functions; updated doc, simplified code
|
- updated `CCPersistentHashtbl` with new functions; updated doc, simplified code
|
||||||
- move `CCString` into core/, since it deals with a basic type; also add some features to `CCString` (Sub and Split modules to deal with slices and splitting by a string)
|
- move `CCString` into core/, since it deals with a basic type; also add some features to `CCString` (Sub and Split modules to deal with slices and splitting by a string)
|
||||||
- `CCArray.blit`, .Sub.to_slice; some bugfixes
|
- `CCArray.blit`, `.Sub.to_slice`; some bugfixes
|
||||||
- applicative and lifting operators for `CCError`
|
- applicative and lifting operators for `CCError`
|
||||||
- `CCError.map2`
|
- `CCError.map2`
|
||||||
- more combinators in `CCError`
|
- more combinators in `CCError`
|
||||||
|
|
@ -219,9 +234,9 @@
|
||||||
- `CCOpt.sequence_l`
|
- `CCOpt.sequence_l`
|
||||||
- mplus instance for `CCOpt`
|
- mplus instance for `CCOpt`
|
||||||
- monad instance for `CCFun`
|
- monad instance for `CCFun`
|
||||||
- updated description in _oasis
|
- updated description in `_oasis`
|
||||||
- `CCTrie`, a compressed functorial persistent trie structure
|
- `CCTrie`, a compressed functorial persistent trie structure
|
||||||
- fix `CCPrint.unit`, add `CCPrint.silent`
|
- fix `CCPrint.unit`, add `CCPrint.silent`
|
||||||
- fix type mismatch
|
- fix type mismatch
|
||||||
|
|
||||||
note: git log --no-merges previous_version..HEAD --pretty=%s
|
note: `git log --no-merges previous_version..HEAD --pretty=%s`
|
||||||
|
|
|
||||||
2
HOWTO.md
2
HOWTO.md
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
## Make a release
|
## Make a release
|
||||||
|
|
||||||
1. `make test-all`
|
1. `make test`
|
||||||
2. update version in `_oasis`
|
2. update version in `_oasis`
|
||||||
3. `make update_next_tag` (to update `@since` comments; be careful not to change symlinks)
|
3. `make update_next_tag` (to update `@since` comments; be careful not to change symlinks)
|
||||||
4. update `CHANGELOG.md` (see its end to find the right git command)
|
4. update `CHANGELOG.md` (see its end to find the right git command)
|
||||||
|
|
|
||||||
2
Makefile
2
Makefile
|
|
@ -60,6 +60,8 @@ QTESTABLE=$(filter-out $(DONTTEST), \
|
||||||
$(wildcard src/string/*.mli) \
|
$(wildcard src/string/*.mli) \
|
||||||
$(wildcard src/io/*.ml) \
|
$(wildcard src/io/*.ml) \
|
||||||
$(wildcard src/io/*.mli) \
|
$(wildcard src/io/*.mli) \
|
||||||
|
$(wildcard src/unix/*.ml) \
|
||||||
|
$(wildcard src/unix/*.mli) \
|
||||||
$(wildcard src/sexp/*.ml) \
|
$(wildcard src/sexp/*.ml) \
|
||||||
$(wildcard src/sexp/*.mli) \
|
$(wildcard src/sexp/*.mli) \
|
||||||
$(wildcard src/advanced/*.ml) \
|
$(wildcard src/advanced/*.ml) \
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -10,7 +10,10 @@ What is _containers_?
|
||||||
are totally independent and are prefixed with `CC` (for "containers-core"
|
are totally independent and are prefixed with `CC` (for "containers-core"
|
||||||
or "companion-cube" because I'm megalomaniac). This part should be
|
or "companion-cube" because I'm megalomaniac). This part should be
|
||||||
usable and should work. For instance, `CCList` contains functions and
|
usable and should work. For instance, `CCList` contains functions and
|
||||||
lists including safe versions of `map` and `append`.
|
lists including safe versions of `map` and `append`. It also
|
||||||
|
provides a drop-in replacement to the standard library, in the module
|
||||||
|
`Containers` (intended to be opened, replaces some stdlib modules
|
||||||
|
with extended ones)
|
||||||
- Several small additional libraries that complement it:
|
- Several small additional libraries that complement it:
|
||||||
* `containers.data` with additional data structures that don't have an
|
* `containers.data` with additional data structures that don't have an
|
||||||
equivalent in the standard library;
|
equivalent in the standard library;
|
||||||
|
|
@ -21,9 +24,6 @@ What is _containers_?
|
||||||
KMP search algorithm, and a few naive utils). Again, modules are independent
|
KMP search algorithm, and a few naive utils). Again, modules are independent
|
||||||
and sometimes parametric on the string and char types (so they should
|
and sometimes parametric on the string and char types (so they should
|
||||||
be able to deal with your favorite unicode library).
|
be able to deal with your favorite unicode library).
|
||||||
- A drop-in replacement to the standard library, `containers.pervasives`,
|
|
||||||
that defined a `CCPervasives` module intented to be opened to extend some
|
|
||||||
modules of the stdlib.
|
|
||||||
- A sub-library with complicated abstractions, `containers.advanced` (with
|
- A sub-library with complicated abstractions, `containers.advanced` (with
|
||||||
a LINQ-like query module, batch operations using GADTs, and others).
|
a LINQ-like query module, batch operations using GADTs, and others).
|
||||||
- A library using [Lwt](https://github.com/ocsigen/lwt/), `containers.lwt`.
|
- A library using [Lwt](https://github.com/ocsigen/lwt/), `containers.lwt`.
|
||||||
|
|
@ -45,7 +45,7 @@ See [this file](https://github.com/c-cube/ocaml-containers/blob/master/CHANGELOG
|
||||||
## Finding help
|
## Finding help
|
||||||
|
|
||||||
- the [github wiki](https://github.com/c-cube/ocaml-containers/wiki)
|
- the [github wiki](https://github.com/c-cube/ocaml-containers/wiki)
|
||||||
- the IRC channel (`##ocaml-containers` on Freenode)
|
- on IRC, ask `companion_cube` on `#ocaml`
|
||||||
|
|
||||||
## Use
|
## Use
|
||||||
|
|
||||||
|
|
@ -109,6 +109,10 @@ Documentation [here](http://cedeela.fr/~simon/software/containers).
|
||||||
|
|
||||||
- `CCIO`, basic utilities for IO
|
- `CCIO`, basic utilities for IO
|
||||||
|
|
||||||
|
### Containers.unix
|
||||||
|
|
||||||
|
- `CCUnix`, utils for `Unix`
|
||||||
|
|
||||||
### Containers.sexp
|
### Containers.sexp
|
||||||
|
|
||||||
A small S-expression library.
|
A small S-expression library.
|
||||||
|
|
|
||||||
49
_oasis
49
_oasis
|
|
@ -1,6 +1,6 @@
|
||||||
OASISFormat: 0.4
|
OASISFormat: 0.4
|
||||||
Name: containers
|
Name: containers
|
||||||
Version: 0.9
|
Version: 0.10
|
||||||
Homepage: https://github.com/c-cube/ocaml-containers
|
Homepage: https://github.com/c-cube/ocaml-containers
|
||||||
Authors: Simon Cruanes
|
Authors: Simon Cruanes
|
||||||
License: BSD-2-clause
|
License: BSD-2-clause
|
||||||
|
|
@ -25,6 +25,10 @@ Flag "misc"
|
||||||
Description: Build the misc library, with experimental modules still susceptible to change
|
Description: Build the misc library, with experimental modules still susceptible to change
|
||||||
Default: true
|
Default: true
|
||||||
|
|
||||||
|
Flag "unix"
|
||||||
|
Description: Build the containers.unix library (depends on Unix)
|
||||||
|
Default: false
|
||||||
|
|
||||||
Flag "lwt"
|
Flag "lwt"
|
||||||
Description: Build modules which depend on Lwt
|
Description: Build modules which depend on Lwt
|
||||||
Default: false
|
Default: false
|
||||||
|
|
@ -49,7 +53,8 @@ Library "containers"
|
||||||
Path: src/core
|
Path: src/core
|
||||||
Modules: CCVector, CCPrint, CCError, CCHeap, CCList, CCOpt, CCPair,
|
Modules: CCVector, CCPrint, CCError, CCHeap, CCList, CCOpt, CCPair,
|
||||||
CCFun, CCHash, CCInt, CCBool, CCFloat, CCArray, CCRef, CCSet,
|
CCFun, CCHash, CCInt, CCBool, CCFloat, CCArray, CCRef, CCSet,
|
||||||
CCOrd, CCRandom, CCString, CCHashtbl, CCMap, CCFormat
|
CCOrd, CCRandom, CCString, CCHashtbl, CCMap, CCFormat,
|
||||||
|
Containers
|
||||||
BuildDepends: bytes
|
BuildDepends: bytes
|
||||||
|
|
||||||
Library "containers_io"
|
Library "containers_io"
|
||||||
|
|
@ -59,6 +64,13 @@ Library "containers_io"
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
FindlibName: io
|
FindlibName: io
|
||||||
|
|
||||||
|
Library "containers_unix"
|
||||||
|
Path: src/unix
|
||||||
|
Modules: CCUnix
|
||||||
|
BuildDepends: bytes, unix
|
||||||
|
FindlibParent: containers
|
||||||
|
FindlibName: unix
|
||||||
|
|
||||||
Library "containers_sexp"
|
Library "containers_sexp"
|
||||||
Path: src/sexp
|
Path: src/sexp
|
||||||
Modules: CCSexp, CCSexpStream, CCSexpM
|
Modules: CCSexp, CCSexpStream, CCSexpM
|
||||||
|
|
@ -70,7 +82,7 @@ Library "containers_data"
|
||||||
Path: src/data
|
Path: src/data
|
||||||
Modules: CCMultiMap, CCMultiSet, CCTrie, CCFlatHashtbl, CCCache,
|
Modules: CCMultiMap, CCMultiSet, CCTrie, CCFlatHashtbl, CCCache,
|
||||||
CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl,
|
CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl,
|
||||||
CCMixmap, CCRingBuffer
|
CCMixmap, CCRingBuffer, CCIntMap, CCPersistentArray
|
||||||
BuildDepends: bytes
|
BuildDepends: bytes
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
FindlibName: data
|
FindlibName: data
|
||||||
|
|
@ -84,7 +96,8 @@ Library "containers_iter"
|
||||||
Library "containers_string"
|
Library "containers_string"
|
||||||
Path: src/string
|
Path: src/string
|
||||||
Pack: true
|
Pack: true
|
||||||
Modules: KMP, Levenshtein
|
Modules: KMP, Levenshtein, App_parse
|
||||||
|
BuildDepends: bytes
|
||||||
FindlibName: string
|
FindlibName: string
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
|
|
||||||
|
|
@ -105,18 +118,12 @@ Library "containers_bigarray"
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
BuildDepends: containers, bigarray, bytes
|
BuildDepends: containers, bigarray, bytes
|
||||||
|
|
||||||
Library "containers_pervasives"
|
|
||||||
Path: src/pervasives
|
|
||||||
Modules: CCPervasives
|
|
||||||
BuildDepends: containers
|
|
||||||
FindlibName: pervasives
|
|
||||||
FindlibParent: containers
|
|
||||||
|
|
||||||
Library "containers_misc"
|
Library "containers_misc"
|
||||||
Path: src/misc
|
Path: src/misc
|
||||||
Pack: true
|
Pack: true
|
||||||
Modules: AbsSet, Automaton, Bij, CSM, Hashset, LazyGraph, PHashtbl,
|
Modules: AbsSet, Automaton, Bij, CSM, Hashset, LazyGraph, PHashtbl,
|
||||||
PrintBox, RAL, RoseTree, SmallSet, UnionFind, Univ
|
PrintBox, RAL, RoseTree, SmallSet, UnionFind, Univ, Puf,
|
||||||
|
Backtrack
|
||||||
BuildDepends: containers, containers.data
|
BuildDepends: containers, containers.data
|
||||||
FindlibName: misc
|
FindlibName: misc
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
|
|
@ -145,15 +152,15 @@ Document containers
|
||||||
Title: Containers docs
|
Title: Containers docs
|
||||||
Type: ocamlbuild (0.3)
|
Type: ocamlbuild (0.3)
|
||||||
BuildTools+: ocamldoc
|
BuildTools+: ocamldoc
|
||||||
Build$: flag(docs) && flag(advanced) && flag(bigarray) && flag(lwt) && flag(misc)
|
Build$: flag(docs) && flag(advanced) && flag(bigarray) && flag(lwt) && flag(misc) && flag(unix)
|
||||||
Install: true
|
Install: true
|
||||||
XOCamlbuildPath: .
|
XOCamlbuildPath: .
|
||||||
XOCamlbuildExtraArgs:
|
XOCamlbuildExtraArgs:
|
||||||
"-docflags '-colorize-code -short-functors -charset utf-8'"
|
"-docflags '-colorize-code -short-functors -charset utf-8'"
|
||||||
XOCamlbuildLibraries:
|
XOCamlbuildLibraries:
|
||||||
containers, containers.misc, containers.iter, containers.data,
|
containers, containers.misc, containers.iter, containers.data,
|
||||||
containers.string, containers.pervasives, containers.bigarray,
|
containers.string, containers.bigarray,
|
||||||
containers.advanced, containers.io, containers.sexp,
|
containers.advanced, containers.io, containers.unix, containers.sexp,
|
||||||
containers.lwt
|
containers.lwt
|
||||||
|
|
||||||
Executable run_benchs
|
Executable run_benchs
|
||||||
|
|
@ -166,12 +173,12 @@ Executable run_benchs
|
||||||
containers.data, containers.string, containers.iter,
|
containers.data, containers.string, containers.iter,
|
||||||
sequence, gen, benchmark
|
sequence, gen, benchmark
|
||||||
|
|
||||||
Executable bench_hash
|
Executable run_bench_hash
|
||||||
Path: benchs/
|
Path: benchs/
|
||||||
Install: false
|
Install: false
|
||||||
CompiledObject: best
|
CompiledObject: best
|
||||||
Build$: flag(bench) && flag(misc)
|
Build$: flag(bench) && flag(misc)
|
||||||
MainIs: bench_hash.ml
|
MainIs: run_bench_hash.ml
|
||||||
BuildDepends: containers, containers.misc
|
BuildDepends: containers, containers.misc
|
||||||
|
|
||||||
Executable run_test_future
|
Executable run_test_future
|
||||||
|
|
@ -194,11 +201,11 @@ Executable run_qtest
|
||||||
Install: false
|
Install: false
|
||||||
CompiledObject: best
|
CompiledObject: best
|
||||||
MainIs: run_qtest.ml
|
MainIs: run_qtest.ml
|
||||||
Build$: flag(tests) && flag(bigarray)
|
Build$: flag(tests) && flag(misc) && flag(bigarray) && flag(unix) && flag(advanced)
|
||||||
BuildDepends: containers, containers.misc, containers.string, containers.iter,
|
BuildDepends: containers, containers.misc, containers.string, containers.iter,
|
||||||
containers.io, containers.advanced, containers.sexp,
|
containers.io, containers.advanced, containers.sexp,
|
||||||
containers.bigarray,
|
containers.bigarray, containers.unix,
|
||||||
sequence, gen, oUnit, QTest2Lib
|
sequence, gen, unix, oUnit, QTest2Lib
|
||||||
|
|
||||||
Executable run_qtest_lwt
|
Executable run_qtest_lwt
|
||||||
Path: qtest/lwt/
|
Path: qtest/lwt/
|
||||||
|
|
@ -222,7 +229,7 @@ Executable run_tests
|
||||||
Test all
|
Test all
|
||||||
Command: make test-all
|
Command: make test-all
|
||||||
TestTools: run_tests, run_qtest
|
TestTools: run_tests, run_qtest
|
||||||
Run$: flag(tests) && flag(misc)
|
Run$: flag(tests) && flag(misc) && flag(unix) && flag(advanced) && flag(bigarray)
|
||||||
|
|
||||||
Test lwt
|
Test lwt
|
||||||
Command: echo "test lwt"; ./run_qtest_lwt.native
|
Command: echo "test lwt"; ./run_qtest_lwt.native
|
||||||
|
|
|
||||||
28
_tags
28
_tags
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 4bc9d475d595a814a666d126274b25b1)
|
# DO NOT EDIT (digest: 2d4ff427096956a049556073cd9b4191)
|
||||||
# Ignore VCS directories, you can use the same kind of rule outside
|
# Ignore VCS directories, you can use the same kind of rule outside
|
||||||
# OASIS_START/STOP if you want to exclude directories that contains
|
# OASIS_START/STOP if you want to exclude directories that contains
|
||||||
# useless stuff for the build process
|
# useless stuff for the build process
|
||||||
|
|
@ -20,6 +20,10 @@ true: annot, bin_annot
|
||||||
# Library containers_io
|
# Library containers_io
|
||||||
"src/io/containers_io.cmxs": use_containers_io
|
"src/io/containers_io.cmxs": use_containers_io
|
||||||
<src/io/*.ml{,i,y}>: package(bytes)
|
<src/io/*.ml{,i,y}>: package(bytes)
|
||||||
|
# Library containers_unix
|
||||||
|
"src/unix/containers_unix.cmxs": use_containers_unix
|
||||||
|
<src/unix/*.ml{,i,y}>: package(bytes)
|
||||||
|
<src/unix/*.ml{,i,y}>: package(unix)
|
||||||
# Library containers_sexp
|
# Library containers_sexp
|
||||||
"src/sexp/containers_sexp.cmxs": use_containers_sexp
|
"src/sexp/containers_sexp.cmxs": use_containers_sexp
|
||||||
<src/sexp/*.ml{,i,y}>: package(bytes)
|
<src/sexp/*.ml{,i,y}>: package(bytes)
|
||||||
|
|
@ -32,6 +36,8 @@ true: annot, bin_annot
|
||||||
"src/string/containers_string.cmxs": use_containers_string
|
"src/string/containers_string.cmxs": use_containers_string
|
||||||
"src/string/KMP.cmx": for-pack(Containers_string)
|
"src/string/KMP.cmx": for-pack(Containers_string)
|
||||||
"src/string/levenshtein.cmx": for-pack(Containers_string)
|
"src/string/levenshtein.cmx": for-pack(Containers_string)
|
||||||
|
"src/string/app_parse.cmx": for-pack(Containers_string)
|
||||||
|
<src/string/*.ml{,i,y}>: package(bytes)
|
||||||
# Library containers_advanced
|
# Library containers_advanced
|
||||||
"src/advanced/containers_advanced.cmxs": use_containers_advanced
|
"src/advanced/containers_advanced.cmxs": use_containers_advanced
|
||||||
"src/advanced/CCLinq.cmx": for-pack(Containers_advanced)
|
"src/advanced/CCLinq.cmx": for-pack(Containers_advanced)
|
||||||
|
|
@ -46,10 +52,6 @@ true: annot, bin_annot
|
||||||
<src/bigarray/*.ml{,i,y}>: package(bigarray)
|
<src/bigarray/*.ml{,i,y}>: package(bigarray)
|
||||||
<src/bigarray/*.ml{,i,y}>: package(bytes)
|
<src/bigarray/*.ml{,i,y}>: package(bytes)
|
||||||
<src/bigarray/*.ml{,i,y}>: use_containers
|
<src/bigarray/*.ml{,i,y}>: use_containers
|
||||||
# Library containers_pervasives
|
|
||||||
"src/pervasives/containers_pervasives.cmxs": use_containers_pervasives
|
|
||||||
<src/pervasives/*.ml{,i,y}>: package(bytes)
|
|
||||||
<src/pervasives/*.ml{,i,y}>: use_containers
|
|
||||||
# Library containers_misc
|
# Library containers_misc
|
||||||
"src/misc/containers_misc.cmxs": use_containers_misc
|
"src/misc/containers_misc.cmxs": use_containers_misc
|
||||||
"src/misc/absSet.cmx": for-pack(Containers_misc)
|
"src/misc/absSet.cmx": for-pack(Containers_misc)
|
||||||
|
|
@ -65,6 +67,8 @@ true: annot, bin_annot
|
||||||
"src/misc/smallSet.cmx": for-pack(Containers_misc)
|
"src/misc/smallSet.cmx": for-pack(Containers_misc)
|
||||||
"src/misc/unionFind.cmx": for-pack(Containers_misc)
|
"src/misc/unionFind.cmx": for-pack(Containers_misc)
|
||||||
"src/misc/univ.cmx": for-pack(Containers_misc)
|
"src/misc/univ.cmx": for-pack(Containers_misc)
|
||||||
|
"src/misc/puf.cmx": for-pack(Containers_misc)
|
||||||
|
"src/misc/backtrack.cmx": for-pack(Containers_misc)
|
||||||
<src/misc/*.ml{,i,y}>: package(bytes)
|
<src/misc/*.ml{,i,y}>: package(bytes)
|
||||||
<src/misc/*.ml{,i,y}>: use_containers
|
<src/misc/*.ml{,i,y}>: use_containers
|
||||||
<src/misc/*.ml{,i,y}>: use_containers_data
|
<src/misc/*.ml{,i,y}>: use_containers_data
|
||||||
|
|
@ -101,11 +105,11 @@ true: annot, bin_annot
|
||||||
<benchs/*.ml{,i,y}>: use_containers_advanced
|
<benchs/*.ml{,i,y}>: use_containers_advanced
|
||||||
<benchs/*.ml{,i,y}>: use_containers_iter
|
<benchs/*.ml{,i,y}>: use_containers_iter
|
||||||
<benchs/*.ml{,i,y}>: use_containers_string
|
<benchs/*.ml{,i,y}>: use_containers_string
|
||||||
# Executable bench_hash
|
# Executable run_bench_hash
|
||||||
<benchs/bench_hash.{native,byte}>: package(bytes)
|
<benchs/run_bench_hash.{native,byte}>: package(bytes)
|
||||||
<benchs/bench_hash.{native,byte}>: use_containers
|
<benchs/run_bench_hash.{native,byte}>: use_containers
|
||||||
<benchs/bench_hash.{native,byte}>: use_containers_data
|
<benchs/run_bench_hash.{native,byte}>: use_containers_data
|
||||||
<benchs/bench_hash.{native,byte}>: use_containers_misc
|
<benchs/run_bench_hash.{native,byte}>: use_containers_misc
|
||||||
<benchs/*.ml{,i,y}>: package(bytes)
|
<benchs/*.ml{,i,y}>: package(bytes)
|
||||||
<benchs/*.ml{,i,y}>: use_containers
|
<benchs/*.ml{,i,y}>: use_containers
|
||||||
<benchs/*.ml{,i,y}>: use_containers_data
|
<benchs/*.ml{,i,y}>: use_containers_data
|
||||||
|
|
@ -130,6 +134,7 @@ true: annot, bin_annot
|
||||||
<qtest/run_qtest.{native,byte}>: package(gen)
|
<qtest/run_qtest.{native,byte}>: package(gen)
|
||||||
<qtest/run_qtest.{native,byte}>: package(oUnit)
|
<qtest/run_qtest.{native,byte}>: package(oUnit)
|
||||||
<qtest/run_qtest.{native,byte}>: package(sequence)
|
<qtest/run_qtest.{native,byte}>: package(sequence)
|
||||||
|
<qtest/run_qtest.{native,byte}>: package(unix)
|
||||||
<qtest/run_qtest.{native,byte}>: use_containers
|
<qtest/run_qtest.{native,byte}>: use_containers
|
||||||
<qtest/run_qtest.{native,byte}>: use_containers_advanced
|
<qtest/run_qtest.{native,byte}>: use_containers_advanced
|
||||||
<qtest/run_qtest.{native,byte}>: use_containers_bigarray
|
<qtest/run_qtest.{native,byte}>: use_containers_bigarray
|
||||||
|
|
@ -139,12 +144,14 @@ true: annot, bin_annot
|
||||||
<qtest/run_qtest.{native,byte}>: use_containers_misc
|
<qtest/run_qtest.{native,byte}>: use_containers_misc
|
||||||
<qtest/run_qtest.{native,byte}>: use_containers_sexp
|
<qtest/run_qtest.{native,byte}>: use_containers_sexp
|
||||||
<qtest/run_qtest.{native,byte}>: use_containers_string
|
<qtest/run_qtest.{native,byte}>: use_containers_string
|
||||||
|
<qtest/run_qtest.{native,byte}>: use_containers_unix
|
||||||
<qtest/*.ml{,i,y}>: package(QTest2Lib)
|
<qtest/*.ml{,i,y}>: package(QTest2Lib)
|
||||||
<qtest/*.ml{,i,y}>: package(bigarray)
|
<qtest/*.ml{,i,y}>: package(bigarray)
|
||||||
<qtest/*.ml{,i,y}>: package(bytes)
|
<qtest/*.ml{,i,y}>: package(bytes)
|
||||||
<qtest/*.ml{,i,y}>: package(gen)
|
<qtest/*.ml{,i,y}>: package(gen)
|
||||||
<qtest/*.ml{,i,y}>: package(oUnit)
|
<qtest/*.ml{,i,y}>: package(oUnit)
|
||||||
<qtest/*.ml{,i,y}>: package(sequence)
|
<qtest/*.ml{,i,y}>: package(sequence)
|
||||||
|
<qtest/*.ml{,i,y}>: package(unix)
|
||||||
<qtest/*.ml{,i,y}>: use_containers
|
<qtest/*.ml{,i,y}>: use_containers
|
||||||
<qtest/*.ml{,i,y}>: use_containers_advanced
|
<qtest/*.ml{,i,y}>: use_containers_advanced
|
||||||
<qtest/*.ml{,i,y}>: use_containers_bigarray
|
<qtest/*.ml{,i,y}>: use_containers_bigarray
|
||||||
|
|
@ -154,6 +161,7 @@ true: annot, bin_annot
|
||||||
<qtest/*.ml{,i,y}>: use_containers_misc
|
<qtest/*.ml{,i,y}>: use_containers_misc
|
||||||
<qtest/*.ml{,i,y}>: use_containers_sexp
|
<qtest/*.ml{,i,y}>: use_containers_sexp
|
||||||
<qtest/*.ml{,i,y}>: use_containers_string
|
<qtest/*.ml{,i,y}>: use_containers_string
|
||||||
|
<qtest/*.ml{,i,y}>: use_containers_unix
|
||||||
# Executable run_qtest_lwt
|
# Executable run_qtest_lwt
|
||||||
<qtest/lwt/run_qtest_lwt.{native,byte}>: package(QTest2Lib)
|
<qtest/lwt/run_qtest_lwt.{native,byte}>: package(QTest2Lib)
|
||||||
<qtest/lwt/run_qtest_lwt.{native,byte}>: package(bytes)
|
<qtest/lwt/run_qtest_lwt.{native,byte}>: package(bytes)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ module B = Benchmark
|
||||||
let (@>) = B.Tree.(@>)
|
let (@>) = B.Tree.(@>)
|
||||||
let (@>>) = B.Tree.(@>>)
|
let (@>>) = B.Tree.(@>>)
|
||||||
let (@>>>) = B.Tree.(@>>>)
|
let (@>>>) = B.Tree.(@>>>)
|
||||||
|
let (|>) = CCFun.(|>)
|
||||||
|
|
||||||
let app_int f n = string_of_int n @> lazy (f n)
|
let app_int f n = string_of_int n @> lazy (f n)
|
||||||
let app_ints f l = B.Tree.concat (List.map (app_int f) l)
|
let app_ints f l = B.Tree.concat (List.map (app_int f) l)
|
||||||
|
|
@ -234,6 +235,13 @@ module Tbl = struct
|
||||||
done;
|
done;
|
||||||
!h
|
!h
|
||||||
|
|
||||||
|
let intmap_add n =
|
||||||
|
let h = ref CCIntMap.empty in
|
||||||
|
for i = n downto 0 do
|
||||||
|
h := CCIntMap.add i i !h;
|
||||||
|
done;
|
||||||
|
!h
|
||||||
|
|
||||||
let icchashtbl_add n =
|
let icchashtbl_add n =
|
||||||
let h = ICCHashtbl.create 50 in
|
let h = ICCHashtbl.create 50 in
|
||||||
for i = n downto 0 do
|
for i = n downto 0 do
|
||||||
|
|
@ -248,6 +256,7 @@ module Tbl = struct
|
||||||
"ihashtbl_add", (fun n -> ignore (ihashtbl_add n)), n;
|
"ihashtbl_add", (fun n -> ignore (ihashtbl_add n)), n;
|
||||||
"ipersistenthashtbl_add", (fun n -> ignore (ipersistenthashtbl_add n)), n;
|
"ipersistenthashtbl_add", (fun n -> ignore (ipersistenthashtbl_add n)), n;
|
||||||
"imap_add", (fun n -> ignore (imap_add n)), n;
|
"imap_add", (fun n -> ignore (imap_add n)), n;
|
||||||
|
"intmap_add", (fun n -> ignore (intmap_add n)), n;
|
||||||
"ccflathashtbl_add", (fun n -> ignore (icchashtbl_add n)), n;
|
"ccflathashtbl_add", (fun n -> ignore (icchashtbl_add n)), n;
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -301,6 +310,16 @@ module Tbl = struct
|
||||||
done;
|
done;
|
||||||
!h
|
!h
|
||||||
|
|
||||||
|
let intmap_replace n =
|
||||||
|
let h = ref CCIntMap.empty in
|
||||||
|
for i = 0 to n do
|
||||||
|
h := CCIntMap.add i i !h;
|
||||||
|
done;
|
||||||
|
for i = n downto 0 do
|
||||||
|
h := CCIntMap.add i i !h;
|
||||||
|
done;
|
||||||
|
!h
|
||||||
|
|
||||||
let icchashtbl_replace n =
|
let icchashtbl_replace n =
|
||||||
let h = ICCHashtbl.create 50 in
|
let h = ICCHashtbl.create 50 in
|
||||||
for i = 0 to n do
|
for i = 0 to n do
|
||||||
|
|
@ -318,11 +337,10 @@ module Tbl = struct
|
||||||
"ihashtbl_replace", (fun n -> ignore (ihashtbl_replace n)), n;
|
"ihashtbl_replace", (fun n -> ignore (ihashtbl_replace n)), n;
|
||||||
"ipersistenthashtbl_replace", (fun n -> ignore (ipersistenthashtbl_replace n)), n;
|
"ipersistenthashtbl_replace", (fun n -> ignore (ipersistenthashtbl_replace n)), n;
|
||||||
"imap_replace", (fun n -> ignore (imap_replace n)), n;
|
"imap_replace", (fun n -> ignore (imap_replace n)), n;
|
||||||
|
"intmap_replace", (fun n -> ignore (intmap_replace n)), n;
|
||||||
"ccflathashtbl_replace", (fun n -> ignore (icchashtbl_replace n)), n;
|
"ccflathashtbl_replace", (fun n -> ignore (icchashtbl_replace n)), n;
|
||||||
]
|
]
|
||||||
|
|
||||||
let my_len = 250
|
|
||||||
|
|
||||||
let phashtbl_find h =
|
let phashtbl_find h =
|
||||||
fun n ->
|
fun n ->
|
||||||
for i = 0 to n-1 do
|
for i = 0 to n-1 do
|
||||||
|
|
@ -353,12 +371,24 @@ module Tbl = struct
|
||||||
ignore (Array.get a i);
|
ignore (Array.get a i);
|
||||||
done
|
done
|
||||||
|
|
||||||
|
let persistent_array_find a =
|
||||||
|
fun n ->
|
||||||
|
for i = 0 to n-1 do
|
||||||
|
ignore (CCPersistentArray.get a i);
|
||||||
|
done
|
||||||
|
|
||||||
let imap_find m =
|
let imap_find m =
|
||||||
fun n ->
|
fun n ->
|
||||||
for i = 0 to n-1 do
|
for i = 0 to n-1 do
|
||||||
ignore (IMap.find i m);
|
ignore (IMap.find i m);
|
||||||
done
|
done
|
||||||
|
|
||||||
|
let intmap_find m =
|
||||||
|
fun n ->
|
||||||
|
for i = 0 to n-1 do
|
||||||
|
ignore (CCIntMap.find i m);
|
||||||
|
done
|
||||||
|
|
||||||
let icchashtbl_find m =
|
let icchashtbl_find m =
|
||||||
fun n ->
|
fun n ->
|
||||||
for i = 0 to n-1 do
|
for i = 0 to n-1 do
|
||||||
|
|
@ -370,8 +400,10 @@ module Tbl = struct
|
||||||
let h' = hashtbl_add n in
|
let h' = hashtbl_add n in
|
||||||
let h'' = ihashtbl_add n in
|
let h'' = ihashtbl_add n in
|
||||||
let h''''' = ipersistenthashtbl_add n in
|
let h''''' = ipersistenthashtbl_add n in
|
||||||
let a = Array.init n (fun i -> string_of_int i) in
|
let a = Array.init n string_of_int in
|
||||||
|
let pa = CCPersistentArray.init n string_of_int in
|
||||||
let m = imap_add n in
|
let m = imap_add n in
|
||||||
|
let m' = intmap_add n in
|
||||||
let h'''''' = icchashtbl_add n in
|
let h'''''' = icchashtbl_add n in
|
||||||
B.throughputN 3 [
|
B.throughputN 3 [
|
||||||
"phashtbl_find", (fun () -> phashtbl_find h n), ();
|
"phashtbl_find", (fun () -> phashtbl_find h n), ();
|
||||||
|
|
@ -379,7 +411,9 @@ module Tbl = struct
|
||||||
"ihashtbl_find", (fun () -> ihashtbl_find h'' n), ();
|
"ihashtbl_find", (fun () -> ihashtbl_find h'' n), ();
|
||||||
"ipersistenthashtbl_find", (fun () -> ipersistenthashtbl_find h''''' n), ();
|
"ipersistenthashtbl_find", (fun () -> ipersistenthashtbl_find h''''' n), ();
|
||||||
"array_find", (fun () -> array_find a n), ();
|
"array_find", (fun () -> array_find a n), ();
|
||||||
|
"persistent_array_find", (fun () -> persistent_array_find pa n), ();
|
||||||
"imap_find", (fun () -> imap_find m n), ();
|
"imap_find", (fun () -> imap_find m n), ();
|
||||||
|
"intmap_find", (fun () -> intmap_find m' n), ();
|
||||||
"cchashtbl_find", (fun () -> icchashtbl_find h'''''' n), ();
|
"cchashtbl_find", (fun () -> icchashtbl_find h'''''' n), ();
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 98c09c3ae4c860914660bcfa48ec375f)
|
# DO NOT EDIT (digest: 463813d3e54d45bc5b6a9d7d4eb17cd0)
|
||||||
src/core/CCVector
|
src/core/CCVector
|
||||||
src/core/CCPrint
|
src/core/CCPrint
|
||||||
src/core/CCError
|
src/core/CCError
|
||||||
|
|
@ -21,6 +21,7 @@ src/core/CCString
|
||||||
src/core/CCHashtbl
|
src/core/CCHashtbl
|
||||||
src/core/CCMap
|
src/core/CCMap
|
||||||
src/core/CCFormat
|
src/core/CCFormat
|
||||||
|
src/core/Containers
|
||||||
src/misc/AbsSet
|
src/misc/AbsSet
|
||||||
src/misc/Automaton
|
src/misc/Automaton
|
||||||
src/misc/Bij
|
src/misc/Bij
|
||||||
|
|
@ -34,6 +35,8 @@ src/misc/RoseTree
|
||||||
src/misc/SmallSet
|
src/misc/SmallSet
|
||||||
src/misc/UnionFind
|
src/misc/UnionFind
|
||||||
src/misc/Univ
|
src/misc/Univ
|
||||||
|
src/misc/Puf
|
||||||
|
src/misc/Backtrack
|
||||||
src/iter/CCKTree
|
src/iter/CCKTree
|
||||||
src/iter/CCKList
|
src/iter/CCKList
|
||||||
src/data/CCMultiMap
|
src/data/CCMultiMap
|
||||||
|
|
@ -48,15 +51,18 @@ src/data/CCBV
|
||||||
src/data/CCMixtbl
|
src/data/CCMixtbl
|
||||||
src/data/CCMixmap
|
src/data/CCMixmap
|
||||||
src/data/CCRingBuffer
|
src/data/CCRingBuffer
|
||||||
|
src/data/CCIntMap
|
||||||
|
src/data/CCPersistentArray
|
||||||
src/string/KMP
|
src/string/KMP
|
||||||
src/string/Levenshtein
|
src/string/Levenshtein
|
||||||
src/pervasives/CCPervasives
|
src/string/App_parse
|
||||||
src/bigarray/CCBigstring
|
src/bigarray/CCBigstring
|
||||||
src/advanced/CCLinq
|
src/advanced/CCLinq
|
||||||
src/advanced/CCBatch
|
src/advanced/CCBatch
|
||||||
src/advanced/CCCat
|
src/advanced/CCCat
|
||||||
src/advanced/CCMonadIO
|
src/advanced/CCMonadIO
|
||||||
src/io/CCIO
|
src/io/CCIO
|
||||||
|
src/unix/CCUnix
|
||||||
src/sexp/CCSexp
|
src/sexp/CCSexp
|
||||||
src/sexp/CCSexpStream
|
src/sexp/CCSexpStream
|
||||||
src/sexp/CCSexpM
|
src/sexp/CCSexpM
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,11 @@ CCRef
|
||||||
CCSet
|
CCSet
|
||||||
CCString
|
CCString
|
||||||
CCVector
|
CCVector
|
||||||
|
Containers
|
||||||
}
|
}
|
||||||
|
|
||||||
{4 Pervasives (aliases to Core Modules)}
|
The module {!Containers} contains aliases to most other modules defined
|
||||||
|
in {i containers core}, and mixins
|
||||||
Contains aliases to most modules from {i containers core}, and mixins
|
|
||||||
such as:
|
such as:
|
||||||
|
|
||||||
{[ module List = struct
|
{[ module List = struct
|
||||||
|
|
@ -57,8 +57,6 @@ such as:
|
||||||
end
|
end
|
||||||
]}
|
]}
|
||||||
|
|
||||||
{!modules: CCPervasives}
|
|
||||||
|
|
||||||
{4 Containers.data}
|
{4 Containers.data}
|
||||||
|
|
||||||
Various data structures.
|
Various data structures.
|
||||||
|
|
@ -68,10 +66,12 @@ CCBV
|
||||||
CCCache
|
CCCache
|
||||||
CCFQueue
|
CCFQueue
|
||||||
CCFlatHashtbl
|
CCFlatHashtbl
|
||||||
|
CCIntMap
|
||||||
CCMixmap
|
CCMixmap
|
||||||
CCMixtbl
|
CCMixtbl
|
||||||
CCMultiMap
|
CCMultiMap
|
||||||
CCMultiSet
|
CCMultiSet
|
||||||
|
CCPersistentArray
|
||||||
CCPersistentHashtbl
|
CCPersistentHashtbl
|
||||||
CCRingBuffer
|
CCRingBuffer
|
||||||
CCTrie
|
CCTrie
|
||||||
|
|
@ -83,6 +83,12 @@ Helpers to perform simple IO (mostly on files) and iterate on channels.
|
||||||
|
|
||||||
{!modules: CCIO}
|
{!modules: CCIO}
|
||||||
|
|
||||||
|
{4 Containers.unix}
|
||||||
|
|
||||||
|
Helpers that depend on {!Unix}, e.g. to spawn sub-processes.
|
||||||
|
|
||||||
|
{!modules: CCUnix}
|
||||||
|
|
||||||
{4 Containers.sexp}
|
{4 Containers.sexp}
|
||||||
|
|
||||||
A small S-expression library. The interface is relatively unstable, but
|
A small S-expression library. The interface is relatively unstable, but
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(* OASIS_START *)
|
(* OASIS_START *)
|
||||||
(* DO NOT EDIT (digest: fb8dea068c03b0d63bc05634c5db1689) *)
|
(* DO NOT EDIT (digest: c0298c035a279ad3c641dc2bb1ecc03b) *)
|
||||||
module OASISGettext = struct
|
module OASISGettext = struct
|
||||||
(* # 22 "src/oasis/OASISGettext.ml" *)
|
(* # 22 "src/oasis/OASISGettext.ml" *)
|
||||||
|
|
||||||
|
|
@ -611,13 +611,13 @@ let package_default =
|
||||||
[
|
[
|
||||||
("containers", ["src/core"], []);
|
("containers", ["src/core"], []);
|
||||||
("containers_io", ["src/io"], []);
|
("containers_io", ["src/io"], []);
|
||||||
|
("containers_unix", ["src/unix"], []);
|
||||||
("containers_sexp", ["src/sexp"], []);
|
("containers_sexp", ["src/sexp"], []);
|
||||||
("containers_data", ["src/data"], []);
|
("containers_data", ["src/data"], []);
|
||||||
("containers_iter", ["src/iter"], []);
|
("containers_iter", ["src/iter"], []);
|
||||||
("containers_string", ["src/string"], []);
|
("containers_string", ["src/string"], []);
|
||||||
("containers_advanced", ["src/advanced"], []);
|
("containers_advanced", ["src/advanced"], []);
|
||||||
("containers_bigarray", ["src/bigarray"], []);
|
("containers_bigarray", ["src/bigarray"], []);
|
||||||
("containers_pervasives", ["src/pervasives"], []);
|
|
||||||
("containers_misc", ["src/misc"], []);
|
("containers_misc", ["src/misc"], []);
|
||||||
("containers_thread", ["src/threads"], []);
|
("containers_thread", ["src/threads"], []);
|
||||||
("containers_lwt", ["src/lwt"], [])
|
("containers_lwt", ["src/lwt"], [])
|
||||||
|
|
@ -629,7 +629,6 @@ let package_default =
|
||||||
("tests/threads", ["src/core"; "src/threads"]);
|
("tests/threads", ["src/core"; "src/threads"]);
|
||||||
("tests", ["src/core"; "src/data"; "src/misc"; "src/string"]);
|
("tests", ["src/core"; "src/data"; "src/misc"; "src/string"]);
|
||||||
("src/threads", ["src/core"]);
|
("src/threads", ["src/core"]);
|
||||||
("src/pervasives", ["src/core"]);
|
|
||||||
("src/misc", ["src/core"; "src/data"]);
|
("src/misc", ["src/core"; "src/data"]);
|
||||||
("src/lwt", ["src/core"; "src/misc"]);
|
("src/lwt", ["src/core"; "src/misc"]);
|
||||||
("src/bigarray", ["src/core"]);
|
("src/bigarray", ["src/core"]);
|
||||||
|
|
@ -644,7 +643,8 @@ let package_default =
|
||||||
"src/iter";
|
"src/iter";
|
||||||
"src/misc";
|
"src/misc";
|
||||||
"src/sexp";
|
"src/sexp";
|
||||||
"src/string"
|
"src/string";
|
||||||
|
"src/unix"
|
||||||
]);
|
]);
|
||||||
("examples", ["src/core"; "src/misc"; "src/sexp"]);
|
("examples", ["src/core"; "src/misc"; "src/sexp"]);
|
||||||
("benchs",
|
("benchs",
|
||||||
|
|
|
||||||
1
opam
1
opam
|
|
@ -12,6 +12,7 @@ build: [
|
||||||
"--%{lwt:enable}%-lwt"
|
"--%{lwt:enable}%-lwt"
|
||||||
"--%{base-bigarray:enable}%-bigarray"
|
"--%{base-bigarray:enable}%-bigarray"
|
||||||
"--%{sequence:enable}%-advanced"
|
"--%{sequence:enable}%-advanced"
|
||||||
|
"--%{base-unix:enable}%-unix"
|
||||||
"--enable-docs"
|
"--enable-docs"
|
||||||
"--enable-misc"]
|
"--enable-misc"]
|
||||||
[make "build"]
|
[make "build"]
|
||||||
|
|
|
||||||
126
setup.ml
126
setup.ml
|
|
@ -1,7 +1,7 @@
|
||||||
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
||||||
|
|
||||||
(* OASIS_START *)
|
(* OASIS_START *)
|
||||||
(* DO NOT EDIT (digest: d2414bb4ed47c14d1e696e080da28357) *)
|
(* DO NOT EDIT (digest: bc1fcdeddb836af6942617417a65ae05) *)
|
||||||
(*
|
(*
|
||||||
Regenerated by OASIS v0.4.5
|
Regenerated by OASIS v0.4.5
|
||||||
Visit http://oasis.forge.ocamlcore.org for more information and
|
Visit http://oasis.forge.ocamlcore.org for more information and
|
||||||
|
|
@ -6965,7 +6965,7 @@ let setup_t =
|
||||||
alpha_features = ["ocamlbuild_more_args"];
|
alpha_features = ["ocamlbuild_more_args"];
|
||||||
beta_features = [];
|
beta_features = [];
|
||||||
name = "containers";
|
name = "containers";
|
||||||
version = "0.9";
|
version = "0.10";
|
||||||
license =
|
license =
|
||||||
OASISLicense.DEP5License
|
OASISLicense.DEP5License
|
||||||
(OASISLicense.DEP5Unit
|
(OASISLicense.DEP5Unit
|
||||||
|
|
@ -7041,6 +7041,18 @@ let setup_t =
|
||||||
"Build the misc library, with experimental modules still susceptible to change";
|
"Build the misc library, with experimental modules still susceptible to change";
|
||||||
flag_default = [(OASISExpr.EBool true, true)]
|
flag_default = [(OASISExpr.EBool true, true)]
|
||||||
});
|
});
|
||||||
|
Flag
|
||||||
|
({
|
||||||
|
cs_name = "unix";
|
||||||
|
cs_data = PropList.Data.create ();
|
||||||
|
cs_plugin_data = []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flag_description =
|
||||||
|
Some
|
||||||
|
"Build the containers.unix library (depends on Unix)";
|
||||||
|
flag_default = [(OASISExpr.EBool true, false)]
|
||||||
|
});
|
||||||
Flag
|
Flag
|
||||||
({
|
({
|
||||||
cs_name = "lwt";
|
cs_name = "lwt";
|
||||||
|
|
@ -7141,7 +7153,8 @@ let setup_t =
|
||||||
"CCString";
|
"CCString";
|
||||||
"CCHashtbl";
|
"CCHashtbl";
|
||||||
"CCMap";
|
"CCMap";
|
||||||
"CCFormat"
|
"CCFormat";
|
||||||
|
"Containers"
|
||||||
];
|
];
|
||||||
lib_pack = false;
|
lib_pack = false;
|
||||||
lib_internal_modules = [];
|
lib_internal_modules = [];
|
||||||
|
|
@ -7179,6 +7192,40 @@ let setup_t =
|
||||||
lib_findlib_name = Some "io";
|
lib_findlib_name = Some "io";
|
||||||
lib_findlib_containers = []
|
lib_findlib_containers = []
|
||||||
});
|
});
|
||||||
|
Library
|
||||||
|
({
|
||||||
|
cs_name = "containers_unix";
|
||||||
|
cs_data = PropList.Data.create ();
|
||||||
|
cs_plugin_data = []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bs_build = [(OASISExpr.EBool true, true)];
|
||||||
|
bs_install = [(OASISExpr.EBool true, true)];
|
||||||
|
bs_path = "src/unix";
|
||||||
|
bs_compiled_object = Best;
|
||||||
|
bs_build_depends =
|
||||||
|
[
|
||||||
|
FindlibPackage ("bytes", None);
|
||||||
|
FindlibPackage ("unix", None)
|
||||||
|
];
|
||||||
|
bs_build_tools = [ExternalTool "ocamlbuild"];
|
||||||
|
bs_c_sources = [];
|
||||||
|
bs_data_files = [];
|
||||||
|
bs_ccopt = [(OASISExpr.EBool true, [])];
|
||||||
|
bs_cclib = [(OASISExpr.EBool true, [])];
|
||||||
|
bs_dlllib = [(OASISExpr.EBool true, [])];
|
||||||
|
bs_dllpath = [(OASISExpr.EBool true, [])];
|
||||||
|
bs_byteopt = [(OASISExpr.EBool true, [])];
|
||||||
|
bs_nativeopt = [(OASISExpr.EBool true, [])]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lib_modules = ["CCUnix"];
|
||||||
|
lib_pack = false;
|
||||||
|
lib_internal_modules = [];
|
||||||
|
lib_findlib_parent = Some "containers";
|
||||||
|
lib_findlib_name = Some "unix";
|
||||||
|
lib_findlib_containers = []
|
||||||
|
});
|
||||||
Library
|
Library
|
||||||
({
|
({
|
||||||
cs_name = "containers_sexp";
|
cs_name = "containers_sexp";
|
||||||
|
|
@ -7245,7 +7292,9 @@ let setup_t =
|
||||||
"CCBV";
|
"CCBV";
|
||||||
"CCMixtbl";
|
"CCMixtbl";
|
||||||
"CCMixmap";
|
"CCMixmap";
|
||||||
"CCRingBuffer"
|
"CCRingBuffer";
|
||||||
|
"CCIntMap";
|
||||||
|
"CCPersistentArray"
|
||||||
];
|
];
|
||||||
lib_pack = false;
|
lib_pack = false;
|
||||||
lib_internal_modules = [];
|
lib_internal_modules = [];
|
||||||
|
|
@ -7294,7 +7343,7 @@ let setup_t =
|
||||||
bs_install = [(OASISExpr.EBool true, true)];
|
bs_install = [(OASISExpr.EBool true, true)];
|
||||||
bs_path = "src/string";
|
bs_path = "src/string";
|
||||||
bs_compiled_object = Best;
|
bs_compiled_object = Best;
|
||||||
bs_build_depends = [];
|
bs_build_depends = [FindlibPackage ("bytes", None)];
|
||||||
bs_build_tools = [ExternalTool "ocamlbuild"];
|
bs_build_tools = [ExternalTool "ocamlbuild"];
|
||||||
bs_c_sources = [];
|
bs_c_sources = [];
|
||||||
bs_data_files = [];
|
bs_data_files = [];
|
||||||
|
|
@ -7306,7 +7355,7 @@ let setup_t =
|
||||||
bs_nativeopt = [(OASISExpr.EBool true, [])]
|
bs_nativeopt = [(OASISExpr.EBool true, [])]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lib_modules = ["KMP"; "Levenshtein"];
|
lib_modules = ["KMP"; "Levenshtein"; "App_parse"];
|
||||||
lib_pack = true;
|
lib_pack = true;
|
||||||
lib_internal_modules = [];
|
lib_internal_modules = [];
|
||||||
lib_findlib_parent = Some "containers";
|
lib_findlib_parent = Some "containers";
|
||||||
|
|
@ -7391,36 +7440,6 @@ let setup_t =
|
||||||
lib_findlib_name = Some "bigarray";
|
lib_findlib_name = Some "bigarray";
|
||||||
lib_findlib_containers = []
|
lib_findlib_containers = []
|
||||||
});
|
});
|
||||||
Library
|
|
||||||
({
|
|
||||||
cs_name = "containers_pervasives";
|
|
||||||
cs_data = PropList.Data.create ();
|
|
||||||
cs_plugin_data = []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
bs_build = [(OASISExpr.EBool true, true)];
|
|
||||||
bs_install = [(OASISExpr.EBool true, true)];
|
|
||||||
bs_path = "src/pervasives";
|
|
||||||
bs_compiled_object = Best;
|
|
||||||
bs_build_depends = [InternalLibrary "containers"];
|
|
||||||
bs_build_tools = [ExternalTool "ocamlbuild"];
|
|
||||||
bs_c_sources = [];
|
|
||||||
bs_data_files = [];
|
|
||||||
bs_ccopt = [(OASISExpr.EBool true, [])];
|
|
||||||
bs_cclib = [(OASISExpr.EBool true, [])];
|
|
||||||
bs_dlllib = [(OASISExpr.EBool true, [])];
|
|
||||||
bs_dllpath = [(OASISExpr.EBool true, [])];
|
|
||||||
bs_byteopt = [(OASISExpr.EBool true, [])];
|
|
||||||
bs_nativeopt = [(OASISExpr.EBool true, [])]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lib_modules = ["CCPervasives"];
|
|
||||||
lib_pack = false;
|
|
||||||
lib_internal_modules = [];
|
|
||||||
lib_findlib_parent = Some "containers";
|
|
||||||
lib_findlib_name = Some "pervasives";
|
|
||||||
lib_findlib_containers = []
|
|
||||||
});
|
|
||||||
Library
|
Library
|
||||||
({
|
({
|
||||||
cs_name = "containers_misc";
|
cs_name = "containers_misc";
|
||||||
|
|
@ -7462,7 +7481,9 @@ let setup_t =
|
||||||
"RoseTree";
|
"RoseTree";
|
||||||
"SmallSet";
|
"SmallSet";
|
||||||
"UnionFind";
|
"UnionFind";
|
||||||
"Univ"
|
"Univ";
|
||||||
|
"Puf";
|
||||||
|
"Backtrack"
|
||||||
];
|
];
|
||||||
lib_pack = true;
|
lib_pack = true;
|
||||||
lib_internal_modules = [];
|
lib_internal_modules = [];
|
||||||
|
|
@ -7592,7 +7613,9 @@ let setup_t =
|
||||||
(OASISExpr.EFlag "bigarray",
|
(OASISExpr.EFlag "bigarray",
|
||||||
OASISExpr.EAnd
|
OASISExpr.EAnd
|
||||||
(OASISExpr.EFlag "lwt",
|
(OASISExpr.EFlag "lwt",
|
||||||
OASISExpr.EFlag "misc"))))),
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "misc",
|
||||||
|
OASISExpr.EFlag "unix")))))),
|
||||||
true)
|
true)
|
||||||
];
|
];
|
||||||
doc_install = [(OASISExpr.EBool true, true)];
|
doc_install = [(OASISExpr.EBool true, true)];
|
||||||
|
|
@ -7648,7 +7671,7 @@ let setup_t =
|
||||||
{exec_custom = false; exec_main_is = "run_benchs.ml"});
|
{exec_custom = false; exec_main_is = "run_benchs.ml"});
|
||||||
Executable
|
Executable
|
||||||
({
|
({
|
||||||
cs_name = "bench_hash";
|
cs_name = "run_bench_hash";
|
||||||
cs_data = PropList.Data.create ();
|
cs_data = PropList.Data.create ();
|
||||||
cs_plugin_data = []
|
cs_plugin_data = []
|
||||||
},
|
},
|
||||||
|
|
@ -7679,7 +7702,7 @@ let setup_t =
|
||||||
bs_byteopt = [(OASISExpr.EBool true, [])];
|
bs_byteopt = [(OASISExpr.EBool true, [])];
|
||||||
bs_nativeopt = [(OASISExpr.EBool true, [])]
|
bs_nativeopt = [(OASISExpr.EBool true, [])]
|
||||||
},
|
},
|
||||||
{exec_custom = false; exec_main_is = "bench_hash.ml"});
|
{exec_custom = false; exec_main_is = "run_bench_hash.ml"});
|
||||||
Executable
|
Executable
|
||||||
({
|
({
|
||||||
cs_name = "run_test_future";
|
cs_name = "run_test_future";
|
||||||
|
|
@ -7772,7 +7795,13 @@ let setup_t =
|
||||||
(OASISExpr.EBool true, false);
|
(OASISExpr.EBool true, false);
|
||||||
(OASISExpr.EAnd
|
(OASISExpr.EAnd
|
||||||
(OASISExpr.EFlag "tests",
|
(OASISExpr.EFlag "tests",
|
||||||
OASISExpr.EFlag "bigarray"),
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "misc",
|
||||||
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "bigarray",
|
||||||
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "unix",
|
||||||
|
OASISExpr.EFlag "advanced")))),
|
||||||
true)
|
true)
|
||||||
];
|
];
|
||||||
bs_install = [(OASISExpr.EBool true, false)];
|
bs_install = [(OASISExpr.EBool true, false)];
|
||||||
|
|
@ -7788,8 +7817,10 @@ let setup_t =
|
||||||
InternalLibrary "containers_advanced";
|
InternalLibrary "containers_advanced";
|
||||||
InternalLibrary "containers_sexp";
|
InternalLibrary "containers_sexp";
|
||||||
InternalLibrary "containers_bigarray";
|
InternalLibrary "containers_bigarray";
|
||||||
|
InternalLibrary "containers_unix";
|
||||||
FindlibPackage ("sequence", None);
|
FindlibPackage ("sequence", None);
|
||||||
FindlibPackage ("gen", None);
|
FindlibPackage ("gen", None);
|
||||||
|
FindlibPackage ("unix", None);
|
||||||
FindlibPackage ("oUnit", None);
|
FindlibPackage ("oUnit", None);
|
||||||
FindlibPackage ("QTest2Lib", None)
|
FindlibPackage ("QTest2Lib", None)
|
||||||
];
|
];
|
||||||
|
|
@ -7908,7 +7939,13 @@ let setup_t =
|
||||||
(OASISExpr.EFlag "tests",
|
(OASISExpr.EFlag "tests",
|
||||||
OASISExpr.EAnd
|
OASISExpr.EAnd
|
||||||
(OASISExpr.EFlag "tests",
|
(OASISExpr.EFlag "tests",
|
||||||
OASISExpr.EFlag "misc")),
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "misc",
|
||||||
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "unix",
|
||||||
|
OASISExpr.EAnd
|
||||||
|
(OASISExpr.EFlag "advanced",
|
||||||
|
OASISExpr.EFlag "bigarray"))))),
|
||||||
true)
|
true)
|
||||||
];
|
];
|
||||||
test_tools =
|
test_tools =
|
||||||
|
|
@ -8063,7 +8100,8 @@ let setup_t =
|
||||||
};
|
};
|
||||||
oasis_fn = Some "_oasis";
|
oasis_fn = Some "_oasis";
|
||||||
oasis_version = "0.4.5";
|
oasis_version = "0.4.5";
|
||||||
oasis_digest = Some "\180\018\197c\134\002\173(\245'\138\144\0262\197z";
|
oasis_digest =
|
||||||
|
Some "Q\133\224\006'\239^\194\020\007 \247\168\220\142\188";
|
||||||
oasis_exec = None;
|
oasis_exec = None;
|
||||||
oasis_setup_args = [];
|
oasis_setup_args = [];
|
||||||
setup_update = false
|
setup_update = false
|
||||||
|
|
@ -8071,6 +8109,6 @@ let setup_t =
|
||||||
|
|
||||||
let setup () = BaseSetup.setup setup_t;;
|
let setup () = BaseSetup.setup setup_t;;
|
||||||
|
|
||||||
# 8075 "setup.ml"
|
# 8113 "setup.ml"
|
||||||
(* OASIS_STOP *)
|
(* OASIS_STOP *)
|
||||||
let () = setup ();;
|
let () = setup ();;
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,12 @@ val wrap3 : ('a -> 'b -> 'c -> 'd) -> 'a -> 'b -> 'c -> ('d, exn) t
|
||||||
(** {2 Applicative} *)
|
(** {2 Applicative} *)
|
||||||
|
|
||||||
val pure : 'a -> ('a, 'err) t
|
val pure : 'a -> ('a, 'err) t
|
||||||
|
(** Synonym of {!return} *)
|
||||||
|
|
||||||
val (<*>) : ('a -> 'b, 'err) t -> ('a, 'err) t -> ('b, 'err) t
|
val (<*>) : ('a -> 'b, 'err) t -> ('a, 'err) t -> ('b, 'err) t
|
||||||
|
(** [a <*> b] evaluates [a] and [b], and, in case of success, returns
|
||||||
|
[`Ok (a b)]. Otherwise, it fails, and the error of [a] is chosen
|
||||||
|
over the error of [b] if both fail *)
|
||||||
|
|
||||||
(** {2 Collections} *)
|
(** {2 Collections} *)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,12 @@ let sorted_merge ?(cmp=Pervasives.compare) l1 l2 =
|
||||||
(*$T
|
(*$T
|
||||||
List.sort Pervasives.compare ([(( * )2); ((+)1)] <*> [10;100]) \
|
List.sort Pervasives.compare ([(( * )2); ((+)1)] <*> [10;100]) \
|
||||||
= [11; 20; 101; 200]
|
= [11; 20; 101; 200]
|
||||||
|
sorted_merge [1;1;2] [1;2;3] = [1;1;1;2;2;3]
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(pair (list int) (list int)) (fun (l1,l2) -> \
|
||||||
|
List.length (sorted_merge l1 l2) = List.length l1 + List.length l2)
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let sort_uniq (type elt) ?(cmp=Pervasives.compare) l =
|
let sort_uniq (type elt) ?(cmp=Pervasives.compare) l =
|
||||||
|
|
@ -247,6 +253,56 @@ let sort_uniq (type elt) ?(cmp=Pervasives.compare) l =
|
||||||
sort_uniq [10;10;10;10;1;10] = [1;10]
|
sort_uniq [10;10;10;10;1;10] = [1;10]
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
let uniq_succ ?(eq=(=)) l =
|
||||||
|
let rec f acc l = match l with
|
||||||
|
| [] -> List.rev acc
|
||||||
|
| [x] -> List.rev (x::acc)
|
||||||
|
| x :: ((y :: _) as tail) when eq x y -> f acc tail
|
||||||
|
| x :: tail -> f (x::acc) tail
|
||||||
|
in
|
||||||
|
f [] l
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
uniq_succ [1;1;2;3;1;6;6;4;6;1] = [1;2;3;1;6;4;6;1]
|
||||||
|
*)
|
||||||
|
|
||||||
|
let sorted_merge_uniq ?(cmp=Pervasives.compare) l1 l2 =
|
||||||
|
let push ~cmp acc x = match acc with
|
||||||
|
| [] -> [x]
|
||||||
|
| y :: _ when cmp x y > 0 -> x :: acc
|
||||||
|
| _ -> acc (* duplicate, do not yield *)
|
||||||
|
in
|
||||||
|
let rec recurse ~cmp acc l1 l2 = match l1,l2 with
|
||||||
|
| [], l
|
||||||
|
| l, [] ->
|
||||||
|
let acc = List.fold_left (push ~cmp) acc l in
|
||||||
|
List.rev acc
|
||||||
|
| x1::l1', x2::l2' ->
|
||||||
|
let c = cmp x1 x2 in
|
||||||
|
if c < 0 then recurse ~cmp (push ~cmp acc x1) l1' l2
|
||||||
|
else if c > 0 then recurse ~cmp (push ~cmp acc x2) l1 l2'
|
||||||
|
else recurse ~cmp acc l1 l2' (* drop one of the [x] *)
|
||||||
|
in
|
||||||
|
recurse ~cmp [] l1 l2
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
sorted_merge_uniq [1; 1; 2; 3; 5; 8] [1; 2; 3; 4; 6; 8; 9; 9] = [1;2;3;4;5;6;8;9]
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(list int) (fun l -> \
|
||||||
|
let l = List.sort Pervasives.compare l in \
|
||||||
|
sorted_merge_uniq l [] = uniq_succ l)
|
||||||
|
Q.(list int) (fun l -> \
|
||||||
|
let l = List.sort Pervasives.compare l in \
|
||||||
|
sorted_merge_uniq [] l = uniq_succ l)
|
||||||
|
Q.(pair (list int) (list int)) (fun (l1, l2) -> \
|
||||||
|
let l1 = List.sort Pervasives.compare l1 \
|
||||||
|
and l2 = List.sort Pervasives.compare l2 in \
|
||||||
|
let l3 = sorted_merge_uniq l1 l2 in \
|
||||||
|
uniq_succ l3 = l3)
|
||||||
|
*)
|
||||||
|
|
||||||
let take n l =
|
let take n l =
|
||||||
let rec direct i n l = match l with
|
let rec direct i n l = match l with
|
||||||
| [] -> []
|
| [] -> []
|
||||||
|
|
|
||||||
|
|
@ -118,11 +118,23 @@ val filter_map : ('a -> 'b option) -> 'a t -> 'b t
|
||||||
(** Map and remove elements at the same time *)
|
(** Map and remove elements at the same time *)
|
||||||
|
|
||||||
val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
||||||
(** merges elements from both sorted list, removing duplicates *)
|
(** merges elements from both sorted list *)
|
||||||
|
|
||||||
val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list
|
val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list
|
||||||
(** Sort the list and remove duplicate elements *)
|
(** Sort the list and remove duplicate elements *)
|
||||||
|
|
||||||
|
val sorted_merge_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
||||||
|
(** [sorted_merge_uniq l1 l2] merges the sorted lists [l1] and [l2] and
|
||||||
|
removes duplicates
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val uniq_succ : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list
|
||||||
|
(** [uniq_succ l] removes duplicate elements that occur one next to the other.
|
||||||
|
Examples:
|
||||||
|
[uniq_succ [1;2;1] = [1;2;1]]
|
||||||
|
[uniq_succ [1;1;2] = [1;2]]
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
(** {2 Indices} *)
|
(** {2 Indices} *)
|
||||||
|
|
||||||
module Idx : sig
|
module Idx : sig
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,24 @@ let of_array a =
|
||||||
let to_array s =
|
let to_array s =
|
||||||
Array.init (String.length s) (fun i -> s.[i])
|
Array.init (String.length s) (fun i -> s.[i])
|
||||||
|
|
||||||
|
let lines_gen s = Split.gen_cpy ~by:"\n" s
|
||||||
|
|
||||||
|
let lines s = Split.list_cpy ~by:"\n" s
|
||||||
|
|
||||||
|
let concat_gen ~sep g =
|
||||||
|
let b = Buffer.create 256 in
|
||||||
|
let rec aux ~first () = match g () with
|
||||||
|
| None -> Buffer.contents b
|
||||||
|
| Some s ->
|
||||||
|
if not first then Buffer.add_string b sep;
|
||||||
|
Buffer.add_string b s;
|
||||||
|
aux ~first:false ()
|
||||||
|
in aux ~first:true ()
|
||||||
|
|
||||||
|
let unlines l = String.concat "\n" l
|
||||||
|
|
||||||
|
let unlines_gen g = concat_gen ~sep:"\n" g
|
||||||
|
|
||||||
let pp buf s =
|
let pp buf s =
|
||||||
Buffer.add_char buf '"';
|
Buffer.add_char buf '"';
|
||||||
Buffer.add_string buf s;
|
Buffer.add_string buf s;
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,30 @@ val suffix : suf:string -> string -> bool
|
||||||
not (suffix ~suf:"abcd" "cd")
|
not (suffix ~suf:"abcd" "cd")
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
val lines : string -> string list
|
||||||
|
(** [lines s] returns a list of the lines of [s] (splits along '\n')
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val lines_gen : string -> string gen
|
||||||
|
(** [lines_gen s] returns a generator of the lines of [s] (splits along '\n')
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val concat_gen : sep:string -> string gen -> string
|
||||||
|
(** [concat_gen ~sep g] concatenates all strings of [g], separated with [sep].
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val unlines : string list -> string
|
||||||
|
(** [unlines l] concatenates all strings of [l], separated with '\n'
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val unlines_gen : string gen -> string
|
||||||
|
(** [unlines_gen g] concatenates all strings of [g], separated with '\n'
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.printable_string (fun s -> unlines (lines s) = s)
|
||||||
|
*)
|
||||||
|
|
||||||
include S with type t := string
|
include S with type t := string
|
||||||
|
|
||||||
(** {2 Splitting} *)
|
(** {2 Splitting} *)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 71114627b2165c5eaff8d7c614d71974)
|
# DO NOT EDIT (digest: 09a66d8274446aebd1544537d064203d)
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "bytes"
|
requires = "bytes"
|
||||||
archive(byte) = "containers.cma"
|
archive(byte) = "containers.cma"
|
||||||
|
|
@ -8,8 +8,19 @@ archive(byte, plugin) = "containers.cma"
|
||||||
archive(native) = "containers.cmxa"
|
archive(native) = "containers.cmxa"
|
||||||
archive(native, plugin) = "containers.cmxs"
|
archive(native, plugin) = "containers.cmxs"
|
||||||
exists_if = "containers.cma"
|
exists_if = "containers.cma"
|
||||||
|
package "unix" (
|
||||||
|
version = "0.10"
|
||||||
|
description = "A modular standard library focused on data structures."
|
||||||
|
requires = "bytes unix"
|
||||||
|
archive(byte) = "containers_unix.cma"
|
||||||
|
archive(byte, plugin) = "containers_unix.cma"
|
||||||
|
archive(native) = "containers_unix.cmxa"
|
||||||
|
archive(native, plugin) = "containers_unix.cmxs"
|
||||||
|
exists_if = "containers_unix.cma"
|
||||||
|
)
|
||||||
|
|
||||||
package "thread" (
|
package "thread" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "containers threads"
|
requires = "containers threads"
|
||||||
archive(byte) = "containers_thread.cma"
|
archive(byte) = "containers_thread.cma"
|
||||||
|
|
@ -20,8 +31,9 @@ package "thread" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "string" (
|
package "string" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
|
requires = "bytes"
|
||||||
archive(byte) = "containers_string.cma"
|
archive(byte) = "containers_string.cma"
|
||||||
archive(byte, plugin) = "containers_string.cma"
|
archive(byte, plugin) = "containers_string.cma"
|
||||||
archive(native) = "containers_string.cmxa"
|
archive(native) = "containers_string.cmxa"
|
||||||
|
|
@ -30,7 +42,7 @@ package "string" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "sexp" (
|
package "sexp" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "bytes"
|
requires = "bytes"
|
||||||
archive(byte) = "containers_sexp.cma"
|
archive(byte) = "containers_sexp.cma"
|
||||||
|
|
@ -40,19 +52,8 @@ package "sexp" (
|
||||||
exists_if = "containers_sexp.cma"
|
exists_if = "containers_sexp.cma"
|
||||||
)
|
)
|
||||||
|
|
||||||
package "pervasives" (
|
|
||||||
version = "0.9"
|
|
||||||
description = "A modular standard library focused on data structures."
|
|
||||||
requires = "containers"
|
|
||||||
archive(byte) = "containers_pervasives.cma"
|
|
||||||
archive(byte, plugin) = "containers_pervasives.cma"
|
|
||||||
archive(native) = "containers_pervasives.cmxa"
|
|
||||||
archive(native, plugin) = "containers_pervasives.cmxs"
|
|
||||||
exists_if = "containers_pervasives.cma"
|
|
||||||
)
|
|
||||||
|
|
||||||
package "misc" (
|
package "misc" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "containers containers.data"
|
requires = "containers containers.data"
|
||||||
archive(byte) = "containers_misc.cma"
|
archive(byte) = "containers_misc.cma"
|
||||||
|
|
@ -63,7 +64,7 @@ package "misc" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "lwt" (
|
package "lwt" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "containers lwt containers.misc"
|
requires = "containers lwt containers.misc"
|
||||||
archive(byte) = "containers_lwt.cma"
|
archive(byte) = "containers_lwt.cma"
|
||||||
|
|
@ -74,7 +75,7 @@ package "lwt" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "iter" (
|
package "iter" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
archive(byte) = "containers_iter.cma"
|
archive(byte) = "containers_iter.cma"
|
||||||
archive(byte, plugin) = "containers_iter.cma"
|
archive(byte, plugin) = "containers_iter.cma"
|
||||||
|
|
@ -84,7 +85,7 @@ package "iter" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "io" (
|
package "io" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "bytes"
|
requires = "bytes"
|
||||||
archive(byte) = "containers_io.cma"
|
archive(byte) = "containers_io.cma"
|
||||||
|
|
@ -95,7 +96,7 @@ package "io" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "data" (
|
package "data" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "bytes"
|
requires = "bytes"
|
||||||
archive(byte) = "containers_data.cma"
|
archive(byte) = "containers_data.cma"
|
||||||
|
|
@ -106,7 +107,7 @@ package "data" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "bigarray" (
|
package "bigarray" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "containers bigarray bytes"
|
requires = "containers bigarray bytes"
|
||||||
archive(byte) = "containers_bigarray.cma"
|
archive(byte) = "containers_bigarray.cma"
|
||||||
|
|
@ -117,7 +118,7 @@ package "bigarray" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "advanced" (
|
package "advanced" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "A modular standard library focused on data structures."
|
description = "A modular standard library focused on data structures."
|
||||||
requires = "containers sequence"
|
requires = "containers sequence"
|
||||||
archive(byte) = "containers_advanced.cma"
|
archive(byte) = "containers_advanced.cma"
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@ Changed [Opt] to [Option] to better reflect that this module is about the
|
||||||
['a option] type, with [module Option = CCOpt].
|
['a option] type, with [module Option = CCOpt].
|
||||||
|
|
||||||
@since 0.5
|
@since 0.5
|
||||||
|
|
||||||
|
Renamed from [CCPervasives] in [containers.pervasives], to [Containers]
|
||||||
|
in the core library [containers]
|
||||||
|
|
||||||
|
@since 0.10
|
||||||
*)
|
*)
|
||||||
|
|
||||||
module Array = struct
|
module Array = struct
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 5c58c781604360016ba544a7c9d0c597)
|
# DO NOT EDIT (digest: b1fae2373cf2a628a9465ba233f7c127)
|
||||||
CCVector
|
CCVector
|
||||||
CCPrint
|
CCPrint
|
||||||
CCError
|
CCError
|
||||||
|
|
@ -21,4 +21,5 @@ CCString
|
||||||
CCHashtbl
|
CCHashtbl
|
||||||
CCMap
|
CCMap
|
||||||
CCFormat
|
CCFormat
|
||||||
|
Containers
|
||||||
# OASIS_STOP
|
# OASIS_STOP
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 5c58c781604360016ba544a7c9d0c597)
|
# DO NOT EDIT (digest: b1fae2373cf2a628a9465ba233f7c127)
|
||||||
CCVector
|
CCVector
|
||||||
CCPrint
|
CCPrint
|
||||||
CCError
|
CCError
|
||||||
|
|
@ -21,4 +21,5 @@ CCString
|
||||||
CCHashtbl
|
CCHashtbl
|
||||||
CCMap
|
CCMap
|
||||||
CCFormat
|
CCFormat
|
||||||
|
Containers
|
||||||
# OASIS_STOP
|
# OASIS_STOP
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,11 @@ let rec cons : 'a. 'a -> 'a t -> 'a t
|
||||||
| Deep (n,Three (y,z,z'), lazy q', tail) ->
|
| Deep (n,Three (y,z,z'), lazy q', tail) ->
|
||||||
_deep (n+1) (Two (x,y)) (lazy (cons (z,z') q')) tail
|
_deep (n+1) (Two (x,y)) (lazy (cons (z,z') q')) tail
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.pair Q.int (Q.list Q.int)) (fun (x,l) -> \
|
||||||
|
cons x (of_list l) |> to_list = x::l)
|
||||||
|
*)
|
||||||
|
|
||||||
let rec snoc : 'a. 'a t -> 'a -> 'a t
|
let rec snoc : 'a. 'a t -> 'a -> 'a t
|
||||||
= fun q x -> match q with
|
= fun q x -> match q with
|
||||||
| Shallow Zero -> _single x
|
| Shallow Zero -> _single x
|
||||||
|
|
@ -87,6 +92,11 @@ let rec snoc : 'a. 'a t -> 'a -> 'a t
|
||||||
| Deep (n,hd, lazy q', Three (y,z,z')) ->
|
| Deep (n,hd, lazy q', Three (y,z,z')) ->
|
||||||
_deep (n+1) hd (lazy (snoc q' (y,z))) (Two(z',x))
|
_deep (n+1) hd (lazy (snoc q' (y,z))) (Two(z',x))
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.pair Q.int (Q.list Q.int)) (fun (x,l) -> \
|
||||||
|
snoc (of_list l) x |> to_list = l @ [x])
|
||||||
|
*)
|
||||||
|
|
||||||
let rec take_front_exn : 'a. 'a t -> ('a *'a t)
|
let rec take_front_exn : 'a. 'a t -> ('a *'a t)
|
||||||
= fun q -> match q with
|
= fun q -> match q with
|
||||||
| Shallow Zero -> raise Empty
|
| Shallow Zero -> raise Empty
|
||||||
|
|
@ -105,6 +115,12 @@ let rec take_front_exn : 'a. 'a t -> ('a *'a t)
|
||||||
| Deep (n,Three (x,y,z), middle, tail) ->
|
| Deep (n,Three (x,y,z), middle, tail) ->
|
||||||
x, _deep (n-1) (Two(y,z)) middle tail
|
x, _deep (n-1) (Two(y,z)) middle tail
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.pair Q.int (Q.list Q.int)) (fun (x,l) -> \
|
||||||
|
let x', q = cons x (of_list l) |> take_front_exn in \
|
||||||
|
x'=x && to_list q = l)
|
||||||
|
*)
|
||||||
|
|
||||||
let take_front q =
|
let take_front q =
|
||||||
try Some (take_front_exn q)
|
try Some (take_front_exn q)
|
||||||
with Empty -> None
|
with Empty -> None
|
||||||
|
|
@ -117,6 +133,11 @@ let take_front_l n q =
|
||||||
aux (x::acc) q' (n-1)
|
aux (x::acc) q' (n-1)
|
||||||
in aux [] q n
|
in aux [] q n
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
let l, q = take_front_l 5 (1 -- 10) in \
|
||||||
|
l = [1;2;3;4;5] && to_list q = [6;7;8;9;10]
|
||||||
|
*)
|
||||||
|
|
||||||
let take_front_while p q =
|
let take_front_while p q =
|
||||||
let rec aux acc q =
|
let rec aux acc q =
|
||||||
if is_empty q then List.rev acc, q
|
if is_empty q then List.rev acc, q
|
||||||
|
|
@ -125,6 +146,10 @@ let take_front_while p q =
|
||||||
if p x then aux (x::acc) q' else List.rev acc, q
|
if p x then aux (x::acc) q' else List.rev acc, q
|
||||||
in aux [] q
|
in aux [] q
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
take_front_while (fun x-> x<5) (1 -- 10) |> fst = [1;2;3;4]
|
||||||
|
*)
|
||||||
|
|
||||||
let rec take_back_exn : 'a. 'a t -> 'a t * 'a
|
let rec take_back_exn : 'a. 'a t -> 'a t * 'a
|
||||||
= fun q -> match q with
|
= fun q -> match q with
|
||||||
| Shallow Zero -> invalid_arg "FQueue.take_back_exn"
|
| Shallow Zero -> invalid_arg "FQueue.take_back_exn"
|
||||||
|
|
@ -141,6 +166,12 @@ let rec take_back_exn : 'a. 'a t -> 'a t * 'a
|
||||||
| Deep (n, hd, middle, Two(x,y)) -> _deep (n-1) hd middle (One x), y
|
| Deep (n, hd, middle, Two(x,y)) -> _deep (n-1) hd middle (One x), y
|
||||||
| Deep (n, hd, middle, Three(x,y,z)) -> _deep (n-1) hd middle (Two (x,y)), z
|
| Deep (n, hd, middle, Three(x,y,z)) -> _deep (n-1) hd middle (Two (x,y)), z
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.pair Q.int (Q.list Q.int)) (fun (x,l) -> \
|
||||||
|
let q,x' = snoc (of_list l) x |> take_back_exn in \
|
||||||
|
x'=x && to_list q = l)
|
||||||
|
*)
|
||||||
|
|
||||||
let take_back q =
|
let take_back q =
|
||||||
try Some (take_back_exn q)
|
try Some (take_back_exn q)
|
||||||
with Empty -> None
|
with Empty -> None
|
||||||
|
|
@ -186,6 +217,11 @@ let size : 'a. 'a t -> int
|
||||||
| Shallow d -> _size_digit d
|
| Shallow d -> _size_digit d
|
||||||
| Deep (n, _, _, _) -> n
|
| Deep (n, _, _, _) -> n
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
size (of_list l) = List.length l)
|
||||||
|
*)
|
||||||
|
|
||||||
let _nth_digit i d = match i, d with
|
let _nth_digit i d = match i, d with
|
||||||
| _, Zero -> raise Not_found
|
| _, Zero -> raise Not_found
|
||||||
| 0, One x -> x
|
| 0, One x -> x
|
||||||
|
|
@ -228,18 +264,41 @@ let nth i q =
|
||||||
try Some (nth_exn i q)
|
try Some (nth_exn i q)
|
||||||
with Failure _ -> None
|
with Failure _ -> None
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
let len = List.length l in let idx = CCList.(0 -- (len - 1)) in \
|
||||||
|
let q = of_list l in \
|
||||||
|
l = [] || List.for_all (fun i -> nth i q = Some (List.nth l i)) idx)
|
||||||
|
*)
|
||||||
|
|
||||||
let init q =
|
let init q =
|
||||||
try fst (take_back_exn q)
|
try fst (take_back_exn q)
|
||||||
with Empty -> q
|
with Empty -> q
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
l = [] || (of_list l |> init |> to_list = List.rev (List.tl (List.rev l))))
|
||||||
|
*)
|
||||||
|
|
||||||
let tail q =
|
let tail q =
|
||||||
try snd (take_front_exn q)
|
try snd (take_front_exn q)
|
||||||
with Empty -> q
|
with Empty -> q
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
l = [] || (of_list l |> tail |> to_list = List.tl l))
|
||||||
|
*)
|
||||||
|
|
||||||
let add_seq_front seq q =
|
let add_seq_front seq q =
|
||||||
let q = ref q in
|
let l = ref [] in
|
||||||
seq (fun x -> q := cons x !q);
|
(* reversed seq *)
|
||||||
!q
|
seq (fun x -> l := x :: !l);
|
||||||
|
List.fold_left (fun q x -> cons x q) q !l
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(pair (list int) (list int)) (fun (l1, l2) -> \
|
||||||
|
add_seq_front (Sequence.of_list l1) (of_list l2) |> to_list = l1 @ l2)
|
||||||
|
*)
|
||||||
|
|
||||||
let add_seq_back q seq =
|
let add_seq_back q seq =
|
||||||
let q = ref q in
|
let q = ref q in
|
||||||
|
|
@ -260,12 +319,22 @@ let rec to_seq : 'a. 'a t -> 'a sequence
|
||||||
to_seq q' (fun (x,y) -> k x; k y);
|
to_seq q' (fun (x,y) -> k x; k y);
|
||||||
_digit_to_seq tail k
|
_digit_to_seq tail k
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
of_list l |> to_seq |> Sequence.to_list = l)
|
||||||
|
*)
|
||||||
|
|
||||||
let append q1 q2 =
|
let append q1 q2 =
|
||||||
match q1, q2 with
|
match q1, q2 with
|
||||||
| Shallow Zero, _ -> q2
|
| Shallow Zero, _ -> q2
|
||||||
| _, Shallow Zero -> q1
|
| _, Shallow Zero -> q1
|
||||||
| _ -> add_seq_back q1 (to_seq q2)
|
| _ -> add_seq_back q1 (to_seq q2)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.pair (Q.list Q.int)(Q.list Q.int)) (fun (l1,l2) -> \
|
||||||
|
append (of_list l1) (of_list l2) |> to_list = l1 @ l2)
|
||||||
|
*)
|
||||||
|
|
||||||
let _map_digit f d = match d with
|
let _map_digit f d = match d with
|
||||||
| Zero -> Zero
|
| Zero -> Zero
|
||||||
| One x -> One (f x)
|
| One x -> One (f x)
|
||||||
|
|
@ -279,6 +348,11 @@ let rec map : 'a 'b. ('a -> 'b) -> 'a t -> 'b t
|
||||||
let q'' = map (fun (x,y) -> f x, f y) q' in
|
let q'' = map (fun (x,y) -> f x, f y) q' in
|
||||||
_deep size (_map_digit f hd) (Lazy.from_val q'') (_map_digit f tl)
|
_deep size (_map_digit f hd) (Lazy.from_val q'') (_map_digit f tl)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
of_list l |> map string_of_int |> to_list = List.map string_of_int l)
|
||||||
|
*)
|
||||||
|
|
||||||
let (>|=) q f = map f q
|
let (>|=) q f = map f q
|
||||||
|
|
||||||
let _fold_digit f acc d = match d with
|
let _fold_digit f acc d = match d with
|
||||||
|
|
@ -295,6 +369,11 @@ let rec fold : 'a 'b. ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
||||||
let acc = fold (fun acc (x,y) -> f (f acc x) y) acc q' in
|
let acc = fold (fun acc (x,y) -> f (f acc x) y) acc q' in
|
||||||
_fold_digit f acc tl
|
_fold_digit f acc tl
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
of_list l |> fold (fun acc x->x::acc) [] = List.rev l)
|
||||||
|
*)
|
||||||
|
|
||||||
let iter f q = to_seq q f
|
let iter f q = to_seq q f
|
||||||
|
|
||||||
let of_list l = List.fold_left snoc empty l
|
let of_list l = List.fold_left snoc empty l
|
||||||
|
|
@ -304,16 +383,23 @@ let to_list q =
|
||||||
to_seq q (fun x -> l := x :: !l);
|
to_seq q (fun x -> l := x :: !l);
|
||||||
List.rev !l
|
List.rev !l
|
||||||
|
|
||||||
let of_seq seq =
|
let of_seq seq = add_seq_front seq empty
|
||||||
let l = ref [] in
|
|
||||||
seq (fun x -> l := x :: !l);
|
|
||||||
List.fold_left (fun q x -> cons x q) empty !l
|
|
||||||
|
|
||||||
(*$Q
|
(*$Q
|
||||||
(Q.list Q.int) (fun l -> \
|
(Q.list Q.int) (fun l -> \
|
||||||
Sequence.of_list l |> of_seq |> to_list = l)
|
Sequence.of_list l |> of_seq |> to_list = l)
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
let rev q =
|
||||||
|
let q' = ref empty in
|
||||||
|
iter (fun x -> q' := cons x !q') q;
|
||||||
|
!q'
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
(Q.list Q.int) (fun l -> \
|
||||||
|
of_list l |> rev |> to_list = List.rev l)
|
||||||
|
*)
|
||||||
|
|
||||||
let _nil () = `Nil
|
let _nil () = `Nil
|
||||||
let _single x cont () = `Cons (x, cont)
|
let _single x cont () = `Cons (x, cont)
|
||||||
let _double x y cont () = `Cons (x, _single y cont)
|
let _double x y cont () = `Cons (x, _single y cont)
|
||||||
|
|
@ -358,3 +444,24 @@ let rec _equal_klist eq l1 l2 = match l1(), l2() with
|
||||||
eq x1 x2 && _equal_klist eq l1' l2'
|
eq x1 x2 && _equal_klist eq l1' l2'
|
||||||
|
|
||||||
let equal eq q1 q2 = _equal_klist eq (to_klist q1) (to_klist q2)
|
let equal eq q1 q2 = _equal_klist eq (to_klist q1) (to_klist q2)
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
let q1 = 1 -- 10 and q2 = append (1 -- 5) (6 -- 10) in \
|
||||||
|
equal (=) q1 q2
|
||||||
|
*)
|
||||||
|
|
||||||
|
let (--) a b =
|
||||||
|
let rec up_to q a b = if a = b
|
||||||
|
then snoc q a
|
||||||
|
else up_to (snoc q a) (a+1) b
|
||||||
|
and down_to q a b = if a = b then snoc q a
|
||||||
|
else down_to (snoc q a) (a-1) b
|
||||||
|
in
|
||||||
|
if a <= b then up_to empty a b else down_to empty a b
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
1 -- 5 |> to_list = [1;2;3;4;5]
|
||||||
|
5 -- 1 |> to_list = [5;4;3;2;1]
|
||||||
|
0 -- 0 |> to_list = [0]
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,10 +110,15 @@ val append : 'a t -> 'a t -> 'a t
|
||||||
after elements of the first one.
|
after elements of the first one.
|
||||||
Linear in the size of the second queue. *)
|
Linear in the size of the second queue. *)
|
||||||
|
|
||||||
|
val rev : 'a t -> 'a t
|
||||||
|
(** Reverse the queue, O(n) complexity
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val map : ('a -> 'b) -> 'a t -> 'b t
|
val map : ('a -> 'b) -> 'a t -> 'b t
|
||||||
(** Map values *)
|
(** Map values *)
|
||||||
|
|
||||||
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
||||||
|
(** Synonym to {!map} *)
|
||||||
|
|
||||||
val size : 'a t -> int
|
val size : 'a t -> int
|
||||||
(** Number of elements in the queue (constant time) *)
|
(** Number of elements in the queue (constant time) *)
|
||||||
|
|
@ -130,6 +135,7 @@ val of_list : 'a list -> 'a t
|
||||||
val to_list : 'a t -> 'a list
|
val to_list : 'a t -> 'a list
|
||||||
|
|
||||||
val add_seq_front : 'a sequence -> 'a t -> 'a t
|
val add_seq_front : 'a sequence -> 'a t -> 'a t
|
||||||
|
|
||||||
val add_seq_back : 'a t -> 'a sequence -> 'a t
|
val add_seq_back : 'a t -> 'a sequence -> 'a t
|
||||||
|
|
||||||
val to_seq : 'a t -> 'a sequence
|
val to_seq : 'a t -> 'a sequence
|
||||||
|
|
@ -138,3 +144,7 @@ val of_seq : 'a sequence -> 'a t
|
||||||
val to_klist : 'a t -> 'a klist
|
val to_klist : 'a t -> 'a klist
|
||||||
val of_klist : 'a klist -> 'a t
|
val of_klist : 'a klist -> 'a t
|
||||||
|
|
||||||
|
val (--) : int -> int -> int t
|
||||||
|
(** [a -- b] is the integer range from [a] to [b], both included.
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
|
|
||||||
276
src/data/CCIntMap.ml
Normal file
276
src/data/CCIntMap.ml
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 Map specialized for Int keys} *)
|
||||||
|
|
||||||
|
(* "Fast Mergeable Integer Maps", Okasaki & Gill.
|
||||||
|
We use big-endian trees. *)
|
||||||
|
|
||||||
|
type 'a t =
|
||||||
|
| E (* empty *)
|
||||||
|
| L of int * 'a (* leaf *)
|
||||||
|
| N of int (* common prefix *) * int (* bit switch *) * 'a t * 'a t
|
||||||
|
|
||||||
|
let empty = E
|
||||||
|
|
||||||
|
let bit_is_0_ x ~bit = x land bit = 0
|
||||||
|
|
||||||
|
let mask_ x ~mask = (x lor (mask -1)) land (lnot mask)
|
||||||
|
(* low endian: let mask_ x ~mask = x land (mask - 1) *)
|
||||||
|
|
||||||
|
let is_prefix_ ~prefix y ~bit = prefix = mask_ y ~mask:bit
|
||||||
|
|
||||||
|
(* loop down until x=lowest_bit_ x *)
|
||||||
|
let rec highest_bit_naive x m =
|
||||||
|
if m = 0 then 0
|
||||||
|
else if x land m = 0 then highest_bit_naive x (m lsr 1)
|
||||||
|
else m
|
||||||
|
|
||||||
|
let highest_bit =
|
||||||
|
(* the highest representable 2^n *)
|
||||||
|
let max_log = 1 lsl (Sys.word_size - 2) in
|
||||||
|
fun x ->
|
||||||
|
if x > 1 lsl 20
|
||||||
|
then (* small shortcut: remove least significant 20 bits *)
|
||||||
|
let x' = x land (lnot ((1 lsl 20) -1)) in
|
||||||
|
highest_bit_naive x' max_log
|
||||||
|
else highest_bit_naive x max_log
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.int (fun i -> \
|
||||||
|
let b = highest_bit i in \
|
||||||
|
i < 0 || (b <= i && (i-b) < b))
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* helper:
|
||||||
|
|
||||||
|
let b_of_i i =
|
||||||
|
let rec f acc i =
|
||||||
|
if i=0 then acc else let q, r = i/2, i mod 2
|
||||||
|
in
|
||||||
|
f (r::acc) q in f [] i;;
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* low endian: let branching_bit_ a _ b _ = lowest_bit_ (a lxor b) *)
|
||||||
|
let branching_bit_ a b =
|
||||||
|
highest_bit (a lxor b)
|
||||||
|
|
||||||
|
let rec find_exn k t = match t with
|
||||||
|
| E -> raise Not_found
|
||||||
|
| L (k', v) when k = k' -> v
|
||||||
|
| L _ -> raise Not_found
|
||||||
|
| N (prefix, m, l, r) ->
|
||||||
|
if is_prefix_ ~prefix k ~bit:m
|
||||||
|
then if bit_is_0_ k ~bit:m
|
||||||
|
then find_exn k l
|
||||||
|
else find_exn k r
|
||||||
|
else raise Not_found
|
||||||
|
|
||||||
|
(* FIXME: valid if k < 0?
|
||||||
|
if k <= prefix (* search tree *)
|
||||||
|
then find_exn k l
|
||||||
|
else find_exn k r
|
||||||
|
*)
|
||||||
|
|
||||||
|
let find k t =
|
||||||
|
try Some (find_exn k t)
|
||||||
|
with Not_found -> None
|
||||||
|
|
||||||
|
let mem k t =
|
||||||
|
try ignore (find_exn k t); true
|
||||||
|
with Not_found -> false
|
||||||
|
|
||||||
|
let mk_node_ prefix switch l r = match l, r with
|
||||||
|
| E, o | o, E -> o
|
||||||
|
| _ -> N (prefix, switch, l, r)
|
||||||
|
|
||||||
|
(* join trees t1 and t2 with prefix p1 and p2 respectively
|
||||||
|
(p1 and p2 do not overlap) *)
|
||||||
|
let join_ t1 p1 t2 p2 =
|
||||||
|
let switch = branching_bit_ p1 p2 in
|
||||||
|
let prefix = mask_ p1 ~mask:switch in
|
||||||
|
if bit_is_0_ p1 ~bit:switch
|
||||||
|
then mk_node_ prefix switch t1 t2
|
||||||
|
else (assert (bit_is_0_ p2 ~bit:switch); mk_node_ prefix switch t2 t1)
|
||||||
|
|
||||||
|
let singleton k v = L (k, v)
|
||||||
|
|
||||||
|
(* c: conflict function *)
|
||||||
|
let rec insert_ c k v t = match t with
|
||||||
|
| E -> L (k, v)
|
||||||
|
| L (k', v') ->
|
||||||
|
if k=k'
|
||||||
|
then L (k, c ~old:v' v)
|
||||||
|
else join_ t k' (L (k, v)) k
|
||||||
|
| N (prefix, switch, l, r) ->
|
||||||
|
if is_prefix_ ~prefix k ~bit:switch
|
||||||
|
then if bit_is_0_ k ~bit:switch
|
||||||
|
then N(prefix, switch, insert_ c k v l, r)
|
||||||
|
else N(prefix, switch, l, insert_ c k v r)
|
||||||
|
else join_ (L(k,v)) k t prefix
|
||||||
|
|
||||||
|
let add k v t = insert_ (fun ~old:_ v -> v) k v t
|
||||||
|
|
||||||
|
(*$Q & ~count:20
|
||||||
|
Q.(list (pair int int)) (fun l -> \
|
||||||
|
let l = CCList.Set.uniq l in let m = of_list l in \
|
||||||
|
List.for_all (fun (k,v) -> find_exn k m = v) l)
|
||||||
|
*)
|
||||||
|
|
||||||
|
let rec remove k t = match t with
|
||||||
|
| E -> E
|
||||||
|
| L (k', _) -> if k=k' then E else t
|
||||||
|
| N (prefix, switch, l, r) ->
|
||||||
|
if is_prefix_ ~prefix k ~bit:switch
|
||||||
|
then if bit_is_0_ k ~bit:switch
|
||||||
|
then mk_node_ prefix switch (remove k l) r
|
||||||
|
else mk_node_ prefix switch l (remove k r)
|
||||||
|
else t (* not present *)
|
||||||
|
|
||||||
|
let update k f t =
|
||||||
|
try
|
||||||
|
let v = find_exn k t in
|
||||||
|
begin match f (Some v) with
|
||||||
|
| None -> remove k t
|
||||||
|
| Some v' -> add k v' t
|
||||||
|
end
|
||||||
|
with Not_found ->
|
||||||
|
match f None with
|
||||||
|
| None -> t
|
||||||
|
| Some v -> add k v t
|
||||||
|
|
||||||
|
let doubleton k1 v1 k2 v2 = add k1 v1 (singleton k2 v2)
|
||||||
|
|
||||||
|
let rec iter f t = match t with
|
||||||
|
| E -> ()
|
||||||
|
| L (k, v) -> f k v
|
||||||
|
| N (_, _, l, r) -> iter f l; iter f r
|
||||||
|
|
||||||
|
let rec fold f t acc = match t with
|
||||||
|
| E -> acc
|
||||||
|
| L (k, v) -> f k v acc
|
||||||
|
| N (_, _, l, r) ->
|
||||||
|
let acc = fold f l acc in
|
||||||
|
fold f r acc
|
||||||
|
|
||||||
|
let cardinal t = fold (fun _ _ n -> n+1) t 0
|
||||||
|
|
||||||
|
let rec choose_exn = function
|
||||||
|
| E -> raise Not_found
|
||||||
|
| L (k, v) -> k, v
|
||||||
|
| N (_, _, l, _) -> choose_exn l
|
||||||
|
|
||||||
|
let choose t =
|
||||||
|
try Some (choose_exn t)
|
||||||
|
with Not_found -> None
|
||||||
|
|
||||||
|
let rec union f a b = match a, b with
|
||||||
|
| E, o | o, E -> o
|
||||||
|
| L (k, v), o
|
||||||
|
| o, L (k, v) ->
|
||||||
|
(* insert k, v into o *)
|
||||||
|
insert_ (fun ~old v -> f k old v) k v o
|
||||||
|
| N (p1, m1, l1, r1), N (p2, m2, l2, r2) ->
|
||||||
|
if p1 = p2 && m1 = m2
|
||||||
|
then mk_node_ p1 m1 (union f l1 l2) (union f r1 r2)
|
||||||
|
else if m1 < m2 && is_prefix_ ~prefix:p2 p1 ~bit:m1
|
||||||
|
then if bit_is_0_ p2 ~bit:m1
|
||||||
|
then N (p1, m1, union f l1 b, r1)
|
||||||
|
else N (p1, m1, l1, union f r1 b)
|
||||||
|
else if m1 > m2 && is_prefix_ ~prefix:p1 p2 ~bit:m2
|
||||||
|
then if bit_is_0_ p1 ~bit:m2
|
||||||
|
then N (p2, m2, union f l2 a, r2)
|
||||||
|
else N (p2, m2, l2, union f r2 a)
|
||||||
|
else join_ a p1 b p2
|
||||||
|
|
||||||
|
let rec inter f a b = match a, b with
|
||||||
|
| E, _ | _, E -> E
|
||||||
|
| L (k, v), o
|
||||||
|
| o, L (k, v) ->
|
||||||
|
begin try
|
||||||
|
let v' = find_exn k o in
|
||||||
|
L (k, f k v v')
|
||||||
|
with Not_found -> E
|
||||||
|
end
|
||||||
|
| N (p1, m1, l1, r1), N (p2, m2, l2, r2) ->
|
||||||
|
if p1 = p2 && m1 = m2
|
||||||
|
then mk_node_ p1 m1 (inter f l1 l2) (inter f r1 r2)
|
||||||
|
else if m1 < m2 && is_prefix_ ~prefix:p2 p1 ~bit:m1
|
||||||
|
then if bit_is_0_ p2 ~bit:m1
|
||||||
|
then inter f l1 b
|
||||||
|
else inter f r1 b
|
||||||
|
else if m1 > m2 && is_prefix_ ~prefix:p1 p2 ~bit:m2
|
||||||
|
then if bit_is_0_ p1 ~bit:m2
|
||||||
|
then inter f l2 a
|
||||||
|
else inter f r2 a
|
||||||
|
else E
|
||||||
|
|
||||||
|
(* TODO: write tests *)
|
||||||
|
|
||||||
|
(** {2 Whole-collection operations} *)
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
|
||||||
|
let add_list t l = List.fold_left (fun t (k,v) -> add k v t) t l
|
||||||
|
|
||||||
|
let of_list l = add_list empty l
|
||||||
|
|
||||||
|
let to_list t = fold (fun k v l -> (k,v) :: l) t []
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(list (pair int int)) (fun l -> \
|
||||||
|
let l = List.map (fun (k,v) -> abs k,v) l in \
|
||||||
|
let rec is_sorted = function [] | [_] -> true \
|
||||||
|
| x::y::tail -> x <= y && is_sorted (y::tail) in \
|
||||||
|
of_list l |> to_list |> List.rev_map fst |> is_sorted)
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(list (pair int int)) (fun l -> \
|
||||||
|
of_list l |> cardinal = List.length l)
|
||||||
|
*)
|
||||||
|
|
||||||
|
let add_seq t seq =
|
||||||
|
let t = ref t in
|
||||||
|
seq (fun (k,v) -> t := add k v !t);
|
||||||
|
!t
|
||||||
|
|
||||||
|
let of_seq seq = add_seq empty seq
|
||||||
|
|
||||||
|
let to_seq t yield = iter (fun k v -> yield (k,v)) t
|
||||||
|
|
||||||
|
let keys t yield = iter (fun k _ -> yield k) t
|
||||||
|
|
||||||
|
let values t yield = iter (fun _ v -> yield v) t
|
||||||
|
|
||||||
|
type 'a tree = unit -> [`Nil | `Node of 'a * 'a tree list]
|
||||||
|
|
||||||
|
let rec as_tree t () = match t with
|
||||||
|
| E -> `Nil
|
||||||
|
| L (k, v) -> `Node (`Leaf (k, v), [])
|
||||||
|
| N (prefix, switch, l, r) ->
|
||||||
|
`Node (`Node (prefix, switch), [as_tree l; as_tree r])
|
||||||
96
src/data/CCIntMap.mli
Normal file
96
src/data/CCIntMap.mli
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 Map specialized for Int keys}
|
||||||
|
|
||||||
|
{b status: unstable}
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
type 'a t
|
||||||
|
|
||||||
|
val empty : 'a t
|
||||||
|
|
||||||
|
val singleton : int -> 'a -> 'a t
|
||||||
|
|
||||||
|
val doubleton : int -> 'a -> int -> 'a -> 'a t
|
||||||
|
|
||||||
|
val mem : int -> _ t -> bool
|
||||||
|
|
||||||
|
val find : int -> 'a t -> 'a option
|
||||||
|
|
||||||
|
val find_exn : int -> 'a t -> 'a
|
||||||
|
(** Same as {!find} but unsafe
|
||||||
|
@raise Not_found if key not present *)
|
||||||
|
|
||||||
|
val add : int -> 'a -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val remove : int -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val update : int -> ('a option -> 'a option) -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val cardinal : _ t -> int
|
||||||
|
|
||||||
|
val iter : (int -> 'a -> unit) -> 'a t -> unit
|
||||||
|
|
||||||
|
val fold : (int -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b
|
||||||
|
|
||||||
|
val choose : 'a t -> (int * 'a) option
|
||||||
|
|
||||||
|
val choose_exn : 'a t -> int * 'a
|
||||||
|
|
||||||
|
val union : (int -> 'a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val inter : (int -> 'a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t
|
||||||
|
|
||||||
|
(** {2 Whole-collection operations} *)
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
|
||||||
|
val add_list : 'a t -> (int * 'a) list -> 'a t
|
||||||
|
|
||||||
|
val of_list : (int * 'a) list -> 'a t
|
||||||
|
|
||||||
|
val to_list : 'a t -> (int * 'a) list
|
||||||
|
|
||||||
|
val add_seq : 'a t -> (int * 'a) sequence -> 'a t
|
||||||
|
|
||||||
|
val of_seq : (int * 'a) sequence -> 'a t
|
||||||
|
|
||||||
|
val to_seq : 'a t -> (int * 'a) sequence
|
||||||
|
|
||||||
|
val keys : _ t -> int sequence
|
||||||
|
|
||||||
|
val values : 'a t -> 'a sequence
|
||||||
|
|
||||||
|
|
||||||
|
(** Helpers *)
|
||||||
|
|
||||||
|
val highest_bit : int -> int
|
||||||
|
|
||||||
|
type 'a tree = unit -> [`Nil | `Node of 'a * 'a tree list]
|
||||||
|
|
||||||
|
val as_tree : 'a t -> [`Node of int * int | `Leaf of int * 'a ] tree
|
||||||
92
src/data/CCPersistentArray.ml
Normal file
92
src/data/CCPersistentArray.ml
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, Guillaume Bury
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
(* Persistent arrays *)
|
||||||
|
|
||||||
|
type 'a t = 'a data ref
|
||||||
|
and 'a data =
|
||||||
|
| Array of 'a array
|
||||||
|
| Diff of int * 'a * 'a t
|
||||||
|
|
||||||
|
let make n a = ref (Array (Array.make n a))
|
||||||
|
let init n f = ref (Array (Array.init n f))
|
||||||
|
|
||||||
|
let rec _reroot t k = match !t with
|
||||||
|
| Array a -> k a
|
||||||
|
| Diff (i, v, t') ->
|
||||||
|
_reroot t' (fun a ->
|
||||||
|
let v' = a.(i) in
|
||||||
|
a.(i) <- v;
|
||||||
|
t := Array a;
|
||||||
|
t' := Diff(i, v', t);
|
||||||
|
k a
|
||||||
|
)
|
||||||
|
|
||||||
|
let reroot t = match !t with
|
||||||
|
| Array a -> a
|
||||||
|
| _ -> _reroot t (fun x -> x)
|
||||||
|
|
||||||
|
let copy t = ref (Array(Array.copy (reroot t)))
|
||||||
|
|
||||||
|
let get t i = match !t with
|
||||||
|
| Array a -> a.(i)
|
||||||
|
| _ -> (reroot t).(i)
|
||||||
|
|
||||||
|
let set t i v =
|
||||||
|
let a = reroot t in
|
||||||
|
let old = a.(i) in
|
||||||
|
a.(i) <- v;
|
||||||
|
let t' = ref (Array a) in
|
||||||
|
t := Diff (i, old, t');
|
||||||
|
t'
|
||||||
|
|
||||||
|
let length t = Array.length (reroot t)
|
||||||
|
|
||||||
|
let map f t = ref (Array (Array.map f (reroot t)))
|
||||||
|
let mapi f t = ref (Array (Array.mapi f (reroot t)))
|
||||||
|
|
||||||
|
let iter f t = Array.iter f (reroot t)
|
||||||
|
let iteri f t = Array.iteri f (reroot t)
|
||||||
|
|
||||||
|
let fold_left f acc t = Array.fold_left f acc (reroot t)
|
||||||
|
let fold_right f t acc = Array.fold_right f (reroot t) acc
|
||||||
|
|
||||||
|
let to_array t = Array.copy (reroot t)
|
||||||
|
let of_array a = init (Array.length a) (fun i -> a.(i))
|
||||||
|
|
||||||
|
let to_list t = Array.to_list (reroot t)
|
||||||
|
let of_list l = ref (Array (Array.of_list l))
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
|
||||||
|
let to_seq a yield = iter yield a
|
||||||
|
|
||||||
|
let of_seq seq =
|
||||||
|
let l = ref [] in
|
||||||
|
seq (fun x -> l := x :: !l);
|
||||||
|
of_list (List.rev !l)
|
||||||
|
|
||||||
|
|
||||||
105
src/data/CCPersistentArray.mli
Normal file
105
src/data/CCPersistentArray.mli
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, Guillaume Bury
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
(** {1 Persistent Arrays}
|
||||||
|
|
||||||
|
From the paper by Jean-Christophe Filliâtre,
|
||||||
|
"A persistent Union-Find data structure", see
|
||||||
|
{{: https://www.lri.fr/~filliatr/ftp/publis/puf-wml07.ps} the ps version}
|
||||||
|
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
type 'a t
|
||||||
|
(** The type of persistent arrays *)
|
||||||
|
|
||||||
|
val make : int -> 'a -> 'a t
|
||||||
|
(** [make n x] returns a persistent array of length n, with [x]. All the
|
||||||
|
elements of this new array are initially physically equal to x
|
||||||
|
(in the sense of the == predicate). Consequently, if x is mutable, it is
|
||||||
|
shared among all elements of the array, and modifying x through one of the
|
||||||
|
array entries will modify all other entries at the same time.
|
||||||
|
@raise Invalid_argument if [n < 0] or [n > Sys.max_array_length].
|
||||||
|
If the value of x is a floating-point number, then the maximum size is
|
||||||
|
only [Sys.max_array_length / 2].*)
|
||||||
|
|
||||||
|
val init : int -> (int -> 'a) -> 'a t
|
||||||
|
(** [make n f] returns a persistent array of length n, with element
|
||||||
|
[i] initialized to the result of [f i].
|
||||||
|
@raise Invalid_argument if [n < 0] or [n > Sys.max_array_length].
|
||||||
|
If the value of x is a floating-point number, then the maximum size is
|
||||||
|
only [Sys.max_array_length / 2].*)
|
||||||
|
|
||||||
|
val get : 'a t -> int -> 'a
|
||||||
|
(** [get a i] Returns the element with index [i] from the array [a].
|
||||||
|
@raise Invalid_argument "index out of bounds" if [n] is outside the
|
||||||
|
range [0] to [Array.length a - 1].*)
|
||||||
|
|
||||||
|
val set : 'a t -> int -> 'a -> 'a t
|
||||||
|
(** [set a i v] sets the element index [i] from the array [a] to [v].
|
||||||
|
@raise Invalid_argument "index out of bounds" if [n] is outside the
|
||||||
|
range [0] to [Array.length a - 1].*)
|
||||||
|
|
||||||
|
val length : 'a t -> int
|
||||||
|
(** Returns the length of the persistent array. *)
|
||||||
|
|
||||||
|
val copy : 'a t -> 'a t
|
||||||
|
(** [copy a] returns a fresh copy of [a]. Both copies are independent. *)
|
||||||
|
|
||||||
|
val map : ('a -> 'b) -> 'a t -> 'b t
|
||||||
|
val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t
|
||||||
|
(** Applies the given function to all elements of the array, and returns
|
||||||
|
a persistent array initialized by the results of f. In the case of [mapi],
|
||||||
|
the function is also given the index of the element.
|
||||||
|
It is equivalent to [fun f t -> init (fun i -> f (get t i))]. *)
|
||||||
|
|
||||||
|
val iter : ('a -> unit) -> 'a t -> unit
|
||||||
|
val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
||||||
|
(** [iter f t] applies function [f] to all elements of the persistent array,
|
||||||
|
in order from element [0] to element [length t - 1]. *)
|
||||||
|
|
||||||
|
val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
||||||
|
val fold_right : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b
|
||||||
|
(** Fold on the elements of the array. *)
|
||||||
|
|
||||||
|
val to_array : 'a t -> 'a array
|
||||||
|
(** [to_array t] returns a mutable copy of [t]. *)
|
||||||
|
|
||||||
|
val of_array : 'a array -> 'a t
|
||||||
|
(** [from_array a] returns an immutable copy of [a]. *)
|
||||||
|
|
||||||
|
val to_list : 'a t -> 'a list
|
||||||
|
(** [to_list t] returns the list of elements in [t]. *)
|
||||||
|
|
||||||
|
val of_list : 'a list -> 'a t
|
||||||
|
(** [of_list l] returns a fresh persistent array containing the elements of [l]. *)
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
|
||||||
|
val to_seq : 'a t -> 'a sequence
|
||||||
|
|
||||||
|
val of_seq : 'a sequence -> 'a t
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 868cf65b04ece1e5b4b46f9a48586507)
|
# DO NOT EDIT (digest: b83e1a21d44ea00373b0dde5cda9eedd)
|
||||||
CCMultiMap
|
CCMultiMap
|
||||||
CCMultiSet
|
CCMultiSet
|
||||||
CCTrie
|
CCTrie
|
||||||
|
|
@ -12,4 +12,6 @@ CCBV
|
||||||
CCMixtbl
|
CCMixtbl
|
||||||
CCMixmap
|
CCMixmap
|
||||||
CCRingBuffer
|
CCRingBuffer
|
||||||
|
CCIntMap
|
||||||
|
CCPersistentArray
|
||||||
# OASIS_STOP
|
# OASIS_STOP
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 868cf65b04ece1e5b4b46f9a48586507)
|
# DO NOT EDIT (digest: b83e1a21d44ea00373b0dde5cda9eedd)
|
||||||
CCMultiMap
|
CCMultiMap
|
||||||
CCMultiSet
|
CCMultiSet
|
||||||
CCTrie
|
CCTrie
|
||||||
|
|
@ -12,4 +12,6 @@ CCBV
|
||||||
CCMixtbl
|
CCMixtbl
|
||||||
CCMixmap
|
CCMixmap
|
||||||
CCRingBuffer
|
CCRingBuffer
|
||||||
|
CCIntMap
|
||||||
|
CCPersistentArray
|
||||||
# OASIS_STOP
|
# OASIS_STOP
|
||||||
|
|
|
||||||
|
|
@ -74,20 +74,20 @@ type ('a, +'perm) t constraint 'perm = [< `r | `w]
|
||||||
|
|
||||||
type ('a, 'perm) pipe = ('a, 'perm) t
|
type ('a, 'perm) pipe = ('a, 'perm) t
|
||||||
|
|
||||||
val keep : _ t -> unit Lwt.t -> unit
|
val keep : (_,_) t -> unit Lwt.t -> unit
|
||||||
(** [keep p fut] adds a pointer from [p] to [fut] so that [fut] is not
|
(** [keep p fut] adds a pointer from [p] to [fut] so that [fut] is not
|
||||||
garbage-collected before [p] *)
|
garbage-collected before [p] *)
|
||||||
|
|
||||||
val is_closed : _ t -> bool
|
val is_closed : (_,_) t -> bool
|
||||||
|
|
||||||
val close : _ t -> unit Lwt.t
|
val close : (_,_) t -> unit Lwt.t
|
||||||
(** [close p] closes [p], which will not accept input anymore.
|
(** [close p] closes [p], which will not accept input anymore.
|
||||||
This sends [`End] to all readers connected to [p] *)
|
This sends [`End] to all readers connected to [p] *)
|
||||||
|
|
||||||
val close_async : _ t -> unit
|
val close_async : (_,_) t -> unit
|
||||||
(** Same as {!close} but closes in the background *)
|
(** Same as {!close} but closes in the background *)
|
||||||
|
|
||||||
val wait : _ t -> unit Lwt.t
|
val wait : (_,_) t -> unit Lwt.t
|
||||||
(** Evaluates once the pipe closes *)
|
(** Evaluates once the pipe closes *)
|
||||||
|
|
||||||
val create : ?max_size:int -> unit -> ('a, 'perm) t
|
val create : ?max_size:int -> unit -> ('a, 'perm) t
|
||||||
|
|
@ -101,7 +101,7 @@ val connect : ?ownership:[`None | `InOwnsOut | `OutOwnsIn] ->
|
||||||
@param own determines which pipes owns which (the owner, when it
|
@param own determines which pipes owns which (the owner, when it
|
||||||
closes, also closes the ownee) *)
|
closes, also closes the ownee) *)
|
||||||
|
|
||||||
val link_close : _ t -> after:_ t -> unit
|
val link_close : (_,_) t -> after:(_,_) t -> unit
|
||||||
(** [link_close p ~after] will close [p] when [after] closes.
|
(** [link_close p ~after] will close [p] when [after] closes.
|
||||||
if [after] is closed already, closes [p] immediately *)
|
if [after] is closed already, closes [p] immediately *)
|
||||||
|
|
||||||
|
|
|
||||||
193
src/misc/backtrack.ml
Normal file
193
src/misc/backtrack.ml
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
|
||||||
|
module type MONAD = sig
|
||||||
|
type 'a t
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
||||||
|
end
|
||||||
|
|
||||||
|
module NonLogical = struct
|
||||||
|
type 'a t = unit -> 'a
|
||||||
|
let return x () = x
|
||||||
|
let (>>=) x f () = let y = x() in f y ()
|
||||||
|
end
|
||||||
|
|
||||||
|
type ('a, 'b) list_view =
|
||||||
|
| Nil of exn
|
||||||
|
| Cons of 'a * 'b
|
||||||
|
|
||||||
|
(** The monad is parametrised in the types of state, environment and
|
||||||
|
writer. *)
|
||||||
|
module type Param = sig
|
||||||
|
(** Read only *)
|
||||||
|
type e
|
||||||
|
(** Write only *)
|
||||||
|
type w
|
||||||
|
(** [w] must be a monoid *)
|
||||||
|
val wunit : w
|
||||||
|
val wprod : w -> w -> w
|
||||||
|
(** Read-write *)
|
||||||
|
type s
|
||||||
|
(** Update-only. Essentially a writer on [u->u]. *)
|
||||||
|
type u
|
||||||
|
(** [u] must be pointed. *)
|
||||||
|
val uunit : u
|
||||||
|
end
|
||||||
|
|
||||||
|
module Logical (P:Param) = struct
|
||||||
|
type state = {
|
||||||
|
e: P.e;
|
||||||
|
w: P.w;
|
||||||
|
s: P.s;
|
||||||
|
u: P.u;
|
||||||
|
}
|
||||||
|
|
||||||
|
type _ t =
|
||||||
|
| Ignore : _ t -> unit t
|
||||||
|
| Return : 'a -> 'a t
|
||||||
|
| Bind : 'a t * ('a -> 'b t) -> 'b t
|
||||||
|
| Map : 'a t * ('a -> 'b) -> 'b t
|
||||||
|
| Get : P.s t
|
||||||
|
| Set : P.s -> unit t
|
||||||
|
| Modify : (P.s -> P.s) -> unit t
|
||||||
|
| Put : P.w -> unit t
|
||||||
|
| Current : P.e t
|
||||||
|
| Local : P.e * 'a t -> 'a t (* local bind *)
|
||||||
|
| Update : (P.u -> P.u) -> unit t
|
||||||
|
| Zero : exn -> 'a t
|
||||||
|
| WithState : state * 'a t -> 'a t (* use other state *)
|
||||||
|
| Plus : 'a t * (exn -> 'a t ) -> 'a t
|
||||||
|
| Split : 'a t -> ('a, exn -> 'a t) list_view t
|
||||||
|
| Once : 'a t -> 'a t (* keep at most one element *)
|
||||||
|
| Break : (exn -> exn option) * 'a t -> 'a t
|
||||||
|
|
||||||
|
let return x = Return x
|
||||||
|
|
||||||
|
let (>>=) x f = Bind (x, f)
|
||||||
|
|
||||||
|
let map f x = match x with
|
||||||
|
| Return x -> return (f x)
|
||||||
|
| Map (y, g) -> Map (y, fun x -> f (g x))
|
||||||
|
| _ -> Map (x, f)
|
||||||
|
|
||||||
|
let rec ignore : type a. a t -> unit t = function
|
||||||
|
| Return _ -> Return ()
|
||||||
|
| Map (x, _) -> ignore x
|
||||||
|
| x -> Ignore x
|
||||||
|
|
||||||
|
let set x = Set x
|
||||||
|
let get = Get
|
||||||
|
let modify f = Modify f
|
||||||
|
let put x = Put x
|
||||||
|
let current = Current
|
||||||
|
let local x y = Local (x, y)
|
||||||
|
let update f = Update f
|
||||||
|
let zero e = Zero e
|
||||||
|
let with_state st x = WithState (st, x)
|
||||||
|
|
||||||
|
let rec plus a f = match a with
|
||||||
|
| Zero e -> f e
|
||||||
|
| Plus (a1, f1) ->
|
||||||
|
plus a1 (fun e -> plus (f1 e) f)
|
||||||
|
| _ -> Plus (a, f)
|
||||||
|
|
||||||
|
let split x = Split x
|
||||||
|
|
||||||
|
let rec once : type a. a t -> a t = function
|
||||||
|
| Zero e -> Zero e
|
||||||
|
| Return x -> Return x
|
||||||
|
| Map (x, f) -> map f (once x)
|
||||||
|
| x -> Once x
|
||||||
|
|
||||||
|
let break f x = Break (f, x)
|
||||||
|
|
||||||
|
type 'a reified =
|
||||||
|
| RNil of exn
|
||||||
|
| RCons of 'a * (exn -> 'a reified)
|
||||||
|
|
||||||
|
let repr r () = match r with
|
||||||
|
| RNil e -> Nil e
|
||||||
|
| RCons (x, f) -> Cons (x, f)
|
||||||
|
|
||||||
|
let cons x cont = Cons (x, cont)
|
||||||
|
let nil e = Nil e
|
||||||
|
|
||||||
|
let rcons x cont = RCons (x, cont)
|
||||||
|
let rnil e = RNil e
|
||||||
|
|
||||||
|
(* TODO: maybe (('a * state), exn -> state -> 'a t) list_view is better
|
||||||
|
for bind and local? *)
|
||||||
|
type 'a splitted = (('a * state), exn -> 'a t) list_view
|
||||||
|
|
||||||
|
let rec run_rec
|
||||||
|
: type a. state -> a t -> a splitted
|
||||||
|
= fun st t -> match t with
|
||||||
|
| Return x -> cons (x, st) zero
|
||||||
|
| Ignore x ->
|
||||||
|
begin match run_rec st x with
|
||||||
|
| Nil e -> Nil e
|
||||||
|
| Cons ((_, st), cont) -> cons ((), st) (fun e -> Ignore (cont e))
|
||||||
|
end
|
||||||
|
| Bind (x,f) ->
|
||||||
|
begin match run_rec st x with
|
||||||
|
| Nil e -> Nil e
|
||||||
|
| Cons ((x, st_x), cont) ->
|
||||||
|
let y = f x in
|
||||||
|
run_rec st_x (plus y (fun e -> with_state st (cont e >>= f)))
|
||||||
|
end
|
||||||
|
| Map (x,f) ->
|
||||||
|
begin match run_rec st x with
|
||||||
|
| Nil e -> Nil e
|
||||||
|
| Cons ((x, st), cont) ->
|
||||||
|
cons (f x, st) (fun e -> map f (cont e))
|
||||||
|
end
|
||||||
|
| Get -> cons (st.s, st) zero
|
||||||
|
| Set s -> cons ((), {st with s}) zero
|
||||||
|
| Modify f ->
|
||||||
|
let st = {st with s = f st.s} in
|
||||||
|
cons ((), st) zero
|
||||||
|
| Put w -> cons ((), {st with w}) zero
|
||||||
|
| Current -> cons (st.e, st) zero
|
||||||
|
| Local (e,x) ->
|
||||||
|
(* bind [st.e = e] in [x], then restore old [e] in each result *)
|
||||||
|
let old_e = st.e in
|
||||||
|
let st' = {st with e} in
|
||||||
|
begin match run_rec st' x with
|
||||||
|
| Nil e -> Nil e
|
||||||
|
| Cons ((x, st''), cont) ->
|
||||||
|
cons (x, {st'' with e=old_e}) (fun e -> assert false) (* TODO: restore old_e*)
|
||||||
|
end
|
||||||
|
| Update f ->
|
||||||
|
let st = {st with u=f st.u} in
|
||||||
|
cons ((), st) zero
|
||||||
|
| WithState (st', x) -> run_rec st' x (* ignore [st] *)
|
||||||
|
| Zero e -> Nil e (* failure *)
|
||||||
|
| Plus (x,cont) ->
|
||||||
|
begin match run_rec st x with
|
||||||
|
| Nil e -> run_rec st (cont e)
|
||||||
|
| Cons ((x, st), cont') ->
|
||||||
|
cons (x, st) (fun e -> plus (cont' e) cont)
|
||||||
|
end
|
||||||
|
| Split x ->
|
||||||
|
begin match run_rec st x with
|
||||||
|
| Nil e -> cons (Nil e, st) zero
|
||||||
|
| Cons ((x, st'), cont) -> cons (cons x cont, st') zero
|
||||||
|
end
|
||||||
|
| Once x ->
|
||||||
|
begin match run_rec st x with
|
||||||
|
| Nil e -> Nil e
|
||||||
|
| Cons ((x, st), _) -> cons (x, st) zero
|
||||||
|
end
|
||||||
|
| Break (f,x) -> assert false (* TODO: ? *)
|
||||||
|
|
||||||
|
let run t e s =
|
||||||
|
let state = {e; s; u=P.uunit; w=P.wunit} in
|
||||||
|
let rec run_list
|
||||||
|
: type a. state -> a t -> (a * state) reified
|
||||||
|
= fun state t -> match run_rec state t with
|
||||||
|
| Nil e -> rnil e
|
||||||
|
| Cons ((x, st), cont) ->
|
||||||
|
rcons (x, st) (fun e -> run_list state (cont e))
|
||||||
|
in
|
||||||
|
run_list state t
|
||||||
|
end
|
||||||
|
|
||||||
88
src/misc/backtrack.mli
Normal file
88
src/misc/backtrack.mli
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
|
||||||
|
(** {1 Experiment with Backtracking Monad}
|
||||||
|
|
||||||
|
Playing stuff, don't use (yet?).
|
||||||
|
|
||||||
|
{b status: experimental}
|
||||||
|
@since 0.10
|
||||||
|
*)
|
||||||
|
|
||||||
|
module type MONAD = sig
|
||||||
|
type 'a t
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
||||||
|
end
|
||||||
|
|
||||||
|
(** Taken from Coq "logic_monad.mli" *)
|
||||||
|
|
||||||
|
module NonLogical : sig
|
||||||
|
type 'a t = unit -> 'a
|
||||||
|
include MONAD with type 'a t := 'a t
|
||||||
|
end
|
||||||
|
|
||||||
|
(** {6 Logical layer} *)
|
||||||
|
(** The logical monad is a backtracking monad on top of which is
|
||||||
|
layered a state monad (which is used to implement all of read/write,
|
||||||
|
read only, and write only effects). The state monad being layered on
|
||||||
|
top of the backtracking monad makes it so that the state is
|
||||||
|
backtracked on failure.
|
||||||
|
Backtracking differs from regular exception in that, writing (+)
|
||||||
|
for exception catching and (>>=) for bind, we require the
|
||||||
|
following extra distributivity laws:
|
||||||
|
x+(y+z) = (x+y)+z
|
||||||
|
zero+x = x
|
||||||
|
x+zero = x
|
||||||
|
(x+y)>>=k = (x>>=k)+(y>>=k) *)
|
||||||
|
(** A view type for the logical monad, which is a form of list, hence
|
||||||
|
we can decompose it with as a list. *)
|
||||||
|
type ('a, 'b) list_view =
|
||||||
|
| Nil of exn
|
||||||
|
| Cons of 'a * 'b
|
||||||
|
|
||||||
|
(** The monad is parametrised in the types of state, environment and
|
||||||
|
writer. *)
|
||||||
|
module type Param = sig
|
||||||
|
(** Read only *)
|
||||||
|
type e
|
||||||
|
(** Write only *)
|
||||||
|
type w
|
||||||
|
(** [w] must be a monoid *)
|
||||||
|
val wunit : w
|
||||||
|
val wprod : w -> w -> w
|
||||||
|
(** Read-write *)
|
||||||
|
type s
|
||||||
|
(** Update-only. Essentially a writer on [u->u]. *)
|
||||||
|
type u
|
||||||
|
(** [u] must be pointed. *)
|
||||||
|
val uunit : u
|
||||||
|
end
|
||||||
|
|
||||||
|
module Logical (P:Param) : sig
|
||||||
|
include MONAD
|
||||||
|
val map : ('a -> 'b) -> 'a t -> 'b t
|
||||||
|
val ignore : 'a t -> unit t
|
||||||
|
val set : P.s -> unit t
|
||||||
|
val get : P.s t
|
||||||
|
val modify : (P.s -> P.s) -> unit t
|
||||||
|
val put : P.w -> unit t
|
||||||
|
val current : P.e t
|
||||||
|
val local : P.e -> 'a t -> 'a t
|
||||||
|
val update : (P.u -> P.u) -> unit t
|
||||||
|
val zero : exn -> 'a t
|
||||||
|
val plus : 'a t -> (exn -> 'a t) -> 'a t
|
||||||
|
val split : 'a t -> (('a,(exn->'a t)) list_view) t
|
||||||
|
val once : 'a t -> 'a t
|
||||||
|
val break : (exn -> exn option) -> 'a t -> 'a t
|
||||||
|
(* val lift : 'a NonLogical.t -> 'a t *)
|
||||||
|
type 'a reified
|
||||||
|
|
||||||
|
type state = {
|
||||||
|
e: P.e;
|
||||||
|
w: P.w;
|
||||||
|
s: P.s;
|
||||||
|
u: P.u;
|
||||||
|
}
|
||||||
|
|
||||||
|
val repr : 'a reified -> ('a, exn -> 'a reified) list_view NonLogical.t
|
||||||
|
val run : 'a t -> P.e -> P.s -> ('a * state) reified
|
||||||
|
end
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 64ac3a98881a419a2ed1f076194542f9)
|
# DO NOT EDIT (digest: a0730df368ed19a3b181d80ccf7985b6)
|
||||||
AbsSet
|
AbsSet
|
||||||
Automaton
|
Automaton
|
||||||
Bij
|
Bij
|
||||||
|
|
@ -13,4 +13,6 @@ RoseTree
|
||||||
SmallSet
|
SmallSet
|
||||||
UnionFind
|
UnionFind
|
||||||
Univ
|
Univ
|
||||||
|
Puf
|
||||||
|
Backtrack
|
||||||
# OASIS_STOP
|
# OASIS_STOP
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ module PArray = struct
|
||||||
a
|
a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let iteri f t = Array.iteri f (reroot t)
|
||||||
|
|
||||||
let get t i =
|
let get t i =
|
||||||
match !t with
|
match !t with
|
||||||
| Array a -> a.(i)
|
| Array a -> a.(i)
|
||||||
|
|
@ -204,6 +206,9 @@ module type S = sig
|
||||||
(** [iter_equiv_class uf a f] calls [f] on every element of [uf] that
|
(** [iter_equiv_class uf a f] calls [f] on every element of [uf] that
|
||||||
is congruent to [a], including [a] itself. *)
|
is congruent to [a], including [a] itself. *)
|
||||||
|
|
||||||
|
val iter : _ t -> (elt -> unit) -> unit
|
||||||
|
(** Iterate on all root values *)
|
||||||
|
|
||||||
val inconsistent : _ t -> (elt * elt * elt * elt) option
|
val inconsistent : _ t -> (elt * elt * elt * elt) option
|
||||||
(** Check whether the UF is inconsistent. It returns [Some (a, b, a', b')]
|
(** Check whether the UF is inconsistent. It returns [Some (a, b, a', b')]
|
||||||
in case of inconsistency, where a = b, a = a' and b = b' by congruence,
|
in case of inconsistency, where a = b, a = a' and b = b' by congruence,
|
||||||
|
|
@ -222,7 +227,8 @@ module type S = sig
|
||||||
|
|
||||||
val explain_distinct : 'e t -> elt -> elt -> elt * elt
|
val explain_distinct : 'e t -> elt -> elt -> elt * elt
|
||||||
(** [explain_distinct uf a b] gives the original pair [a', b'] that
|
(** [explain_distinct uf a b] gives the original pair [a', b'] that
|
||||||
made [a] and [b] distinct by calling [distinct a' b'] *)
|
made [a] and [b] distinct by calling [distinct a' b']. The
|
||||||
|
terms must be distinct, otherwise Failure is raised. *)
|
||||||
end
|
end
|
||||||
|
|
||||||
module IH = Hashtbl.Make(struct type t = int let equal i j = i = j let hash i = i end)
|
module IH = Hashtbl.Make(struct type t = int let equal i j = i = j let hash i = i end)
|
||||||
|
|
@ -446,6 +452,14 @@ module Make(X : ID) : S with type elt = X.t = struct
|
||||||
in
|
in
|
||||||
traverse ia
|
traverse ia
|
||||||
|
|
||||||
|
let iter uf f =
|
||||||
|
PArray.iteri
|
||||||
|
(fun i i' ->
|
||||||
|
if i = i' then match PArray.get uf.data i with
|
||||||
|
| None -> ()
|
||||||
|
| Some d -> f d.elt
|
||||||
|
) uf.parent
|
||||||
|
|
||||||
let inconsistent uf = uf.inconsistent
|
let inconsistent uf = uf.inconsistent
|
||||||
|
|
||||||
(** Closest common ancestor of the two elements in the proof forest *)
|
(** Closest common ancestor of the two elements in the proof forest *)
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,10 @@ module type S = sig
|
||||||
(** [iter_equiv_class uf a f] calls [f] on every element of [uf] that
|
(** [iter_equiv_class uf a f] calls [f] on every element of [uf] that
|
||||||
is congruent to [a], including [a] itself. *)
|
is congruent to [a], including [a] itself. *)
|
||||||
|
|
||||||
|
val iter : _ t -> (elt -> unit) -> unit
|
||||||
|
(** Iterate on all root values
|
||||||
|
@since NExT_RELEASE *)
|
||||||
|
|
||||||
val inconsistent : _ t -> (elt * elt * elt * elt) option
|
val inconsistent : _ t -> (elt * elt * elt * elt) option
|
||||||
(** Check whether the UF is inconsistent. It returns [Some (a, b, a', b')]
|
(** Check whether the UF is inconsistent. It returns [Some (a, b, a', b')]
|
||||||
in case of inconsistency, where a = b, a = a' and b = b' by congruence,
|
in case of inconsistency, where a = b, a = a' and b = b' by congruence,
|
||||||
|
|
|
||||||
835
src/string/app_parse.ml
Normal file
835
src/string/app_parse.ml
Normal file
|
|
@ -0,0 +1,835 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 Applicative Parser Combinators} *)
|
||||||
|
|
||||||
|
type ('a,'b) result = [`Error of 'b | `Ok of 'a]
|
||||||
|
|
||||||
|
type multiplicity =
|
||||||
|
| Star (* 0 or more *)
|
||||||
|
| Plus (* 1 or more *)
|
||||||
|
| Question (* 0 or 1 *)
|
||||||
|
|
||||||
|
let str fmt = Printf.sprintf fmt
|
||||||
|
|
||||||
|
module CharSet = Set.Make(Char)
|
||||||
|
module CharMap = Map.Make(Char)
|
||||||
|
|
||||||
|
let print_char = function
|
||||||
|
| '\t' -> "\\t"
|
||||||
|
| '\n' -> "\\n"
|
||||||
|
| '\r' -> "\\r"
|
||||||
|
| '"' -> "\\\""
|
||||||
|
| c -> str "%c" c
|
||||||
|
|
||||||
|
let print_char_set set =
|
||||||
|
let buf = Buffer.create 32 in
|
||||||
|
Buffer.add_char buf '"';
|
||||||
|
CharSet.iter (fun c -> Buffer.add_string buf (print_char c)) set;
|
||||||
|
Buffer.add_char buf '"';
|
||||||
|
Buffer.contents buf
|
||||||
|
|
||||||
|
let domain_of_char_map m =
|
||||||
|
CharMap.fold (fun c _ set -> CharSet.add c set) m CharSet.empty
|
||||||
|
|
||||||
|
let print_char_map map =
|
||||||
|
let l = CharMap.fold
|
||||||
|
(fun c _ acc -> print_char c :: acc) map [] in
|
||||||
|
String.concat ", " l
|
||||||
|
|
||||||
|
let ppmap ?(sep=", ") pp_k pp_v fmt m =
|
||||||
|
let first = ref true in
|
||||||
|
CharMap.iter
|
||||||
|
(fun k v ->
|
||||||
|
if !first then first := false else Format.pp_print_string fmt sep;
|
||||||
|
pp_k fmt k;
|
||||||
|
Format.pp_print_string fmt " → ";
|
||||||
|
pp_v fmt v;
|
||||||
|
Format.pp_print_cut fmt ()
|
||||||
|
) m;
|
||||||
|
()
|
||||||
|
|
||||||
|
let set_of_string s =
|
||||||
|
let set = ref CharSet.empty in
|
||||||
|
String.iter
|
||||||
|
(fun c ->
|
||||||
|
if CharSet.mem c !set
|
||||||
|
then invalid_arg (str "any_of: duplicate char %c" c);
|
||||||
|
set := CharSet.add c !set
|
||||||
|
) s;
|
||||||
|
!set
|
||||||
|
|
||||||
|
(* add [c -> p] to the map, for every [c] in [set] *)
|
||||||
|
let map_add_set init set p =
|
||||||
|
CharSet.fold
|
||||||
|
(fun c map -> CharMap.add c p map)
|
||||||
|
set init
|
||||||
|
|
||||||
|
(* function composition *)
|
||||||
|
let compose f g x = f (g x)
|
||||||
|
|
||||||
|
let str_of_l l =
|
||||||
|
let b = Bytes.make (List.length l) ' ' in
|
||||||
|
List.iteri (fun i c -> Bytes.set b i c) l;
|
||||||
|
Bytes.unsafe_to_string b
|
||||||
|
|
||||||
|
type 'a t = {
|
||||||
|
mutable st : 'a parse_or_compiled;
|
||||||
|
}
|
||||||
|
|
||||||
|
(* syntactic version *)
|
||||||
|
and _ parse =
|
||||||
|
| Many : 'a t * unit t * multiplicity -> 'a list parse
|
||||||
|
| Skip : 'a t * multiplicity -> unit parse (* same as Many, but ignores *)
|
||||||
|
| Lazy : 'a t lazy_t -> 'a parse
|
||||||
|
|
||||||
|
(* compiled version *)
|
||||||
|
and _ compiled =
|
||||||
|
| C_Return : 'a -> 'a compiled
|
||||||
|
| C_Map : ('a -> 'b) * 'a t -> 'b compiled
|
||||||
|
| C_Filter: ('a -> bool) * 'a t -> 'a compiled
|
||||||
|
| C_App : ('a -> 'b) t * 'a t -> 'b compiled
|
||||||
|
| C_AppLeft : 'a t * 'b t -> 'a compiled
|
||||||
|
| C_AppRight : 'a t * 'b t -> 'b compiled
|
||||||
|
| C_Fail : string -> 'a compiled
|
||||||
|
| C_Int : int compiled
|
||||||
|
| C_Float : float compiled
|
||||||
|
| C_Junk : unit compiled (* ignore next char *)
|
||||||
|
| C_AnyOf : CharSet.t -> char compiled
|
||||||
|
| C_SwitchC : 'a t CharMap.t * 'a t option -> 'a compiled
|
||||||
|
| C_Eof : unit compiled
|
||||||
|
|
||||||
|
and 'a parse_or_compiled =
|
||||||
|
| Parse of 'a parse
|
||||||
|
| Compiled of 'a compiled
|
||||||
|
|
||||||
|
(** {2 Helpers} *)
|
||||||
|
|
||||||
|
(* build a new parser *)
|
||||||
|
let make p = {st=Parse p}
|
||||||
|
let make_c c = {st=Compiled c}
|
||||||
|
let make_pc st = {st}
|
||||||
|
|
||||||
|
let ppmult fmt = function
|
||||||
|
| Star -> Format.pp_print_string fmt "*"
|
||||||
|
| Plus -> Format.pp_print_string fmt "+"
|
||||||
|
| Question -> Format.pp_print_string fmt "?"
|
||||||
|
|
||||||
|
let print fmt p =
|
||||||
|
let depth = ref 0 in
|
||||||
|
(* print up to a given limit into lazy values *)
|
||||||
|
let rec print_aux
|
||||||
|
: type a. Format.formatter -> a t -> unit
|
||||||
|
= fun fmt p ->
|
||||||
|
let ppstr = Format.pp_print_string
|
||||||
|
and ppf fmt x = Format.fprintf fmt x in
|
||||||
|
let ppc fmt c = ppf fmt "'%s'" (print_char c) in
|
||||||
|
match p.st with
|
||||||
|
| Compiled (C_Return _) -> ppstr fmt "<ret>"
|
||||||
|
| Compiled (C_Map (_, x)) -> ppf fmt "@[(map@ %a)@]" print_aux x
|
||||||
|
| Compiled (C_Filter (_, x)) -> ppf fmt "@[(filter@ %a)@]" print_aux x
|
||||||
|
| Compiled (C_App (f, x)) -> ppf fmt "@[<2>@[%a@]@ <*>@ @[%a@]@]" print_aux f print_aux x
|
||||||
|
| Compiled (C_AppLeft (a, b)) -> ppf fmt "@[%a@ <<@ %a@]" print_aux a print_aux b
|
||||||
|
| Compiled (C_AppRight (a, b)) -> ppf fmt "@[%a@ >>@ %a@]" print_aux a print_aux b
|
||||||
|
| Compiled (C_Fail _) -> ppf fmt "<fail>"
|
||||||
|
| Compiled C_Int -> ppstr fmt "<int>"
|
||||||
|
| Compiled C_Float -> ppstr fmt "<float>"
|
||||||
|
| Compiled C_Junk -> ppstr fmt "<junk>"
|
||||||
|
| Compiled (C_AnyOf set) -> ppf fmt "@[(any@ %s)@]" (print_char_set set)
|
||||||
|
| Parse (Many (p, sep, mult)) ->
|
||||||
|
ppf fmt "@[<2>(@[%a@]@ sep:@[%a@])%a@]" print_aux p print_aux sep ppmult mult
|
||||||
|
| Parse (Skip (p, mult)) ->
|
||||||
|
ppf fmt "@[<2>(skip @[%a@]%a)@]" print_aux p ppmult mult
|
||||||
|
| Compiled (C_SwitchC (map, None)) ->
|
||||||
|
ppf fmt "@[<hv2>(switch@ @[%a@])@]" (ppmap ppc print_aux) map
|
||||||
|
| Compiled (C_SwitchC (map, Some o)) ->
|
||||||
|
ppf fmt "@[<hv2>(switch@ @[%a@]@ or:%a)@]" (ppmap ppc print_aux) map print_aux o
|
||||||
|
| Parse (Lazy _) when !depth > 3 -> ppf fmt "<lazy>"
|
||||||
|
| Parse (Lazy (lazy p)) ->
|
||||||
|
incr depth;
|
||||||
|
print_aux fmt p;
|
||||||
|
decr depth
|
||||||
|
| Compiled C_Eof -> ppstr fmt "<eof>"
|
||||||
|
in
|
||||||
|
print_aux fmt p
|
||||||
|
|
||||||
|
let int_first_char = lazy (set_of_string "-0123456789")
|
||||||
|
let float_first_char = lazy (set_of_string ".-0123456789")
|
||||||
|
|
||||||
|
(* a set of characters that are valid as first characters of a parser *)
|
||||||
|
type possible_first_chars =
|
||||||
|
| Set of CharSet.t
|
||||||
|
| AllChars
|
||||||
|
| NoChar
|
||||||
|
| NoCharOrSet of CharSet.t (* either no char, or something starting with set *)
|
||||||
|
| IsFail of string
|
||||||
|
|
||||||
|
let ret_set set = match CharSet.cardinal set with
|
||||||
|
| 0 -> NoChar
|
||||||
|
| 256 -> AllChars
|
||||||
|
| _ -> Set set
|
||||||
|
|
||||||
|
let ret_no_char_or set = match CharSet.cardinal set with
|
||||||
|
| 0 -> NoChar
|
||||||
|
| 256 -> AllChars
|
||||||
|
| _ -> NoCharOrSet set
|
||||||
|
|
||||||
|
(* pfc of parsing a or b *)
|
||||||
|
let union_pfc a b = match a, b with
|
||||||
|
| Set a, Set b -> ret_set (CharSet.union a b)
|
||||||
|
| NoCharOrSet s, Set s'
|
||||||
|
| Set s', NoCharOrSet s -> ret_no_char_or (CharSet.union s s')
|
||||||
|
| NoChar, Set s
|
||||||
|
| Set s, NoChar -> ret_no_char_or s
|
||||||
|
| NoCharOrSet s, NoCharOrSet s' -> ret_no_char_or (CharSet.union s s')
|
||||||
|
| IsFail e, _ | _, IsFail e -> IsFail e
|
||||||
|
| AllChars, _ | _, AllChars -> AllChars
|
||||||
|
| NoChar, o | o, NoChar -> o
|
||||||
|
|
||||||
|
(* pfc of parsing a then b *)
|
||||||
|
let then_pfc a b = match a, b with
|
||||||
|
| Set a, Set b -> ret_set (CharSet.union a b)
|
||||||
|
| NoCharOrSet s, NoCharOrSet s' -> ret_no_char_or (CharSet.union s s')
|
||||||
|
| NoCharOrSet s, Set s' -> ret_set (CharSet.union s s')
|
||||||
|
| NoCharOrSet s, NoChar -> ret_no_char_or s
|
||||||
|
| Set s, _ -> ret_set s
|
||||||
|
| IsFail e, _ | _, IsFail e -> IsFail e
|
||||||
|
| AllChars, _ | _, AllChars -> AllChars
|
||||||
|
| NoChar, o -> o
|
||||||
|
|
||||||
|
let (<|||>) a b = match a with
|
||||||
|
| NoChar -> Lazy.force b
|
||||||
|
| NoCharOrSet _ -> then_pfc a (Lazy.force b)
|
||||||
|
| _ -> a
|
||||||
|
|
||||||
|
(* set of possibilities for the first char of a parser *)
|
||||||
|
let rec pfc : type a. a t -> possible_first_chars = fun t -> pfc_pc t.st
|
||||||
|
|
||||||
|
and pfc_pc
|
||||||
|
: type a. a parse_or_compiled -> possible_first_chars
|
||||||
|
= function
|
||||||
|
| Parse p -> pfc_p p
|
||||||
|
| Compiled c -> pfc_c c
|
||||||
|
|
||||||
|
and pfc_p
|
||||||
|
: type a. a parse -> possible_first_chars
|
||||||
|
= function
|
||||||
|
| Many (p, _, (Question | Star)) -> union_pfc (pfc p) NoChar
|
||||||
|
| Many (p, _, Plus) -> pfc p
|
||||||
|
| Skip (p, (Question | Star)) -> union_pfc (pfc p) NoChar
|
||||||
|
| Skip (p, Plus) -> pfc p
|
||||||
|
| Lazy (lazy p) -> pfc p
|
||||||
|
|
||||||
|
and pfc_c
|
||||||
|
: type a. a compiled -> possible_first_chars
|
||||||
|
= function
|
||||||
|
| C_Return _ -> NoChar
|
||||||
|
| C_Map (_, x) -> pfc x
|
||||||
|
| C_Filter (_, x) -> pfc x
|
||||||
|
| C_App (f, x) -> pfc f <|||> lazy (pfc x)
|
||||||
|
| C_AppLeft (a, b) -> pfc a <|||> lazy (pfc b)
|
||||||
|
| C_AppRight (a, b) -> pfc a <|||> lazy (pfc b)
|
||||||
|
| C_Fail e -> IsFail e
|
||||||
|
| C_Int -> Set (Lazy.force int_first_char)
|
||||||
|
| C_Float -> Set (Lazy.force float_first_char)
|
||||||
|
| C_Junk -> AllChars
|
||||||
|
| C_AnyOf set -> ret_set set
|
||||||
|
| C_SwitchC (map, None) -> ret_set (domain_of_char_map map)
|
||||||
|
| C_SwitchC (map, Some o) ->
|
||||||
|
let s = domain_of_char_map map in
|
||||||
|
union_pfc (ret_set s) (pfc o)
|
||||||
|
| C_Eof -> NoChar
|
||||||
|
|
||||||
|
let possible_first_chars = pfc
|
||||||
|
|
||||||
|
(** {2 Combinators} *)
|
||||||
|
|
||||||
|
let return x = make_c (C_Return x)
|
||||||
|
let pure = return
|
||||||
|
|
||||||
|
let success = pure ()
|
||||||
|
|
||||||
|
let fail msg = make_c (C_Fail msg)
|
||||||
|
|
||||||
|
let junk = make_c C_Junk
|
||||||
|
|
||||||
|
let failf fmt = Printf.ksprintf (fun msg -> fail msg) fmt
|
||||||
|
|
||||||
|
let map f x = match x.st with
|
||||||
|
| Compiled (C_Map (g, y)) -> make_c (C_Map (compose f g, y))
|
||||||
|
| Compiled (C_Return x) -> pure (f x)
|
||||||
|
| _ -> make_c (C_Map (f, x))
|
||||||
|
|
||||||
|
let app f x = match f.st with
|
||||||
|
| Compiled (C_Return f) -> map f x
|
||||||
|
| _ -> make_c (C_App (f, x))
|
||||||
|
|
||||||
|
let fun_and f f' x = f x && f' x
|
||||||
|
|
||||||
|
let filter f x = match x.st with
|
||||||
|
| Compiled (C_Return y) -> if f y then return y else fail "filter failed"
|
||||||
|
| Compiled (C_Filter (f', y)) -> make_c (C_Filter (fun_and f f', y))
|
||||||
|
| _ -> make_c (C_Filter (f, x))
|
||||||
|
|
||||||
|
let app_left a b = make_c (C_AppLeft (a, b)) (* return (fun x y -> x) <*> a <*> b *)
|
||||||
|
|
||||||
|
let app_right a b = make_c (C_AppRight (a, b)) (* return (fun x y -> y) <*> a <*> b *)
|
||||||
|
|
||||||
|
let int = make_c C_Int
|
||||||
|
|
||||||
|
let float = make_c C_Float
|
||||||
|
|
||||||
|
let many ?(sep=success) p = make (Many (p, sep, Star))
|
||||||
|
|
||||||
|
let many1 ?(sep=success) p = make (Many (p, sep, Plus))
|
||||||
|
|
||||||
|
let skip p = make (Skip (p, Star))
|
||||||
|
|
||||||
|
let skip1 p = make (Skip (p, Plus))
|
||||||
|
|
||||||
|
let opt p =
|
||||||
|
map
|
||||||
|
(function
|
||||||
|
| [x] -> Some x
|
||||||
|
| [] -> None
|
||||||
|
| _ -> assert false
|
||||||
|
) (make (Many (p, success, Question)))
|
||||||
|
|
||||||
|
let any_of' s = make_c (C_AnyOf s)
|
||||||
|
let any_of s = any_of' (set_of_string s)
|
||||||
|
|
||||||
|
let char c = any_of' (CharSet.singleton c)
|
||||||
|
|
||||||
|
let spaces = skip (any_of " \t")
|
||||||
|
let spaces1 = skip1 (any_of " \t")
|
||||||
|
|
||||||
|
let white = skip (any_of " \t\n")
|
||||||
|
let white1 = skip1 (any_of " \t\n")
|
||||||
|
|
||||||
|
let alpha_lower_ = set_of_string "abcdefghijklmonpqrstuvwxyz"
|
||||||
|
let alpha_upper_ = set_of_string "ABCDEFGHIJKLMONPQRSTUVWXYZ"
|
||||||
|
let num_ = set_of_string "0123456789"
|
||||||
|
let alpha_ = CharSet.union alpha_lower_ alpha_upper_
|
||||||
|
let symbols_ = set_of_string "|!;$#@%&-_/="
|
||||||
|
|
||||||
|
let alpha_lower = any_of' alpha_lower_
|
||||||
|
let alpha_upper = any_of' alpha_upper_
|
||||||
|
let num = any_of' num_
|
||||||
|
let symbols = any_of' symbols_
|
||||||
|
let alpha = any_of' alpha_
|
||||||
|
let alpha_num = any_of' (CharSet.union num_ alpha_)
|
||||||
|
|
||||||
|
let eof = make_c C_Eof
|
||||||
|
|
||||||
|
let switch_c ?default l =
|
||||||
|
if l = [] then match default with
|
||||||
|
| None -> invalid_arg "switch_c: empty list";
|
||||||
|
| Some d -> d
|
||||||
|
else
|
||||||
|
let map = List.fold_left
|
||||||
|
(fun map (c, t) ->
|
||||||
|
if CharMap.mem c map
|
||||||
|
then invalid_arg (str "switch_c: duplicate char %c" c);
|
||||||
|
CharMap.add c t map
|
||||||
|
) CharMap.empty l
|
||||||
|
in
|
||||||
|
make_c (C_SwitchC (map, default))
|
||||||
|
|
||||||
|
exception ExnIsFail of string
|
||||||
|
|
||||||
|
let make_switch_c a b = make_c (C_SwitchC (a, b))
|
||||||
|
|
||||||
|
(* binary choice: compiled into decision tree *)
|
||||||
|
let rec merge a b =
|
||||||
|
(* build a switch by first char *)
|
||||||
|
try
|
||||||
|
begin match a.st, b.st with
|
||||||
|
| Compiled (C_SwitchC (map_a, def_a)),
|
||||||
|
Compiled (C_SwitchC (map_b, def_b)) ->
|
||||||
|
(* merge jump tables *)
|
||||||
|
let def = match def_a, def_b with
|
||||||
|
| None, None -> None
|
||||||
|
| Some d, None
|
||||||
|
| None, Some d -> Some d
|
||||||
|
| Some _, Some _ ->
|
||||||
|
invalid_arg "choice: ambiguous, several parsers accept any input"
|
||||||
|
in
|
||||||
|
let map = CharMap.merge
|
||||||
|
(fun _ a b -> match a, b with
|
||||||
|
| Some a', Some b' -> Some (merge a' b')
|
||||||
|
| Some m, None
|
||||||
|
| None, Some m -> Some m
|
||||||
|
| None, None -> assert false
|
||||||
|
) map_a map_b
|
||||||
|
in
|
||||||
|
make_switch_c map def
|
||||||
|
| Compiled (C_SwitchC (map, def)), other
|
||||||
|
| other, Compiled (C_SwitchC (map, def)) ->
|
||||||
|
let map', def' = match pfc_pc other, def with
|
||||||
|
| AllChars, _ ->
|
||||||
|
invalid_arg "choice: ambiguous, several parsers accept any input"
|
||||||
|
| NoChar, None -> map, Some (make_pc other)
|
||||||
|
| NoChar, Some _ ->
|
||||||
|
invalid_arg "choice: ambiguous"
|
||||||
|
| IsFail msg, _ -> raise (ExnIsFail msg)
|
||||||
|
| NoCharOrSet set, def
|
||||||
|
| Set set, def ->
|
||||||
|
if CharSet.exists (fun c -> CharMap.mem c map) set
|
||||||
|
then invalid_arg
|
||||||
|
(str "choice: ambiguous parsers (overlap on {%s})"
|
||||||
|
(print_char_set (CharSet.inter set (domain_of_char_map map))));
|
||||||
|
(* else: merge jump tables *)
|
||||||
|
let map = map_add_set map set (make_pc other) in
|
||||||
|
map, def
|
||||||
|
in
|
||||||
|
make_switch_c map' def'
|
||||||
|
| _ ->
|
||||||
|
begin match possible_first_chars a, possible_first_chars b with
|
||||||
|
| (Set set1 | NoCharOrSet set1), (Set set2 | NoCharOrSet set2) ->
|
||||||
|
if CharSet.exists (fun c -> CharSet.mem c set2) set1
|
||||||
|
then invalid_arg
|
||||||
|
(str "choice: ambiguous parsers (overlap on {%s})"
|
||||||
|
(print_char_set (CharSet.inter set1 set2)));
|
||||||
|
let map = map_add_set CharMap.empty set1 a in
|
||||||
|
let map = map_add_set map set2 b in
|
||||||
|
make_switch_c map None
|
||||||
|
| IsFail e, _ | _, IsFail e -> raise (ExnIsFail e)
|
||||||
|
| Set s, NoChar -> make_switch_c (map_add_set CharMap.empty s a) (Some b)
|
||||||
|
| NoChar, Set s -> make_switch_c (map_add_set CharMap.empty s b) (Some a)
|
||||||
|
| AllChars, _ | _, AllChars ->
|
||||||
|
invalid_arg "choice: ambiguous parsers (one accepts everything)"
|
||||||
|
| (NoChar | NoCharOrSet _), (NoChar | NoCharOrSet _) ->
|
||||||
|
invalid_arg "choice: ambiguous parsers (both accept nothing)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
with ExnIsFail msg -> make_c (C_Fail msg)
|
||||||
|
|
||||||
|
let rec choice = function
|
||||||
|
| [] -> invalid_arg "choice: empty list";
|
||||||
|
| [x] -> x
|
||||||
|
| a :: tl -> merge a (choice tl)
|
||||||
|
|
||||||
|
(* temporary structure for buildings switches *)
|
||||||
|
type 'a trie =
|
||||||
|
| TrieLeaf of 'a t
|
||||||
|
| TrieNode of 'a trie CharMap.t
|
||||||
|
|
||||||
|
let trie_empty = TrieNode CharMap.empty
|
||||||
|
|
||||||
|
let rec parser_of_trie : type a. a trie -> a t = function
|
||||||
|
| TrieLeaf p -> p
|
||||||
|
| TrieNode m ->
|
||||||
|
make_switch_c (CharMap.map parser_of_trie' m) None
|
||||||
|
(* consume next char, then build sub-trie *)
|
||||||
|
and parser_of_trie'
|
||||||
|
: type a. a trie -> a t
|
||||||
|
= fun x -> app_right junk (parser_of_trie x)
|
||||||
|
|
||||||
|
(* build prefix trie *)
|
||||||
|
let switch_s l =
|
||||||
|
if l = [] then invalid_arg "switch_s: empty list";
|
||||||
|
(* add parser p in trie [t], with key slice of [s] starting at [i] *)
|
||||||
|
let rec add_trie t s i p =
|
||||||
|
if i = String.length s
|
||||||
|
then match t with
|
||||||
|
| TrieNode m when CharMap.is_empty m -> TrieLeaf p
|
||||||
|
| TrieNode _ -> invalid_arg (str "key \"%s\" is prefix of another key" s)
|
||||||
|
| TrieLeaf _ -> invalid_arg (str "duplicate key \"%s\"" s)
|
||||||
|
else
|
||||||
|
let c = String.get s i in
|
||||||
|
match t with
|
||||||
|
| TrieLeaf _ ->
|
||||||
|
invalid_arg (str "key \"%s\" is prefixed by another key" s)
|
||||||
|
| TrieNode map ->
|
||||||
|
try
|
||||||
|
let sub = CharMap.find c map in
|
||||||
|
let sub = add_trie sub s (i+1) p in
|
||||||
|
TrieNode (CharMap.add c sub map)
|
||||||
|
with Not_found ->
|
||||||
|
let sub = add_trie trie_empty s (i+1) p in
|
||||||
|
TrieNode (CharMap.add c sub map)
|
||||||
|
in
|
||||||
|
let trie =
|
||||||
|
List.fold_left
|
||||||
|
(fun trie (s, p) ->
|
||||||
|
if s = "" then invalid_arg "switch_s: empty string";
|
||||||
|
add_trie trie s 0 p
|
||||||
|
) trie_empty l
|
||||||
|
in
|
||||||
|
parser_of_trie trie
|
||||||
|
|
||||||
|
let bool =
|
||||||
|
switch_s
|
||||||
|
[ "true", return true
|
||||||
|
; "false", return false
|
||||||
|
]
|
||||||
|
|
||||||
|
let fix f =
|
||||||
|
(* outermost lazy needed for the recursive definition *)
|
||||||
|
let rec r = {
|
||||||
|
st=Parse (Lazy (lazy (f r)));
|
||||||
|
} in
|
||||||
|
r
|
||||||
|
|
||||||
|
module Infix = struct
|
||||||
|
let (>|=) x f = map f x
|
||||||
|
let (<*>) = app
|
||||||
|
let (<<) = app_left
|
||||||
|
let (>>) = app_right
|
||||||
|
let (<+>) a b = choice [a; b]
|
||||||
|
let (<::>) a b = pure (fun x l -> x::l) <*> a <*> b
|
||||||
|
end
|
||||||
|
|
||||||
|
include Infix
|
||||||
|
|
||||||
|
let word =
|
||||||
|
pure (fun c s -> str_of_l (c :: s)) <*> alpha <*> many alpha_num
|
||||||
|
|
||||||
|
let quoted =
|
||||||
|
let q = char '"' in
|
||||||
|
let escaped = char '\\' >> char '"' in
|
||||||
|
let inner = choice [escaped; alpha_num; any_of "()' \t\n|!;$#@%&-_/=~.,:<>[]"] in
|
||||||
|
q >> (many inner >|= str_of_l) << q
|
||||||
|
|
||||||
|
(** {2 Compilation} *)
|
||||||
|
|
||||||
|
let encode_cons x sep tl = pure (fun x _sep tl -> x :: tl) <*> x <*> sep <*> tl
|
||||||
|
|
||||||
|
let encode_many
|
||||||
|
: type a. set:CharSet.t -> p:a t -> self:a list t -> sep:unit t -> a list t
|
||||||
|
= fun ~set ~p ~self ~sep ->
|
||||||
|
let on_success = encode_cons p sep self
|
||||||
|
and on_fail = pure [] in
|
||||||
|
make_switch_c (map_add_set CharMap.empty set on_success) (Some on_fail)
|
||||||
|
|
||||||
|
let encode_opt ~set x =
|
||||||
|
let mk_one x = [x] in
|
||||||
|
let on_success = make_c (C_Map (mk_one, x))
|
||||||
|
and on_fail = pure [] in
|
||||||
|
make_switch_c (map_add_set CharMap.empty set on_success) (Some on_fail)
|
||||||
|
|
||||||
|
let encode_skip
|
||||||
|
: type a. set:CharSet.t -> p:a t -> self:unit t -> unit t
|
||||||
|
= fun ~set ~p ~self ->
|
||||||
|
let on_success = p >> self
|
||||||
|
and on_fail = pure () in
|
||||||
|
make_switch_c (map_add_set CharMap.empty set on_success) (Some on_fail)
|
||||||
|
|
||||||
|
let many_
|
||||||
|
: type a. sep:unit t -> mult:multiplicity -> p:a t -> a list t
|
||||||
|
= fun ~sep ~mult ~p -> match possible_first_chars p with
|
||||||
|
| Set set ->
|
||||||
|
begin match mult with
|
||||||
|
| Star -> fix (fun self -> encode_many ~set ~sep ~p ~self)
|
||||||
|
| Plus -> encode_cons p sep (fix (fun self -> encode_many ~set ~sep ~p ~self))
|
||||||
|
| Question -> encode_opt ~set p
|
||||||
|
end
|
||||||
|
| IsFail msg -> fail msg
|
||||||
|
| NoCharOrSet _ -> invalid_arg (str "many: invalid parser (might not consume input)")
|
||||||
|
| AllChars -> invalid_arg (str "many: invalid parser (always succeeds)")
|
||||||
|
| NoChar -> invalid_arg (str "many: invalid parser (does not consume input)")
|
||||||
|
|
||||||
|
let skip_ : type a. mult:multiplicity -> p:a t -> unit t
|
||||||
|
= fun ~mult ~p -> match possible_first_chars p with
|
||||||
|
| Set set ->
|
||||||
|
begin match mult with
|
||||||
|
| Star -> fix (fun self -> encode_skip ~set ~p ~self)
|
||||||
|
| Plus -> p >> fix (fun self -> encode_skip ~set ~p ~self)
|
||||||
|
| Question -> encode_opt ~set p >> pure ()
|
||||||
|
end
|
||||||
|
| IsFail msg -> fail msg
|
||||||
|
| NoCharOrSet _ -> invalid_arg (str "many: invalid parser (might not consume input)")
|
||||||
|
| AllChars -> invalid_arg (str "skip: invalid parser (always succeeds)")
|
||||||
|
| NoChar -> invalid_arg (str "skip: invalid parser (does not consume input)")
|
||||||
|
|
||||||
|
let rec compile
|
||||||
|
: type a. a t -> a compiled
|
||||||
|
= fun t -> match t.st with
|
||||||
|
| Compiled c -> c (* already compiled *)
|
||||||
|
| Parse (Many (p, sep, mult)) ->
|
||||||
|
let c = compile (many_ ~sep ~mult ~p) in
|
||||||
|
t.st <- Compiled c;
|
||||||
|
c
|
||||||
|
| Parse (Skip (p, mult)) ->
|
||||||
|
let c = compile (skip_ ~mult ~p) in
|
||||||
|
t.st <- Compiled c;
|
||||||
|
c
|
||||||
|
| Parse (Lazy (lazy p)) ->
|
||||||
|
let c = compile p in
|
||||||
|
t.st <- Compiled c;
|
||||||
|
c
|
||||||
|
|
||||||
|
(** {2 Signatures} *)
|
||||||
|
|
||||||
|
type error = {
|
||||||
|
line: int;
|
||||||
|
col: int;
|
||||||
|
msg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let string_of_error e = str "at %d:%d; %s" e.line e.col e.msg
|
||||||
|
|
||||||
|
exception Error of error
|
||||||
|
|
||||||
|
module type S = sig
|
||||||
|
type source
|
||||||
|
(** Source of characters *)
|
||||||
|
|
||||||
|
val parse : source -> 'a t -> ('a, error) result
|
||||||
|
(** Parse the given source using the parser, and returns the parsed value. *)
|
||||||
|
|
||||||
|
val parse': source -> 'a t -> ('a, string) result
|
||||||
|
(** Same as {!parse}, but returns a user-friendly string in case of failure *)
|
||||||
|
|
||||||
|
val parse_exn : source -> 'a t -> 'a
|
||||||
|
(** Unsafe version of {!parse}.
|
||||||
|
@raise Error if parsing fails *)
|
||||||
|
end
|
||||||
|
|
||||||
|
(** {2 Build a parser from a given Monadic Input} *)
|
||||||
|
|
||||||
|
module type INPUT = sig
|
||||||
|
type t
|
||||||
|
|
||||||
|
val read : t -> Bytes.t -> int -> int -> int
|
||||||
|
end
|
||||||
|
|
||||||
|
type token =
|
||||||
|
| Yield of char
|
||||||
|
| EOF
|
||||||
|
|
||||||
|
module type READER = sig
|
||||||
|
type t
|
||||||
|
type source
|
||||||
|
|
||||||
|
val create : source -> t
|
||||||
|
val peek : t -> token (* peek; do not consume *)
|
||||||
|
val next : t -> token (* read and consume *)
|
||||||
|
val junk : t -> unit (* consume last token, obtained with junk *)
|
||||||
|
val line : t -> int
|
||||||
|
val col : t -> int
|
||||||
|
end
|
||||||
|
|
||||||
|
module ReaderOfInput(I : INPUT) : READER with type source = I.t = struct
|
||||||
|
type t = {
|
||||||
|
mutable rline : int;
|
||||||
|
mutable rcol : int;
|
||||||
|
input : I.t;
|
||||||
|
buf : Bytes.t;
|
||||||
|
mutable i : int;
|
||||||
|
mutable len : int;
|
||||||
|
}
|
||||||
|
type source = I.t
|
||||||
|
|
||||||
|
let line t = t.rline
|
||||||
|
let col t = t.rcol
|
||||||
|
|
||||||
|
let create input = {
|
||||||
|
rline=1;
|
||||||
|
rcol=0;
|
||||||
|
input;
|
||||||
|
buf = Bytes.make 1024 ' ';
|
||||||
|
i=1;
|
||||||
|
len=1; (* trick for initialization *)
|
||||||
|
}
|
||||||
|
|
||||||
|
let read_next t =
|
||||||
|
let c = Bytes.get t.buf t.i in
|
||||||
|
t.i <- t.i + 1;
|
||||||
|
if c = '\n' then (
|
||||||
|
t.rcol <- 0;
|
||||||
|
t.rline <- t.rline + 1;
|
||||||
|
) else (
|
||||||
|
t.rcol <- t.rcol + 1
|
||||||
|
);
|
||||||
|
Yield c
|
||||||
|
|
||||||
|
let refill t =
|
||||||
|
t.len <- I.read t.input t.buf 0 (Bytes.length t.buf);
|
||||||
|
t.i <- 0;
|
||||||
|
()
|
||||||
|
|
||||||
|
let next t =
|
||||||
|
if t.len = 0 then EOF
|
||||||
|
else if t.i = t.len
|
||||||
|
then (
|
||||||
|
refill t;
|
||||||
|
if t.len = 0 then EOF else read_next t
|
||||||
|
) else read_next t
|
||||||
|
|
||||||
|
let peek t =
|
||||||
|
if t.i = t.len
|
||||||
|
then refill t;
|
||||||
|
Yield (Bytes.get t.buf t.i)
|
||||||
|
|
||||||
|
let junk t =
|
||||||
|
assert (t.len > 0 && t.i < t.len);
|
||||||
|
t.i <- t.i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
module MakeFromReader(R : READER) : S with type source = R.source = struct
|
||||||
|
type source = R.source
|
||||||
|
|
||||||
|
let error r msg =
|
||||||
|
raise (Error {
|
||||||
|
line = R.line r;
|
||||||
|
col = R.col r;
|
||||||
|
msg;
|
||||||
|
})
|
||||||
|
let errorf r fmt =
|
||||||
|
Printf.ksprintf
|
||||||
|
(fun msg -> error r msg)
|
||||||
|
fmt
|
||||||
|
|
||||||
|
let is_int c = Char.code c >= Char.code '0' && Char.code c <= Char.code '9'
|
||||||
|
let to_int c = Char.code c - Char.code '0'
|
||||||
|
|
||||||
|
let rec parse_int r ~sign i = match R.peek r with
|
||||||
|
| EOF -> i
|
||||||
|
| Yield c when is_int c ->
|
||||||
|
R.junk r;
|
||||||
|
parse_int r ~sign (10 * i + to_int c)
|
||||||
|
| Yield '-' when i = 0 && sign ->
|
||||||
|
(* switch sign: only on first char *)
|
||||||
|
R.junk r;
|
||||||
|
parse_int r ~sign:false 0
|
||||||
|
| _ -> if sign then i else -i
|
||||||
|
|
||||||
|
let parse_float _r _buf = assert false
|
||||||
|
|
||||||
|
let rec parse_rec : type a. R.t -> a t -> a =
|
||||||
|
fun r p -> match compile p with
|
||||||
|
| C_Return x -> x
|
||||||
|
| C_Map (f, x) ->
|
||||||
|
let y = parse_rec r x in
|
||||||
|
f y
|
||||||
|
| C_Filter (f, x) ->
|
||||||
|
let y = parse_rec r x in
|
||||||
|
if f y then y else errorf r "filter failed"
|
||||||
|
| C_App (f, x) ->
|
||||||
|
let f' = parse_rec r f in
|
||||||
|
let x' = parse_rec r x in
|
||||||
|
f' x'
|
||||||
|
| C_AppLeft (a, b) ->
|
||||||
|
let a' = parse_rec r a in
|
||||||
|
let _ = parse_rec r b in
|
||||||
|
a'
|
||||||
|
| C_AppRight (a, b) ->
|
||||||
|
let _ = parse_rec r a in
|
||||||
|
let b' = parse_rec r b in
|
||||||
|
b'
|
||||||
|
| C_Fail msg -> error r msg
|
||||||
|
| C_Int -> parse_int r ~sign:true 0
|
||||||
|
| C_Float -> parse_float r (Buffer.create 8)
|
||||||
|
| C_Junk -> R.junk r
|
||||||
|
| C_AnyOf set ->
|
||||||
|
begin match R.next r with
|
||||||
|
| EOF -> errorf r "expected any of %s, got EOF" (print_char_set set)
|
||||||
|
| Yield c ->
|
||||||
|
if CharSet.mem c set then c
|
||||||
|
else errorf r "expected any of %s, got '%s'" (print_char_set set) (print_char c)
|
||||||
|
end
|
||||||
|
| C_SwitchC (map, def) ->
|
||||||
|
begin match R.peek r with
|
||||||
|
| EOF -> errorf r "expected any of %s, got EOF" (print_char_map map)
|
||||||
|
| Yield c ->
|
||||||
|
begin try
|
||||||
|
let p' = CharMap.find c map in
|
||||||
|
parse_rec r p'
|
||||||
|
with Not_found -> match def with
|
||||||
|
| None ->
|
||||||
|
errorf r "expected any of %s, got %c" (print_char_map map) c
|
||||||
|
| Some d -> parse_rec r d
|
||||||
|
end
|
||||||
|
end
|
||||||
|
| C_Eof ->
|
||||||
|
begin match R.next r with
|
||||||
|
| EOF -> ()
|
||||||
|
| Yield c -> errorf r "expected EOF, got %c" c
|
||||||
|
end
|
||||||
|
|
||||||
|
(* public functions *)
|
||||||
|
let parse_exn src p =
|
||||||
|
let r = R.create src in
|
||||||
|
parse_rec r p
|
||||||
|
|
||||||
|
let parse src p =
|
||||||
|
let r = R.create src in
|
||||||
|
try
|
||||||
|
`Ok (parse_rec r p)
|
||||||
|
with Error e ->
|
||||||
|
`Error e
|
||||||
|
|
||||||
|
let parse' src p = match parse src p with
|
||||||
|
| `Ok x -> `Ok x
|
||||||
|
| `Error e -> `Error (string_of_error e)
|
||||||
|
end
|
||||||
|
|
||||||
|
module Make(I : INPUT) = struct
|
||||||
|
module R = ReaderOfInput(I)
|
||||||
|
include MakeFromReader(R)
|
||||||
|
end
|
||||||
|
|
||||||
|
module Str = MakeFromReader(struct
|
||||||
|
(* reader of string *)
|
||||||
|
type t = {
|
||||||
|
str : string;
|
||||||
|
mutable i : int;
|
||||||
|
mutable rcol : int;
|
||||||
|
mutable rline : int;
|
||||||
|
}
|
||||||
|
type source = string
|
||||||
|
|
||||||
|
let create str = {
|
||||||
|
str;
|
||||||
|
i = 0;
|
||||||
|
rcol = 1;
|
||||||
|
rline = 1;
|
||||||
|
}
|
||||||
|
let line t = t.rline
|
||||||
|
let col t = t.rcol
|
||||||
|
let peek t =
|
||||||
|
if t.i = String.length t.str then EOF else Yield (String.get t.str t.i)
|
||||||
|
let junk t =
|
||||||
|
assert (t.i < String.length t.str);
|
||||||
|
t.i <- t.i + 1
|
||||||
|
let next t =
|
||||||
|
if t.i = String.length t.str then EOF
|
||||||
|
else (
|
||||||
|
let c = String.get t.str t.i in
|
||||||
|
t.i <- t.i + 1;
|
||||||
|
if c = '\n' then (
|
||||||
|
t.rcol <- 1;
|
||||||
|
t.rline <- t.rline + 1
|
||||||
|
) else t.rcol <- t.rcol + 1;
|
||||||
|
Yield c
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
module Chan = Make(struct
|
||||||
|
type t = in_channel
|
||||||
|
let read = input
|
||||||
|
end)
|
||||||
271
src/string/app_parse.mli
Normal file
271
src/string/app_parse.mli
Normal file
|
|
@ -0,0 +1,271 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 Applicative Parser Combinators}
|
||||||
|
|
||||||
|
Example: basic S-expr parser
|
||||||
|
|
||||||
|
{[
|
||||||
|
open Containers_string.App_parse;;
|
||||||
|
|
||||||
|
type sexp = Atom of string | List of sexp list;;
|
||||||
|
|
||||||
|
let mkatom a = Atom a;;
|
||||||
|
let mklist l = List l;;
|
||||||
|
|
||||||
|
let ident_char = alpha_num <+> any_of "|!;$#@%&-_/=*.:~+[]<>'" ;;
|
||||||
|
let ident = many1 ident_char >|= str_of_l ;;
|
||||||
|
let atom = (ident <+> quoted) >|= mkatom ;;
|
||||||
|
|
||||||
|
let sexp = fix (fun sexp ->
|
||||||
|
white >>
|
||||||
|
(atom <+>
|
||||||
|
((char '(' >> many sexp << char ')') >|= mklist)
|
||||||
|
)
|
||||||
|
);;
|
||||||
|
|
||||||
|
Str.parse_exn "(a (b c d) e)" sexp;;
|
||||||
|
|
||||||
|
]}
|
||||||
|
|
||||||
|
{b status: experimental}
|
||||||
|
@since 0.10
|
||||||
|
*)
|
||||||
|
|
||||||
|
type ('a,'b) result = [`Error of 'b | `Ok of 'a]
|
||||||
|
|
||||||
|
type 'a t
|
||||||
|
(** Parser that yields an error or a value of type 'a *)
|
||||||
|
|
||||||
|
(** {6 Combinators} *)
|
||||||
|
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
(** Parser that succeeds with the given value *)
|
||||||
|
|
||||||
|
val pure : 'a -> 'a t
|
||||||
|
(** Synonym to {!return} *)
|
||||||
|
|
||||||
|
val junk : unit t
|
||||||
|
(** Skip next char *)
|
||||||
|
|
||||||
|
val fail : string -> 'a t
|
||||||
|
(** [fail msg] fails with the given error message *)
|
||||||
|
|
||||||
|
val failf : ('a, unit, string, 'b t) format4 -> 'a
|
||||||
|
|
||||||
|
val app : ('a -> 'b) t -> 'a t -> 'b t
|
||||||
|
(** Applicative *)
|
||||||
|
|
||||||
|
val map : ('a -> 'b) -> 'a t -> 'b t
|
||||||
|
(** Map the parsed value *)
|
||||||
|
|
||||||
|
val int : int t
|
||||||
|
(** Parse an integer *)
|
||||||
|
|
||||||
|
val float : float t
|
||||||
|
(** Parse a floating point number *)
|
||||||
|
|
||||||
|
val bool : bool t
|
||||||
|
(** Parse "true" or "false" *)
|
||||||
|
|
||||||
|
val char : char -> char t
|
||||||
|
(** [char c] parses [c] and [c] only *)
|
||||||
|
|
||||||
|
val any_of : string -> char t
|
||||||
|
(** Parse any of the chars present in the given string *)
|
||||||
|
|
||||||
|
val alpha_lower : char t
|
||||||
|
|
||||||
|
val alpha_upper : char t
|
||||||
|
|
||||||
|
val alpha : char t
|
||||||
|
|
||||||
|
val symbols : char t
|
||||||
|
(** symbols, such as "!-=_"... *)
|
||||||
|
|
||||||
|
val num : char t
|
||||||
|
|
||||||
|
val alpha_num : char t
|
||||||
|
|
||||||
|
val word : string t
|
||||||
|
(** [word] parses any identifier not starting with an integer and
|
||||||
|
not containing any whitespace nor delimiter
|
||||||
|
TODO: specify *)
|
||||||
|
|
||||||
|
val quoted : string t
|
||||||
|
(** Quoted string, following OCaml conventions *)
|
||||||
|
|
||||||
|
val str_of_l : char list -> string
|
||||||
|
(** Helper to build strings from lists of chars *)
|
||||||
|
|
||||||
|
val spaces : unit t
|
||||||
|
(** Parse a sequence of ['\t'] and [' '] *)
|
||||||
|
|
||||||
|
val spaces1 : unit t
|
||||||
|
(** Same as {!spaces} but requires at least one space *)
|
||||||
|
|
||||||
|
val white : unit t
|
||||||
|
(** Parse a sequence of ['\t'], ['\n'] and [' '] *)
|
||||||
|
|
||||||
|
val white1 : unit t
|
||||||
|
|
||||||
|
val eof : unit t
|
||||||
|
(** Matches the end of input, fails otherwise *)
|
||||||
|
|
||||||
|
val many : ?sep:unit t -> 'a t -> 'a list t
|
||||||
|
(** 0 or more parsed elements of the given type.
|
||||||
|
@param sep separator between elements of the list (for instance, {!space}) *)
|
||||||
|
|
||||||
|
val many1 : ?sep:unit t -> 'a t -> 'a list t
|
||||||
|
(** Same as {!many}, but needs at least one element *)
|
||||||
|
|
||||||
|
val skip : _ t -> unit t
|
||||||
|
(** Skip 0 or more instances of the given parser *)
|
||||||
|
|
||||||
|
val skip1 : _ t -> unit t
|
||||||
|
|
||||||
|
val opt : 'a t -> 'a option t
|
||||||
|
(** [opt x] tries to parse [x], and returns [None] otherwise *)
|
||||||
|
|
||||||
|
val filter : ('a -> bool) -> 'a t -> 'a t
|
||||||
|
(** [filter f p] parses the same as [p], but fails if the returned value
|
||||||
|
does not satisfy [f] *)
|
||||||
|
|
||||||
|
|
||||||
|
(* TODO: complement operator any_but (all but \, for instance) *)
|
||||||
|
(* TODO: a "if-then-else" combinator (assuming the test has a
|
||||||
|
set of possible first chars) *)
|
||||||
|
|
||||||
|
val switch_c : ?default:'a t -> (char * 'a t) list -> 'a t
|
||||||
|
(** [switch_c l] matches the next char and uses the corresponding parser.
|
||||||
|
Fails if the next char is not in the list, unless default is defined.
|
||||||
|
@param default parser to use if no char matches
|
||||||
|
@raise Invalid_argument if some char occurs several times in [l] *)
|
||||||
|
|
||||||
|
val switch_s : (string * 'a t) list -> 'a t
|
||||||
|
(** [switch_s l] attempts to match matches any of the strings in [l].
|
||||||
|
If one of those strings matches, the corresponding parser
|
||||||
|
is used from now on.
|
||||||
|
@raise Invalid_argument if some string is a prefix of another string,
|
||||||
|
or is empty, or if the list is empty *)
|
||||||
|
|
||||||
|
val choice : 'a t list -> 'a t
|
||||||
|
(** [choice l] chooses between the parsers, unambiguously
|
||||||
|
@raise Invalid_argument if the list is empty, or if some parsers
|
||||||
|
overlap, making the choice ambiguous *)
|
||||||
|
|
||||||
|
val fix : ('a t -> 'a t) -> 'a t
|
||||||
|
(** [fix f] makes a fixpoint *)
|
||||||
|
|
||||||
|
module Infix : sig
|
||||||
|
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
||||||
|
(** Infix version of {!map} *)
|
||||||
|
|
||||||
|
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
||||||
|
(** Synonym to {!app} *)
|
||||||
|
|
||||||
|
val (>>) : _ t -> 'a t -> 'a t
|
||||||
|
(** [a >> b] parses [a], ignores its result, then parses [b] *)
|
||||||
|
|
||||||
|
val (<<) : 'a t -> _ t -> 'a t
|
||||||
|
(** [a << b] parses [a], then [b], and discards [b] to return [a] *)
|
||||||
|
|
||||||
|
val (<+>) : 'a t -> 'a t -> 'a t
|
||||||
|
(** [a <+> b] is [choice [a;b]], a binary choice *)
|
||||||
|
|
||||||
|
val (<::>) : 'a t -> 'a list t -> 'a list t
|
||||||
|
(** [a <::> b] is [app (fun x l -> x::l) a b] *)
|
||||||
|
end
|
||||||
|
|
||||||
|
include module type of Infix
|
||||||
|
|
||||||
|
(** {2 Signatures} *)
|
||||||
|
|
||||||
|
(** {6 Parsing} *)
|
||||||
|
|
||||||
|
type error = {
|
||||||
|
line: int;
|
||||||
|
col: int;
|
||||||
|
msg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
val string_of_error : error -> string
|
||||||
|
|
||||||
|
exception Error of error
|
||||||
|
|
||||||
|
module type S = sig
|
||||||
|
type source
|
||||||
|
(** Source of characters *)
|
||||||
|
|
||||||
|
val parse : source -> 'a t -> ('a, error) result
|
||||||
|
(** Parse the given source using the parser, and returns the parsed value. *)
|
||||||
|
|
||||||
|
val parse': source -> 'a t -> ('a, string) result
|
||||||
|
(** Same as {!parse}, but returns a user-friendly string in case of failure *)
|
||||||
|
|
||||||
|
val parse_exn : source -> 'a t -> 'a
|
||||||
|
(** Unsafe version of {!parse}.
|
||||||
|
@raise Error if parsing fails *)
|
||||||
|
end
|
||||||
|
|
||||||
|
(** {2 Parse} *)
|
||||||
|
|
||||||
|
module type INPUT = sig
|
||||||
|
type t
|
||||||
|
|
||||||
|
val read : t -> Bytes.t -> int -> int -> int
|
||||||
|
end
|
||||||
|
|
||||||
|
module Make(I : INPUT) : S with type source = I.t
|
||||||
|
|
||||||
|
(** {2 Low-level interface} *)
|
||||||
|
|
||||||
|
val print : Format.formatter -> _ t -> unit
|
||||||
|
(** Print a parser structure, for debug purpose *)
|
||||||
|
|
||||||
|
type token =
|
||||||
|
| Yield of char
|
||||||
|
| EOF
|
||||||
|
|
||||||
|
module type READER = sig
|
||||||
|
type t
|
||||||
|
type source (* underlying source *)
|
||||||
|
|
||||||
|
val create : source -> t
|
||||||
|
val peek : t -> token (* peek; do not consume *)
|
||||||
|
val next : t -> token (* read and consume *)
|
||||||
|
val junk : t -> unit (* consume last token, obtained with junk *)
|
||||||
|
val line : t -> int
|
||||||
|
val col : t -> int
|
||||||
|
end
|
||||||
|
|
||||||
|
module MakeFromReader(R : READER) : S with type source = R.source
|
||||||
|
|
||||||
|
(** {2 Defaults} *)
|
||||||
|
|
||||||
|
module Str : S with type source = string
|
||||||
|
|
||||||
|
module Chan : S with type source = in_channel
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: eed887f169b0c8e02f98f97c676f846c)
|
# DO NOT EDIT (digest: 200ff8feb7cb7b8d5e2aea5b7c63241a)
|
||||||
KMP
|
KMP
|
||||||
Levenshtein
|
Levenshtein
|
||||||
|
App_parse
|
||||||
# OASIS_STOP
|
# OASIS_STOP
|
||||||
|
|
|
||||||
2
src/unix/.merlin
Normal file
2
src/unix/.merlin
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
PKG unix
|
||||||
|
REC
|
||||||
115
src/unix/CCUnix.ml
Normal file
115
src/unix/CCUnix.ml
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 High-level Functions on top of Unix} *)
|
||||||
|
|
||||||
|
type 'a or_error = [`Ok of 'a | `Error of string]
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
|
||||||
|
(** {2 Calling Commands} *)
|
||||||
|
|
||||||
|
let int_of_process_status = function
|
||||||
|
| Unix.WEXITED i
|
||||||
|
| Unix.WSIGNALED i
|
||||||
|
| Unix.WSTOPPED i -> i
|
||||||
|
|
||||||
|
let str_exists s p =
|
||||||
|
let rec f s p i =
|
||||||
|
if i = String.length s then false
|
||||||
|
else p s.[i] || f s p (i+1)
|
||||||
|
in
|
||||||
|
f s p 0
|
||||||
|
|
||||||
|
let rec iter_gen f g = match g() with
|
||||||
|
| None -> ()
|
||||||
|
| Some x -> f x; iter_gen f g
|
||||||
|
|
||||||
|
(* print a string, but escaped if required *)
|
||||||
|
let escape_str buf s =
|
||||||
|
if str_exists s
|
||||||
|
(function ' ' | '"' | '\'' | '\n' | '\t'-> true | _ -> false)
|
||||||
|
then (
|
||||||
|
Buffer.add_char buf '\'';
|
||||||
|
String.iter
|
||||||
|
(function
|
||||||
|
| '\'' -> Buffer.add_string buf "''"
|
||||||
|
| c -> Buffer.add_char buf c
|
||||||
|
) s;
|
||||||
|
Buffer.add_char buf '\'';
|
||||||
|
) else Buffer.add_string buf s
|
||||||
|
|
||||||
|
let read_all ?(size=1024) ic =
|
||||||
|
let buf = ref (Bytes.create size) in
|
||||||
|
let len = ref 0 in
|
||||||
|
try
|
||||||
|
while true do
|
||||||
|
(* resize *)
|
||||||
|
if !len = Bytes.length !buf then (
|
||||||
|
buf := Bytes.extend !buf 0 !len;
|
||||||
|
);
|
||||||
|
assert (Bytes.length !buf > !len);
|
||||||
|
let n = input ic !buf !len (Bytes.length !buf - !len) in
|
||||||
|
len := !len + n;
|
||||||
|
if n = 0 then raise Exit; (* exhausted *)
|
||||||
|
done;
|
||||||
|
assert false (* never reached*)
|
||||||
|
with Exit ->
|
||||||
|
Bytes.sub_string !buf 0 !len
|
||||||
|
|
||||||
|
type call_result =
|
||||||
|
< stdout:string;
|
||||||
|
stderr:string;
|
||||||
|
status:Unix.process_status;
|
||||||
|
errcode:int; (** extracted from status *)
|
||||||
|
>
|
||||||
|
|
||||||
|
let kbprintf' buf fmt k = Printf.kbprintf k buf fmt
|
||||||
|
|
||||||
|
let call ?(bufsize=2048) ?(stdin=`Str "") ?(env=[||]) cmd =
|
||||||
|
(* render the command *)
|
||||||
|
let buf = Buffer.create 256 in
|
||||||
|
kbprintf' buf cmd
|
||||||
|
(fun buf ->
|
||||||
|
let cmd = Buffer.contents buf in
|
||||||
|
let oc, ic, errc = Unix.open_process_full cmd env in
|
||||||
|
(* send stdin *)
|
||||||
|
begin match stdin with
|
||||||
|
| `Str s -> output_string ic s
|
||||||
|
| `Gen g -> iter_gen (output_string ic) g
|
||||||
|
end;
|
||||||
|
close_out ic;
|
||||||
|
(* read out and err *)
|
||||||
|
let out = read_all ~size:bufsize oc in
|
||||||
|
let err = read_all ~size:bufsize errc in
|
||||||
|
let status = Unix.close_process_full (oc, ic, errc) in
|
||||||
|
object
|
||||||
|
method stdout = out
|
||||||
|
method stderr = err
|
||||||
|
method status = status
|
||||||
|
method errcode = int_of_process_status status
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
77
src/unix/CCUnix.mli
Normal file
77
src/unix/CCUnix.mli
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 High-level Functions on top of Unix}
|
||||||
|
|
||||||
|
Some useful functions built on top of Unix.
|
||||||
|
|
||||||
|
{b status: unstable}
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
type 'a or_error = [`Ok of 'a | `Error of string]
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
|
||||||
|
(** {2 Calling Commands} *)
|
||||||
|
|
||||||
|
val escape_str : Buffer.t -> string -> unit
|
||||||
|
(** Escape a string so it can be a shell argument.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
CCPrint.sprintf "%a" escape_str "foo" = "foo"
|
||||||
|
CCPrint.sprintf "%a" escape_str "foo bar" = "'foo bar'"
|
||||||
|
CCPrint.sprintf "%a" escape_str "fo'o b'ar" = "'fo''o b''ar'"
|
||||||
|
*)
|
||||||
|
|
||||||
|
type call_result =
|
||||||
|
< stdout:string;
|
||||||
|
stderr:string;
|
||||||
|
status:Unix.process_status;
|
||||||
|
errcode:int; (** extracted from status *)
|
||||||
|
>
|
||||||
|
|
||||||
|
val call : ?bufsize:int ->
|
||||||
|
?stdin:[`Gen of string gen | `Str of string] ->
|
||||||
|
?env:string array ->
|
||||||
|
('a, Buffer.t, unit, call_result) format4 ->
|
||||||
|
'a
|
||||||
|
(** [call cmd] wraps the result of [Unix.open_process_full cmd] into an
|
||||||
|
object. It reads the full stdout and stderr of the subprocess before
|
||||||
|
returning.
|
||||||
|
@param stdin if provided, the generator or string is consumed and fed to
|
||||||
|
the subprocess input channel, which is then closed.
|
||||||
|
@param bufsize buffer size used to read stdout and stderr
|
||||||
|
@param env environment to run the command in
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
(call ~stdin:(`Str "abc") "cat")#stdout = "abc"
|
||||||
|
(call "echo %a" escape_str "a'b'c")#stdout = "abc\n"
|
||||||
|
(call "echo %s" "a'b'c")#stdout = "abc\n"
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4
src/unix/containers_unix.mldylib
Normal file
4
src/unix/containers_unix.mldylib
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# OASIS_START
|
||||||
|
# DO NOT EDIT (digest: cc54fa6ddd5d32bdf577cb187f4cf07c)
|
||||||
|
CCUnix
|
||||||
|
# OASIS_STOP
|
||||||
4
src/unix/containers_unix.mllib
Normal file
4
src/unix/containers_unix.mllib
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# OASIS_START
|
||||||
|
# DO NOT EDIT (digest: cc54fa6ddd5d32bdf577cb187f4cf07c)
|
||||||
|
CCUnix
|
||||||
|
# OASIS_STOP
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
(** Tests for persistent union find *)
|
(** Tests for persistent union find *)
|
||||||
|
|
||||||
open OUnit
|
open OUnit
|
||||||
|
open Containers_misc
|
||||||
|
|
||||||
module P = Puf.Make(struct type t = int let get_id i = i end)
|
module P = Puf.Make(struct type t = int let get_id i = i end)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue