Compare commits

...

1482 commits
0.19 ... main

Author SHA1 Message Date
Simon Cruanes
c1b13f1c7f
feat: add CCAtomic.update_cas
Some checks failed
format / format (push) Has been cancelled
Build and Test / build (push) Has been cancelled
2025-12-08 13:41:29 -05:00
Simon Cruanes
f51b56ffbc
cleanup
Some checks failed
format / format (push) Has been cancelled
Build and Test / build (push) Has been cancelled
2025-11-25 20:38:19 -05:00
Simon Cruanes
02c4d51fd0
chore: CI 2025-11-25 20:12:06 -05:00
Simon Cruanes
7c8adbd9fc
move to ocamlformat 0.27, format code 2025-11-25 20:11:54 -05:00
Simon Cruanes
954ea61d22
doc + benchs 2025-11-25 20:04:47 -05:00
Simon Cruanes
b069461fe2
test: enrich pvec test 2025-11-25 20:01:16 -05:00
Simon Cruanes
f13fb6f471
feat pvec: add flat_map 2025-11-25 19:59:23 -05:00
Simon Cruanes
01402388e4
fix warning 2025-11-25 19:21:11 -05:00
István Donkó
14ad490c7e fix: insert missing symbol into range doc comments
Some checks failed
Build and Test / build (push) Has been cancelled
Build and Test / format (push) Has been cancelled
2025-10-27 12:03:46 -04:00
Simon Cruanes
3b49ad2a4e
Merge pull request #478 from jmid/cbor-roundtrip-prop-patch
Some checks failed
Build and Test / build (push) Has been cancelled
Build and Test / format (push) Has been cancelled
Patch CBor round-trip QCheck test to hold for nan's too
2025-07-11 15:22:25 -04:00
Jan Midtgaard
1a11459991 Auto-format code 2025-07-09 16:06:47 +02:00
Jan Midtgaard
0290aa9754 Use CCList.equal for backward compatibility 2025-07-09 15:48:24 +02:00
Jan Midtgaard
9df429005d Patch CBor roundtrip property to hold for nan's too 2025-07-09 12:25:39 +02:00
Simon Cruanes
99dba20fa6
prepare for 3.16
Some checks failed
Build and Test / build (push) Has been cancelled
Build and Test / format (push) Has been cancelled
2025-05-27 09:22:31 -04:00
Simon Cruanes
f934db1e9c
fix: compat with OCaml 5.4
Some checks are pending
Build and Test / build (push) Waiting to run
Build and Test / format (push) Waiting to run
close #477
2025-05-26 23:44:02 -04:00
Simon Cruanes
14ad8c1f2a
format
Some checks failed
Build and Test / build (push) Has been cancelled
Build and Test / format (push) Has been cancelled
2025-05-06 22:24:04 -04:00
Simon Cruanes
0ff9614520
feat: add containers.leb128 library
adapted from pbrt
2025-05-06 21:53:26 -04:00
Simon Cruanes
ab7d0fcc09
fix: oob(!!) in CCHash.bytes
Some checks are pending
Build and Test / build (push) Waiting to run
Build and Test / format (push) Waiting to run
2025-05-06 10:01:31 -04:00
Simon Cruanes
b55d3cfe6a
tests for hashing strings 2025-05-06 10:01:31 -04:00
Simon Cruanes
4613aafb30
feat: add CCFun.with_return
Some checks failed
Build and Test / build (push) Has been cancelled
Build and Test / format (push) Has been cancelled
2025-02-07 16:57:56 -05:00
Adlertz, Niclas
4294dc7ca3 Add square brackets in comment for CCList.return
Some checks failed
Build and Test / build (push) Has been cancelled
Build and Test / format (push) Has been cancelled
2025-01-28 22:19:11 -05:00
Simon Cruanes
31ad563044
Merge pull request #467 from mobotsar/enrich_char
Additional functions for the `Char` module to check common character properties
2025-01-04 17:09:24 -05:00
Alexander
2dcaa12fb7 Fixed docstring typo. 2025-01-04 11:19:57 -05:00
Alexander
bace9fe209 Fixed tests to work with older OCaml versions that lack String.for_all. 2025-01-04 10:11:03 -05:00
Alexander
1486cbf5a1 Added tests for CCChar predicates. 2025-01-04 10:00:36 -05:00
Alexander
b95e2de65b Added functions to the Char module to check common character properties. 2025-01-04 09:18:51 -05:00
Simon Cruanes
f310bc5771
more CI 2025-01-03 21:22:05 -05:00
Simon Cruanes
6d962a70d0
grr CI 2025-01-03 13:10:23 -05:00
Simon Cruanes
517d4605d5
try to update CI 2025-01-03 12:58:59 -05:00
Simon Cruanes
b0f673fbbb
add more tests for CCString.{r,}take_while 2025-01-03 12:54:01 -05:00
Simon Cruanes
c6f6a012b4
Merge pull request #465 from mobotsar/main
Add `take_while` and `rtake_while` to `CCString`, addressing #463
2025-01-03 12:48:57 -05:00
Alexander Lucas
1e06423e87 Fixed formatting of t_string.ml tests for take_while, etc. 2025-01-01 10:33:05 -05:00
Alexander Lucas
8bb3801a52 Fixed formatting of CCString.rtake_while. 2025-01-01 10:22:42 -05:00
Alexander Lucas
d29ed7ee72 Renamed predicate parameter of take_while, rtake_while from p to f, aligining it with pre-existing drop_while. 2025-01-01 09:55:26 -05:00
Alexander Lucas
330cba94de added tests for take_while, rtake_while. 2025-01-01 09:46:22 -05:00
Alexander Lucas
699b370220 Updated String and StringLabels interfaces to reflect take_while, rtake_while. 2025-01-01 09:34:06 -05:00
mobotsar
85ca948012
Merge branch 'c-cube:main' into main 2025-01-01 09:19:25 -05:00
mobotsar
6c8569a7d9
Update CCString.mli to align parameter names in mli descriptions and implementations. 2025-01-01 00:48:58 -05:00
mobotsar
1498158a4f
Update CCString.mli for take_while, rtake_while 2025-01-01 00:47:17 -05:00
mobotsar
d8c00f96be
Update CCString.ml with take_while, rtake_while
Added two functions to the `CCString` module addressing #463 following the style of `CCString.drop_while` and `CCString.rdrop_while`. Corresponding `CCString.mli` changes to follow.
2025-01-01 00:35:55 -05:00
mobotsar
510db54150 Update CCEither.mli fixing type in docstring
Changed "form OCaml 4.12" to "from OCaml 4.12".
2024-12-31 23:05:02 -05:00
mobotsar
2e8d70f073
Update CCEither.mli fixing type in docstring
Changed "form OCaml 4.12" to "from OCaml 4.12".
2024-12-31 22:25:55 -05:00
Simon Cruanes
2fda76a5f7
factor implem for Vec.{find,find_i} 2024-12-13 00:19:05 -05:00
Simon Cruanes
cad41d70d6
ocamlformat 2024-12-13 00:17:53 -05:00
John Hester
b140a50c46 feat: add CCVector.findi 2024-12-13 00:15:27 -05:00
Simon Cruanes
e1de3da1e3
prepare for 3.15 2024-11-18 12:22:16 -05:00
Simon Cruanes
f02df05b35
additional fix for #454 on OCaml 4.10..4.12 2024-11-18 12:22:16 -05:00
Simon Cruanes
477e9cc7ca
remove warning in tests 2024-11-18 12:22:15 -05:00
Simon Cruanes
921db438f2
chore: in CI, run tests in release profile
this is required to be able to repro #454
2024-11-18 12:22:15 -05:00
Simon Cruanes
303f51f93d
chore: add 4.10 to compat matrix 2024-11-18 12:22:15 -05:00
Simon Cruanes
6dcaddb7c6
fixes and format 2024-11-15 11:02:38 -05:00
seprov
8d8f1d4145
Add split_result (#459)
add `CCList.split_result` (@seprov)
2024-11-15 11:01:20 -05:00
Fardale
9cfedad7ba feat: add pretty printer to CCMultiSet 2024-11-05 18:25:51 +01:00
Simon Cruanes
9bef25b6e2
format 2024-10-02 12:31:53 -04:00
Simon Cruanes
afb93cfc43
Merge pull request #457 from gmevel/linear-heap-building
Improvements to CCHeap
2024-10-02 10:04:42 -04:00
Simon Cruanes
3c530f47f4
Merge branch 'main' into linear-heap-building 2024-10-02 10:04:34 -04:00
Simon Cruanes
3efaa02d9d
update test output 2024-09-17 14:50:42 -04:00
Simon Cruanes
69f0e9b624
test: better regression test for #454 2024-09-17 14:04:09 -04:00
Simon Cruanes
c959e396b3
fix #454: work around a weird miscompilation 2024-09-17 12:51:07 -04:00
Simon Cruanes
6ab811f79b
prepare for 3.14 2024-09-10 08:47:46 -04:00
Simon Cruanes
9f8c2efe64
add missing @since tags 2024-09-03 13:12:12 -04:00
Simon Cruanes
07cfdb0d94
format 2024-09-03 13:11:57 -04:00
Simon Cruanes
5abb63517c
Merge pull request #458 from benbellick/add-predicate-combinator
predicate combinators: and_p and or_p
2024-09-03 13:11:50 -04:00
Benjamin Bellick
c6cb572230 and_p -> and_pred, or_p -> or_pred 2024-09-03 11:59:43 -05:00
Ben Bellick
1dc046c6e9 fix formatting 2024-08-24 10:53:59 -05:00
Ben Bellick
df0e442956 predicate combinators: and_p and or_p 2024-08-24 10:26:01 -05:00
Simon Cruanes
65fc920427
feat pp: add a bunch of extensions
thanks to @grayswandyr
2024-08-19 12:17:58 -04:00
Glen Mével
5d315503e1 CCHeap: building from almost-sorted sequences 2024-08-09 14:46:17 +02:00
Glen Mével
a24e1f7472 doc/CCHeap: fix English, improve wording, add sections 2024-07-31 17:50:35 +02:00
Glen Mével
13db1c31e9 tests/CCHeap: add tests 2024-07-31 16:03:06 +02:00
Glen Mével
92676f5513 tests/CCHeap: reorder tests 2024-07-31 03:27:52 +02:00
Glen Mével
78e67a9f4a tests/CCHeap: improve existing tests
- label all tests
- decouple tests about different heap functions
- random instances now have better coverage of possible cases:
  + more variability in size
    (previously, some tests were limited to a fixed size)
  + high probability of duplicates
    (previously, the probability of duplicates was negligible,
    because elements were drawn uniformly from the full `int` range)
- the test for `of_list, take_exn` is now more precise
  (added a duplicate element)
- the test for `to_list_sorted` is now more precise
  (checks that the resulting list is what we want,
  instead of just checking that it is sorted)
- the test for `filter` is now more precise
  (also checks that no element has been spuriously dropped)
- more uniform style for easier reading, using `|>`
2024-07-31 03:27:52 +02:00
Glen Mével
fdfc806afb CCHeap: avoid boxing in delete_one 2024-07-31 03:27:52 +02:00
Glen Mével
6c810eb83d doc/CCHeap: document (==) for merge 2024-07-31 03:27:52 +02:00
Glen Mével
3f95fd44e6 perf/CCHeap: filter, delete_all in O(n) and ensure (==)
- for `delete_all` this is a bugfix
  (physical equality was documented but not implemented)
- `delete_one` is unchanged, it already had complexity O(n)
  and ensured physical equality
2024-07-31 03:27:49 +02:00
Glen Mével
806bb8c7bc perf/CCHeap: heap building in O(n) 2024-07-31 02:19:33 +02:00
Glen Mével
cc2dd6d829 doc/CCHeap: move filter down 2024-07-27 04:57:43 +02:00
Glen Mével
8349a4d244 doc/CCHeap: fix grammar, improve doc of delete_{one,all} 2024-07-27 04:57:41 +02:00
Glen Mével
793bad1e5b doc/CCHeap: document complexities
Committing to these complexities in documentation is not a constraint
for representation of heaps, because they are achieved by every
well-known representation (for some of them, in amortized time):

https://en.wikipedia.org/wiki/Template:Heap_Running_Times

- `find_min`: O(1)
- `take`: O(log n)
- `insert`: O(log n)
- `merge`: O(log(m+n)) (excepted binary heaps which only achieve O(m+n))
- `add_seq`: O(n log(m+n)) (trivially, by repeated insertion)
  + this can be improved to O(log(m) + n), regardless of the
    representation of heaps (to be done in a later commit)
- `of_seq`: O(n log n) (ditto: can be improved to O(n))

Less trivial:

- `filter`, `delete_{one,all}`:

  + O(n) can be achieved for any reasonable representation of heaps, by
    using `of_seq` and `to_seq` which, as said, can always be made O(n).

  + With the current implementation, it is not obvious, but the
    complexity of `filter` and `delete_all` is Θ(n log n); the
    complexity of `delete_one` is O(n). Indeed, node rebuilding with
    `_make_node` is in O(1), merging is in Θ(log n), and every element
    deletion induces one merge; there are heap instances that achieve
    the worst case Ω(n log n), for instance:

                     x
                    / \
                   x   y
                  / \
                ...  y
                /
               x
              / \
             h   y

    with n/3 occurrences of x, n/3 occurrences of y, a sub-heap h of n/3
    elements, and when y is greater than all elements of h; then,
    deleting all occurrences of x performs the following computation:

        merge (merge (merge (merge h y) …) y) y

    where each `merge` takes time Θ(log n).
2024-07-27 04:55:40 +02:00
Glen Mével
8666faf257 doc/CCHeap: uniformize doc of conversion functions 2024-07-26 22:34:13 +02:00
Glen Mével
6bd5d3aacf doc/CCHeap: reorder conversion functions 2024-07-26 22:17:05 +02:00
Simon Cruanes
02ac5bd78a
add @since tags 2024-07-19 14:06:06 -04:00
Simon Cruanes
cb14c0d04b
format 2024-07-19 14:04:00 -04:00
NoahBatchelor
e933995733
Kleisli Composition Operator and Apply_or Added (#455)
Added the Kleisli composition operator for Option, Result, and CCFun.
2024-07-19 14:03:52 -04:00
Simon Cruanes
60bd3ae1d6 perf: use a monomorphic impl for CCMonomorphic.{min,max}
close #452
2024-07-09 10:13:50 -04:00
Simon Cruanes
99bfa200af
CI: compile on 5.2 2024-05-16 14:21:57 -04:00
Simon Cruanes
944410d3c7
CI: run all tests on linux and various OCaml versions
and run macOS stuff only for 5.1
2024-05-13 22:36:16 -04:00
Simon Cruanes
2e276002c6
format 2024-05-13 22:06:31 -04:00
Simon Cruanes
53b3f75d64
docs 2024-05-13 21:54:33 -04:00
Simon Cruanes
f5aa4de6e7
add CCByte_buffer.to_slice 2024-05-13 21:52:46 -04:00
Simon Cruanes
c29083c216
richer API for byte_buf 2024-05-13 21:51:27 -04:00
Simon Cruanes
14dc772eba
format 2024-05-13 21:43:29 -04:00
Simon Cruanes
040fe2f97c
move to dune 3.0, fix warnings 2024-05-13 21:42:54 -04:00
Simon Cruanes
8eaa2b6429
improve API for byte slice 2024-05-13 21:34:05 -04:00
Simon Cruanes
5a56269b6f
gitignore 2024-05-13 21:07:08 -04:00
Simon Cruanes
c299b32309
helper script to run benchs 2024-05-13 21:05:55 -04:00
Simon Cruanes
8b60f52377
add byte_slice module, fix warnings 2024-05-13 21:05:06 -04:00
Simon Cruanes
4ff604015c
rework CI a tiny bit 2024-05-13 21:00:30 -04:00
Simon Cruanes
0b0dd83423
reformat all the things 2024-05-13 20:57:53 -04:00
Simon Cruanes
042d5b4f68
refactor byte buf: make the type public
it's time to let the types roam free, people.
2024-05-13 20:56:49 -04:00
Simon Cruanes
94b67deda4
remove dead file 2024-05-13 20:56:44 -04:00
Simon Cruanes
fcd4d3f6ec
add cons_when to CCListLabels 2024-04-19 09:52:13 -04:00
Nicola Mometto
4ff1853222
feat(CCList): add cons_when 2024-04-19 09:52:13 -04:00
Simon Cruanes
570e3f8d67
Merge pull request #450 from Bronsa/nicola/tup_pipe
feat(CCFun): add (||>)
2024-04-11 10:25:47 -04:00
Nicola Mometto
71233f2c1a chore: add since NEXT_RELEASE 2024-04-11 14:58:56 +01:00
Nicola Mometto
6a70c57253 feat(CCFun): add (|||>) 2024-04-11 14:54:07 +01:00
Nicola Mometto
2a21181580 feat(CCFun): add (||>) 2024-04-11 14:51:55 +01:00
Simon Cruanes
69cd3ca78d
Merge pull request #448 from c-cube/wip-pvec
containers.pvec
2024-01-16 14:25:58 -05:00
Simon Cruanes
41d8a7a968
add Pvec.equal 2024-01-16 14:20:09 -05:00
Master Builder
17eab9c3f4 CCVector: Add function foldi 2024-01-11 12:19:12 -05:00
Simon Cruanes
cb949e4c7f
more benchs 2024-01-10 12:48:33 -05:00
Simon Cruanes
813ea40ac5
comment 2024-01-08 23:49:55 -05:00
Simon Cruanes
b49f358d47
perf: more bench for pvec 2024-01-08 12:53:26 -05:00
Simon Cruanes
821fa6e3cf
more tests 2024-01-08 09:19:39 -05:00
Simon Cruanes
dd552fe334
more tests 2024-01-07 23:30:12 -05:00
Simon Cruanes
b9cc91fb96
pvec: implement iter_rev directly 2024-01-07 23:21:32 -05:00
Simon Cruanes
12ff3802ce
perf: implement iter separately from iteri 2024-01-07 23:17:57 -05:00
Simon Cruanes
a281476082
perf: reduce GC pressure by using a branching factor of 16 2024-01-07 23:17:39 -05:00
Simon Cruanes
8dca0ea78d
fix build 2024-01-06 22:45:42 -05:00
Simon Cruanes
04440deb39
small refactor 2024-01-06 17:17:06 -05:00
Simon Cruanes
81408b8e1b
add last to Pvec 2024-01-05 22:54:08 -05:00
Simon Cruanes
6a3cafa763
compat 2024-01-05 22:38:05 -05:00
Simon Cruanes
b9b6bf82b6
perf: restore branching factor to 32 2024-01-05 22:14:22 -05:00
Simon Cruanes
42967b2127
benchs: add pvec 2024-01-05 22:14:18 -05:00
Simon Cruanes
03e253a31c
fix pvec tests
(make choose's result irrelevant, only test whether it returns)
2024-01-05 21:54:41 -05:00
Simon Cruanes
66b42ea944
fixes for pvec 2024-01-05 21:54:38 -05:00
Simon Cruanes
209ee3a3ed
fix warning in test 2024-01-05 21:47:40 -05:00
Simon Cruanes
dd0e23cea2
add tests for pvec 2024-01-05 21:47:25 -05:00
Simon Cruanes
7b7eda5a05
wip: persistent vectors based on clojure's 2024-01-05 21:47:09 -05:00
Gabriel Scherer
9de8f1fb2e CCVector: fix two labels-omitted warnings
These warnings are silenced by the use of -nolabels in the compilation
flags (which I understand is designed to make the life of the
CC*Labels file easier, not let minor labeling mistakes sleep in.)
2024-01-04 16:44:34 -05:00
Simon Cruanes
60bb2c8c68
prepare for 3.13.1 2023-12-20 14:41:48 -05:00
Simon Cruanes
884d354986
fix test 2023-12-20 14:41:48 -05:00
Simon Cruanes
8dc4d5a706
fix: overshoot, concat_map is only TRMC after 5.1 2023-12-20 14:38:39 -05:00
Simon Cruanes
9ebfbe1c2d
boooooost CI 2023-12-15 22:37:58 -05:00
Simon Cruanes
d6fe4db6a2
fixity fix 2023-12-15 22:37:57 -05:00
Simon Cruanes
81f410649e
list: TRMC was in 4.14, we can use it earlier 2023-12-15 22:37:57 -05:00
Simon Cruanes
ad2ceb6e13
perf: use concat_map for CCList.flat_map on >= 5.1 2023-12-15 22:37:35 -05:00
Simon Cruanes
c4dcf1efe2
fix insidious bug in CCList.flat_map
we have been accidentally relying on evaluation order.
2023-12-15 22:36:39 -05:00
Simon Cruanes
7436727942
test: sanity test for flat_map 2023-12-15 22:36:21 -05:00
Simon Cruanes
8b53966dff
changelog 2023-12-06 09:21:39 -05:00
Simon Cruanes
7c1ca1d82f
prepare for 3.13 2023-12-05 16:09:29 -05:00
Simon Cruanes
f68d187142
fix stupid bug 2023-12-05 15:02:41 -05:00
Simon Cruanes
4682f9787b
tweak tweak tweak 2023-12-05 14:35:25 -05:00
Simon Cruanes
33053a1f96
finish removing threads 2023-12-05 13:45:48 -05:00
Simon Cruanes
bf2375f042
delete containers-thread
use moonpool instead!
2023-12-05 13:04:51 -05:00
Simon Cruanes
98ceaac8de
detail 2023-12-05 13:03:53 -05:00
Simon Cruanes
36790cf3ed
bugfix 2023-12-05 12:19:15 -05:00
Simon Cruanes
7fcf26963b
ensure unfold is tailrec 2023-12-05 12:04:55 -05:00
Ben Bellick
73e68dae7c CCList: add unfold 2023-12-05 11:59:55 -05:00
Simon Cruanes
50b478366f fix for 4.08 2023-12-03 20:03:16 -05:00
Simon Cruanes
fcee2f9c41 perf: accelerate List.append and List.flat_map on 5.1 2023-12-03 20:03:16 -05:00
Simon Cruanes
ec9148cf81 update benchs to add 2 distinct flat_map to it 2023-12-03 20:03:16 -05:00
Simon Cruanes
4d581498ae chore: add scripts to run benchmarks 2023-12-03 20:03:16 -05:00
Master Builder
77bfa34355 CCBool: Add functions if_then and if_then_else 2023-11-26 23:31:36 -05:00
Simon Cruanes
fdb7c0f4b0
remove opam dependencies, broken currently 2023-11-26 23:31:08 -05:00
Simon Cruanes
19e3dc9b44
fix CI 2023-11-24 11:06:43 -05:00
Simon Cruanes
49d66def49
Merge pull request #441 from c-cube/wip-rely-on-trmc
rely on TRMC more
2023-11-20 19:05:12 -05:00
Simon Cruanes
037c55a43d
tailrec 2023-11-19 23:51:47 -05:00
Simon Cruanes
517fd99a5f add test for nested ansi color 2023-11-19 22:27:51 -05:00
Simon Cruanes
ba9ef1f453 breaking: pp: modify Ext.t so it takes surrounding value
The type is now opaque, using a smart constructor, and is passed
the value used in the closest surrounding call to this extension,
if any. It is used by `Term_color` to properly restore ANSI
style in nested situations.
2023-11-19 22:27:51 -05:00
Simon Cruanes
1b3ddb7adf
fix test 2023-11-19 22:25:17 -05:00
Simon Cruanes
8c224e42fd
CCList: remove some functions that are subsumed by the stdlib 2023-11-19 21:56:10 -05:00
Simon Cruanes
3bd95d257c
CCList: use TRMC for many functions on 5.1 2023-11-19 21:47:57 -05:00
Simon Cruanes
1b026f267c
tests: update t_list to check more functions for tail-rec safety 2023-11-19 21:47:39 -05:00
Simon Cruanes
b16385bb9d
CI: test on 5.1 2023-11-19 21:47:28 -05:00
Simon Cruanes
51cb8e2992
feat: cpp: handle iflt and ifgt 2023-11-19 21:47:14 -05:00
Simon Cruanes
71dcc0937c
benchs: add funvec.flatten, quite terrible 2023-11-16 15:32:13 -05:00
Simon Cruanes
3a296ba127
feat ccfunvec: add fold_rev 2023-11-16 15:32:07 -05:00
Simon Cruanes
a07c688404
fix benchs somewhat 2023-11-16 14:42:29 -05:00
Simon Cruanes
1508b6c940 add Containers_pp.newline_or_spaces 2023-11-13 14:32:59 -05:00
Simon Cruanes
94e9335c35
CI: restore opam analysis 2023-10-16 15:45:54 -04:00
Simon Cruanes
33af762216
fix doc 2023-08-31 11:26:56 -04:00
Simon Cruanes
01358f93fd
Merge pull request #437 from BridgeTheMasterBuilder/master
Fix CCMultiMap
2023-08-03 21:53:02 -04:00
BridgeTheMasterBuilder
c97b934542
fix(CCMultiMap): Integrate suggested changes to doc comment for find_right
Co-authored-by: Simon Cruanes <simon.cruanes.2007@m4x.org>
2023-08-03 21:39:39 +00:00
BridgeTheMasterBuilder
85cf52d5ee
fix(CCMultiMap): Integrate suggested changes to doc comment for find_left
Co-authored-by: Simon Cruanes <simon.cruanes.2007@m4x.org>
2023-08-03 21:39:18 +00:00
Master Builder
e0fb678d1e fix(CCMultiMap): Correct @since tags 2023-08-03 15:40:12 +00:00
Master Builder
528b9030a4 fix(CCMultiMap): Rename functions find_left and find_right in the bidirectional multimap to find_left_iter and find_right_iter respectively to reflect their usage, and add new functions to replace the old find_left and find_right that return a list of values rather than an iterator, to make the signatures of CCMultiMap.S and CCMultiMap.BIDIR cohere. Additionally, change the return type of S.find_iter from t -> key -> (value -> unit) -> unit to t -> key -> value iter. These types are the same though, it's just for clarity since CCMultiMap already exposes an iter type 2023-08-03 15:17:47 +00:00
Master Builder
4fb0df50e9 Add missing required dependency to build instructions in Contributing section 2023-08-03 14:31:44 +00:00
Simon Cruanes
ba516e81af
detail 2023-07-12 19:15:23 -04:00
Fardale
d2bdee097e Apply ocamlformat on t_array.ml 2023-07-12 16:55:22 +02:00
Simon Cruanes
492484a9a2
cleanup: remove stubs for code always present on 4.08 2023-07-10 11:55:43 -04:00
Simon Cruanes
61887100ae
deprecate containers.thread 2023-06-28 11:47:02 -04:00
Simon Cruanes
ad10cdc9d5
fix test 2023-06-24 16:05:49 -04:00
Simon Cruanes
979eca042c
remove last refs to CCShims 2023-06-24 15:59:01 -04:00
Simon Cruanes
459098312e
fix opam 2023-06-24 15:46:14 -04:00
Simon Cruanes
9d48d228ef
CI 2023-06-24 15:23:58 -04:00
Simon Cruanes
1a23731730
remove conditional over OCaml >= 4.08
in particular, all the let-ops are now unconditional!
2023-06-24 15:22:21 -04:00
Simon Cruanes
d0903a09be
opam: require OCaml >= 4.08 2023-06-24 15:10:44 -04:00
Simon Cruanes
7ed1d44888
change COC to ocaml-coc 2023-06-20 12:32:50 -04:00
Michael Lan
adda7864e1 doc: fix typo 2023-06-15 21:58:16 -04:00
Simon Cruanes
64eb7737e3
revert change that broke 4.03 2023-06-06 22:55:45 -04:00
Simon Cruanes
bbfbe0f770
fix many, many warnings 2023-06-06 22:16:20 -04:00
Simon Cruanes
77ff1ee6a5
stricter warnings; remove dead code 2023-06-06 22:03:24 -04:00
Simon Cruanes
3975eb9862
fix warnings
reimplement CCtimer's server loop with `Unix.select` because of a
deprecation warning.
2023-06-06 21:54:02 -04:00
Simon Cruanes
afeb2b762a
dune: enable more warnings 2023-06-06 21:53:58 -04:00
Simon Cruanes
81acaaa2cb
prepare for 3.12 2023-06-06 10:26:11 -04:00
Simon Cruanes
e6afa76eaf
fix for OCaml 5.1: use a generative functor for CCBitfield 2023-06-06 10:26:11 -04:00
Simon Cruanes
b72fac90c7
compat: test cannot use let-ops 2023-06-01 15:21:52 -04:00
Simon Cruanes
2b4cf1e663
remove dbg message 2023-06-01 15:03:46 -04:00
Simon Cruanes
9f1ecdba27
another fix for CCParse and slices 2023-06-01 15:03:46 -04:00
Simon Cruanes
c7de9389b0
fix bug in CCParse 2023-06-01 15:03:46 -04:00
Simon Cruanes
10a8a7ce0f
fix(CCParse): fix issue in recurse
recursively parsing a slice means we temporarily switch the state
to the slice; but once the sub-parser returns we need to switch back to
the old state.
2023-06-01 15:03:46 -04:00
Simon Cruanes
6d013251fe
test: add test for CCParse 2023-06-01 15:03:46 -04:00
Simon Cruanes
a8449e9847
Merge pull request #428 from c-cube/wip-pp
pretty printer
2023-06-01 15:03:05 -04:00
Simon Cruanes
cb6c646978
fix small typo in docs 2023-05-28 21:07:29 -04:00
Simon Cruanes
ef40581b44
Merge pull request #430 from bclement-ocp/patch-1
[doc] CCIO.File.walk
2023-05-28 21:07:06 -04:00
Basile Clément
7cf1ba1764
[doc] CCIO.File.walk
This PR clarifies the behavior of `walk` and `read_dir ~recurse:true` by documenting that:

 - `walk p` always includes `p`
 - `read_dir ~recurse:true` only includes file paths (whereas `read_dir ~recurse:false` can include directory paths)
2023-05-26 13:32:47 +02:00
Simon Cruanes
87b10adcca
test: update the cbor tests 2023-04-19 22:11:11 -04:00
Simon Cruanes
74e3a9e875
compat, reformat 2023-04-19 21:22:19 -04:00
Simon Cruanes
c2952e0ce6
pp: add Term_color extension 2023-04-19 21:22:19 -04:00
Simon Cruanes
adaecf470e
pp: add zero-width text; add bracket2 combinator 2023-04-19 21:22:18 -04:00
Simon Cruanes
c1d980048d
more doc 2023-04-19 21:22:18 -04:00
Simon Cruanes
785932861b
helpers for pp 2023-04-19 21:22:18 -04:00
Simon Cruanes
1ed81107df
pp: expose fill and and fill_map 2023-04-19 21:22:17 -04:00
Simon Cruanes
58596a9bd5
chore: makefile 2023-04-19 21:22:16 -04:00
Simon Cruanes
ae7b1aef48
compat 2023-04-19 21:21:47 -04:00
Simon Cruanes
9d35f96033
add Pp.debug 2023-04-19 21:21:46 -04:00
Simon Cruanes
679534597d
fix(pp): slicing needs attention 2023-04-19 21:21:46 -04:00
Simon Cruanes
94640e9efe
comment 2023-04-19 21:21:46 -04:00
Simon Cruanes
91a2ecee4a
Pp: rename wrap to ext; more doc, more combinators 2023-04-19 21:21:46 -04:00
Simon Cruanes
4d77a17029
Pp: expose generic output; simplify extensions 2023-04-19 21:21:45 -04:00
Simon Cruanes
d36c57459e
feat(Pp): add wrap for extension nodes 2023-04-19 21:21:45 -04:00
Simon Cruanes
cea844fdde
add tests for Pp 2023-04-19 21:21:44 -04:00
Simon Cruanes
03c25cb18f
wip: add Containers_pp sub-library
this implements Wadler's pretty printers, albeit in a more eager way.
2023-04-19 21:21:44 -04:00
Simon Cruanes
aa6b40342e
update ocamlformat 2023-04-19 21:21:44 -04:00
Simon Cruanes
c5c72e0a50
move cbor tests 2023-04-19 21:21:43 -04:00
Simon Cruanes
4cf71ef3f0
opam constraint 2023-04-12 09:07:39 -04:00
Fardale
b4c164a8e4 fix: __FUNCTION__ was only introduced in 4.12 2023-04-12 13:56:53 +02:00
Fardale
ff3e838553 CCArray(feat): Add max,argmax,min,argmin and their _exn conterpart 2023-04-12 11:52:57 +02:00
Simon Cruanes
4a46fa4d71
add a op test for Fun_vec 2023-04-09 14:59:39 -04:00
Simon Cruanes
7ec9cd94dc
details 2023-04-09 14:59:32 -04:00
Simon Cruanes
fd760d44a3
makefile 2023-04-09 14:59:19 -04:00
Simon Cruanes
9261e654e7
add Option.flat_map_l 2023-04-07 20:30:43 -04:00
Simon Cruanes
d985019fe1
compat 4.03 2023-04-07 12:27:55 -04:00
Simon Cruanes
84173382db
feat(CCParse): add take_until_success
this reads a slice using the given parser to parse the end delimiter
(e.g "end gpg signature" 😉)
2023-04-07 11:45:12 -04:00
Fardale
ea0e4473a8 fix: fix Set.find_last_map on OCaml 4.03 2023-03-31 12:14:03 +02:00
Fardale
b6d99645ea CCSet: implement find_last_map using find_last
find_last exists since ocaml 4.05, using it for find_map avoid the
linear time behavior on ocaml >= 4.05
2023-03-14 19:17:45 +01:00
Simon Cruanes
0b72812a55
more tests for Vec 2023-03-13 19:34:20 -04:00
Simon Cruanes
503c61f72b
fix(vector): make sure Vector.to_{seq,gen} captures the length initially 2023-03-13 15:37:00 -04:00
Simon Cruanes
83009aac10
feat(cchash): native FNV hash for int64/int32 2023-03-13 15:37:00 -04:00
Fardale
a7b14c5620 doc: inline the stdlib doc of Seq and ListLabels 2023-03-13 11:26:23 +01:00
Fardale
e6611f1920 feat(CCSet): add find_first_map and find_last_map 2023-02-16 12:23:14 +01:00
Fardale
53f2ffca9f CI: fix gh-page
odig need the package to be installed to compile the documentations
2023-02-15 18:31:59 +01:00
Simon Cruanes
1d08a05c44
Merge pull request #426 from FardaleM/cleanup
Cleanup
2023-02-15 09:28:38 -05:00
Fardale
d5d10af079 CI(doc): use odig to generate documentation 2023-02-15 14:32:07 +01:00
Fardale
0a167dc3dd doc: remove link to ocaml manual
The goal is to use odig to build the documentation and with odig the
comment of the function from the standard library are shown.
2023-02-15 14:32:05 +01:00
Fardale
8607de2749 CI(chore): remove explicite pin and deps install
Pinning and installation of the dependency is already done by
setup-ocaml
2023-02-15 11:02:09 +01:00
Fardale
def8f242fc CI(chore): disable dune cache for the doc 2023-02-15 11:01:55 +01:00
Fardale
a30e471a6f
fix doc (#425) 2023-02-14 20:56:15 -05:00
Simon Cruanes
38d6aa4ad1
disable opam dependencies CI action 2023-02-14 20:55:54 -05:00
Simon Cruanes
5ff60d2a52
fix doc 2023-02-14 08:50:56 -05:00
Simon Cruanes
161c192bff
prepare for 3.11 2023-02-07 12:39:35 -05:00
Simon Cruanes
d249ce5f13
fix mdx test 2023-02-07 12:39:35 -05:00
Simon Cruanes
735729c329
add CCFun.(let@) (if OCaml >= 4.08) 2023-02-07 12:23:27 -05:00
Simon Cruanes
b1c39832aa fix(CCVector): concurrent modification safety in resize_with 2023-01-08 22:42:24 -05:00
Simon Cruanes
b73fc4ee5c fix(CCVector): always obtain a copy of array before using unsafe_{set,get}
close #423
2023-01-08 22:42:24 -05:00
Fardale
b0ed8d9182 chore(CI): rename job CI 2022-12-23 15:57:03 +01:00
Fardale
ae16f5d2f8 opam: add mdx as test dependency of containers-data 2022-12-23 14:00:20 +01:00
Fardale
b11aea96bf chore(CI): add ocaml 5.0.x 2022-12-23 13:51:56 +01:00
Samuel Hym
fb09468837 Add OCaml 5 bytecode-only to the tested platforms 2022-12-22 23:08:14 +01:00
Samuel Hym
f58310913a Allow explicit fallback to bytecode for various tests
Relax the requirements for the tests, to fall back on the bytecode
version when the native version is not available. Otherwise the tests
will fail on bytecode-only architectures.
2022-12-22 23:08:14 +01:00
Samuel Hym
1367d5b855 Rewrite a test so that it passes also on the bytecode backend
Rewrite a test to shorten the lexical scope of the string it builds
because, in the bytecode backend, a variable is deemed live at least as
long as its lexical scope.

Reference: https://github.com/ocaml/ocaml/pull/10071
2022-12-22 23:08:14 +01:00
Simon Cruanes
d1de46c7a9
Merge pull request #421 from shym/allow-bytecode-target
Allow explicit fallback to bytecode for cpp
2022-12-12 12:30:15 -05:00
Samuel Hym
5d3768b5a2 Allow explicit fallback to bytecode for cpp
Relax the requirements for the cpp preprocessor, to fall back on the
bytecode version when the native version is not available. Otherwise the
build fails on bytecode-only architectures.
2022-12-12 12:31:04 +01:00
Simon Cruanes
d4e582e829
add CCHet.Tbl.{clear,reset} 2022-11-30 09:21:35 -05:00
Simon Cruanes
cee2c7d8e3
Merge pull request #418 from nino/master
Fix some typos
2022-11-28 11:30:14 -05:00
Nino Annighoefer
46e53ec85f Fix more typos 2022-11-26 10:19:10 +00:00
Nino Annighoefer
3ccb3e16f7 Fix typos 2022-11-26 09:53:17 +00:00
Simon Cruanes
fcfd8f19b0
doc 2022-11-16 13:30:13 -05:00
Simon Cruanes
069423bb77
prepare for 3.10 2022-11-16 10:27:20 -05:00
Simon Cruanes
24fdfdf3ee
readme 2022-11-14 09:08:39 -05:00
Fardale
5227fb975c feat(CCArray): add mapi_inplace 2022-10-19 12:07:13 +02:00
Simon Cruanes
e0a8285e17
add containers.scc 2022-10-05 10:12:50 -04:00
Simon Cruanes
5b1f2af227
chore(github): add opam deps workflow 2022-09-26 11:25:36 -04:00
Simon Cruanes
a0c8859519
list codec libraries in readme 2022-09-21 13:17:45 -04:00
Fardale
399cd6d570 fix(CCSeq): add implementation of concat_map 2022-09-21 16:20:02 +02:00
Fardale
b2ec88b0e1 feat(CCSeq): add some missing function from 4.14 2022-09-21 15:44:18 +02:00
Fardale
46fbc3b82f doc(Unix): add example from call_full 2022-09-21 11:22:02 +02:00
Fardale
47ff9935dc include Seq in CCSeq for ocaml >= 4.07 2022-09-20 15:09:45 +02:00
Fardale
a5f9f2b95d chore(CI): enable dune cache 2022-09-17 21:39:04 +02:00
Fardale
15c9152795 chore(CI): bump the last version of ocaml from 4.13 to 4.14 2022-09-17 21:28:55 +02:00
Simon Cruanes
00d344e09e
fix(Int64.hash): wrong shift
found by @copy
2022-08-29 09:49:51 -04:00
Simon Cruanes
a3abf40bc2 add CCInt64.{hash,hash_to_int64} 2022-08-22 17:48:21 +00:00
Fardale
4e2f9220dd doc: add details to CCResult.of_opt 2022-08-05 21:38:22 +02:00
Simon Cruanes
43f82d7668
feat(Ref): add protect function 2022-08-04 11:58:39 -04:00
Simon Cruanes
d535cfe677
detail 2022-07-21 11:54:46 -04:00
Simon Cruanes
249dc3596e
prepare for 3.9 2022-07-06 22:27:25 -04:00
Simon Cruanes
6a415e963a
fix(cbor): use int64 as main int type 2022-07-06 22:27:24 -04:00
Simon Cruanes
484aa3a1e7
Merge pull request #394 from c-cube/ccbv_bytes2
(continued) use bytes for CCBV
2022-07-06 16:41:21 -04:00
Simon Cruanes
b7d19e9dc5
test 2022-07-05 21:29:03 -04:00
Simon Cruanes
af77f371fd
feat(testlib): allow ?long arg 2022-07-05 21:28:54 -04:00
Simon Cruanes
8b751754ba
test: compat 4.03 2022-07-04 22:16:46 -04:00
Simon Cruanes
feaa8ecf7d
test BV.init 2022-07-04 22:15:13 -04:00
Simon Cruanes
e15971934d
feat(BV): add init 2022-07-04 22:15:06 -04:00
Simon Cruanes
b24feaf2d6
strong BV test 2022-07-04 22:09:25 -04:00
Simon Cruanes
36eb87db21
fix(BV): clear bits properly 2022-07-04 22:09:14 -04:00
Simon Cruanes
e01b758de8
more tests 2022-07-04 22:04:50 -04:00
Simon Cruanes
d9717095ef
improve doc for BV 2022-07-04 22:04:40 -04:00
Simon Cruanes
30cb40c71f
test: add strong tests for BV
we use the classic QCheck construction with a random list of operations, and
test:
- internal invariant after each operation
- same cardinal and content as reference implementation after each operation
2022-07-04 21:56:14 -04:00
Simon Cruanes
60b9ece69e
feat(BV): correct many bugs, clarify parts of the API 2022-07-04 21:49:50 -04:00
Simon Cruanes
75fe196d3a
feat(testlib): optional arguments for q 2022-07-04 21:47:24 -04:00
Simon Cruanes
090945c3f8
fix(BV): equal function 2022-07-04 16:08:17 -04:00
Simon Cruanes
cc55e4cdfb
feat(testlib): optional name for all tests 2022-07-04 16:07:58 -04:00
Simon Cruanes
856e73d2b2
fix 2022-07-04 14:37:24 -04:00
Simon Cruanes
2b5b2a0e02
chore: have make test be quiet 2022-07-04 14:35:32 -04:00
Simon Cruanes
3dd63964fb
Merge branch 'master' into ccbv_bytes2 2022-07-04 14:35:25 -04:00
Simon Cruanes
69f2805f10
Merge pull request #414 from c-cube/wip-testlib
custom testlibrary, remove qtest
2022-07-04 13:57:35 -04:00
Simon Cruanes
8d964458d9 chore: ci 2022-07-04 13:36:06 -04:00
Simon Cruanes
3c5b2329bc tests belong in specific packages 2022-07-04 13:36:06 -04:00
Simon Cruanes
10865eaced reformat 2022-07-04 13:36:06 -04:00
Simon Cruanes
3e2379660e
move cbor tests into tests/ 2022-07-02 23:49:41 -04:00
Simon Cruanes
e242b004ad
use preproc to deal with 4.03 and others < 4.08 versions 2022-07-02 23:39:33 -04:00
Simon Cruanes
919360f96e
remove ounit 2022-07-02 23:18:16 -04:00
Simon Cruanes
55b59b5b91
move more tests into testlib 2022-07-02 22:25:29 -04:00
Simon Cruanes
3b2cd786e2
finish removing qtest 2022-07-02 22:12:40 -04:00
Simon Cruanes
1e4a22fbf2
refactor: finish migration to qtest 2022-07-02 22:09:25 -04:00
Simon Cruanes
1111c0fa9a
wip: convert tests into testlib 2022-07-02 14:47:03 -04:00
Simon Cruanes
91ddccc782
compat 4.03 2022-07-02 01:08:59 -04:00
Simon Cruanes
b695918e99
move all core tests to new testlib 2022-07-02 00:29:25 -04:00
Simon Cruanes
49c06e93fa
wip: use testlib for tests 2022-06-30 22:28:19 -04:00
Simon Cruanes
0bee9bdd55
wip: remove tests from src/ 2022-06-30 22:28:07 -04:00
Simon Cruanes
215c5c7d5b
testlib: improve API 2022-06-30 22:28:01 -04:00
Simon Cruanes
369b208385
test: migrate part of CCList's tests to experiment with testlib 2022-06-30 21:15:16 -04:00
Simon Cruanes
f8d8c0962c
wip: add internal test library to replace qtest 2022-06-30 21:15:16 -04:00
Simon Cruanes
f9abed084e
Merge pull request #413 from c-cube/feat-cbor
add CBOR sub-library
2022-06-30 21:06:58 -04:00
Simon Cruanes
43f88a372f
stronger test for cbor 2022-06-30 21:06:21 -04:00
Simon Cruanes
20fb411b50
compat fix 2022-06-30 20:45:08 -04:00
Simon Cruanes
db9c613f57
add some basic docs for cbor 2022-06-30 20:39:09 -04:00
Simon Cruanes
962874c038
dune 2022-06-30 20:36:14 -04:00
Simon Cruanes
89702924d8
test: add qcheck test for cbor 2022-06-30 20:25:19 -04:00
Simon Cruanes
b1c7c64b87
improve test for cbor 2022-06-30 20:06:38 -04:00
Simon Cruanes
40ceded65f
remove expected file for cbor tests
reason is, under 4.08 we can't produce the same file because CBOR is
basically an empty module.
2022-06-29 20:12:36 -04:00
Simon Cruanes
ddd9ed48f1
chore: disable CI for windows temporarily
it's currently just broken
2022-06-28 23:38:30 -04:00
Simon Cruanes
fd4c679479
disable cbor tests on < 4.08 2022-06-28 23:38:01 -04:00
Simon Cruanes
565b3ed5c2
compat with 4.03 2022-06-28 21:24:53 -04:00
Simon Cruanes
bad23766e3
chore: enable preprocessor in cbor 2022-06-28 20:56:50 -04:00
Simon Cruanes
06b58d36d1
test for cbor, based on appendix A test vector 2022-06-17 22:22:00 -04:00
Simon Cruanes
27ab6af573
depend on yojson for tests 2022-06-17 22:21:59 -04:00
Simon Cruanes
98d0cdfe6d
fix(cbor): many bugfixes 2022-06-17 22:21:56 -04:00
Simon Cruanes
e7b5d675d2
doc: add RFC for CBOR 2022-06-16 22:27:37 -04:00
Simon Cruanes
69907e96d1
feat: add Containers_cbor module
from scratch reimplementation of https://www.rfc-editor.org/rfc/rfc8949.html
2022-06-16 22:21:35 -04:00
Simon Cruanes
e24b2060e7
fix: handle uppercase in string/hex 2022-06-15 13:38:43 -04:00
Simon Cruanes
75b498a433
prepare for 3.8 2022-06-10 23:47:21 -04:00
Simon Cruanes
259edb965b
try to fix test 2022-06-10 23:26:21 -04:00
Simon Cruanes
90a131b7af
fix compiler warning 2022-06-10 23:25:22 -04:00
Simon Cruanes
58ac755f82
chore: move to ounit2
see if that fixes the windows build.
2022-06-09 21:39:09 -04:00
Simon Cruanes
977e0c9577
add test for String.to_hex 2022-06-09 21:11:47 -04:00
Simon Cruanes
911e9faff7
add Containers_bencode
A small module to parse/print Bencode values. Bencode is really simple
and can embed binary strings easily, unlike JSON.
2022-06-09 21:07:43 -04:00
Simon Cruanes
e63383174e
perf(cchash): improve a bit commutative hashing of arrays/lists 2022-06-07 16:20:26 -04:00
Simon Cruanes
40133ee511
perf(cchash): only hash prefix of string/bytes 2022-06-07 16:20:14 -04:00
Simon Cruanes
e7dad1b54a
fix(parse): rename function in test case
like Grant remarked, the chaining function is actually
right-associative, not left-associative
2022-06-07 16:19:28 -04:00
Simon Cruanes
322b15d757
Merge pull request #409 from dmbaturin/assoc-helpers
New assoc list helpers: `keys`, `values`, and `map_values`
2022-06-04 21:15:21 -04:00
Daniil Baturin
0075378f29 feat(CCList): Add keys, values, and map_values 2022-06-01 15:49:33 +03:00
Fardale
70703b3512 fix: add since tag for Array.map_inplace 2022-05-12 11:19:47 +02:00
Fardale
8a71b1dcaa feat(ccarray): add CCArray.map_inplace 2022-05-12 11:03:38 +02:00
Simon Cruanes
e59cc68c24
fix doc 2022-05-09 10:49:48 -04:00
Simon Cruanes
2e4db82b67
doc: readme irc 2022-04-28 21:24:44 -04:00
Simon Cruanes
522772356f
chore: CI 2022-04-16 23:12:32 -04:00
Simon Cruanes
34f76e926c
add CCString.{to_hex,of_hex} 2022-04-06 10:53:26 -04:00
Simon Cruanes
a753b0df3e
Merge remote-tracking branch 'origin/master' 2022-03-24 15:46:23 -04:00
Simon Cruanes
a2a1901630
prepare for 3.7 2022-03-24 13:46:45 -04:00
Simon Cruanes
54201a4e28
fix(atomic): prevent race conditions under flambda, for now 2022-03-24 13:42:24 -04:00
Glenn Slotte
7f4c87cfb9
docs: fix CCOption.map_or doc comment (#407) 2022-03-23 09:02:53 -04:00
Simon Cruanes
6fa4c1c7d2
Merge pull request #406 from c-cube/wip-format-stag
use `stag` for color handling in CCFormat
2022-03-19 18:53:43 -04:00
Simon Cruanes
5a4adfa76b
fixes, do not run Format tests on < 4.08 2022-03-19 14:13:15 -04:00
Simon Cruanes
0ce613d7c4
gate more code in the version conditional 2022-03-19 13:53:38 -04:00
Simon Cruanes
38552f5c0c
use stag properly, add with_styling.
all tests pass again.
2022-03-19 10:06:08 -04:00
Simon Cruanes
e397d90279
wip: use Stag in Format 2022-03-19 09:40:43 -04:00
Simon Cruanes
40189757ca
Merge pull request #401 from c-cube/experiment-preproc
custom preprocessor rather than shim modules
2022-02-22 23:15:56 -05:00
Simon Cruanes
1b92e905e4
chore: rename build on CI 2022-02-22 23:09:50 -05:00
Simon Cruanes
e9e959eb6c
small optim in preprocessor 2022-02-22 11:26:46 -05:00
Simon Cruanes
0364929a99
improve test behavior 2022-02-22 11:26:43 -05:00
Simon Cruanes
f6dc3b23f8
fix: compat in CCArray 2022-02-21 22:26:51 -05:00
Simon Cruanes
68e539173f
failfast in main build task 2022-02-21 22:26:44 -05:00
Simon Cruanes
ceebfe3ae1
update CI with distinct jobs 2022-02-21 22:18:30 -05:00
Simon Cruanes
558c069b7b
forgotten module 2022-02-21 22:03:40 -05:00
Simon Cruanes
dae93cf25f
remove final shims 2022-02-21 22:03:26 -05:00
Simon Cruanes
b837509de9
remove many more shims 2022-02-21 21:52:06 -05:00
Simon Cruanes
26ab8229e1
preprocess monomorphic too 2022-02-21 21:26:49 -05:00
Simon Cruanes
6f3a7d902a
remove more shims 2022-02-21 21:25:39 -05:00
Simon Cruanes
c32529fd5a
ci: run a simple build matrix first 2022-02-21 21:20:30 -05:00
Simon Cruanes
59407b0f5e
wip: remove some shims 2022-02-21 17:12:32 -05:00
Simon Cruanes
3d87d2672e
ci 😱 2022-02-21 16:47:55 -05:00
Simon Cruanes
eadfa4981a
force dune 2.9 in CI 2022-02-21 15:31:17 -05:00
Simon Cruanes
5840d677c0
Merge pull request #402 from bluddy/master
CCVector: add `insert`
2022-02-21 14:47:58 -05:00
Yotam Barnoy
408c14fac7
CCVector.insert: check if there's a need to blit
Co-authored-by: Simon Cruanes <simon.cruanes.2007@m4x.org>
2022-02-21 18:50:19 +02:00
Yotam Barnoy
9bb280e353 CCVector: add insert 2022-02-21 18:42:16 +02:00
Simon Cruanes
ef9851983f
update dune to 1.10, condition some rules to unix 2022-02-20 22:01:39 -05:00
Simon Cruanes
b23e075762
fix occurrences of warning 50 2022-02-20 22:01:02 -05:00
Simon Cruanes
6717d03a35
remove custom split_on_char post 4.04 2022-02-17 14:37:14 -05:00
Simon Cruanes
01295a71fd
grr \r on windows 2022-02-17 10:46:34 -05:00
Simon Cruanes
8aa50b2523
dune 2 shenanigans 2022-02-17 10:34:08 -05:00
Simon Cruanes
c50ee3d928
try to fix compat issue 2022-02-17 10:20:24 -05:00
Simon Cruanes
acadb6b9d3
move to dune 2.0 2022-02-17 10:17:08 -05:00
Simon Cruanes
4934b302c6
feat(cpp): better locations after blocks end 2022-02-17 10:16:11 -05:00
Simon Cruanes
10286098c4
fix qtest generation
we need to avoid files named foo.pp.ml as they're not handled by qtest
the right way (computes the wrong module name).
2022-02-17 00:17:37 -05:00
Simon Cruanes
60a1614919
silence warning 70 2022-02-17 00:17:31 -05:00
Simon Cruanes
7ae113b6dc
compat with merlin by using [@@@ifge 4.12] instead of [%IFGE 4.12] 2022-02-16 23:14:26 -05:00
Simon Cruanes
bc6c8947b1
start using preprocessor to remove some shim modules 2022-02-16 23:01:00 -05:00
Simon Cruanes
2d860b30ae
fix 2022-02-16 22:45:10 -05:00
Simon Cruanes
7bd0aa075c
wip: try to have a custom little preprocessor 2022-02-12 20:22:52 -05:00
Simon Cruanes
45f567dca1
perf: reduce allocations in CCSeq.to_array 2022-02-11 21:15:09 -05:00
Simon Cruanes
2a1c7cd8f0
fix warning 2022-02-11 21:15:04 -05:00
Simon Cruanes
01b209b218
doc: fix mdx for readme 2022-02-11 21:14:51 -05:00
Simon Cruanes
c5d435848b
improve test for CCByte_buffer 2022-02-08 13:07:51 -05:00
Simon Cruanes
826381690c
add random test to CCByte_buffer 2022-02-08 13:07:51 -05:00
Simon Cruanes
d7214345e5
update doc and aliases 2022-02-08 13:07:51 -05:00
Simon Cruanes
b42b1f4907
fix: rename size to cap in CCByte_buffer 2022-02-08 13:07:50 -05:00
Simon Cruanes
5f064dbbbf
feat: add Byte_buf, a byte buffer. 2022-02-08 13:07:50 -05:00
Simon Cruanes
bc8b7b168b
Merge pull request #399 from c-cube/wip-ccvector-resize
change growth strategy for Vector
2022-02-07 12:46:48 -05:00
Simon Cruanes
21c10d2ad4
less aggressive constant.
series of sizes should now be:

```
 # let next n = n + n lsr 1 + 2;;
 # CCSeq.unfold (fun x -> Some (x, next x)) 0 |> CCSeq.take 20 |> CCSeq.to_list;;
- : int list =
[0; 2; 5; 9; 15; 24; 38; 59; 90; 137; 207; 312; 470; 707; 1062; 1595; 2394;
 3593; 5391; 8088]
 ```
2022-02-03 19:15:13 -05:00
Simon Cruanes
02c0953468
fix stupid typo 2022-02-03 19:13:43 -05:00
Simon Cruanes
0baa4fddec
perf(vector): inline some more stuff plz 2022-02-03 18:55:50 -05:00
Simon Cruanes
8c9d7016b8
perf: uniformize ocamlopt_flags
we don't need codegen which depends on >= 4.03, it's assumed. Also
include a reasonable value for `-inline` when flambda isn't available.
2022-02-03 18:54:59 -05:00
Simon Cruanes
7ec9e50f74
perf: make sure to use some decent level of inlining even without flambda 2022-02-03 18:51:09 -05:00
Simon Cruanes
f540a6d7e5
perf(vector): less aggressive growth for internal resizing 2022-02-03 18:50:32 -05:00
Simon Cruanes
2d30b2ae14
add CCSeq.{zip_i,of_string} 2022-01-27 13:48:49 -05:00
Simon Cruanes
e25b9fc9b4
fix @since in CCSeq 2022-01-27 13:45:01 -05:00
Ewen Maclean
4e79b72306
adding opt_map to simplify result function application over optionals (#397)
adding `Result.opt_map` to simplify result function application over optionals
2022-01-25 15:05:11 -05:00
Fardale
a13fc12ff4 chore(ci): change ocaml 4.12.x to ocaml 4.13.x 2022-01-22 21:10:52 +01:00
Simon Cruanes
3960ea3792
feat(BV): add set_bool 2022-01-02 21:58:45 -05:00
Simon Cruanes
3d57a5c86e
feat(CCBV): prevent resize from shrinking underlying array
also add `BV.resize_minimize_memory` to force shrinking. This shouldn't
be the default because it can allocate a lot in case of repeated
shrinkings.
2022-01-02 21:57:53 -05:00
Simon Cruanes
92463d33c5
perf(BV): make more functions inline, use raise_notrace 2022-01-02 21:56:33 -05:00
Simon Cruanes
ced66a76e1
perf(CCBV): better bitwise operations
- a 8-bit popcount
- simpler logic for LSB masks
2022-01-02 21:45:26 -05:00
Simon Cruanes
b8c93f42fa
feat(CCInt32): add popcount function 2022-01-02 21:44:05 -05:00
Simon Cruanes
22bbe23c5a
feat(CCInt64): add popcount operation
adapted from CCInt, but directly on int64, so it works for
Int64.{min_int/max_int}.
2022-01-02 21:17:18 -05:00
Simon Cruanes
569e254540
fix: use == 2022-01-02 12:15:31 -05:00
Simon Cruanes
64ecd0c3ba
add shims for Atomic and Unit 2022-01-02 12:08:16 -05:00
Simon Cruanes
4e0f35c078
make fun shims inline 2021-12-22 11:00:33 -05:00
Jochen Bartl
ab0673a688
fix typos in README (#393) 2021-12-20 18:12:11 -05:00
Simon Cruanes
a127e139ae
doc for CCParse
close #392
2021-12-16 13:17:09 -05:00
Shon Feder
946ac4e05d
Make CCSeq.to_array behave better with stateful sequences (#390)
Make Seq.to_array only traverse seq once

This PR suggests a change to `Seq.to_array`, which uses construction of
an intermediate list to prevent traversing the Seq twice. This requires
the allocation of an intermediate list, but it eliminates the surprising
behavior that otherwise occurs with state-full sequences, due to the
extra traversal required to obtain the length of the sequence. E.g.,
with the previous implementation, the value of `to_array` for the
sequence constructed in the test added in this commit is `[|4;5;6|]`,
while `to_list` gives `[|1;2;3|]`.
2021-12-11 21:28:10 -05:00
Simon Cruanes
74954f53a0
update changelog 2021-12-04 14:37:21 -05:00
Simon Cruanes
16bea66073
more warnings 2021-12-02 11:48:57 -05:00
Simon Cruanes
cea6647c3c
fix warnigns for CCOption 2021-12-02 11:46:41 -05:00
Simon Cruanes
bee23722ea
fix: use labels in CCParse 2021-12-02 11:38:22 -05:00
Simon Cruanes
9123f7907f
feat(ccparse): expose pos to get current pos; improve perf
perf of obtaining many positions is now better because we cache line
offsets, which means computing a line,col pair is just a O(ln n) bisect
away.
2021-12-01 16:05:20 -05:00
Fardale
c33477c397 chore: remove unwanted comment 2021-11-12 17:38:37 +01:00
Fardale
a5822f7273 doc: inline the doc of CCShim*_ module in the doc 2021-11-12 17:34:06 +01:00
Fardale
57cb3446b3 add semicolon to ocaml block in the README 2021-11-12 11:42:54 +01:00
Fardale
099f2e176f chore(doc): adapt module docstring for the index page 2021-11-11 14:40:35 +01:00
Simon Cruanes
db1ebaf3ce
Merge branch 'wip-3.6.1' 2021-10-25 20:13:17 -04:00
Simon Cruanes
04693f4f08
fix opam file 2021-10-25 09:35:57 -04:00
Simon Cruanes
d59a856787
prepare for 3.6.1 2021-10-24 22:57:54 -04:00
Simon Cruanes
62ee8ad17e
fix: rely on either compatibility library 2021-10-24 22:57:17 -04:00
Simon Cruanes
2100a0a0fb
fix: rely on either compatibility library 2021-10-24 22:56:36 -04:00
Simon Cruanes
2c2fa5d008
fix asymptotic behavior of resize functions 2021-10-21 11:07:11 -04:00
Simon Cruanes
e6e07ba4da
fix tests and implem for CCVector 2021-10-21 10:59:03 -04:00
Dario Pinto
d1ddeeb31f
add CCVector.resize_with and CCVector.resize_with_init, tests and doc (#389)
add CCVector.resize_with and CCVector.resize_with_init, tests and doc
2021-10-21 10:57:23 -04:00
Simon Cruanes
541d716d5c
in CCVector, use invalid_arg, and document it 2021-10-20 10:47:06 -04:00
Simon Cruanes
7288045828
more doc for CCVector 2021-10-19 09:34:45 -04:00
Simon Cruanes
b2cff1d0b7
prepare for 3.6 2021-10-18 22:31:44 -04:00
Simon Cruanes
2c7e907061
update benchs 2021-09-27 20:43:16 -04:00
Fardale
475e7b181e chore(ci): use new syntax for minor ocaml version in setup-ocaml 2021-09-27 13:07:50 +02:00
Fardale
2a7bc70bed chore(ci): migrate gh-pages workflow to setup-ocaml@v2 2021-09-27 13:07:50 +02:00
Fardale
800fdf4d5e chore(ci): bump version from 4.12.0 to 4.12.1 2021-09-27 13:07:50 +02:00
Fardale
3ae5699021 chore(CI): fix ocaml compiler version 2021-09-27 13:07:50 +02:00
Simon Cruanes
bf15e88f0c
fix doc 2021-09-25 20:58:31 -04:00
Simon Cruanes
ff2d1d3cbc
Merge pull request #380 from c-cube/wip-parse-2021-05-04
refactor `CCParse` to make it easier to use
2021-09-25 20:57:26 -04:00
Simon Cruanes
9c72797515
minor changes 2021-09-25 20:51:18 -04:00
Simon Cruanes
938c7cb90a
more doc 2021-09-25 20:50:04 -04:00
Simon Cruanes
b8fa400465
a test to ensure chars1_if p = take1_if p >|= Slice.to_string 2021-09-25 20:48:23 -04:00
Simon Cruanes
6eb8856957
Merge pull request #386 from c-cube/rename_ccopt_ccoption
Rename CCOpt to CCOption and deprecate CCOpt
2021-09-25 15:49:00 -04:00
Simon Cruanes
e06cd516f0
detail 2021-09-25 15:38:35 -04:00
Simon Cruanes
396a7db967
more fixes 2021-09-24 22:58:08 -04:00
Simon Cruanes
8f9ecf5f41
some fixes related to review 2021-09-24 22:45:17 -04:00
Simon Cruanes
ac1baae839
add missing @since 2021-09-24 14:37:36 -04:00
Simon Cruanes
16576e8838
Update src/core/CCOpt.mli 2021-09-24 14:36:53 -04:00
Fardale
302dba6cb5 chore(CCOption): rename CCOpt to CCOption and deprecate CCOpt
In the stdlib the module associated with the option type is called
Option and in containers it was called CCOpt. Renaming CCOpt to CCOption
make the name of containers module uniforme with respect to the stdlib.
2021-09-22 23:07:05 +02:00
Fardale
27e39a0fc8 chore: remplace which' by command -v'
Using `which' to test the existance of a program is deprecated in
debian. Debian recommand to use `command -v' instead.
2021-09-20 14:15:44 +02:00
Fabian
fd783336b8 remove duplicate :standard in dune 2021-08-28 15:59:33 -04:00
Simon Cruanes
f5409d480a
chore: remove dead makefile target 2021-08-26 10:07:48 -04:00
Simon Cruanes
76b108203a
add iterator functions to CCIO 2021-08-19 10:23:00 -04:00
Simon Cruanes
6b99433716
bugfix in CCIO 2021-08-19 10:21:07 -04:00
Simon Cruanes
8e924c98be
add CCIO.File.walk_iter 2021-08-19 10:14:30 -04:00
Simon Cruanes
4783c635fd remove dead doc files 2021-08-09 13:26:30 -04:00
Simon Cruanes
824dfb427c chore: use standard format for license 2021-08-05 10:28:09 -04:00
Simon Cruanes
aa05f69471 prepare for 3.5 2021-08-04 16:49:29 -04:00
Simon Cruanes
30419a2ec7 chore: try to move to setup-ocaml v2 2021-08-02 14:08:00 -04:00
Simon Cruanes
1b87075284 fix test for multicore 2021-08-02 13:32:09 -04:00
Simon Cruanes
f5505297de add CCHash.map 2021-07-09 14:40:15 -04:00
Simon Cruanes
4db9d4eccb style 2021-06-26 23:51:06 -04:00
Simon Cruanes
61b9762269 feat(CCIO): add many Seq.t based functions
each generator function can now produce a seq.
2021-06-26 23:50:30 -04:00
Simon Cruanes
26af1f1297 feat(ccutf8string): add {make,empty,of_uchar} 2021-06-23 14:05:10 -04:00
Simon Cruanes
92aad159c8 add CCFormat.{const_string,opaque} 2021-06-23 14:05:10 -04:00
Simon Cruanes
25660ee2c1 add CCOpt.{some,none}
close #382
2021-06-19 18:43:17 -04:00
Simon Cruanes
1f92564f83 try to fix build 2021-06-08 21:43:17 -04:00
Simon Cruanes
f1084c9b9e test: add some property tests on Csexp/Canonical_sexp 2021-06-08 18:25:46 -04:00
Simon Cruanes
b9828375e1 use dune 1.4 and build ccparse_irclogs only on >= 4.08 2021-06-07 00:28:35 -04:00
Simon Cruanes
5c67fb51ab try to fix ci 2021-06-07 00:10:20 -04:00
Simon Cruanes
1450b869f9 try to fix ci 2021-06-06 23:23:46 -04:00
Simon Cruanes
9c763991ef add example and test of an IRC log parser
also add a sample of IRC logs of #ocaml on libera.chat, to make sure
they parse properly.
2021-06-06 23:01:50 -04:00
Simon Cruanes
d46a679b3b fix bug in CCParse.line, add set_current_slice, fix tests 2021-06-06 23:00:51 -04:00
Simon Cruanes
352fc10d3b more doc for CCParse 2021-06-06 22:49:43 -04:00
Simon Cruanes
1517f64f55 CCParse: add slice and the ability to recurse on them
the idea is that it's often convenient to split the input into smaller
part (e.g. lines), or do a first pass of parsing that just returns a
slice of the input; and then later to use another parser on that slice
to extract the actual data. The new notion of `slice` allows that,
while preserving locations wrt the original input.
2021-06-06 22:42:20 -04:00
Simon Cruanes
7bdc3cff24 add example CCParse-based Sexpr parser, and a test 2021-06-06 18:50:28 -04:00
Simon Cruanes
88fe234a4c add CCParse.{char_fold, chars_fold_map}
useful for non-trivial lexing
2021-06-06 18:49:55 -04:00
Simon Cruanes
c63a2b7b37 fix tests: use dune's locks with absolute path 2021-06-06 18:49:36 -04:00
Simon Cruanes
294fce8634 fixup! feat(ord): add poly, deprecate compare 2021-06-06 17:39:09 -04:00
Simon Cruanes
7081a411c8 small doc change 2021-06-06 17:16:26 -04:00
Simon Cruanes
78a530ccee feat(ord): add poly, deprecate compare 2021-06-06 17:15:51 -04:00
Simon Cruanes
c10ae8d84f parse: fix bugs, add tests, add U.{in_paren,in_paren_opts,option} 2021-06-06 17:08:57 -04:00
Simon Cruanes
37af485971 parse: expose Position module, add or_, both, lookahead, U.bool 2021-06-06 15:08:13 -04:00
Simon Cruanes
171b4ddcd9 parse: deprecate try_, rename new function try_opt 2021-06-06 14:14:48 -04:00
Simon Cruanes
0ec40c2331 CCParse: heavy refactoring, many new functions 2021-06-06 14:14:48 -04:00
Simon Cruanes
7318162c55 wip: rework CCParse 2021-06-06 14:14:48 -04:00
Simon Cruanes
40a6c17548 small changes in CCIntMap, some cleanup 2021-06-06 14:14:05 -04:00
Simon Cruanes
95e96fb5e1 feat(CCFormat): expose ANSI_codes module 2021-06-04 15:43:59 -04:00
Simon Cruanes
ba638aeb70 makea benchs sohuld use profile=release 2021-06-04 10:21:22 -04:00
Simon Cruanes
57e810a882 Revert "small changes related to docs of sorted_diff_uniq"
This reverts commit f7a2edae25.
2021-05-25 19:19:48 -04:00
Simon Cruanes
f7a2edae25
small changes related to docs of sorted_diff_uniq 2021-05-25 19:16:37 -04:00
favonia
1c6bc16362 style(list): move sorted_mem up 2021-05-24 09:26:23 -05:00
favonia
8d532f9a00 feat(list): add sorted_diff_uniq
Also fixed documentation
2021-05-24 09:26:08 -05:00
Fardale
19c65b5472 apply comments from the review 2021-05-23 15:01:36 +02:00
Fardale
6a3e446d27 use precomputed table for count_bits_ 2021-05-23 14:49:31 +02:00
favonia
80e403c969 feat(list): add sorted_mem 2021-05-23 00:45:18 -05:00
favonia
e58c5d8f3b fix(list): add the test sorted_diff (sorted_merge l1 l2) l2 = l1
Also fixed a typo.
2021-05-22 21:41:36 -05:00
favonia
c030beaf52 fix(list): support 4.03 (using CCList.init) 2021-05-22 21:29:21 -05:00
favonia
6d2dc4ccf4 feat(list): add the optional argument all to sorted_remove
Also added another missing "since".
2021-05-22 21:27:35 -05:00
favonia
f6829d1219 fix(list): add "since" for sorted_diff
Co-authored-by: Simon Cruanes <simon.cruanes.2007@m4x.org>
2021-05-22 21:06:20 -05:00
favonia
130f0a63bb feat(list): add sorted_diff 2021-05-22 21:02:15 -05:00
favonia
de7f445207 fix(list): support 4.03 2021-05-22 20:43:35 -05:00
favonia
8c197da02c feat(list): add sorted_remove 2021-05-22 20:28:45 -05:00
Fardale
8ff253f18d chore(CCBV): clean comments 2021-05-22 22:09:24 +02:00
Fardale
8f65bf639b use bytes instead of int array for CCBV 2021-05-22 21:38:36 +02:00
Fardale
3eb676c55c replace for loop and unsafe_get by using iter 2021-05-19 23:36:00 +02:00
favonia
e3b0600a8b fix(hash): resolve ambiguous doc comment of bytes 2021-05-18 17:53:23 -04:00
Simon Cruanes
f352ca916d add a bit of doc 2021-05-18 11:11:31 -04:00
Simon Cruanes
c286bb6d4e Update src/core/CCHash.mli 2021-05-18 10:54:44 -04:00
favonia
13429e5e88 feat(hash): add bytes 2021-05-18 10:54:44 -04:00
Simon Cruanes
795ae5c546 bv: also refactor inter 2021-05-17 10:03:58 -04:00
Simon Cruanes
1c8265c3f3 bv: refactor for performance and readability 2021-05-17 10:01:35 -04:00
Simon Cruanes
92519b4843 fix(bv): index error in union
close #370
2021-05-17 10:00:59 -04:00
Simon Cruanes
a642aa6f6b bv: add more tests, including regression for #370 2021-05-17 10:00:32 -04:00
Simon Cruanes
1b0639886d feat(bv): add equal 2021-05-17 10:00:05 -04:00
Simon Cruanes
6ace6f71e0 doc: fix wrong @since 2021-05-10 11:26:53 -04:00
Simon Cruanes
1167ffdb3c relax constraints in opam 2021-05-04 08:54:08 -04:00
Simon Cruanes
6bfd7f125e test: fix too broad test 2021-05-04 08:54:08 -04:00
Simon Cruanes
943ce7f734 get ready for 3.4 2021-05-03 16:56:24 -04:00
Simon Cruanes
c99f7818c3 udpate doc and add test 2021-04-27 13:21:34 -04:00
Daniil Baturin
3628feed9c Add CCOpt.get_exn_or and deprecate CCOpt.get_exn 2021-04-27 13:15:51 -04:00
Simon Cruanes
0d9a3b82fa
Merge pull request #365 from jberdine/gar
feat(CCRAL): add `get_and_remove_exn` operation
2021-04-16 10:51:17 -04:00
Josh Berdine
430e2a4951 test: ensure tests are run by disabling dune cache 2021-04-16 10:45:28 -04:00
Josh Berdine
9211a01f35 code review 2021-04-16 15:15:11 +01:00
Josh Berdine
9e6f453aff feat(CCRAL): add get_and_remove_exn operation
It seems like a waste to repeat the search for an index to both get
the element at that index and then to remove it. The added
`get_and_remove_exn` operation performs a `remove` but returns the
found element rather than forgetting it.
2021-04-16 14:48:14 +01:00
Josh Berdine
0ab8597b78 fix: CCRAL.remove does not remove 2021-04-15 17:56:36 -04:00
Simon Cruanes
b19cd0db5f add regression test for #364 2021-04-15 17:54:18 -04:00
Simon Cruanes
5611cbf7f3 fix(sexp): re-export the loc type to the functor's argument's type 2021-04-15 10:34:27 -04:00
Fardale
375ae27622 feat(CCString): add CCString.uniq
CCString.uniq remove consecutive duplicate characters
2021-04-08 23:09:53 +02:00
Simon Cruanes
e75d93bb9d refactor and clarify cutoff in String.edit_distance 2021-04-08 11:20:54 -04:00
Simon Cruanes
45b3956421 improve test hash 2021-04-05 00:13:33 -04:00
Fardale
8d6c7470eb Revert "ci: test containers-data on windows and macos"
This reverts commit 75a2f8a325.
2021-04-04 23:39:48 +02:00
Fardale
72b25cfa29 Revert "ci: install test dependency for containers-data on windows and macos"
This reverts commit ca3ca3aaff.
2021-04-04 23:39:37 +02:00
Fardale
ca3ca3aaff ci: install test dependency for containers-data on windows and macos 2021-04-04 23:32:46 +02:00
Fardale
75a2f8a325 ci: test containers-data on windows and macos 2021-04-04 23:23:46 +02:00
Simon Cruanes
25c5eda528 doc: more docs for codegen 2021-04-03 18:54:07 -04:00
Simon Cruanes
4f68b0fc37 fix test for old ocaml 2021-04-03 18:12:03 -04:00
Simon Cruanes
2440092eb5 fix invalid test in intmap 2021-04-03 17:42:17 -04:00
Simon Cruanes
77e3e97dd0 perf: direct alias in CCHash.int 2021-04-03 17:42:17 -04:00
Simon Cruanes
93c0a9af0d fix qtest generation 2021-04-03 17:42:17 -04:00
Simon Cruanes
6323bdc6d3 fix test in CCHash 2021-04-03 17:42:17 -04:00
Simon Cruanes
5bd031c3c2 add test executable for hash functions 2021-04-03 17:42:17 -04:00
Simon Cruanes
cf0d044407 refactor CCHash to use FNV in many combinators 2021-04-03 17:42:17 -04:00
Simon Cruanes
238123b955 move uniformity tests out of CCRandom 2021-04-03 17:42:17 -04:00
Simon Cruanes
7717cc13db fix(ccint): make sure hash is always positive 2021-04-03 17:42:17 -04:00
Simon Cruanes
cc7799f379 perf(ccint): single implementation of popcount using int64 2021-04-03 17:42:17 -04:00
Simon Cruanes
ec796d5fc5 perf(int): use FNV for integer hashing 2021-04-03 17:42:17 -04:00
Fardale
79bbb5ce33 ci: fix cache key for gh-pages 2021-04-03 20:27:44 +02:00
Fardale
701a558676 ci: fix cache for gh-pages job 2021-04-03 20:25:54 +02:00
Fardale
b2342ead0a ci: update ocaml version for gh-pages 2021-04-03 16:41:54 +02:00
Fardale
957bbb10d2 readme: update status badge 2021-04-03 16:38:38 +02:00
Fardale
c7b4c0d0de ci: limit test to 1 process for windows and macos 2021-04-03 12:37:11 +02:00
Fardale
02224148c6 ci: fix name of the main branch 2021-04-02 21:25:08 +02:00
Fardale
8e1e4d36ed ci: fix caching and other improvement 2021-04-02 21:23:00 +02:00
Simon Cruanes
739dd4412c prepare for 3.3 2021-04-01 22:16:40 -04:00
Bertrand Bonnefoy-Claudet
13028c3d17 CCSeq: Add for_all and exists
The functions are implemented the same way as in `oseq` and their
documentation is inspired from their counterparts in `Stdlib.List`.
2021-03-29 18:16:44 -04:00
Simon Cruanes
bfaffc5c39 refactor: have bench compile again 2021-03-28 18:15:45 -04:00
Simon Cruanes
f41887c367 refactor(pool): less locking, fix deadlock, more parallelism 2021-03-28 18:15:45 -04:00
Simon Cruanes
40c05cc7e3 wip: feat(pool): keep one idle thread
see #360; in combination with max_size=1 it means the pool contains
exactly one thread.
2021-03-28 18:15:45 -04:00
Simon Cruanes
8982f87ca7 perf: small optim in Pool.sequence_a 2021-03-28 18:15:45 -04:00
Simon Cruanes
dd1cf2a046 perf(pool): try to inline with_lock 2021-03-28 18:15:45 -04:00
Simon Cruanes
178f7dc92f feat(sexp): expose last location in decoder 2021-03-25 15:20:51 -04:00
Matt Bray
0a54024143 doc: clarify CCOpt.filter 2021-03-19 10:37:28 -04:00
Simon Cruanes
0de515b94b attempt to fix tests 2021-03-13 16:56:21 -05:00
Fardale
2c96dd1b55 feat(CCChar): add CCChar.Infix 2021-03-12 18:27:53 +01:00
Fardale
4ad331fbe3 feat(CCString): add CCString.foldi 2021-03-12 18:13:29 +01:00
Simon Cruanes
5ad8914e4c feat: add code-generator for optimal bitfields; add tests 2021-03-02 09:40:42 -05:00
Simon Cruanes
5593e28431 feat(CCFormat): add string_lines combinator 2021-02-26 17:25:33 -05:00
Simon Cruanes
89d6feed98 fix 2021-02-25 12:59:56 -05:00
Fardale
1975c98025 fix: wrong name in 6b52ec69
partition_filter_either -> partition_map_either
2021-02-25 18:51:33 +01:00
Fardale
6b52ec6945 feat(CCList): update with regards to partition_map
- Add partition_filter_map
- Deprecate partition_map
- Add partition_map_either that match the partition_map from the std
2021-02-25 17:31:15 +01:00
Simon Cruanes
30121b8d2c
Merge pull request #358 from copy/master
Fix integer overflow warning on jsoo (#346)
2021-02-22 20:56:41 -05:00
Fabian
dcf1b4aa6c Fix integer overflow warning on jsoo (#346)
- Remove popcount from shims
- Express large integer literals using bitshifts
2021-02-21 15:53:54 -05:00
Simon Cruanes
b5ecb273ef feat: add CCList.cons'
close #354
2021-02-12 14:35:29 -05:00
Simon Cruanes
2f7366be59
Merge pull request #351 from darrenldl/add-fuzz-helper-scripts
Small upgrade to fuzzing suite scripts
2021-02-12 10:54:54 -05:00
Simon Cruanes
01f70cc802 update code and comments 2021-02-07 13:03:53 -05:00
Arnaud Spiwack
85decd732c
CCMap: implement {of,add}_*_with family of function with update (#352)
This is comparable in conciseness and clarity as an explicit try/with
but it paves the way for a more efficient implementation using the
`update` from the Stdlib which, I presume, uses a one-pass algorithm.
2021-02-07 13:03:33 -05:00
Simon Cruanes
3bee276028 try to fix stupid CI 2021-02-06 12:22:20 -05:00
Simon Cruanes
0ef515f1af feat: add CCHashtbl.{of,add}_{list,seq,iter}_with 2021-02-06 12:16:03 -05:00
Simon Cruanes
51bb9175f3 add CCMap.of_{list,iter,seq}_with functions 2021-02-06 11:50:41 -05:00
Fardale
c4aabbf699 doc: fix doc in CCParse 2021-02-05 15:25:25 +01:00
Darren Ldl
d276208c81 Updated fuzz/run.sh with an upgraded version 2021-02-05 15:29:06 +11:00
Darren Ldl
8efa095a11 Updated .gitignore to ignore fuzz-logs/ 2021-02-05 15:28:45 +11:00
Darren Ldl
5de909a534 Copied fuzzing helper scripts over 2021-02-05 15:20:55 +11:00
Simon Cruanes
447df826f1 move canonical sexps into their own module 2021-02-02 23:02:54 -05:00
Simon Cruanes
176b2e5ff2 cleanup of makefile 2021-02-02 22:48:16 -05:00
Simon Cruanes
427c15e472 add fuzzing for csexp 2021-02-02 22:48:08 -05:00
Simon Cruanes
b2b1d2b5fa feat(ccsexp): printer and parser for canonical S-exprs 2021-02-02 22:16:15 -05:00
Simon Cruanes
0097fd3c3d prepare for 3.2 2021-02-01 10:40:28 -05:00
Fardale
f313361df7 try to fix CI for gh-pages 2021-01-26 12:03:12 +01:00
Fardale
5520735a77 fix: enable jekyll on gh-pages 2021-01-26 11:55:50 +01:00
Fardale
179d19e444 fix(CI): correct the name of the main branch 2021-01-26 11:43:07 +01:00
Fardale
b34c3fe75a try to enable auto deploy of doc 2021-01-26 11:41:44 +01:00
Fardale
d9df726ca0 clean: remove stuff specific for ocaml < 4.03 2021-01-26 11:27:50 +01:00
Simon Cruanes
3068aacc84
Merge pull request #349 from c-cube/cceither
feat: add CCEither module
2021-01-25 14:02:07 -05:00
Fardale
23bcc8887c feat: add CCEither module 2021-01-25 19:52:16 +01:00
Fardale
124a808b54 chore(CI): test core on non ubuntu platform 2021-01-25 19:44:00 +01:00
Fardale
a6318949f6 chore(CI): run test only on Ubuntu 2021-01-25 18:51:11 +01:00
Fardale
663416b350 fix: change container.data to container-data in README.md 2021-01-25 18:04:28 +01:00
JPR
383baf4464 Syncing comments 2021-01-25 15:57:03 +01:00
Simon Cruanes
ae886c2f08 add CCList.chunks 2021-01-24 11:18:53 -05:00
Simon Cruanes
e037ca1afa doc: fix a link in the readme
close #347
2021-01-22 11:08:28 -05:00
Simon Cruanes
5f7b03d83b doc: refresh readme 2021-01-12 12:32:45 -05:00
Simon Cruanes
646ea1645c doc: update readme 2021-01-12 11:53:52 -05:00
Simon Cruanes
f9e9c39c37 feat: add iter/seq functions to CCString 2021-01-12 11:53:37 -05:00
Simon Cruanes
fc57765c31 fix(ccint): pick popcount at runtime on 64 bits
(we can compile on 64 bits, at least for bytecode, and execute
on 32 bits native or jsoo's 32 bits; therefore we need to pick the
implementation at runtime).
2020-12-28 17:13:02 -05:00
Simon Cruanes
858dee7279 fix: in shims, use configurator properly to determine int size
close #346
2020-12-27 22:44:20 -05:00
Simon Cruanes
bb8a9d02d7 chore: try to optimize CI a bit further 2020-12-22 10:45:43 -05:00
Simon Cruanes
fb4891dac3 yoloize the github CI cache 2020-12-22 10:45:43 -05:00
Simon Cruanes
12ac1de588 be nicer to mac OS' lazy scheduler in tests 2020-12-22 10:45:43 -05:00
Simon Cruanes
330e026d0a try to enable cache in CI 2020-12-22 10:45:43 -05:00
Kye W. Shi
fd1a43497d
CCImmutArray: add tests (#344)
CCImmutArray: add tests
2020-12-16 23:39:46 -05:00
Kye Shi
78681736cd CCFormat: add @since tags for space/append/etc. 2020-12-14 13:36:35 -05:00
Kye W. Shi
82781aa9c7 CCFormat: List.iter instead of fold_left for append_l (more efficient)
Co-authored-by: Simon Cruanes <simon.cruanes.2007@m4x.org>
2020-12-14 13:36:35 -05:00
Kye Shi
d0b05fdb76 CCFormat: add append, append_l, infix ++ for sequencing 2020-12-14 13:36:35 -05:00
Kye Shi
b1643cfbd5 CCFormat: add space, break, cut aliases 2020-12-14 13:36:35 -05:00
Kye Shi
d5f2c6b861 CCList: add reduce function (resolves #305) 2020-12-13 17:15:43 -05:00
Simon Cruanes
4b68dc204a chore: activate CI on PRs 2020-12-13 17:14:28 -05:00
Darren
c8d0c60657
Init files for fuzzing (#339)
* Init files for fuzzing
* Fixed fuzz/run.sh
* Added fuzzing for CCUtf8_string.uchar_to_bytes
2020-12-09 16:10:02 -05:00
Simon Cruanes
fcd1247ec8 test: add stronger test to compare with uutf in ccutf8string 2020-12-07 23:42:31 -05:00
Simon Cruanes
52abbcd978 fix(sexp): handle non-ascii escapes in strings
close #338
2020-12-07 23:33:34 -05:00
Simon Cruanes
43701e6726 test: add regression test for #338 2020-12-07 23:32:40 -05:00
Simon Cruanes
e16926fa5f add tests for utf8string 2020-12-07 23:32:00 -05:00
Simon Cruanes
3918ed1155 feat(utf8): add and expose uchar_to_bytes
rather than encoding to buffers directly, we can expose an iterator
over the bytes of an uchar.
2020-12-07 23:31:05 -05:00
Simon Cruanes
f9ee8d0e89 prepare for 3.1 2020-12-04 18:39:54 -05:00
Simon Cruanes
f3e808e870 Merge branch 'wip-ci-2020-11-10' 2020-12-04 17:48:03 -05:00
Simon Cruanes
133aed683c fix build 2020-11-13 17:58:18 -05:00
Simon Cruanes
ca7801a854 fix: use shims again for CCList.(and&) 2020-11-13 15:36:55 -05:00
Simon Cruanes
9068cbc1cc fix tests and build 2020-11-10 18:06:30 -05:00
grayswandyr
057427cb72 Apply suggestions from code review
Co-authored-by: Simon Cruanes <simon.cruanes.2007@m4x.org>
2020-11-10 18:04:27 -05:00
David Chemouil
3912b288e8 add List.combine_chop and corresponding (and&) synchronized product 2020-11-10 18:04:27 -05:00
Simon Cruanes
60eee785a9 doc: update readme 2020-11-10 14:06:19 -05:00
Simon Cruanes
af05520e3b chore: try and remove travis to use github CI instead 2020-11-10 14:06:03 -05:00
JPR
b3e32c587f Comments 2020-11-06 16:57:01 -05:00
David Chemouil
61a8cc58bd add a guard function for list comprehensions 2020-11-05 12:10:14 -05:00
Simon Cruanes
26df938968 more doc 2020-11-05 12:05:31 -05:00
Simon Cruanes
7e160106c5 doc: explain a bit more the Traverse submodule of list 2020-11-05 11:54:48 -05:00
Simon Cruanes
87a9937938 doc: indicate that ccmutheap is experimental 2020-11-04 12:29:15 -05:00
Simon Cruanes
587e445308 doc: add missing @since 2020-10-30 13:06:07 -04:00
Simon Cruanes
9643ee94a9 test: add some basic tests to CCMutHeap 2020-10-07 12:03:37 -04:00
Simon Cruanes
aed72685fc refactor: ask for lt in the mutable heap arg 2020-10-07 12:03:27 -04:00
Simon Cruanes
3484efc691 feat: add mutable heap with increase/decrease to containers-data
this code is adapted from msat
2020-10-07 11:45:58 -04:00
Simon Cruanes
9ca278dc51 fix obsolete comment 2020-10-04 12:50:04 -04:00
Simon Cruanes
e0f14837ac fix warning 2020-09-23 21:34:14 -04:00
Simon Cruanes
264c9b608e un-specify order of elements in CCMap.to_list 2020-09-21 13:49:50 -04:00
Simon Cruanes
5ee25afad5 test: add a test for update 2020-09-21 13:49:49 -04:00
Josh Berdine
e6f77edf1a Move definition of CCMap.update so that it is shadowed by Stdlib.Map.update
Signed-off-by: Josh Berdine <josh@berdine.net>
2020-09-21 13:49:25 -04:00
Josh Berdine
d81cba4b06 Update contributing instructions in README
Signed-off-by: Josh Berdine <josh@berdine.net>
2020-09-21 09:47:58 -04:00
Simon Cruanes
652c823978 fix(intmap): order of arguments for the HO param should be stable
close #329
2020-09-08 10:42:10 -04:00
Simon Cruanes
9a9ae12972 chore: try to fix travis 2020-08-24 10:35:40 -04:00
Simon Cruanes
a59562bed1 prepare for 3.0.1 2020-08-24 10:13:03 -04:00
Simon Cruanes
50ec164b67 fix: remove code that is in the shims 2020-08-06 11:19:52 -04:00
Simon Cruanes
09298b3324 small change in shims generation
as @fardalem points out, better be conservative on archictures and have
64bits popcount be the special case
2020-08-06 09:46:33 -04:00
Simon Cruanes
e0f2c78edd fix(int): use shims to provide separate 32/64 bits versions of popcount
close #327
2020-08-05 14:05:48 -04:00
Simon Cruanes
9fe414f793 chore: small refactor of github actions
sadly the matrix thing is not expressive enough to use a
given switch only on a given OS (like, windows + mingw32).
So, 🤷
2020-08-05 14:05:12 -04:00
Simon Cruanes
38d8fc2f9a doc: update readme 2020-08-04 09:42:55 -04:00
Simon Cruanes
ade2500e68 prepare for 3.0, without further ado 2020-07-31 15:51:46 -04:00
Simon Cruanes
089a1bec16 try to fix tests that fail on mac OS 2020-07-31 15:29:49 -04:00
Simon Cruanes
8a60d44946 ci: try to test on mac OS again, amend tests, make mdx optional 2020-07-30 19:12:49 -04:00
Simon Cruanes
d60bea1a98 fix build for 4.11 by working around -nolabels 2020-07-30 10:02:16 -04:00
Simon Cruanes
8683153cc9 fix opam files 2020-07-28 20:19:58 -04:00
Simon Cruanes
01d9693a16 wip: fix travis 2020-07-28 20:17:33 -04:00
Simon Cruanes
add6a58cf5 prepare for 3.0~rc1 2020-07-28 18:15:05 -04:00
Simon Cruanes
2eb58dd6c4 prepare readme and changelog for 3.0~rc1 2020-07-28 18:12:12 -04:00
Simon Cruanes
5da10f49a2 doc: small fix 2020-07-28 17:52:55 -04:00
Simon Cruanes
211cd5863b feat: add infix operators to String
close #315
2020-07-28 17:34:59 -04:00
Simon Cruanes
39e0ad2395 fix(pool): missing emptiness check in Fut.map_l
also add regression test
2020-07-28 16:27:23 -04:00
Simon Cruanes
30b9307a70
Merge pull request #325 from c-cube/ccpair_map
break(CCPair): use more standard name for some map functions
2020-07-27 22:58:58 -04:00
Fardale
01da25cead break: change pp functions to take unit printer for sep/stop/start
sep/stop/start -> pp_sep/pp_stop/pp_start
string -> unit printer
2020-07-27 22:57:29 -04:00
Fardale
3b2030f6f2 break(CCPair): use more standard name for some map functions
map1 -> map_fst
map2 -> map_snd
map_fst -> fst_map
map_snd -> snd_map
introduce map2 and map_same2
Fix #316
2020-07-27 21:39:17 +02:00
Simon Cruanes
4ac67a7518
chore(ci): fix bad test logic 2020-07-24 09:58:17 -04:00
Simon Cruanes
1f1b859ec7 Merge remote-tracking branch 'origin/wip-github-ci' 2020-07-23 12:56:00 -04:00
Fardale
a8bcbb0e3d chore(CCHeap): drop old comment 2020-07-23 16:32:52 +02:00
Fardale
b6b2c68913 break(CCGraph): remove deprecated module and function
Remove Seq and pp_seq
2020-07-23 16:32:52 +02:00
Simon Cruanes
644e3487a3 test: fix a test that wouldn't pass on 4.03 2020-07-23 16:32:52 +02:00
Simon Cruanes
4122ffa6ab doc: fix some ocamldoc warnings 2020-07-23 16:32:52 +02:00
Fardale
c22fed18de break: convert sequence to iter in data 2020-07-23 16:32:52 +02:00
Fardale
08d59ea07a break: remove klist in data 2020-07-23 16:32:52 +02:00
Fardale
c85c135157 break: remove klist type and functions from core 2020-07-23 16:32:52 +02:00
Fardale
8c3d716ab1 break: rename fonction from *std_seq* to *seq* 2020-07-23 16:32:52 +02:00
Simon Cruanes
fa1f6170d1 chore: github actions: only run tests on linux 2020-07-22 18:24:12 -04:00
Simon Cruanes
aba959aa89 chore(ci): widen support for github CI 2020-07-22 18:00:54 -04:00
Simon Cruanes
c2cab292b1 chore: add github ci 2020-07-22 17:40:59 -04:00
Simon Cruanes
8b41a2bf69 doc: add missing @since 2020-07-22 17:08:48 -04:00
Kye W. Shi
3bae829558 CCResult: add <$> operator 2020-07-22 16:23:04 -04:00
JPR
0a3b04855a ... tweaks 2020-07-02 09:38:25 -05:00
JPR
063a59eee4 Comments 2020-07-02 09:38:25 -05:00
Fardale
8b319edbe1
doc(core): add link to the doc of std module (#320) 2020-06-30 17:31:52 +02:00
Fardale
20234cdd22 fix(CCVector): rename shrink into truncate 2020-06-30 09:02:52 -05:00
Simon Cruanes
1469c72f30 doc: remove list of authors and point to github instead
this prevents the list of authors from getting stale or outdated,
by just relying on existing tools
2020-06-19 21:22:08 -04:00
Kye W. Shi
06b795c604 CCFun: add infix tests 2020-06-19 20:17:30 -05:00
Kye W. Shi
6cfa7307de CCFun: include module type of Infix 2020-06-19 20:17:30 -05:00
Kye W. Shi
a03b6e68e3 CCFun: put infix operators in Infix module 2020-06-19 20:17:30 -05:00
Fourchaux
a5da43511b
comments modifs (#311) 2020-06-17 09:21:31 +02:00
Fourchaux
53febce5a9
Comments presentation (#310)
* Comments presentation
2020-06-12 09:52:50 +02:00
Simon Cruanes
54099f10d5 test: regression test for stack overflow in CCpool 2020-05-24 19:12:04 -04:00
Fardale
685efeae28
Merge pull request #308 from FardaleM/ccint
CCInt{,32,64} and CCNativeint
2020-05-24 00:53:08 +02:00
Fardale
364a9ba1cb
Merge pull request #309 from FardaleM/clean_ccarray
chore(array): clean CCArray and CCArrayLabels
2020-05-24 00:52:49 +02:00
Fardale
5dc96ebfa8 chore(array): clean CCArray and CCArrayLabels
Remove function define in the stdlib and in Infix
2020-05-23 12:52:26 +02:00
Fardale
8c0d11546e small doc fix 2020-05-23 11:37:56 +02:00
Fardale
b8ca053a48 feat(ccnativeint): complete CCNativeint with regards to CCInt 2020-05-23 11:37:56 +02:00
Fardale
f2c0bc7d09 chore(ccnativeint): clean CCNativeint.mli
Remove duplicate functions from Infix and Nativeint
2020-05-23 11:37:56 +02:00
Fardale
1fec2f0f96 chore(ccint64): clean CCInt64.mli
Remove duplicate functions from Infix and Int64
2020-05-23 11:37:56 +02:00
Fardale
efc162125a chore(int32): clean CCInt32.mli
Remove duplicate function from Int32 and Infix module
2020-05-23 11:37:56 +02:00
Fardale
576ee2ede8 feat(Int64): complete CCInt64 with regards to CCInt 2020-05-23 11:37:56 +02:00
Fardale
b7dcc7ed2a chore(int32): change order of definition 2020-05-23 11:37:56 +02:00
Fardale
92b31bedb2 chore(int64): remove duplicate functions between Int64 and CCInt64 2020-05-23 11:37:56 +02:00
Fardale
e574309763 feat(CCInt32): complete CCInt32 with regards to CCInt 2020-05-23 11:37:56 +02:00
Fardale
102ad62075 fix: correct module name in Invalid_argument for CCInt.range_by 2020-05-23 11:37:56 +02:00
Fardale
b06155f05b implement CCInt.sign using CCInt.compare and add more doc 2020-05-23 11:37:56 +02:00
Fardale
eaa421c62d chore(int): include module Int for ocaml >= 4.08 2020-05-23 11:37:56 +02:00
Fardale
8f5c7c8fe9 feat(int): add elements of Int module from the std 2020-05-23 11:37:56 +02:00
Simon Cruanes
5dd90edafa add CCResult.get_lazy 2020-05-21 15:26:27 -04:00
Simon Cruanes
d7a7cbb170 feat: add Int.popcount operator 2020-05-18 14:04:42 -04:00
Simon Cruanes
4b09adaa5a fix typo 2020-05-15 15:28:27 -04:00
Raphael Sousa Santos
4936cb60d4 Add CCFloat.pi 2020-05-15 14:27:59 -05:00
Simon Cruanes
18222af1a3 perf: a few more inline annotations 2020-05-12 12:46:12 -04:00
Simon Cruanes
97e49b6a5c fix: expose always_eq/never_eq in CCEqual
see #232
2020-05-06 10:33:28 -04:00
Simon Cruanes
b26021a976 feat(string): add optional cutoff arg on String.edit_distance
also add more tests
2020-04-30 22:19:49 -04:00
Simon Cruanes
d99d35cc70 chore: travis detail 2020-04-30 22:19:28 -04:00
Simon Cruanes
2153c8a5e6 fix(dune): only build containers-data.top in bytecode 2020-04-30 22:19:06 -04:00
Simon Cruanes
47b631d3f4
Merge pull request #304 from FardaleM/mem
harmonize CCList.mem and CCArray.mem
2020-04-28 16:41:50 -05:00
Fardale
7dd45a0fa8 fix(CCArray) fix use of Stdlib for ocaml < 4.07 2020-04-28 22:31:33 +02:00
Fardale
789eee9d53 CCArray: add @since 2020-04-28 22:26:42 +02:00
Fardale
4267210da9 CCArray: use raise_notrace instead of raise 2020-04-28 22:26:20 +02:00
Fardale
2faa3fbae5 chore(CCVector): rename remove to remove_and_shift 2020-04-28 08:53:35 -05:00
Fardale
c8d61a1248 feat(CCVector): add remove
remove keep the order of the element but need to move
all element after the removed one.
2020-04-28 08:53:35 -05:00
Fardale
c1461940c2 wip(3.0): rename CCVector.remove to CCVector.remove_unordered 2020-04-28 08:53:35 -05:00
Fardale
c50672ff7a feat(CCArray): add optional argument eq to mem 2020-04-28 15:41:01 +02:00
Fardale
2025a62536 feat(CCList): make mem compatible with the Stdlib
The eq argument is now optional.
2020-04-28 15:39:47 +02:00
JPR
0f9e51fbe3 Comments presentation 2020-04-26 16:17:17 -05:00
Simon Cruanes
0fea0ea522 opam and travis 2020-04-24 22:47:37 -04:00
Simon Cruanes
5d536afb68 try to fix test 2020-04-24 22:24:05 -04:00
Simon Cruanes
d7bf01f118 chore: update travis 2020-04-24 21:43:35 -04:00
Simon Cruanes
df5151636b improvements 2020-04-24 21:11:44 -04:00
Simon Cruanes
d923795e1a remove slice APIs in string and array 2020-04-24 20:23:26 -04:00
Simon Cruanes
a767e4618d wip(3.0): remove deprecated functions, in particular sequence 2020-04-24 20:16:53 -04:00
Simon Cruanes
46e40c9165 delete containers.iter and merge parts of it into containers-data 2020-04-24 19:48:42 -04:00
Simon Cruanes
a2d07e4028 chore: update tests to accomodate for split into several libs 2020-04-24 19:27:06 -04:00
Simon Cruanes
b1b5d31665 breaking: move CCSexp into the core library, delete containers.sexp 2020-04-24 19:13:54 -04:00
Simon Cruanes
49545decbf update top packages 2020-04-24 19:07:56 -04:00
Simon Cruanes
da46adb370 chore: split into distinct packages for containers-data and containers-thread 2020-04-24 18:59:39 -04:00
Simon Cruanes
e43f658fa9
Merge pull request #299 from copy/master
add more benchmarks
2020-04-19 17:28:14 -05:00
Fabian
b82d31adf1 Improve use of opaque_identity 2020-04-19 18:05:14 +02:00
Fabian
dafae58e15 Extend benchmark: to_array, cons and cons_fold 2020-04-19 17:59:14 +02:00
Fabian
d681a34caa Extend benchmark: Sek, iter and pop 2020-04-19 17:58:39 +02:00
Fabian
a1233392f0 fix naming 2020-04-19 17:46:00 +02:00
Fabian
d72907302a Disable core_kernel test for now 2020-04-19 17:42:13 +02:00
Fabian
53d5a80b96 benchmark for memory usage of data structures 2020-04-19 17:37:25 +02:00
Simon Cruanes
952b664a68 test for funvec 2020-04-18 22:14:35 -04:00
Simon Cruanes
15fb26249f fix(funvec): error in pop
close #298
2020-04-18 22:10:35 -04:00
Simon Cruanes
d34b7588b0 test: another test 2020-03-29 21:50:39 -04:00
juloo
203723d350 CCSexp: Escape empty atoms
Otherwise (`List [ `Atom "" ]) would be formatted as "()", which is (`List []).
2020-03-29 20:48:56 -05:00
JPR
a5b8a0aa18 Substitute 'Pervasives' with 'Stdlib' 2020-03-24 10:43:49 -04:00
JPR
76c1c98bbf Modifs comments 2020-03-16 15:56:12 -05:00
Simon Cruanes
fb6483539e feat(fmt): add exn combinator 2020-03-07 11:26:00 -06:00
Simon Cruanes
d12213da31 doc: missing raise annotation 2020-03-07 11:25:49 -06:00
Simon Cruanes
dc10a55a75 fix typo
close #289
2020-03-06 08:37:02 -06:00
Fardale
93be8b2cd8 fix *Labels.mli for ocaml <= 4.04 2020-03-05 17:50:30 -06:00
Fardale
c59147f1d1 clean(String): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
baec1f466e clean(Set): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
71a3ebdeb5 clean(Nativeint): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
80ad2f349f clean(Map): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
0d9b4d910a clean(List): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
4f0e219036 clean(Int64): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
7821e8e259 clean(Int32): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
b96f7d6e68 clean(Char): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
f3719d29aa clean(Array): remove functions defined in Stdlib 2020-03-05 17:50:30 -06:00
Fardale
2bde1e4dd3 doc(CCInt): add doc for of_float 2020-03-05 15:42:24 +01:00
Simon Cruanes
cd26e3d3a3 IO: add copy_into for transferring data between channels 2020-01-28 13:03:08 -06:00
Fardale
618e57fdd7 examples: remove lambda.ml 2020-01-27 13:55:50 -06:00
Fardale
51a532ce59 examples: clean up 2020-01-27 13:55:50 -06:00
Fardale
8c43e345ad doc(CCFloat): document the rounding behavior
fixes #237
2020-01-24 23:01:47 +01:00
Fardale
d1a5e047fe feat(CCResult): add get_lazy
fixes #285
2020-01-24 22:57:25 +01:00
Fardale
9d083df3a6 feat(CCInt): add of_float 2020-01-18 16:16:52 +01:00
Fardale
2d1ba8d925 feat(CCInt): add of_string_exn 2020-01-18 15:57:55 +01:00
Simon Cruanes
c1b976d0d3 Merge branch 'br-2.8.1' 2020-01-13 08:30:19 -06:00
Fabian
50042d6c09 Document raising behaviour of CCIO.tee 2020-01-12 20:30:18 -06:00
Fabian
2bf052ab7a Avoid catch-all handlers 2020-01-12 20:30:18 -06:00
Simon Cruanes
8c33147d06 add some tests 2020-01-12 20:28:22 -06:00
Simon Cruanes
527c4414d9 prepare for 2.8.1 2020-01-12 18:18:33 -06:00
Simon Cruanes
2e3393f81e fix: add missing CCVector.of_iter 2020-01-12 18:18:33 -06:00
Fardale
2b5f2fce11 feat(CCVector): add filter_in_place, deprecate filter' 2020-01-08 23:17:53 +01:00
Fardale
4bc01a0b82 feat(opt): fix bind arguments order 2020-01-06 21:39:55 +01:00
Fardale
bf8db5dcff feat(opt): add bind 2020-01-06 16:15:52 +01:00
Fardale
1dcc529623 feat(float): add of_string_opt 2020-01-06 16:15:05 +01:00
Simon Cruanes
5143e28ce8 doc: fix readme url 2019-12-17 08:05:17 -06:00
Simon Cruanes
5126973173 prepare for 2.8 2019-12-14 17:50:35 -06:00
Simon Cruanes
ab494fb753 fix: compat issue 2019-12-14 17:50:35 -06:00
Simon Cruanes
7d9d9d45b8 feat(list): add indexed functions and fold_on_map
close #222
2019-12-14 16:52:35 -06:00
Simon Cruanes
1947d1804b refactor: also port CCGraph to iter 2019-12-14 16:41:49 -06:00
Simon Cruanes
264e89b198 chore: makefile 2019-12-14 16:32:24 -06:00
Simon Cruanes
138047ef11 feat: add {to,of,add}_{iter,std_seq} where relevant; deprecations
deprecate `seq` named functions (for `iter`)
deprecate klist functions (for `std_seq`)

close #231
2019-12-14 16:29:07 -06:00
Simon Cruanes
a836b7ed8b feat(unix): add ensure_session_leader and add some docs 2019-12-14 14:48:46 -06:00
Simon Cruanes
52ef092a4c feat(pool): add infix operators on futures 2019-12-14 14:37:30 -06:00
Simon Cruanes
faeae964fc fix(pp): improve printing of hashtables
close #243
2019-12-14 14:25:38 -06:00
Simon Cruanes
bcb90de435 doc: small change to readme 2019-12-14 14:22:35 -06:00
Simon Cruanes
c92a09ac9d add more deprecation comments 2019-12-14 14:04:09 -06:00
Simon Cruanes
af4662e962 deprecate CCVector.fill_empty_slots_with 2019-12-14 13:57:56 -06:00
Fardale
0b759c67b8 CCVector: update the doc 2019-12-14 13:44:57 -06:00
Fardale
27eb874523 CCVector: resize_ take the elt as argument
It is safer to have the check on the size of the underlying array
close to access of the first element.
2019-12-14 13:44:57 -06:00
Simon Cruanes
b69cc33c26 perf: make let-op functors inline, hopefully 2019-12-14 12:08:48 -06:00
Simon Cruanes
9b76f277f7 more fixes for the shims 2019-12-14 12:08:48 -06:00
Simon Cruanes
616c077880 fix: proper shims for CCArrayLabel too 2019-12-14 12:08:48 -06:00
Simon Cruanes
d5e5b43e1f fix shims for arrays 2019-12-14 12:08:48 -06:00
Simon Cruanes
74e7d87872 fix: backport a pseudo Floatarray pre 4.06 2019-12-14 12:08:48 -06:00
Simon Cruanes
62672fdbd2 fix test 2019-12-14 12:08:48 -06:00
Simon Cruanes
9a672f4e3c chore(travis): disable build on 4.03, enable tests on 4.08/09 2019-12-14 12:08:48 -06:00
Simon Cruanes
b2d9e69042 feat: put the let operators inside the Infix modules when relevant 2019-12-14 12:08:48 -06:00
Simon Cruanes
bf0227d404 feat: on 4.08, support let operators
close #276
2019-12-14 12:08:48 -06:00
Simon Cruanes
037a0ef922 Merge branch 'wip-ccvec' 2019-12-14 12:08:33 -06:00
Fardale
bbdcd93417 wip: improved gc behavior for ccvector 2019-12-14 11:50:47 -06:00
Fardale
1d589cf4ac use array_is_empty_ instead of direct check 2019-12-14 11:50:47 -06:00
Simon Cruanes
5cb715a206 fix: properly alias to CCChar in containers.ml
close #281
2019-12-14 11:42:19 -06:00
Simon Cruanes
70bd7f1e97 fix: move with_temp_dir from CCIO to CCUnix
it depends on unix, which is a deal breaker for core
2019-12-11 09:46:21 -06:00
Simon Cruanes
28f8872ef5 feat: add monoid_product to Array and Vector 2019-12-10 21:38:07 -06:00
Simon Cruanes
5bcb8c63ad fix: missing result 2019-12-10 21:36:35 -06:00
Simon Cruanes
1b5b23a8f1 remove unlabel, remove all traces of Result 2019-12-10 20:48:38 -06:00
Simon Cruanes
30251e9426 bump minimum version of OCaml to 4.03, drop deps {result,uchar}
close #274
2019-12-10 19:56:54 -06:00
Simon Cruanes
858616606b add CCVector.shrink_to_fit to limit memory usage 2019-12-10 16:39:35 -06:00
Simon Cruanes
1239960c42 wip: improved gc behavior for ccvector 2019-12-10 16:39:35 -06:00
Simon Cruanes
236a0c43ce feat: add CCVector.clear_and_reset 2019-12-10 16:39:35 -06:00
Simon Cruanes
0ef454c6dc feat(sexp): expose parse_string_list and the list decoder 2019-12-10 15:50:18 -06:00
Simon Cruanes
08f333ffa8 chore: opam file 2019-12-10 15:50:04 -06:00
Simon Cruanes
bf2dc512fd
Re-enable mdx tests (#277)
ee-enable mdx tests
2019-12-10 15:48:58 -06:00
Simon Cruanes
480a7f85fc
older dune dialect 2019-12-10 15:22:08 -06:00
Simon Cruanes
b3bfa82ccb
use older dune dialect 2019-12-10 15:21:51 -06:00
Simon Cruanes
c2f8d6811b fix(sexp): set location properly when parsing a file 2019-12-06 20:21:46 -06:00
Simon Cruanes
825e350da0 feat(sexp): reexport atom/list cstors 2019-12-05 15:19:38 -06:00
Nathan Rebours
58a17202d7 Re-enable mdx tests 2019-12-04 15:47:39 +01:00
Simon Cruanes
76bec991a2 feat(io): add with_temp_dir function 2019-12-03 12:49:22 -06:00
Simon Cruanes
8ddc3de490 chore: require dune configurator 2019-12-03 08:24:49 -06:00
Simon Cruanes
936d5912e6 chore: fix benchs so they don't depend on clarity and they compile again 2019-11-20 20:59:45 -06:00
Simon Cruanes
7d1862a501 wip: add to_std_seq
see #254
2019-11-20 17:50:40 -06:00
Simon Cruanes
78ef007b77 deprecate CCOpt.to_seq, provide to_iter instead 2019-11-20 17:50:22 -06:00
Simon Cruanes
bd4e4d311d add CCOpt.value to improve compat with Stdlib.Option 2019-11-20 17:49:49 -06:00
Fardale
3804dbff86 add CCVector.mapi 2019-11-17 10:43:18 -06:00
Simon Cruanes
968a39b6bc fix: restore CCSexp.atom which was lost in 2.7 2019-11-13 15:30:11 -06:00
Simon Cruanes
7bdf6f6cef test: use more deterministic test for timer 2019-11-12 10:17:50 -06:00
Simon Cruanes
7cefde490b prepare for 2.7
remove mdx
2019-11-12 08:49:33 -06:00
Simon Cruanes
2241a25d9e CCIO: use attributes for warnings 2019-11-11 20:01:21 -06:00
Simon Cruanes
e106432e21 deprecate CCKList in favor of the standard Seq
see #257
2019-11-11 19:59:37 -06:00
Simon Cruanes
27fb393698 feat(CCIO): add _gen suffixes to some functions
deprecate the previous versions
see #261
2019-11-11 19:55:43 -06:00
Simon Cruanes
edcd97a7ed doc(IO): explain lifetime of gen a bit 2019-11-08 11:27:01 -06:00
Simon Cruanes
11d081a612 doc: add pointer to the repo for gen 2019-11-08 11:17:37 -06:00
Simon Cruanes
09c205db78 fix: missing interface file 2019-11-05 20:16:52 -06:00
Simon Cruanes
853c9f27bd refactor: reuse a bit of code 2019-11-05 19:43:37 -06:00
Simon Cruanes
404e35f850 feat(sexp): provide ability to annotate parsed S-exprs with their position 2019-11-05 19:41:44 -06:00
Simon Cruanes
d6f98032c8 feat(sexp): functorize the parser/printer 2019-11-05 19:24:28 -06:00
Simon Cruanes
2b6d9126c1 feat(ccsexp): support #; for commenting a sexp 2019-11-05 19:02:40 -06:00
Simon Cruanes
2ed821bbe1 style: reindent in ccdeque 2019-11-05 18:23:06 -06:00
Fardale
2fa12665dd change type of CCDeque
Change the definition of the type in CCDeque to remove the Zero cell.
This new type enforce one invariant.
2019-11-04 21:47:09 -06:00
Simon Cruanes
b3ce398624 fix: remove dep from vec to list 2019-10-30 14:28:17 -05:00
Fardale
0dafceb708 Adding to_string (#270)
* add `CCArray.to_string`
* add `CCArrayLabels.to_string`
* add `CCList.to_string`
* add `CCListLabels.to_string`
* add `CCChar.to_string`
* add `CCPair.to_string`
* add `CCHeap.to_string`
* add `CCSet.to_string`
* add `CCVector.to_string`
2019-10-30 14:26:52 -05:00
Simon Cruanes
c1704d71ff style: improve new code 2019-10-29 21:50:22 -05:00
Fardale
509dacb96f add CCDeque.{remove_*;update_*}
functions added:
CCDeque.remove_back
CCDeque.remove_front
CCDeque.update_back
CCDeque.update_front
2019-10-26 17:28:51 -05:00
Fardale
a33963c335 add CCDeque.{*_opt}
Functions added:
CCDeque.peek_front_opt
CCDeque.peek_back_opt
CCDeque.take_back_opt
CCDeque.take_front_opt
2019-10-23 19:16:07 -05:00
Fardale
035aac9a72 add invariant in CCDeque.ml 2019-10-23 19:16:07 -05:00
Simon Cruanes
1b8d9ca9a6 style: small fix 2019-10-22 18:14:59 -05:00
Simon Cruanes
c4631b78dc add CCDeque.{filter,filter_map} 2019-10-22 18:14:59 -05:00
Simon Cruanes
546cbd85fd add CCDeque.filter_in_place 2019-10-22 18:14:59 -05:00
Simon Cruanes
70d7dd234d add CCBool.{to,of}_int 2019-10-21 10:34:26 -05:00
Simon Cruanes
df9bbb8746 add Result.flatten_l to turn a list of results into a result of list 2019-10-16 12:22:55 -05:00
Simon Cruanes
0c23e3ba88
Merge pull request #266 from c-cube/wip-264-improve
improve on #264
2019-10-11 17:44:42 -05:00
Simon Cruanes
b25cf1ea00 fix: forgot const 2019-10-11 17:05:34 -05:00
Simon Cruanes
ab5b3aa6af refactor: remove stdlib's code, simple reimplementation of Stdlib.Fun
keep the whole codebase BSD.
2019-10-11 16:59:22 -05:00
Simon Cruanes
0867583209 test: fix qtest generation to ignore the stdlib's fun module 2019-10-11 16:45:39 -05:00
Simon Cruanes
d63bdbc0eb fix syntax error in ArrayLabels.mli 2019-10-11 16:29:50 -05:00
Simon Cruanes
6d02200429 fix syntax error in Array.mli 2019-10-11 16:29:50 -05:00
narimiran
3658864a5a add CCArray.Infix 2019-10-11 16:29:50 -05:00
Christopher Zimmermann
6a51830305 Don't use raise_with_backtrace in backward-compatible Fun.protect 2019-10-07 14:07:11 +02:00
Christopher Zimmermann
f759a92214 travis: test on OCaml 4.09, too. 2019-10-07 14:01:20 +02:00
Christopher Zimmermann
5fcd1a506e add shim for backward-compatibility Fun module 2019-10-07 13:42:48 +02:00
Christopher Zimmermann
858af75ee8 Make use new Stdlib.Fun to extend / replace CCFun 2019-10-07 12:28:22 +02:00
Christopher Zimmermann
2d5f0e3e8d Document behaviour of Fun.finally when finaliser raises 2019-10-07 12:26:21 +02:00
Simon Cruanes
beb38da150 prepare for 2.6.1 2019-09-06 20:14:42 -05:00
Simon Cruanes
080f81a9dd fix(parse): error in many 2019-09-06 14:12:08 -05:00
Simon Cruanes
19fbd33278 chore: add 4.08 to travis 2019-08-09 16:16:37 -05:00
Kate
e7c265bcf9 Fix Containers.Stdlib on OCaml 4.07 2019-07-05 11:08:55 -05:00
Simon Cruanes
a1f3f4781d prepare for 2.6 2019-06-19 10:02:55 -05:00
Simon Cruanes
21feaaf1ca fix compilation on < 4.08 2019-06-19 10:02:55 -05:00
Simon Cruanes
7ff5aa0d18 fix: add shims for CCArray 2019-06-18 23:10:26 -05:00
Simon Cruanes
f71472ad08 fix: remove reference to sequence 2019-06-14 18:26:15 -05:00
Simon Cruanes
0c00cafb20 use markdown again for changelog 2019-06-14 18:26:14 -05:00
Simon Cruanes
96ed8a37ab feat: introduce shim modules for 4.08 compat
- also make `unlabel` an explicit operation
- use `Stdlib` instead of `Pervasives`
- remove some warnings in Format
2019-06-14 18:26:14 -05:00
Simon Cruanes
fa0290061b doc: fix bad example in CCIO 2019-05-31 09:27:42 -05:00
JPR
8e3dc5e006 Small typos 2019-05-14 11:14:12 -05:00
rymdhund
05e49a27e7 Remove unused reference 2019-04-29 09:58:29 -05:00
Simon Cruanes
9bdf31b07c fix: missing whitespace in readme 2019-04-13 05:49:31 -05:00
Simon Cruanes
b07b030898 doc: update readme a bit 2019-04-13 03:25:26 -05:00
Simon Cruanes
3712db3a5b chore: use iter, not sequence, in tests 2019-04-13 03:20:56 -05:00
Simon Cruanes
0d6c922eb1 fix: use same evaluation order as stdlib for CCList.init
close #256
2019-04-13 03:10:38 -05:00
Simon Cruanes
1654f8c826 test: add regression test for #256 2019-04-13 03:10:29 -05:00
Simon Cruanes
a325600ccb chore: modernize make watch 2019-04-13 03:05:34 -05:00
Christopher Zimmermann
bb4d8a89f3 don't use Compenv.module_of_filename
this simple implementation is good enough for us.
2019-03-07 23:15:24 +00:00
nilsbecker
c70825b250 ocamldebug section in the README (#249)
add `ocamldebug` instruction section to the README
2019-02-27 14:48:56 +00:00
Simon Cruanes
d9555ae063 chore: remove appveyor, too unreliable 2019-02-19 18:48:15 -06:00
Simon Cruanes
bfa5d9adde breaking: make Array.random_choose raise invalid_arg instead of not_found 2019-02-19 18:46:08 -06:00
Simon Cruanes
f190964cfd fix: make Array.random_choose fail on empty array at creation time
see #246
2019-02-18 20:41:17 -06:00
Simon Cruanes
c893716c1a feat: add remove function to het map/tbl 2019-02-16 16:15:24 -06:00
Simon Cruanes
3236d3c8b9 fix: missing type annotation for specializing int.compare 2019-02-04 13:33:52 -06:00
Simon Cruanes
f7327197fe chore: fix travis 2019-02-02 22:01:45 -06:00
Simon Cruanes
6f681256f7 fix readme across versions 2019-02-02 21:37:11 -06:00
Simon Cruanes
18024cc5e9 doc: hide some parts of the readme 2019-02-02 20:35:50 -06:00
Simon Cruanes
b308680bee doc: update doc/containers, migrate it to mdx 2019-02-02 20:34:21 -06:00
Simon Cruanes
404d74ac43 chore: remove ocamlinit file 2019-02-02 20:31:13 -06:00
Simon Cruanes
e481777c43 doc: migrate readme to .md, using mdx to test it 2019-02-02 20:27:15 -06:00
Simon Cruanes
d0a0ecb3ef doc: remove link to gitter… 2019-02-02 14:15:53 -06:00
Simon Cruanes
c10ad46fbd prepare for 2.5 2019-02-02 14:03:22 -06:00
Simon Cruanes
83251c9efa Merge branch 'br-2.4.1' 2019-02-02 14:01:08 -06:00
Simon Cruanes
8038528097 prepare for 2.4.1 2019-02-02 14:00:02 -06:00
Simon Cruanes
b60fe99365 perf: annotate types in monomorphic/float/int to help specialize builtins
close #245
2019-01-30 21:33:39 -06:00
Calascibetta Romain
052e607c5c CCFQueue.t must be covariant 2019-01-21 17:53:26 +00:00
Calascibetta Romain
23f759b984 Use GADT to discard impossible case on CCFQueue. 2019-01-21 17:53:26 +00:00
Simon Cruanes
dcf66ce502 chore: update travis to build faster on most switches 2019-01-21 11:45:37 -06:00
Simon Cruanes
0d05643c57 chore: try to fix appveyor build 2018-12-23 21:04:50 -06:00
Simon Cruanes
d0f0bf7024 doc: small fix 2018-12-21 17:47:35 -06:00
Simon Cruanes
91adde9743 minor fix 2018-12-21 09:44:28 -06:00
Fardale
23d7ea20f6 [WIP] Work on documentation (#242)
`CCResult` add doc for map_l
2018-12-21 15:43:36 +00:00
Simon Cruanes
f8d9e33900 fix(funvec): expose pop, fix off by one error
close #241
2018-12-11 22:57:06 -06:00
Simon Cruanes
6a90cb25e7 wip: fix retrocompat issues in cclist 2018-12-03 19:59:41 -06:00
Simon Cruanes
ef8d19ac65 some typos in unlabel 2018-12-03 09:47:35 -06:00
Simon Cruanes
197b4e7f1b prepare for 2.4 2018-11-30 10:40:13 -06:00
Simon Cruanes
3b0ceb7821 fix(vector): free elements in more functions, add fill_empty_slots_with
see #235
2018-11-30 10:29:08 -06:00
Fabian
ff58dc0b5f Fix #235 for CCRingBuffer
* Make dummy available to MakeFromArray

* Overwrite deleted elements with a dummy element to allow them to be GCed

* Test that deleted elements can be GCed
2018-11-30 10:14:09 -06:00
Simon Cruanes
b21ca4e0d8 wip: fix(vec): release elements after their removal
see #235
2018-11-30 10:14:09 -06:00
Simon Cruanes
4c5010d381 doc: unleash the Emoji 2018-11-19 11:18:58 -06:00
Nathan Rebours
29a75daac1 Add CCResult.iter_err
Closes #238
2018-11-19 17:17:26 +00:00
Simon Cruanes
da2c9e7c7c doc: abide by odoc's whims 2018-11-02 20:25:37 -05:00
Simon Cruanes
113d03225f add CCEqual.{always,never}_eq
close #232
2018-11-02 20:17:36 -05:00
Simon Cruanes
26c8eb33bf fix: remove spurious Labels module 2018-11-02 20:14:50 -05:00
Christopher Zimmermann
333fa8067e add containersLabels.ml 2018-11-03 01:14:12 +00:00
Simon Cruanes
63f702b21c chore: add synopsis to opam file 2018-11-02 11:54:08 -05:00
Simon Cruanes
f9c59a90e2 doc: remove dead link from readme 2018-11-02 11:35:30 -05:00
Simon Cruanes
6d1f0b9957 rename Random.sample_without_{replacement,duplicates}
- deprecate sample_without_replacement
- use `~cmp` as the named argument, more uniform

close #130
2018-10-16 11:09:27 -05:00
Simon Cruanes
f692fe5dd9 chore: update travis so it's faster 2018-10-13 19:28:04 -05:00
Simon Cruanes
a3222c0908 chore: update opam file to opam2 2018-10-13 19:09:36 -05:00
Simon Cruanes
1d3ba3a6f1 doc: fix small inaccuracy in comments and API 2018-10-13 19:09:36 -05:00
Simon Cruanes
b7e8dcb5ff chore: better deps for unlabel 2018-10-13 19:09:36 -05:00
Christopher Zimmermann
f02f291c7a Create CCEqualLabels 2018-10-13 19:09:36 -05:00
Christopher Zimmermann
c6a3fe86eb Create CCArray_sliceLabels 2018-10-13 19:09:35 -05:00
Christopher Zimmermann
7822f3a045 Create CCStringLabels
CAVE: there is a breaking interface change for String.is_sub
2018-10-13 19:09:35 -05:00
Christopher Zimmermann
f6e1d81ed7 Generate unlabelled interfaces from labelled ones
* add unlabel.ml which parses interfaces and removes labels in function declarations and docstrings. This is a quick hack, but it does the job.
 * an attribute [@keep_label] can be added to the labelled arguments to mark labels like ~cmp which should stay in the "unlabelled" interface
 * While augmenting the labelled interfaces I stumbled across some inconsistencies between the currend labelled / non-labelled interfaces. I used the labelling that made most sense to me and added a "FIXME" comment.
 * Maybe we should break backwards compatibility at some point and name the comparison arguments to the sorting functions in CCArrayLabels.ml ~cmp instead of ~f ?
2018-10-13 19:09:35 -05:00
Simon Cruanes
2a9795090b test: improve perf by changing random gens 2018-10-13 18:52:22 -05:00
Simon Cruanes
e22a55668d style edit 2018-10-08 20:48:02 -05:00
Francois Berenger
1e21784ce1 added List.counts, related to List.count (#230)
- add `List.count_true_false` related to `List.count`
2018-10-08 20:43:06 -05:00
Hongchang Wu
3ec63feded Update authors 2018-10-05 00:55:32 -05:00
Hongchang Wu
e8617c4f05 Add CCResult.get_or_failwith 2018-10-05 00:55:32 -05:00
Simon Cruanes
3b1de9a1c8 chore(build): migrate to dune 1.0 2018-09-16 19:53:40 -05:00
Simon Cruanes
058c99b2a9
Create CODE_OF_CONDUCT.md 2018-09-16 22:09:01 +00:00
Metin Akat
b8fb429c0b Add myself to the authors file 2018-09-02 10:56:11 -05:00
Metin Akat
e447f5a1bc Version annotation of CCInt.( ** ) 2018-09-02 10:56:11 -05:00
Metin Akat
7d25684941 Support using ** for exponentiation 2018-09-02 10:56:11 -05:00
Simon Cruanes
13fe66c968 chore: update dune to use dune-config 2018-08-15 13:38:58 -05:00
Simon Cruanes
5f521f6fa2 chore: add 4.07 to travis 2018-08-07 08:39:43 -05:00
Simon Cruanes
9238daf7c3 fix: compat with 4.07 2018-08-07 03:23:11 -05:00
Simon Cruanes
d4a9b0a8d1 prepare for 2.3 2018-08-06 11:52:01 -05:00
Simon Cruanes
e530547356 feat(vector): add Vector.{filter,filter_map}_in_place 2018-07-26 04:39:06 -05:00
Simon Cruanes
c800250038 perf: tweaks in CCVector 2018-07-25 14:32:28 -05:00
Simon Cruanes
551c837398 test: more tests for vector 2018-07-25 14:32:28 -05:00
Simon Cruanes
e510e153f8 test: add more tests in vector 2018-07-25 14:32:28 -05:00
Simon Cruanes
1998ed5090 fix(vector): bugfix in filter 2018-07-25 14:32:28 -05:00
Simon Cruanes
7f1c6ae66f feat(intmap): add is_empty function 2018-06-11 20:10:45 -05:00
Simon Cruanes
aa4b2a4680 fix(build): remove [@inline] attributes since they break on 4.02.3 2018-06-11 19:01:06 -05:00
Simon Cruanes
3e5813d72f perf(hashtrie): use int64 for 64-bits branching factor and popcount
also update style
2018-06-05 00:31:56 -05:00
Simon Cruanes
5523ed428c feat(intmap): add CCIntMap.{filter,filter_map,merge} 2018-06-04 23:36:15 -05:00
Simon Cruanes
ca0521512f test(intmap): add some tests for CCIntMap, also improve style 2018-06-04 23:32:08 -05:00
Fabian
0c48cff2a1 Vector push benchmark: Push all values to the same container 2018-06-01 11:32:06 -05:00
Fabian
35065393c5 More benchmarks for immutable vectors
- Add Map as a reference, as this is the only efficient implementation
  in OCaml's standard library
- Add Clarity.Vector from the clarity library
- New benchmarks for set at index and push

What's missing:

- CCFun_vec.set (no implementation)
- CCRAL.push and Clarity.Vector.push were missing and implemented
  inefficiently in terms of append
2018-06-01 11:32:06 -05:00
Simon Cruanes
1adfc01cf0 fix small detail s in CCHeap 2018-05-29 11:17:11 -05:00
juloo
ba633d5d3c Add CCHeap.Make_from_compare (#225)
Allow to pass modules implementing `compare` without implementing `leq`
2018-05-29 11:15:38 -05:00
Simon Cruanes
1a4919af29 add relation ops CCList.{group_by,join,join_by,join_all_by,group_join_by} 2018-05-29 11:04:08 -05:00
juloo
cbeab54be4 Fix Int32 and Int64 operators are not visible (#224)
Fix visibility of Int32 and Int64 infix operators

Operators are defined in the Infix module.
This module was included in the .ml file but not in the .mli file
2018-05-29 09:57:04 -05:00
Simon Cruanes
8060980266 test(float): add some tests for FP min/max 2018-05-14 18:09:39 -05:00
Simon Cruanes
841dac234a fix(float): make Float.{min,max} compliant with revised IEEE754
closes #220
2018-05-14 18:07:38 -05:00
Simon Cruanes
e825bf2916 prepare for 2.2 2018-05-10 23:13:01 -05:00
Simon Cruanes
ba87e105a0 fix(arrayLabels): compatibility with 4.07 2018-05-07 13:41:19 -05:00
JPR
822b9177e1 Improving comments presentation 2018-05-07 08:46:38 -05:00
Simon Cruanes
becc1007c2 chore: reindent 2018-04-25 20:17:32 -05:00
Etienne Millon
b27acb9bd2 Add CCOpt.return_if 2018-04-25 20:16:23 -05:00
Etienne Millon
bbda79bbcc Add CCOpt.flatten 2018-04-24 17:03:45 -05:00
Kate
d8caef8c02 Add CCString.{,r}drop_while 2018-04-20 19:13:49 -05:00
Simon Cruanes
9e105a3fbc fix stupid typo 2018-04-12 15:47:23 -05:00
Simon Cruanes
ac314aefe7 chore: remove dead link in string doc 2018-04-12 12:11:49 -05:00
Simon Cruanes
7c56bd747e fix: compatibility for CCArrayLabels 2018-04-09 21:13:56 -05:00
Simon Cruanes
33d3ee114c add many missing functions to CCListLabels 2018-04-08 18:57:15 -05:00
Simon Cruanes
fac9f18031 test: consistency CCList{,Labels} 2018-04-08 18:54:40 -05:00
Simon Cruanes
960e704bb1 test: disable labels for tests
necessary for the consistency checks of Label modules
2018-04-08 18:48:54 -05:00
Simon Cruanes
b672eb0e6d fix(CCListLabels): fix @since annotation 2018-04-08 18:42:11 -05:00
Simon Cruanes
b47d622f66 test: add compatibility checks between CCArray{,Labels} 2018-04-08 18:40:40 -05:00
JPR
1727cc8199 Few Comments corrections 2018-04-08 18:39:23 -05:00
Simon Cruanes
f7d5177540 chore(doc): update ocamldoc markup to remove odoc warnings 2018-03-30 01:49:38 -05:00
Simon Cruanes
78d79c1317 chore: minor details in doc 2018-03-28 20:30:26 -05:00
Simon Cruanes
6e50ff41c6 prepare for 2.1 2018-03-28 20:26:17 -05:00
Simon Cruanes
c04ee13d6e fix(array): small change in signatures 2018-03-28 20:20:09 -05:00
Simon Cruanes
5986955fb6 feat(list): add {interleave,intersperse} (closes #191) 2018-03-28 20:10:14 -05:00
Simon Cruanes
89fc7f9c77 fix(string): compat 4.02 2018-03-28 20:09:05 -05:00
Simon Cruanes
55e92b4629 feat(mono): add dotted comparison operators for floats
closes #196
2018-03-28 19:53:02 -05:00
Simon Cruanes
972a6f2720 style: reindent 2018-03-28 19:46:57 -05:00
Simon Cruanes
b874ff9bf9 feat(Bijection): add more functions, add basic tests 2018-03-28 19:46:43 -05:00
Stavros Polymenis
89ce86eec0 Assert emptiness on both maps instead of raising custom exception.
https://github.com/c-cube/ocaml-containers/pull/211\#pullrequestreview-107483136
2018-03-28 19:35:20 -05:00
Stavros Polymenis
712b12d2f1 Add Bijection. https://en.wikipedia.org/wiki/Bijection
Discussion:
http://lists.ocaml.org/pipermail/containers-users/2018-February/000042.html
2018-03-28 19:35:20 -05:00
Simon Cruanes
fe23cb496c fix: strong type aliases in Random (closes #210) 2018-03-26 11:35:31 -05:00
Simon Cruanes
323a6bb40a test: regression test for #210 2018-03-26 11:35:31 -05:00
Simon Cruanes
f07cae6c82 detail 2018-03-18 21:53:24 -05:00
JPR
2c9ed9c550 Reverting CCFormat.mli comment 2018-03-15 23:09:31 -05:00
JPR
d18d9fb636 Comments - Style & typos fixing 2018-03-15 23:09:31 -05:00
Simon Cruanes
9b804b46a5 update readme 2018-03-14 18:21:41 -05:00
Simon Cruanes
7a22286ca1 use standard List.sort_uniq 2018-03-13 00:34:49 -05:00
Simon Cruanes
09d5b146f2 remove explicit dep on bytes in jbuild files 2018-03-12 22:45:48 -05:00
Simon Cruanes
2c5cda7e3d add ?margin parameter to CCFormat.ksprintf 2018-03-09 11:27:11 -06:00
Simon Cruanes
c578dd9583 minor fixes in doc 2018-03-08 17:54:20 -06:00
Simon Cruanes
4a9b41c3cd add various functions on CCUtf8_string 2018-03-07 00:17:48 -06:00
Simon Cruanes
79089677af CCFun_vec: implement missing functions 2018-03-07 00:08:34 -06:00
Simon Cruanes
ea4a4e4ffb utf8string: detect overlong encodings
- also, stronger tests for utf8string
2018-03-07 00:08:27 -06:00
Simon Cruanes
fe88bafe77 simplify CCFun_vec by removing transients, for now 2018-03-06 23:08:02 -06:00
Simon Cruanes
be76d6bf91 fixes in utf8_string: remove some forbidden cases 2018-03-06 23:07:59 -06:00
Simon Cruanes
640ab72bb2 bugfix in CCVector.slice_seq 2018-03-06 22:28:11 -06:00
Simon Cruanes
6b5735a318 fix compat with 4.02 2018-03-06 22:27:52 -06:00
Simon Cruanes
30fca7ae9e add CCUtf8_string with basic encoding and decoding functionalities 2018-03-06 22:16:17 -06:00
Simon Cruanes
524658fb0f add some doc 2018-03-06 10:15:33 -06:00
Nicola Mometto
8f4c1a24b7 default uses labelled argument 2018-03-06 10:12:20 -06:00
Nicola Mometto
68ad3d7408 Add <|> to CCLazy_list 2018-03-06 10:12:20 -06:00
JPR
8d3981d983 Adding CCNativeint 2018-02-28 08:43:14 -06:00
Simon Cruanes
98bb766de6 fix ccint 2018-02-27 21:37:28 -06:00
Simon Cruanes
da6d4a72fa enrich CCInt.Infix to get a uniform interface with CCInt{32,64} 2018-02-27 21:12:04 -06:00
Simon Cruanes
9f2ef2f461 add CCInt{32,64}.Infix 2018-02-27 21:09:35 -06:00
JPR
4a317e57c1 Correction containers.ml file 2018-02-27 20:34:37 -06:00
JPR
d8c16ec95b Adding CCInt32 module 2018-02-27 20:34:37 -06:00
Simon Cruanes
8777996817 point to appveyor build in readme 2018-02-27 10:40:11 -06:00
Jacques-Pascal Deplaix
f5f98c5e11 Fix appveyor 32bits 2018-02-27 15:25:22 +00:00
Jacques-Pascal Deplaix
a4dda4284c Add an appveyor test for 32bits windows 2018-02-27 12:59:29 +00:00
Simon Cruanes
5f0b648845 update printers names in containers.top (closes #201) 2018-02-26 19:47:24 -06:00
Jacques-Pascal Deplaix
a0d0cf9d88 Enable support for Travis CI and Appveyor 2018-02-25 09:54:01 -06:00
Jacques-Pascal Deplaix
001d330bb9 Fix ounit package name 2018-02-25 09:51:31 +00:00
Simon Cruanes
0fb25fac26 note that ccfun_vec is really experimental 2018-02-24 18:38:13 -06:00
Simon Cruanes
5ebebf4fd7 test deps are required when we run tests 2018-02-22 14:18:00 -06:00
Simon Cruanes
fe16608524 add CCHash.combine{5,6} 2018-02-21 10:21:36 -06:00
Simon Cruanes
22fce8e16f point to JST's blog post on poly compare 2018-02-19 14:16:23 -06:00
Simon Cruanes
ab378a98bb proper urls 2018-02-19 12:18:00 -06:00
Simon Cruanes
3c8869dd5b udpate readme to explain a bit more how to live with monomorphic ops 2018-02-19 12:16:14 -06:00
Simon Cruanes
145578f1d9
Merge pull request #195 from madroach/master
Add missing infix operators to `CCFloat`
2018-02-17 14:11:35 -06:00
Christopher Zimmermann
dabb7de24a Add infix operators to CCFloat 2018-02-17 21:05:36 +01:00
Simon Cruanes
62ba3c00af make CCInt64 compatible with Int64 (breaking!) (closes #192)
conversion functions are total, even when the bit widths do not
correspond. Returning options does not make sense in this context.
2018-02-17 10:25:57 -06:00
Simon Cruanes
580dc58979 remove junk file 2018-02-17 10:16:45 -06:00
Simon Cruanes
1640ee89f2 add missing signatures of CCArrayLabels (closes #193) 2018-02-17 10:16:08 -06:00
Simon Cruanes
bff1464560 use non empty lists as indexes in Fun_vec 2018-02-15 08:30:16 -06:00
Simon Cruanes
74d3b0f29f add BatVec to some benchmarks 2018-02-15 08:30:05 -06:00
Simon Cruanes
deb266e1b3 add CCFun_vec to benchmarks 2018-02-15 00:31:26 -06:00
Simon Cruanes
ccad1f3a2c wip: add CCFun_vec data structure for fast functional vectors 2018-02-15 00:31:26 -06:00
Simon Cruanes
02f8af6dbe
Merge pull request #189 from jpdeplaix/master
Fix #188 by adding lower bound on jbuilder
2018-02-14 11:57:43 -06:00
Jacques-Pascal Deplaix
7e08d7c7c1 Fix #188 2018-02-14 17:44:48 +00:00
Simon Cruanes
dd24feab60
Merge pull request #187 from emillon/ccfun-iterate
Add `CCFun.iterate`
2018-02-14 08:40:42 -06:00
Etienne Millon
f1adbcf2f3 Add CCFun.iterate
This adds a new `CCFun.iterate` function that computes the nth-iterate
of a function. That is, that function composed with itself n times.
2018-02-14 15:39:08 +01:00
Simon Cruanes
a4697946ac small typo in readme 2018-02-11 11:08:51 -06:00
Simon Cruanes
f78ee1bf92 add migration guide to the readme 2018-02-11 10:26:02 -06:00
Simon Cruanes
6b9f39d224 prepare for 2.0 2018-02-11 09:57:06 -06:00
Simon Cruanes
44f6c748aa improve test speed and update some doc 2018-02-11 09:52:27 -06:00
Simon Cruanes
35f9b32a5b add CCFormat.lazy_{or,force} for printing thunks 2018-02-09 14:20:46 -06:00
Simon Cruanes
d4fafab9b7 more tests 2018-02-07 20:38:01 -06:00
Simon Cruanes
b3c796176d reindent 2018-02-07 08:22:41 -06:00
Simon Cruanes
7510aaaa18
Merge pull request #186 from Fourchaux/master
move tests from mli files into ml files, update some doc
2018-02-07 08:22:10 -06:00
nathan moreau
3e2fbce3ee Comments - few changes 2018-02-07 14:36:03 +01:00
Simon Cruanes
24592bf926 CCFormat: fix support of unrecognized styles 2018-02-05 08:58:32 -06:00
Simon Cruanes
3ab9cd58e1 with compat >= 4.02, use Format.pp_print_text directly 2018-02-05 08:56:01 -06:00
Simon Cruanes
27c768eebf fix bug in CCRAL.drop (see #184) 2018-02-04 12:39:06 -06:00
Simon Cruanes
5814f23d16 add more tests to CCRAL and others 2018-02-04 12:38:17 -06:00
Simon Cruanes
72838b6ebc
Merge pull request #184 from rand00/master
Fixed bug in ``CCRAL.{drop,take_drop}`
2018-02-04 12:07:22 -06:00
Simon Cruanes
77cd903134
Merge branch 'master' into master 2018-02-04 12:06:44 -06:00
Simon Cruanes
6b48fe873e add another test 2018-02-04 12:05:58 -06:00
Simon Cruanes
9e51f8dc77
Merge pull request #185 from actionshrimp/cclist-repeat-reversed
Don't reverse twice in `CCList.repeat`
2018-02-04 11:57:05 -06:00
Dave Aitken
60596e5408 Update authors list 2018-02-04 17:56:07 +00:00
rand00
47c5c41a96 Added Rand to authors 2018-02-04 18:55:37 +01:00
rand00
cfb8e55eba CCRAL: drop: Added test for bugfix. 2018-02-04 18:54:56 +01:00
Dave Aitken
710266e09c Don't reverse twice in CCList.repeat 2018-02-04 17:34:30 +00:00
rand00
5b6b71373c CCRAL: Fixed bug in drop_tree_. 2018-02-04 17:30:29 +01:00
Simon Cruanes
04d10c2711 makefile help 2018-02-03 15:39:12 -06:00
Simon Cruanes
b340c3dc6c update deps 2018-02-03 15:36:53 -06:00
Simon Cruanes
a0a8954231 proper deps in dune 2018-02-03 15:36:53 -06:00
Simon Cruanes
29118df5f4 opam detail 2018-02-02 08:10:41 -06:00
Simon Cruanes
c382c1c2e5 prepare for 2.0+alpha2 2018-02-01 19:18:17 -06:00
Simon Cruanes
ddf709fc5b reindent code 2018-02-01 19:01:32 -06:00
Simon Cruanes
6ec2fdeb1e
Merge pull request #183 from Fourchaux/master
Adding more comments (thanks to @Fourchaux)
2018-02-01 19:01:19 -06:00
nathan moreau
312901550f Style - small corrections 2018-02-01 22:22:13 +01:00
Simon Cruanes
968edffc03 fix 2018-02-01 09:22:41 -06:00
Simon Cruanes
223647045a update jbuild file 2018-01-31 20:07:27 -06:00
Simon Cruanes
5720120fa1 more tests 2018-01-31 20:07:04 -06:00
Simon Cruanes
9f48725a06 remove qtest makefile and use a script instead 2018-01-31 08:49:52 -06:00
nathan moreau
775f86103e typo (CCString.mli) 2018-01-30 14:25:51 +01:00
nathan moreau
00b2638ae7 Adding more comments 2018-01-30 14:07:05 +01:00
Simon Cruanes
2939dcbf1d rename CCChar.{print,pp} and CCHeap.print (closes #181) 2018-01-29 21:15:24 -06:00
Simon Cruanes
3b8f7099cb style fixes 2018-01-28 10:31:26 -06:00
Simon Cruanes
364890ca36
Merge pull request #180 from FardaleM/CCHeap
Add `CCHeap.delete_{all,one}`
2018-01-28 10:30:20 -06:00
Simon Cruanes
c3e11ba31b
Merge pull request #182 from Fourchaux/master
Correcting test `CCList.tail_opt`
2018-01-28 10:03:50 -06:00
nathan moreau
e598aac764 Correcting test CCList.tail_opt 2018-01-28 16:36:27 +01:00
Fardale
8c2cb3f244 [CCHeap] delete_once -> delete_one 2018-01-28 12:39:44 +01:00
Fardale
8ac62ca04b [CCHeap] add delete_once 2018-01-28 12:37:21 +01:00
Fardale
50d970852e [CCHeap] update comment delete_all 2018-01-28 12:36:37 +01:00
Fardale
4e9eeb50e5 add @since for delete_all 2018-01-27 23:48:47 +01:00
Fardale
dcd975ce85 Merge remote-tracking branch 'perso/master' into CCHeap 2018-01-27 20:18:51 +01:00
Simon Cruanes
7198417fd1
Merge pull request #179 from Fourchaux/master
Adding `CCList.tail_opt`
2018-01-26 08:26:14 -06:00
Simon Cruanes
b8260c737f fix doc target in opam 2018-01-26 08:14:47 -06:00
Fardale
7c7f66cd7b Add CCHeap.delete_all 2018-01-26 09:31:29 +01:00
nathan moreau
b0d92f44ea Adding CCList.tail_opt 2018-01-26 09:25:17 +01:00
Simon Cruanes
2007d7ad37 remove dep on bytes 2018-01-22 08:28:44 -06:00
Simon Cruanes
b3d8eb67a6 update opam file 2018-01-21 20:06:13 -06:00
Simon Cruanes
a3fa07bc05 add @orbifx to authors 2018-01-21 17:50:49 -06:00
Simon Cruanes
7df23d0cca fix build for benchs 2018-01-21 17:09:30 -06:00
Simon Cruanes
c7483ade3b chore(makefile): detail, to always build lib before tests 2018-01-21 15:59:10 -06:00
Simon Cruanes
c53a550822 add optional deps in opam 2018-01-21 15:45:03 -06:00
Simon Cruanes
446ae9f26b prepare for 2.0 2018-01-21 15:38:34 -06:00
Simon Cruanes
bc27e60a81 reindent 2018-01-21 14:39:44 -06:00
Simon Cruanes
f98bcffaee
Merge pull request #178 from Fourchaux/master
Small typos & Style
2018-01-21 14:38:27 -06:00
nathan moreau
cde776f4ac Small typos 2018-01-21 20:29:51 +01:00
Simon Cruanes
f63bcee290
Merge pull request #177 from Fourchaux/master
Add comments and improve their style (from @Fourchaux)
2018-01-21 10:33:31 -06:00
nathan moreau
25f919070f Adding comments 2 2018-01-21 17:09:42 +01:00
nathan moreau
b04e097cf4 Adding comments 2018-01-21 16:16:35 +01:00
Simon Cruanes
829ceeb147
Merge pull request #176 from orbifx/master
Add `CCList.iteri2` and `CCList.foldi2`
2018-01-18 12:21:46 -06:00
Stavros Polymenis
796702a732 Add CCList.iteri2 and CCList.foldi2 2018-01-18 18:07:19 +00:00
Simon Cruanes
ec23d64550 remove junk file 2018-01-17 20:15:04 -06:00
Simon Cruanes
282f85a874 remove PARAM.min_size in CCPool 2018-01-17 20:12:50 -06:00
Simon Cruanes
0e26502008 wip: fix behavior of CCPool when min_size>0
problem is a deadlock occurs when some threads die (too early?)
when P.min_size>0
2018-01-17 20:11:14 -06:00
Simon Cruanes
bc622f636a fix tests for sequence 1.0 2018-01-17 20:04:03 -06:00
Simon Cruanes
ea4de9a618 udpate opam file 2018-01-15 08:44:18 -06:00
Simon Cruanes
564a804701 chore(travis): remove 4.01 from versions 2018-01-14 20:59:50 -06:00
Simon Cruanes
3be488a910 remove merlin file 2018-01-14 20:55:09 -06:00
Simon Cruanes
d97e1e7231 add script to generate jbuilder flags dynamically 2018-01-14 20:38:40 -06:00
Simon Cruanes
a307bb09f7 chore(jbuild): missing flag for optional sublibs, deps 2018-01-14 19:24:46 -06:00
Simon Cruanes
266c0c073e travis: need odoc for the doc 2018-01-14 19:24:46 -06:00
Simon Cruanes
fc329fa118 rename print to pp for Format printers (closes #153) 2018-01-14 17:58:20 -06:00
Simon Cruanes
19b2b7c7cc remove CCFlatHashtbl 2018-01-14 17:57:13 -06:00
Simon Cruanes
5119b69051 update travis script 2018-01-14 17:49:00 -06:00
Simon Cruanes
8f46fdb6d2 move to jbuilder (closes #165) 2018-01-14 17:43:56 -06:00
Simon Cruanes
2c9a1d70c9
Merge pull request #169 from jpdeplaix/CCMonomorphic
Add `CCMonomorphic`, make most optional arguments that rely on poly operators mandatory.
2018-01-14 17:34:53 -06:00
Jacques-Pascal Deplaix
88e4df4b12 Mention Pervasives.(==) as an alternative to CCEqual.physical 2018-01-14 23:33:39 +00:00
Jacques-Pascal Deplaix
aa0f34c5c9 Add CCEqual.physical 2018-01-14 23:33:39 +00:00
Jacques-Pascal Deplaix
3c808f397e Shadow the physical equality operator 2018-01-14 23:33:39 +00:00
Jacques-Pascal Deplaix
ff69945575 Shadow polymorphic functions in CCList 2018-01-14 23:33:39 +00:00
Jacques-Pascal Deplaix
35c2d0ed54 Fix tests 2018-01-14 23:32:13 +00:00
Jacques-Pascal Deplaix
0796a9a8d4 Fix compilation of benchs 2018-01-14 23:32:13 +00:00
Jacques-Pascal Deplaix
9622f6f6ff Avoid uses of the polymorphic operators 2018-01-14 23:32:13 +00:00
Jacques-Pascal Deplaix
35b4e772be Add Containers.Monomorphic and include it by default 2018-01-14 23:32:13 +00:00
Jacques-Pascal Deplaix
6d2063ded4 Internally shadow polymorphic operators and functions from Pervasives 2018-01-14 23:32:13 +00:00
Jacques-Pascal Deplaix
01a3b94ff9 Add a CCMonomorphic module shipped into a containers.monomorphic library 2018-01-14 23:32:13 +00:00
Simon Cruanes
631b33f62e fix doc 2018-01-14 16:21:59 -06:00
Simon Cruanes
4ffe1bbac3 make complexity of Array.lookup explicit (closes #174) 2018-01-06 17:14:00 -06:00
Simon Cruanes
1b9c014e25 use neat trick to alias properly type of Format 2018-01-06 08:24:42 -06:00
Simon Cruanes
53137a6183 prepare for 1.5.2 2018-01-04 11:13:26 -06:00
Simon Cruanes
a160ae3672 missing type aliases (see #173) 2018-01-04 08:53:33 -06:00
Simon Cruanes
d76831a8c3 changelog 2018-01-03 08:05:02 +01:00
Simon Cruanes
858ef0e90f missing extension of Format 2018-01-02 23:39:55 +01:00
Simon Cruanes
18c9f88411 prepare for 1.5 2018-01-02 18:14:32 +01:00
Simon Cruanes
7f6cb0f673 have CCList.{get,insert,set}_at_idx work with negative indices 2017-12-25 17:30:00 +01:00
Simon Cruanes
d8610646d8
Merge pull request #170 from jpdeplaix/remove_at_neg_idx
Allow negative indexes in `CCList.remove_at_idx`
2017-12-25 17:25:15 +01:00
Simon Cruanes
f040f476e2 travis 2017-12-24 17:41:33 +01:00
Simon Cruanes
17dc7bb5c3 fix default implems of CCList.compare_length{s,_with} 2017-12-24 17:22:02 +01:00
Simon Cruanes
c12f2d2095 more tests 2017-12-24 17:21:57 +01:00
Simon Cruanes
a249f2ac0b missing compat functions 2017-12-24 17:10:02 +01:00
Simon Cruanes
f6b3a7addf warnings 2017-12-24 17:07:59 +01:00
Simon Cruanes
787c9ad5d1 travis 2017-12-24 16:54:00 +01:00
Simon Cruanes
b7a250cef2 remove cppo from deps and build 2017-12-24 16:49:47 +01:00
Simon Cruanes
df07cf5bb2 remove all uses of cppo 2017-12-24 16:43:17 +01:00
Simon Cruanes
bb37abe984 add travis support 2017-12-24 16:43:17 +01:00
Jacques-Pascal Deplaix
4b30aba080 Allow negative indexes in CCList.remove_at_idx 2017-12-23 15:35:35 +00:00
Simon Cruanes
ed10db67b6 closes #166 by adding a drop parameter to string split functions 2017-12-21 14:07:52 +01:00
Simon Cruanes
2b67a1a679 add colors 2017-12-19 20:24:12 +01:00
Simon Cruanes
9ac7984f74 add Hash.const0 for trivial hash function that ignores its input 2017-12-15 13:49:34 +01:00
Simon Cruanes
632526e407 improve compatibility with the stdlib 2017-12-15 09:49:54 +01:00
Simon Cruanes
3a4d827d80 fix containers.top (closes #155) 2017-12-15 09:43:44 +01:00
Simon Cruanes
00f0a1dd34
Merge pull request #164 from lostman/master
Use `include` to make `CCListLabels` and `CCArrayLabels` trivial
2017-12-06 11:38:01 +01:00
Maciej Woś
7d88c0f068 Update AUTHORS 2017-12-06 19:35:54 +09:00
Maciej Woś
58277c77bb Automatically add labeled interface to CCList and CCArray 2017-12-06 13:05:20 +09:00
Simon Cruanes
16a7ff6d4e
Merge pull request #162 from jpdeplaix/list_count
Add `List.count`
2017-12-03 22:37:27 +01:00
Jacques-Pascal Deplaix
78ee7e5c2f Add List.count 2017-12-03 21:30:26 +00:00
Simon Cruanes
e16d0ee27b
Merge pull request #160 from jpdeplaix/String.is_empty
Add `String.is_empty`
2017-12-01 09:43:49 +01:00
Jacques-Pascal Deplaix
e20d0ccfcc Add String.is_empty 2017-12-01 08:36:40 +00:00
Simon Cruanes
c66c96d252 small fixes in ocamldoc 2017-11-29 15:00:05 +01:00
Simon Cruanes
946a585a9e backport some functions added in 4.05 in CCList 2017-11-29 14:58:35 +01:00
Simon Cruanes
f65bcd212d small comment 2017-11-29 14:58:35 +01:00
Simon Cruanes
2fbf765466 fix small warning 2017-11-29 14:58:35 +01:00
Simon Cruanes
b1cc57b2fe update warnings 2017-11-29 14:58:35 +01:00
Simon Cruanes
d09820b916 add functions from 4.05 into CC{Map,Set} 2017-11-29 14:58:35 +01:00
Simon Cruanes
170d7662e7
Merge pull request #159 from orbifx/master
Add `CCImmutArray.sub`, which creates a copy
2017-11-20 21:45:57 +01:00
Stavros Polymenis
a28dd399f4 Improve CCImmutArray.sub comments and versioning 2017-11-20 20:42:17 +00:00
SP
c49458d923 Implement CCImmutArray.sub, but creates a copy 2017-11-20 16:14:04 +00:00
Simon Cruanes
3b50617744
Merge pull request #158 from jpdeplaix/fix-cctrie
fix bug in `CCTrie` where an assertion would use polymorphic comparison on arbitrary types
2017-11-07 18:24:17 +01:00
Jacques-Pascal Deplaix
3d27bd285e Add a regression test 2017-11-07 18:08:38 +01:00
Simon Cruanes
66d4ae9811 missing function in CCListLabels 2017-11-07 13:56:38 +01:00
Jacques-Pascal Deplaix
0ed3c70669 Fix CCTrie.Make: Remove polymorphic comparison 2017-11-07 12:11:41 +01:00
Simon Cruanes
f28b75792b
Merge pull request #156 from Gbury/add-cache
Add `CCCache.add` for manual manipulation of caches
2017-11-01 17:32:40 +01:00
Guillaume Bury
03f3457f6d Add CCCache.add 2017-11-01 03:25:08 +01:00
Simon Cruanes
92c683a9c4 doc: CCList.cartesian_product returns results in unspecified order (close #154) 2017-10-27 15:39:01 +02:00
Simon Cruanes
d6f7f1570e prepare for 1.4 2017-10-11 09:29:31 +02:00
Simon Cruanes
66a8dfc396 add a test 2017-10-05 18:19:48 +02:00
Simon Cruanes
336ebe63f9 style and comments for the new CCList.map 2017-10-05 11:59:03 +02:00
Simon Cruanes
e2d20b61f0 Merge pull request #152 from bluddy/master
`CCList`: Use efficient chunking algorithm for tail-recursive list map
2017-10-05 11:52:38 +02:00
Simon Cruanes
1afd0311fc add ocp-indent file 2017-10-04 09:09:02 +02:00
Yotam Barnoy
0aaab670f7 list: Use efficient chunking algorithm for tail-recursive list map
See discussion at
https://discuss.ocaml.org/t/a-new-list-map-that-is-both-stack-safe-and-fast/865/32
2017-10-03 17:45:26 -04:00
Simon Cruanes
4096122979 add CCMap.union 2017-09-30 15:02:03 +02:00
Simon Cruanes
e9b9ed1d92 add CCRef.swap 2017-09-22 17:52:24 +02:00
Simon Cruanes
9beab5c3e6 update readme 2017-09-18 10:58:58 +02:00
Simon Cruanes
9a2dab6802 Merge pull request #151 from quicquid/ccfqueue-bugfix
bugfix for `CCFQueue.take_back_exn` : wrong exception
2017-09-18 10:43:54 +02:00
Martin
49721c4bc5 CCFQueue.take_back_exn raised InvalidArg instead of Empty on an empty queue 2017-09-18 10:40:03 +02:00
Simon Cruanes
f254a0f6e4 small doc 2017-09-18 10:38:54 +02:00
Simon Cruanes
01e8720797 small change for benchs on 4.02 2017-09-18 10:23:33 +02:00
Simon Cruanes
4cc9862ef8 refactoring in vector 2017-09-17 21:37:33 +02:00
Simon Cruanes
86b6d714cf Merge pull request #150 from copy/master
Tests for `CCVector.append{,_array}` and fix for `CCVector.append_array` in empty case
2017-09-17 21:19:46 +02:00
Fabian
ea54fdff32 Update authors 2017-09-16 21:34:36 +02:00
Fabian
03f6a1fe5e Use ensure_not_empty_ when vector is known to be non-empty 2017-09-16 21:31:56 +02:00
Fabian
9219d24356 Fix CCVector.append_array (empty vector case) 2017-09-16 21:29:47 +02:00
Fabian
f1942fd0d4 More tests for CCVector.append and CCVector.append_array 2017-09-16 21:25:55 +02:00
Simon Cruanes
c792d70ac7 assertions and cleanup in CCPool 2017-09-13 18:39:14 +02:00
Simon Cruanes
7405c1c346 more tweaks and benchmarks for CCString.{prefix,suffix} 2017-09-12 10:55:24 +02:00
Simon Cruanes
ff469211af benchmarks for string prefix checking 2017-09-12 10:37:32 +02:00
Simon Cruanes
a323809aa0 faster CCString.{prefix,suffix}
see https://github.com/ocaml-batteries-team/batteries-included/issues/792
for some discussion
2017-09-12 10:37:32 +02:00
Simon Cruanes
56928a1a15 specify behavior of CCFQueue.take_{front,back}_l in some corner cases 2017-09-10 19:56:39 +02:00
Simon Cruanes
d7b90d3ba3 add CCArray.swap 2017-09-10 19:56:39 +02:00
Simon Cruanes
54e12b7f62 style update for some string functions 2017-09-07 10:10:34 +02:00
Simon Cruanes
14d701f84c Merge pull request #147 from cxa/master
fix `CCFun.tap` example in doc (thanks to @cxa)
2017-08-28 17:55:05 +02:00
CHEN Xian-an
90e96e6339 fix CCFun.tap example in doc 2017-08-28 23:46:05 +08:00
Simon Cruanes
d086a617f3 update doc gen 2017-08-25 15:19:13 +02:00
Simon Cruanes
62d76ce555 change signature of CCWBTree.get_rank 2017-08-11 00:41:26 +02:00
Simon Cruanes
cf09112f79 add CCWBTree.get_rank{,_exn} 2017-08-09 10:05:55 +02:00
Simon Cruanes
0e3a659cd1 remove warning in merlin 2017-08-09 10:05:39 +02:00
Simon Cruanes
c575f97369 whitespace 2017-07-29 19:24:37 +02:00
Simon Cruanes
bedf9ecc1e prepare for 1.3 2017-07-29 18:08:58 +02:00
Simon Cruanes
acb286d8e8 add CCString.compare_natural (closes #146) 2017-07-23 13:48:31 +02:00
Simon Cruanes
d076afc405 fix in doc (closes #145) 2017-07-21 15:02:42 +02:00
Simon Cruanes
b7b6bd19a3 deprecate CCBool.negate 2017-07-21 15:02:27 +02:00
Simon Cruanes
609d51c89e bugfix in CCList.split 2017-07-04 16:25:28 +02:00
Simon Cruanes
debf586db5 add callbacks in CCCache.with_cache{,_rec} (closes #140) 2017-07-04 16:25:28 +02:00
Simon Cruanes
aab19f6a50 update headers; reindent 2017-07-04 13:13:24 +02:00
Simon Cruanes
296cdc8748 small changes to CCList 2017-06-29 23:36:54 +02:00
Simon Cruanes
887d2f5d8d Merge pull request #138 from bikalgurung/master
Implement safe version of `List.split` (thanks to @bikalgurung)
2017-06-29 23:34:53 +02:00
Bikal Gurung
2c92771ad9 Update authors page. 2017-06-29 21:19:48 +01:00
Bikal Gurung
eab5fbb36a Addresses reviewer comments. 2017-06-29 21:15:01 +01:00
Bikal Gurung
745c0cd78e Addresses reviewer comments 2017-06-29 18:13:39 +01:00
Bikal Gurung
7a9a741bb0 Adds tests for split function. 2017-06-28 23:27:06 +01:00
Bikal Gurung
973062158a Implements safe version of List.split 2017-06-28 22:10:50 +01:00
Simon Cruanes
adb9159007 Merge pull request #136 from nilsbecker/nilsbecker-patch-1
some doc clarifications/corrections in `Array` and `Array_slice`
2017-06-24 18:19:07 +02:00
nilsbecker
78591cf621 removed trailing spaces 2017-06-24 18:16:21 +02:00
nilsbecker
92958cc116 duplicated the changes in array_slice.mli 2017-06-24 13:48:20 +02:00
nilsbecker
a2b2eaec2e small correction 2017-06-24 13:45:49 +02:00
nilsbecker
4058fc799e typos and clarification in doc strings
for sort_indices, sort_ranks and lookup_exn
2017-06-24 11:59:59 +02:00
Simon Cruanes
a3ff9db0a1 change CCRingBuffer.peek_{front,back} to return options (closes #127) 2017-06-14 23:58:07 +02:00
Simon Cruanes
be84b76dc0 add CCRingBuffer.is_full 2017-06-14 23:52:05 +02:00
Simon Cruanes
f91af32ee4 bugfix in CCRingBuffer.skip, and corresponding tests 2017-06-14 08:54:46 +02:00
Simon Cruanes
ff77a6a16b cleanup and refactor of CCRingBuffer (see #126). Add strong tests.
- add some qcheck test comparing to reference implem
- use bounded buffers only
- use inefficient methods (for now)
2017-06-13 20:42:27 +02:00
Simon Cruanes
a427d7700c more readme 2017-06-13 18:22:14 +02:00
Simon Cruanes
1dbd017c43 more on contributing in readme 2017-06-13 18:20:29 +02:00
Simon Cruanes
6d5d2a56e2 readme again 2017-06-13 17:58:38 +02:00
Simon Cruanes
3bfd1ddf8e update links to doc 2017-06-13 17:56:01 +02:00
Simon Cruanes
783f6020d6 add benchmark 2017-06-02 11:51:28 +02:00
Simon Cruanes
635855b68b CCRingBuffer: add regression test for #126; update headers; style 2017-05-30 15:18:12 +02:00
Simon Cruanes
b2f8eb5b27 update to qcheck 0.6 2017-05-30 09:16:37 +02:00
Simon Cruanes
d659ba677e remove old license header 2017-05-21 15:34:47 +02:00
Simon Cruanes
5d768aeeb2 add CCArray.find_map{,_i}, deprecated older names (closes #129) 2017-05-20 13:18:36 +02:00
Simon Cruanes
bfefda632b add CCList.{keep,all}_{some,ok} (closes #124) 2017-05-20 13:15:18 +02:00
Simon Cruanes
0a58e55287 large refactor of CCSimple_queue (close #125) 2017-05-10 20:26:29 +02:00
Simon Cruanes
002386cad8 small change for consistency in CCIntMap 2017-05-10 17:15:15 +02:00
Simon Cruanes
f48dbc458e add rich testsuite to CCIntMap, based on @jmid's work 2017-05-10 17:14:54 +02:00
Simon Cruanes
d6120d4784 add CCSimple_queue to containers.data 2017-05-10 08:58:51 +02:00
Simon Cruanes
f7394ede9f small change to improve test speed 2017-05-01 18:39:11 +02:00
Simon Cruanes
3ab610ba0e prepapre for 1.2 2017-05-01 16:59:25 +02:00
Simon Cruanes
465b5992e8 add CCString.{l,r}trim (close #121) 2017-05-01 16:54:29 +02:00
Simon Cruanes
5d5909459f details 2017-05-01 16:54:29 +02:00
Simon Cruanes
75e3962ba1 make many modules extensions of stdlib (close #109)
for : Random Array List ArrayLabels ListLabels Char String
2017-05-01 16:54:23 +02:00
Simon Cruanes
0c4bf82c5c Merge pull request #123 from copy/master
Implement `CCInt.floor_div` and `CCInt.rem` (close #122)
2017-04-28 22:27:43 +02:00
Fabian
0408466bd9 More tests for floor_div and rem 2017-04-28 15:22:32 -05:00
Fabian
883eb611f0 Implement CCInt.floor_div and CCInt.rem 2017-04-28 14:40:15 -05:00
Simon Cruanes
43bccceac7 add test and bugfix for CCBV 2017-04-27 22:33:58 +02:00
Simon Cruanes
81ed6139ca add CCList.take_drop_while (close #120) 2017-04-24 20:20:37 +02:00
Simon Cruanes
8d01cf3cc2 missing fun 2017-04-19 22:45:41 +02:00
Simon Cruanes
9aa5d08f96 more doc (close #118) 2017-04-19 22:40:04 +02:00
Simon Cruanes
77ed135493 add a comment about contributing (close #106); update makefile 2017-04-19 22:31:18 +02:00
Simon Cruanes
57d460ecde style 2017-04-19 22:28:02 +02:00
Simon Cruanes
02f1d5c4a0 Merge pull request #117 from rleonid/add_negate
change `CCBV` to track size, with some breaking changes (thank to @rleonid)
2017-04-19 22:25:07 +02:00
Simon Cruanes
71ad95044f missing function 2017-04-19 22:09:46 +02:00
Simon Cruanes
93568949e6 annotations in CCEqual, for optimization 2017-04-19 22:08:56 +02:00
Leonid Rozenberg
84a537efbd Add test for diff 2017-04-19 15:27:35 -04:00
Leonid Rozenberg
0b53ed01a3 Merge and bug fix pass 2017-04-19 14:52:13 -04:00
Leonid Rozenberg
cbff4e5a39 Merge branch 'master' into add_negate 2017-04-19 12:30:35 -04:00
Leonid Rozenberg
2b148f0055 Add self to authors 2017-04-19 12:29:23 -04:00
Leonid Rozenberg
f90f73f671 Incorporate reviewier feedback.
Also added style elements from PR#116.
2017-04-19 12:26:47 -04:00
Simon Cruanes
8460b01f2f fix hair-raising english mistake 2017-04-19 17:36:53 +02:00
Leonid Rozenberg
d8a55a98b9 Size tracking implementation 2017-04-19 02:15:09 -04:00
Simon Cruanes
6c8de1bc64 small fix 2017-04-18 22:04:37 +02:00
Simon Cruanes
fcd987f1c0 fix test 2017-04-18 21:47:32 +02:00
Simon Cruanes
0c7280a8f4 remove test that depends on 4.02 2017-04-18 21:46:38 +02:00
Simon Cruanes
1b200ff695 add CCstring.equal_caseless (close #112) 2017-04-18 21:41:44 +02:00
Simon Cruanes
c725543faa add alias CCString.split (close #115) 2017-04-18 21:23:18 +02:00
Simon Cruanes
9cca745fcf add CCFormat.text (close #111) 2017-04-18 21:19:50 +02:00
Simon Cruanes
fc6682b1c1 add CCFormat.{newline,substring} 2017-04-18 21:19:37 +02:00
Simon Cruanes
f294ce1634 add CCList.combine_gen (close #110) 2017-04-18 20:58:38 +02:00
Simon Cruanes
990b7b7b81 style 2017-04-18 20:55:03 +02:00
Simon Cruanes
6d728d5ce7 add a small test 2017-04-18 14:05:55 +02:00
Simon Cruanes
7e9f87ecba Merge pull request #114 from LemonBoy/tr-combine
Add a tail-recursive implementation of `List.combine` (thanks to @LemonBoy)
2017-04-18 14:01:06 +02:00
LemonBoy
404fede54a Add a tail-recursive implementation of List.combine
Closes #108.
2017-04-18 12:03:46 +02:00
Leonid Rozenberg
b70a8d875e One is _a_ megalomaniac 2017-04-17 19:00:39 -04:00
Simon Cruanes
af6cd08ff4 fix too restrictive type in CCResult 2017-04-13 15:23:22 +02:00
Simon Cruanes
c7b1afca82 missing alias 2017-04-10 10:31:54 +02:00
Simon Cruanes
08bc15dd8c add module CCEqual 2017-04-09 15:11:44 +02:00
Simon Cruanes
02b2a21e33 add CCResult.fold_ok (closes #107) 2017-04-05 10:43:37 +02:00
Simon Cruanes
ee69bdcab8 add CCFormat.with_color_ksf for colored printing 2017-04-03 15:32:26 +02:00
Simon Cruanes
e0287b9efe add CCInt.range{,',by} for iterating on integer ranges 2017-03-29 17:40:54 +02:00
Simon Cruanes
47abc78a51 add CCString.Sub.get 2017-03-29 17:40:54 +02:00
Simon Cruanes
670d2dbd4b build unix support by default 2017-03-29 17:40:54 +02:00
Simon Cruanes
f27f7757de add CCResult.add_ctx{,f} for replacing stack traces 2017-03-27 22:06:37 +02:00
Simon Cruanes
e6221d7e50 add test 2017-03-27 21:05:37 +02:00
Simon Cruanes
7e8c7235bc use result package for retrocompat 2017-03-26 00:36:45 +01:00
Simon Cruanes
e9de0a8902 Merge pull request #105 from glennsl/master
Plugs some holes in `CCOpt` (add `or_`, `_lazy` versions, and `{to,of}_result`)
2017-03-26 00:33:36 +01:00
glennsl
6573a2dd4a Add map_lazy, or_, or_lazy, to_result, to_result_lazy and of_result to CCOpt 2017-03-26 00:29:32 +01:00
Simon Cruanes
923e83b0fc make tests faster 2017-03-16 10:27:00 +01:00
Simon Cruanes
b5be1d71a9 bugfix and test for CCZipper.is_focused (closes #102) 2017-03-14 22:45:11 +01:00
Simon Cruanes
97abfe600e use boxes in CCFormat.Dump for tuples 2017-03-14 11:16:11 +01:00
Simon Cruanes
ef651342eb add CCString.split_on_char 2017-03-10 21:33:40 +01:00
Simon Cruanes
48bb1e24c6 update header, and use more (==) in CCIntMap 2017-03-09 22:51:33 +01:00
Simon Cruanes
d135f73c76 add CCArray.{fold_map,scan_left} (close #101) 2017-03-09 21:42:44 +01:00
Simon Cruanes
6e97ee8c7c add CCList.scan_left 2017-03-09 21:42:44 +01:00
Simon Cruanes
ff53571a3b add CCList.{cartesian_product,map_product_l} 2017-03-09 21:42:44 +01:00
Simon Cruanes
4aa507c7bf small fix in readme 2017-03-07 09:37:31 +01:00
Simon Cruanes
a45d8c46a6 add CCUnix.with_file_lock for locking whole files 2017-03-07 09:37:31 +01:00
Simon Cruanes
ae6d81a9a4 add CCFormat.of_chan 2017-03-07 09:37:29 +01:00
Simon Cruanes
719d048f57 add CCFormat.flush 2017-03-07 09:36:53 +01:00
Simon Cruanes
d45b341232 prepare for 1.1 2017-03-03 16:18:13 +01:00
Simon Cruanes
6df16975ca fix bug in CCOpt.filter (close #100) 2017-03-03 14:15:38 +01:00
Simon Cruanes
5713183a3a remove dead code 2017-03-03 14:15:38 +01:00
Simon Cruanes
18827b920b small fix in doc 2017-03-03 14:15:38 +01:00
Simon Cruanes
8627838faf add CCHeap.to_seq_sorted 2017-02-23 21:01:32 +01:00
Simon Cruanes
12b38f4c31 add CCHeap.to_list_sorted 2017-02-23 20:57:19 +01:00
Simon Cruanes
b06ae52071 new test for CCPool 2017-02-22 13:48:13 +01:00
Simon Cruanes
6fadeb414e add CCIO.File.walk_l 2017-02-17 15:09:51 +01:00
Simon Cruanes
801f059532 add some doc 2017-02-17 14:20:45 +01:00
Simon Cruanes
cd2d07c76a new test and small readme section on CCParse 2017-02-16 11:58:47 +01:00
Simon Cruanes
207a5725de fix the bug in CCGraph 2017-02-13 15:26:52 +01:00
Simon Cruanes
38f5692e21 add test for regression in CCGraph 2017-02-13 15:26:44 +01:00
Simon Cruanes
858a360ab0 update .merlin and .ocamlinit 2017-02-11 15:28:37 +01:00
Simon Cruanes
c1980c2ead remove CCError from tutorial 2017-02-11 14:51:02 +01:00
Simon Cruanes
283b34c3c6 small fix in readme 2017-02-11 14:48:58 +01:00
Simon Cruanes
7603a78970 more radical change: merge tutorial into readme, cleanup 2017-02-11 14:46:56 +01:00
Simon Cruanes
8d671f03a1 update readme and opam file 2017-02-11 14:40:30 +01:00
Simon Cruanes
25b714c3cb Merge branch 'prepare-1.0' into master. 2017-02-11 13:56:26 +01:00
Simon Cruanes
5777549c54 prepare for 1.0 2017-02-11 13:56:08 +01:00
Simon Cruanes
f1459b57df add CCHash.{list,array}_comm 2017-02-11 13:37:32 +01:00
Simon Cruanes
8ddacbb028 add CCHashtbl.Poly and fix issue in Containers (close #46) 2017-02-11 13:28:47 +01:00
Simon Cruanes
edc488b909 add CCHashtbl.get_or_add 2017-02-07 11:38:10 +01:00
Simon Cruanes
827da5a01b more doc 2017-02-06 18:04:27 +01:00
Simon Cruanes
1e9f5a9a21 more flexible CCList.sublists_of_len 2017-02-06 17:35:12 +01:00
Simon Cruanes
fe2336bd3b add CCList.sublists_of_len (close #97) 2017-02-06 17:25:23 +01:00
Simon Cruanes
8462b89bdf add Char.{of_int{,_exn},to_int} (close #95) 2017-01-30 14:46:13 +01:00
Simon Cruanes
126bb2f3f2 test for #94 (using Thread.yield to trigger segfault) 2017-01-26 23:49:59 +01:00
Simon Cruanes
5e7cfed9b8 containers.top: remove printers on structural types (#71) 2017-01-26 15:50:18 +01:00
Simon Cruanes
61f1ca3231 update a test 2017-01-26 14:20:24 +01:00
Simon Cruanes
9a46b4527c reindent in containers.thread 2017-01-25 00:24:14 +01:00
Marcello Seri
59208fd9c6 Fix with_acquire: release a non locked mutex is UB
This is segfaulting (on ubuntu 16.04 and 16.10) when trying to release the unlocked mutex in the release stage (in general this is an undefined behavior).
2017-01-25 00:15:45 +01:00
Simon Cruanes
56462a862b Merge branch 'master' into prepare-1.0 2017-01-25 00:15:03 +01:00
Simon Cruanes
03fd42e67d reindentation 2017-01-25 00:08:12 +01:00
Simon Cruanes
416d19a763 remove deprecated functions and modules
- `CCList.{split,findi,find}`
- `CCHashtbl.{MakeDefault,MakeCounter}`
- `CCVector.flat_map'`
2017-01-25 00:08:12 +01:00
Simon Cruanes
4821772dcf Revert "remove containers.thread"
This reverts commit 9f34a7f6e3.
2017-01-25 00:08:12 +01:00
Simon Cruanes
cebee407ea add makefule rule for ocp-indent 2017-01-25 00:08:12 +01:00
Simon Cruanes
c359b3d570 Merge pull request #94 from mseri/patch-1
Fix `CCSemaphore.with_acquire`: release a non locked mutex is UB (thanks to @mseri)
2017-01-24 23:59:51 +01:00
Simon Cruanes
0a7d2a2411 update benchmarks (ignoring hamt); remove useless old script 2017-01-24 23:43:15 +01:00
Simon Cruanes
a0f3a5d24b update comments in CCParse 2017-01-24 23:28:08 +01:00
Simon Cruanes
dbe00f6ca5 update containers.ml so as to include all core containers 2017-01-24 23:26:23 +01:00
Simon Cruanes
8aab182642 large refactor of CCHash, main type is now 'a -> int 2017-01-24 23:21:10 +01:00
Simon Cruanes
8ad0dce97b CCFormat: remove start/stop args, make sep a unit printer 2017-01-24 22:50:26 +01:00
Simon Cruanes
e5adafced6 many improvements to CCFormat
- add `some`
- add `return`
- add `const`
- add `of_to_string`
2017-01-24 22:39:13 +01:00
Simon Cruanes
d76d3b95e3 add CCOrd.Infix 2017-01-24 22:19:59 +01:00
Marcello Seri
b50c9f4027 Fix with_acquire: release a non locked mutex is UB
This is segfaulting (on ubuntu 16.04 and 16.10) when trying to release the unlocked mutex in the release stage (in general this is an undefined behavior).
2017-01-24 16:42:42 +00:00
Simon Cruanes
6823015b63 update headers 2017-01-24 15:25:57 +01:00
Simon Cruanes
1e8f378f02 Merge pull request #93 from orbitz/add-predicates-for-result
Add `is_ok` and `is_error`, simple predicates for testing a result
2017-01-17 20:12:27 +01:00
orbitz
13888edb4d Add is_ok and is_error, simple predicates for testing a result. This is useful for tests or asserts 2017-01-17 20:09:26 +01:00
Simon Cruanes
3f80e794ba add CCFormat.tee 2017-01-11 18:40:07 +01:00
Simon Cruanes
ed38c25711 replace or_ by default in labelled functions 2016-12-29 11:45:55 +01:00
Simon Cruanes
601354305d breaking: remove trailing _ in CCOrd primitives 2016-12-29 11:43:48 +01:00
Simon Cruanes
f0aecf3b8e add doc for of_list in relevant modules (close #85) 2016-12-29 11:39:21 +01:00
Simon Cruanes
eb217a0cf1 add Labels modules to doc intro 2016-12-29 11:37:37 +01:00
Simon Cruanes
9b53e3c2a5 use Labels versions of CCList and CCArray 2016-12-29 11:07:44 +01:00
Simon Cruanes
0046bea415 bugfix: do not use Sequence.flatMap (close #90)
the function was deprecated and has been removed in sequence 0.9
2016-12-29 10:45:33 +01:00
Simon Cruanes
e8cd571005 prepare 0.22 2016-12-18 01:32:52 +01:00
Simon Cruanes
331d87e6a9 update opam file 2016-12-17 17:29:29 +01:00
Simon Cruanes
617727617c update 'authors' 2016-12-16 21:24:48 +01:00
Simon Cruanes
478a1be535 Merge pull request #89 from dsheets/try-lock
threads/CCLock: add `try_with_lock` to wrap `Mutex.try_lock` (thansk @dsheets)
2016-12-16 21:24:22 +01:00
David Sheets
35859508c0 threads/CCLock: add try_with_lock to wrap Mutex.try_lock 2016-12-16 18:58:04 +00:00
Simon Cruanes
ef07decbac Revert "add Array.append" (already in stdlib Array)
This reverts commit cdb4ba5dbc.
2016-12-12 14:18:05 +01:00
Simon Cruanes
cdb4ba5dbc add Array.append 2016-12-07 16:20:13 +01:00
Simon Cruanes
85d0ff8f3f Merge pull request #87 from jpdeplaix/master
Add `CCMultiSet.remove_all` (thanks @jpdeplaix)
2016-12-06 19:22:12 +01:00
Jacques-Pascal Deplaix
5279304b40 Add CCMultiSet.remove_all 2016-12-06 18:29:50 +01:00
Simon Cruanes
d1e33cd135 document errors in CCIO (close #86) 2016-11-30 20:52:18 +01:00
Simon Cruanes
0b3e1cea77 update readme 2016-11-15 22:04:19 +01:00
Simon Cruanes
a8babbd941 add labels to CCList 2016-11-11 00:52:44 +01:00
Simon Cruanes
b1837e7d05 add labels in CCArray 2016-11-11 00:39:58 +01:00
Simon Cruanes
f29329fb03 deal properly with broken symlinks and permission errors 2016-11-11 00:18:16 +01:00
Simon Cruanes
8e2fd235bb add some code in benchnarks for array.sort 2016-11-04 21:55:01 +01:00
Simon Cruanes
6dd0894c1f update benchmarks 2016-11-04 21:10:54 +01:00
Simon Cruanes
92f86da650 fix _oasis 2016-11-04 11:41:43 +01:00
Simon Cruanes
2f5fa8e7a1 detail in doc 2016-11-03 23:51:32 +01:00
Simon Cruanes
2d718b93ad remove CCHashconsedSet 2016-11-03 23:51:01 +01:00
Simon Cruanes
6943771bdf remove CCAllocCache 2016-11-03 23:49:50 +01:00
Simon Cruanes
d849b51892 remove CCBloom 2016-11-03 23:49:19 +01:00
Simon Cruanes
55ed78084f update doc 2016-11-03 23:47:18 +01:00
Simon Cruanes
13b34f4fcf simplify and cleanup of CCGraph 2016-11-03 23:25:39 +01:00
Simon Cruanes
7229f04981 detail 2016-11-03 23:25:35 +01:00
Simon Cruanes
89145313a5 improve CCUnix a bit 2016-11-03 22:37:26 +01:00
Simon Cruanes
a231bfb9c4 fix containers.ml 2016-11-03 22:21:22 +01:00
Simon Cruanes
192f315f53 simplify CCHash
- remove functor
- use `Hashtbl.seeded_hash` to combine values
2016-11-03 22:18:23 +01:00
Simon Cruanes
2c00983262 split CCList.Zipper into its own module, CCZipper in containers.data 2016-11-03 22:06:41 +01:00
Simon Cruanes
6ff6c51687 change argument ordering in CCList.Assoc 2016-11-03 22:03:13 +01:00
Simon Cruanes
ad1513e36c remove CCList.Idx, rename its functions to toplevel 2016-11-03 21:57:24 +01:00
Simon Cruanes
bf609e7f04 remove CCList.Set, move functions to toplevel and rename them 2016-11-03 21:45:15 +01:00
Simon Cruanes
9f34a7f6e3 remove containers.thread 2016-11-03 21:38:17 +01:00
Simon Cruanes
5a1a88d3f5 rewrite CCBitField with a much simpler interface 2016-11-03 21:35:53 +01:00
Simon Cruanes
4f6bce60e5 split CCArray.Sub into CCArray_slice 2016-11-03 21:24:21 +01:00
Simon Cruanes
610990e945 fix behavior of CCSexp
- allow "\123" escape codes
- allow "\b" escape codes
2016-11-03 20:45:47 +01:00
Simon Cruanes
c3e6e798e6 remove containers.string 2016-11-03 20:42:47 +01:00
Simon Cruanes
bd7a9ce070 add CCString.edit_distance 2016-11-03 20:27:26 +01:00
Simon Cruanes
72d43c6eeb add CCParse into core, a simple, lightweight version of parser combs 2016-11-03 20:10:18 +01:00
Simon Cruanes
8f7b29c3bd remove CCParse and CCKMP (will be replaced in core) 2016-11-03 19:08:00 +01:00
Simon Cruanes
46cee7096c expose CCString.Find for efficient sub-string searching 2016-11-03 18:48:25 +01:00
Simon Cruanes
83b0744a1b more type safety in String.Find 2016-11-03 18:39:03 +01:00
Simon Cruanes
5288713b76 remove poly-variant based errors, use result everywhere 2016-11-03 18:33:34 +01:00
Simon Cruanes
7628e654f7 remove containers.advanced 2016-11-03 18:29:23 +01:00
Simon Cruanes
13b283a91d remove buffer printers, rename pretty-printers to pp 2016-11-03 18:24:11 +01:00
Simon Cruanes
d4d7bc1de2 add CCFormat.Dump.{result,to_string} 2016-11-03 18:11:05 +01:00
Simon Cruanes
c89186a100 remove CCPrint (also, update tests relying on it) 2016-11-03 17:57:41 +01:00
Simon Cruanes
af6b1dd6e0 change type of CCUnix.escape_str 2016-11-03 17:56:05 +01:00
Simon Cruanes
e9c20b9b21 .merlin 2016-11-03 17:55:57 +01:00
Simon Cruanes
941d74968e remove CCSexpM, use ocamllex for a much simpler CCSexp 2016-11-03 17:44:35 +01:00
Simon Cruanes
f26b47ea5f update ocamlinit 2016-11-03 17:25:36 +01:00
Simon Cruanes
9f0b8851b0 remove containers.io 2016-11-03 16:29:14 +01:00
Simon Cruanes
bfa5a20f07 remove containers.bigarray 2016-11-03 16:28:21 +01:00
Simon Cruanes
c7b815509d prepare for 0.21 2016-11-03 16:04:12 +01:00
Simon Cruanes
af4c3fc195 change boxing in CCFormat.Dump; add example/doc 2016-11-03 15:57:03 +01:00
Simon Cruanes
9045fcca0b add CCFormat.{with_color_sf,fprintf_dyn_color,sprintf_dyn_color}
more dynamic way of adding colors, switching colors on/off, etc.
2016-11-03 15:48:21 +01:00
Simon Cruanes
0d9d17d5db add CCFormat.Dump for easy debugging (see #82) 2016-11-03 15:36:25 +01:00
Simon Cruanes
4ff174ce18 (breaking) make default start/stop arguments empty in printers (#82) 2016-11-03 15:19:50 +01:00
Simon Cruanes
269d4a7ba9 handle '\r` in CCSexpM (fixes #83) 2016-11-03 09:48:50 +01:00
Simon Cruanes
89c63a5357 update oasis setup 2016-11-02 11:49:09 +01:00
Simon Cruanes
3e7cbc1420 add alias Containers.IO 2016-11-02 08:22:03 +01:00
Simon Cruanes
18b32f8313 bugfixes in CCArray.Sub 2016-11-01 12:17:01 +01:00
Simon Cruanes
61ff75dca0 bugfix + tests for CCArray.Sub.sub 2016-11-01 11:46:14 +01:00
Simon Cruanes
b7db149e27 add CCArray.Sub.to_list 2016-11-01 11:27:07 +01:00
Simon Cruanes
73bb61a2de disable parallel build to support cygwin 2016-10-26 18:21:39 +02:00
Simon Cruanes
7ba8f58571 fix typo 2016-10-19 23:59:23 +02:00
Simon Cruanes
2a872907a1 add CCArray.{sorted,sort_indices,sort_ranking} (closes #81) 2016-10-19 18:18:05 +02:00
Simon Cruanes
bc7967054f prepare for 0.20 2016-10-14 11:33:53 +02:00
Simon Cruanes
81ca239ccc bugfix in CCArray.equal 2016-10-14 11:28:44 +02:00
Simon Cruanes
59a463a882 small fix + test 2016-10-14 11:24:57 +02:00
Simon Cruanes
fed7dd41e0 add functions in CCArray: fold2,iter2,map2 2016-10-13 10:04:58 +02:00
Simon Cruanes
53030c4c29 more general types for CCArray.{for_all2,exists2} 2016-10-13 10:04:23 +02:00
Simon Cruanes
a99720945b add CCArray.rev 2016-10-13 10:01:21 +02:00
Simon Cruanes
f0381ae0d9 update authors 2016-10-04 13:35:46 +02:00
Simon Cruanes
6cd4e6923c Merge pull request #79 from little-arhat/patch-1
fix `CCResult.map_or` type signature (thanks to @little-arhat)
2016-10-04 13:34:31 +02:00
Roma Sokolov
d4d22b1488 Fixes map_or
~default arg for `map_or`, as well as function, should not depend on the type of error case.
2016-10-04 14:27:34 +03:00
Simon Cruanes
d7e8cb24fd add CCFloat.round 2016-09-25 19:43:21 +02:00
Simon Cruanes
103963dc45 style 2016-09-25 19:39:02 +02:00
Simon Cruanes
e4c6752b6b add CCVector.append_gen 2016-09-25 19:38:03 +02:00
Simon Cruanes
3e50420ce8 add CCList.{head_opt,last_opt} 2016-09-25 19:34:05 +02:00
Simon Cruanes
7a823b16d8 fix CCString.*_ascii; add CCChar.{upper,lower}case_ascii 2016-09-18 20:31:53 +02:00
Simon Cruanes
b249adf86f add CCInt.{print_binary,to_string_binary} + tests (thanks @gsg) 2016-09-18 10:37:05 +02:00
Simon Cruanes
8cd06599ae update readme 2016-08-22 10:21:19 +02:00
Simon Cruanes
656565c195 add gh-pages doc generation to makefile 2016-08-22 10:15:37 +02:00
389 changed files with 49302 additions and 31344 deletions

28
.github/workflows/format.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: format
on:
push:
branches:
- main
pull_request:
jobs:
format:
name: format
strategy:
matrix:
ocaml-compiler:
- '5.3'
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@main
- name: Use OCaml ${{ matrix.ocaml-compiler }}
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{ matrix.ocaml-compiler }}
dune-cache: true
allow-prerelease-opam: true
- run: opam install ocamlformat.0.27.0
- run: opam exec -- make format-check

33
.github/workflows/gh-pages.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: github pages
on:
push:
branches:
- master # Set a branch name to trigger deployment
jobs:
deploy:
name: Deploy doc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: Use OCaml
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: '5.2'
dune-cache: false
- name: Deps
run: opam install odig containers containers-data
- name: Build
run: opam exec -- odig odoc --cache-dir=_doc/ containers containers-data
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_doc/html/
destination_dir: dev
enable_jekyll: true

64
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,64 @@
name: Build and Test
on:
push:
branches:
- main
pull_request:
jobs:
run:
name: build
timeout-minutes: 15
strategy:
fail-fast: true
matrix:
os:
- ubuntu-latest
ocaml-compiler:
- '4.08'
- '4.10'
- '4.14'
- '5.3'
- 'ocaml-variants.5.0.0+options,ocaml-option-bytecode-only'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@main
- name: Use OCaml ${{ matrix.ocaml-compiler }}
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{ matrix.ocaml-compiler }}
dune-cache: true
allow-prerelease-opam: true
- run: opam install -t containers containers-data --deps-only
- run: opam exec -- dune build '@install'
- run: opam exec -- dune runtest --force --profile=release
compat:
name: build
timeout-minutes: 15
strategy:
fail-fast: true
matrix:
os:
- macos-latest
- ubuntu-latest
#- windows-latest
ocaml-compiler:
- '5.1'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@main
- name: Use OCaml ${{ matrix.ocaml-compiler }}
uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: ${{ matrix.ocaml-compiler }}
dune-cache: true
allow-prerelease-opam: true
- run: |
opam install -t containers --deps-only ;
opam install containers-data --deps-only # no test deps
- run: opam exec -- dune build '@install'
- run: opam exec -- dune runtest -j 1 -p containers --profile=release # test only core on non-ubuntu platform

11
.gitignore vendored
View file

@ -4,8 +4,15 @@ _build
*.native
*.byte
.session
TAGS
*.docdir
setup.*
qtest*
*.html
.merlin
*.install
.ignore
_opam
*.exe
fuzz-*-input
fuzz-*-output
fuzz-logs/
doc/papers

30
.merlin
View file

@ -1,30 +0,0 @@
S src/core
S src/data/
S src/io
S src/iter/
S src/advanced/
S src/lwt/
S src/sexp/
S src/threads/
S src/misc
S src/string
S src/bigarray
S benchs
S examples
S tests
B _build/src/**
B _build/benchs
B _build/examples
B _build/tests
PKG oUnit
PKG benchmark
PKG result
PKG threads
PKG threads.posix
PKG lwt
PKG bigarray
PKG sequence
PKG hamt
PKG gen
PKG qcheck
FLG -w +a -w -4 -w -44

15
.ocamlformat Normal file
View file

@ -0,0 +1,15 @@
version = 0.27.0
profile=conventional
margin=80
if-then-else=k-r
parens-ite=true
parens-tuple=multi-line-only
sequence-style=terminator
type-decl=sparse
break-cases=toplevel
cases-exp-indent=2
field-space=tight-decl
leading-nested-match-parens=true
module-item-spacing=compact
quiet=true
parse-docstrings=false

View file

@ -1,34 +0,0 @@
#use "topfind";;
#thread
#require "bigarray";;
#require "unix";;
#require "sequence";;
#directory "_build/src/core";;
#directory "_build/src/misc";;
#directory "_build/src/pervasives/";;
#directory "_build/src/string";;
#directory "_build/src/io";;
#directory "_build/src/unix";;
#directory "_build/src/iter";;
#directory "_build/src/data";;
#directory "_build/src/advanced/";;
#directory "_build/src/sexp";;
#directory "_build/src/bigarray/";;
#directory "_build/src/threads";;
#directory "_build/src/top/";;
#directory "_build/tests/";;
#load "containers.cma";;
#load "containers_iter.cma";;
#load "containers_data.cma";;
#load "containers_advanced.cma";;
#load "containers_io.cma";;
#load "containers_unix.cma";;
#load "containers_sexp.cma";;
#load "containers_string.cma";;
#load "containers_pervasives.cma";;
#load "containers_bigarray.cma";;
#load "containers_top.cma";;
#thread;;
#load "containers_thread.cma";;
(* vim:syntax=ocaml:
*)

View file

@ -1,16 +0,0 @@
= Authors and contributors
- Simon Cruanes (`companion_cube`)
- Drup (Gabriel Radanne)
- Jacques-Pascal Deplaix
- Nicolas Braud-Santoni
- Whitequark (Peter Zotov)
- hcarty (Hezekiah M. Carty)
- struktured (Carmelo Piccione)
- Bernardo da Costa
- Vincent Bernardoff (vbmithr)
- Emmanuel Surleau (emm)
- Guillaume Bury (guigui)
- JP Rodi
- octachron (Florian Angeletti)
- Johannes Kloos

View file

@ -1,564 +0,0 @@
= Changelog
== 0.19
- add regression test for #75
- Fix `CCString.Split.{left,right}` (#75)
- additional functions in `CCMultiSet`
- show ocaml array type concretely in `CCRingBuffer.Make` sig
- cleanup and more tests in `CCHeap`
- fix bugs in `CCFlatHashtbl`, add some tests
- add more generic printers for `CCError` and `CCResult` (close #73)
- add `CCstring.of_char`
- update headers
== 0.18
- update implem of `CCVector.equal`
- add `CCOpt.get_or` with label, deprecates `get`
- add `CCArray.get_safe` (close #70)
- add `CCGraph.is_dag`
- add aliases to deprecated functions from `String`, add `Fun.opaque_identity`
- add `CCLazy_list.take`
- add `Lazy_list.filter`
- add `CCList.range_by`
== 0.17
=== potentially breaking
- change the semantics of `CCString.find_all` (allow overlaps)
=== Additions
- add `CCString.pad` for more webscale
- add `(--^)` to CCRAl, CCFQueue, CCKlist (closes #56); add `CCKList.Infix`
- add monomorphic signatures in `CCInt` and `CCFloat`
- add `CCList.{sorted_insert,is_sorted}`
- add `CCLazy_list` in containers.iter (with a few functions)
- add `CCTrie.longest_prefix`
- provide additional ordering properties in `CCTrie.{above,below}`
- add `CCOpt.if_`
- have
* `CCRandom.split_list` fail on `len=0`
* `CCRandom.sample_without_replacement` fail if `n<=0`
- add `CCOpt.{for_all, exists}`
- add `CCRef.{get_then_incr,incr_then_get}`
- add `Result.{to,of}_err`
- add `CCFormat.within`
- add `map/mapi` to some of the map types.
- add `CCString.{drop,take,chop_prefix,chop_suffix,filter,filter_map}`
- add `CCList.fold_filter_map`
- add `CCIO.File.with_temp` for creating temporary files
- add `{CCArray,CCVector,CCList}.(--^)` for right-open ranges
- add `Containers.{Char,Result}`
- modify `CCPersistentHashtbl.merge` and add `CCMap.merge_safe`
- add `CCHet`, heterogeneous containers (table/map) indexed by keys
- add `CCString.rev`
- add `CCImmutArray` into containers.data
- add `CCList.Assoc.remove`
=== Fixes, misc
- Make `CCPersistentHashtbl.S.merge` more general.
- optimize KMP search in `CCString.Find` (hand-specialize code)
- bugfix in `CCFormat.to_file` (fd was closed too early)
- add a special case for pattern of length 1 in `CCString.find`
- more tests, bugfixes, and benchs for KMP in CCString
- in CCString, use KMP for faster sub-string search; add `find_all{,_l}`
others:
- `watch` target should build all
- add version constraint on sequence
- migrate to new qtest
- add an `IO` section to the tutorial
- enable `-j 0` for ocamlbuild
== 0.16
=== breaking
- change the signature of `CCHeap.{of_gen,of_seq,of_klist}`
- change the API of `CCMixmap`
- make type `CCHash.state` abstract (used to be `int64`)
- optional argument `~eq` to `CCGraph.Dot.pp`
- rename `CCFuture` into `CCPool`
=== deprecations
- deprecate `containers.bigarray`
- deprecate `CCHashtbl.{Counter,Default}` tables
- deprecate `CCLinq` in favor of standalone `OLinq` (to be released)
=== bugfixes
- fix wrong signature of `CCHashtbl.Make.{keys,values}_list`
- missing constraint in `CCSexpM.ID_MONAD`
=== new features
- add a tutorial file
- add a printer into CCHeap
- add `{CCList,CCOpt}.Infix` modules
- add `CCOpt.map_or`, deprecating `CCopt.maybe`
- add `CCFormat.sprintf_no_color`
- add `CCFormat.{h,v,hov,hv}box` printer combinators
- add `CCFormat.{with_color, with_colorf}`
- add `CCList.hd_tl`
- add `CCResult.{map_or,get_or}`
- add `CCGraph.make` and utils
- add `CCHashtbl.add_list`
- add counter function in `CCHashtbl`, to replace `CCHashtbl.Counter`
- add `CCPair.make`
- add `CCString.Split.{left,right}_exn`
- add `CCIO.File.{read,write,append}` for quickly handling files
- add `CCRandom.pick_{list,array}`
- add `CCList.Assoc.update`
- add `CCList.Assoc.mem`
- add `{CCMap,CCHashtbl}.get_or` for lookup with default value
- add `CCLock.{decr_then_get, get_then_{decr,set,clear}}`
- rename `CCFuture` into `CCPool`, expose the thread pool
- split `CCTimer` out of `CCFuture`, a standalone 1-thread timer
- move `CCThread.Queue` into `CCBlockingQueue`
- add `CCResult`, with dependency on `result` for retrocompat
- add `CCThread.spawn{1,2}`
- add many helpers in `CCUnix` (for sockets, files, and processes)
- add `CCFun.finally{1,2}`, convenience around `finally`
- add `CCLock.update_map`
- add `CCLock.{incr_then_get,get_then_incr}`
- add breaking space in `CCFormat.{pair,triple,quad}`
- update `examples/id_sexp` so it can read on stdin
- add `CCList.fold_map2`
== 0.15
=== breaking changes
- remove deprecated `CCFloat.sign`
- remove deprecated `CCSexpStream`
=== other changes
- basic color handling in `CCFormat`, using tags and ANSI codes
- add `CCVector.ro_vector` as a convenience alias
- add `CCOrd.option`
- add `CCMap.{keys,values}`
- add wip `CCAllocCache`, an allocation cache for short-lived arrays
- add `CCError.{join,both}` applicative functions for CCError
- opam: depend on ecamlbuild
- work on `CCRandom` by octachron:
* add an uniformity test
* Make `split_list` uniform
* Add sample_without_replacement
- bugfix: forgot to export `{Set.Map}.OrderedType` in `Containers`
== 0.14
=== breaking changes
- change the type `'a CCParse.t` with continuations
- add labels on `CCParse.parse_*` functions
- change semantics of `CCList.Zipper.is_empty`
=== other changes
- deprecate `CCVector.rev'`, renamed into `CCVector.rev_in_place`
- deprecate `CCVector.flat_map'`, renamed `flat_map_seq`
- add `CCMap.add_{list,seqe`
- add `CCSet.add_{list,seq}`
- fix small uglyness in `Map.print` and `Set.print`
- add `CCFormat.{ksprintf,string_quoted}`
- add `CCArray.sort_generic` for sorting over array-like structures in place
- add `CCHashtbl.add` mimicking the stdlib `Hashtbl.add`
- add `CCString.replace` and tests
- add `CCPersistentHashtbl.stats`
- reimplementation of `CCPersistentHashtbl`
- add `make watch` target
- add `CCVector.rev_iter`
- add `CCVector.append_list`
- add `CCVector.ensure_with`
- add `CCVector.return`
- add `CCVector.find_map`
- add `CCVector.flat_map_list`
- add `Containers.Hashtbl` with most combinators of `CCHashtbl`
- many more functions in `CCList.Zipper`
- large update of `CCList.Zipper`
- add `CCHashtbl.update`
- improve `CCHashtbl.MakeCounter`
- add `CCList.fold_flat_map`
- add module `CCChar`
- add functions in `CCFormat`
- add `CCPrint.char`
- add `CCVector.to_seq_rev`
- doc and tests for `CCLevenshtein`
- expose blocking decoder in `CCSexpM`
- add `CCList.fold_map`
- add `CCError.guard_str_trace`
- add `CCError.of_exn_trace`
- add `CCKlist.memoize` for costly computations
- add `CCLevenshtein.Index.{of,to}_{gen,seq}` and `cardinal`
- small bugfix in `CCSexpM.print`
- fix broken link to changelog (fix #51)
- fix doc generation for `containers.string`
- bugfix in `CCString.find`
- raise exception in `CCString.replace` if `sub=""`
- bugfix in hashtable printing
- bugfix in `CCKList.take`, it was slightly too eager
== 0.13
=== Breaking changes
- big refactoring of `CCLinq` (now simpler and cleaner)
- changed the types `input` and `ParseError` in `CCParse`
- move `containers.misc` and `containers.lwt` into their own repo
- change the exceptions in `CCVector`
- change signature of `CCDeque.of_seq`
=== Other changes
- add module `CCWBTree`, a weight-balanced tree, in `containers.data`.
- add module `CCBloom` in `containers.data`, a bloom filter
- new module `CCHashTrie` in `containers.data`, HAMT-like associative map
- add module `CCBitField` in `containers.data`, a safe abstraction for bitfields of < 62 bits
- add module `CCHashSet` into `containers.data`, a mutable set
- add module `CCInt64`
- move module `RAL` into `containers.data` as `CCRAL`
- new module `CCThread` in `containers.thread`, utils for threading (+ blocking queue)
- new module `CCSemaphore` in `containers.thread`, with simple semaphore
- add `containers.top`, a small library that installs printers
- add `CCParse.memo` for memoization (changes `CCParse.input`)
- add `CCString.compare_versions`
- update `CCHash` with a functor and module type for generic hashing
- add `CCList.{take,drop}_while`; improve map performance
- add `CCList.cons_maybe`
- add `CCArray.bsearch` (back from batteries)
- add fair functions to `CCKList`
- deprecate `CCList.split`, introduce `CCList.take_drop` instead.
- add `CCKtree.force`
- add tests to `CCIntMap`; now flagged "stable" (for the API)
- add `CCOpt.choice_seq`
- add `CCOpt.print`
- add `CCIntMap.{equal,compare,{of,to,add}_{gen,klist}}`
- add `CCThread.Barrier` for simple synchronization
- add `CCPersistentArray.{append,flatten,flat_map,of_gen,to_gen}`
- add `CCDeque.clear`
- add `CCDeque.{fold,append_{front,back},{of,to}_{gen,list}}` and others
- add `CCKList.{zip, unzip}`
- add `CCKList.{of_array,to_array}`
- add `CCKList.{head,tail,mapi,iteri}`
- add `CCKList.{unfold,of_gen}`
- add `CCParse.{input_of_chan,parse_file,parse_file_exn}`
- modify `CCParse.U.list` to skip newlines
- add `CCDeque.print`
- add `CCBV.print`
- add printer to `CCHashtbl`
- bugfix in `CCSexpM`
- new tests in `CCTrie`; bugfix in `CCTrie.below`
- lots of new tests
- more benchmarks; cleanup of benchmarks
- migration of tests to 100% qtest
- migration markdown to asciidoc for doc (readme, etc.)
- add tests to `CCIntMap`, add type safety, and fix various bugs in `{union,inter}`
- more efficient `CCThread.Queue.{push,take}_list`
- slightly different implem for `CCThread.Queue.{take,push}`
- new implementation for `CCDeque`, more efficient
- update makefile (target devel)
== 0.12
=== breaking
- change type of `CCString.blit` so it writes into `Bytes.t`
- better default opening flags for `CCIO.with_{in, out}`
=== non-breaking
NOTE: use of `containers.io` is deprecated (its only module has moved to `containers`)
- add `CCString.mem`
- add `CCString.set` for updating immutable strings
- add `CCList.cons` function
- enable `-safe-string` on the project; fix `-safe-string` issues
- move `CCIO` from `containers.io` to `containers`, add dummy module in `containers.io`
- add `CCIO.read_all_bytes`, reading a whole file into a `Bytes.t`
- add `CCIO.with_in_out` to read and write a file
- add `CCArray1` in containers.bigarray, a module on 1-dim bigarrays (experimental)
- add module `CCGraph` in `containers.data`, a simple graph abstraction similar to `LazyGraph`
- add a lot of string functions in `CCString`
- add `CCError.catch`, in prevision of the future standard `Result.t` type
- add `CCError.Infix` module
- add `CCHashconsedSet` in `containers.data` (set with maximal struct sharing)
- fix: use the proper array module in `CCRingBuffer`
- bugfix: `CCRandom.float_range`
== 0.11
- add `CCList.{remove,is_empty}`
- add `CCOpt.is_none`
- remove packs for `containers_string` and `containers_advanced`
- add `Containers_string.Parse`, very simple monadic parser combinators
- add `CCList.{find_pred,find_pred_exn}`
- bugfix in `CCUnix.escape_str`
- add methods and accessors to `CCUnix`
- in `CCUnix`, use `Unix.environment` as the default environment
- add `CCList.partition_map`
- `RingBuffer.{of_array, to_array}` convenience functions
- `containers.misc.RAL`: more efficient in memory (unfold list)
- add `CCInt.pow` (thanks to bernardofpc)
- add `CCList.group_succ`
- `containers.data.CCMixset`, set of values indexed by poly keys
- disable warning 32 (unused val) in .merlin
- some infix operators for `CCUnix`
- add `CCUnix.async_call` for spawning and communicating with subprocess
- add `CCList.Set.{add,remove}`
- fix doc of `CCstring.Split.list_`
== 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
- add `Float`, `Ref`, `Set`, `Format` to `CCPervasives`
- `CCRingBuffer.append` (simple implementation)
- `containers.data` now depends on bytes
- new `CCRingBuffer` module, imperative deque with batch (blit) operations,
mostly done by Carmelo Piccione
- new `Lwt_pipe` and `Lwt_klist` streams for Lwt, respectively (un)bounded
synchronized queues and lazy lists
- `CCKTree.print`, a simple S-expressions printer for generic trees
- Add `CCMixmap` in containers.data (close #40), functional alternative to `CCMixtbl`
- remove old META file
- simplified `CCTrie` implementation
- use "compiledObject: best" in `_oasis` for binaries
- document some invariants in `CCCache` (see #38)
- tests for `CCCache.lru`
- fix `CCFormat.seq` combinator
- add `CCSet` module in core/
- add `CCRef` module in core/
== 0.8
- add `@Emm` to authors
- refactored heavily `CCFuture` (much simpler, cleaner, basic API and thread pool)
- add `CCLock` in containers.thread
- merged `test_levenshtein` with other tests
- Add experimental rose tree in `Containers_misc.RoseTree`.
- remove a lot of stuff from `containers.misc` (see `_oasis` for details)
- `make devel` command, activating most flags, for developpers (see #27)
- use benchmark 1.4, with the upstreamed tree system
- test `ccvector.iteri`
- add `CCFormat` into core/
- infix map operators for `CCArray`
- `fold_while` impl for `CCList` and `CCArray`
- Added `CCBigstring.length` for more consistency with the `CCString` module.
- Added name and dev fields in the OPAM file for local pinning.
- Fix `CCIO.remove*` functions.
- Added `CCIO.remove_safe`.
- only build doc if all the required flags are enabled
- `CCHashtbl.{keys,values}_list` in the functor as well. Better doc.
- `CCHashtbl.{keys,values}_list`
- more accurate type for `CCHashtbl.Make`
== 0.7
=== breaking
- remove `cgi`/
- removed useless Lwt-related module
- remove `CCGen` and `CCsequence` (use the separate libraries)
- split the library into smaller pieces (with `containers.io`, `containers.iter`,
`containers.sexp`, `containers.data`)
=== other changes
- cleanup: move sub-libraries to their own subdir each; mv everything into `src/`
- `sexp`:
* `CCSexp` now splitted into `CCSexp` (manipulating expressions) and `CCSexpStream`
* add `CCSexpM` for a simpler, monadic parser of S-expressions (deprecating `CCSexpStream`)
- `core`:
* `CCString.fold`
* `CCstring.suffix`
* more efficient `CCString.init`
* fix errors in documentation of `CCString` (slightly over-reaching sed)
* add `CCFloat.{fsign, sign_exn}` (thanks @bernardofpc)
- new `containers.bigarray`, with `CCBigstring`
- `CCHashtbl.map_list`
- `io`:
* `CCIO.read_all` now with ?size parameter
* use `Bytes.extend` (praise modernity!)
* bugfix in `CCIO.read_all` and `CCIO.read_chunks`
- use `-no-alias-deps`
== 0.6.1
- use subtree `gen/` for `CCGen` (symlink) rather than a copy.
- Add benchmarks for the function `iter` of iterators.
- `CCKTree`: more printers (to files), `Format` printer
- `CCOpt.get_lazy` convenience function
- introduce `CCFloat`, add float functions to `CCRandom` (thanks to @struktured)
== 0.6
=== breaking changes
- new `CCIO` module, much simpler, but incompatible interface
- renamed `CCIO` to `advanced.CCMonadIO`
=== other changes
- `CCMultiSet.{add_mult,remove_mult,update}`
- `CCVector.{top,top_exn}`
- `CCFun.compose_binop` (binary composition)
- `CCList.init`
- `CCError.map2` has a more general type (thanks to @hcarty)
- new module `CCCache`
* moved from `misc`
* add `CCache`.{size,iter}
* incompatible interface (functor -> values), much simpler to use
- `lwt/Lwt_actor` stub, for erlang-style concurrency (albeit much much more naive)
- `misc/Mixtbl` added from its old repository
- more benchmarks, with a more general system to select/run them
- more efficient versions of `CCList.{flatten,append,flat_map}`, some functions
are now tailrec
== 0.5
=== breaking changes
- dependency on `cppo` (thanks to @whitequark, see `AUTHORS.md`) and `bytes`
- `CCError`:
* now polymorphic on the error type
* some retro-incompatibilies (wrap,guard)
- `CCPervasives.Opt` -> `CCPervasives.Option`
- `Levenshtein.Index.remove` changed signature (useless param removed)
=== other changes
- stronger inlining for `CCVector` (so that e.g. push is inline)
- more tests for `CCVector`
- removed many warnings
- `CCSequence` now provides some bytes-dependent operations
- `CCList.(>|=)` map operator
- `CCOpt.filter`
- `CCInt.neg`
- `CCMap` wrapper to the standard `Map` module
- make some functions in `CCFun` and `CCString` depend on ocaml version
- thanks to @whitequark, could use cppo for preprocessing files
- add Format printers to `CCString`
- `AUTHORS.md`
== 0.4.1
- `CCOpt.get`
- new functions in `CCSexp.Traverse`
- comments in `CCMultiSet.mli`, to explain meet/intersection/union
- `CCMultiset`: Add meet
- update of readme
- generate doc for `containers.advanced`
== 0.4
- `core/CCSexp` for fast and lightweight S-expressions parsing/printing
- moved `CCLinq`, `CCBatch` and `CCat` from core/ to advanced/
- ensure compatibility with ocaml 4.00
- get rid of deprecated `Array.create`
- move benchmarks to benchs/ so they are separate from tests
- `CCError.{iter,get_exn}`
- `CCPair.print`
- some small improvements to `CCRandom`
- moved `CCHashtbl` to `CCFlatHashtbl`; new module `CCHashtbl` that
wraps and extends the standard hashtable
- `CCPervasives` module, replacing modules of the standard library
- removed type alias `CCString.t` (duplicate of String.t which already exists)
== 0.3.4
- subtree for `sequence` repo
- `CCSequence` is now a copy of `sequence`
- `CCOpt.wrap{1,2}`
- `CCList.findi`, `CCArray.findi` and `CCArray.find_idx`
- better `Format` printers (using break hints)
- specialize some comparison functions
- `CCOrd.map`
== 0.3.3
- readme: add ci hook (to http://ci.cedeela.fr)
- `CCIO`: monad for IO actions-as-values
- explicit finalizer system, to use a `>>>=` operator rather than callbacks
- `File` for basic filenames manipulations
- `Seq` for streams
- `CCMultiMap`: functor for bidirectional mappings
- `CCMultiSet`: sequence
- renamed threads/future to threads/CCFuture
- big upgrade of `RAL` (random access lists)
- `CCList.Ref` to help use references on lists
- `CCKList`: `group,uniq,sort,sort_uniq,repeat` and `cycle`, infix ops, applicative,product
- `CCTrie.above/below`: ranges of items
- more functions in `CCPair`
- `CCCat`: funny (though useless) definitions inspired from Haskell
- `CCList`: applicative instance
- `CCString.init`
- `CCError.fail_printf`
== 0.3.2
- small change in makefile
- conversions for `CCString`
- `CCHashtbl`: open-addressing table (Robin-Hood hashing)
- registered printers for `CCError`.guard,wrap1,etc.
- monadic operator in `CCList`: `map_m_par`
- simple interface to `PrintBox` now more powerful
- constructors for 1 or 2 elements fqueues
- bugfixes in BTree (insertion should work now)
- `CCFQueue`: logarithmic access by index
- add BTree partial implementation (not working yet)
- fix bug in `CCPrint.to_file`
- `CCArray.lookup` for divide-and-conquer search
- `CCList.sort_uniq`
- `CCError`: retry and choose combinators
- stub for monadic IO in `CCPrint`
- `CCopt.pure`
- 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)
- `CCArray.blit`, `.Sub.to_slice`; some bugfixes
- applicative and lifting operators for `CCError`
- `CCError.map2`
- more combinators in `CCError`
== 0.3.1
- test for `CCArray.shuffle`
- bugfix in `CCArray.shuffle`
- `CCOpt.get_exn`
- `CCOpt.sequence_l`
- mplus instance for `CCOpt`
- monad instance for `CCFun`
- updated description in `_oasis`
- `CCTrie`, a compressed functorial persistent trie structure
- fix `CCPrint.unit`, add `CCPrint.silent`
- fix type mismatch
NOTE: `git log --no-merges previous_version..HEAD --pretty=%s`

1324
CHANGELOG.md Normal file

File diff suppressed because it is too large Load diff

9
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,9 @@
# Code of Conduct
This project has adopted the [OCaml Code of Conduct](https://github.com/ocaml/code-of-conduct/blob/main/CODE_OF_CONDUCT.md).
# Enforcement
This project follows the OCaml Code of Conduct
[enforcement policy](https://github.com/ocaml/code-of-conduct/blob/main/CODE_OF_CONDUCT.md#enforcement).
To report any violations, please contact @c-cube

View file

@ -1,32 +0,0 @@
= HOWTO
== Make a release
Beforehand, check `grep deprecated -r src` to see whether some functions
can be removed.
. `make test`
. update version in `_oasis`
. `make update_next_tag` (to update `@since` comments; be careful not to change symlinks)
. check status of modules (`{b status: foo}`) and update if required;
removed deprecated functions, etc.
. update `CHANGELOG.md` (see its end to find the right git command)
. commit the changes
. `git checkout stable`
. `git merge master`
. `oasis setup; make test doc`
. update `opam` (the version field; remove `oasis` in deps)
. tag, and push both to github
. `opam pin add containers https://github.com/c-cube/ocaml-containers.git#<release>`
. new opam package: `opam publish prepare; opam publish submit`
. re-generate doc: `make doc push_doc`
== List Authors
`git log --format='%aN' | sort -u`
== Subtree
If gen is https://github.com/c-cube/gen.git[this remote]:
git subtree pull --prefix gen gen master --squash

149
Makefile
View file

@ -1,137 +1,44 @@
# OASIS_START
# DO NOT EDIT (digest: 9a60866e2fa295c5e33a3fe33b8f3a32)
PACKAGES=containers,containers-data
SETUP = ./setup.exe
all: build test
build: setup.data $(SETUP)
$(SETUP) -build $(BUILDFLAGS)
build:
dune build @install -p $(PACKAGES)
doc: setup.data $(SETUP) build
$(SETUP) -doc $(DOCFLAGS)
test: build
# run tests in release mode to expose bug in #454
dune runtest --display=quiet --cache=disabled --no-buffer --force --profile=release
test: setup.data $(SETUP) build
$(SETUP) -test $(TESTFLAGS)
clean:
dune clean
all: $(SETUP)
$(SETUP) -all $(ALLFLAGS)
doc:
dune build @doc
install: setup.data $(SETUP)
$(SETUP) -install $(INSTALLFLAGS)
examples:
dune build examples/id_sexp.exe
uninstall: setup.data $(SETUP)
$(SETUP) -uninstall $(UNINSTALLFLAGS)
format:
@dune build $(DUNE_OPTS) @fmt --auto-promote
reinstall: setup.data $(SETUP)
$(SETUP) -reinstall $(REINSTALLFLAGS)
format-check:
@dune build $(DUNE_OPTS) @fmt --display=quiet
clean: $(SETUP)
$(SETUP) -clean $(CLEANFLAGS)
distclean: $(SETUP)
$(SETUP) -distclean $(DISTCLEANFLAGS)
$(RM) $(SETUP)
setup.data: $(SETUP)
$(SETUP) -configure $(CONFIGUREFLAGS)
configure: $(SETUP)
$(SETUP) -configure $(CONFIGUREFLAGS)
setup.exe: setup.ml
ocamlfind ocamlopt -o $@ -linkpkg -package oasis.dynrun $< || ocamlfind ocamlc -o $@ -linkpkg -package oasis.dynrun $< || true
$(RM) setup.cmi setup.cmo setup.cmx setup.o
.PHONY: build doc test all install uninstall reinstall clean distclean configure
# OASIS_STOP
EXAMPLES = examples/mem_size.native examples/collatz.native \
examples/bencode_write.native # examples/crawl.native
OPTIONS = -use-ocamlfind -I _build
examples: all
ocamlbuild $(OPTIONS) -package unix -I . $(EXAMPLES)
push_doc: doc
rsync -tavu containers.docdir/* cedeela.fr:~/simon/root/software/containers/
DONTTEST=myocamlbuild.ml setup.ml $(wildcard src/**/*.cppo.*)
QTESTABLE=$(filter-out $(DONTTEST), \
$(wildcard src/core/*.ml) \
$(wildcard src/core/*.mli) \
$(wildcard src/data/*.ml) \
$(wildcard src/data/*.mli) \
$(wildcard src/string/*.ml) \
$(wildcard src/string/*.mli) \
$(wildcard src/io/*.ml) \
$(wildcard src/io/*.mli) \
$(wildcard src/unix/*.ml) \
$(wildcard src/unix/*.mli) \
$(wildcard src/sexp/*.ml) \
$(wildcard src/sexp/*.mli) \
$(wildcard src/advanced/*.ml) \
$(wildcard src/advanced/*.mli) \
$(wildcard src/iter/*.ml) \
$(wildcard src/iter/*.mli) \
$(wildcard src/bigarray/*.ml) \
$(wildcard src/bigarray/*.mli) \
$(wildcard src/threads/*.ml) \
$(wildcard src/threads/*.mli) \
)
qtest-clean:
@rm -rf qtest/
QTEST_PREAMBLE='open CCFun;; '
#qtest-build: qtest-clean build
# @mkdir -p qtest
# @qtest extract --preamble $(QTEST_PREAMBLE) \
# -o qtest/qtest_all.ml \
# $(QTESTABLE) 2> /dev/null
# @ocamlbuild $(OPTIONS) -pkg oUnit,QTest2Lib,ocamlbuildlib \
# -I core -I misc -I string \
# qtest/qtest_all.native
qtest-gen:
@mkdir -p qtest
@if which qtest > /dev/null ; then \
qtest extract --preamble $(QTEST_PREAMBLE) \
-o qtest/run_qtest.ml \
$(QTESTABLE) 2> /dev/null ; \
else touch qtest/run_qtest.ml ; \
fi
push-stable:
git checkout stable
git merge master -m 'merge from master'
oasis setup
git commit -a -m 'oasis files'
git push origin
git checkout master
clean-generated:
rm **/*.{mldylib,mlpack,mllib} myocamlbuild.ml -f
tags:
otags *.ml *.mli
VERSION=$(shell awk '/^Version:/ {print $$2}' _oasis)
VERSION=$(shell awk '/^version:/ {print $$2}' containers.opam)
update_next_tag:
@echo "update version to $(VERSION)..."
zsh -c 'sed -i "s/NEXT_VERSION/$(VERSION)/g" **/*.ml **/*.mli'
zsh -c 'sed -i "s/NEXT_RELEASE/$(VERSION)/g" **/*.ml **/*.mli'
devel:
./configure --enable-bench --enable-tests --enable-unix \
--enable-bigarray --enable-thread --enable-advanced
make all
sed -i "s/NEXT_VERSION/$(VERSION)/g" $(wildcard src/**/*.ml) $(wildcard src/**/*.mli)
sed -i "s/NEXT_RELEASE/$(VERSION)/g" $(wildcard src/**/*.ml) $(wildcard src/**/*.mli)
WATCH?=@src/check @tests/runtest
watch:
while find src/ benchs/ -print0 | xargs -0 inotifywait -e delete_self -e modify ; do \
echo "============ at `date` ==========" ; \
make all; \
done
@dune build $(WATCH) -w
.PHONY: examples push_doc tags qtest-gen qtest-clean devel update_next_tag
reindent:
@which ocp-indent || ( echo "require ocp-indent" ; exit 1 )
@find src '(' -name '*.ml' -or -name '*.mli' ')' -type f -print0 | xargs -0 echo "reindenting: "
@find src '(' -name '*.ml' -or -name '*.mli' ')' -type f -print0 | xargs -0 ocp-indent -i
.PHONY: all test clean build doc update_next_tag watch examples

View file

@ -1,276 +0,0 @@
= OCaml-containers =
:toc: macro
:source-highlighter: pygments
What is _containers_? (take a look at the link:TUTORIAL.adoc[tutorial]!
or the http://cedeela.fr/~simon/software/containers[documentation])
In `containers` and `containers.data`, all modules abide by
_pay for what you use_: only modules that are used are linked (there are no
cross-module dependencies).
- A usable, reasonably well-designed library that extends OCaml's standard
library (in 'src/core/', packaged under `containers` in ocamlfind. Modules
are totally independent and are prefixed with `CC` (for "containers-core"
or "companion-cube" because I'm megalomaniac). This part should be
usable and should work. For instance, `CCList` contains functions and
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:
containers.data:: with additional data structures that don't have an
equivalent in the standard library;
containers.io:: (deprecated)
containers.iter:: with list-like and tree-like iterators;
containers.string:: (in directory `string`) with
a few packed modules that deal with strings (Levenshtein distance,
KMP search algorithm, and a few naive utils). Again, modules are independent
and sometimes parametric on the string and char types (so they should
be able to deal with your favorite unicode library).
- A sub-library with complicated abstractions, `containers.advanced` (with
a LINQ-like query module, batch operations using GADTs, and others).
- Utilities around the `unix` library in `containers.unix` (mainly to spawn
sub-processes)
- A bigstring module using `bigarray` in `containers.bigarray` (*deprecated*)
- A lightweight S-expression printer and streaming parser in `containers.sexp`
Some of the modules have been moved to their own repository (e.g. `sequence`,
`gen`, `qcheck`) and are on opam for great fun and profit.
image:https://ci.cedeela.fr/buildStatus/icon?job=containers[alt="Build Status", link="http://ci.cedeela.fr/job/containers/"]
toc::[]
image::media/logo.png[logo]
== Change Log
See link:CHANGELOG.adoc[this file].
== Finding help
- *new*: http://lists.ocaml.org/listinfo/containers-users[Mailing List]
the address is mailto:containers-users@lists.ocaml.org[]
- the https://github.com/c-cube/ocaml-containers/wiki[github wiki]
- on IRC, ask `companion_cube` on `#ocaml@freenode.net`
- image:https://badges.gitter.im/Join%20Chat.svg[alt="Gitter", link="https://gitter.im/c-cube/ocaml-containers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"]
== Use
Start with the link:TUTORIAL.adoc[tutorial]
You can either build and install the library (see <<build>>), or just copy
files to your own project. The last solution has the benefits that you
don't have additional dependencies nor build complications (and it may enable
more inlining). Since modules have a friendly license and are mostly
independent, both options are easy.
In a toplevel, using ocamlfind:
[source,OCaml]
----
# #use "topfind";;
# #require "containers";;
# CCList.flat_map;;
- : ('a -> 'b list) -> 'a list -> 'b list = <fun>
# open Containers;; (* optional *)
# List.flat_map ;;
- : ('a -> 'b list) -> 'a list -> 'b list = <fun>
----
If you have comments, requests, or bugfixes, please share them! :-)
== License
This code is free, under the BSD license.
The logo (`media/logo.png`) is
CC-SA3 http://en.wikipedia.org/wiki/File:Hypercube.svg[wikimedia].
== Contents
The library contains a <<core,Core part>> that mostly extends the stdlib
and adds a few very common structures (heap, vector), and sub-libraries
that deal with either more specific things, or require additional dependencies.
Some structural types are used throughout the library:
gen:: `'a gen = unit -> 'a option` is an iterator type. Many combinators
are defined in the opam library https://github.com/c-cube/gen[gen]
sequence:: `'a sequence = (unit -> 'a) -> unit` is also an iterator type.
It is easier to define on data structures than `gen`, but it a bit less
powerful. The opam library https://github.com/c-cube/sequence[sequence]
can be used to consume and produce values of this type.
error:: `'a or_error = [`Error of string | `Ok of 'a]` is a error type
that is used in other libraries, too. The reference module in containers
is `CCError`.
klist:: `'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]` is a lazy list
without memoization, used as a persistent iterator. The reference
module is `CCKList` (in `containers.iter`).
printer:: `'a printer = Format.formatter -> 'a -> unit` is a pretty-printer
to be used with the standard module `Format`. In particular, in many cases,
`"foo: %a" Foo.print foo` will type-check.
[[core]]
=== Core Modules (extension of the standard library)
the core library, `containers`, now depends on
https://github.com/mjambon/cppo[cppo] and `base-bytes` (provided
by ocamlfind).
Documentation http://cedeela.fr/~simon/software/containers[here].
- `CCHeap`, a purely functional heap structure
- `CCVector`, a growable array (pure OCaml, no C) with mutability annotations
- `CCList`, functions on lists, including tail-recursive implementations of `map` and `append` and many other things
- `CCArray`, utilities on arrays and slices
- `CCHashtbl`, `CCMap` extensions of the standard modules `Hashtbl` and `Map`
- `CCInt`
- `CCString` (basic string operations)
- `CCPair` (cartesian products)
- `CCOpt` (options, very useful)
- `CCFun` (function combinators)
- `CCBool`
- `CCFloat`
- `CCOrd` (combinators for total orderings)
- `CCRandom` (combinators for random generators)
- `CCPrint` (printing combinators)
- `CCHash` (hashing combinators)
- `CCError` (monadic error handling, very useful)
- `CCIO`, basic utilities for IO (channels, files)
- `CCInt64,` utils for `int64`
- `CCChar`, utils for `char`
- `CCFormat`, pretty-printing utils around `Format`
=== Containers.data
- `CCBitField`, bitfields embedded in integers
- `CCBloom`, a bloom filter
- `CCCache`, memoization caches, LRU, etc.
- `CCFlatHashtbl`, a flat (open-addressing) hashtable functorial implementation
- `CCTrie`, a prefix tree
- `CCHashTrie`, a map where keys are hashed and put in a trie by hash
- `CCMultimap` and `CCMultiset`, functors defining persistent structures
- `CCFQueue`, a purely functional double-ended queue structure
- `CCBV`, mutable bitvectors
- `CCHashSet`, mutable set
- `CCPersistentHashtbl` and `CCPersistentArray`, a semi-persistent array and hashtable
(similar to https://www.lri.fr/~filliatr/ftp/ocaml/ds/parray.ml.html[persistent arrays])
- `CCMixmap`, `CCMixtbl`, `CCMixset`, containers of universal types (heterogenous containers)
- `CCRingBuffer`, a double-ended queue on top of an array-like structure,
with batch operations
- `CCIntMap`, map specialized for integer keys based on Patricia Trees,
with fast merges
- `CCHashconsedSet`, a set structure with sharing of sub-structures
- `CCGraph`, a small collection of graph algorithms
- `CCBitField`, a type-safe implementation of bitfields that fit in `int`
- `CCWBTree`, a weight-balanced tree, implementing a map interface
- `CCRAL`, a random-access list structure, with `O(1)` cons/hd/tl and `O(ln(n))`
access to elements by their index.
- `CCImmutArray`, immutable interface to arrays
=== Containers.io
*deprecated*, `CCIO` is now a <<core,core>> module. You can still install it and
depend on it but it contains no useful module.
=== Containers.unix
- `CCUnix`, utils for `Unix`
=== Containers.sexp
A small S-expression library.
- `CCSexp`, a small S-expression library
=== Containers.iter
Iterators:
- `CCKList`, a persistent iterator structure (akin to a lazy list, without memoization)
- `CCKTree`, an abstract lazy tree structure
=== String
See http://cedeela.fr/~simon/software/containers/Containers_string[doc].
In the module `Containers_string`:
- `Levenshtein`: edition distance between two strings
- `KMP`: Knuth-Morris-Pratt substring algorithm
- `Parse`: simple parser combinators
=== Advanced
See http://cedeela.fr/~simon/software/containers/Containers_advanced[doc].
In the module `Containers_advanced`:
- `CCLinq`, high-level query language over collections
- `CCCat`, a few categorical structures
- `CCBatch`, to combine operations on collections into one traversal
=== Thread
In the library `containers.thread`, for preemptive system threads:
- `CCFuture`, a set of tools for preemptive threading, including a thread pool,
monadic futures, and MVars (concurrent boxes)
- `CCLock`, values protected by locks
- `CCSemaphore`, a simple implementation of semaphores
- `CCThread` basic wrappers for `Thread`
=== Misc
The library has moved to https://github.com/c-cube/containers-misc .
=== Others
`containers.lwt` has moved to https://github.com/c-cube/containers-lwt .
[[build]]
== Build
You will need OCaml `>=` 4.00.0.
=== Via opam
The prefered way to install is through http://opam.ocaml.org/[opam].
$ opam install containers
=== From Sources
On the branch `master` you will need `oasis` to build the library. On the
branch `stable` it is not necessary.
$ make
To build and run tests (requires `oUnit` and https://github.com/vincent-hugot/iTeML[qtest]):
$ opam install oUnit qtest
$ ./configure --enable-tests --enable-unix --enable-bigarray
$ make test
To build the small benchmarking suite (requires https://github.com/chris00/ocaml-benchmark[benchmark]):
$ opam install benchmark
$ make bench
$ ./benchs.native
== Contributing
PRs on github are welcome (patches by email too, if you prefer so).
A few guidelines:
- no dependencies between basic modules (even just for signatures);
- add `@since` tags for new functions;
- add tests if possible (using `qtest`).
Powered by image:http://oasis.forge.ocamlcore.org/oasis-badge.png[alt="OASIS", style="border: none;", link="http://oasis.forge.ocamlcore.org/"]
== Documentation by version
- http://c-cube.github.io/ocaml-containers/0.17/[0.17]

699
README.md Normal file
View file

@ -0,0 +1,699 @@
# OCaml-containers 📦 [![Build and test](https://github.com/c-cube/ocaml-containers/actions/workflows/main.yml/badge.svg)](https://github.com/c-cube/ocaml-containers/actions/workflows/main.yml)
A modular, clean and powerful extension of the OCaml standard library.
[(Jump to the current API documentation)](https://c-cube.github.io/ocaml-containers/)
Containers is an extension of OCaml's standard library (under BSD license)
focused on data structures, combinators and iterators, without dependencies on
unix, str or num. Every module is independent and is prefixed with 'CC' in the
global namespace. Some modules extend the stdlib (e.g. `CCList` provides safe
`map`/`fold_right`/`append`, and additional functions on lists).
Alternatively, `open Containers` will bring enhanced versions of the standard
modules into scope.
## Quick Summary
Containers is:
- A usable, reasonably well-designed library that extends OCaml's standard
library (in 'src/core/', packaged under `containers` in ocamlfind. Modules
are totally independent and are prefixed with `CC` (for "containers-core"
or "companion-cube" because I'm a megalomaniac). This part should be
usable and should work. For instance, `CCList` contains functions and
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), and a small S-expression printer and parser
that can be functorized over the representation of values.
- Some sub-libraries with a specific focus each:
* Utilities around the `unix` library in `containers.unix` (mainly to spawn
sub-processes easily and deal with resources safely)
* A bencode codec in `containers.bencode`. This is a tiny json-like
serialization format that is extremely simple. It comes from bittorrent files.
* A [CBOR](https://cbor.io) codec in `containers.cbor`. This is a
compact binary serialization format.
* The [Strongly Connected Component](https://en.wikipedia.org/wiki/Strongly_connected_component)
algorithm, functorized, in `containers.scc`
- A separate library `containers-data` with additional
data structures that don't have an equivalent in the standard library,
typically not as thoroughly maintained. This is now in its own package
since 3.0.
Some of the modules have been moved to their own repository (e.g. `sequence` (now `iter`),
`gen`, `qcheck`) and are on opam for great fun and profit.
Containers-thread has been removed in favor of [Moonpool](https://github.com/c-cube/moonpool/).
## Migration Guide
### To 3.0
The [changelog's breaking section](CHANGELOG.md) contains a list of the breaking
changes in this release.
1. The biggest change is that some sub-libraries have been either turned into
their own packages (`containers-data`),
deleted (`containers.iter`),or merged elsewhere (`containers.sexp`).
This means that if use these libraries you will have to edit your
`dune`/`_oasis`/`opam` files.
- if you use `containers.sexp` (i.e. the `CCSexp` module), it now lives in
`containers` itself.
- if you used anything in `containers.data`, you need to depend on the
`containers-data` package now.
2. Another large change is the removal (at last!) of functions deprecated
in 2.8, related to the spread of `Seq.t` as the standard iterator type.
Functions like `CCVector.of_seq` now operate on this standard `Seq.t` type,
and old-time iteration based on [iter](https://github.com/c-cube/iter)
is now named `of_iter`, `to_iter`, etc.
Here you need to change your code, possibly using search and replace.
Thankfully, the typechecker should guide you.
3. `Array_slice` and `String.Sub` have been removed to simplify the
code and `String` more lightweight. There is no replacement at the moment.
Please tell us if you need this to be turned into a sub-library.
4. Renaming of some functions into more explicit/clear names.
Examples:
* `CCVector.shrink` is now `CCVector.truncate`
* `CCVector.remove` is now `CCVector.remove_unordered`, to be
contrasted with the new `CCVector.remove_and_shift`.
* `CCPair.map_fst` and `map_snd` now transform a tuple into another tuple
by modify the first (resp. second) element.
5. All the collection pretty-printers now take their separator/start/stop
optional arguments as `unit printer` (i.e. `Format.formatter -> unit -> unit`
functions) rather than strings. This gives the caller better control
over the formatting of lists, arrays, queues, tables, etc.
6. Removal of many deprecated functions.
### To 2.0
- The type system should detect issues related to `print` renamed into `pp` easily.
If you are lucky, a call to `sed -i 's/print/pp/g'` on the concerned files
might help rename all the calls
properly.
- many optional arguments have become mandatory, because their default value
would be a polymorphic "magic" operator such as `(=)` or `(>=)`.
Now these have to be specified explicitly, but during the transition
you can use `Stdlib.(=)` and `Stdlib.(>=)` as explicit arguments.
- if your code contains `open Containers`, the biggest hurdle you face
might be that operators have become monomorphic by default.
We believe this is a useful change that prevents many subtle bugs.
However, during migration and until you use proper combinators for
equality (`CCEqual`), comparison (`CCOrd`), and hashing (`CCHash`),
you might want to add `open Stdlib` just after the `open Containers`.
See [the section on monomorphic operators](#monomorphic-operators-why-and-how) for more details.
## Monomorphic operators: why, and how?
### Why shadow polymorphic operators by default?
To quote @bluddy in [#196](https://github.com/c-cube/ocaml-containers/issues/196):
The main problem with polymorphic comparison is that many data structures will
give one result for structural comparison, and a different result for semantic
comparison. The classic example is comparing maps. If you have a list of maps
and try to use comparison to sort them, you'll get the wrong result: multiple
map structures can represent the same semantic mapping from key to value, and
comparing them in terms of structure is simply wrong. A far more pernicious bug
occurs with hashtables. Identical hashtables will seem to be identical for a
while, as before they've had a key clash, the outer array is likely to be the
same. Once you get a key clash though, you start getting lists inside the
arrays (or maps inside the arrays if you try to make a smarter hashtable) and
that will cause comparison errors ie. identical hashtables will be seen as
different or vice versa.
Every time you use a polymorphic comparison where you're using a data type
where structural comparison != semantic comparison, it's a bug. And every time
you use polymorphic comparison where the type of data being compared may vary
(e.g. it's an int now, but it may be a map later), you're planting a bug for
the future.
See also:
- https://blog.janestreet.com/the-perils-of-polymorphic-compare/
- https://blog.janestreet.com/building-a-better-compare/
### Sometimes polymorphic operators still make sense!
If you just want to use polymorphic operators, it's fine! You can access them
easily by using `Stdlib.(=)`, `Stdlib.max`, etc.
When migrating a module, you can add `open Stdlib` on top of it to restore
the default behavior. It is, however, recommended to export an `equal` function
(and `compare`, and `hash`) for all the public types, even if their internal
definition is just the corresponding polymorphic operator.
This way, other modules can refer to `Foo.equal` and will not have to be
updated the day `Foo.equal` is no longer just polymorphic equality.
Another bonus is that `Hashtbl.Make(Foo)` or `Map.Make(Foo)` will just work™.
### Further discussions
See issues
[#196](https://github.com/c-cube/ocaml-containers/issues/196),
[#197](https://github.com/c-cube/ocaml-containers/issues/197)
## Debugging with `ocamldebug`
To print values with types defined in `containers` in the bytecode debugger,
you first have to load the appropriate bytecode archives. After starting a
session, e.g. `ocamldebug your_program.bc`,
```ocaml non-deterministic=command
# #load_printer containers_monomorphic.cma;;
# #load_printer containers.cma;;
```
For these archives to be found, you may have to `run` the program first. Now
printing functions that have the appropriate type `Format.formatter -> 'a ->
unit` can be installed. For example,
```ocaml non-deterministic=command
# #install_printer Containers.Int.pp;;
```
However, printer combinators are not easily handled by `ocamldebug`. For
instance `# install_printer Containers.(List.pp Int.pp)` will *not* work out of
the box. You can make this work by writing a short module which defines
ready-made combined printing functions, and loading that in ocamldebug. For
instance
```ocaml non-deterministic=command
module M = struct
let pp_int_list = Containers.(List.pp Int.pp)
end;;
```
loaded via `# load_printer m.cmo` and installed as `# install_printer
M.pp_int_list`.
## Change Log
See [this file](./CHANGELOG.md).
## Finding help
- [Mailing List](http://lists.ocaml.org/listinfo/containers-users)
the address is <mailto:containers-users@lists.ocaml.org>
- the [github wiki](https://github.com/c-cube/ocaml-containers/wiki)
- on IRC, ask `companion_cube` on `#ocaml@irc.libera.chat`
- there is a `#containers` channel on OCaml's discord server.
## Use
You might start with the [tutorial](#tutorial) to get a picture of how to use the library.
You can either build and install the library (see [build](#build)), or just copy
files to your own project. The last solution has the benefits that you
don't have additional dependencies nor build complications (and it may enable
more inlining). Since modules have a friendly license and are mostly
independent, both options are easy.
In a toplevel, using ocamlfind:
```ocaml
# #use "topfind";;
...
# #require "containers";;
# #require "containers-data";;
# CCList.flat_map;;
- : ('a -> 'b list) -> 'a list -> 'b list = <fun>
# open Containers (* optional *);;
# List.flat_map ;;
- : ('a -> 'b list) -> 'a list -> 'b list = <fun>
```
If you have comments, requests, or bugfixes, please share them! :-)
## License
This code is free, under the BSD license.
## Contents
See [the documentation](http://c-cube.github.io/ocaml-containers/)
and [the tutorial below](#tutorial) for a gentle introduction.
## Documentation
In general, see http://c-cube.github.io/ocaml-containers/last/ for the **API documentation**.
Some examples can be found [there](doc/containers.md),
per-version doc [there](http://c-cube.github.io/ocaml-containers/).
## Build
You will need OCaml `>=` 4.03.0.
### Via opam
The preferred way to install is through [opam](http://opam.ocaml.org/).
```
$ opam install containers
```
### From Sources
<details>
You need dune (formerly jbuilder).
```
$ make
```
To build and run tests (requires `qcheck-core`, `gen`, `iter`):
```
$ opam install qcheck-core
$ make test
```
To build the small benchmarking suite (requires [benchmark](https://github.com/chris00/ocaml-benchmark)):
```
$ opam install benchmark batteries
$ make bench
$ ./benchs/run_benchs.sh
```
</details>
## Contributing
PRs on github are very welcome (patches by email too, if you prefer so).
<details>
<summary>how to contribute (click to unfold)</summary>
### List of authors
The list of contributors can be seen [on github](https://github.com/c-cube/ocaml-containers/graphs/contributors).
Alternatively, `git authors` from git-extras can be invoked from within the repo
to list authors based on the git commits.
### First-Time Contributors
Assuming your are in a clone of the repository:
1. Some dependencies are required, you'll need
`opam install benchmark qcheck-core iter gen mdx uutf yojson`.
2. run `make all` to enable everything (including tests).
3. make your changes, commit, push, and open a PR.
4. use `make test` without moderation! It must pass before a PR
is merged. There are around 1150 tests right now, and new
features should come with their own tests.
If you feel like writing new tests, that is totally worth a PR
(and my gratefulness).
### General Guidelines
A few guidelines to follow the philosophy of containers:
- no dependencies between basic modules (even just for signatures);
- add `@since` tags for new functions;
- add tests if possible (see `tests/` dir)
There are numerous inline tests already,
to see what it looks like search for comments starting with `(*$`
in source files.
### For Total Beginners
Thanks for wanting to contribute!
To contribute a change, here are the steps (roughly):
1. click "fork" on https://github.com/c-cube/ocaml-containers on the top right of the page. This will create a copy of the repository on your own github account.
2. click the big green "clone or download" button, with "SSH". Copy the URL (which should look like `git@github.com:<your username>/ocaml-containers.git`) into a terminal to enter the command:
```
$ git clone git@github.com:<your username>/ocaml-containers.git
```
3. then, `cd` into the newly created directory.
4. make the changes you want. See <#first-time-contributors> for
more details about what to do in particular.
5. use `git add` and `git commit` to commit these changes.
6. `git push origin master` to push the new change(s) onto your
copy of the repository
7. on github, open a "pull request" (PR). Et voilà !
</details>
## Tutorial
This tutorial contains a few examples to illustrate the features and
usage of containers.
<details>
<summary>an introduction to containers (click to unfold)</summary>
We assume containers is installed and that
the library is loaded, e.g. with:
```ocaml
# #require "containers";;
# Format.set_margin 50 (* for readability here *);;
- : unit = ()
```
### Basics
We will start with a few list helpers, then look at other parts of
the library, including printers, maps, etc.
```ocaml
# (|>) (* quick reminder of this awesome standard operator *);;
- : 'a -> ('a -> 'b) -> 'b = <fun>
# 10 |> succ;;
- : int = 11
# open CCList.Infix;;
# let l = 1 -- 100;;
val l : int list =
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;
22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39;
40; 41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57;
58; 59; 60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; 74; 75;
76; 77; 78; 79; 80; 81; 82; 83; 84; 85; 86; 87; 88; 89; 90; 91; 92; 93;
94; 95; 96; 97; 98; 99; 100]
# (* transform a list, dropping some elements *)
l
|> CCList.filter_map
(fun x-> if x mod 3=0 then Some (float x) else None)
|> CCList.take 5 ;;
- : float list = [3.; 6.; 9.; 12.; 15.]
# let l2 = l |> CCList.take_while (fun x -> x<10) ;;
val l2 : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
```
```ocaml
(* an extension of Map.Make, compatible with Map.Make(CCInt) *)
module IntMap = CCMap.Make(CCInt);;
```
```ocaml
# (* conversions using the "iter" type, fast iterators that are
pervasively used in containers. Combinators can be found
in the opam library "iter". *)
let map : string IntMap.t =
l2
|> List.map (fun x -> x, string_of_int x)
|> CCList.to_iter
|> IntMap.of_iter;;
val map : string IntMap.t = <abstr>
# CCList.to_iter (* check the type *);;
- : 'a list -> 'a CCList.iter = <fun>
# IntMap.of_iter ;;
- : (int * 'a) CCMap.iter -> 'a IntMap.t = <fun>
# (* we can print, too *)
Format.printf "@[<2>map =@ @[<hov>%a@]@]@."
(IntMap.pp CCFormat.int CCFormat.string_quoted)
map;;
map =
1 -> "1", 2 -> "2", 3 -> "3", 4 -> "4", 5
-> "5", 6 -> "6", 7 -> "7", 8 -> "8", 9 -> "9"
- : unit = ()
# (* options are good *)
IntMap.get 3 map |> CCOption.map (fun s->s ^ s);;
- : string option = Some "33"
```
### New types: `CCVector`, `CCHeap`, `CCResult`, `CCSexp`, `CCByte_buffer`
Containers also contains (!) a few datatypes that are not from the standard
library but that are useful in a lot of situations:
- `CCVector`:
A resizable array, with a mutability parameter. A value of type
`('a, CCVector.ro) CCVector.t` is an immutable vector of values of type `'a`,
whereas a `('a, CCVector.rw) CCVector.t` is a mutable vector that
can be modified. This way, vectors can be used in a quite functional
way, using operations such as `map` or `flat_map`, or in a more
imperative way.
- `CCHeap`:
A priority queue (currently, leftist heaps) functorized over
a module `sig val t val leq : t -> t -> bool` that provides a type `t`
and a partial order `leq` on `t`.
- `CCResult`
An error type for making error handling more explicit (an error monad,
really, if you're not afraid of the "M"-word).
Subsumes and replaces the old `CCError`.
It uses the new `result` type from the standard library (or from
the retrocompatibility package on opam) and provides
many combinators for dealing with `result`.
- `CCSexp` and `CCCanonical_sexp`:
functorized printer and parser for S-expressions, respectively as
actual S-expressions (like `sexplib`) and as canonical binary-safe
S-expressions (like `csexp`)
- `CCByte_buffer`: a better version of the standard `Buffer.t` which cannot be
extended and prevents access to its internal byte array. This type is
designed for (blocking) IOs and to produce complex strings incrementally
in an efficient way.
Now for a few examples:
```ocaml
# (* create a new empty vector. It is mutable, for otherwise it would
not be very useful. *)
CCVector.create;;
- : unit -> ('a, CCVector.rw) CCVector.t = <fun>
# (* init, similar to Array.init, can be used to produce a
vector that is mutable OR immutable (see the 'mut parameter?) *)
CCVector.init ;;
- : int -> (int -> 'a) -> ('a, 'mut) CCVector.t = <fun>
```
```ocaml non-deterministic=output
# (* use the infix (--) operator for creating a range. Notice
that v is a vector of integer but its mutability is not
decided yet. *)
let v = CCVector.(1 -- 10);;
val v : (int, '_a) CCVector.t = <abstr>
```
```ocaml
# Format.printf "v = @[%a@]@." (CCVector.pp CCInt.pp) v;;
v = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
- : unit = ()
# CCVector.push v 42;;
- : unit = ()
# v (* now v is a mutable vector *);;
- : (int, CCVector.rw) CCVector.t = <abstr>
# (* functional combinators! *)
let v2 : _ CCVector.ro_vector = v
|> CCVector.map (fun x-> x+1)
|> CCVector.filter (fun x-> x mod 2=0)
|> CCVector.rev ;;
val v2 : int CCVector.ro_vector = <abstr>
# Format.printf "v2 = @[%a@]@." (CCVector.pp CCInt.pp) v2;;
v2 = 10, 8, 6, 4, 2
- : unit = ()
```
```ocaml
(* let's transfer to a heap *)
module IntHeap = CCHeap.Make(struct type t = int let leq = (<=) end);;
```
```ocaml
# let h = v2 |> CCVector.to_iter |> IntHeap.of_iter ;;
val h : IntHeap.t = <abstr>
# (* We can print the content of h
(printing is not necessarily in order, though) *)
Format.printf "h = [@[%a@]]@." (IntHeap.pp CCInt.pp) h;;
h = [2,4,6,8,10]
- : unit = ()
# (* we can remove the first element, which also returns a new heap
that does not contain it — CCHeap is a functional data structure *)
IntHeap.take h;;
- : (IntHeap.t * int) option = Some (<abstr>, 2)
# let h', x = IntHeap.take_exn h ;;
val h' : IntHeap.t = <abstr>
val x : int = 2
# IntHeap.to_list h' (* see, 2 is removed *);;
- : int list = [4; 8; 10; 6]
```
### IO helpers
The core library contains a module called `CCIO` that provides useful
functions for reading and writing files. It provides functions that
make resource handling easy, following
the pattern `with_resource : resource -> (access -> 'a) -> 'a` where
the type `access` is a temporary handle to the resource (e.g.,
imagine `resource` is a file name and `access` a file descriptor).
Calling `with_resource r f` will access `r`, give the result to `f`,
compute the result of `f` and, whether `f` succeeds or raises an
error, it will free the resource.
Consider for instance:
```ocaml
# CCIO.with_out "./foobar"
(fun out_channel ->
CCIO.write_lines_l out_channel ["hello"; "world"]);;
- : unit = ()
```
This just opened the file 'foobar', creating it if it didn't exist,
and wrote two lines in it. We did not have to close the file descriptor
because `with_out` took care of it. By the way, the type signatures are:
```ocaml non-deterministic=command
val with_out :
?mode:int -> ?flags:open_flag list ->
string -> (out_channel -> 'a) -> 'a
val write_lines_l : out_channel -> string list -> unit
```
So we see the pattern for `with_out` (which opens a function in write
mode and gives its functional argument the corresponding file descriptor).
NOTE: you should never let the resource escape the
scope of the `with_resource` call, because it will not be valid outside.
OCaml's type system doesn't make it easy to forbid that so we rely
on convention here (it would be possible, but cumbersome, using
a record with an explicitly quantified function type).
Now we can read the file again:
```ocaml
# let lines : string list = CCIO.with_in "./foobar" CCIO.read_lines_l ;;
val lines : string list = ["hello"; "world"]
```
There are some other functions in `CCIO` that return _generators_
instead of lists. The type of generators in containers
is `type 'a gen = unit -> 'a option` (combinators can be
found in the opam library called "gen"). A generator is to be called
to obtain successive values, until it returns `None` (which means it
has been exhausted). In particular, python users might recognize
the function
```ocaml non-deterministic=command
# CCIO.File.walk ;;
- : string -> walk_item gen = <fun>;;
```
where `type walk_item = [ ``Dir | ``File ] * string` is a path
paired with a flag distinguishing files from directories.
### To go further: `containers-data`
There is also a library called `containers-data`, with lots of
more specialized data-structures.
The documentation contains the API for all the modules; they also provide
interface to `iter` and, as the rest of containers, minimize
dependencies over other modules. To use `containers-data` you need to link it,
either in your build system or by `#require containers-data;;`
A quick example based on purely functional double-ended queues:
```ocaml
# #require "containers-data";;
# #install_printer CCFQueue.pp (* better printing of queues! *);;
# let q = CCFQueue.of_list [2;3;4] ;;
val q : int CCFQueue.t = queue {2; 3; 4}
# let q2 = q |> CCFQueue.cons 1 |> CCFQueue.cons 0 ;;
val q2 : int CCFQueue.t = queue {0; 1; 2; 3; 4}
# (* remove first element *)
CCFQueue.take_front q2;;
- : (int * int CCFQueue.t) option = Some (0, queue {1; 2; 3; 4})
# (* q was not changed *)
CCFQueue.take_front q;;
- : (int * int CCFQueue.t) option = Some (2, queue {3; 4})
# (* take works on both ends of the queue *)
CCFQueue.take_back_l 2 q2;;
- : int CCFQueue.t * int list = (queue {0; 1; 2}, [3; 4])
```
### Common Type Definitions
Some structural types are used throughout the library:
- `gen`: `'a gen = unit -> 'a option` is an iterator type. Many combinators
are defined in the opam library [gen](https://github.com/c-cube/gen)
- `iter`: `'a iter = (unit -> 'a) -> unit` is also an iterator type, formerly
named `sequence`.
It is easier to define on data structures than `gen`, but it a bit less
powerful. The opam library [iter](https://github.com/c-cube/iter)
can be used to consume and produce values of this type.
It was renamed
from `'a sequence` to `'a iter` to distinguish it better from `Core.Sequence`
and the standard `seq`.
- `error`: `'a or_error = ('a, string) result = Error of string | Ok of 'a`
using the standard `result` type, supported in `CCResult`.
- `printer`: `'a printer = Format.formatter -> 'a -> unit` is a pretty-printer
to be used with the standard module `Format`. In particular, in many cases,
`"foo: %a" Foo.print foo` will type-check.
### Extended Documentation
See [the extended documentation](doc/containers.md) for more examples.
</details>
## HOWTO (for contributors)
<details>
### Make a release
Beforehand, check `grep deprecated -r src` to see whether some functions
can be removed.
- `make all`
- update version in `containers.opam`
- `make update_next_tag` (to update `@since` comments; be careful not to change symlinks)
- check status of modules (`{b status: foo}`) and update if required;
removed deprecated functions, etc.
- update `CHANGELOG.md` (see its end to find the right git command)
- commit the changes
- `make test doc`
- `export VERSION=<tag here>; git tag -f $VERSION; git push origin :$VERSION; git push origin $VERSION`
- new opam package: `opam publish https://github.com/c-cube/ocaml-containers/archive/<tag>.tar.gz`
- re-generate doc: `make doc` and put it into `gh-pages`
### List Authors
```
git log --format='%aN' | sort -u
```
</details>

View file

@ -1,275 +0,0 @@
= Tutorial
:source-highlighter: pygments
This tutorial contains a few examples to illustrate the features and
usage of containers. We assume containers is installed and that
the library is loaded, e.g. with:
[source,OCaml]
----
#require "containers";;
----
== Basics
We will start with a few list helpers, then look at other parts of
the library, including printers, maps, etc.
[source,OCaml]
----
(* quick reminder of this awesome standard operator *)
# (|>) ;;
- : 'a -> ('a -> 'b) -> 'b = <fun>
# open CCList.Infix;;
# let l = 1 -- 100;;
val l : int list = [1; 2; .....]
# l
|> CCList.filter_map
(fun x-> if x mod 3=0 then Some (float x) else None)
|> CCList.take 5 ;;
- : float list = [3.; 6.; 9.; 12.; 15.]
# let l2 = l |> CCList.take_while (fun x -> x<10) ;;
val l2 : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
(* an extension of Map.Make, compatible with Map.Make(CCInt) *)
# module IntMap = CCMap.Make(CCInt);;
(* conversions using the "sequence" type, fast iterators that are
pervasively used in containers. Combinators can be found
in the opam library "sequence". *)
# let map =
l2
|> List.map (fun x -> x, string_of_int x)
|> CCList.to_seq
|> IntMap.of_seq;;
val map : string CCIntMap.t = <abstr>
(* check the type *)
# CCList.to_seq ;;
- : 'a list -> 'a sequence = <fun>
# IntMap.of_seq ;;
- : (int * 'a) CCMap.sequence -> 'a IntMap.t = <fun>
(* we can print, too *)
# Format.printf "@[<2>map =@ @[<hov>%a@]@]@."
(IntMap.print CCFormat.int CCFormat.string_quoted)
map;;
map =
[1 --> "1", 2 --> "2", 3 --> "3", 4 --> "4", 5 --> "5", 6 --> "6",
7 --> "7", 8 --> "8", 9 --> "9"]
- : unit = ()
(* options are good *)
# IntMap.get 3 map |> CCOpt.map (fun s->s ^ s);;
- : string option = Some "33"
----
== New types: `CCVector`, `CCHeap`, `CCError`, `CCResult`
Containers also contains (!) a few datatypes that are not from the standard
library but that are useful in a lot of situations:
CCVector::
A resizable array, with a mutability parameter. A value of type
`('a, CCVector.ro) CCVector.t` is an immutable vector of values of type `'a`,
whereas a `('a, CCVector.rw) CCVector.t` is a mutable vector that
can be modified. This way, vectors can be used in a quite functional
way, using operations such as `map` or `flat_map`, or in a more
imperative way.
CCHeap::
A priority queue (currently, leftist heaps) functorized over
a module `sig val t val leq : t -> t -> bool` that provides a type `t`
and a partial order `leq` on `t`.
CCError::
An error type for making error handling more explicit (an error monad,
really, if you're not afraid of the "M"-word). It is similar to the
more recent `CCResult`, but works with polymorphic variants for
compatibility with the numerous libraries that use the same type,
that is, `type ('a, 'b) CCError.t = [`Ok of 'a | `Error of 'b]`.
CCResult::
It uses the new `result` type from the standard library (or from
the retrocompatibility package on opam), and presents an interface
similar to `CCError`. In an indeterminate amount of time, it will
totally replace `CCError`.
Now for a few examples:
[source,OCaml]
----
(* create a new empty vector. It is mutable, for otherwise it would
not be very useful. *)
# CCVector.create;;
- : unit -> ('a, CCVector.rw) CCVector.t = <fun>
(* init, similar to Array.init, can be used to produce a
vector that is mutable OR immutable (see the 'mut parameter?) *)
# CCVector.init ;;
- : int -> (int -> 'a) -> ('a, 'mut) CCVector.t = <fun>c
(* use the infix (--) operator for creating a range. Notice
that v is a vector of integer but its mutability is not
decided yet. *)
# let v = CCVector.(1 -- 10);;
val v : (int, '_a) CCVector.t = <abstr>
# Format.printf "v = @[%a@]@." (CCVector.print CCInt.print) v;;
v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
(* now let's mutate v *)
# CCVector.push v 42;;
- : unit = ()
(* now v is a mutable vector *)
# v;;
- : (int, CCVector.rw) CCVector.t = <abstr>
(* functional combinators! *)
# let v2 = v
|> CCVector.map (fun x-> x+1)
|> CCVector.filter (fun x-> x mod 2=0)
|> CCVector.rev ;;
val v2 : (int, '_a) CCVector.t = <abstr>
# Format.printf "v2 = @[%a@]@." (CCVector.print CCInt.print) v2;;
v2 = [10, 8, 6, 4, 2]
(* let's transfer to a heap *)
# module IntHeap = CCHeap.Make(struct type t = int let leq = (<=) end);;
# let h = v2 |> CCVector.to_seq |> IntHeap.of_seq ;;
val h : IntHeap.t = <abstr>
(* We can print the content of h
(printing is not necessarily in order, though) *)
# Format.printf "h = [@[%a@]]@." (IntHeap.print CCInt.print) h;;
h = [2,4,6,8,10]
(* we can remove the first element, which also returns a new heap
that does not contain it — CCHeap is a functional data structure *)
# IntHeap.take h;;
- : (IntHeap.t * int) option = Some (<abstr>, 2)
# let h', x = IntHeap.take_exn h ;;
val h' : IntHeap.t = <abstr>
val x : int = 2
(* see, 2 is removed *)
# IntHeap.to_list h' ;;
- : int list = [4; 6; 8; 10]
----
== IO helpers
The core library contains a module called `CCIO` that provides useful
functions for reading and writing files. It provides functions that
make resource handling easy, following
the pattern `with_resource : resource -> (access -> 'a) -> 'a` where
the type `access` is a temporary handle to the resource (e.g.,
imagine `resource` is a file name and `access` a file descriptor).
Calling `with_resource r f` will access `r`, give the result to `f`,
compute the result of `f` and, whether `f` succeeds or raises an
error, it will free the resource.
Consider for instance:
[source,OCaml]
----
# CCIO.with_out "/tmp/foobar"
(fun out_channel ->
CCIO.write_lines_l out_channel ["hello"; "world"]);;
- : unit = ()
----
This just opened the file '/tmp/foobar', creating it if it didn't exist,
and wrote two lines in it. We did not have to close the file descriptor
because `with_out` took care of it. By the way, the type signatures are:
[source,OCaml]
----
val with_out :
?mode:int -> ?flags:open_flag list ->
string -> (out_channel -> 'a) -> 'a
val write_lines_l : out_channel -> string list -> unit
----
So we see the pattern for `with_out` (which opens a function in write
mode and gives its functional argument the corresponding file descriptor).
NOTE: you should never let the resource escape the
scope of the `with_resource` call, because it will not be valid outside.
OCaml's type system doesn't make it easy to forbid that so we rely
on convention here (it would be possible, but cumbersome, using
a record with an explicitely quantified function type).
Now we can read the file again:
[source,OCaml]
----
# let lines = CCIO.with_in "/tmp/foobar" CCIO.read_lines_l ;;
val lines : string list = ["hello"; "world"]
----
There are some other functions in `CCIO` that return _generators_
instead of lists. The type of generators in containers
is `type 'a gen = unit -> 'a option` (combinators can be
found in the opam library called "gen"). A generator is to be called
to obtain successive values, until it returns `None` (which means it
has been exhausted). In particular, python users might recognize
the function
[source,OCaml]
----
# CCIO.File.walk ;;
- : string -> walk_item gen = <fun>;;
----
where `type walk_item = [ `Dir | `File ] * string` is a path
paired with a flag distinguishing files from directories.
== To go further: containers.data
There is also a sub-library called `containers.data`, with lots of
more specialized data-structures.
The documentation contains the API for all the modules
(see link:README.adoc[the readme]); they also provide
interface to `sequence` and, as the rest of containers, minimize
dependencies over other modules. To use `containers.data` you need to link it,
either in your build system or by `#require containers.data;;`
A quick example based on purely functional double-ended queues:
[source,OCaml]
----
# #require "containers.data";;
# #install_printer CCFQueue.print;; (* better printing of queues! *)
# let q = CCFQueue.of_list [2;3;4] ;;
val q : int CCFQueue.t = queue {2; 3; 4}
# let q2 = q |> CCFQueue.cons 1 |> CCFQueue.cons 0 ;;
val q2 : int CCFQueue.t = queue {0; 1; 2; 3; 4}
(* remove first element *)
# CCFQueue.take_front q2;;
- : (int * int CCFQueue.t) option = Some (0, queue {1; 2; 3; 4})
(* q was not changed *)
# CCFQueue.take_front q;;
- : (int * int CCFQueue.t) option = Some (2, queue {3; 4})
(* take works on both ends of the queue *)
# CCFQueue.take_back_l 2 q2;;
- : int CCFQueue.t * int list = (queue {0; 1; 2}, [3; 4])
----

207
_oasis
View file

@ -1,207 +0,0 @@
OASISFormat: 0.4
Name: containers
Version: 0.19
Homepage: https://github.com/c-cube/ocaml-containers
Authors: Simon Cruanes
License: BSD-2-clause
LicenseFile: LICENSE
Plugins: META (0.3), DevFiles (0.3)
OCamlVersion: >= 4.00.1
BuildTools: ocamlbuild
AlphaFeatures: compiled_setup_ml, ocamlbuild_more_args
XOCamlbuildExtraArgs: "-j 0"
Synopsis: A modular standard library focused on data structures.
Description:
Containers is a standard library (BSD license) focused on data structures,
combinators and iterators, without dependencies on unix. Every module is
independent and is prefixed with 'CC' in the global namespace. Some modules
extend the stdlib (e.g. CCList provides safe map/fold_right/append, and
additional functions on lists).
It also features optional libraries for dealing with strings, and
helpers for unix and threads.
Flag "unix"
Description: Build the containers.unix library (depends on Unix)
Default: false
Flag "thread"
Description: Build modules that depend on threads
Default: true
Flag "bench"
Description: Build and run benchmarks
Default: true
Flag "bigarray"
Description: Build modules that depend on bigarrays
Default: true
Flag "advanced"
Description: Build advanced combinators (requires "sequence")
Default: true
Library "containers"
Path: src/core
Modules: CCVector, CCPrint, CCError, CCHeap, CCList, CCOpt, CCPair,
CCFun, CCHash, CCInt, CCBool, CCFloat, CCArray, CCRef, CCSet,
CCOrd, CCRandom, CCString, CCHashtbl, CCMap, CCFormat, CCIO,
CCInt64, CCChar, CCResult, Containers
BuildDepends: bytes, result
# BuildDepends: bytes, bisect_ppx
Library "containers_io"
Path: src/io
Modules: Containers_io_is_deprecated
BuildDepends: bytes
FindlibParent: containers
FindlibName: io
Library "containers_unix"
Path: src/unix
Modules: CCUnix
BuildDepends: bytes, unix
FindlibParent: containers
FindlibName: unix
Library "containers_sexp"
Path: src/sexp
Modules: CCSexp, CCSexpM
BuildDepends: bytes
FindlibParent: containers
FindlibName: sexp
Library "containers_data"
Path: src/data
Modules: CCMultiMap, CCMultiSet, CCTrie, CCFlatHashtbl, CCCache,
CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl,
CCMixmap, CCRingBuffer, CCIntMap, CCPersistentArray,
CCMixset, CCHashconsedSet, CCGraph, CCHashSet, CCBitField,
CCHashTrie, CCBloom, CCWBTree, CCRAL, CCAllocCache,
CCImmutArray, CCHet
BuildDepends: bytes
# BuildDepends: bytes, bisect_ppx
FindlibParent: containers
FindlibName: data
Library "containers_iter"
Path: src/iter
Modules: CCKTree, CCKList, CCLazy_list
FindlibParent: containers
FindlibName: iter
Library "containers_string"
Path: src/string
Modules: Containers_string, CCKMP, CCLevenshtein, CCApp_parse, CCParse
BuildDepends: bytes
FindlibName: string
FindlibParent: containers
Library "containers_advanced"
Path: src/advanced
Modules: Containers_advanced, CCLinq, CCBatch, CCCat, CCMonadIO
Build$: flag(advanced)
Install$: flag(advanced)
FindlibName: advanced
FindlibParent: containers
BuildDepends: containers, sequence
Library "containers_bigarray"
Path: src/bigarray
Modules: CCBigstring, CCArray1
FindlibName: bigarray
FindlibParent: containers
BuildDepends: containers, bigarray, bytes
Library "containers_thread"
Path: src/threads/
Modules: CCPool, CCLock, CCSemaphore, CCThread, CCBlockingQueue,
CCTimer
FindlibName: thread
FindlibParent: containers
Build$: flag(thread)
Install$: flag(thread)
BuildDepends: containers, threads
XMETARequires: containers, threads
Library "containers_top"
Path: src/top/
Modules: Containers_top
FindlibName: top
FindlibParent: containers
BuildDepends: compiler-libs.common, containers, containers.data,
containers.bigarray, containers.string,
containers.unix, containers.sexp, containers.iter
Document containers
Title: Containers docs
Type: ocamlbuild (0.3)
BuildTools+: ocamldoc
Build$: flag(docs) && flag(advanced) && flag(bigarray) && flag(unix)
Install: true
XOCamlbuildPath: .
XOCamlbuildExtraArgs:
"-docflags '-colorize-code -short-functors -charset utf-8'"
XOCamlbuildLibraries:
containers, containers.iter, containers.data,
containers.string, containers.bigarray, containers.thread,
containers.advanced, containers.io, containers.unix, containers.sexp
Executable run_benchs
Path: benchs/
Install: false
CompiledObject: best
Build$: flag(bench)
MainIs: run_benchs.ml
BuildDepends: containers, containers.advanced, qcheck,
containers.data, containers.string, containers.iter,
containers.thread, sequence, gen, benchmark, hamt
Executable run_bench_hash
Path: benchs/
Install: false
CompiledObject: best
Build$: flag(bench)
MainIs: run_bench_hash.ml
BuildDepends: containers
PreBuildCommand: make qtest-gen
Executable run_qtest
Path: qtest/
Install: false
CompiledObject: best
MainIs: run_qtest.ml
Build$: flag(tests) && flag(bigarray) && flag(unix) && flag(advanced)
BuildDepends: containers, containers.string, containers.iter,
containers.io, containers.advanced, containers.sexp,
containers.bigarray, containers.unix, containers.thread,
containers.data,
sequence, gen, unix, oUnit, qcheck
Test all
Command: ./run_qtest.native
TestTools: run_qtest
Run$: flag(tests) && flag(unix) && flag(advanced) && flag(bigarray)
Executable mem_measure
Path: benchs/
Install: false
CompiledObject: native
MainIs: mem_measure.ml
Build$: flag(bench)
BuildDepends: sequence, unix, containers, containers.data, hamt
Executable id_sexp
Path: examples/
Install: false
CompiledObject: best
MainIs: id_sexp.ml
BuildDepends: containers.sexp
SourceRepository head
Type: git
Location: https://github.com/c-cube/ocaml-containers
Browser: https://github.com/c-cube/ocaml-containers/tree/master/src

161
_tags
View file

@ -1,161 +0,0 @@
# OASIS_START
# DO NOT EDIT (digest: 1681c391580688c2463b8457d464cf03)
# Ignore VCS directories, you can use the same kind of rule outside
# OASIS_START/STOP if you want to exclude directories that contains
# useless stuff for the build process
true: annot, bin_annot
<**/.svn>: -traverse
<**/.svn>: not_hygienic
".bzr": -traverse
".bzr": not_hygienic
".hg": -traverse
".hg": not_hygienic
".git": -traverse
".git": not_hygienic
"_darcs": -traverse
"_darcs": not_hygienic
# Library containers
"src/core/containers.cmxs": use_containers
<src/core/*.ml{,i,y}>: package(bytes)
<src/core/*.ml{,i,y}>: package(result)
# Library containers_io
"src/io/containers_io.cmxs": use_containers_io
<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
"src/sexp/containers_sexp.cmxs": use_containers_sexp
<src/sexp/*.ml{,i,y}>: package(bytes)
# Library containers_data
"src/data/containers_data.cmxs": use_containers_data
<src/data/*.ml{,i,y}>: package(bytes)
# Library containers_iter
"src/iter/containers_iter.cmxs": use_containers_iter
# Library containers_string
"src/string/containers_string.cmxs": use_containers_string
<src/string/*.ml{,i,y}>: package(bytes)
# Library containers_advanced
"src/advanced/containers_advanced.cmxs": use_containers_advanced
<src/advanced/*.ml{,i,y}>: package(bytes)
<src/advanced/*.ml{,i,y}>: package(result)
<src/advanced/*.ml{,i,y}>: package(sequence)
<src/advanced/*.ml{,i,y}>: use_containers
# Library containers_bigarray
"src/bigarray/containers_bigarray.cmxs": use_containers_bigarray
<src/bigarray/*.ml{,i,y}>: package(bigarray)
<src/bigarray/*.ml{,i,y}>: package(bytes)
<src/bigarray/*.ml{,i,y}>: package(result)
<src/bigarray/*.ml{,i,y}>: use_containers
# Library containers_thread
"src/threads/containers_thread.cmxs": use_containers_thread
<src/threads/*.ml{,i,y}>: package(bytes)
<src/threads/*.ml{,i,y}>: package(result)
<src/threads/*.ml{,i,y}>: package(threads)
<src/threads/*.ml{,i,y}>: use_containers
# Library containers_top
"src/top/containers_top.cmxs": use_containers_top
<src/top/*.ml{,i,y}>: package(bigarray)
<src/top/*.ml{,i,y}>: package(bytes)
<src/top/*.ml{,i,y}>: package(compiler-libs.common)
<src/top/*.ml{,i,y}>: package(result)
<src/top/*.ml{,i,y}>: package(unix)
<src/top/*.ml{,i,y}>: use_containers
<src/top/*.ml{,i,y}>: use_containers_bigarray
<src/top/*.ml{,i,y}>: use_containers_data
<src/top/*.ml{,i,y}>: use_containers_iter
<src/top/*.ml{,i,y}>: use_containers_sexp
<src/top/*.ml{,i,y}>: use_containers_string
<src/top/*.ml{,i,y}>: use_containers_unix
# Executable run_benchs
<benchs/run_benchs.{native,byte}>: package(benchmark)
<benchs/run_benchs.{native,byte}>: package(bytes)
<benchs/run_benchs.{native,byte}>: package(gen)
<benchs/run_benchs.{native,byte}>: package(hamt)
<benchs/run_benchs.{native,byte}>: package(result)
<benchs/run_benchs.{native,byte}>: package(sequence)
<benchs/run_benchs.{native,byte}>: package(threads)
<benchs/run_benchs.{native,byte}>: use_containers
<benchs/run_benchs.{native,byte}>: use_containers_advanced
<benchs/run_benchs.{native,byte}>: use_containers_data
<benchs/run_benchs.{native,byte}>: use_containers_iter
<benchs/run_benchs.{native,byte}>: use_containers_string
<benchs/run_benchs.{native,byte}>: use_containers_thread
<benchs/*.ml{,i,y}>: package(benchmark)
<benchs/*.ml{,i,y}>: package(gen)
<benchs/*.ml{,i,y}>: package(threads)
<benchs/*.ml{,i,y}>: use_containers_advanced
<benchs/*.ml{,i,y}>: use_containers_iter
<benchs/*.ml{,i,y}>: use_containers_string
<benchs/*.ml{,i,y}>: use_containers_thread
# Executable run_bench_hash
<benchs/run_bench_hash.{native,byte}>: package(bytes)
<benchs/run_bench_hash.{native,byte}>: package(result)
<benchs/run_bench_hash.{native,byte}>: use_containers
# Executable run_qtest
<qtest/run_qtest.{native,byte}>: package(QTest2Lib)
<qtest/run_qtest.{native,byte}>: package(bigarray)
<qtest/run_qtest.{native,byte}>: package(bytes)
<qtest/run_qtest.{native,byte}>: package(gen)
<qtest/run_qtest.{native,byte}>: package(oUnit)
<qtest/run_qtest.{native,byte}>: package(result)
<qtest/run_qtest.{native,byte}>: package(sequence)
<qtest/run_qtest.{native,byte}>: package(threads)
<qtest/run_qtest.{native,byte}>: package(unix)
<qtest/run_qtest.{native,byte}>: use_containers
<qtest/run_qtest.{native,byte}>: use_containers_advanced
<qtest/run_qtest.{native,byte}>: use_containers_bigarray
<qtest/run_qtest.{native,byte}>: use_containers_data
<qtest/run_qtest.{native,byte}>: use_containers_io
<qtest/run_qtest.{native,byte}>: use_containers_iter
<qtest/run_qtest.{native,byte}>: use_containers_sexp
<qtest/run_qtest.{native,byte}>: use_containers_string
<qtest/run_qtest.{native,byte}>: use_containers_thread
<qtest/run_qtest.{native,byte}>: use_containers_unix
<qtest/*.ml{,i,y}>: package(QTest2Lib)
<qtest/*.ml{,i,y}>: package(bigarray)
<qtest/*.ml{,i,y}>: package(bytes)
<qtest/*.ml{,i,y}>: package(gen)
<qtest/*.ml{,i,y}>: package(oUnit)
<qtest/*.ml{,i,y}>: package(result)
<qtest/*.ml{,i,y}>: package(sequence)
<qtest/*.ml{,i,y}>: package(threads)
<qtest/*.ml{,i,y}>: package(unix)
<qtest/*.ml{,i,y}>: use_containers
<qtest/*.ml{,i,y}>: use_containers_advanced
<qtest/*.ml{,i,y}>: use_containers_bigarray
<qtest/*.ml{,i,y}>: use_containers_data
<qtest/*.ml{,i,y}>: use_containers_io
<qtest/*.ml{,i,y}>: use_containers_iter
<qtest/*.ml{,i,y}>: use_containers_sexp
<qtest/*.ml{,i,y}>: use_containers_string
<qtest/*.ml{,i,y}>: use_containers_thread
<qtest/*.ml{,i,y}>: use_containers_unix
# Executable mem_measure
"benchs/mem_measure.native": package(bytes)
"benchs/mem_measure.native": package(hamt)
"benchs/mem_measure.native": package(result)
"benchs/mem_measure.native": package(sequence)
"benchs/mem_measure.native": package(unix)
"benchs/mem_measure.native": use_containers
"benchs/mem_measure.native": use_containers_data
<benchs/*.ml{,i,y}>: package(bytes)
<benchs/*.ml{,i,y}>: package(hamt)
<benchs/*.ml{,i,y}>: package(result)
<benchs/*.ml{,i,y}>: package(sequence)
<benchs/*.ml{,i,y}>: package(unix)
<benchs/*.ml{,i,y}>: use_containers
<benchs/*.ml{,i,y}>: use_containers_data
# Executable id_sexp
<examples/id_sexp.{native,byte}>: package(bytes)
<examples/id_sexp.{native,byte}>: use_containers_sexp
<examples/*.ml{,i,y}>: package(bytes)
<examples/*.ml{,i,y}>: use_containers_sexp
# OASIS_STOP
<tests/*.ml{,i}>: thread
<src/threads/*.ml{,i}>: thread
<src/core/CCVector.cmx> or <src/core/CCString.cmx>: inline(25)
<src/data/CCFlatHashtbl.cm*> or <src/data/CCHashTrie.cm*> or <src/data/CCPersistent*>: inline(15)
<src/**/*.ml> and not <src/misc/*.ml>: warn_A, warn(-4), warn(-44)
true: no_alias_deps, safe_string, short_paths

24
benchs/dune Normal file
View file

@ -0,0 +1,24 @@
(executables
(names run_benchs run_bench_hash run_objsize)
(libraries
containers
containers_pvec
containers-data
benchmark
gen
iter
qcheck
oseq
batteries
base
sek)
(flags :standard -warn-error -3-5 -w -60 -safe-string -color always)
(optional)
(ocamlopt_flags
:standard
-O3
-color
always
-unbox-closures
-unbox-closures-factor
20))

View file

@ -1,119 +0,0 @@
(* goal: measure memory consumption *)
(* number of words allocated *)
let mem_allocated () =
let gc = Gc.stat () in
gc.Gc.minor_words +. gc.Gc.major_words -. gc.Gc.promoted_words
(* overhead in memory *)
let mem_occupied x = Objsize.size_kb (Obj.repr x)
type stats = {
time: float;
occ: int;
alloc: float;
}
let measure_time_mem f =
let mem_alloc1 = mem_allocated () in
let start = Unix.gettimeofday() in
let x = f () in
let stop = Unix.gettimeofday() in
Gc.compact ();
let mem_alloc2 = mem_allocated () in
let mem_occupied = mem_occupied x in
ignore x;
{ occ=mem_occupied;
alloc=mem_alloc2-.mem_alloc1;
time=stop -. start;
}
let spf = Printf.sprintf
let do_test ~name f =
Format.printf "test %s...@." name;
let res = measure_time_mem f in
Format.printf " allocated:%.2f MB, occupied:%d kB, time: %.2f s@."
(res.alloc *. 8. /. 1_000_000.)
res.occ
res.time
let test_hashtrie n =
let module M = CCHashTrie.Make(CCInt) in
do_test ~name:(spf "hashtrie(%d)" n)
(fun () ->
let m = M.of_seq Sequence.(1 -- n |> map (fun x-> x,x)) in
m
)
let test_hamt n =
let module M = Hamt.Make'(CCInt) in
do_test ~name:(spf "hamt(%d)" n)
(fun () ->
let m = Sequence.(1 -- n
|> map (fun x-> x,x)
|> fold (fun m (k,v) -> M.add k v m) M.empty
) in
m
)
let test_map n =
let module M = CCMap.Make(CCInt) in
do_test ~name:(spf "map(%d)" n)
(fun () ->
let m = M.of_seq Sequence.(1 -- n |> map (fun x-> x,x)) in
m
)
let test_wbt n =
let module M = CCWBTree.Make(CCInt) in
do_test ~name:(spf "wbt(%d)" n)
(fun () ->
let m = M.of_seq Sequence.(1 -- n |> map (fun x-> x,x)) in
m
)
let test_hashtbl n =
let module H = CCHashtbl.Make(CCInt) in
do_test ~name:(spf "hashtbl(%d)" n)
(fun () ->
let m = H.of_seq Sequence.(1 -- n |> map (fun x-> x,x)) in
m
)
let test_intmap n =
let module M = CCIntMap in
do_test ~name:(spf "intmap(%d)" n)
(fun () ->
let m = M.of_seq Sequence.(1 -- n |> map (fun x-> x,x)) in
m
)
let tests_ =
[ "hashtrie", test_hashtrie
; "map", test_map
; "hamt", test_hamt
; "wbt", test_wbt
; "hashtbl", test_hashtbl
; "intmap", test_intmap
]
let run_test ~n name = List.assoc name tests_ n
let print_list () =
Format.printf "@[<v2>tests:@ %a@]@."
(CCList.print CCString.print) (List.map fst tests_)
let () =
let to_test = ref [] in
let n = ref 1_000_000 in
let options = Arg.align
[ "-n", Arg.Set_int n, " size of the collection"
] in
Arg.parse options (CCList.Ref.push to_test) "usage: mem_measure [name*]";
match !to_test with
| [] ->
print_list ();
exit 0
| _ -> List.iter (run_test ~n:!n) (List.rev !to_test)

View file

@ -22,50 +22,52 @@ open Obj
(*s Pointers already visited are stored in a hash-table, where
comparisons are done using physical equality. *)
module H = Hashtbl.Make(
struct
type t = Obj.t
let equal = (==)
let hash o = Hashtbl.hash (magic o : int)
end)
module H = Hashtbl.Make (struct
type t = Obj.t
let equal = ( == )
let hash o = Hashtbl.hash (magic o : int)
end)
let node_table = (H.create 257 : unit H.t)
let in_table o = try H.find node_table o; true with Not_found -> false
let in_table o =
try
H.find node_table o;
true
with Not_found -> false
let add_in_table o = H.add node_table o ()
let reset_table () = H.clear node_table
(*s Objects are traversed recursively, as soon as their tags are less than
[no_scan_tag]. [count] records the numbers of words already visited. *)
let size_of_double = size (repr 1.0)
let count = ref 0
let rec traverse t =
if not (in_table t) then begin
if not (in_table t) then (
add_in_table t;
if is_block t then begin
if is_block t then (
let n = size t in
let tag = tag t in
if tag < no_scan_tag then begin
count := !count + 1 + n;
for i = 0 to n - 1 do
let f = field t i in
if is_block f then traverse f
done
end else if tag = string_tag then
count := !count + 1 + n
if tag < no_scan_tag then (
count := !count + 1 + n;
for i = 0 to n - 1 do
let f = field t i in
if is_block f then traverse f
done
) else if tag = string_tag then
count := !count + 1 + n
else if tag = double_tag then
count := !count + size_of_double
count := !count + size_of_double
else if tag = double_array_tag then
count := !count + 1 + size_of_double * n
count := !count + 1 + (size_of_double * n)
else
incr count
end
end
incr count
)
)
(*s Sizes of objects in words and in bytes. The size in bytes is computed
system-independently according to [Sys.word_size]. *)
@ -76,8 +78,5 @@ let size_w o =
traverse (repr o);
!count
let size_b o = (size_w o) * (Sys.word_size / 8)
let size_kb o = (size_w o) / (8192 / Sys.word_size)
let size_b o = size_w o * (Sys.word_size / 8)
let size_kb o = size_w o / (8192 / Sys.word_size)

View file

@ -1,58 +1,55 @@
(* reference implementations for some structures, for comparison purpose *)
module PersistentHashtbl(H : Hashtbl.HashedType) = struct
module Table = Hashtbl.Make(H)
(** Imperative hashtable *)
module PersistentHashtbl (H : Hashtbl.HashedType) = struct
module Table = Hashtbl.Make (H)
(** Imperative hashtable *)
type key = H.t
type 'a t = 'a zipper ref
and 'a zipper =
| Table of 'a Table.t (** Concrete table *)
| Add of key * 'a * 'a t (** Add key *)
| Table of 'a Table.t (** Concrete table *)
| Add of key * 'a * 'a t (** Add key *)
| Replace of key * 'a * 'a t (** Replace key by value *)
| Remove of key * 'a t (** As the table, but without given key *)
let create i =
ref (Table (Table.create i))
| Remove of key * 'a t (** As the table, but without given key *)
let create i = ref (Table (Table.create i))
let empty () = create 11
(* pass continuation to get a tailrec rerooting *)
let rec _reroot t k = match !t with
| Table tbl -> k tbl (* done *)
| Add (key, v, t') ->
_reroot t'
(fun tbl ->
t' := Remove (key, t);
Table.add tbl key v;
t := Table tbl;
k tbl)
| Replace (key, v, t') ->
_reroot t'
(fun tbl ->
let v' = Table.find tbl key in
t' := Replace (key, v', t);
t := Table tbl;
Table.replace tbl key v;
k tbl)
| Remove (key, t') ->
_reroot t'
(fun tbl ->
let v = Table.find tbl key in
t' := Add (key, v, t);
t := Table tbl;
Table.remove tbl key;
k tbl)
let rec _reroot t k =
match !t with
| Table tbl -> k tbl (* done *)
| Add (key, v, t') ->
_reroot t' (fun tbl ->
t' := Remove (key, t);
Table.add tbl key v;
t := Table tbl;
k tbl)
| Replace (key, v, t') ->
_reroot t' (fun tbl ->
let v' = Table.find tbl key in
t' := Replace (key, v', t);
t := Table tbl;
Table.replace tbl key v;
k tbl)
| Remove (key, t') ->
_reroot t' (fun tbl ->
let v = Table.find tbl key in
t' := Add (key, v, t);
t := Table tbl;
Table.remove tbl key;
k tbl)
(* Reroot: modify the zipper so that the current node is a proper
hashtable, and return the hashtable *)
let reroot t = match !t with
let reroot t =
match !t with
| Table tbl -> tbl
| _ -> _reroot t (fun x -> x)
let is_empty t = Table.length (reroot t) = 0
let find t k = Table.find (reroot t) k
(*$R
@ -91,13 +88,8 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
*)
let get_exn k t = find t k
let get k t =
try Some (find t k)
with Not_found -> None
let get k t = try Some (find t k) with Not_found -> None
let mem t k = Table.mem (reroot t) k
let length t = Table.length (reroot t)
(*$R
@ -120,11 +112,9 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let t' = ref (Table tbl) in
(* update [t] to point to the new hashtable *)
(try
let v' = Table.find tbl k in
t := Replace (k, v', t')
with Not_found ->
t := Remove (k, t')
);
let v' = Table.find tbl k in
t := Replace (k, v', t')
with Not_found -> t := Remove (k, t'));
(* modify the underlying hashtable *)
Table.replace tbl k v;
t'
@ -170,12 +160,12 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let h = H.of_list l in
let h = List.fold_left (fun h (k,_) -> H.remove h k) h l in
H.is_empty h)
*)
*)
let update t k f =
let v = get k t in
match v, f v with
| None, None -> t (* no change *)
| None, None -> t (* no change *)
| Some _, None -> remove t k
| _, Some v' -> replace t k v'
@ -209,10 +199,11 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let tbl = reroot t in
let res = Table.create (Table.length tbl) in
Table.iter
(fun k v -> match f k v with
(fun k v ->
match f k v with
| None -> ()
| Some v' -> Table.replace res k v'
) tbl;
| Some v' -> Table.replace res k v')
tbl;
ref (Table res)
exception ExitPTbl
@ -231,17 +222,17 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let merge f t1 t2 =
let tbl = Table.create (max (length t1) (length t2)) in
iter t1
(fun k v1 ->
iter t1 (fun k v1 ->
let v2 = try Some (find t2 k) with Not_found -> None in
match f k (Some v1) v2 with
| None -> ()
| Some v' -> Table.replace tbl k v');
iter t2
(fun k v2 ->
if not (mem t1 k) then match f k None (Some v2) with
iter t2 (fun k v2 ->
if not (mem t1 k) then (
match f k None (Some v2) with
| None -> ()
| Some _ -> Table.replace tbl k v2);
| Some _ -> Table.replace tbl k v2
));
ref (Table tbl)
(*$R
@ -262,13 +253,11 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let add_seq init seq =
let tbl = ref init in
seq (fun (k,v) -> tbl := replace !tbl k v);
seq (fun (k, v) -> tbl := replace !tbl k v);
!tbl
let of_seq seq = add_seq (empty ()) seq
let add_list init l =
add_seq init (fun k -> List.iter k l)
let add_list init l = add_seq init (fun k -> List.iter k l)
(*$QR
_list_int_int (fun l ->
@ -293,7 +282,7 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let to_list t =
let tbl = reroot t in
let bindings = Table.fold (fun k v acc -> (k,v)::acc) tbl [] in
let bindings = Table.fold (fun k v acc -> (k, v) :: acc) tbl [] in
bindings
(*$R
@ -302,10 +291,9 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
OUnit.assert_equal my_list (List.sort compare l)
*)
let to_seq t =
fun k ->
let tbl = reroot t in
Table.iter (fun x y -> k (x,y)) tbl
let to_seq t k =
let tbl = reroot t in
Table.iter (fun x y -> k (x, y)) tbl
(*$R
let h = H.of_seq my_seq in
@ -316,31 +304,34 @@ module PersistentHashtbl(H : Hashtbl.HashedType) = struct
let equal eq t1 t2 =
length t1 = length t2
&&
for_all
(fun k v -> match get k t2 with
| None -> false
| Some v' -> eq v v'
) t1
&& for_all
(fun k v ->
match get k t2 with
| None -> false
| Some v' -> eq v v')
t1
let pp pp_k pp_v buf t =
Buffer.add_string buf "{";
let first = ref true in
iter t
(fun k v ->
if !first then first:=false else Buffer.add_string buf ", ";
Printf.bprintf buf "%a -> %a" pp_k k pp_v v
);
iter t (fun k v ->
if !first then
first := false
else
Buffer.add_string buf ", ";
Printf.bprintf buf "%a -> %a" pp_k k pp_v v);
Buffer.add_string buf "}"
let print pp_k pp_v fmt t =
Format.pp_print_string fmt "{";
let first = ref true in
iter t
(fun k v ->
if !first then first:=false
else (Format.pp_print_string fmt ", "; Format.pp_print_cut fmt ());
Format.fprintf fmt "%a -> %a" pp_k k pp_v v
);
iter t (fun k v ->
if !first then
first := false
else (
Format.pp_print_string fmt ", ";
Format.pp_print_cut fmt ()
);
Format.fprintf fmt "%a -> %a" pp_k k pp_v v);
Format.pp_print_string fmt "}"
end

View file

@ -4,61 +4,53 @@ type tree =
| Empty
| Node of int * tree list
let mk_node i l = Node (i,l)
let mk_node i l = Node (i, l)
let random_tree =
CCRandom.(fix
~base:(return Empty)
~subn:[int 10, (fun sublist -> pure mk_node <*> small_int <*> sublist)]
(int_range 15 150)
)
let random_list =
CCRandom.(
int 5 >>= fun len ->
CCList.random_len len random_tree
)
fix ~base:(return Empty)
~subn:[ (int 10, fun sublist -> pure mk_node <*> small_int <*> sublist) ]
(int_range 15 150))
let rec eq t1 t2 = match t1, t2 with
let rec eq t1 t2 =
match t1, t2 with
| Empty, Empty -> true
| Node(i1,l1), Node (i2,l2) -> i1=i2 && CCList.equal eq l1 l2
| Node _, _
| _, Node _ -> false
| Node (i1, l1), Node (i2, l2) -> i1 = i2 && CCList.equal eq l1 l2
| Node _, _ | _, Node _ -> false
let rec hash_tree t h = match t with
| Empty -> CCHash.string_ "empty" h
| Node (i, l) ->
CCHash.list_ hash_tree l (CCHash.int_ i (CCHash.string_ "node" h))
let rec hash_tree t =
match t with
| Empty -> CCHash.string "empty"
| Node (i, l) -> CCHash.(combine2 (int i) (list hash_tree l))
module H = Hashtbl.Make(struct
module H = Hashtbl.Make (struct
type t = tree
let equal = eq
let hash = CCHash.apply hash_tree
let hash = hash_tree
end)
let print_hashcons_stats st =
let open Hashtbl in
CCPrint.printf
"tbl stats: %d elements, num buckets: %d, max bucket: %d\n"
st.num_bindings st.num_buckets st.max_bucket_length;
Array.iteri
(fun i n -> CCPrint.printf " %d\t buckets have length %d\n" n i)
st.bucket_histogram
Format.printf "tbl stats: %d elements, num buckets: %d, max bucket: %d@."
st.num_bindings st.num_buckets st.max_bucket_length;
Array.iteri
(fun i n -> Format.printf " %d\t buckets have length %d@." n i)
st.bucket_histogram
let () =
let st = Random.State.make_self_init () in
let n = 50_000 in
CCPrint.printf "generate %d elements...\n" n;
Format.printf "generate %d elements...\n" n;
let l = CCRandom.run ~st (CCList.random_len n random_tree) in
(* with custom hashtable *)
CCPrint.printf "### custom hashtable\n";
Format.printf "### custom hashtable\n";
let tbl = H.create 256 in
List.iter (fun t -> H.replace tbl t ()) l;
print_hashcons_stats (H.stats tbl);
(* with default hashtable *)
CCPrint.printf "### default hashtable\n";
Format.printf "### default hashtable\n";
let tbl' = Hashtbl.create 256 in
List.iter (fun t -> Hashtbl.replace tbl' t ()) l;
print_hashcons_stats (Hashtbl.stats tbl');
()

File diff suppressed because it is too large Load diff

3
benchs/run_benchs.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
exec dune exec --profile=release benchs/run_benchs.exe -- $@

94
benchs/run_objsize.ml Normal file
View file

@ -0,0 +1,94 @@
(* module Deque = Core_kernel.Deque *)
module Int_map = CCMap.Make (CCInt)
module Int_set = CCSet.Make (CCInt)
let dup = CCPair.dup
let id = CCFun.id
let ns n = List.init n CCFun.id
let iter_range n f = List.iter f (ns n)
let gen_cons x xs =
let saw_x = ref false in
fun () ->
if !saw_x then (
saw_x := true;
Some x
) else
xs ()
let front = Sek.front
let dummy = 0
let types =
[
("Stdlib.List", fun n -> Obj.magic @@ ns n);
("Stdlib.Array", fun n -> Obj.magic @@ Array.init n id);
( "Stdlib.Hashtbl",
fun n -> Obj.magic @@ CCHashtbl.of_iter Iter.(init dup |> take n) );
( "Base.Hashtbl",
fun n -> Obj.magic @@ Base.Hashtbl.Poly.of_alist_exn (List.init n dup) );
( "Stdlib.Map",
fun n -> Obj.magic @@ Int_map.of_iter Iter.(init dup |> take n) );
( "Stdlib.Set",
fun n -> Obj.magic @@ Int_set.of_iter Iter.(init id |> take n) );
("CCFun_vec", fun n -> Obj.magic @@ CCFun_vec.of_list (ns n));
("CCRAL", fun n -> Obj.magic @@ CCRAL.of_list (ns n));
("BatVect", fun n -> Obj.magic @@ BatVect.of_list (ns n));
( "Sek.Persistent",
fun n ->
Obj.magic
@@ List.fold_left
(Sek.Persistent.push front)
(Sek.Persistent.create dummy)
(ns n) );
( "Sek.Ephemeral",
fun n ->
Obj.magic
@@
let c = Sek.Ephemeral.create dummy in
iter_range n (Sek.Ephemeral.push front c);
c );
( "CCVector",
fun n ->
Obj.magic
@@
let c = CCVector.create () in
iter_range n (CCVector.push c);
c );
(* "Core_kernel.Deque", (fun n -> Obj.magic @@ let c = Deque.create () in iter_range n (Deque.enqueue_back c); c); *)
( "Base.Queue",
fun n ->
Obj.magic
@@
let c = Base.Queue.create () in
iter_range n (Base.Queue.enqueue c);
c );
( "Stdlib.Queue",
fun n ->
Obj.magic
@@
let q = Queue.create () in
iter_range n (fun x -> Queue.push x q);
q );
("CCQueue", fun n -> Obj.magic @@ CCDeque.of_list (ns n));
("Iter", fun n -> Obj.magic @@ List.fold_right Iter.cons (ns n) Iter.empty);
("Gen", fun n -> Obj.magic @@ List.fold_right gen_cons (ns n) Gen.empty);
( "Stdlib.Seq",
fun n -> Obj.magic @@ List.fold_right OSeq.cons (ns n) OSeq.empty );
]
let () =
let sizes = [ 0; 1; 10; 100; 1000; 10000 ] in
Printf.printf "%-20s " "";
sizes |> List.iter (fun n -> Printf.printf "%6d " n);
Printf.printf "\n";
types
|> List.iter (fun (name, create) ->
Printf.printf "%-20s: " name;
sizes
|> List.iter (fun n ->
let obj = create n in
let size = Objsize.size_w obj in
(* let size = Obj.reachable_words (Obj.repr obj) in *)
Printf.printf "%6d " size);
Printf.printf "\n")

27
configure vendored
View file

@ -1,27 +0,0 @@
#!/bin/sh
# OASIS_START
# DO NOT EDIT (digest: 6f7b8221311e800a7093dc3b793f67ca)
set -e
FST=true
for i in "$@"; do
if $FST; then
set --
FST=false
fi
case $i in
--*=*)
ARG=${i%%=*}
VAL=${i##*=}
set -- "$@" "$ARG" "$VAL"
;;
*)
set -- "$@" "$i"
;;
esac
done
make configure CONFIGUREFLAGS="$*"
# OASIS_STOP

26
containers-data.opam Normal file
View file

@ -0,0 +1,26 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "3.15"
synopsis: "A set of advanced datatypes for containers"
maintainer: ["c-cube"]
authors: ["c-cube"]
license: "BSD-2-Clause"
tags: ["containers" "RAL" "function" "vector" "okasaki"]
homepage: "https://github.com/c-cube/ocaml-containers/"
bug-reports: "https://github.com/c-cube/ocaml-containers/issues"
depends: [
"dune" {>= "3.0"}
"ocaml" {>= "4.08"}
"containers" {= version}
"qcheck-core" {>= "0.18" & with-test}
"iter" {with-test}
"gen" {with-test}
"mdx" {with-test}
"odoc" {with-doc}
]
dev-repo: "git+https://github.com/c-cube/ocaml-containers.git"
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "build" "@doc" "-p" name ] {with-doc}
["dune" "runtest" "-p" name "-j" jobs] {with-test & arch != "x86_32" & arch != "arm32"}
]

View file

@ -0,0 +1,5 @@
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "build" "@doc" "-p" name ] {with-doc}
["dune" "runtest" "-p" name "-j" jobs] {with-test & arch != "x86_32" & arch != "arm32"}
]

31
containers.opam Normal file
View file

@ -0,0 +1,31 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "3.15"
synopsis:
"A modular, clean and powerful extension of the OCaml standard library"
maintainer: ["c-cube"]
authors: ["c-cube"]
license: "BSD-2-Clause"
tags: ["stdlib" "containers" "iterators" "list" "heap" "queue"]
homepage: "https://github.com/c-cube/ocaml-containers/"
bug-reports: "https://github.com/c-cube/ocaml-containers/issues"
depends: [
"dune" {>= "3.0"}
"ocaml" {>= "4.08"}
"either"
"dune-configurator"
"qcheck-core" {>= "0.18" & with-test}
"yojson" {with-test}
"iter" {with-test}
"gen" {with-test}
"csexp" {with-test}
"uutf" {with-test}
"odoc" {with-doc}
]
depopts: ["base-unix" "base-threads"]
dev-repo: "git+https://github.com/c-cube/ocaml-containers.git"
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "build" "@doc" "-p" name ] {with-doc}
["dune" "runtest" "-p" name "-j" jobs] {with-test & arch != "x86_32" & arch != "arm32"}
]

5
containers.opam.template Normal file
View file

@ -0,0 +1,5 @@
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "build" "@doc" "-p" name ] {with-doc}
["dune" "runtest" "-p" name "-j" jobs] {with-test & arch != "x86_32" & arch != "arm32"}
]

View file

@ -1,32 +0,0 @@
#!/usr/bin/env ocaml
(* note: this requires to generate documentation first, so that
.odoc files are generated *)
#use "topfind";;
#require "containers";;
#require "containers.io";;
#require "gen";;
#require "unix";;
let odoc_files =
CCIO.File.walk "_build"
|> Gen.filter_map
(function
| `File, f when CCString.suffix ~suf:".odoc" f -> Some f
| _ -> None
)
|> Gen.flat_map
(fun f -> Gen.of_list ["-load"; f])
|> Gen.to_list
;;
let out = "deps.dot";;
let cmd =
"ocamldoc -dot -o " ^ out ^ " " ^ String.concat " " odoc_files
;;
print_endline ("run: " ^ cmd);;
Unix.system cmd;;
print_endline ("output in " ^ out);;

81
doc/containers.md Normal file
View file

@ -0,0 +1,81 @@
# More about OCaml-containers
This document contains more information on some modules of Containers.
```ocaml
# #require "containers";;
```
## Hash combinators: `CCHash`
Although OCaml provides polymorphic hash tables (`('a,'b) Hashtbl.t`)
using the polymorphic equality `(=)` and hash `Hashtbl.hash`, it is often
safer and more efficient to use `Hashtbl.Make` (or the extended `CCHashtbl.Make`)
with custom equality and hash functions.
`CCHash` provides combinators for writing hash functions:
```ocaml
# module H = CCHash;;
module H = CCHash
# let hash1 : (int * bool) list H.t = H.(list (pair int bool));;
val hash1 : (int * bool) list H.t = <fun>
```
```ocaml non-deterministic=output
# hash1 [1, true; 2, false; 3, true];;
- : int = 636041136
# hash1 CCList.(1 -- 1000 |> map (fun i->i, i mod 2 = 0));;
- : int = 845685523
# hash1 CCList.(1 -- 1001 |> map (fun i->i, i mod 2 = 0));;
- : int = 381026697
```
The polymorphic hash function is still present, as `CCHash.poly`.
The functions `CCHash.list_comm` and `CCHash.array_comm` allow to hash
lists and arrays while ignoring the order of elements: all permutations
of the input will have the same hash.
## Parser Combinator: `CCParse`
The module `CCParse` defines basic parser combinators on strings.
Adapting [angstrom's tutorial example](https://github.com/inhabitedtype/angstrom#usage)
gives the following snippet.
Note that backtracking is explicit in `CCParse`, hence
the use of `try_` to allow it in some places.
Explicit memoization with `memo` and `fix_memo` is also possible.
```ocaml
open CCParse.Infix
module P = CCParse
let parens p = P.try_ (P.char '(') *> p <* P.char ')'
let add = P.char '+' *> P.return (+)
let sub = P.char '-' *> P.return (-)
let mul = P.char '*' *> P.return ( * )
let div = P.char '/' *> P.return ( / )
let integer =
P.chars1_if (function '0'..'9'->true|_->false) >|= int_of_string
let chainl1 e op =
P.fix (fun r ->
e >>= fun x -> P.try_ (op <*> P.return x <*> r) <|> P.return x)
let expr : int P.t =
P.fix (fun expr ->
let factor = parens expr <|> integer in
let term = chainl1 factor (mul <|> div) in
chainl1 term (add <|> sub))
```
Now we can parse strings using `expr`:
```ocaml
# P.parse_string expr "4*1+2";; (* Ok 6 *)
- : int P.or_error = Result.Ok 6
# P.parse_string expr "4*(1+2)";; (* Ok 12 *)
- : int P.or_error = Result.Ok 12
```

View file

@ -1,181 +0,0 @@
{1 Containers}
{2 Change Log}
See {{: https://github.com/c-cube/ocaml-containers/blob/master/CHANGELOG.adoc } this file}
{2 License}
This code is free, under the BSD license.
The logo (media/logo.png) is
CC-SA3 {{:http://en.wikipedia.org/wiki/File:Hypercube.svg} wikimedia}
{2 Contents}
The design is mostly centered around polymorphism rather than functors. Such
structures comprise (some modules in misc/, some other in core/):
the core library, containers, now depends on
{{:https://github.com/mjambon/cppo}cppo} and base-bytes (provided
by ocamlfind).
{4 Core Modules (extension of the standard library)}
{b findlib name}: containers
{!modules:
CCArray
CCBool
CCChar
CCError
CCFloat
CCFun
CCFormat
CCHash
CCHashtbl
CCHeap
CCInt
CCInt64
CCIO
CCList
CCMap
CCOpt
CCOrd
CCPair
CCPrint
CCRandom
CCRef
CCResult
CCSet
CCString
CCVector
Containers
}
The module {!Containers} contains aliases to most other modules defined
in {i containers core}, and mixins
such as:
{[ module List = struct
include List
include CCList
end
]}
{4 Containers.data}
{b findlib name}: containers.data
Various data structures.
{!modules:
CCAllocCache
CCBitField
CCBloom
CCBV
CCCache
CCDeque
CCFQueue
CCFlatHashtbl
CCGraph
CCHashSet
CCHashTrie
CCImmutArray
CCIntMap
CCMixmap
CCMixset
CCMixtbl
CCMultiMap
CCMultiSet
CCPersistentArray
CCPersistentHashtbl
CCRAL
CCRingBuffer
CCTrie
CCWBTree
}
{4 Containers.io}
{b deprecated} use {!CCIO} directly from the set of core modules.
{4 Containers.unix}
Helpers that depend on {!Unix}, e.g. to spawn sub-processes.
{!modules: CCUnix}
{4 Containers.sexp}
A small S-expression library. The interface is relatively unstable, but
the main type ([CCSexp.t]) isn't.
{!modules:
CCSexp
CCSexpM
}
{4 Containers.iter}
Iterators:
{!modules:
CCKList
CCKTree
CCLazy_list}
{4 String}
{b findlib name}: containers.string
{!modules:
CCApp_parse
CCKMP
CCLevenshtein
CCParse
}
{4 Bigarrays}
{b deprecated} (use package bigstring instead)
Use bigarrays to hold large strings and map files directly into memory.
{!modules: CCBigstring CCArray1}
{4 Advanced}
{b findlib name}: containers.advanced
This module is qualified with [Containers_advanced]. It
requires {{:https://github.com/c-cube/sequence} Sequence}.
{!modules: CCLinq CCCat CCBatch}
{4 Misc}
Moved to its own repository.
{4 Lwt}
Moved to its own repository
{4 Thread Helpers}
{b findlib name}: containers.thread
Modules related to the use of [Thread].
{!modules:
CCBlockingQueue
CCLock
CCPool
CCSemaphore
CCThread
CCTimer
}
{2 Index}
{!indexlist}

41
dune Normal file
View file

@ -0,0 +1,41 @@
(rule
(targets README.md.corrected)
(deps
(package containers-data)
./src/mdx_runner.exe)
(enabled_if
(= %{system} "linux"))
(action
(run ./src/mdx_runner.exe)))
(rule
(alias runtest)
(package containers-data)
(enabled_if
(= %{system} "linux"))
(locks /ctest)
(action
(diff README.md README.md.corrected)))
(env
(_
(flags
:standard
-warn-error
-a+8
-w
-32-48-60-70
-w
+a-4-40-42-44-70
-color
always
-safe-string
-strict-sequence)
(ocamlopt_flags
:standard
-O3
-unbox-closures
-unbox-closures-factor
20
-inline
100)))

42
dune-project Normal file
View file

@ -0,0 +1,42 @@
(lang dune 3.0)
(name containers)
(generate_opam_files true)
(version 3.15)
(authors c-cube)
(maintainers c-cube)
(license BSD-2-Clause)
(homepage "https://github.com/c-cube/ocaml-containers/")
(source (github c-cube/ocaml-containers))
(package
(name containers)
(synopsis "A modular, clean and powerful extension of the OCaml standard library")
(tags (stdlib containers iterators list heap queue))
(depends
(ocaml (>= 4.08))
either
dune-configurator
(qcheck-core (and (>= 0.18) :with-test))
(yojson :with-test)
(iter :with-test)
(gen :with-test)
(csexp :with-test)
(uutf :with-test)
(odoc :with-doc))
(depopts
base-unix
base-threads))
(package
(name containers-data)
(synopsis "A set of advanced datatypes for containers")
(tags (containers RAL function vector okasaki))
(depends
(ocaml (>= 4.08))
(containers (= :version))
(qcheck-core (and (>= 0.18) :with-test))
(iter :with-test)
(gen :with-test)
(mdx :with-test)
(odoc :with-doc)))

View file

@ -1,22 +0,0 @@
(** Write 10_000 Bencode values on the given file *)
(* write n times the same value in the file *)
let write_values file n =
let out = BencodeOnDisk.open_out file in
Printf.printf "[%d] opened file\n" (Unix.getpid ());
let v = Bencode.(L [I 0; I 1; S "foo"]) in
for i = 0 to n-1 do
Printf.printf "[%d] iteration %d\n" (Unix.getpid ()) i;
flush stdout;
BencodeOnDisk.write out v;
done;
BencodeOnDisk.close_out out;
Printf.printf "done\n";
()
let _ =
let file = Sys.argv.(1) in
Printf.printf "[%d] start: write to %s\n" (Unix.getpid ()) file;
flush stdout;
write_values file 100

View file

@ -0,0 +1,80 @@
(* parse IRC logs *)
type datetime = {
year: int;
month: int;
day: int;
hour: int;
min: int;
sec: int;
}
let pp_datetime out d =
let { year; month; day; hour; min; sec } = d in
CCFormat.(
fprintf out "{y=%d;M=%d;d=%d;h=%d;m=%d;s=%d}" year month day hour min sec)
type msg = {
timestamp: datetime;
user: string;
msg: string;
}
let pp_msg out m =
CCFormat.fprintf out "{@[time=%a;@ user=%S;@ msg=%S@]}" pp_datetime
m.timestamp m.user m.msg
open CCParse
let p_datetime : datetime t =
let int = U.int in
let* date, time = split_2 ~on_char:' ' in
let* y, m, d = recurse date (split_3 ~on_char:'-') in
let* year = recurse y int in
let* month = recurse m int in
let* day = recurse d int in
let* hour, min, sec =
recurse time
(let* hour = int in
char ':'
*> let* min = int in
char ':'
*> let+ sec = int in
hour, min, sec)
in
let dt = { year; month; day; hour; min; sec } in
return dt
let p_line =
let* line = lookahead all in
if Slice.is_empty line then
return None
else
let* fields = split_list ~on_char:'\t' in
match fields with
| [ date; user; rest ] ->
let+ timestamp = recurse date p_datetime
and+ user =
recurse user
(chars_if (function
| '>' -> false
| _ -> true))
and+ msg = recurse rest (all_str >|= String.trim) in
Some { timestamp; user; msg }
| _ ->
failf "expected 3 fields, got [%s]"
(String.concat ";" @@ List.map String.escaped
@@ List.map Slice.to_string fields)
let p_file = each_line (parsing "line" p_line) >|= CCList.keep_some
let () =
let s = CCIO.File.read_exn Sys.argv.(1) in
match parse_string p_file s with
| Ok l ->
Format.printf "parsed:@.";
List.iter (Format.printf "%a@." pp_msg) l
| Error e ->
Format.printf "parse error: %s@." e;
exit 1

73
examples/ccparse_sexp.ml Normal file
View file

@ -0,0 +1,73 @@
open CCParse
type sexp =
| Atom of string
| List of sexp list
let rec pp_sexpr out (s : sexp) : unit =
match s with
| Atom s -> Format.fprintf out "%S" s
| List l ->
Format.fprintf out "(@[";
List.iteri
(fun i s ->
if i > 0 then Format.fprintf out "@ ";
pp_sexpr out s)
l;
Format.fprintf out "@])"
let skip_white_and_comments =
fix @@ fun self ->
skip_white
*> try_or (char ';')
~f:(fun _ ->
skip_chars (function
| '\n' -> false
| _ -> true)
*> self)
~else_:(return ())
let atom =
chars_fold_transduce `Start ~f:(fun acc c ->
match acc, c with
| `Start, '"' -> `Continue `In_quote
| `Start, (' ' | '\t' | '\n' | '(' | ')' | ';') -> `Fail "atom"
| `Normal, (' ' | '\t' | '\n' | '(' | ')' | ';') -> `Stop
| `Done, _ -> `Stop
| `In_quote, '"' -> `Continue `Done (* consume *)
| `In_quote, '\\' -> `Continue `Escape
| `In_quote, c -> `Yield (`In_quote, c)
| `Escape, 'n' -> `Yield (`In_quote, '\n')
| `Escape, 't' -> `Yield (`In_quote, '\t')
| `Escape, '"' -> `Yield (`In_quote, '"')
| `Escape, '\\' -> `Yield (`In_quote, '\\')
| `Escape, c -> `Fail (Printf.sprintf "unknown escape code \\%c" c)
| (`Start | `Normal), c -> `Yield (`Normal, c)
| _ -> `Fail "invalid atom")
>>= function
| `In_quote, _ -> fail "unclosed \""
| `Escape, _ -> fail "unfinished escape sequence"
| _, "" -> fail "expected non-empty atom"
| _, s -> return (Atom s)
let psexp =
fix @@ fun self ->
skip_white_and_comments
*> try_or (char '(')
~f:(fun _ ->
sep ~by:skip_white_and_comments self
<* skip_white_and_comments <* char ')'
>|= fun l -> List l)
~else_:atom
let psexp_l = many_until ~until:(skip_white_and_comments *> eoi) psexp
let () =
let s = CCIO.File.read_exn Sys.argv.(1) in
match parse_string psexp_l s with
| Ok l ->
Format.printf "parsed:@.";
List.iter (Format.printf "%a@." pp_sexpr) l
| Error e ->
Format.printf "parse error: %s@." e;
exit 1

View file

@ -1,26 +0,0 @@
(** Export the list of files in a directory *)
let dir = "/tmp/"
(* list of files in a dir *)
let lsdir dir =
let d = Unix.opendir dir in
let l = ref [] in
begin try while true do
l := Unix.readdir d :: !l
done with End_of_file -> Unix.closedir d
end;
!l
let export dir =
let l = lsdir dir in
ToWeb.HTML.(concat
[ h1 (str ("files in "^ dir))
; list (List.map str l)
])
let state = ToWeb.State.create dir ~export
let _ =
ToWeb.serve_state ~sockfile:"/tmp/foo.sock" state

View file

@ -1,20 +0,0 @@
(** Display the graph of the collatz conjecture, starting from the given int *)
let g = LazyGraph.map
~edges:(fun () -> [])
~vertices:(fun i -> [`Label (string_of_int i)])
LazyGraph.collatz_graph
let collatz n filename =
Format.printf "print graph to %s@." filename;
let out = open_out filename in
let fmt = Format.formatter_of_out_channel out in
LazyGraph.Dot.pp ~name:"collatz" g fmt (Sequence.singleton n);
Format.pp_print_flush fmt ();
close_out out
let _ =
if Array.length Sys.argv < 3
then (Format.printf "use: collatz num file@."; exit 0)
else collatz (int_of_string Sys.argv.(1)) Sys.argv.(2)

View file

@ -1,83 +0,0 @@
(** Crawl the web to find shortest path between two urls *)
open Batteries
let pool = Future.Pool.create ~timeout:15. ~size:50
let split_lines s = String.nsplit s ~by:"\n"
let get_and_parse url =
let cmd = Format.sprintf "wget -q '%s' -O - | grep -o 'http\\(s\\)\\?://[^ \"]\\+'" url in
let content = Future.spawn_process ?stdin:None ~pool ~cmd in
content
|> Future.map (fun (_, stdout, _) -> stdout)
|> Future.map split_lines
|> Batteries.tap (fun lines ->
Future.on_success lines (fun lines -> Format.printf "downloaded %s (%d urls)@." url (List.length lines)))
type page = string * (string list Future.t)
(** The web graph; its vertices are annotated by futures of the content *)
let g : (page, string, unit) LazyGraph.t =
let force (url, future) =
Format.printf "force %s@." url;
let urls =
try Future.get future |> List.map (fun url -> (), (url, get_and_parse url))
with e -> [] in
let edges = Gen.of_list urls in
(* need to parse the page to get the urls *)
LazyGraph.Node ((url, future), url, edges)
in LazyGraph.make
~eq:(fun (url1,_) (url2,_) -> url1 = url2)
~hash:(fun (url,_) -> Hashtbl.hash url)
force
let pp_path fmt path =
List.print ~sep:"\n"
(fun fmt ((u1,_), (), (u2,_)) ->
String.print fmt u1; String.print fmt " -> "; String.print fmt u2)
fmt path
(* seek a path from the first url to the second *)
let path_between from into =
Format.printf "seek path from %s to %s@." from into;
let on_explore (url,_) = Format.printf " explore %s...@." url in
try
let cost, path = LazyGraph.dijkstra ~on_explore g
(from, get_and_parse from) (into, get_and_parse into) in
Printf.printf "found path (cost %f):\n%a\n" cost pp_path path
with Not_found ->
Format.printf "no path could be found@."
let print_limit file start depth =
Format.printf "print into %s webgraph starting from %s, up to depth %d@."
file start depth;
let start = start, get_and_parse start in
let g' = LazyGraph.limit_depth g depth (Gen.singleton start) in
let g'' = LazyGraph.map ~vertices:(fun v -> [`Label v]) ~edges:(fun _ -> []) g' in
let out = Format.formatter_of_out_channel (open_out file) in
LazyGraph.Dot.pp ~name:"web" g'' out (Gen.singleton start);
Format.pp_print_flush out ();
()
let _ =
let timer = Future.Timer.create () in
let rec ping () =
Format.printf "*** ping! (size of pool: %d)@." (Future.Pool.size pool);
Future.Timer.schedule_in timer 10. ping
in ping ()
let print_usage () =
Format.printf "usage: crawl path url1 url2@.";
Format.printf "usage: crawl print file url depth@.";
()
let _ =
match Sys.argv with
| [|_; "print"; file; url; depth|] ->
print_limit file url (int_of_string depth)
| [|_; "path"; from; into|] ->
path_between from into
| _ ->
print_usage ()

49
examples/dune Normal file
View file

@ -0,0 +1,49 @@
(executables
(names id_sexp ccparse_sexp ccparse_irclogs)
(libraries containers)
(flags :standard -warn-error -a+8))
(rule
(alias runtest)
(locks /ctest)
(deps
(source_tree test_data))
(action
(ignore-stdout
(run ./id_sexp.exe test_data/benchpress.sexp))))
(rule
(alias runtest)
(locks /ctest)
(deps
(source_tree test_data))
(action
(ignore-stdout
(run ./ccparse_sexp.exe test_data/benchpress.sexp))))
(rule
(targets ccparse_irclogs.ml)
(enabled_if
(>= %{ocaml_version} "4.08"))
(action
(copy ccparse_irclogs_real.cond.ml %{targets})))
(rule
(targets ccparse_irclogs.ml)
(enabled_if
(< %{ocaml_version} "4.08"))
(action
(with-stdout-to
%{targets}
(run echo "let() = print_endline {|ok|}"))))
(rule
(alias runtest)
(locks /ctest)
(deps
(source_tree test_data))
(enabled_if
(>= %{ocaml_version} "4.08"))
(action
(ignore-stdout
(run ./ccparse_irclogs.exe test_data/irc-logs.txt))))

View file

@ -1,18 +1,14 @@
let pp_sexp s = match s with
| `Ok l ->
List.iter
(fun s -> Format.printf "@[%a@]@." CCSexpM.print s)
l
| `Error msg ->
Format.printf "error: %s@." msg
let pp_sexp s =
match s with
| Ok l -> List.iter (fun s -> Format.printf "@[%a@]@." CCSexp.pp s) l
| Error msg -> Format.printf "error: %s@." msg
let () =
match Sys.argv with
| [| _ |] ->
let s = CCSexpM.parse_chan_list stdin in
pp_sexp s
let s = CCSexp.parse_chan_list stdin in
pp_sexp s
| [| _; file |] ->
let s = CCSexpM.parse_file_list file in
pp_sexp s
let s = CCSexp.parse_file_list file in
pp_sexp s
| _ -> failwith "usage: id_sexp [file]"

View file

@ -1,112 +0,0 @@
(** Example of printing trees: lambda-term evaluation *)
type term =
| Lambda of string * term
| App of term * term
| Var of string
let _gensym =
let r = ref 0 in
fun () ->
let s = Printf.sprintf "x%d" !r in
incr r;
s
module SSet = Set.Make(String)
module SMap = Map.Make(String)
let rec fvars t = match t with
| Var s -> SSet.singleton s
| Lambda (v,t') ->
let set' = fvars t' in
SSet.remove v set'
| App (t1, t2) -> SSet.union (fvars t1) (fvars t2)
(* replace [var] with the term [by] *)
let rec replace t ~var ~by = match t with
| Var s -> if s=var then by else t
| App (t1,t2) -> App (replace t1 ~var ~by, replace t2 ~var ~by)
| Lambda (v, t') when v=var -> t (* no risk *)
| Lambda (v, t') -> Lambda (v, replace t' ~var ~by)
(* rename [t] so that [var] doesn't occur in it *)
let rename ~var t =
if SSet.mem var (fvars t)
then replace t ~var ~by:(Var (_gensym ()))
else t
let (>>=) o f = match o with
| None -> None
| Some x -> f x
let rec one_step t = match t with
| App (Lambda (var, t1), t2) ->
let t2' = rename ~var t2 in
Some (replace t1 ~var ~by:t2')
| App (t1, t2) ->
begin match one_step t1 with
| None ->
one_step t2 >>= fun t2' ->
Some (App (t1,t2'))
| Some t1' ->
Some (App (t1',t2))
end
| Var _ -> None
| Lambda (v,t') ->
one_step t' >>= fun t'' ->
Some (Lambda (v, t''))
let normal_form t =
let rec aux acc t = match one_step t with
| None -> List.rev (t::acc)
| Some t' -> aux (t::acc) t'
in
aux [] t
let _split_fuel f =
assert (f>=2);
if f=2 then 1,1
else
let x = 1+Random.int (f-1) in
f-x, x
let _random_var () =
let v = [| "x"; "y"; "z"; "u"; "w" |] in
v.(Random.int (Array.length v))
let _choose_var ~vars = match vars with
| [] -> Var (_random_var ())
| _::_ ->
let i = Random.int (List.length vars) in
List.nth vars i
let rec _random_term fuel vars =
match Random.int 2 with
| _ when fuel = 1 -> _choose_var ~vars
| 0 ->
let f1,f2 = _split_fuel fuel in
App (_random_term f1 vars, _random_term f2 vars)
| 1 ->
let v = _random_var () in
Lambda (v, _random_term (fuel-1) (Var v::vars))
| _ -> assert false
let print_term t =
PrintBox.mk_tree
(function
| Var v -> PrintBox.line v, []
| App (t1,t2) -> PrintBox.line "app", [t1;t2]
| Lambda (v,t') -> PrintBox.line "lambda", [Var v; t']
) t
let print_reduction t =
let l = normal_form t in
let l = List.map (fun t -> PrintBox.pad (print_term t)) l in
PrintBox.vlist ~bars:false l
let () =
Random.self_init ();
let t = _random_term (5 + Random.int 20) [] in
PrintBox.output ~indent:2 stdout (print_reduction t)

View file

@ -1,67 +0,0 @@
(** Compute the memory footprint of a value (and its subvalues). Reference is
http://rwmj.wordpress.com/2009/08/05/ocaml-internals-part-2-strings-and-other-types/ *)
(** A graph vertex is an Obj.t value *)
let graph =
let force x =
if Obj.is_block x
then
let children = Sequence.map (fun i -> i, Obj.field x i) (0--(Obj.size x - 1)) in
LazyGraph.Node (x, Obj.tag x, children)
else
LazyGraph.Node (x, Obj.obj x, Sequence.empty)
in LazyGraph.make ~eq:(==) force
let word_size = Sys.word_size / 8
let size x =
if Obj.is_block x
then (1+Obj.size x) * word_size
else word_size
let compute_size x =
let o = Obj.repr x in
let vertices = LazyGraph.bfs graph o in
Sequence.fold (fun sum (o',_,_) -> size o' + sum) 0 vertices
let print_val fmt x =
let o = Obj.repr x in
let graph' = LazyGraph.map ~edges:(fun i -> [`Label (string_of_int i)])
~vertices:(fun v -> [`Label (string_of_int v); `Shape "box"]) graph in
LazyGraph.Dot.pp ~name:"value" graph' fmt (Sequence.singleton o)
let print_val_file filename x =
let out = open_out filename in
let fmt = Format.formatter_of_out_channel out in
print_val fmt x;
Format.pp_print_flush fmt ();
close_out out
let process_val ~name x =
print_val_file (Format.sprintf "/tmp/%s.dot" name) x;
Format.printf "size of val is %d@." (compute_size x)
module ISet = Set.Make(struct type t = int let compare = compare end)
let mk_circ n =
let start = Sequence.to_list (1--n) in
(* make the end of the list point to its beginning *)
let rec cycle l = match l with
| [] -> assert false
| [_] -> Obj.set_field (Obj.repr l) 1 (Obj.repr start)
| _::l' -> cycle l'
in
cycle start;
start
let _ =
let s = Sequence.fold (fun s x -> ISet.add x s) ISet.empty (1--100) in
process_val ~name:"foo" s;
let l = Sequence.to_list (Sequence.map (fun i -> Sequence.to_list (i--(i+42)))
(Sequence.of_list [0;100;1000])) in
process_val ~name:"bar" l;
let l' = mk_circ 100 in
process_val ~name:"baaz" l';
()

View file

@ -0,0 +1,13 @@
(prover
(name msat)
(synopsis "msat for pure sat problems")
(version "git:.")
(sat "^Sat")
(unsat "^Unsat")
(cmd "$cur_dir/../msat.exe -time $timeout $file"))
(dir
(path $cur_dir)
(pattern ".*\\.cnf")
(expect (const unknown)))

View file

@ -0,0 +1,777 @@
2021-06-04 00:50:44 kluk> How do I start using DynArray from the ocaml command line?
2021-06-04 00:50:51 kluk> I have already done opam install extlib
2021-06-04 00:51:12 kluk> I am a newbie at OCaml
2021-06-04 05:18:03 dockerusocamlus> Hello! I'm minimizing an Alpine-based Docker image with OCaml installed via opam, and I'm trying to understand if I could erase some files to save some space. Basically, trying to understand if they are needed only on special situations, or if that would cause issues for users of the Docker image.
2021-06-04 05:19:46 dockerusocamlus> For instance, in this image, I have file ~/.opam/<version>/lib/ocaml/expunge, which take 15 MB of space. I don't think I have ever used it, but I don't know if it's internally used by some other OCaml process.
2021-06-04 05:28:12 dockerusocamlus> I don't have much documentation about it, and grepping ocaml's sources only shows a few occurrences. It seems related to the installation of the OCaml compiler itself, but even after removing it, I'm still able to do a `opam switch create` to install a different compiler, so... I guess it's fine to remove it?
2021-06-04 05:36:13 octachron> This is a compiler tool which is used to build REPLs. It is also used by utop.
2021-06-04 05:42:54 dockerusocamlus> Thanks!
2021-06-04 08:10:44 superherointj> Need some feedback on a minimalistic lwt demo: https://github.com/superherointj/lwt-demo1
2021-06-04 08:38:37 d_bot> <superherointj> Just solved it. I must be really tired.
2021-06-04 09:49:45 d_bot> <superherointj> Can anybody point me to a good article/information on incompatible ppx drivers (ppxlib and ocaml-migrate-parsetree)?
2021-06-04 09:49:46 d_bot> <superherointj> I have read already the saga blog post, but I am missing something.
2021-06-04 09:49:47 d_bot> <superherointj> I want to build my old project. I'm trying to replicate problem atm on a demo.
2021-06-04 09:50:25 companion_cube> people are supposed to use ppxlib, that's all I know
2021-06-04 09:51:25 d_bot> <superherointj> Any example?
2021-06-04 09:51:51 companion_cube> https://github.com/ocaml-ppx/ppx_deriving I guess?
2021-06-04 09:52:40 d_bot> <superherointj> Found this:
2021-06-04 09:52:41 d_bot> <superherointj> https://ppxlib.readthedocs.io/_/downloads/en/stable/pdf/
2021-06-04 09:57:49 d_bot> <EduardoRFS> Why does OCaml not optimizes this in a noop? Even under flambda and -O3
2021-06-04 09:57:49 d_bot> <EduardoRFS>
2021-06-04 09:57:51 d_bot> <EduardoRFS> ```ocaml
2021-06-04 09:57:52 d_bot> <EduardoRFS> let f (a, b) = (a, b)
2021-06-04 09:57:53 d_bot> <EduardoRFS> ```
2021-06-04 10:00:07 @adrien> it returns a new tuple, not the same one
2021-06-04 10:00:37 @adrien> let x = (1,2);; let f (a, b) = (a, b);; let y = f x;; y == x;;
2021-06-04 10:00:41 d_bot> <EduardoRFS> the question is why? It would change the `==` behavior but it's already not defined from what I remember
2021-06-04 10:01:06 d_bot> <EduardoRFS> it behaves differently in bytecode, native and IIRC it's also different in flambda
2021-06-04 10:01:14 companion_cube> I agree it'd be a valid optim
2021-06-04 10:02:19 d_bot> <EduardoRFS> This is especiall try for the case of different types and pattern matching but that generates identical data in memory, like
2021-06-04 10:02:20 d_bot> <EduardoRFS>
2021-06-04 10:02:21 d_bot> <EduardoRFS> ```ocaml
2021-06-04 10:02:22 d_bot> <EduardoRFS> type a = | A(int)
2021-06-04 10:02:24 d_bot> <EduardoRFS> type b = B(int)
2021-06-04 10:02:25 d_bot> <EduardoRFS> let f = function | A v -> B v
2021-06-04 10:02:26 d_bot> <EduardoRFS> ```
2021-06-04 10:02:36 @adrien> I get the same behaviour in native
2021-06-04 10:03:11 @adrien> and you can do f u = u
2021-06-04 10:03:13 companion_cube> @eduardors these are only the same by accident though
2021-06-04 10:03:18 companion_cube> seems far less useful as an optim
2021-06-04 10:03:18 zozozo> see https://github.com/ocaml/ocaml/pull/8958
2021-06-04 10:03:22 d_bot> <EduardoRFS> yes but the compiler knows it
2021-06-04 10:03:32 @adrien> not sure how is the generated code but in that case it's not a new tuple
2021-06-04 10:04:02 zozozo> there is a PR to do pretty much that (the link I posted above)
2021-06-04 10:04:05 theblatte> I keep writing functions like `let f ((a,b) as x0) = let a' = g a in let b' = g b in if a == a' && b == b' then x0 else (a', b')`
2021-06-04 10:04:07 d_bot> <EduardoRFS> in this case yes, but not all cases, I'm not asking about this specific tuple, I'm asking more about identical blocks that are known to be always identical
2021-06-04 10:04:13 companion_cube> I don't think it's a very useful optimization to see if per chance two different variants of different types happen to have the same binary representation
2021-06-04 10:04:33 companion_cube> more important stuff is to eliminate temporaries imho
2021-06-04 10:04:41 companion_cube> like a tuple built just to be deconstructed in the same function
2021-06-04 10:04:45 companion_cube> (or an option…)
2021-06-04 10:04:53 zozozo> companion_cube: what do you mean by "temporaries"?
2021-06-04 10:05:05 d_bot> <EduardoRFS> temporary allocations IIUC
2021-06-04 10:05:06 companion_cube> data that doesn't escape the current function :p
2021-06-04 10:05:09 zozozo> companion_cube: ah, well, avoiding these is more or less exactly the job of flambda, ^^
2021-06-04 10:05:11 companion_cube> (after inlining)
2021-06-04 10:05:12 companion_cube> yeah I know
2021-06-04 10:05:17 companion_cube> godspeed to you zozozo
2021-06-04 10:05:30 zozozo> ^^
2021-06-04 10:05:55 zozozo> @EduardoRFS : did you look at https://github.com/ocaml/ocaml/pull/8958 ?
2021-06-04 10:07:07 d_bot> <EduardoRFS> I'm looking on it, the argument of not being predictable is sad, it's a flat allocation reduction, no hidden allocation, not trying to make non efficient code efficient, but trying to make code that is efficient as possible more efficient
2021-06-04 10:07:34 zozozo> companion_cube: also, note that sometimes, because of type subtleties, you need to write the "identity" function, as a pattern match that then reconstructs exactly the same value, but with a slightly different type (thing GADTs), in such cases, being able to detect that a switch returns exactly its argument, is a nice improvements, and you can't really write it differently because of the types
2021-06-04 10:07:36 @adrien> well, as theblatte said, the "as" construct should help for that case
2021-06-04 10:08:04 d_bot> <EduardoRFS> that's exactly the case zozozo, for a lot of code in ocaml-migrate-types
2021-06-04 10:08:11 theblatte> zozozo: yes!
2021-06-04 10:08:19 zozozo> the advantage of the PR I linked is that it can trigger in cases where one cannot write code using "as"
2021-06-04 10:08:27 theblatte> much sad when that happens
2021-06-04 10:08:30 d_bot> <EduardoRFS> "as"?
2021-06-04 10:08:53 zozozo> @EduardoRFS : `let f ((a, b) as pair) = pair`
2021-06-04 10:09:13 d_bot> <EduardoRFS> oh but that works only for structural types
2021-06-04 10:09:21 companion_cube> zozozo: good argument against GADTs ;)
2021-06-04 10:09:34 d_bot> <EduardoRFS> companion_cube loves GADTs
2021-06-04 10:09:42 companion_cube> heh, in small doses
2021-06-04 10:09:47 theblatte> companion_cube: no need for GADTs! https://github.com/facebook/infer/blob/cfed4c4fa0c99ab1f42683bb92df76c8c8434e79/infer/src/pulse/PulseSummary.ml#L56
2021-06-04 10:10:03 olle> as?
2021-06-04 10:10:06 olle> new keyword?
2021-06-04 10:10:13 companion_cube> wait, theblatte, why
2021-06-04 10:10:14 theblatte> eg phantom type parameters
2021-06-04 10:10:18 companion_cube> ah yes
2021-06-04 10:10:29 companion_cube> it's unfortunate
2021-06-04 10:10:34 theblatte> (in my case not phantom but "phantom" because it doesn't show up in some of the variants)
2021-06-04 10:10:37 companion_cube> but it's the same constructors in this case.
2021-06-04 10:10:38 zozozo> companion_cube: gadts are useful *sometimes*
2021-06-04 10:10:40 d_bot> <EduardoRFS> I wonder if #8958 would be better as lambda layer
2021-06-04 10:10:44 d_bot> <EduardoRFS> but tempting to rebase it ;/
2021-06-04 10:11:25 zozozo> @EduardoRFS : the problem is that if you do that at lambda level, you miss out on situations where it happens after some inlining/simplification
2021-06-04 10:11:47 d_bot> <EduardoRFS> yeah but you ensure same behavior between all backends
2021-06-04 10:11:50 zozozo> (also, the code of lambda simplifications is quite a mess from what I hear)
2021-06-04 10:12:33 theblatte> companion_cube: same constructors: yes, personally I would only care about preserving physical equality when the objects are actually equal but ymmv
2021-06-04 10:12:34 zozozo> well.. there is now a pass specifically designed to implement optimizations, so why not use it ?
2021-06-04 10:13:05 theblatte> I've seen several examples where it would have a material effect on perf
2021-06-04 10:13:08 d_bot> <EduardoRFS> But the pass should not change behavior of code unless it provides a fallback, this is how I see most of it
2021-06-04 10:13:13 d_bot> <EduardoRFS> maybe Sys.opaque_identity would ignore it
2021-06-04 10:13:32 d_bot> <EduardoRFS> can we deprecate ==? That seems like a better idea overall
2021-06-04 10:13:34 companion_cube> zozozo: because it only works for native?
2021-06-04 10:13:41 companion_cube> ahahah
2021-06-04 10:13:47 companion_cube> removing == kills perf for other programs
2021-06-04 10:14:01 theblatte> #8958 ftw, I didn't know there'd been such a PR in flight for such a long time
2021-06-04 10:14:04 zozozo> companion_cube: well, bytecode is pretty much meant to not care about performance, so from that point of view it's not unreasonable
2021-06-04 10:14:05 d_bot> <EduardoRFS> not removing it, deprecating it, keep it under Obj.xx
2021-06-04 10:14:34 theblatte> == is an important part of the language, not an extension
2021-06-04 10:14:41 zozozo> the *good* solution would be to change the bytecode generation to use the result of flambda
2021-06-04 10:14:56 zozozo> the semantics of "==" is largely not officially specified
2021-06-04 10:14:56 d_bot> <EduardoRFS> NAH
2021-06-04 10:15:10 theblatte> but not a bad idea to not give it such an easily-confused name :p eg use "phys_equal" instead
2021-06-04 10:15:12 zozozo> and for any non-mutable record, there are next to no guarantees about "=="
2021-06-04 10:15:26 d_bot> <EduardoRFS> unless we had a blazing fast flambda pass, bytecode is so fast right now
2021-06-04 10:16:22 d_bot> <EduardoRFS> == is not exactly part of the language in many ways, and it's known to behave differently depending on the backend which should never happen for a specified feature of the language
2021-06-04 10:16:30 zozozo> @EduardoRFS: are you talking about compilation time or runtime of the compild program ?
2021-06-04 10:16:35 d_bot> <EduardoRFS> compilation time
2021-06-04 10:16:36 companion_cube> zozozo: I wish I could agree
2021-06-04 10:16:40 companion_cube> but some of us are stuck with bytecode
2021-06-04 10:16:45 d_bot> <EduardoRFS> bytecode is slow in runtime, really slow
2021-06-04 10:16:46 companion_cube> because that's the only official toplevel for now
2021-06-04 10:17:10 d_bot> <EduardoRFS> but bytecode generated from flambda would still work with the toplevel
2021-06-04 10:17:16 zozozo> companion_cube: yeah, but sometimes with others in my team, we talk about making it so that bytecode is generated after the flambda pass, which would solve all problems (if we can make it work)
2021-06-04 10:17:21 companion_cube> sure
2021-06-04 10:17:36 companion_cube> I mean in the future maybe we'll also have a JIT
2021-06-04 10:17:42 d_bot> <EduardoRFS> there is any plan on deprecating closure middle end?
2021-06-04 10:17:45 companion_cube> but for now it's not like there's a choice, and there's basically 0 optims on bytecode
2021-06-04 10:17:47 companion_cube> which… ugh
2021-06-04 10:19:26 d_bot> <dinosaure> it remmembers me one time when people compared ocsigenserver and http servers and used the bytecode version accidentally and say, OCaml is so bad
2021-06-04 10:19:34 companion_cube> :D
2021-06-04 10:19:38 d_bot> <EduardoRFS> D:
2021-06-04 10:19:49 companion_cube> or even using dune without --profile=release
2021-06-04 10:19:53 companion_cube> bye bye optims
2021-06-04 10:19:58 d_bot> <EduardoRFS> TEZOS IS RUNNING WITHOUT PROFILE=RELEASE
2021-06-04 10:20:25 d_bot> <EduardoRFS> even worse it is benchmarked without profile=release
2021-06-04 10:20:33 companion_cube> hu, weirder
2021-06-04 10:21:18 zozozo> well, if the switch is not using flambda, I don't think the difference is that important between the dev and release profiles
2021-06-04 10:22:34 companion_cube> err, you still have a bit of cross module inlining, don't you?
2021-06-04 10:22:39 companion_cube> with normal ocamlopt
2021-06-04 10:22:54 zozozo> I'm not sure
2021-06-04 10:22:55 d_bot> <EduardoRFS> yeah it makes difference, I benchmarked it, around 30% boost on some smart contracts
2021-06-04 10:23:06 d_bot> <EduardoRFS> dune without profile=release runs under -opaque
2021-06-04 10:23:10 companion_cube> I think it does, including for stuff like externals
2021-06-04 10:23:16 companion_cube> exactly
2021-06-04 10:23:25 companion_cube> --profile=release brings you back to normal behavior
2021-06-04 10:23:26 zozozo> I think (but I'm not sure) the only thing cross-inlined would be externals, but those are in the .mlis so no need for cross-optimization actually
2021-06-04 10:23:30 d_bot> <EduardoRFS> externals rely on the interface, so it doesn't depend on profile=release
2021-06-04 10:23:50 companion_cube> zozozo: but the .cmx ?
2021-06-04 10:24:00 theblatte> is profile=release different than passing -O3 to ocamlopt??
2021-06-04 10:24:05 zozozo> ah, maybe the small functions that closure unconditionally inline are inliend cross-modules by vanilla ocamlopt
2021-06-04 10:24:17 d_bot> <EduardoRFS> it is, because without profile=release you're under -opaque
2021-06-04 10:24:30 theblatte> whaaaat
2021-06-04 10:24:40 theblatte> :o
2021-06-04 10:24:44 d_bot> <EduardoRFS> that's the only way to achieve blazing fast build speed
2021-06-04 10:24:53 companion_cube> zozozo: the functions marked "inline" in .cmx files
2021-06-04 10:24:56 d_bot> <EduardoRFS> yup, small functions like having `Module.equal` are not inlined and Module.equal a lot of times is literally a single cnstruction
2021-06-04 10:25:09 theblatte> blazing fast = 6x slower than without -O3 ^^
2021-06-04 10:25:11 companion_cube> that's what I was talking about
2021-06-04 10:25:21 zozozo> companion_cube: indeed, ^^
2021-06-04 10:25:30 companion_cube> so it can make a big difference :)
2021-06-04 10:25:35 companion_cube> even without flambda
2021-06-04 10:25:45 theblatte> ohhh, recently-ish we noticed marking some functor arguments as [@inline] made a big difference
2021-06-04 10:25:52 companion_cube> :D
2021-06-04 10:25:59 zozozo> that's not surprising
2021-06-04 10:26:04 theblatte> is that sort of thing (adding @inline) not needed with flambda + release profile?
2021-06-04 10:26:25 theblatte> or is that independent?
2021-06-04 10:26:26 companion_cube> it still gives you better control
2021-06-04 10:26:34 zozozo> iirc, flambda tries as much as possibvle to inline functor applicaiton that are at toplevel, so you shouldn't need the annotations in that particular case
2021-06-04 10:26:51 companion_cube> do a lot of people use flambda1 in production?!
2021-06-04 10:26:59 zozozo> companion_cube: jane street i guess ?
2021-06-04 10:27:07 companion_cube> ahah maybe they have enough RAM
2021-06-04 10:27:16 zozozo> also, the binary release of dolmen is now compiled with flambda, :D
2021-06-04 10:27:18 companion_cube> I stopped using it years ago
2021-06-04 10:27:18 theblatte> infer is 30% faster with flambda, so you bet
2021-06-04 10:27:32 companion_cube> wow
2021-06-04 10:27:37 companion_cube> well can't wait for flambda2
2021-06-04 10:28:01 companion_cube> anyway, the point of --profile=release is to tell dune to not block optimizations, it doesn't enable new ones
2021-06-04 10:28:05 companion_cube> for that you can use ocamlopt_flags
2021-06-04 10:28:13 d_bot> <EduardoRFS> tezos is another 20% faster on flambda
2021-06-04 10:28:15 zozozo> we're trying very hard on making it so that flambda2 is as fast as possible, but it's hard sometimes
2021-06-04 10:28:27 companion_cube> zozozo: it's not just a question of "fast"
2021-06-04 10:28:35 companion_cube> it's also "not gobble up RAM on bad cases"
2021-06-04 10:28:38 theblatte> yes but I'm trying to understand if adding --profile=release will make a difference
2021-06-04 10:28:51 theblatte> I'll try that
2021-06-04 10:29:01 companion_cube> so, -p foo already switches to release mode
2021-06-04 10:29:12 companion_cube> it's only if you use `dune build @all` and that kind of stuff that it matters
2021-06-04 10:29:21 zozozo> companion_cube: right, can you send me (if you recall), the packages that were not working 'or taking ut too much RAM) ?
2021-06-04 10:29:24 companion_cube> it makes compilation slower (removes -opaque) but enables optimization
2021-06-04 10:29:27 companion_cube> zozozo: at least dose3
2021-06-04 10:29:30 companion_cube> that was the blocker
2021-06-04 10:29:32 zozozo> so that we can at least try and see what happens with flamdba2
2021-06-04 10:29:32 companion_cube> and camlp4
2021-06-04 10:29:35 d_bot> <EduardoRFS> even the new dose3?
2021-06-04 10:29:52 d_bot> <EduardoRFS> dose3 6 changed quite a bit of stuff, even parmap they're using now
2021-06-04 10:30:34 theblatte> companion_cube: we do "dune build infer.exe"
2021-06-04 10:31:29 companion_cube> lol
2021-06-04 10:31:39 companion_cube> yeah you need the flag
2021-06-04 10:31:54 companion_cube> idk about dose3 6
2021-06-04 10:32:01 companion_cube> I stopped trying flambda a while ago
2021-06-04 10:32:17 companion_cube> using too much ram is a big problem imho
2021-06-04 10:32:45 d_bot> <EduardoRFS> that seems weird, flambda reduces the number of allocations considerably
2021-06-04 10:33:30 companion_cube> per module
2021-06-04 10:33:38 companion_cube> with this you might also gain cross module
2021-06-04 10:33:54 theblatte> ah I thought you meant too much ram used during compilation :)
2021-06-04 10:34:09 companion_cube> that's what I meant yes
2021-06-04 10:34:11 companion_cube> sorry
2021-06-04 10:34:18 companion_cube> but theblatte, try the flag :p
2021-06-04 10:34:26 d_bot> <EduardoRFS> yeah makes sense
2021-06-04 10:34:29 theblatte> companion_cube: I am!!
2021-06-04 10:34:30 companion_cube> and also, make sure .cmx are installed for all libraries
2021-06-04 10:34:52 d_bot> <EduardoRFS> do we have an idea on what leads flambda to use so much memory?
2021-06-04 10:34:57 theblatte> companion_cube: how?
2021-06-04 10:35:14 companion_cube> well most should do it if they use dune
2021-06-04 10:35:25 d_bot> <ggole> Is there any info on flambda2 floating around yet?
2021-06-04 10:35:36 companion_cube> there's zozozo's brain
2021-06-04 10:35:40 companion_cube> although it's not floating
2021-06-04 10:39:04 d_bot> <dinosaure> technically, his brain is floating in his skull
2021-06-04 10:39:15 companion_cube> he might be a robot
2021-06-04 10:39:17 companion_cube> can't be sure
2021-06-04 10:39:27 d_bot> <EduardoRFS> if he is doing flambda2 he is a robot
2021-06-04 10:40:07 zozozo> right, I can try and answer questions about flambda2
2021-06-04 10:40:17 zozozo> since I'm working on it, ^^
2021-06-04 10:41:07 companion_cube> it'll be the default if it works well enough, right?
2021-06-04 10:41:53 zozozo> that's the plan
2021-06-04 10:43:01 companion_cube> 🤞
2021-06-04 10:43:57 d_bot> <ggole> Hmm, I'm not sure I know enough about it to ask good questions
2021-06-04 10:45:07 d_bot> <ggole> Although maybe "what was not adequate about the first flambda design" is an obvious one
2021-06-04 10:45:29 theblatte> companion_cube: ah, but actually we never use dune default profiles, we do --profile=opt (or dev). There's no -opaque in the build logs
2021-06-04 10:45:41 companion_cube> ah, I see
2021-06-04 10:45:47 theblatte> phew :)
2021-06-04 10:45:49 companion_cube> (wait, there's a profile=opt??)
2021-06-04 10:46:01 theblatte> you can name your profile however you want :p
2021-06-04 10:46:40 zozozo> @ggole: basically, flambda2 now uses a CPS representation of source code, which is very useful (whereas flambda1 had an ANF representation iirc)
2021-06-04 10:46:40 theblatte> then we have (env (opt (ocamlopt_flags (:standard -O3))), etc.
2021-06-04 10:47:35 theblatte> maybe we should have -opaque for profile=dev though!
2021-06-04 10:47:52 d_bot> <EduardoRFS> wondering, when the optimization mentioned in 8958 may be triggered after inlining?
2021-06-04 10:48:19 d_bot> <EduardoRFS> It would be weird if flambda allocated two identical temporary blocks
2021-06-04 10:48:30 d_bot> <Drup> I also have a question on flambda 2.0
2021-06-04 10:48:37 d_bot> <ggole> @guigui CPS is an interesting direction. It used to be the IL style of choice, but seems to have gone right out of favour.
2021-06-04 10:49:04 zozozo> Drup: fire away, ^^
2021-06-04 10:49:07 d_bot> <Drup> Do you (the flambda team) intend to keep working on it instead of instantly decide to shoot the for moon and work on flambda 3.0 ?
2021-06-04 10:49:36 companion_cube> lolol
2021-06-04 10:49:39 companion_cube> I could say the same of ppx
2021-06-04 10:49:44 zozozo> Drup: the plan is to continue working on flambda2
2021-06-04 10:50:14 d_bot> <ggole> Although people who use ANF seem to have discovered the need for very continuation-like constructs with join points
2021-06-04 10:50:17 zozozo> basically, doing flambda1 gave the team (note that this was before I joined) some insights about how to do and not to do some things
2021-06-04 10:50:17 d_bot> <Drup> (you don't have to answer it, it's friday evening, and I know you don't really have a sway on this all that much)
2021-06-04 10:50:50 zozozo> Drup: indeed, but I'm right now in a conference call with Pierre so I can ask him, ^^
2021-06-04 10:51:02 d_bot> <Drup> Say hello from me :p
2021-06-04 10:51:22 zozozo> Drup: he says hello to you too
2021-06-04 10:52:18 theblatte> hi pchambart :)
2021-06-04 10:52:48 companion_cube> coucou to him
2021-06-04 10:52:58 d_bot> <Drup> but yeah, flambda in general is a bit moonshot infused sometimes. I understand why (it's much more fun to work on "The Perfect IR") but it's a bit infuriating.
2021-06-04 10:53:28 companion_cube> like multicore has been for a while, too
2021-06-04 10:53:31 companion_cube> or even opam 2.1
2021-06-04 10:53:36 companion_cube> seems like a common theme in OCaml :p
2021-06-04 10:53:37 theblatte> companion_cube: alright so something good still came out of that: compiling with -opaqe turns a 50s full build into a 40s one \o/ and I assume it's even better for incremental build?
2021-06-04 10:53:42 zozozo> yeah, but now with flambda2 we should have a good enough IR to do what we want and need
2021-06-04 10:54:11 companion_cube> theblatte: err it's faster builds, but slower code, yes
2021-06-04 10:54:12 d_bot> <Drup> let's hope so
2021-06-04 10:54:34 theblatte> companion_cube: it's for "dev" builds
2021-06-04 10:54:49 companion_cube> then yes
2021-06-04 10:55:07 companion_cube> with -opaque you have fully separate compilation
2021-06-04 10:55:24 theblatte> I was wondering why dune was doing so much work on incremental compilation ^^
2021-06-04 10:55:31 theblatte> thanks!
2021-06-04 10:56:35 d_bot> <Drup> (I though dune already added `-opaque` for dev builds)
2021-06-04 10:57:05 d_bot> <ggole> @guigui what was difficult before that's easy now?
2021-06-04 10:57:06 companion_cube> seems like theblatte has his own profiles
2021-06-04 10:57:37 companion_cube> zozozo: so in CPS, do you have 2 "kinds" of function calls? normal and continuations?
2021-06-04 10:57:42 companion_cube> to make sure there's no new closures?
2021-06-04 10:57:53 d_bot> <Drup> That doesn't seem very smart if those are less though-out than the normal ones :3
2021-06-04 10:57:56 theblatte> dune profiles have... weird defaults
2021-06-04 10:58:24 theblatte> fair enough :p
2021-06-04 10:59:06 zozozo> companion_cube: continuations in flambda2 are more along the lines of static jumps
2021-06-04 10:59:12 companion_cube> cool
2021-06-04 10:59:33 companion_cube> zozozo: please stop delaying the PR for ocaml.org
2021-06-04 10:59:33 companion_cube> plz
2021-06-04 11:00:48 zozozo> sorry, ^^
2021-06-04 11:00:57 companion_cube> why does a PR against a fracking website take a full week to be merged anyway
2021-06-04 11:01:29 zozozo> right, that's a problem
2021-06-04 11:02:22 companion_cube> if you want the website to go stale because no one opens a PR to update it, that's the best way to go
2021-06-04 11:02:38 octachron> companion_cube, because there is noone clearly responsible? My commit right is normally mostly for OCaml releases
2021-06-04 11:03:07 companion_cube> is Anil trying to do too many things? :p
2021-06-04 11:03:21 companion_cube> definitely not blaming you octachron
2021-06-04 11:04:36 companion_cube> just annoyed that this, which should have taken literally 5 minutes, is taking a week
2021-06-04 11:04:41 theblatte> interesting, -opaque seems to make no difference for incremental compilation, only for full compilation
2021-06-04 11:04:46 companion_cube> during which the information on the website is misleading
2021-06-04 11:05:14 companion_cube> theblatte: try modifying a file deep in the dep graph, but only the implementation, not the interface
2021-06-04 11:05:22 theblatte> that's what I tried
2021-06-04 11:05:36 companion_cube> hu
2021-06-04 11:06:25 theblatte> humm, there's a leftover -opaque in the logs, my experiment must have gone wrong, sorry, digging in further
2021-06-04 11:11:27 d_bot> <EduardoRFS> theblatte: also opaque allows to build strictly against cmi which leads to better parallelism if you're using mli well
2021-06-04 11:12:30 d_bot> <EduardoRFS> so opaque should definitely matter for incremental as without it you need to rebuilt the full tree if any module changes
2021-06-04 11:12:36 d_bot> <EduardoRFS> maybe dune doesn't have this implemented?
2021-06-04 11:12:48 d_bot> <EduardoRFS> @rgrinberg any idea here?
2021-06-04 11:13:00 theblatte> I think because we use the "dev" name for our profile -opaque was already being passed!
2021-06-04 11:13:48 theblatte> even though we override (flags ...)
2021-06-04 11:13:53 theblatte> but not ocamlopt_flags
2021-06-04 11:15:11 octachron> companion_cube, anyway my week ended 15 minutes ago, so the PR is merged.
2021-06-04 11:16:16 theblatte> and we still see a win for the full build by forcing -opaque because it passes it in a bunch of places where dune doesn't by default
2021-06-04 11:16:58 theblatte> looks like that's when building the entire libraries' .cmx
2021-06-04 11:17:21 @adrien> octachron: thanks :)
2021-06-04 11:17:46 theblatte> so, hmmm, *shrug*
2021-06-04 11:39:10 companion_cube> octachron: 😂 thank you
2021-06-04 11:43:12 companion_cube> and the website is updated already, nice
2021-06-04 11:46:07 companion_cube> "variant constructor unboxing" that's nice
2021-06-04 11:46:16 companion_cube> didn't we discuss it here recently?
2021-06-04 11:46:21 companion_cube> perhaps about bitvectors
2021-06-04 11:51:05 olle> oooooh
2021-06-04 13:58:46 zozozo> @ggole : sorry for the delay, basically, control flow manipulation is much easier in cps form, also inlining a function's body is tricky to do in ANF (and can be exponential in the worst case if you need to ensure the result if in strict ANF)
2021-06-04 13:59:23 companion_cube> coudl you post a snippet of a tiny CPS AST? :p
2021-06-04 13:59:39 companion_cube> sth where we could see let, application, and like a primitive like + ?
2021-06-04 13:59:44 zozozo> sure
2021-06-04 13:59:56 companion_cube> 👍
2021-06-04 14:00:08 companion_cube> I want to see how the continuations are represented
2021-06-04 14:07:32 zozozo> https://gist.github.com/Gbury/7a02a35cb4906914fa351183490f11b2
2021-06-04 14:07:44 zozozo> basically, a continuation is a (unique) integer
2021-06-04 14:08:05 zozozo> companion_cube: ^
2021-06-04 14:09:06 companion_cube> so, apply_cont is where you jump
2021-06-04 14:09:09 zozozo> yup
2021-06-04 14:09:29 zozozo> also, after a function call (i.e. Apply_expr), you call the given continuation with the return value of the function call
2021-06-04 14:09:35 companion_cube> and why is there 2 let?
2021-06-04 14:09:42 companion_cube> yeah
2021-06-04 14:09:49 companion_cube> and you call the function on already computed arguments
2021-06-04 14:09:59 zozozo> you can bind continuations, and regular expressions
2021-06-04 14:10:37 companion_cube> hmmm
2021-06-04 14:10:54 companion_cube> I mean, Let_expr makes sense, it's a local definition, ok
2021-06-04 14:11:00 companion_cube> but what's the "handler" in Let_cont?
2021-06-04 14:11:00 zozozo> yup
2021-06-04 14:11:07 zozozo> the code of the continuation
2021-06-04 14:11:17 companion_cube> oh shit ok
2021-06-04 14:11:17 zozozo> let_cont k args = handler in body
2021-06-04 14:11:22 companion_cube> nice
2021-06-04 14:11:43 zozozo> note that continuations are local to a function's body and cannot escape
2021-06-04 14:11:44 companion_cube> so patmatch could also create such expressions, for example
2021-06-04 14:11:55 zozozo> since continuations are not regular value (i.e. simples or named)
2021-06-04 14:11:55 companion_cube> with explicit sharing and everything
2021-06-04 14:12:02 zozozo> yes
2021-06-04 14:12:29 companion_cube> (I imagine switch could also have a default case)
2021-06-04 14:12:49 zozozo> in this case no, the switch has no default case
2021-06-04 14:12:56 zozozo> it simplifies some things
2021-06-04 14:13:07 zozozo> but in theory it could
2021-06-04 14:13:08 companion_cube> even in flambda2?
2021-06-04 14:13:17 companion_cube> I guess since you can share continuations, it's ok
2021-06-04 14:13:24 zozozo> it's just that having no default case means the code is much more regular
2021-06-04 14:13:29 zozozo> you can fold on the arms of the switch
2021-06-04 14:13:41 zozozo> and not have to specifically treat the default case
2021-06-04 14:15:30 companion_cube> heh, fair enough
2021-06-04 14:16:03 companion_cube> I think the insight that continuations are not values, is sth I didn't realize
2021-06-04 14:16:05 companion_cube> so thank you! :)
2021-06-04 14:16:27 zozozo> no problem, ^^
2021-06-04 14:30:12 d_bot> <ggole> zozozo: hmm, that's actually pretty close to what I expected. Thanks for taking the time to write it up.
2021-06-04 14:33:07 d_bot> <ggole> When I tried CPS ILs I found it difficult to perform what should be simple transformations like commuting `case` expressions, but perhaps my approach was too naive.
2021-06-04 14:37:04 zozozo> @ggole : well, commuting switches would be quite complicated indeed (and isn't done currently in flambda2)
2021-06-04 14:38:59 d_bot> <ggole> That's one benefit of a more lambda-calculus like IL, it's quite easy to do context-directed optimisations (of which commuting is probably the most significant)
2021-06-04 14:39:37 zozozo> yeah, but then again, I don't think commuting is really something that we want to do in flambda2
2021-06-04 14:39:39 d_bot> <ggole> But there are downsides with scope
2021-06-04 14:39:55 d_bot> <colin> will flambda2 carry through to faithful CPS compilation or what
2021-06-04 14:40:21 zozozo> @colin : I'm not sure what you mean ?
2021-06-04 14:41:00 d_bot> <ggole> SML/NJ style CPS all the way? Seems unlikely.
2021-06-04 14:41:03 d_bot> <colin> I've seen compilers that use CPS as an IR yet blast to something slightly different to compile to something that still uses a runtime stack
2021-06-04 14:41:22 d_bot> <colin> Yeah, I don't think SML/NJ or MLton can be described as using CPS to much of an extent nowadays tbh
2021-06-04 14:41:57 d_bot> <ggole> I thought SML/NJ still used that for their `Cont` implementation
2021-06-04 14:41:57 zozozo> ah well, the flambda IR is in CPS, but there will be no change to the other IR of the compiler, so that's that, ^^
2021-06-04 14:43:13 d_bot> <colin> is the Apply_cont constructor in this cps.ml file representing "contificated"/static continuations?
2021-06-04 14:43:43 zozozo> yeah, it represents static continuations bound previously by a Let_cont
2021-06-04 14:43:59 d_bot> <colin> interesting, I've only ever seen the IR presented in Appel's CwC book
2021-06-04 14:44:30 d_bot> <ggole> There's a nice paper on an CPS IR a bit like this that you might be interested in
2021-06-04 14:44:36 d_bot> <colin> is it by Kennedy
2021-06-04 14:44:42 d_bot> <ggole> Yeah
2021-06-04 14:44:56 d_bot> <colin> yeah, I've seen that as well actually, it's the one most people seem to go with I think
2021-06-04 14:45:17 d_bot> <ggole> Makes a lot of sense if you aren't supporting call/cc
2021-06-04 14:45:18 companion_cube> zozozo: what comes after flambda? something with a control flow graph already?
2021-06-04 14:45:36 zozozo> companion_cube: after flambda, it's cmm
2021-06-04 14:46:07 d_bot> <colin> been a while since I've toyed with CPSing compilers because very few go the full mile with the whole "no runtime stack" - they go the chicken route and use it as a GC nursery because they can't get their C compiler to do the strict (tail) call -> jumps that CPS requires and LLVM certainly can't handle CPS so you're just stuck writing your own back-end each time
2021-06-04 14:46:17 zozozo> (fun factoid: cmm quite literraly means C minus minus, :p )
2021-06-04 14:46:56 d_bot> <ggole> If the continuations are second class as in this example, then you can probably linearise to SSA fairly successfully
2021-06-04 14:47:25 companion_cube> hmm so cmm still has function calls and expressions, but no types, right?
2021-06-04 14:47:33 d_bot> <colin> I just think going from ANF -> LLVM (SSA) is simpler
2021-06-04 14:47:41 d_bot> <ggole> Although there's the usual complications of closure conversion and whatnot because LLVM is first order
2021-06-04 14:48:10 d_bot> <colin> Oleg seems to have some strong views on actually doing faithful compilation of CPS as well, along the lines of "whole-program continuations are never useful" and uh "the garbage collector doesn't like this" etc. paraphrasing (perhaps inaccurately) here
2021-06-04 14:48:21 zozozo> companion_cube: cmm has very minimal types (basically it says whether a value can/should be scanned)
2021-06-04 14:48:39 d_bot> <ggole> Well, CPS as a compiler IL is a different storly to exposing continuations reified as functions
2021-06-04 14:48:42 companion_cube> yeah, that's not typing ;)
2021-06-04 14:49:20 companion_cube> but there you eliminate continuations again, right? towards some sort of static jump, like local exceptions?
2021-06-04 14:49:27 zozozo> yup
2021-06-04 14:49:38 zozozo> cmm has static jumps and flambda continuations maps perfectly to that
2021-06-04 14:49:50 zozozo> (ofc continuations that are used exactly once can be inlined)
2021-06-04 14:50:23 companion_cube> right
2021-06-04 14:50:32 d_bot> <ggole> Either a return or a jump
2021-06-04 14:50:36 d_bot> <colin> this discussion is urging me to actually go and read Shivers' k-CFA stuff since I've always just avoided any real detail/proposed benefit of program transformations in CPS
2021-06-04 14:50:39 companion_cube> you can still use static jumps for patmathc and stuff
2021-06-04 14:50:54 d_bot> <ggole> Or maybe an exception handler if double-barrelled CPS
2021-06-04 14:51:18 zozozo> flambda actually has double-barrelled CPS
2021-06-04 14:51:22 zozozo> (flambda2)
2021-06-04 14:51:47 d_bot> <ggole> That makes sense, rather than duplicating all of the control constructs
2021-06-04 14:51:51 d_bot> <ggole> And optims on them
2021-06-04 14:52:40 d_bot> <colin> what's double-barrelled, just doing the CPS twice?
2021-06-04 14:52:58 companion_cube> wait
2021-06-04 14:53:03 companion_cube> does the second handler also work for effects?
2021-06-04 14:53:10 companion_cube> or wolud there be a third handler?
2021-06-04 14:53:11 d_bot> <ggole> Along with the usual return continuation you pass another continuation which is the error/exn path
2021-06-04 14:53:42 d_bot> <colin> ah
2021-06-04 14:54:19 zozozo> companion_cube: effects as in algebraic effects (cf multicore) ?
2021-06-04 14:54:29 companion_cube> yes
2021-06-04 14:54:34 companion_cube> runtime effects anyway
2021-06-04 14:54:38 companion_cube> the one shot continuations :)
2021-06-04 14:54:43 zozozo> that's a very good question
2021-06-04 14:55:21 companion_cube> I think exceptions will just be another effect, except in the type system, so you can probably only have 2
2021-06-04 14:55:22 d_bot> <colin> who funds OCamlPro? INRIA? Jane Street? or is it its own company
2021-06-04 14:57:27 d_bot> <Christophe> I have a question about the change log of 4.13. The change "type check x |> f and f @@ x as (f x) ` is marked as breaking change. What are the consequences of that change actually? (sorry for interrupting a very interesting conversation)
2021-06-04 14:59:15 companion_cube> it might change a few things in a subtle way
2021-06-04 14:59:22 companion_cube> like `f x` can be `f ?a ?b x`
2021-06-04 14:59:26 companion_cube> if f has optional arguments
2021-06-04 14:59:43 zozozo> @colin : OCamlPro is its own company, and janestreet is one client of ocamlpro
2021-06-04 15:00:51 d_bot> <colin> Ah, I see, I was looking at compiler jobs at Jane Street (wishful thinking) but now they don't seem like they'd be as interesting as this flambda2 stuff (unless there's some ties between both companies)
2021-06-04 15:01:19 d_bot> <Christophe> Ah yes, I didn't think of optional arguments, thanks!
2021-06-04 15:01:37 companion_cube> aren't they funding flambda2? :D
2021-06-04 15:01:37 zozozo> @colin : well, the work on flambda2 is funded by JaneStreet, ^^
2021-06-04 15:41:47 d_bot> <EduardoRFS> type check of `x |> f` as `f x` is something I was not expecting but I really appreciate
2021-06-04 15:42:00 d_bot> <EduardoRFS> now we need to type check `let x = y` in the opposite order
2021-06-04 15:43:25 d_bot> <EduardoRFS> can we implement this kind of subtyping or would it be unsound?
2021-06-04 15:43:26 d_bot> <EduardoRFS> ```ocaml
2021-06-04 15:43:27 d_bot> <EduardoRFS> module X : sig
2021-06-04 15:43:28 d_bot> <EduardoRFS> type 'a t = private 'a
2021-06-04 15:43:30 d_bot> <EduardoRFS> end = struct
2021-06-04 15:43:31 d_bot> <EduardoRFS> type 'a t = 'a
2021-06-04 15:43:32 d_bot> <EduardoRFS> end
2021-06-04 15:43:34 d_bot> <EduardoRFS> let add (a : int X.t) (b : int) = a + b
2021-06-04 15:43:35 d_bot> <EduardoRFS> ```
2021-06-04 16:03:27 d_bot> <octachron> This is already implemented, with an explicit coercion as usual: `let add a b = (a:int X.t:>int) + b`
2021-06-04 19:56:48 hackinghorn> hi
2021-06-04 19:57:03 hackinghorn> how do I run commands like ls for linux in ocaml?
2021-06-04 19:59:38 dh`> there's a binding for system() somewhere
2021-06-04 19:59:40 hackinghorn> oh, fileutils work
2021-06-04 19:59:56 hackinghorn> got it, thanks
2021-06-04 23:15:51 d_bot> <EduardoRFS> Why not implicit?
2021-06-04 23:20:48 companion_cube> There are no implicit coercions in ocaml
2021-06-04 23:51:53 d_bot> <dj charlie> 👀 nice to see the stdlib increasingly fleshed out feels good
2021-06-05 00:39:14 companion_cube> like what?
2021-06-05 00:57:05 d_bot> <dj charlie> like fold_left and fold_right with the strings
2021-06-05 00:57:12 d_bot> <dj charlie> the math functions for floats
2021-06-05 01:05:15 companion_cube> Lolol ok
2021-06-05 01:05:33 companion_cube> Fold on string, heh?
2021-06-05 01:05:43 companion_cube> Forgot that that wasn't there
2021-06-05 01:06:10 d_bot> <dj charlie> hey guy who wrote his own stdlib
2021-06-05 01:06:13 d_bot> <dj charlie> it's pretty cool to me ok?
2021-06-05 07:50:23 companion_cube> :D it is, it is
2021-06-05 09:57:02 tane> howdy! found the way
2021-06-05 11:46:29 d_bot> <giga_08> anyone familiar with ocaml verification? termination in particular
2021-06-05 12:03:08 d_bot> <darrenldl> small code or large projects?
2021-06-05 12:41:30 d_bot> <giga_08> small code
2021-06-05 13:02:29 companion_cube> @giga_08 you could give a look at try.imandra.ai (it's proprietary but termination checking is def. sth interesting)
2021-06-05 18:18:14 d_bot> <TheSkeward> learning ocaml and I occasionally giggle to myself because "O Caml! My Camel!" will pop into my head like a line from some sort of desert-themed walt whitman poem
2021-06-05 18:19:38 companion_cube> `my $camel` sounds more like perl, tbh
2021-06-05 18:21:20 d_bot> <TheSkeward> perls before swine
2021-06-05 23:22:45 kluk> how do I start using DynArray? I tried include DynArray, include Extlib, nothing works
2021-06-05 23:23:07 companion_cube> you need to have it in your dune file, if you use dune
2021-06-05 23:23:10 companion_cube> and to install it in the first place
2021-06-05 23:24:09 kluk> I don't know what dune is yet, I'm still a beginner at OCaml. how do I install DynArray? with opam right?
2021-06-05 23:24:51 companion_cube> hmmm if you're that beginner, maybe take a look at a book
2021-06-05 23:24:55 companion_cube> there's a lot to explain :/
2021-06-05 23:26:43 kluk> I just wanted to play around on the ocaml repl with some arrays... not looking for making a project, folders, dune stuff, any of that, if possible to avoid at this point. Is it possible to just play with the OCaml language to learn it and not worry about how it mixes up with unix?
2021-06-05 23:27:56 companion_cube> ah well, sure, just type `ocaml`
2021-06-05 23:28:07 companion_cube> but Dynarray is a 3rd party library for vectors/resizable arrays
2021-06-05 23:28:16 companion_cube> it's not exactly a central type in OCaml :
2021-06-05 23:28:17 companion_cube> :p
2021-06-05 23:29:14 kluk> yes I can get to the repl, but I wanted to play with arrays first without worrying about packages, does that make sense? I wanted to explore OCaml the language first, like a try.ocaml.org sort of thing if that makes sense... I wanted to have some fun with the language and learn it and not have to think about packages and managing projects for a little
2021-06-05 23:30:40 kluk> I need a stack whose elements can be randomly accessed by an integer so I just happen to have an exact use case for arrays, but I am open to suggestions
2021-06-05 23:34:07 companion_cube> arrays are in the stdlib
2021-06-05 23:34:17 companion_cube> not dynamic arrays
2021-06-05 23:34:31 companion_cube> but yeah, a stack with indexing is a good use case
2021-06-05 23:34:55 kluk> companion_cube :)
2021-06-06 00:03:27 d_bot> <Bluddy> IMO vectors should replace arrays as a primary data type in the language
2021-06-06 00:04:29 companion_cube> why "replace"?
2021-06-06 00:04:42 companion_cube> I think it'd be nice to be able to build them safely
2021-06-06 00:04:47 d_bot> <Bluddy> as the *primary* data type
2021-06-06 00:04:51 companion_cube> but otherwise, they have some overhead
2021-06-06 00:05:03 companion_cube> arrays are simpler as they're always fully initialized
2021-06-06 00:05:11 d_bot> <Bluddy> yeah the overhead is very minor though
2021-06-06 00:05:34 d_bot> <Bluddy> very few languages have arrays as their primary data structure
2021-06-06 00:05:48 d_bot> <Bluddy> python's lists are vectors
2021-06-06 00:05:49 companion_cube> I mean… java?
2021-06-06 00:06:12 companion_cube> I think the problem is the GC, because in a vector you need some unitialized space
2021-06-06 00:06:15 companion_cube> even in rust it's quite dirty
2021-06-06 00:06:46 d_bot> <Bluddy> hmm
2021-06-06 00:07:10 companion_cube> it's hard to do well without a bit of Obj currently :/
2021-06-06 00:08:53 d_bot> <Bluddy> ok so I guess python/ruby's bias may be due to their reference counting
2021-06-06 00:09:11 companion_cube> also they're insanely high level and slow :p
2021-06-06 00:09:39 d_bot> <Bluddy> yeah but that's beside the point. java has array, c# has array vs List (really a vector)
2021-06-06 00:09:54 companion_cube> java has ArrayList, but only for boxed types
2021-06-06 00:09:59 companion_cube> the primitive on the JVM is arrays, same as OCaml
2021-06-06 00:10:07 companion_cube> (except with unsound variance)
2021-06-06 00:10:12 d_bot> <Bluddy> right
2021-06-06 00:10:30 d_bot> <Bluddy> ok so yeah I think I'm just using python too much recently
2021-06-06 00:11:00 d_bot> <Bluddy> javascript also has array as its primary type
2021-06-06 00:11:07 companion_cube> remember that in OCaml, an array is *one* word of overhead
2021-06-06 00:11:12 d_bot> <Bluddy> so are python and ruby really the exceptions?
2021-06-06 00:11:26 companion_cube> as far as primitive types go? I'm not sure
2021-06-06 00:13:25 d_bot> <EduardoRFS> JS arrays are dynamic arrays / vectors
2021-06-06 00:13:34 d_bot> <EduardoRFS> and the implementation of it is really all over the place
2021-06-06 00:13:51 d_bot> <Bluddy> perl has dynamic arrays. also reference counted
2021-06-06 00:14:18 companion_cube> _scripting languages_ were primitives are all in C
2021-06-06 00:15:51 d_bot> <Bluddy> interesting. and it's gc'd.
2021-06-06 00:16:30 d_bot> <Bluddy> @companion_cube GC is only an issue if you don't have a bit to tell the GC not to scan the uninitialized memory. If OCaml had it, it wouldn't be an issue.
2021-06-06 00:16:58 companion_cube> sure, if you entirely rewrite the GC so it's not just based on the initial tag… :p
2021-06-06 00:17:13 d_bot> <EduardoRFS> but JS objects nowadays operates like OCaml blocks, adding and removing field is generally a bad idea because of the types, while it is possible that can trigger a whole lot of compiled and optimized code to be invalidated
2021-06-06 00:17:15 d_bot> <Bluddy> hmm.. no I guess you need to build it into the GC process itself so it knows how to process the vector
2021-06-06 00:17:24 d_bot> <Bluddy> so it looks at length vs capacity
2021-06-06 00:17:26 d_bot> <EduardoRFS> well we can extend the object header
2021-06-06 00:17:26 companion_cube> (well for a vector you'd need to fit 2 sizes in one, basically: capacity, and actual size)
2021-06-06 00:17:35 d_bot> <EduardoRFS> I'm looking on it during the shower
2021-06-06 00:17:52 d_bot> <Bluddy> yeah a bit is not enough, you need to teach the GC about a new kind of object
2021-06-06 00:18:00 companion_cube> also remember that vectors are 2 levels of indirection, not one
2021-06-06 00:18:06 companion_cube> one to the {len,capacity,ptr}
2021-06-06 00:18:12 companion_cube> + the pointer itself
2021-06-06 00:18:31 companion_cube> but you've got to have this level of indirection so you can change the underlying array/pointer
2021-06-06 00:19:02 d_bot> <Bluddy> that's true
2021-06-06 00:19:36 companion_cube> so that's non trivial overhead compared to a basic array, when all you need is an array
2021-06-06 00:19:53 d_bot> <EduardoRFS> but that access can be mostly reduced if you know the cell size at compile time
2021-06-06 00:19:56 d_bot> <Bluddy> the problem is that you very rarely need an array
2021-06-06 00:20:38 d_bot> <Bluddy> if your primary type is a list, all an array gives you is mutability + O(1) access to any element. it's good, but the lack of ability to extend it is annoying
2021-06-06 00:20:46 d_bot> <Bluddy> if you're doing mutable stuff, you almost always want to extend it
2021-06-06 00:20:56 companion_cube> idk, it's nice in ASTs for example
2021-06-06 00:21:03 companion_cube> I agree that often a vector is also useful
2021-06-06 00:22:19 d_bot> <EduardoRFS> I wonder if having an unrolled linked list with some tricks wouldn't be enough for almost all cases
2021-06-06 00:22:53 companion_cube> for mutable stuff we just should have a good vector
2021-06-06 00:22:59 d_bot> <EduardoRFS> like couple cells all cache aligned + pointers to additional cells if they were created all together so that you can do O(1) after a List.map
2021-06-06 00:23:03 companion_cube> for immutable stuff, we _could_ use HAMT… but well
2021-06-06 00:25:01 d_bot> <EduardoRFS> copy on write is the solution to all problems
2021-06-06 00:25:11 companion_cube> noooo :D
2021-06-06 00:27:33 d_bot> <EduardoRFS> computers are fun, nowadays you have an ALU and caching inside of the MMU
2021-06-06 00:28:05 d_bot> <EduardoRFS> lisp machine to rule them all
2021-06-06 00:51:48 d_bot> <Bluddy> companion_cube: what do you do to prevent the GC from scanning the uninitialized vector area?
2021-06-06 00:53:27 d_bot> <EduardoRFS> If it is set to 0x0 the GC should just behave normally, it's a block of tag 0, size 0
2021-06-06 00:57:50 companion_cube> @Bluddy in containers, indeed, I fill the vector with 0
2021-06-06 00:58:03 companion_cube> or 0.0 if it's a float array 🙄
2021-06-06 01:34:37 d_bot> <Bluddy> ugh yeah that's bad
2021-06-06 01:34:57 companion_cube> not like we have a better option, imhp
2021-06-06 01:34:59 companion_cube> imho
2021-06-06 01:37:39 d_bot> <Bluddy> I wonder what other languages do
2021-06-06 01:37:44 d_bot> <Bluddy> ones with GC
2021-06-06 01:40:49 companion_cube> well, java fills with null I imagine
2021-06-06 01:40:54 companion_cube> boxed primitives and all that
2021-06-06 01:41:03 companion_cube> D… probably does ugly stuff?
2021-06-06 01:41:10 companion_cube> Go has 0 values for all types, so that's easy
2021-06-06 01:41:31 companion_cube> and the scripting stuff has nil/None/whatever to fill the blanks
2021-06-06 01:42:17 d_bot> <Bluddy> at the Obj level it would be nice if you could have a contiguous array where the size is the length, and right after that you'd place a string header with the remaining size
2021-06-06 01:42:38 companion_cube> you'd have to move the header every time you push/pop? :/
2021-06-06 01:42:48 d_bot> <Bluddy> not a huge deal. same cache line
2021-06-06 01:43:07 companion_cube> ideally push should be as simple and inlineable as possible :p
2021-06-06 01:43:53 d_bot> <Bluddy> still pretty simple. copy header over, reduce string size
2021-06-06 01:44:34 companion_cube> + code path for possible resize… that's a lot more than just a normal push
2021-06-06 01:44:37 d_bot> <Bluddy> pop doesn't need to do anything because you can just zero data out at that point
2021-06-06 01:45:12 d_bot> <Bluddy> that code path is there regardless
2021-06-06 01:45:38 d_bot> <Bluddy> a multi-push function can be more efficient as it can do the header copy once
2021-06-06 01:45:59 companion_cube> pop still needs to copy the header back
2021-06-06 01:46:58 d_bot> <Bluddy> yeah I guess that's true. the only annoying thing about the header is the size counter
2021-06-06 01:47:20 companion_cube> I'd rather wish OCaml had a primitive for partially initialized arrays, and that's it
2021-06-06 01:47:22 d_bot> <Bluddy> but it should be doable with a couple of instructions
2021-06-06 01:47:43 d_bot> <Bluddy> well that's not going to happen anytime soon
2021-06-06 01:48:23 d_bot> <Bluddy> it can happen in the 64-bit runtime, but the 32-bit cannot handle it
2021-06-06 01:48:38 d_bot> <Bluddy> because you need that extra header space for the size
2021-06-06 01:48:39 companion_cube> not sure how that's related :p
2021-06-06 01:49:03 companion_cube> I just want an API for the array with a valid 0 inside
2021-06-06 01:49:16 companion_cube> that doesn't force me to Obj.magic to see if it's a float array or normal array
2021-06-06 01:49:16 d_bot> <Bluddy> valid 0?
2021-06-06 01:49:26 companion_cube> a valid object for this array
2021-06-06 01:49:42 companion_cube> a valid object for this array, _as seen by the GC_
2021-06-06 01:51:38 d_bot> <Bluddy> is this another wish? to deal more easily with float arrays? or is it related?
2021-06-06 01:51:58 companion_cube> it's related because it's the only reason I have to use Obj in containers :p
2021-06-06 01:52:04 companion_cube> (or one of the few, I can't remember)
2021-06-06 01:52:20 companion_cube> to be able to implement a vector
2021-06-06 01:52:39 d_bot> <Bluddy> but it doesn't deal with this particular issue
2021-06-06 01:52:47 d_bot> <Bluddy> I mean they're phasing out float arrays
2021-06-06 01:52:57 companion_cube> yeah that'll be nice
2021-06-06 01:53:16 companion_cube> without float arrays one could always fill the array with 0
2021-06-06 01:53:29 companion_cube> since the GC doesn't mind 0
2021-06-06 01:53:55 d_bot> <Bluddy> yeah I see that piece of code now
2021-06-06 01:54:12 d_bot> <Bluddy> let fill_with_junk_ (a:_ array) i len : unit =
2021-06-06 01:54:15 companion_cube> yep yep
2021-06-06 01:54:27 d_bot> <Bluddy> https://github.com/c-cube/ocaml-containers/blob/95e96fb5e12558fa5b1e907a8e315d8c859c23b8/src/core/CCVector.ml#L27
2021-06-06 01:54:29 companion_cube> always interested in better ideas
2021-06-06 02:04:20 d_bot> <ggole> For 64-bit machine zero (not OCaml zero) is fine for float arrays as well
2021-06-06 02:05:07 d_bot> <ggole> So you might be able to get away with coercing to `float array` and then filling with `0.0`
2021-06-06 02:05:26 d_bot> <ggole> However, the recent `FloatArray` stuff might kill that idea
2021-06-06 02:08:30 d_bot> <ggole> The no naked pointer changes might also be trouble
2021-06-06 03:32:21 d_bot> <aotmr> Hi everyone! I'm a 3rd-year CS student making personal explorations into programming languages with an emphasis on functional and concatenative languages, as well as metaprogramming and optimizing compilers.
2021-06-06 03:33:32 d_bot> <aotmr> I'm currently using OCaml to build a functional FORTH interpreter that I hope to shape into a general optimizing FORTH compiler
2021-06-06 03:33:49 d_bot> <aotmr> And right now I'm investigating to what extent I can express FORTH concepts in OCaml
2021-06-06 03:42:01 d_bot> <ggole> Hmm, they're pretty different
2021-06-06 03:43:21 d_bot> <ggole> OCaml code is very variable heavy, which seems to be at odds with the Forth philosophy of communicating between tiny bits with the stack
2021-06-06 03:43:38 d_bot> <aotmr> So, for example, inside my VM state is a list representing the current data stack.
2021-06-06 03:43:38 d_bot> <aotmr> ```ocaml
2021-06-06 03:43:40 d_bot> <aotmr> type state = {
2021-06-06 03:43:41 d_bot> <aotmr> ds : Int.t list;
2021-06-06 03:43:42 d_bot> <aotmr> (* ... *)
2021-06-06 03:43:44 d_bot> <aotmr> }
2021-06-06 03:43:45 d_bot> <aotmr> ```
2021-06-06 03:43:46 d_bot> <aotmr> Stack-based interpreters are excellent matches for programming languages with pattern matching facilities, as it turns out.
2021-06-06 03:44:15 d_bot> <aotmr> ```ocaml
2021-06-06 03:44:16 d_bot> <aotmr> type opcode =
2021-06-06 03:44:17 d_bot> <aotmr> | Lit of Int.t
2021-06-06 03:44:19 d_bot> <aotmr> | Add
2021-06-06 03:44:20 d_bot> <aotmr> | Dot
2021-06-06 03:44:21 d_bot> <aotmr> (* ... *)
2021-06-06 03:44:23 d_bot> <aotmr> ```
2021-06-06 03:44:41 d_bot> <aotmr> Let's define a small opcode set for our VM: push a literal to the stack, add the top two on the stack, and print the top on the stack (`Dot`)
2021-06-06 03:46:01 d_bot> <aotmr> Now, here's where OCaml's list matching becomes very elegant. Let's define a function, `execute`, that takes a state and an opcode and returns a new state that reflects having executed the opcode.
2021-06-06 03:46:01 d_bot> <aotmr> ```ocaml
2021-06-06 03:46:03 d_bot> <aotmr> let execute st = function
2021-06-06 03:46:04 d_bot> <aotmr> | Lit i -> { st with ds = i::st.ds }
2021-06-06 03:46:05 d_bot> <aotmr> | Add -> (* ... *)
2021-06-06 03:46:07 d_bot> <aotmr> | Dot -> (* ... *)
2021-06-06 03:46:08 d_bot> <aotmr> ```
2021-06-06 03:46:32 d_bot> <colin> awaiting the IRC users who'll ask you to read the channel description
2021-06-06 03:46:43 d_bot> <aotmr> Aw shit 🤦‍♂️
2021-06-06 03:46:49 d_bot> <colin> :p
2021-06-06 03:46:52 zozozo> @aotmr : code blocks from discord do not render great on the irc side of this channel, so it'd be best if you could use some paste website to link to code when there are more than a few lines, ^^
2021-06-06 03:46:59 d_bot> <aotmr> There it is
2021-06-06 03:47:08 zozozo> haha, XD
2021-06-06 03:47:32 d_bot> <aotmr> Well all that goes to say
2021-06-06 03:47:32 d_bot> <aotmr> You can express stack operations using pattern matching.
2021-06-06 03:48:43 d_bot> <colin> if you think that's cute, you'll like a similar idea in dependent typing where you can express stack changes (as a list) indexing the opcodes or something similar
2021-06-06 03:48:44 d_bot> <aotmr> For example, to swap the top two items on the stack, you'd use the record update syntax
2021-06-06 03:48:45 d_bot> <aotmr> `{ st with ds = match st.ds with a:🅱️:tl -> b:🅰️:tl | _ -> assert false }`
2021-06-06 03:48:46 d_bot> <aotmr> Last code block for the time being, I promise 😅
2021-06-06 03:49:17 d_bot> <aotmr> (And you can also use `let` matching, I've found, but I can't get ocaml to stop complaining even though I fully understand it'll crash if there aren't enough elements)
2021-06-06 03:49:30 d_bot> <aotmr> Oh, have a paper on that?
2021-06-06 03:49:54 d_bot> <aotmr> I'm wanting to see how high-level I can get with forth and still generate good code for small microprocessors--say, for NES and game boy dev
2021-06-06 03:50:06 d_bot> <colin> no, just thought it was very cute when I studied Agda at university, relevant construction of Hutton's razor can be found at https://github.com/fredrikNordvallForsberg/CS410-20/blob/master/Coursework/Two.agda#L492-L506 what you're saying just reminded me of it, not really relevant just in case you wanted to see cute things
2021-06-06 03:50:15 zozozo> @aotmr : small one-line blocks of code (like your last one) are mostly okay I'd say, ^^
2021-06-06 03:50:48 d_bot> <aotmr> Oh I'll look at it never the less, thanks.
2021-06-06 03:50:49 d_bot> <aotmr> Forth has its own concept of combinators and I want to try to compile those efficiently
2021-06-06 03:52:04 d_bot> <aotmr> Honestly I'd say OCaml is distantly related to FORTH just usagewise, there's a similar concept of "pipelining". Where in FORTH you'd write a series of words, passing state between them implicitly on the stack, you do the same in Ocaml when expressing a `|>` or `@@` pipeline
2021-06-06 03:54:16 d_bot> <aotmr> This is an interesting idea as, while FORTH is typically untyped, I could use this concept to track the entire lifetimes of values throughout a program
2021-06-06 03:55:20 d_bot> <colin> it's just a nice encoding of how the stack ought to change, helps the type system help you implement it correctly (though not a full specification by any means, just a cute stack requirement)
2021-06-06 03:55:27 d_bot> <ggole> There are some interesting typed concatenative langs
2021-06-06 03:55:47 d_bot> <ggole> Kitten and Cat
2021-06-06 03:55:48 d_bot> <aotmr> I've finally taken the forth-pill so to speak because I finally understand how to implement a compiler for the language
2021-06-06 03:56:18 d_bot> <colin> a whole new world.mp3 https://llvm.moe/
2021-06-06 03:56:29 d_bot> <colin> see past stack-based paradigm
2021-06-06 03:56:58 d_bot> <aotmr> Well, once I have a compiler for a stack-based VM that opens the door to using it as an intermediate representation
2021-06-06 03:57:14 d_bot> <colin> would there be any benefit
2021-06-06 03:57:27 d_bot> <colin> I, admittedly, have never seen the appeal of stack-based languages for general programming
2021-06-06 03:57:32 d_bot> <colin> I used to write postscript by hand recreationally
2021-06-06 03:57:35 d_bot> <colin> but that's about it
2021-06-06 03:57:46 d_bot> <aotmr> It's admittedly kind of recreational
2021-06-06 03:58:10 d_bot> <aotmr> I think the real strength is in the way you can build an entire system from the ground up by hand and know every moving part
2021-06-06 03:59:32 d_bot> <aotmr> You could write an optimizing compiler x86 in, oh, a month
2021-06-06 04:00:51 d_bot> <colin> sadly the majority of back-end optimisations for x86 are really just suffering
2021-06-06 04:00:59 d_bot> <aotmr> OCaml's own VM is stack-based so it's kind of circular
2021-06-06 04:01:09 d_bot> <colin> yeah but that's just the bytecode OCaml stuff
2021-06-06 04:01:12 d_bot> <aotmr> Oh yeah no x86 is a horrible architecture to program for
2021-06-06 04:01:19 d_bot> <aotmr> Sure but it's still a neat thought
2021-06-06 04:01:25 d_bot> <aotmr> But I digress
2021-06-06 04:01:28 d_bot> <colin> I used to be confused as to why Xavier Leroy's earlier work seemed to focus rather specifically on bytecode stack machines as the target of Camls
2021-06-06 04:01:51 d_bot> <colin> but then someone said like "it was research into creating a tactic computational kernel for some proof assistant"
2021-06-06 04:02:01 d_bot> <colin> not sure how true that is, perhaps someone here can clarify if that's nonsense
2021-06-06 04:02:07 d_bot> <colin> and Xavier just really likes stack machines
2021-06-06 04:02:56 d_bot> <aotmr> So, it could be that you can take advantage of immutable VM states in unit testing
2021-06-06 04:03:13 d_bot> <aotmr> And using it to accelerate the general process
2021-06-06 04:04:16 d_bot> <aotmr> If you wanted to do an exhaustive search of the program P with inputs a, b, c..., you could run P over every possible value of a, b, c
2021-06-06 04:05:19 d_bot> <aotmr> That is, we're trying to find a, b, c... that causes P to fail
2021-06-06 04:06:00 d_bot> <ggole> There's actually some tooling for that
2021-06-06 04:06:02 d_bot> <ggole> See Crowbar
2021-06-06 04:06:08 d_bot> <aotmr> One way to speed up that process is to memoize the VM state, I think
2021-06-06 04:06:44 d_bot> <ggole> It's not exhaustive search, but coverage-feedback guided random generation
2021-06-06 04:06:47 d_bot> <aotmr> If we find a "success" set of (a, b, c...), we could maybe remember all of the previous states of the VM and if we ever encounter them again we can stop early
2021-06-06 04:07:14 d_bot> <aotmr> But that would blow up your space requirements for little speedup, I'd think
2021-06-06 04:07:17 d_bot> <colin> can see why that'd help (as a form of concolic execution) but I think the accepted reality in industry is that Google fuzz their own software over billions of instances using AFL on dozens of Google cloud instances and just consider that alright
2021-06-06 04:08:00 d_bot> <aotmr> My other use case is of a rewindable debugger where you can undo all the way back to the start of the program
2021-06-06 04:08:51 d_bot> <colin> time travel debugging is pretty cool
2021-06-06 04:09:07 d_bot> <aotmr> That also brings to mind the idea of a rewindable game engine, I think rewind mechanics are pretty cool in theory
2021-06-06 04:09:12 d_bot> <colin> I always wanted a clean injection mechanism for debugging
2021-06-06 04:09:27 d_bot> <colin> hot reloading debugging stubs, that kinda thing
2021-06-06 04:09:54 d_bot> <aotmr> I'm still not entirely familiar with the mechanics of debuggers
2021-06-06 04:10:07 d_bot> <colin> syscalls and suffering™
2021-06-06 04:10:36 d_bot> <aotmr> I'm under the impression that, if you can execute from RAM, you can at least single-step on pretty much any CPU
2021-06-06 04:11:58 d_bot> <colin> yeah there's architectural single step stuff provided by most systems; *nix has PTRACE_SINGLESTEP
2021-06-06 04:12:02 d_bot> <aotmr> If you want to single-step the instruction at a given address, then you'd write some kind of "breakpoint" opcode (or, crudely, even just an absolute jump) directly following it, but you'd have to know the length of the opcode beforehand
2021-06-06 04:12:27 d_bot> <aotmr> But I'd hope consumer CPUs can single-step in silicon by now 😅
2021-06-06 04:12:28 d_bot> <colin> variable length encoding is just one part of suffering in writing x86(_64) tooling, yes
2021-06-06 04:12:42 d_bot> <aotmr> Oh yeah I guess debugging has to be infinitely easier on a fixed-length RISC
2021-06-06 04:13:14 d_bot> <aotmr> Imagine if x86 had an instruction that only decoded the length of an instruction at a given address
2021-06-06 04:13:18 d_bot> <colin> I suppose there's other challenges, given the domain where RISC microprocessors are probably most prevalently being debugged
2021-06-06 04:13:39 d_bot> <colin> who knows, they might, Intel has a ton of hidden instructions and their manual doesn't even document some of them accurately
2021-06-06 04:13:46 d_bot> <aotmr> You're right, there probably is.
2021-06-06 04:14:06 d_bot> <ggole> There's tons of hardware support for debugging
2021-06-06 04:14:09 d_bot> <colin> it's common for trampoline hooking code to come with a "variable length decoder" as a form of minimal disassembler
2021-06-06 04:14:13 d_bot> <ggole> Watch registers and that kind of thing
2021-06-06 04:14:26 d_bot> <ggole> Pretty complicated from what I understand
2021-06-06 04:14:27 d_bot> <colin> to know how many bytes to replace w/ their placed `jmp` or `push ...; ret` etc.
2021-06-06 04:16:26 d_bot> <colin> but yeah, can't lie
2021-06-06 04:16:34 d_bot> <colin> confused how we went from stack langs to all this
2021-06-06 04:16:58 d_bot> <colin> what is your ambition, aotmr, to write a forth interpreter/compiler?
2021-06-06 04:19:34 d_bot> <aotmr> Just to do it, I guess. I think it's interesting to build a software stack nearly from the bottom up--or nearly so
2021-06-06 04:19:53 d_bot> <colin> what, in Forth?
2021-06-06 04:20:04 d_bot> <aotmr> I mean, build a Forth itself from the bottom up
2021-06-06 04:20:14 d_bot> <colin> oh alright
2021-06-06 04:20:29 d_bot> <aotmr> In theory it can even be possible to replace the Ocaml parts with Forth themselves
2021-06-06 04:21:15 d_bot> <aotmr> Though "bootstrapping"
2021-06-06 04:21:47 d_bot> <aotmr> First, I'd write a forth compiler in ocaml
2021-06-06 04:22:07 d_bot> <aotmr> Then, translate the compiler to forth
2021-06-06 04:22:17 d_bot> <aotmr> Compile the compiler-in-forth with the compiler-in-ocaml
2021-06-06 04:22:30 d_bot> <aotmr> And then I have a forth compiler, compiled and written in forth
2021-06-06 04:22:36 d_bot> <colin> can graduate to something hacky like JITing the FORTH then using C FFI to map the code and somehow return opaque caml values back to the user as callables within OCaml
2021-06-06 04:22:55 d_bot> <colin> galaxy brain interplay
2021-06-06 04:23:14 d_bot> <aotmr> That sounds terrifying
2021-06-06 04:23:22 d_bot> <colin> -ly based
2021-06-06 04:23:28 d_bot> <aotmr> You got it
2021-06-06 04:23:44 d_bot> <colin> don't actually know if you can do that
2021-06-06 04:23:52 d_bot> <colin> on the conceptual level, you certainly can with enough hacks
2021-06-06 04:24:21 d_bot> <aotmr> Probably the easiest way to "JIT" stack code is just to apply peephole optimization
2021-06-06 04:24:34 d_bot> <colin> can't lie, I hate stacks
2021-06-06 04:24:56 d_bot> <aotmr> The compiler writer writes manual superwords that implement a series of smaller words in a faster way
2021-06-06 04:26:26 d_bot> <aotmr> For example, replacing `>r + r>` with the much shorter machine code for the equivalent sequence that just adds the top element of the stack to the third
2021-06-06 04:42:07 d_bot> <BobbyT> Im just marinating in all these high level ideas
2021-06-06 05:58:42 ralu> I am trying to build infer, but I keep getting error about failed dune build. So i can not build dune. Has anyone has any pointers?
2021-06-06 09:38:22 d_bot> <Bluddy> What if we make it so a proper null pointer inside an array means the end of GC scanning?
2021-06-06 10:32:24 d_bot> <Drup> @Bluddy that's not compatible with a bunch of much more interesting representations improvements (like democratizing the Zarith hack, for instance)
2021-06-06 10:52:39 d_bot> <Deadrat> Would lightweight higher kinded types be added to ocaml in the future?
2021-06-06 10:58:32 d_bot> <xvw> With modular immlicits I guess that lightweight higher kinded types will be less useful
2021-06-06 11:08:02 d_bot> <rbrott> There's a nice chapter on that idea in CPDT: <http://adam.chlipala.net/cpdt/html/Cpdt.StackMachine.html>
2021-06-06 11:08:04 d_bot> <Bluddy> @Drup could you explain the 'zarith hack'?
2021-06-06 11:09:03 d_bot> <Deadrat> But they are still years away as I understand?
2021-06-06 11:09:35 d_bot> <Drup> @Bluddy A value of type `Z.t` in zarith is either a normal ocaml integer (63bits usually, etc) or a GMP "big integers"
2021-06-06 11:11:56 d_bot> <Drup> This is achieved by considering the type morally as `int | Big of gmp`. OCaml integers already have a bit put aside for the GC to differentiate them from pointers, so we don't need an extra tag to differentiate between small integers and pointers to a big integer.
2021-06-06 11:12:15 d_bot> <Drup> This is only possible by going through the C FFI
2021-06-06 11:12:29 d_bot> <ggole> Machine zero isn't an `int` or a block though
2021-06-06 11:15:09 d_bot> <Drup> @ggole I can never remember if the tag for integers is 0 or 1.
2021-06-06 11:17:58 d_bot> <ggole> It's 1
2021-06-06 11:18:24 d_bot> <ggole> But even if it were zero, you could set aside a non-valid pointer value to indicate a truncation spot
2021-06-06 11:20:59 d_bot> <Drup> right, I'm not sure how much I like it, but it could work
2021-06-06 11:26:30 d_bot> <ggole> I guess there would have to be an `Array.unsafe_set_terminator` or something, which would be a bit nasty
2021-06-06 11:26:41 d_bot> <ggole> And I dunno what the interaction with bounds checking would be
2021-06-06 11:27:07 d_bot> <ggole> I suspect they would be more trouble than the terminator value itself though
2021-06-06 11:49:23 d_bot> <Bluddy> I need to try it out and see the performance difference.
2021-06-06 11:51:38 d_bot> <Bluddy> it's not automatically clear that setting all the memory is a bad idea
2021-06-06 13:00:48 companion_cube> I'd just like to point out that no one else uses a terminator for vectors, afaik
2021-06-06 13:00:55 companion_cube> it seems like a pretty bad idea :p
2021-06-06 13:05:10 d_bot> <ggole> Most of the other langs with vectors can handle uninitialised memory or keep the bits there without leaks
2021-06-06 13:06:34 companion_cube> and again, it's not that common
2021-06-06 13:06:57 companion_cube> languages that compile to native and have a GC and don't rely on C to implement a ton of datastructures are not plenty
2021-06-06 13:47:15 d_bot> <aotmr> I'm still not entirely used to building data structures in any language *but* C, to be honest--it feels strange
2021-06-06 13:47:52 d_bot> <aotmr> I probably just don't have practice because C is the only language that I use that doesn't have a dynamic array, really
2021-06-06 13:48:49 companion_cube> well OCaml is excellent for implementing a lot of data structures
2021-06-06 13:49:01 companion_cube> vectors just happen to be a bit on the low-level, unsafe memory thingie side
2021-06-06 13:51:37 d_bot> <aotmr> What's a good way to map from a discriminated union to successive integers?
2021-06-06 13:51:43 d_bot> <aotmr> And the other way around?
2021-06-06 13:53:53 companion_cube> ppx_deriving.enum maybe?
2021-06-06 13:54:02 companion_cube> if it's an enum, without payload on the variants, that is.
2021-06-06 13:57:14 d_bot> <aotmr> Hmm
2021-06-06 13:57:14 d_bot> <aotmr> Here's a simpler question: how do I get the "tag" of a sum type?
2021-06-06 13:57:41 companion_cube> you don't :)
2021-06-06 13:57:45 d_bot> <aotmr> I figure I can quickly map integers to most of the opcodes and then manually handle opcodes with a payload
2021-06-06 13:57:47 companion_cube> it's not really specified in the language.
2021-06-06 13:57:48 d_bot> <aotmr> Oh...
2021-06-06 13:57:52 d_bot> <octachron> The simpler and most forward-compatible way is to write the function.
2021-06-06 13:58:11 d_bot> <aotmr> True, but then I'd have to write two functions and keep them in sync manually, or generate the code.
2021-06-06 13:58:35 d_bot> <aotmr> *sigh* Okay then
2021-06-06 13:58:37 companion_cube> the function from integers to variants seems impossible to write
2021-06-06 13:58:45 companion_cube> if they have payloads that is
2021-06-06 13:58:56 d_bot> <aotmr> I'd be converting from a packed representation
2021-06-06 14:01:41 companion_cube> your best chance is codegen indeed
2021-06-06 14:01:53 companion_cube> variant to int: generate a pattern matching function
2021-06-06 14:02:10 companion_cube> int+payload to variant: well, match on the int I guess
2021-06-06 14:04:58 d_bot> <aotmr> Actually wait, I'm wrong
2021-06-06 14:04:58 d_bot> <aotmr> I shouldn't have written the VM with a discriminated union like this anyways
2021-06-06 14:05:13 d_bot> <aotmr> But, I guess I might as well keep a separate encoded and decoded form
2021-06-06 14:10:07 companion_cube> a VM seems like a good use case for C or C++ or rust, ironically
2021-06-06 14:23:33 d_bot> <aotmr> Oh it's definitely more appropriate, but I'm actually making some headway
2021-06-06 14:24:11 d_bot> <aotmr> I haven't played with ocaml in quite some time (OS issues--it didn't work well on Windows for me until quite recently)
2021-06-06 14:24:23 companion_cube> glad to hear it works better now
2021-06-06 14:24:45 d_bot> <aotmr> I mean, it works better now because it's running in WSL 😆
2021-06-06 14:25:44 d_bot> <aotmr> So I'm happy that I remember how to build list to list mappings that produce and consume varying numbers of elements
2021-06-06 15:08:24 d_bot> <aotmr> Cool, so I've figured out how to build an encoder and decoder for a variable-length instruction stream
2021-06-06 18:00:25 kluk> I get "Error: Unbound module Batteries" after doing open Batteries;; on the ocaml repl after having done opam install batteries. what am I missing?
2021-06-06 18:04:03 companion_cube> #require "batteries";;
2021-06-06 18:04:12 companion_cube> (and possibly, before that, #use "topfind";;)
2021-06-06 18:07:13 kluk> Ahhh.. it wasn't clear to me that #use was needed to bring #require but now that I ran it I can see in its blurb that it does do that. Thank you very much.
2021-06-06 18:07:49 companion_cube> also note that if you use `utop` it does the topfind thing directly
2021-06-06 18:08:03 companion_cube> you can also put the blurb in ~/.ocamlinit
2021-06-06 18:11:31 kluk> companion_cube thank you for the .ocamlinit tip
2021-06-06 18:27:10 kluk> companion_cube so now I can use DynArray from Batteries just fine :) thanks so much for the help once again.
2021-06-06 18:35:30 companion_cube> heh

View file

@ -0,0 +1,17 @@
let gen_sexp =
let open! Crowbar in
let ( >|= ) = map in
fix (fun self ->
choose
[
(([ bytes ] : _ gens) >|= fun s -> `Atom s);
([ list self ] >|= fun l -> `List l);
])
let () =
Crowbar.add_test ~name:"ccsexp_csexp_reparse" [ gen_sexp ] (fun s ->
let str = CCCanonical_sexp.to_string s in
match CCCanonical_sexp.parse_string_list str with
| Ok [ s2 ] -> assert (s = s2)
| Ok _ -> failwith "wrong number of sexps"
| Error e -> failwith e)

View file

@ -0,0 +1,3 @@
let () =
Crowbar.add_test ~name:"ccsexp_parse_string_does_not_crash" [ Crowbar.bytes ]
(fun s -> CCSexp.parse_string s |> ignore)

View file

@ -0,0 +1,148 @@
let simple_uchar_to_string (c : Uchar.t) : string =
let c = Uchar.to_int c in
let bits =
Array.make 64 false
|> Array.mapi (fun i _ -> Int.shift_right c (63 - i) land 0x1 <> 0)
in
let char_of_bit_list bits =
let bits = Array.of_list bits in
assert (Array.length bits = 8);
let res = ref 0 in
for i = 0 to 7 do
if bits.(i) then res := !res lor (0x1 lsl (7 - i))
done;
Char.chr !res
in
let get_start_from_right i = Array.get bits (63 - i) in
let chars =
if c <= 0x7F then
[
[
false;
get_start_from_right 6;
get_start_from_right 5;
get_start_from_right 4;
get_start_from_right 3;
get_start_from_right 2;
get_start_from_right 1;
get_start_from_right 0;
];
]
else if c <= 0x7FF then
[
[
true;
true;
false;
get_start_from_right 10;
get_start_from_right 9;
get_start_from_right 8;
get_start_from_right 7;
get_start_from_right 6;
];
[
true;
false;
get_start_from_right 5;
get_start_from_right 4;
get_start_from_right 3;
get_start_from_right 2;
get_start_from_right 1;
get_start_from_right 0;
];
]
else if c <= 0xFFFF then
[
[
true;
true;
true;
false;
get_start_from_right 15;
get_start_from_right 14;
get_start_from_right 13;
get_start_from_right 12;
];
[
true;
false;
get_start_from_right 11;
get_start_from_right 10;
get_start_from_right 9;
get_start_from_right 8;
get_start_from_right 7;
get_start_from_right 6;
];
[
true;
false;
get_start_from_right 5;
get_start_from_right 4;
get_start_from_right 3;
get_start_from_right 2;
get_start_from_right 1;
get_start_from_right 0;
];
]
else if c <= 0x10FFFF then
[
[
true;
true;
true;
true;
false;
get_start_from_right 20;
get_start_from_right 19;
get_start_from_right 18;
];
[
true;
false;
get_start_from_right 17;
get_start_from_right 16;
get_start_from_right 15;
get_start_from_right 14;
get_start_from_right 13;
get_start_from_right 12;
];
[
true;
false;
get_start_from_right 11;
get_start_from_right 10;
get_start_from_right 9;
get_start_from_right 8;
get_start_from_right 7;
get_start_from_right 6;
];
[
true;
false;
get_start_from_right 5;
get_start_from_right 4;
get_start_from_right 3;
get_start_from_right 2;
get_start_from_right 1;
get_start_from_right 0;
];
]
else
failwith "Unexpected case"
in
chars |> List.map char_of_bit_list |> List.to_seq |> String.of_seq
let () =
Crowbar.add_test
~name:"ccutf8_string_uchar_to_bytes_is_same_as_simple_version"
[ Crowbar.range (succ 0x10FFFF) ]
(fun c ->
Crowbar.guard (Uchar.is_valid c);
let c = Uchar.of_int c in
let simple_answer = simple_uchar_to_string c in
let answer =
let buf = ref [] in
CCUtf8_string.uchar_to_bytes c (fun c -> buf := c :: !buf);
!buf |> List.rev |> List.to_seq |> String.of_seq
in
Crowbar.check_eq simple_answer answer)

6
fuzz/clean.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
script_dir=$(dirname $(readlink -f "$0"))
rm -r "$script_dir"/../fuzz-*-input
rm -r "$script_dir"/../fuzz-*-output

9
fuzz/dune Normal file
View file

@ -0,0 +1,9 @@
(executables
(flags
(-w "+a-4-9-29-37-40-42-44-48-50-32-70" -g))
(names
ccsexp_parse_string_does_not_crash
ccutf8_string_uchar_to_bytes_is_same_as_simple_version
ccsexp_csexp_reparse)
(optional)
(libraries crowbar containers))

15
fuzz/list.sh Executable file
View file

@ -0,0 +1,15 @@
#!/bin/bash
script_dir=$(dirname $(readlink -f "$0"))
echo "Building"
dune build @all
echo ""
echo "Fuzzing tests available:"
for file in "$script_dir"/../_build/default/fuzz/*.exe; do
echo "- "$(basename $file | sed 's/\.exe$//')
done

37
fuzz/run.sh Executable file
View file

@ -0,0 +1,37 @@
#!/bin/bash
script_dir=$(dirname $(readlink -f "$0"))
skip_build=$2
if [[ "$skip_build" != "skip_build" ]]; then
echo "Building"
dune build @all
fi
if [[ "$1" == "" ]]; then
echo "Please enter a fuzzing test to run"
exit 1
fi
name=$(echo "$1" | sed 's/\.exe$//' | sed 's/\.ml$//')
echo "Creating input directory"
input_dir="$script_dir"/../"fuzz-""$name""-input"
output_dir="$script_dir"/../"fuzz-""$name""-output"
mkdir -p "$input_dir"
echo "abcd" > "$input_dir"/dummy
if [ -d "$output_dir" ]; then
afl-fuzz -t 1000 -i - -o "$output_dir" "$script_dir"/../_build/default/fuzz/"$name".exe @@
else
mkdir -p "$output_dir"
afl-fuzz -t 1000 -i "$input_dir" -o "$output_dir" "$script_dir"/../_build/default/fuzz/"$name".exe @@
fi

126
fuzz/run_all.sh Executable file
View file

@ -0,0 +1,126 @@
#!/bin/bash
cpu_count=$(grep -c ^processor /proc/cpuinfo)
simul_test_count=$[cpu_count-1]
test_timeout="10m"
script_dir=$(dirname $(readlink -f "$0"))
log_dir="$script_dir"/../fuzz-logs
echo "Building"
dune build @all
echo ""
start_date=$(date "+%Y-%m-%d %H:%M")
start_time=$(date "+%s")
names=()
i=0
for file in "$script_dir"/../_build/default/fuzz/*.exe; do
name=$(basename $file | sed 's/\.exe$//')
names[$i]=$name
i=$[i+1]
done
test_count=${#names[@]}
echo "Fuzzing tests available:"
for name in ${names[@]}; do
echo "- "$name
done
echo ""
echo "Fuzzing start time:" $start_date
echo ""
echo "Starting $test_count tests"
echo ""
mkdir -p "$log_dir"
i=0
while (( $i < $test_count )); do
if (( $test_count - $i >= $simul_test_count )); then
tests_to_run=$simul_test_count
else
tests_to_run=$[test_count - i]
fi
echo "Running $tests_to_run tests in parallel"
for (( c=0; c < $tests_to_run; c++ )); do
name=${names[$i]}
if [[ "$name" != "" ]]; then
echo " Starting $name"
(AFL_NO_UI=1 timeout "$test_timeout" "$script_dir"/run.sh "$name" skip_build > "$log_dir"/"$name".log) &
i=$[i+1]
fi
done
echo "Waiting for $test_timeout"
sleep $test_timeout
echo "Terminating tests"
pkill afl-fuzz
sleep 5
echo ""
echo "$[test_count - i] / $test_count tests remaining"
echo ""
done
end_date=$(date "+%Y-%m-%d %H:%M")
end_time=$(date "+%s")
echo ""
echo "Test end:" $end_date
echo ""
echo "Time elapsed:" $[(end_time - start_time) / 60] "minutes"
test_fail_count=0
tests_failed=()
for name in ${names[@]}; do
output_dir="$script_dir"/../"fuzz-""$name""-output"
crashes_dir="$output_dir"/crashes
if [ -z "$(ls -A $crashes_dir)" ]; then
# crashes dir is empty
:
else
# crashes dir is not empty
test_fail_count=$[$test_fail_count + 1]
tests_failed+=("$name")
fi
done
echo "========================================"
if [[ $test_fail_count == 0 ]]; then
echo "All $test_count tests passed"
exit_code=0
else
echo "$test_fail_count tests failed"
echo ""
echo "List of tests failed :"
for t in ${tests_failed[@]}; do
echo " "$t
done
exit_code=1
fi

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

View file

@ -1,726 +0,0 @@
(* OASIS_START *)
(* DO NOT EDIT (digest: b119194f5742ac2f3cdceac9a223dda7) *)
module OASISGettext = struct
(* # 22 "src/oasis/OASISGettext.ml" *)
let ns_ str =
str
let s_ str =
str
let f_ (str: ('a, 'b, 'c, 'd) format4) =
str
let fn_ fmt1 fmt2 n =
if n = 1 then
fmt1^^""
else
fmt2^^""
let init =
[]
end
module OASISExpr = struct
(* # 22 "src/oasis/OASISExpr.ml" *)
open OASISGettext
type test = string
type flag = string
type t =
| EBool of bool
| ENot of t
| EAnd of t * t
| EOr of t * t
| EFlag of flag
| ETest of test * string
type 'a choices = (t * 'a) list
let eval var_get t =
let rec eval' =
function
| EBool b ->
b
| ENot e ->
not (eval' e)
| EAnd (e1, e2) ->
(eval' e1) && (eval' e2)
| EOr (e1, e2) ->
(eval' e1) || (eval' e2)
| EFlag nm ->
let v =
var_get nm
in
assert(v = "true" || v = "false");
(v = "true")
| ETest (nm, vl) ->
let v =
var_get nm
in
(v = vl)
in
eval' t
let choose ?printer ?name var_get lst =
let rec choose_aux =
function
| (cond, vl) :: tl ->
if eval var_get cond then
vl
else
choose_aux tl
| [] ->
let str_lst =
if lst = [] then
s_ "<empty>"
else
String.concat
(s_ ", ")
(List.map
(fun (cond, vl) ->
match printer with
| Some p -> p vl
| None -> s_ "<no printer>")
lst)
in
match name with
| Some nm ->
failwith
(Printf.sprintf
(f_ "No result for the choice list '%s': %s")
nm str_lst)
| None ->
failwith
(Printf.sprintf
(f_ "No result for a choice list: %s")
str_lst)
in
choose_aux (List.rev lst)
end
# 132 "myocamlbuild.ml"
module BaseEnvLight = struct
(* # 22 "src/base/BaseEnvLight.ml" *)
module MapString = Map.Make(String)
type t = string MapString.t
let default_filename =
Filename.concat
(Sys.getcwd ())
"setup.data"
let load ?(allow_empty=false) ?(filename=default_filename) () =
if Sys.file_exists filename then
begin
let chn =
open_in_bin filename
in
let st =
Stream.of_channel chn
in
let line =
ref 1
in
let st_line =
Stream.from
(fun _ ->
try
match Stream.next st with
| '\n' -> incr line; Some '\n'
| c -> Some c
with Stream.Failure -> None)
in
let lexer =
Genlex.make_lexer ["="] st_line
in
let rec read_file mp =
match Stream.npeek 3 lexer with
| [Genlex.Ident nm; Genlex.Kwd "="; Genlex.String value] ->
Stream.junk lexer;
Stream.junk lexer;
Stream.junk lexer;
read_file (MapString.add nm value mp)
| [] ->
mp
| _ ->
failwith
(Printf.sprintf
"Malformed data file '%s' line %d"
filename !line)
in
let mp =
read_file MapString.empty
in
close_in chn;
mp
end
else if allow_empty then
begin
MapString.empty
end
else
begin
failwith
(Printf.sprintf
"Unable to load environment, the file '%s' doesn't exist."
filename)
end
let rec var_expand str env =
let buff =
Buffer.create ((String.length str) * 2)
in
Buffer.add_substitute
buff
(fun var ->
try
var_expand (MapString.find var env) env
with Not_found ->
failwith
(Printf.sprintf
"No variable %s defined when trying to expand %S."
var
str))
str;
Buffer.contents buff
let var_get name env =
var_expand (MapString.find name env) env
let var_choose lst env =
OASISExpr.choose
(fun nm -> var_get nm env)
lst
end
# 237 "myocamlbuild.ml"
module MyOCamlbuildFindlib = struct
(* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *)
(** OCamlbuild extension, copied from
* http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild
* by N. Pouillard and others
*
* Updated on 2009/02/28
*
* Modified by Sylvain Le Gall
*)
open Ocamlbuild_plugin
type conf =
{ no_automatic_syntax: bool;
}
(* these functions are not really officially exported *)
let run_and_read =
Ocamlbuild_pack.My_unix.run_and_read
let blank_sep_strings =
Ocamlbuild_pack.Lexers.blank_sep_strings
let exec_from_conf exec =
let exec =
let env_filename = Pathname.basename BaseEnvLight.default_filename in
let env = BaseEnvLight.load ~filename:env_filename ~allow_empty:true () in
try
BaseEnvLight.var_get exec env
with Not_found ->
Printf.eprintf "W: Cannot get variable %s\n" exec;
exec
in
let fix_win32 str =
if Sys.os_type = "Win32" then begin
let buff = Buffer.create (String.length str) in
(* Adapt for windowsi, ocamlbuild + win32 has a hard time to handle '\\'.
*)
String.iter
(fun c -> Buffer.add_char buff (if c = '\\' then '/' else c))
str;
Buffer.contents buff
end else begin
str
end
in
fix_win32 exec
let split s ch =
let buf = Buffer.create 13 in
let x = ref [] in
let flush () =
x := (Buffer.contents buf) :: !x;
Buffer.clear buf
in
String.iter
(fun c ->
if c = ch then
flush ()
else
Buffer.add_char buf c)
s;
flush ();
List.rev !x
let split_nl s = split s '\n'
let before_space s =
try
String.before s (String.index s ' ')
with Not_found -> s
(* ocamlfind command *)
let ocamlfind x = S[Sh (exec_from_conf "ocamlfind"); x]
(* This lists all supported packages. *)
let find_packages () =
List.map before_space (split_nl & run_and_read (exec_from_conf "ocamlfind" ^ " list"))
(* Mock to list available syntaxes. *)
let find_syntaxes () = ["camlp4o"; "camlp4r"]
let well_known_syntax = [
"camlp4.quotations.o";
"camlp4.quotations.r";
"camlp4.exceptiontracer";
"camlp4.extend";
"camlp4.foldgenerator";
"camlp4.listcomprehension";
"camlp4.locationstripper";
"camlp4.macro";
"camlp4.mapgenerator";
"camlp4.metagenerator";
"camlp4.profiler";
"camlp4.tracer"
]
let dispatch conf =
function
| After_options ->
(* By using Before_options one let command line options have an higher
* priority on the contrary using After_options will guarantee to have
* the higher priority override default commands by ocamlfind ones *)
Options.ocamlc := ocamlfind & A"ocamlc";
Options.ocamlopt := ocamlfind & A"ocamlopt";
Options.ocamldep := ocamlfind & A"ocamldep";
Options.ocamldoc := ocamlfind & A"ocamldoc";
Options.ocamlmktop := ocamlfind & A"ocamlmktop";
Options.ocamlmklib := ocamlfind & A"ocamlmklib"
| After_rules ->
(* When one link an OCaml library/binary/package, one should use
* -linkpkg *)
flag ["ocaml"; "link"; "program"] & A"-linkpkg";
if not (conf.no_automatic_syntax) then begin
(* For each ocamlfind package one inject the -package option when
* compiling, computing dependencies, generating documentation and
* linking. *)
List.iter
begin fun pkg ->
let base_args = [A"-package"; A pkg] in
(* TODO: consider how to really choose camlp4o or camlp4r. *)
let syn_args = [A"-syntax"; A "camlp4o"] in
let (args, pargs) =
(* Heuristic to identify syntax extensions: whether they end in
".syntax"; some might not.
*)
if Filename.check_suffix pkg "syntax" ||
List.mem pkg well_known_syntax then
(syn_args @ base_args, syn_args)
else
(base_args, [])
in
flag ["ocaml"; "compile"; "pkg_"^pkg] & S args;
flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args;
flag ["ocaml"; "doc"; "pkg_"^pkg] & S args;
flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args;
flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args;
(* TODO: Check if this is allowed for OCaml < 3.12.1 *)
flag ["ocaml"; "compile"; "package("^pkg^")"] & S pargs;
flag ["ocaml"; "ocamldep"; "package("^pkg^")"] & S pargs;
flag ["ocaml"; "doc"; "package("^pkg^")"] & S pargs;
flag ["ocaml"; "infer_interface"; "package("^pkg^")"] & S pargs;
end
(find_packages ());
end;
(* Like -package but for extensions syntax. Morover -syntax is useless
* when linking. *)
List.iter begin fun syntax ->
flag ["ocaml"; "compile"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
flag ["ocaml"; "doc"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
flag ["ocaml"; "infer_interface"; "syntax_"^syntax] &
S[A"-syntax"; A syntax];
end (find_syntaxes ());
(* The default "thread" tag is not compatible with ocamlfind.
* Indeed, the default rules add the "threads.cma" or "threads.cmxa"
* options when using this tag. When using the "-linkpkg" option with
* ocamlfind, this module will then be added twice on the command line.
*
* To solve this, one approach is to add the "-thread" option when using
* the "threads" package using the previous plugin.
*)
flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]);
flag ["ocaml"; "pkg_threads"; "doc"] (S[A "-I"; A "+threads"]);
flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]);
flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]);
flag ["ocaml"; "package(threads)"; "compile"] (S[A "-thread"]);
flag ["ocaml"; "package(threads)"; "doc"] (S[A "-I"; A "+threads"]);
flag ["ocaml"; "package(threads)"; "link"] (S[A "-thread"]);
flag ["ocaml"; "package(threads)"; "infer_interface"] (S[A "-thread"]);
| _ ->
()
end
module MyOCamlbuildBase = struct
(* # 22 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *)
(** Base functions for writing myocamlbuild.ml
@author Sylvain Le Gall
*)
open Ocamlbuild_plugin
module OC = Ocamlbuild_pack.Ocaml_compiler
type dir = string
type file = string
type name = string
type tag = string
(* # 62 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *)
type t =
{
lib_ocaml: (name * dir list * string list) list;
lib_c: (name * dir * file list) list;
flags: (tag list * (spec OASISExpr.choices)) list;
(* Replace the 'dir: include' from _tags by a precise interdepends in
* directory.
*)
includes: (dir * dir list) list;
}
let env_filename =
Pathname.basename
BaseEnvLight.default_filename
let dispatch_combine lst =
fun e ->
List.iter
(fun dispatch -> dispatch e)
lst
let tag_libstubs nm =
"use_lib"^nm^"_stubs"
let nm_libstubs nm =
nm^"_stubs"
let dispatch t e =
let env =
BaseEnvLight.load
~filename:env_filename
~allow_empty:true
()
in
match e with
| Before_options ->
let no_trailing_dot s =
if String.length s >= 1 && s.[0] = '.' then
String.sub s 1 ((String.length s) - 1)
else
s
in
List.iter
(fun (opt, var) ->
try
opt := no_trailing_dot (BaseEnvLight.var_get var env)
with Not_found ->
Printf.eprintf "W: Cannot get variable %s\n" var)
[
Options.ext_obj, "ext_obj";
Options.ext_lib, "ext_lib";
Options.ext_dll, "ext_dll";
]
| After_rules ->
(* Declare OCaml libraries *)
List.iter
(function
| nm, [], intf_modules ->
ocaml_lib nm;
let cmis =
List.map (fun m -> (String.uncapitalize m) ^ ".cmi")
intf_modules in
dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis
| nm, dir :: tl, intf_modules ->
ocaml_lib ~dir:dir (dir^"/"^nm);
List.iter
(fun dir ->
List.iter
(fun str ->
flag ["ocaml"; "use_"^nm; str] (S[A"-I"; P dir]))
["compile"; "infer_interface"; "doc"])
tl;
let cmis =
List.map (fun m -> dir^"/"^(String.uncapitalize m)^".cmi")
intf_modules in
dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"]
cmis)
t.lib_ocaml;
(* Declare directories dependencies, replace "include" in _tags. *)
List.iter
(fun (dir, include_dirs) ->
Pathname.define_context dir include_dirs)
t.includes;
(* Declare C libraries *)
List.iter
(fun (lib, dir, headers) ->
(* Handle C part of library *)
flag ["link"; "library"; "ocaml"; "byte"; tag_libstubs lib]
(S[A"-dllib"; A("-l"^(nm_libstubs lib)); A"-cclib";
A("-l"^(nm_libstubs lib))]);
flag ["link"; "library"; "ocaml"; "native"; tag_libstubs lib]
(S[A"-cclib"; A("-l"^(nm_libstubs lib))]);
flag ["link"; "program"; "ocaml"; "byte"; tag_libstubs lib]
(S[A"-dllib"; A("dll"^(nm_libstubs lib))]);
(* When ocaml link something that use the C library, then one
need that file to be up to date.
This holds both for programs and for libraries.
*)
dep ["link"; "ocaml"; tag_libstubs lib]
[dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
dep ["compile"; "ocaml"; tag_libstubs lib]
[dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
(* TODO: be more specific about what depends on headers *)
(* Depends on .h files *)
dep ["compile"; "c"]
headers;
(* Setup search path for lib *)
flag ["link"; "ocaml"; "use_"^lib]
(S[A"-I"; P(dir)]);
)
t.lib_c;
(* Add flags *)
List.iter
(fun (tags, cond_specs) ->
let spec = BaseEnvLight.var_choose cond_specs env in
let rec eval_specs =
function
| S lst -> S (List.map eval_specs lst)
| A str -> A (BaseEnvLight.var_expand str env)
| spec -> spec
in
flag tags & (eval_specs spec))
t.flags
| _ ->
()
let dispatch_default conf t =
dispatch_combine
[
dispatch t;
MyOCamlbuildFindlib.dispatch conf;
]
end
# 606 "myocamlbuild.ml"
open Ocamlbuild_plugin;;
let package_default =
{
MyOCamlbuildBase.lib_ocaml =
[
("containers", ["src/core"], []);
("containers_io", ["src/io"], []);
("containers_unix", ["src/unix"], []);
("containers_sexp", ["src/sexp"], []);
("containers_data", ["src/data"], []);
("containers_iter", ["src/iter"], []);
("containers_string", ["src/string"], []);
("containers_advanced", ["src/advanced"], []);
("containers_bigarray", ["src/bigarray"], []);
("containers_thread", ["src/threads"], []);
("containers_top", ["src/top"], [])
];
lib_c = [];
flags = [];
includes =
[
("src/top",
[
"src/bigarray";
"src/core";
"src/data";
"src/iter";
"src/sexp";
"src/string";
"src/unix"
]);
("src/threads", ["src/core"]);
("src/bigarray", ["src/core"]);
("src/advanced", ["src/core"]);
("qtest",
[
"src/advanced";
"src/bigarray";
"src/core";
"src/data";
"src/io";
"src/iter";
"src/sexp";
"src/string";
"src/threads";
"src/unix"
]);
("examples", ["src/sexp"]);
("benchs",
[
"src/advanced";
"src/core";
"src/data";
"src/iter";
"src/string";
"src/threads"
])
]
}
;;
let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false}
let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;;
# 673 "myocamlbuild.ml"
(* OASIS_STOP *)
let doc_intro = "doc/intro.txt"
open Ocamlbuild_plugin;;
dispatch
(MyOCamlbuildBase.dispatch_combine [
begin function
| After_rules ->
(* replace with Ocamlbuild_cppo.dispatch when 4.00 is not supported
anymore *)
let dep_cppo = "%(name).cppo.ml" in
let prod1 = "%(name: <*> and not <*.cppo>).ml" in
let prod2 = "%(name: <**/*> and not <**/*.cppo>).ml" in
let f prod env _build =
let dep = env dep_cppo in
let prod = env prod in
let tags = tags_of_pathname prod ++ "cppo" in
Cmd (S[A "cppo"; T tags; S [A "-o"; P prod]; P dep ])
in
rule "cppo1" ~dep:dep_cppo ~prod:prod1 (f prod1) ;
rule "cppo2" ~dep:dep_cppo ~prod:prod2 (f prod2) ;
pflag ["cppo"] "cppo_D" (fun s -> S [A "-D"; A s]) ;
pflag ["cppo"] "cppo_U" (fun s -> S [A "-U"; A s]) ;
pflag ["cppo"] "cppo_I" (fun s ->
if Pathname.is_directory s then S [A "-I"; P s]
else S [A "-I"; P (Pathname.dirname s)]
) ;
pdep ["cppo"] "cppo_I" (fun s ->
if Pathname.is_directory s then [] else [s]) ;
flag ["cppo"; "cppo_q"] (A "-q") ;
flag ["cppo"; "cppo_s"] (A "-s") ;
flag ["cppo"; "cppo_n"] (A "-n") ;
pflag ["cppo"] "cppo_x" (fun s -> S [A "-x"; A s]);
(* end replace *)
let major, minor = Scanf.sscanf Sys.ocaml_version "%d.%d.%d"
(fun major minor patchlevel -> major, minor)
in
let ocaml_major = "OCAML_MAJOR " ^ string_of_int major in
let ocaml_minor = "OCAML_MINOR " ^ string_of_int minor in
flag ["cppo"] & S[A"-D"; A ocaml_major; A"-D"; A ocaml_minor] ;
(* Documentation index *)
dep ["ocaml"; "doc"; "extension:html"] & [doc_intro] ;
flag ["ocaml"; "doc"; "extension:html"]
& S[A"-t"; A"Containers doc"; A"-intro"; P doc_intro ];
| _ -> ()
end;
dispatch_default
])

46
opam
View file

@ -1,46 +0,0 @@
opam-version: "1.2"
name: "containers"
version: "dev"
author: "Simon Cruanes"
maintainer: "simon.cruanes@inria.fr"
build: [
["./configure"
"--prefix" prefix
"--%{base-threads:enable}%-thread"
"--disable-bench"
"--disable-tests"
"--%{base-bigarray:enable}%-bigarray"
"--%{sequence:enable}%-advanced"
"--%{base-unix:enable}%-unix"
"--enable-docs"
]
[make "build"]
]
install: [
[make "install"]
]
build-doc: [ make "doc" ]
build-test: [ make "test" ]
remove: [
["ocamlfind" "remove" "containers"]
]
depends: [
"ocamlfind" {build}
"oasis" {build}
"base-bytes"
"result"
"cppo" {build}
"ocamlbuild" {build}
]
depopts: [ "sequence" "base-bigarray" "base-unix" "base-threads" "qtest" { test } ]
conflicts: [
"sequence" { < "0.5" }
"qtest" { < "2.2" }
"qcheck"
]
tags: [ "stdlib" "containers" "iterators" "list" "heap" "queue" ]
homepage: "https://github.com/c-cube/ocaml-containers/"
doc: "http://cedeela.fr/~simon/software/containers/"
available: [ocaml-version >= "4.00.0"]
dev-repo: "https://github.com/c-cube/ocaml-containers.git"
bug-reports: "https://github.com/c-cube/ocaml-containers/issues/"

4
run_bench_hash.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
OPTS="--profile=release --display=quiet"
exec dune exec $OPTS -- benchs/run_benchs_hash.exe $@

4
run_benchs.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
OPTS="--profile=release --display=quiet"
exec dune exec $OPTS -- benchs/run_benchs.exe $@

View file

@ -1,30 +0,0 @@
(* setup.ml generated for the first time by OASIS v0.4.4 *)
(* OASIS_START *)
(* DO NOT EDIT (digest: 172e37fc4b327922311f6cf9389bc560) *)
(******************************************************************************)
(* OASIS: architecture for building OCaml libraries and applications *)
(* *)
(* Copyright (C) 2011-2013, Sylvain Le Gall *)
(* Copyright (C) 2008-2011, OCamlCore SARL *)
(* *)
(* This library is free software; you can redistribute it and/or modify it *)
(* under the terms of the GNU Lesser General Public License as published by *)
(* the Free Software Foundation; either version 2.1 of the License, or (at *)
(* your option) any later version, with the OCaml static compilation *)
(* exception. *)
(* *)
(* This library is distributed in the hope that it will be useful, but *)
(* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *)
(* or FITNESS FOR A PARTICULAR PURPOSE. See the file COPYING for more *)
(* details. *)
(* *)
(* You should have received a copy of the GNU Lesser General Public License *)
(* along with this library; if not, write to the Free Software Foundation, *)
(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)
(******************************************************************************)
open OASISDynRun
(* OASIS_STOP *)
let () = setup ();;

View file

@ -1,237 +0,0 @@
(*
copyright (c) 2013-2014, Simon Cruanes, Gabriel Radanne
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 Batch Operations on Collections} *)
module type COLLECTION = sig
type 'a t
val empty : 'a t
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
val map : ('a -> 'b) -> 'a t -> 'b t
val filter : ('a -> bool) -> 'a t -> 'a t
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
val flat_map : ('a -> 'b t) -> 'a t -> 'b t
end
module type S = sig
type 'a t
type ('a,'b) op
(** Operation that converts a ['a t] into a ['b t] *)
val apply : ('a,'b) op -> 'a t -> 'b t
(** Apply the operation to the collection. *)
val apply_fold : ('a, 'b) op -> ('c -> 'b -> 'c) -> 'c -> 'a t -> 'c
(** Apply the operation plus a fold to the collection. *)
val apply' : 'a t -> ('a,'b) op -> 'b t
(** Flip of {!apply} *)
(** {6 Combinators} *)
val id : ('a, 'a) op
val map : ('a -> 'b) -> ('a, 'b) op
val filter : ('a -> bool) -> ('a,'a) op
val filter_map : ('a -> 'b option) -> ('a,'b) op
val flat_map : ('a -> 'b t) -> ('a,'b) op
val extern : ('a t -> 'b t) -> ('a,'b) op
val compose : ('b,'c) op -> ('a,'b) op -> ('a,'c) op
val (>>>) : ('a,'b) op -> ('b,'c) op -> ('a,'c) op
end
module Make(C : COLLECTION) = struct
type 'a t = 'a C.t
type (_,_) op =
| Nil : ('a,'a) op
| Compose : ('a,'b) base_op * ('b, 'c) op -> ('a, 'c) op
and (_,_) base_op =
| Map : ('a -> 'b) -> ('a, 'b) base_op
| Filter : ('a -> bool) -> ('a, 'a) base_op
| FilterMap : ('a -> 'b option) -> ('a,'b) base_op
| FlatMap : ('a -> 'b t) -> ('a,'b) base_op
| Extern : ('a t -> 'b t) -> ('a,'b) base_op
(* associativity: put parenthesis on the right *)
let rec _compose : type a b c. (a,b) op -> (b,c) op -> (a,c) op
= fun f g -> match f with
| Compose (f1, Nil) -> Compose (f1, g)
| Compose (f1, f2) -> Compose (f1, _compose f2 g)
| Nil -> g
(* After optimization, the op is a list of flatmaps and external operations,
with maybe something else at the end *)
type (_,_) optimized_op =
| OptNil : ('a, 'a) optimized_op
| OptBase : ('a,'b) base_op * ('b, 'c) optimized_op -> ('a,'c) optimized_op
| OptFlatMap : ('a -> 'b t) * ('b, 'c) optimized_op -> ('a, 'c) optimized_op
| OptExtern : ('a t -> 'b t) * ('b, 'c) optimized_op -> ('a, 'c) optimized_op
(* As compose, but optimize recursively on the way. *)
let rec optimize_compose
: type a b c. (a,b) base_op -> (b,c) op -> (a,c) optimized_op
= fun base_op op -> match base_op, op with
| f, Nil -> OptBase (f, OptNil)
| Map f, Compose (Map g, cont) ->
optimize_compose (Map (fun x -> g (f x))) cont
| Map f, Compose (Filter p, cont) ->
optimize_compose
(FilterMap (fun x -> let y = f x in if p y then Some y else None)) cont
| Map f, Compose (FilterMap f', cont) ->
optimize_compose
(FilterMap (fun x -> f' (f x))) cont
| Map f, Compose (FlatMap f', cont) ->
optimize_compose
(FlatMap (fun x -> f' (f x))) cont
| Filter p, Compose (Filter p', cont) ->
optimize_compose (Filter (fun x -> p x && p' x)) cont
| Filter p, Compose (Map g, cont) ->
optimize_compose
(FilterMap (fun x -> if p x then Some (g x) else None)) cont
| Filter p, Compose (FilterMap f', cont) ->
optimize_compose
(FilterMap (fun x -> if p x then f' x else None)) cont
| Filter p, Compose (FlatMap f', cont) ->
optimize_compose
(FlatMap (fun x -> if p x then f' x else C.empty)) cont
| FilterMap f, Compose (FilterMap f', cont) ->
optimize_compose
(FilterMap
(fun x -> match f x with None -> None | Some y -> f' y))
cont
| FilterMap f, Compose (Filter p, cont) ->
optimize_compose
(FilterMap
(fun x -> match f x with
| (Some y) as res when p y -> res
| _ -> None))
cont
| FilterMap f, Compose (Map f', cont) ->
optimize_compose
(FilterMap
(fun x -> match f x with
| None -> None
| Some y -> Some (f' y)))
cont
| FilterMap f, Compose (FlatMap f', cont) ->
optimize_compose
(FlatMap
(fun x -> match f x with
| None -> C.empty
| Some y -> f' y))
cont
| FlatMap f, Compose (f', tail) ->
merge_flat_map f (optimize_compose f' tail)
| Extern f, Compose (f', tail) ->
OptExtern (f, optimize_compose f' tail)
| op, Compose (Extern f', cont) ->
OptBase (op, optimize_compose (Extern f') cont)
and merge_flat_map
: type a b c. (a -> b C.t) -> (b,c) optimized_op -> (a,c) optimized_op =
fun f op -> match op with
| OptNil -> OptFlatMap (f, op)
| OptFlatMap (f', cont) ->
merge_flat_map
(fun x ->
let a = f x in
C.flat_map f' a)
cont
| OptExtern _ -> OptFlatMap (f, op)
| OptBase _ -> OptFlatMap (f, op)
(* Optimize a batch operation by fusion *)
let optimize : type a b. (a,b) op -> (a,b) optimized_op
= fun op -> match op with
| Compose (a, b) -> optimize_compose a b
| Nil -> OptNil
let rec apply_optimized : type a b. (a,b) optimized_op -> a t -> b t
= fun op a -> match op with
| OptNil -> a
| OptBase (f,c) -> apply_optimized c (apply_base f a)
| OptFlatMap (f,c) -> apply_optimized c (C.flat_map f a)
| OptExtern (f,c) -> apply_optimized c (f a)
and apply_base : type a b. (a,b) base_op -> a t -> b t
= fun op a -> match op with
| Map f -> C.map f a
| Filter p -> C.filter p a
| FlatMap f -> C.flat_map f a
| FilterMap f -> C.filter_map f a
| Extern f -> f a
let fusion_fold : type a b c. (a,b) base_op -> (c -> b -> c) -> c -> a -> c
= fun op f' -> match op with
| Map f -> (fun z x -> f' z (f x))
| Filter p -> (fun z x -> if p x then f' z x else z)
| FlatMap f -> (fun z x -> C.fold f' z (f x))
| FilterMap f -> (fun z x -> match f x with Some x' -> f' z x' | None -> z)
| Extern _ -> assert false
let rec apply_optimized_with_fold
: type a b c. (a,b) optimized_op -> (c -> b -> c) -> c -> a t -> c
= fun op fold z a -> match op with
| OptNil -> C.fold fold z a
| OptBase (Extern f, OptNil) ->
C.fold fold z (f a)
| OptBase (f,OptNil) ->
(* terminal fold *)
C.fold (fusion_fold f fold) z a
| OptBase (f,c) ->
(* make intermediate collection and continue *)
apply_optimized_with_fold c fold z (apply_base f a)
| OptExtern (f,c) -> apply_optimized_with_fold c fold z (f a)
| OptFlatMap (f,c) -> apply_optimized_with_fold c fold z (C.flat_map f a)
(* Optimize and run *)
let apply op a =
let op' = optimize op in
apply_optimized op' a
let apply_fold op fold z a =
let op' = optimize op in
apply_optimized_with_fold op' fold z a
let apply' a op = apply op a
(** {6 Combinators} *)
let id = Nil
let map f = Compose (Map f, Nil)
let filter p = Compose (Filter p, Nil)
let filter_map f = Compose (FilterMap f, Nil)
let flat_map f = Compose (FlatMap f, Nil)
let extern f = Compose (Extern f, Nil)
let compose f g = _compose g f
let (>>>) f g = _compose f g
end

View file

@ -1,80 +0,0 @@
(*
copyright (c) 2013-2014, 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 Batch Operations on Collections}
Define and combine operations on a collection of elements, then
run the composition of those operations on some collection. The
composition is optimized to minimize the number of intermediate
collections *)
(** {2 Definition of a Collection} *)
module type COLLECTION = sig
type 'a t
val empty : 'a t
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
val map : ('a -> 'b) -> 'a t -> 'b t
val filter : ('a -> bool) -> 'a t -> 'a t
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
val flat_map : ('a -> 'b t) -> 'a t -> 'b t
end
(** {2 Definition of a Batch operations} *)
module type S = sig
type 'a t
type ('a,'b) op
(** Operation that converts a ['a t] into a ['b t] *)
val apply : ('a,'b) op -> 'a t -> 'b t
(** Apply the operation to the collection. *)
val apply_fold : ('a, 'b) op -> ('c -> 'b -> 'c) -> 'c -> 'a t -> 'c
(** Apply the operation plus a fold to the collection. *)
val apply' : 'a t -> ('a,'b) op -> 'b t
(** Flip of {!apply} *)
(** {6 Combinators} *)
val id : ('a, 'a) op
val map : ('a -> 'b) -> ('a, 'b) op
val filter : ('a -> bool) -> ('a,'a) op
val filter_map : ('a -> 'b option) -> ('a,'b) op
val flat_map : ('a -> 'b t) -> ('a,'b) op
val extern : ('a t -> 'b t) -> ('a,'b) op
(** Use a specific function that won't be optimized *)
val compose : ('b,'c) op -> ('a,'b) op -> ('a,'c) op
val (>>>) : ('a,'b) op -> ('b,'c) op -> ('a,'c) op
end
(** {2 Functor} *)
module Make(C : COLLECTION) : S with type 'a t = 'a C.t

View file

@ -1,144 +0,0 @@
(*
copyright (c) 2013-2014, 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 Categorical Constructs} *)
(** {2 Signatures} *)
module type MONOID = sig
type t
val empty : t
val append : t -> t -> t
end
module type FUNCTOR = sig
type +'a t
val map : ('a -> 'b) -> 'a t -> 'b t
end
module type APPLICATIVE = sig
type +'a t
include FUNCTOR with type 'a t := 'a t
val pure : 'a -> 'a t
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
end
module type MONAD_BARE = sig
type +'a t
val return : 'a -> 'a t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
end
module type MONAD = sig
include MONAD_BARE
include APPLICATIVE with type 'a t := 'a t
end
module type MONAD_TRANSFORMER = sig
include MONAD
module M : MONAD
val lift : 'a M.t -> 'a t
end
type 'a sequence = ('a -> unit) -> unit
module type FOLDABLE = sig
type 'a t
val to_seq : 'a t -> 'a sequence
end
module type TRAVERSE = functor(M : MONAD) -> sig
type +'a t
val sequence_m : 'a M.t t -> 'a t M.t
val fold_m : ('b -> 'a -> 'b M.t) -> 'b -> 'a t -> 'b M.t
val map_m : ('a -> 'b M.t) -> 'a t -> 'b t M.t
end
module type FREE_MONAD = sig
module F : FUNCTOR
type +'a t =
| Return of 'a
| Roll of 'a t F.t
include MONAD with type 'a t := 'a t
val inj : 'a F.t -> 'a t
end
(** {2 Some Implementations} *)
module WrapMonad(M : MONAD_BARE) = struct
include M
let map f x = x >>= (fun x -> return (f x))
let pure = return
let (<*>) f x = f >>= fun f -> x >>= fun x -> return (f x)
end
module MakeFree(F : FUNCTOR) = struct
module F = F
type 'a t = Return of 'a | Roll of ('a t F.t)
let return x = Return x
let pure = return
let rec map : type a b. (a -> b) -> a t -> b t
= fun f x -> match x with
| Return x -> Return (f x)
| Roll xs -> Roll (F.map (map f) xs)
let rec _bind : type a b. (a -> b t) -> a t -> b t
= fun f x -> match x with
| Return x -> f x
| Roll y -> Roll (F.map (_bind f) y)
let (>>=) x f = _bind f x
let rec _app : type a b. (a -> b) t -> a t -> b t
= fun f x -> match f, x with
| Return f, Return x -> Return (f x)
| Return f, Roll xs -> Roll (F.map (map f) xs)
| Roll fs, _ -> Roll (F.map (fun f -> _app f x) fs)
let (<*>) = _app
let inj x = Roll (F.map return x)
end
module MakeFreeFold(FM : FREE_MONAD)(Fold : FOLDABLE with type 'a t = 'a FM.F.t) = struct
type 'a t = 'a FM.t
let rec to_seq : type a. a FM.t -> a sequence
= fun x k -> match x with
| FM.Return x -> k x
| FM.Roll xs -> Fold.to_seq xs (fun x -> to_seq x k)
end

View file

@ -1,113 +0,0 @@
(*
copyright (c) 2013-2014, 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 Categorical Constructs}
Attempt to copy some structures from Haskell and the likes. Disclaimer:
I don't know much about category theory, only about type signatures ;). *)
(** {2 Signatures} *)
module type MONOID = sig
type t
val empty : t
val append : t -> t -> t
end
module type FUNCTOR = sig
type +'a t
val map : ('a -> 'b) -> 'a t -> 'b t
end
module type APPLICATIVE = sig
type +'a t
include FUNCTOR with type 'a t := 'a t
val pure : 'a -> 'a t
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
end
module type MONAD_BARE = sig
type +'a t
val return : 'a -> 'a t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
end
module type MONAD = sig
include MONAD_BARE
include APPLICATIVE with type 'a t := 'a t
end
module type MONAD_TRANSFORMER = sig
include MONAD
module M : MONAD
val lift : 'a M.t -> 'a t
end
(** Cheating: use an equivalent of "to List" with a sequence *)
type 'a sequence = ('a -> unit) -> unit
module type FOLDABLE = sig
type 'a t
val to_seq : 'a t -> 'a sequence
end
module type TRAVERSE = functor(M : MONAD) -> sig
type +'a t
val sequence_m : 'a M.t t -> 'a t M.t
val fold_m : ('b -> 'a -> 'b M.t) -> 'b -> 'a t -> 'b M.t
val map_m : ('a -> 'b M.t) -> 'a t -> 'b t M.t
end
(** The free monad is built by nesting applications of a functor [F].
For instance, Lisp-like nested lists can be built and dealt with like this:
{[
module Lisp = CCCat.FreeMonad(CCList);;
let l = Lisp.(inj [1;2;3] >>= fun x -> inj [x; x*2; x+100]);;
]} *)
module type FREE_MONAD = sig
module F : FUNCTOR
type +'a t =
| Return of 'a
| Roll of 'a t F.t
include MONAD with type 'a t := 'a t
val inj : 'a F.t -> 'a t
end
(** {2 Some Implementations} *)
(** Implement the applicative and functor modules from only return and bind *)
module WrapMonad(M : MONAD_BARE) : MONAD with type 'a t = 'a M.t
module MakeFree(F : FUNCTOR) : FREE_MONAD with module F = F
module MakeFreeFold(FM : FREE_MONAD)(Fold : FOLDABLE with type 'a t = 'a FM.F.t)
: FOLDABLE with type 'a t = 'a FM.t

View file

@ -1,888 +0,0 @@
(*
copyright (c) 2013-2014, 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 LINQ-like operations on collections} *)
type 'a sequence = ('a -> unit) -> unit
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a hash = 'a -> int
type 'a with_err = [`Ok of 'a | `Error of string ]
let _id x = x
exception ExitWithError of string
let _exit_with_error s = raise (ExitWithError s)
let _error_of_exn f = try `Ok (f ()) with ExitWithError s -> `Error s
module PMap = struct
type ('a, 'b) t = {
is_empty : unit -> bool;
size : unit -> int; (* Number of keys *)
get : 'a -> 'b option;
fold : 'c. ('c -> 'a -> 'b -> 'c) -> 'c -> 'c;
to_seq : ('a * 'b) sequence;
}
let get m x = m.get x
let mem m x = match m.get x with
| None -> false
| Some _ -> true
let to_seq m = m.to_seq
let fold f acc m = m.fold f acc
let size m = m.size ()
type ('a, 'b) build = {
mutable cur : ('a, 'b) t;
add : 'a -> 'b -> unit;
update : 'a -> ('b option -> 'b option) -> unit;
}
let build_get b = b.cur
let add b x y = b.add x y
let update b f = b.update f
(* careful to use this map linearly *)
let make_hash (type key) ?(eq=(=)) ?(hash=Hashtbl.hash) () =
let module H = Hashtbl.Make(struct
type t = key
let equal = eq
let hash = hash
end) in
(* build table *)
let tbl = H.create 32 in
let cur = {
is_empty = (fun () -> H.length tbl = 0);
size = (fun () -> H.length tbl);
get = (fun k ->
try Some (H.find tbl k)
with Not_found -> None);
fold = (fun f acc -> H.fold (fun k v acc -> f acc k v) tbl acc);
to_seq = (fun k -> H.iter (fun key v -> k (key,v)) tbl);
} in
{ cur;
add = (fun k v -> H.replace tbl k v);
update = (fun k f ->
match (try f (Some (H.find tbl k)) with Not_found -> f None) with
| None -> H.remove tbl k
| Some v' -> H.replace tbl k v');
}
let make_cmp (type key) ?(cmp=Pervasives.compare) () =
let module M = Sequence.Map.Make(struct
type t = key
let compare = cmp
end) in
let map = ref M.empty in
let cur = {
is_empty = (fun () -> M.is_empty !map);
size = (fun () -> M.cardinal !map);
get = (fun k ->
try Some (M.find k !map)
with Not_found -> None);
fold = (fun f acc ->
M.fold
(fun key set acc -> f acc key set) !map acc
);
to_seq = (fun k -> M.to_seq !map k);
} in
{
cur;
add = (fun k v -> map := M.add k v !map);
update = (fun k f ->
match (try f (Some (M.find k !map)) with Not_found -> f None) with
| None -> map := M.remove k !map
| Some v' -> map := M.add k v' !map);
}
type 'a build_method =
| FromCmp of 'a ord
| FromHash of 'a equal * 'a hash
| Default
let make ?(build=Default) () = match build with
| Default -> make_hash ()
| FromCmp cmp -> make_cmp ~cmp ()
| FromHash (eq,hash) -> make_hash ~eq ~hash ()
(* choose a build method from the optional arguments *)
let _make_build ?cmp ?eq ?hash () =
let _maybe default o = match o with
| Some x -> x
| None -> default
in
match eq, hash with
| Some _, _
| _, Some _ ->
FromHash ( _maybe (=) eq, _maybe Hashtbl.hash hash)
| _ ->
match cmp with
| Some f -> FromCmp f
| _ -> Default
let multimap_of_seq ?(build=make ()) seq =
seq (fun (k,v) ->
build.update k (function
| None -> Some [v]
| Some l -> Some (v::l)));
build.cur
let count_of_seq ?(build=make ()) seq =
seq (fun x ->
build.update x
(function
| None -> Some 1
| Some n -> Some (n+1)));
build.cur
(* map values *)
let map f m = {
is_empty = m.is_empty;
size = m.size;
get = (fun k -> match m.get k with
| None -> None
| Some v -> Some (f v)
);
to_seq = Sequence.map (fun (x,y) -> x, f y) m.to_seq;
fold = (fun f' acc ->
m.fold (fun acc x y -> f' acc x (f y)) acc
);
}
let to_list m = Sequence.to_rev_list m.to_seq
let reverse_ ~build m =
let build = make ~build () in
let seq = Sequence.map (fun (x,y) -> y,x) (to_seq m) in
multimap_of_seq ~build seq
let reverse_multimap_ ~build m =
let build = make ~build () in
let seq = to_seq m in
let seq = Sequence.flat_map
(fun (x,l) -> Sequence.map (fun y -> y,x) (Sequence.of_list l)
) seq
in
multimap_of_seq ~build seq
let reverse ?cmp ?eq ?hash () m =
let build = _make_build ?cmp ?eq ?hash () in
reverse_ ~build m
let reverse_multimap ?cmp ?eq ?hash () m =
let build = _make_build ?cmp ?eq ?hash () in
reverse_multimap_ ~build m
let fold_multimap f acc m =
m.fold (fun acc x l -> List.fold_left (fun acc y -> f acc x y) acc l) acc
let get_seq key m = match get m key with
| None -> Sequence.empty
| Some x -> Sequence.return x
let iter m = m.to_seq
let flatten m =
let seq = Sequence.flat_map
(fun (k,v) -> Sequence.map (fun v' -> k,v') v)
m.to_seq
in
seq
let flatten_l m =
let seq = Sequence.flatMap
(fun (k,v) -> Sequence.map (fun v' -> k,v') (Sequence.of_list v))
m.to_seq
in
seq
end
type 'a search_result =
| SearchContinue
| SearchStop of 'a
type ('a,'b,'key,'c) join_descr = {
join_key1 : 'a -> 'key;
join_key2 : 'b -> 'key;
join_merge : 'key -> 'a -> 'b -> 'c option;
join_build : 'key PMap.build_method;
}
type ('a,'b) group_join_descr = {
gjoin_proj : 'b -> 'a;
gjoin_build : 'a PMap.build_method;
}
module ImplemSetOps = struct
let choose s = Sequence.take 1 s
let distinct ~cmp s = Sequence.sort_uniq ~cmp s
let search obj s =
match
Sequence.find
(fun x -> match obj#check x with
| SearchContinue -> None
| SearchStop y -> Some y
) s
with None -> obj#failure
| Some x -> x
let do_join ~join c1 c2 =
let build1 =
let seq = Sequence.map (fun x -> join.join_key1 x, x) c1 in
PMap.multimap_of_seq ~build:(PMap.make ~build:join.join_build ()) seq
in
let l = Sequence.fold
(fun acc y ->
let key = join.join_key2 y in
match PMap.get build1 key with
| None -> acc
| Some l1 ->
List.fold_left
(fun acc x -> match join.join_merge key x y with
| None -> acc
| Some res -> res::acc
) acc l1
) [] c2
in
Sequence.of_list l
let do_group_join ~gjoin c1 c2 =
let build = PMap.make ~build:gjoin.gjoin_build () in
c1 (fun x -> PMap.add build x []);
c2
(fun y ->
(* project [y] into some element of [c1] *)
let x = gjoin.gjoin_proj y in
PMap.update build x
(function
| None -> None (* [x] not present, ignore! *)
| Some l -> Some (y::l)
)
);
PMap.build_get build
let do_union ~build c1 c2 =
let build = PMap.make ~build () in
c1 (fun x -> PMap.add build x ());
c2 (fun x -> PMap.add build x ());
let seq = PMap.to_seq (PMap.build_get build) in
Sequence.map fst seq
type inter_status =
| InterLeft
| InterDone (* already output *)
let do_inter ~build c1 c2 =
let build = PMap.make ~build () in
let l = ref [] in
c1 (fun x -> PMap.add build x InterLeft);
c2 (fun x ->
PMap.update build x
(function
| None -> Some InterDone
| Some InterDone as foo -> foo
| Some InterLeft ->
l := x :: !l;
Some InterDone
)
);
Sequence.of_list !l
let do_diff ~build c1 c2 =
let build = PMap.make ~build () in
c2 (fun x -> PMap.add build x ());
let map = PMap.build_get build in
(* output elements of [c1] not in [map] *)
Sequence.filter (fun x -> not (PMap.mem map x)) c1
end
(** {2 Query operators} *)
type (_, _) unary =
| Map : ('a -> 'b) -> ('a, 'b ) unary
| Filter : ('a -> bool) -> ('a, 'a ) unary
| Fold : ('b -> 'a -> 'b) * 'b -> ('a, 'b) unary
| Reduce : ('a -> 'b) * ('a -> 'b -> 'b) * ('b -> 'c)
-> ('a, 'c) unary
| Size : ('a, int) unary
| Choose : ('a, 'a) unary
| FilterMap : ('a -> 'b option) -> ('a, 'b) unary
| FlatMap : ('a -> 'b sequence) -> ('a, 'b) unary
| Take : int -> ('a, 'a) unary
| TakeWhile : ('a -> bool) -> ('a, 'a) unary
| Sort : 'a ord -> ('a, 'a) unary
| Distinct : 'a ord -> ('a, 'a) unary
| Search :
< check: ('a -> 'b search_result);
failure : 'b;
> -> ('a, 'b) unary
| Contains : 'a equal * 'a -> ('a, bool) unary
| GroupBy : 'b PMap.build_method * ('a -> 'b)
-> ('a, ('b,'a list) PMap.t) unary
| Count : 'a PMap.build_method -> ('a, ('a, int) PMap.t) unary
| Lazy : ('a lazy_t, 'a) unary
type set_op =
| Union
| Inter
| Diff
type (_, _, _) binary =
| App : ('a -> 'b, 'a, 'b) binary
| Join : ('a, 'b, 'key, 'c) join_descr
-> ('a, 'b, 'c) binary
| GroupJoin : ('a, 'b) group_join_descr
-> ('a, 'b, ('a, 'b list) PMap.t) binary
| Product : ('a, 'b, ('a*'b)) binary
| Append : ('a, 'a, 'a) binary
| SetOp : set_op * 'a PMap.build_method
-> ('a, 'a, 'a) binary
(* type of queries that return a 'a *)
and 'a t =
| Return : 'a -> 'a t
| OfSeq : 'a sequence -> 'a t
| Unary : ('a, 'b) unary * 'a t -> 'b t
| Binary : ('a, 'b, 'c) binary * 'a t * 'b t -> 'c t
| Bind : ('a -> 'b t) * 'a t -> 'b t
| Reflect : 'a t -> 'a sequence t
let start x = Return x
let of_list l =
OfSeq (Sequence.of_list l)
let of_array a =
OfSeq (Sequence.of_array a)
let of_array_i a =
OfSeq (Sequence.of_array_i a)
let of_hashtbl h =
OfSeq (Sequence.of_hashtbl h)
let range i j = OfSeq (Sequence.int_range ~start:i ~stop:j)
let (--) = range
let of_seq seq =
OfSeq seq
let of_queue q =
OfSeq (Sequence.of_queue q)
let of_stack s =
OfSeq (Sequence.of_stack s)
let of_string s =
OfSeq (Sequence.of_str s)
(** {6 Execution} *)
let rec _optimize : type a. a t -> a t
= fun q -> match q with
| Return _ -> q
| Unary (u, q) ->
_optimize_unary u (_optimize q)
| Binary (b, q1, q2) ->
_optimize_binary b (_optimize q1) (_optimize q2)
| Reflect q -> Reflect (_optimize q)
| OfSeq _ -> q
| Bind (f,q) -> Bind(f, _optimize q) (* cannot optimize [f] before execution *)
and _optimize_unary : type a b. (a,b) unary -> a t -> b t
= fun u q -> match u, q with
| Size, Unary (Choose, _) -> Return 1
| Map f, Unary (Map g, q') ->
_optimize_unary (Map (fun x -> f (g x))) q'
| Filter p, Unary (Map f, cont) ->
_optimize_unary
(FilterMap (fun x -> let y = f x in if p y then Some y else None))
cont
| Filter p, Unary (Filter p', q) ->
_optimize_unary (Filter (fun x -> p x && p' x)) q
| FilterMap f, Unary (Map g, q') ->
_optimize_unary (FilterMap (fun x -> f (g x))) q'
| Map f, Unary (Filter p, cont) ->
_optimize_unary
(FilterMap (fun x -> if p x then Some (f x) else None))
cont
| Map _, Binary (Append, q1, q2) ->
_optimize_binary Append (Unary (u, q1)) (Unary (u, q2))
| Filter _, Binary (Append, q1, q2) ->
_optimize_binary Append (Unary (u, q1)) (Unary (u, q2))
| Fold (f,acc), Unary (Map f', cont) ->
_optimize_unary
(Fold ((fun acc x -> f acc (f' x)), acc))
cont
| Reduce (start, mix, stop), Unary (Map f, cont) ->
_optimize_unary
(Reduce (
(fun x -> start (f x)),
(fun x acc -> mix (f x) acc),
stop))
cont
| Size, Unary (Map _, cont) ->
_optimize_unary Size cont (* ignore the map! *)
| Size, Unary (Sort _, cont) ->
_optimize_unary Size cont
| _ -> Unary (u, _optimize q)
(* TODO: other cases *)
and _optimize_binary : type a b c. (a,b,c) binary -> a t -> b t -> c t
= fun b q1 q2 -> match b, q1, q2 with
| App, Return f, Return x -> Return (f x)
| App, Return f, x -> _optimize_unary (Map f) x
| App, f, Return x -> _optimize_unary (Map (fun f -> f x)) f
| App, _, _ -> Binary (b, _optimize q1, _optimize q2)
| Join _, _, _ -> Binary (b, _optimize q1, _optimize q2)
| GroupJoin _, _, _ -> Binary (b, _optimize q1, _optimize q2)
| Product, _, _ -> Binary (b, _optimize q1, _optimize q2)
| Append, _, _ -> Binary (b, _optimize q1, _optimize q2)
| SetOp _, _, _ -> Binary (b, _optimize q1, _optimize q2)
(* apply a unary operator on a collection *)
let _do_unary : type a b. (a,b) unary -> a sequence -> b sequence
= fun u c -> match u with
| Map f -> Sequence.map f c
| Filter p -> Sequence.filter p c
| Fold (f, acc) -> Sequence.return (Sequence.fold f acc c)
| Reduce (start, mix, stop) ->
let acc = Sequence.fold
(fun acc x -> match acc with
| None -> Some (start x)
| Some acc -> Some (mix x acc)
) None c
in
begin match acc with
| None -> Sequence.empty
| Some x -> Sequence.return (stop x)
end
| Size -> Sequence.return (Sequence.length c)
| Choose -> ImplemSetOps.choose c
| FilterMap f -> Sequence.filter_map f c
| FlatMap f -> Sequence.flat_map f c
| Take n -> Sequence.take n c
| TakeWhile p -> Sequence.take_while p c
| Sort cmp -> Sequence.sort ~cmp c
| Distinct cmp -> ImplemSetOps.distinct ~cmp c
| Search obj -> Sequence.return (ImplemSetOps.search obj c)
| GroupBy (build,f) ->
let seq = Sequence.map (fun x -> f x, x) c in
Sequence.return (PMap.multimap_of_seq ~build:(PMap.make ~build ()) seq)
| Contains (eq, x) -> Sequence.return (Sequence.mem ~eq x c)
| Count build ->
Sequence.return (PMap.count_of_seq ~build:(PMap.make ~build ()) c)
| Lazy -> Sequence.map Lazy.force c
let _do_binary : type a b c. (a, b, c) binary -> a sequence -> b sequence -> c sequence
= fun b c1 c2 -> match b with
| Join join -> ImplemSetOps.do_join ~join c1 c2
| GroupJoin gjoin -> Sequence.return (ImplemSetOps.do_group_join ~gjoin c1 c2)
| Product -> Sequence.product c1 c2
| Append -> Sequence.append c1 c2
| App -> Sequence.(c1 <*> c2)
| SetOp (Inter,build) -> ImplemSetOps.do_inter ~build c1 c2
| SetOp (Union,build) -> ImplemSetOps.do_union ~build c1 c2
| SetOp (Diff,build) -> ImplemSetOps.do_diff ~build c1 c2
let rec _run : type a. opt:bool -> a t -> a sequence
= fun ~opt q -> match q with
| Return c -> Sequence.return c
| Unary (u, q') -> _do_unary u (_run ~opt q')
| Binary (b, q1, q2) -> _do_binary b (_run ~opt q1) (_run ~opt q2)
| OfSeq s -> s
| Bind (f, q') ->
let seq = _run ~opt q' in
Sequence.flat_map
(fun x ->
let q'' = f x in
let q'' = if opt then _optimize q'' else q'' in
_run ~opt q''
) seq
| Reflect q ->
let seq = Sequence.persistent_lazy (_run ~opt q) in
Sequence.return seq
let _apply_limit ?limit seq = match limit with
| None -> seq
| Some l -> Sequence.take l seq
(* safe execution *)
let run ?limit q =
let seq = _run ~opt:true (_optimize q) in
_apply_limit ?limit seq
let run_no_optim ?limit q =
let seq = _run ~opt:false q in
_apply_limit ?limit seq
let run1 q =
let seq = _run ~opt:true (_optimize q) in
match Sequence.head seq with
| Some x -> x
| None -> raise Not_found
(** {6 Basics} *)
let empty = OfSeq Sequence.empty
let map f q = Unary (Map f, q)
let (>|=) q f = Unary (Map f, q)
let filter p q = Unary (Filter p, q)
let choose q = Unary (Choose, q)
let filter_map f q = Unary (FilterMap f, q)
let flat_map f q = Unary (FlatMap f, q)
let flat_map_l f q =
let f' x = Sequence.of_list (f x) in
Unary (FlatMap f', q)
let flatten_seq q = Unary (FlatMap (fun x->x), q)
let flatten q = Unary (FlatMap Sequence.of_list, q)
let take n q = Unary (Take n, q)
let take_while p q = Unary (TakeWhile p, q)
let sort ?(cmp=Pervasives.compare) () q = Unary (Sort cmp, q)
let distinct ?(cmp=Pervasives.compare) () q =
Unary (Distinct cmp, q)
let group_by ?cmp ?eq ?hash f q =
Unary (GroupBy (PMap._make_build ?cmp ?eq ?hash (),f), q)
let group_by' ?cmp ?eq ?hash f q =
flat_map PMap.iter (group_by ?cmp ?eq ?hash f q)
let count ?cmp ?eq ?hash () q =
Unary (Count (PMap._make_build ?cmp ?eq ?hash ()), q)
let count' ?cmp () q =
flat_map PMap.iter (count ?cmp () q)
let fold f acc q =
Unary (Fold (f, acc), q)
let size q = Unary (Size, q)
let sum q = Unary (Fold ((+), 0), q)
let reduce start mix stop q =
Unary (Reduce (start,mix,stop), q)
let _avg_start x = (x,1)
let _avg_mix x (y,n) = (x+y,n+1)
let _avg_stop (x,n) = x/n
let _lift_some f x y = match y with
| None -> Some x
| Some y -> Some (f x y)
let max q = Unary (Reduce (_id, Pervasives.max, _id), q)
let min q = Unary (Reduce (_id, Pervasives.min, _id), q)
let average q = Unary (Reduce (_avg_start, _avg_mix, _avg_stop), q)
let is_empty q =
Unary (Search (object
method check _ = SearchStop false (* stop in case there is an element *)
method failure = true
end), q)
let contains ?(eq=(=)) x q =
Unary (Contains (eq, x), q)
let for_all p q =
Unary (Search (object
method check x = if p x then SearchContinue else SearchStop false
method failure = true
end), q)
let exists p q =
Unary (Search (object
method check x = if p x then SearchStop true else SearchContinue
method failure = false
end), q)
let find p q =
Unary (Search (object
method check x = if p x then SearchStop (Some x) else SearchContinue
method failure = None
end), q)
let find_map f q =
Unary (Search (object
method check x = match f x with
| Some y -> SearchStop (Some y)
| None -> SearchContinue
method failure = None
end), q)
(** {6 Binary Operators} *)
let join ?cmp ?eq ?hash join_key1 join_key2 ~merge q1 q2 =
let join_build = PMap._make_build ?eq ?hash ?cmp () in
let j = {
join_key1;
join_key2;
join_merge=merge;
join_build;
} in
Binary (Join j, q1, q2)
let group_join ?cmp ?eq ?hash gjoin_proj q1 q2 =
let gjoin_build = PMap._make_build ?eq ?hash ?cmp () in
let j = {
gjoin_proj;
gjoin_build;
} in
Binary (GroupJoin j, q1, q2)
let product q1 q2 = Binary (Product, q1, q2)
let append q1 q2 = Binary (Append, q1, q2)
let inter ?cmp ?eq ?hash () q1 q2 =
let build = PMap._make_build ?cmp ?eq ?hash () in
Binary (SetOp (Inter, build), q1, q2)
let union ?cmp ?eq ?hash () q1 q2 =
let build = PMap._make_build ?cmp ?eq ?hash () in
Binary (SetOp (Union, build), q1, q2)
let diff ?cmp ?eq ?hash () q1 q2 =
let build = PMap._make_build ?cmp ?eq ?hash () in
Binary (SetOp (Diff, build), q1, q2)
let fst q = map fst q
let snd q = map snd q
let map1 f q = map (fun (x,y) -> f x, y) q
let map2 f q = map (fun (x,y) -> x, f y) q
let flatten_opt q = filter_map _id q
let opt_unwrap q =
Unary
(Map
(function
| Some x -> x
| None -> _exit_with_error "opt_unwrap"),
q
)
(** {6 Applicative} *)
let pure x = Return x
let app f x = Binary (App, f, x)
let (<*>) = app
(** {6 Monadic stuff} *)
let return x = Return x
let bind f q = Bind (f,q)
let (>>=) x f = Bind (f, x)
(** {6 Misc} *)
let lazy_ q = Unary (Lazy, q)
let reflect q = Reflect q
(** {6 Infix} *)
module Infix = struct
let (>>=) = (>>=)
let (>|=) = (>|=)
let (<*>) = (<*>)
let (--) = (--)
end
(** {6 Adapters} *)
let to_seq q = reflect q
let to_hashtbl q =
Unary (Map (fun c -> Sequence.to_hashtbl c), Reflect q)
let to_queue q =
Unary (Map (fun c -> let q = Queue.create() in Sequence.to_queue q c; q), Reflect q)
let to_stack q =
Unary (Map (fun c -> let s = Stack.create () in Sequence.to_stack s c; s), Reflect q)
module List = struct
let of_list l = OfSeq (Sequence.of_list l)
let to_list q = map Sequence.to_list (Reflect q)
let run q = run1 (to_list q)
end
module Array = struct
let of_array a = OfSeq (Sequence.of_array a)
let to_array q =
map (fun s -> Array.of_list (Sequence.to_list s)) (Reflect q)
let run q = run1 (to_array q)
end
module AdaptSet(S : Set.S) = struct
let of_set set = OfSeq (fun k -> S.iter k set)
let to_set q =
let f c = Sequence.fold (fun set x -> S.add x set) S.empty c in
map f (reflect q)
let run q = run1 (to_set q)
end
module AdaptMap(M : Map.S) = struct
let _to_seq m k = M.iter (fun x y -> k (x,y)) m
let of_map map = OfSeq (_to_seq map)
let to_pmap m = {
PMap.get = (fun x -> try Some (M.find x m) with Not_found -> None);
PMap.size = (fun () -> M.cardinal m);
PMap.is_empty = (fun () -> M.is_empty m);
PMap.fold = (fun f acc -> M.fold (fun x y acc -> f acc x y) m acc);
PMap.to_seq = _to_seq m;
}
let to_map q =
let f c =
Sequence.fold (fun m (x,y) -> M.add x y m) M.empty c
in
map f (reflect q)
let run q = run1 (to_map q)
end
module IO = struct
let _slurp with_input =
let l = lazy (with_input (fun ic -> CCIO.read_all ic)) in
lazy_ (return l)
let slurp ic = _slurp (fun f -> f ic)
let _with_file_in filename f =
try
let ic = open_in filename in
try
let x = f ic in
close_in ic;
x
with e ->
close_in ic;
_exit_with_error (Printexc.to_string e)
with e ->
_exit_with_error (Printexc.to_string e)
let _with_file_out filename f =
try
let oc = open_out filename in
try
let x = f oc in
close_out oc;
x
with e ->
close_out oc;
_exit_with_error (Printexc.to_string e)
with e ->
_exit_with_error (Printexc.to_string e)
let slurp_file filename = _slurp (_with_file_in filename)
(* find [c] in [s], starting at offset [i] *)
let rec _find s c i =
if i >= String.length s then None
else if s.[i] = c then Some i
else _find s c (i+1)
let rec _lines s i k = match _find s '\n' i with
| None ->
if i<String.length s then k (String.sub s i (String.length s-i))
| Some j ->
let s' = String.sub s i (j-i) in
k s';
_lines s (j+1) k
let lines q =
(* sequence of lines *)
let f s = _lines s 0 in
flat_map f q
let lines' q =
let f s = lazy (Sequence.to_list (_lines s 0)) in
lazy_ (map f q)
let _join ~sep ?(stop="") seq =
let buf = Buffer.create 128 in
Sequence.iteri
(fun i x ->
if i>0 then Buffer.add_string buf sep;
Buffer.add_string buf x)
seq;
Buffer.add_string buf stop;
Buffer.contents buf
let unlines q =
let f l = lazy (_join ~sep:"\n" ~stop:"\n" l) in
lazy_ (map f (reflect q))
let join sep q =
let f l = lazy (_join ~sep l) in
lazy_ (map f (reflect q))
let out oc q =
output_string oc (run1 q)
let out_lines oc q =
let x = run q in
Sequence.iter (fun l -> output_string oc l; output_char oc '\n') x
let to_file_exn filename q =
_with_file_out filename (fun oc -> out oc q)
let to_file filename q =
try `Ok (_with_file_out filename (fun oc -> out oc q))
with Failure s -> `Error s
let to_file_lines_exn filename q =
_with_file_out filename (fun oc -> out_lines oc q)
let to_file_lines filename q =
try `Ok (_with_file_out filename (fun oc -> out_lines oc q))
with Failure s -> `Error s
end

View file

@ -1,424 +0,0 @@
(*
copyright (c) 2013-2014, 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 LINQ-like operations on collections}
The purpose is to provide powerful combinators to express iteration,
transformation and combination of collections of items. This module depends
on several other modules, including {!CCList} and {!CCSequence}.
Functions and operations are assumed to be referentially transparent, i.e.
they should not rely on external side effects, they should not rely on
the order of execution.
@deprecated use {{: https://github.com/c-cube/olinq} OLinq}
{[
CCLinq.(
of_list [1;2;3]
|> flat_map (fun x -> Sequence.(x -- (x+10)))
|> sort ()
|> count ()
|> flat_map PMap.to_seq
|> List.run
);;
- : (int * int) list = [(13, 1); (12, 2); (11, 3); (10, 3); (9, 3);
(8, 3); (7, 3); (6, 3); (5, 3); (4, 3); (3, 3); (2, 2); (1, 1)]
CCLinq.(
IO.slurp_file "/tmp/foo"
|> IO.lines
|> sort ()
|> IO.to_file_lines "/tmp/bar"
);;
- : `Ok ()
]}
{b DEPRECATED, use "OLinq" (standalone library) instead}
{b status: deprecated}
*)
type 'a sequence = ('a -> unit) -> unit
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a hash = 'a -> int
type 'a with_err = [`Ok of 'a | `Error of string ]
(** {2 Polymorphic Maps} *)
module PMap : sig
type ('a, 'b) t
val get : ('a,'b) t -> 'a -> 'b option
val size : (_,_) t -> int
val to_seq : ('a, 'b) t -> ('a * 'b) sequence
val map : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t
(** Transform values *)
val to_list : ('a,'b) t -> ('a*'b) list
val reverse : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> unit ->
('a,'b) t -> ('b,'a list) t
(** Reverse relation of the map, as a multimap *)
val reverse_multimap : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash -> unit ->
('a,'b list) t -> ('b,'a list) t
(** Reverse relation of the multimap *)
val fold : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> ('a,'b) t -> 'acc
(** Fold on the items of the map *)
val fold_multimap : ('acc -> 'a -> 'b -> 'acc) -> 'acc ->
('a,'b list) t -> 'acc
(** Fold on the items of the multimap *)
val get_seq : 'a -> ('a, 'b) t -> 'b sequence
(** Select a key from a map and wrap into sequence *)
val iter : ('a,'b) t -> ('a*'b) sequence
(** View a multimap as a proper collection *)
val flatten : ('a,'b sequence) t -> ('a*'b) sequence
(** View a multimap as a collection of individual key/value pairs *)
val flatten_l : ('a,'b list) t -> ('a*'b) sequence
(** View a multimap as a list of individual key/value pairs *)
end
(** {2 Query operators} *)
type 'a t
(** Type of a query that returns zero, one or more values of type 'a *)
(** {6 Initial values} *)
val empty : 'a t
(** Empty collection *)
val start : 'a -> 'a t
(** Start with a single value
@deprecated since 0.13, use {!return} instead *)
val return : 'a -> 'a t
(** Return one value *)
val of_list : 'a list -> 'a t
(** Query that just returns the elements of the list *)
val of_array : 'a array -> 'a t
val of_array_i : 'a array -> (int * 'a) t
val range : int -> int -> int t
(** [range i j] goes from [i] up to [j] included *)
val (--) : int -> int -> int t
(** Synonym to {!range} *)
val of_hashtbl : ('a,'b) Hashtbl.t -> ('a * 'b) t
val of_seq : 'a sequence -> 'a t
(** Query that returns the elements of the given sequence. *)
val of_queue : 'a Queue.t -> 'a t
val of_stack : 'a Stack.t -> 'a t
val of_string : string -> char t
(** Traverse the characters of the string *)
(** {6 Execution} *)
val run : ?limit:int -> 'a t -> 'a sequence
(** Execute the query, possibly returning an error if things go wrong
@param limit max number of values to return *)
val run1 : 'a t -> 'a
(** Run the query and return the first value
@raise Not_found if the query succeeds with 0 element *)
val run_no_optim : ?limit:int -> 'a t -> 'a sequence
(** Run without any optimization *)
(** {6 Basics} *)
val map : ('a -> 'b) -> 'a t -> 'b t
(** Map each value *)
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
(** Infix synonym of {!map} *)
val filter : ('a -> bool) -> 'a t -> 'a t
(** Filter out values that do not satisfy predicate *)
val size : _ t -> int t
(** [size t] returns one value, the number of items returned by [t] *)
val choose : 'a t -> 'a t
(** Choose one element (if any, otherwise empty) in the collection.
This is like a "cut" in prolog. *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
(** Filter and map elements at once *)
val flat_map : ('a -> 'b sequence) -> 'a t -> 'b t
(** Same as {!flat_map} but using sequences *)
val flat_map_l : ('a -> 'b list) -> 'a t -> 'b t
(** map each element to a collection and flatten the result *)
val flatten : 'a list t -> 'a t
val flatten_seq : 'a sequence t -> 'a t
val take : int -> 'a t -> 'a t
(** Take at most [n] elements *)
val take_while : ('a -> bool) -> 'a t -> 'a t
(** Take elements while they satisfy a predicate *)
val sort : ?cmp:'a ord -> unit -> 'a t -> 'a t
(** Sort items by the given comparison function *)
val distinct : ?cmp:'a ord -> unit -> 'a t -> 'a t
(** Remove duplicate elements from the input collection.
All elements in the result are distinct. *)
(** {6 Aggregation} *)
val group_by : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash ->
('a -> 'b) -> 'a t -> ('b,'a list) PMap.t t
(** [group_by f] takes a collection [c] as input, and returns
a multimap [m] such that for each [x] in [c],
[x] occurs in [m] under the key [f x]. In other words, [f] is used
to obtain a key from [x], and [x] is added to the multimap using this key. *)
val group_by' : ?cmp:'b ord -> ?eq:'b equal -> ?hash:'b hash ->
('a -> 'b) -> 'a t -> ('b * 'a list) t
val count : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash ->
unit -> 'a t -> ('a, int) PMap.t t
(** [count c] returns a map from elements of [c] to the number
of time those elements occur. *)
val count' : ?cmp:'a ord -> unit -> 'a t -> ('a * int) t
val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b t
(** Fold over the collection *)
val reduce : ('a -> 'b) -> ('a -> 'b -> 'b) -> ('b -> 'c) ->
'a t -> 'c t
(** [reduce start mix stop q] uses [start] on the first element of [q],
and combine the result with following elements using [mix]. The final
value is transformed using [stop]. *)
val is_empty : 'a t -> bool t
val sum : int t -> int t
val contains : ?eq:'a equal -> 'a -> 'a t -> bool t
val average : int t -> int t
val max : int t -> int t
val min : int t -> int t
val for_all : ('a -> bool) -> 'a t -> bool t
val exists : ('a -> bool) -> 'a t -> bool t
val find : ('a -> bool) -> 'a t -> 'a option t
val find_map : ('a -> 'b option) -> 'a t -> 'b option t
(** {6 Binary Operators} *)
val join : ?cmp:'key ord -> ?eq:'key equal -> ?hash:'key hash ->
('a -> 'key) -> ('b -> 'key) ->
merge:('key -> 'a -> 'b -> 'c option) ->
'a t -> 'b t -> 'c t
(** [join key1 key2 ~merge] is a binary operation
that takes two collections [a] and [b], projects their
elements resp. with [key1] and [key2], and combine
values [(x,y)] from [(a,b)] with the same [key]
using [merge]. If [merge] returns [None], the combination
of values is discarded. *)
val group_join : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash ->
('b -> 'a) -> 'a t -> 'b t ->
('a, 'b list) PMap.t t
(** [group_join key2] associates to every element [x] of
the first collection, all the elements [y] of the second
collection such that [eq x (key y)] *)
val product : 'a t -> 'b t -> ('a * 'b) t
(** Cartesian product *)
val append : 'a t -> 'a t -> 'a t
(** Append two collections together *)
val inter : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> unit ->
'a t -> 'a t -> 'a t
(** Intersection of two collections. Each element will occur at most once
in the result *)
val union : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> unit ->
'a t -> 'a t -> 'a t
(** Union of two collections. Each element will occur at most once
in the result *)
val diff : ?cmp:'a ord -> ?eq:'a equal -> ?hash:'a hash -> unit ->
'a t -> 'a t -> 'a t
(** Set difference *)
(** {6 Tuple and Options} *)
(** Specialized projection operators *)
val fst : ('a * 'b) t -> 'a t
val snd : ('a * 'b) t -> 'b t
val map1 : ('a -> 'b) -> ('a * 'c) t -> ('b * 'c) t
val map2 : ('a -> 'b) -> ('c * 'a) t -> ('c * 'b) t
val flatten_opt : 'a option t -> 'a t
(** Flatten the collection by removing options *)
(** {6 Applicative} *)
val pure : 'a -> 'a t
(** Synonym to {!return} *)
val app : ('a -> 'b) t -> 'a t -> 'b t
(** Apply each function to each value *)
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
(** Infix synonym to {!app} *)
(** {6 Monad}
Careful, those operators do not allow any optimization before running the
query, they might therefore be pretty slow. *)
val bind : ('a -> 'b t) -> 'a t -> 'b t
(** Use the result of a query to build another query and immediately run it. *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Infix version of {!bind} *)
(** {6 Misc} *)
val lazy_ : 'a lazy_t t -> 'a t
val opt_unwrap : 'a option t -> 'a t
val reflect : 'a t -> 'a sequence t
(** [reflect q] evaluates all values in [q] and returns a sequence
of all those values. Also blocks optimizations *)
(** {6 Infix} *)
module Infix : sig
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
val (--) : int -> int -> int t
end
(** {6 Adapters} *)
val to_seq : 'a t -> 'a sequence t
(** Build a (re-usable) sequence of elements, which can then be
converted into other structures *)
val to_hashtbl : ('a * 'b) t -> ('a, 'b) Hashtbl.t t
(** Build a hashtable from the collection *)
val to_queue : 'a t -> 'a Queue.t t
val to_stack : 'a t -> 'a Stack.t t
module List : sig
val of_list : 'a list -> 'a t
val to_list : 'a t -> 'a list t
val run : 'a t -> 'a list
end
module Array : sig
val of_array : 'a array -> 'a t
val to_array : 'a t -> 'a array t
val run : 'a t -> 'a array
end
module AdaptSet(S : Set.S) : sig
val of_set : S.t -> S.elt t
val to_set : S.elt t -> S.t t
val run : S.elt t -> S.t
end
module AdaptMap(M : Map.S) : sig
val of_map : 'a M.t -> (M.key * 'a) t
val to_pmap : 'a M.t -> (M.key, 'a) PMap.t
val to_map : (M.key * 'a) t -> 'a M.t t
val run : (M.key * 'a) t -> 'a M.t
end
module IO : sig
val slurp : in_channel -> string t
(** Slurp the whole channel in (blocking), returning the
corresponding string. The channel will be read at most once
during execution, and its content cached; however the channel
might never get read because evaluation is lazy. *)
val slurp_file : string -> string t
(** Read a whole file (given by name) and return its content as
a string *)
val lines : string t -> string t
(** Convert a string into a collection of lines *)
val lines' : string t -> string list t
(** Convert a string into a list of lines *)
val join : string -> string t -> string t
val unlines : string t -> string t
(** Join lines together *)
val out : out_channel -> string t -> unit
val out_lines : out_channel -> string t -> unit
(** Evaluate the query and print it line by line on the output *)
(** {8 Run methods} *)
val to_file : string -> string t -> unit with_err
val to_file_exn : string -> string t -> unit
val to_file_lines : string -> string t -> unit with_err
val to_file_lines_exn : string -> string t -> unit
end

View file

@ -1,519 +0,0 @@
(*
copyright (c) 2013-2014, 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 IO Monad} *)
type _ t =
| Return : 'a -> 'a t
| Fail : string -> 'a t
| Map : ('a -> 'b) * 'a t -> 'b t
| Bind : ('a -> 'b t) * 'a t -> 'b t
| WithGuard: unit t * 'a t -> 'a t (* run guard in any case *)
| Star : ('a -> 'b) t * 'a t -> 'b t
| Repeat : int * 'a t -> 'a list t
| RepeatIgnore : int * 'a t -> unit t
| Wrap : (unit -> 'a) -> 'a t
| SequenceMap : ('a -> 'b t) * 'a list -> 'b list t
type 'a io = 'a t
type 'a with_finalizer = ('a t * unit t) t
type 'a or_error = [ `Ok of 'a | `Error of string ]
let (>>=) x f = Bind(f,x)
let bind ?finalize f a = match finalize with
| None -> Bind(f,a)
| Some b -> WithGuard (b, Bind (f,a))
let map f x = Map(f, x)
let (>|=) x f = Map(f, x)
let return x = Return x
let pure = return
let fail msg = Fail msg
let (<*>) f a = Star (f, a)
let lift = map
let lift2 f a b =
a >>= fun x -> map (f x) b
let lift3 f a b c =
a >>= fun x ->
b >>= fun y -> map (f x y) c
let sequence_map f l =
SequenceMap (f,l)
let sequence l =
let _id x = x in
SequenceMap(_id, l)
let repeat i a =
if i <= 0 then Return [] else Repeat (i,a)
let repeat' i a =
if i <= 0 then Return () else RepeatIgnore (i,a)
(** {2 Finalizers} *)
let (>>>=) a f =
a >>= function
| x, finalizer -> WithGuard (finalizer, x >>= f)
(** {2 Running} *)
exception IOFailure of string
let rec _run : type a. a t -> a = function
| Return x -> x
| Fail msg -> raise (IOFailure msg)
| Map (f, a) -> f (_run a)
| Bind (f, a) -> _run (f (_run a))
| WithGuard (g, a) ->
begin try
let res = _run a in
_run g;
res
with e ->
_run g;
raise e
end
| Star (f, a) -> _run f (_run a)
| Repeat (i,a) -> _repeat [] i a
| RepeatIgnore (i,a) -> _repeat_ignore i a
| Wrap f -> f()
| SequenceMap (f, l) -> _sequence_map f l []
and _repeat : type a. a list -> int -> a t -> a list
= fun acc i a -> match i with
| 0 -> List.rev acc
| _ ->
let x = _run a in
_repeat (x::acc) (i-1) a
and _repeat_ignore : type a. int -> a t -> unit
= fun i a -> match i with
| 0 -> ()
| _ ->
let _ = _run a in
_repeat_ignore (i-1) a
and _sequence_map : type a b. (a -> b t) -> a list -> b list -> b list
= fun f l acc -> match l with
| [] -> List.rev acc
| a::tail ->
let x = _run (f a) in
_sequence_map f tail (x::acc)
let _printers =
ref [
(* default printer *)
( function IOFailure msg
| Sys_error msg -> Some msg
| Exit -> Some "exit"
| _ -> None
)
]
exception PrinterResult of string
let _print_exn e =
try
List.iter
(fun p -> match p e with
| None -> ()
| Some msg -> raise (PrinterResult msg)
) !_printers;
Printexc.to_string e
with PrinterResult s -> s
let run x =
try `Ok (_run x)
with e -> `Error (_print_exn e)
exception IO_error of string
let run_exn x =
try _run x
with e -> raise (IO_error (_print_exn e))
let register_printer p = _printers := p :: !_printers
(** {2 Standard Wrappers} *)
let _open_in mode flags filename () =
open_in_gen flags mode filename
let _close_in ic () = close_in ic
let with_in ?(mode=0o644) ?(flags=[]) filename =
Wrap (_open_in mode flags filename)
>>= fun ic ->
Return (Return ic, Wrap (_close_in ic))
let _read ic s i len () = input ic s i len
let read ic s i len = Wrap (_read ic s i len)
let _read_line ic () =
try Some (Pervasives.input_line ic)
with End_of_file -> None
let read_line ic = Wrap(_read_line ic)
let rec _read_lines ic acc =
read_line ic
>>= function
| None -> return (List.rev acc)
| Some l -> _read_lines ic (l::acc)
let read_lines ic = _read_lines ic []
let read_all ic = Wrap(fun () -> CCIO.read_all ic)
let _open_out mode flags filename () =
open_out_gen flags mode filename
let _close_out oc () = close_out oc
let with_out ?(mode=0o644) ?(flags=[]) filename =
Wrap(_open_out mode (Open_wronly::flags) filename)
>>= fun oc ->
Return(Return oc, Wrap(_close_out oc))
let with_out_a ?mode ?(flags=[]) filename =
with_out ?mode ~flags:(Open_creat::Open_append::flags) filename
#if OCAML_MAJOR >= 4 && OCAML_MINOR >= 2
let output_str_ = Pervasives.output_substring
#else
let output_str_ = Pervasives.output
#endif
let _write oc s i len () = output_str_ oc s i len
let write oc s i len = Wrap (_write oc s i len)
let _write_str oc s () = output_str_ oc s 0 (String.length s)
let write_str oc s = Wrap (_write_str oc s)
let _write_line oc l () =
output_string oc l;
output_char oc '\n'
let write_line oc l = Wrap (_write_line oc l)
let _write_buf oc buf () = Buffer.output_buffer oc buf
let write_buf oc buf = Wrap (_write_buf oc buf)
let flush oc = Wrap (fun () -> Pervasives.flush oc)
(** {2 Seq} *)
module Seq = struct
type 'a step_result =
| Yield of 'a
| Stop
type 'a gen = unit -> 'a step_result io
type 'a t = 'a gen
let _stop () = return Stop
let _yield x = return (Yield x)
let map_pure f gen () =
gen() >>= function
| Stop -> _stop ()
| Yield x -> _yield (f x)
let map f g () =
g() >>= function
| Stop -> _stop ()
| Yield x -> f x >>= _yield
let rec filter_map f g () =
g() >>= function
| Stop -> _stop()
| Yield x ->
match f x with
| None -> filter_map f g()
| Some y -> _yield y
let rec filter f g () =
g() >>= function
| Stop -> _stop()
| Yield x ->
if f x then _yield x else filter f g()
let rec flat_map f g () =
g() >>= function
| Stop -> _stop ()
| Yield x ->
f x >>= fun g' -> _flat_map_aux f g g' ()
and _flat_map_aux f g g' () =
g'() >>= function
| Stop -> flat_map f g ()
| Yield x -> _yield x
let general_iter f acc g =
let acc = ref acc in
let rec _next () =
g() >>= function
| Stop -> _stop()
| Yield x ->
f !acc x >>= function
| `Stop -> _stop()
| `Continue (acc', ret) ->
acc := acc';
match ret with
| None -> _next()
| Some y -> _yield y
in
_next
let take n seq =
general_iter
(fun n x -> if n<=0
then return `Stop
else return (`Continue (n-1, Some x))
) n seq
let drop n seq =
general_iter
(fun n x -> if n<=0
then return (`Continue (n, Some x))
else return (`Continue (n-1, None))
) n seq
let take_while p seq =
general_iter
(fun () x ->
p x >|= function
| true -> `Continue ((), Some x)
| false -> `Stop
) () seq
let drop_while p seq =
general_iter
(fun dropping x ->
if dropping
then p x >|= function
| true -> `Continue (true, None)
| false -> `Continue (false, Some x)
else return (`Continue (false, Some x))
) true seq
(* apply all actions from [l] to [x] *)
let rec _apply_all_to x l = match l with
| [] -> return ()
| f::tail -> f x >>= fun () -> _apply_all_to x tail
let _tee funs g () =
g() >>= function
| Stop -> _stop()
| Yield x ->
_apply_all_to x funs >>= fun () ->
_yield x
let tee funs g = match funs with
| [] -> g
| _::_ -> _tee funs g
(** {6 Consume} *)
let rec fold_pure f acc g =
g() >>= function
| Stop -> return acc
| Yield x -> fold_pure f (f acc x) g
let length g = fold_pure (fun acc _ -> acc+1) 0 g
let rec fold f acc g =
g() >>= function
| Stop -> return acc
| Yield x ->
f acc x >>= fun acc' -> fold f acc' g
let rec iter f g =
g() >>= function
| Stop -> return ()
| Yield x -> f x >>= fun _ -> iter f g
let of_fun g = g
let empty () = _stop()
let singleton x =
let first = ref true in
fun () ->
if !first then (first := false; _yield x) else _stop()
let cons x g =
let first = ref true in
fun () ->
if !first then (first := false; _yield x) else g()
let of_list l =
let l = ref l in
fun () -> match !l with
| [] -> _stop()
| x::tail -> l:= tail; _yield x
let of_array a =
let i = ref 0 in
fun () ->
if !i = Array.length a
then _stop()
else (
let x = a.(!i) in
incr i;
_yield x
)
(* TODO: wrapper around with_in? using bind ~finalize:... ? *)
let chunks ~size ic =
let buf = Buffer.create size in
let eof = ref false in
let next() =
if !eof then _stop()
else try
Buffer.add_channel buf ic size;
let s = Buffer.contents buf in
Buffer.clear buf;
_yield s
with End_of_file ->
let s = Buffer.contents buf in
eof := true;
if s="" then _stop() else _yield s
in
next
let lines ic () =
try _yield (input_line ic)
with End_of_file -> _stop()
let words _g =
failwith "words: not implemented yet"
(* TODO: state machine that goes:
- 0: read input chunk
- switch to "search for ' '", and yield word
- goto 0 if no ' ' found
- yield leftover when g returns Stop
let buf = Buffer.create 32 in
let next() =
g() >>= function
| Stop -> _stop
| Yield s ->
Buffer.add_string buf s;
search_
in
next
*)
let output ?sep oc seq =
let first = ref true in
iter
(fun s ->
(* print separator *)
( if !first
then (first:=false; return ())
else match sep with
| None -> return ()
| Some sep -> write_str oc sep
) >>= fun () ->
write_str oc s
) seq
>>= fun () -> flush oc
end
(** {6 File and file names} *)
module File = struct
type t = string
let to_string f = f
let make f =
if Filename.is_relative f
then Filename.concat (Sys.getcwd()) f
else f
let exists f = Wrap (fun () -> Sys.file_exists f)
let is_directory f = Wrap (fun () -> Sys.is_directory f)
let remove f = Wrap (fun () -> Sys.remove f)
let _read_dir d () =
if Sys.is_directory d
then
let arr = Sys.readdir d in
Seq.map_pure make (Seq.of_array arr)
else Seq.empty
let rec _walk d () =
if Sys.is_directory d
then
let arr = Sys.readdir d in
let tail = Seq.of_array arr in
let tail = Seq.flat_map
(fun s -> return (_walk (Filename.concat d s) ()))
tail
in Seq.cons (`Dir,d) tail
else Seq.singleton (`File, d)
let walk t = Wrap (_walk t)
let read_dir ?(recurse=false) d =
if recurse
then walk d
>|= Seq.filter_map
(function
| `File, f -> Some f
| `Dir, _ -> None
)
else Wrap (_read_dir d)
let rec _read_dir_rec d () =
if Sys.is_directory d
then
let arr = Sys.readdir d in
let arr = Seq.of_array arr in
let arr = Seq.map_pure (fun s -> Filename.concat d s) arr in
Seq.flat_map
(fun s ->
if Sys.is_directory s
then return (_read_dir_rec s ())
else return (Seq.singleton s)
) arr
else Seq.empty
end
(** {2 Raw} *)
module Raw = struct
let wrap f = Wrap f
end

View file

@ -1,322 +0,0 @@
(*
copyright (c) 2013-2014, 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 IO Monad}
A simple abstraction over blocking IO, with strict evaluation. This is in
no way an alternative to Lwt/Async if you need concurrency.
@since 0.3.3
*)
(**
Examples:
- obtain the list of lines of a file:
{[
let l = CCIO.((with_in "/tmp/some_file" >>>= read_lines) |> run_exn);;
]}
- transfer one file into another:
{[
# let a = CCIO.(
with_in "input" >>>= fun ic ->
with_out ~flags:[Open_creat] "output" >>>= fun oc ->
Seq.chunks 512 ic
|> Seq.output oc
) ;;
# run a;;
]}
*)
type 'a t
type 'a io = 'a t
type 'a with_finalizer
(** A value of type ['a with_finalizer] is similar to a value ['a t] but
also contains a finalizer that must be run to cleanup.
See {!(>>>=)} to get rid of it. *)
type 'a or_error = [ `Ok of 'a | `Error of string ]
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Wait for the result of an action, then use a function to build a
new action and execute it *)
val return : 'a -> 'a t
(** Just return a value *)
val repeat : int -> 'a t -> 'a list t
(** Repeat an IO action as many times as required *)
val repeat' : int -> 'a t -> unit t
(** Same as {!repeat}, but ignores the result *)
val map : ('a -> 'b) -> 'a t -> 'b t
(** Map values *)
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
val bind : ?finalize:(unit t) -> ('a -> 'b t) -> 'a t -> 'b t
(** [bind f a] runs the action [a] and applies [f] to its result
to obtain a new action. It then behaves exactly like this new
action.
@param finalize an optional action that is always run after evaluating
the whole action *)
val pure : 'a -> 'a t
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
val lift : ('a -> 'b) -> 'a t -> 'b t
(** Synonym to {!map} *)
val lift2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
val lift3 : ('a -> 'b -> 'c -> 'd) -> 'a t -> 'b t -> 'c t -> 'd t
val sequence : 'a t list -> 'a list t
(** Runs operations one by one and gather their results *)
val sequence_map : ('a -> 'b t) -> 'a list -> 'b list t
(** Generalization of {!sequence} *)
val fail : string -> 'a t
(** [fail msg] fails with the given message. Running the IO value will
return an [`Error] variant *)
(** {2 Finalizers} *)
val (>>>=) : 'a with_finalizer -> ('a -> 'b t) -> 'b t
(** Same as {!(>>=)}, but taking the finalizer into account. Once this
IO value is done executing, the finalizer is executed and the resource,
fred. *)
(** {2 Running} *)
val run : 'a t -> 'a or_error
(** Run an IO action.
@return either [`Ok x] when [x] is the successful result of the
computation, or some [`Error "message"] *)
exception IO_error of string
val run_exn : 'a t -> 'a
(** Unsafe version of {!run}. It assumes non-failure.
@raise IO_error if the execution didn't go well *)
val register_printer : (exn -> string option) -> unit
(** [register_printer p] register [p] as a possible failure printer.
If [run a] raises an exception [e], [p e] is evaluated. If [p e = Some msg]
then the error message will be [msg], otherwise other printers will
be tried *)
(** {2 Standard Wrappers} *)
(** {6 Input} *)
val with_in : ?mode:int -> ?flags:open_flag list ->
string -> in_channel with_finalizer
(** Open an input file with the given optional flag list.
It yields a [in_channel] with a finalizer attached. See {!(>>>=)} to
use it. *)
val read : in_channel -> Bytes.t -> int -> int -> int t
(** Read a chunk into the given string *)
val read_line : in_channel -> string option t
(** Read a line from the channel. Returns [None] if the input is terminated. *)
val read_lines : in_channel -> string list t
(** Read all lines eagerly *)
val read_all : in_channel -> string t
(** Read the whole channel into a buffer, then converted into a string *)
(** {6 Output} *)
val with_out : ?mode:int -> ?flags:open_flag list ->
string -> out_channel with_finalizer
(** Same as {!with_in} but for an output channel *)
val with_out_a : ?mode:int -> ?flags:open_flag list ->
string -> out_channel with_finalizer
(** Similar to {!with_out} but with the [Open_append] and [Open_creat]
flags activated *)
val write : out_channel -> string -> int -> int -> unit t
val write_str : out_channel -> string -> unit t
val write_buf : out_channel -> Buffer.t -> unit t
val write_line : out_channel -> string -> unit t
val flush : out_channel -> unit t
(* TODO: printf/fprintf wrappers *)
(** {2 Streams}
Iterators on chunks of bytes, or lines, or any other value using combinators.
Those iterators are usable only once, because their source might
be usable only once (think of a socket) *)
module Seq : sig
type 'a t
(** An IO stream of values of type 'a, consumable (iterable only once) *)
val map : ('a -> 'b io) -> 'a t -> 'b t
(** Map values with actions *)
val map_pure : ('a -> 'b) -> 'a t -> 'b t
(** Map values with a pure function *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
val filter : ('a -> bool) -> 'a t -> 'a t
val flat_map : ('a -> 'b t io) -> 'a t -> 'b t
(** Map each value to a sub sequence of values *)
val take : int -> 'a t -> 'a t
val drop : int -> 'a t -> 'a t
val take_while : ('a -> bool io) -> 'a t -> 'a t
val drop_while : ('a -> bool io) -> 'a t -> 'a t
val general_iter : ('b -> 'a -> [`Stop | `Continue of ('b * 'c option)] io) ->
'b -> 'a t -> 'c t
(** [general_iter f acc seq] performs a [filter_map] over [seq],
using [f]. [f] is given a state and the current value, and
can either return [`Stop] to indicate it stops traversing,
or [`Continue (st, c)] where [st] is the new state and
[c] an optional output value.
The result is the stream of values output by [f] *)
val tee : ('a -> unit io) list -> 'a t -> 'a t
(** [tee funs seq] behaves like [seq], but each element is given to
every function [f] in [funs]. This function [f] returns an action that
is eagerly executed. *)
(** {6 Consume} *)
val iter : ('a -> _ io) -> 'a t -> unit io
(** Iterate on the stream, with an action for each element *)
val length : _ t -> int io
(** Length of the stream *)
val fold : ('b -> 'a -> 'b io) -> 'b -> 'a t -> 'b io
(** [fold f acc seq] folds over [seq], consuming it. Every call to [f]
has the right to return an IO value. *)
val fold_pure : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b io
(** [fold f acc seq] folds over [seq], consuming it. [f] is pure. *)
(** {6 Standard Wrappers} *)
type 'a step_result =
| Yield of 'a
| Stop
type 'a gen = unit -> 'a step_result io
val of_fun : 'a gen -> 'a t
(** Create a stream from a function that yields an element or stops *)
val empty : 'a t
val singleton : 'a -> 'a t
val cons : 'a -> 'a t -> 'a t
val of_list : 'a list -> 'a t
val of_array : 'a array -> 'a t
val chunks : size:int -> in_channel -> string t
(** Read the channel's content into chunks of size [size] *)
val lines : in_channel -> string t
(** Lines of an input channel *)
val words : string t -> string t
(** Split strings into words at " " boundaries.
{b NOT IMPLEMENTED} *)
val output : ?sep:string -> out_channel -> string t -> unit io
(** [output oc seq] outputs every value of [seq] into [oc], separated
with the optional argument [sep] (default: None).
It blocks until all values of [seq] are produced and written to [oc]. *)
end
(** {6 File and file names}
How to list recursively files in a directory:
{[
CCIO.(
File.read_dir ~recurse:true (File.make "/tmp")
>>= Seq.output ~sep:"\n" stdout
) |> CCIO.run_exn ;;
]}
See {!File.walk} if you also need to list directories.
*)
module File : sig
type t = string
(** A file is always represented by its absolute path *)
val to_string : t -> string
val make : string -> t
(** Build a file representation from a path (absolute or relative) *)
val exists : t -> bool io
val is_directory : t -> bool io
val remove : t -> unit io
val read_dir : ?recurse:bool -> t -> t Seq.t io
(** [read_dir d] returns a sequence of files and directory contained
in the directory [d] (or an empty stream if [d] is not a directory)
@param recurse if true (default [false]), sub-directories are also
explored *)
val walk : t -> ([`File | `Dir] * t) Seq.t io
(** Similar to {!read_dir} (with [recurse=true]), this function walks
a directory recursively and yields either files or directories.
Is a file anything that doesn't satisfy {!is_directory} (including
symlinks, etc.) *)
end
(** {2 Low level access} *)
module Raw : sig
val wrap : (unit -> 'a) -> 'a t
(** [wrap f] is the IO action that, when executed, returns [f ()].
[f] should be callable as many times as required *)
end

View file

@ -1,29 +0,0 @@
(*
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.
*)
module Batch = CCBatch
module Cat = CCCat
module Linq = CCLinq
module MonadIO = CCMonadIO

View file

@ -0,0 +1,183 @@
module Str_map = Map.Make (String)
type t =
| Int of int64
| String of string
| List of t list
| Map of t Str_map.t
let rec equal t1 t2 =
match t1, t2 with
| Int i1, Int i2 -> i1 = i2
| String s1, String s2 -> s1 = s2
| List l1, List l2 ->
(try List.for_all2 equal l1 l2 with Invalid_argument _ -> false)
| Map d1, Map d2 -> Str_map.equal equal d1 d2
| (Int _ | String _ | List _ | Map _), _ -> false
let rec hash t =
let module H = CCHash in
match t with
| Int i -> H.int64 i
| String s -> H.combine2 10 (H.string s)
| List l -> H.combine2 20 (H.list hash l)
| Map l ->
H.combine2 30
( H.iter (H.pair H.string hash) @@ fun k ->
Str_map.iter (fun x y -> k (x, y)) l )
let int64 i : t = Int i
let int i : t = int64 (Int64.of_int i)
let string s : t = String s
let list l : t = List l
let map m : t = Map m
let map_of_list l : t =
map @@ List.fold_left (fun m (k, v) -> Str_map.add k v m) Str_map.empty l
let rec pp_debug out (self : t) : unit =
let fpf = Format.fprintf in
match self with
| Int i -> fpf out "%Ld" i
| String s -> fpf out "%S" s
| List l ->
fpf out "[@[<hv>";
List.iteri
(fun i v ->
if i > 0 then fpf out ";@ ";
pp_debug out v)
l;
fpf out "@]]"
| Map m ->
fpf out "{@[<hv>";
let i = ref 0 in
Str_map.iter
(fun k v ->
if !i > 0 then fpf out ";@ ";
incr i;
fpf out "@[<1>%S:@ %a@]" k pp_debug v)
m;
fpf out "@]}"
let to_string_debug self = Format.asprintf "%a" pp_debug self
module Encode = struct
let bpf = Printf.bprintf
let fpf = Printf.fprintf
let rec to_buffer (buf : Buffer.t) (self : t) : unit =
let recurse = to_buffer buf in
let addc = Buffer.add_char in
match self with
| Int i -> bpf buf "i%Lde" i
| String s -> bpf buf "%d:%s" (String.length s) s
| List l ->
addc buf 'l';
List.iter recurse l;
addc buf 'e'
| Map l ->
addc buf 'd';
Str_map.iter
(fun k v -> bpf buf "%d:%s%a" (String.length k) k to_buffer v)
l;
addc buf 'e'
let to_string (self : t) : string =
let buf = Buffer.create 32 in
to_buffer buf self;
Buffer.contents buf
let rec to_chan (oc : out_channel) (self : t) : unit =
let recurse = to_chan oc in
let addc = output_char in
match self with
| Int i -> fpf oc "i%Lde" i
| String s -> fpf oc "%d:%s" (String.length s) s
| List l ->
addc oc 'l';
List.iter recurse l;
addc oc 'e'
| Map l ->
addc oc 'd';
Str_map.iter (fun k v -> fpf oc "%d:%s%a" (String.length k) k to_chan v) l;
addc oc 'e'
let to_fmt out self = Format.pp_print_string out (to_string self)
end
module Decode = struct
exception Fail
let of_string s =
let i = ref 0 in
let[@inline] check_not_eof () =
if !i >= String.length s then raise_notrace Fail
in
let rec top () : t =
check_not_eof ();
match String.unsafe_get s !i with
| 'l' ->
incr i;
read_list []
| 'd' ->
incr i;
read_map Str_map.empty
| 'i' ->
incr i;
let n = read_int 'e' true 0 in
int n
| '0' .. '9' -> String (parse_str_len ())
| _ -> raise_notrace Fail
(* read integer until char [stop] is met, consume [stop], return int *)
and read_int stop sign n : int =
check_not_eof ();
match String.unsafe_get s !i with
| c when c == stop ->
incr i;
if sign then
n
else
-n
| '-' when stop == 'e' && sign && n = 0 ->
incr i;
read_int stop false n
| '0' .. '9' as c ->
incr i;
read_int stop sign (Char.code c - Char.code '0' + (10 * n))
| _ -> raise_notrace Fail
and parse_str_len () : string =
let n = read_int ':' true 0 in
if !i + n > String.length s then raise_notrace Fail;
let s = String.sub s !i n in
i := !i + n;
s
and read_list acc =
check_not_eof ();
match String.unsafe_get s !i with
| 'e' ->
incr i;
List (List.rev acc)
| _ ->
let x = top () in
read_list (x :: acc)
and read_map acc =
check_not_eof ();
match String.unsafe_get s !i with
| 'e' ->
incr i;
Map acc
| _ ->
let k = parse_str_len () in
let v = top () in
read_map (Str_map.add k v acc)
in
try Some (top ()) with Fail -> None
let of_string_exn s =
match of_string s with
| Some x -> x
| None -> failwith "bencode.decode: invalid string"
end

View file

@ -0,0 +1,44 @@
(** Basic Bencode decoder/encoder.
See https://en.wikipedia.org/wiki/Bencode .
@since 3.8 *)
module Str_map : module type of Map.Make (String)
type t =
| Int of int64
| String of string
| List of t list
| Map of t Str_map.t
val equal : t -> t -> bool
val hash : t -> int
val pp_debug : Format.formatter -> t -> unit
(** Printer for diagnostic/human consumption *)
val to_string_debug : t -> string
val int : int -> t
val int64 : int64 -> t
val string : string -> t
val list : t list -> t
val map_of_list : (string * t) list -> t
val map : t Str_map.t -> t
(** Encoding *)
module Encode : sig
val to_string : t -> string
val to_buffer : Buffer.t -> t -> unit
val to_chan : out_channel -> t -> unit
val to_fmt : Format.formatter -> t -> unit
end
(** Decoding *)
module Decode : sig
val of_string : string -> t option
val of_string_exn : string -> t
(** Parse string.
@raise Failure if the string is not valid bencode. *)
end

5
src/bencode/dune Normal file
View file

@ -0,0 +1,5 @@
(library
(name containers_bencode)
(public_name containers.bencode)
(libraries containers)
(synopsis "Bencode codec for containers (the format for bittorrent files)"))

View file

@ -1,753 +0,0 @@
(*
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 Bigarrays of dimension 1 *)
module A = Bigarray.Array1
type 'a printer = Format.formatter -> 'a -> unit
type 'a sequence = ('a -> unit) -> unit
type 'a or_error = [`Ok of 'a | `Error of string]
type random = Random.State.t
type json = [ `Assoc of (string * json) list
| `Bool of bool
| `Float of float
| `Int of int
| `List of json list
| `Null
| `String of string ]
type 'a to_json = 'a -> json
type 'a of_json = json -> 'a or_error
type ('a, 'b, 'perm) t =
('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
constraint 'perm = [< `R | `W]
type ('a, 'b, 'perm) array_ = ('a, 'b, 'perm) t
exception WrongDimension
let make ?x ~kind n =
let a = A.create kind Bigarray.c_layout n in
begin match x with
| None -> ()
| Some x -> A.fill a x
end;
a
let make_int n = make ~kind:Bigarray.int n
let make_char n = make ~kind:Bigarray.char n
let make_int8s n = make ~kind:Bigarray.int8_signed n
let make_int8u n = make ~kind:Bigarray.int8_unsigned n
let make_int16s n = make ~kind:Bigarray.int16_signed n
let make_int16u n = make ~kind:Bigarray.int16_unsigned n
let make_int32 n = make ~kind:Bigarray.int32 n
let make_int64 n = make ~kind:Bigarray.int64 n
let make_native n = make ~kind:Bigarray.nativeint n
let make_float32 n = make ~kind:Bigarray.float32 n
let make_float64 n = make ~kind:Bigarray.float64 n
let make_complex32 n = make ~kind:Bigarray.complex32 n
let make_complex64 n = make ~kind:Bigarray.complex64 n
let init ~kind ~f n =
let a = A.create kind Bigarray.c_layout n in
for i = 0 to n-1 do
A.unsafe_set a i (f i)
done;
a
(*$T
let a = init ~kind:Bigarray.int 10 ~f:(fun x->x) in \
CCList.(0 -- 9) |> List.for_all (fun i -> get a i = i)
*)
let of_bigarray a = a
let to_bigarray a = a
let ro (t : ('a,'b,[>`R]) t) : ('a,'b,[`R]) t = t
let wo (t : ('a,'b,[>`W]) t) : ('a,'b,[`W]) t = t
let fill = A.fill
let copy a =
let b = make ~kind:(A.kind a) (A.dim a) in
A.blit a b;
b
let length a = A.dim a
(*$T
length (make_int 42) = 42
*)
let set = A.set
let get = A.get
let blit = A.blit
let sub = A.sub
let iter ~f a =
for i = 0 to A.dim a - 1 do
f (A.unsafe_get a i)
done
exception LocalExit
let for_all ~f a =
try
for i = 0 to A.dim a - 1 do
if not (f (A.unsafe_get a i)) then raise LocalExit
done;
true
with LocalExit -> false
let exists ~f a =
try
for i = 0 to A.dim a - 1 do
if f (A.unsafe_get a i) then raise LocalExit
done;
false
with LocalExit -> true
(*$T
init ~kind:Bigarray.int 10 ~f:(fun x->x) |> for_all ~f:(fun x -> x<10)
init ~kind:Bigarray.int 10 ~f:(fun x->x) |> exists ~f:(fun x -> x=5)
*)
let iteri ~f a =
for i = 0 to A.dim a - 1 do
f i (A.unsafe_get a i)
done
let foldi f acc a =
let rec fold' f acc a i =
if i = A.dim a then acc
else
let acc = f acc i (A.unsafe_get a i) in
fold' f acc a (i+1)
in
fold' f acc a 0
let pp pp_x out a =
Format.pp_print_char out '[';
iteri a
~f:(fun i x ->
if i > 0 then Format.fprintf out ",@ ";
pp_x out x
);
Format.pp_print_char out ']';
()
module Bool = struct
type ('a, 'perm) t = (int, 'a, 'perm) array_
let set a i x = A.set a i (if x then 1 else 0)
let get a i = A.get a i <> 0
let zeroes n = make ~x:0 ~kind:Bigarray.int8_unsigned n
let ones n = make ~x:1 ~kind:Bigarray.int8_unsigned n
let iter_zeroes ~f a =
for i = 0 to A.dim a - 1 do
if A.unsafe_get a i = 0 then f i
done
let iter_ones ~f a =
for i = 0 to A.dim a - 1 do
if A.unsafe_get a i > 0 then f i
done
let cardinal a =
let rec fold a i acc =
if i = A.dim a then acc
else
let acc = if A.get a i <> 0 then acc+1 else acc in
fold a (i+1) acc
in
fold a 0 0
let or_ ?res a b =
let res = match res with
| Some r ->
if A.dim r <> max (A.dim a) (A.dim b) then raise WrongDimension;
A.fill r 0;
r
| None -> make ~x:0 ~kind:(A.kind a) (max (A.dim a) (A.dim b))
in
(* ensure [a] is no longer than [b] *)
let a, b = if A.dim a < A.dim b then a, b else b, a in
for i = 0 to A.dim a - 1 do
if A.unsafe_get a i > 0 || A.unsafe_get b i > 0
then set b i true
done;
res
let and_ ?res a b =
let res = match res with
| Some r ->
if A.dim r <> max (A.dim a) (A.dim b) then raise WrongDimension;
A.fill r 0;
r
| None -> make ~x:0 ~kind:(A.kind a) (max (A.dim a) (A.dim b))
in
(* ensure [a] is no longer than [b] *)
let a, b = if A.dim a < A.dim b then a, b else b, a in
for i=0 to A.dim a - 1 do
if A.unsafe_get a i > 0 && A.unsafe_get b i > 0
then set res i true
done;
res
let not_ ?res a =
let res = match res with
| Some r ->
if A.dim r <> A.dim a then raise WrongDimension;
A.fill r 0;
r
| None -> make ~x:0 ~kind:(A.kind a) (A.dim a)
in
for i=0 to A.dim a - 1 do
if A.unsafe_get a i = 0 then set res i true
done;
res
(* assumes dimensions are ok and [A.dim a >= A.dim b] *)
let mix_ a b ~res =
let na = A.dim a
and nb = A.dim b in
assert (nb <= na);
(* a has more bits, and we group them in successive chunks of size [d] *)
let step = 1 + (na + nb) / nb in
for i = 0 to na + nb - 1 do
let q, r = i / step, i mod step in
if r = 0
then set res i (get b q)
else set res i (get a (q + r - 1))
done
let mix ?res a b =
let res = match res with
| Some r ->
if A.dim a + A.dim b <> A.dim r then raise WrongDimension;
r
| None -> make ~kind:(A.kind a) (A.dim a + A.dim b)
in
if A.dim a < A.dim b then mix_ b a ~res else mix_ a b ~res;
res
let rec big_or_ a b i j acc =
if j = A.dim b then acc
else (* acc xor (a[i+j] and b[j]) *)
let acc = acc <> (get a ((i+j) mod A.dim a) && get b j) in
big_or_ a b i (j+1) acc
(* [into[i] = big_or_{j in [0...nb-1]} (a[i+j-1 mod na] and b[j]) *)
let convolution ?res a ~by:b =
let res = match res with
| Some r ->
if A.dim a < A.dim b || A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim res - 1 do
if big_or_ a b i 0 false then set res i true
done;
res
let pp out a = pp
(fun oc b ->
Format.pp_print_char oc (if b>0 then '1' else '0')
) out a
end
let append ?res a b =
let res = match res with
| Some r ->
if A.dim a + A.dim b <> A.dim r then raise WrongDimension;
r
| None -> make ~kind:(A.kind a) (A.dim a + A.dim b)
in
let n = A.dim a in
A.blit a (A.sub res 0 n);
A.blit b (A.sub res n (A.dim b));
res
let map ?res ~f a =
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~kind:(A.kind a) (A.dim a)
in
for i=0 to A.dim a - 1 do
A.set res i (f (A.unsafe_get a i))
done;
res
let map2 ?res ~f a b =
if A.dim a <> A.dim b then raise WrongDimension;
let res = match res with
| Some r ->
if A.dim r <> A.dim a then raise WrongDimension;
r
| None -> make ~kind:(A.kind a) (A.dim a)
in
for i=0 to A.dim a - 1 do
A.set res i (f (A.unsafe_get a i) (A.unsafe_get b i))
done;
res
let filter ?res ~f a =
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0 ~kind:Bigarray.int8_unsigned (A.dim a)
in
for i=0 to A.dim a - 1 do
if f (A.unsafe_get a i)
then Bool.set res i true
done;
res
module type S = sig
type elt
type ('a, 'perm) t = (elt, 'a, 'perm) array_
val add :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
('a, [>`R]) t ->
('a, 'perm) t
(** Elementwise sum
@raise WrongDimension if dimensions do not fit *)
val mult :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
('a, [>`R]) t ->
('a, 'perm) t
(** Elementwise product *)
val scalar_add :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
x:elt ->
('a, 'perm) t
(** @raise WrongDimension if dimensions do not fit *)
val scalar_mult :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
x:elt ->
('a, 'perm) t
(** @raise WrongDimension if dimensions do not fit *)
val sum_elt : (_, [>`R]) t -> elt
(** Efficient sum of elements *)
val product_elt : (_, [>`R]) t -> elt
(** Efficient product of elements *)
val dot_product : (_, [>`R]) t -> (_, [>`R]) t -> elt
(** [dot_product a b] returns [sum_i a(i)*b(i)] with the given
sum and product, on [elt].
[dot_product a b = sum_elt (product a b)]
@raise WrongDimension if [a] and [b] do not have the same size *)
module Infix : sig
val ( * ) : ('a, [>`R]) t -> ('a, [>`R]) t -> ('a, 'perm) t
(** Alias to {!mult} *)
val ( + ) : ('a, [>`R]) t -> (_, [>`R]) t -> ('a, 'perm) t
(** Alias to {!add} *)
val ( *! ) : ('a, [>`R]) t -> elt -> ('a, 'perm) t
(** Alias to {!scalar_mult} *)
val ( +! ) : ('a, [>`R]) t -> elt -> ('a, 'perm) t
(** Alias to {!scalar_add} *)
end
include module type of Infix
end
module Int = struct
type elt = int
type ('a, 'perm) t = (elt, 'a, 'perm) array_
let add ?res a b =
if A.dim a <> A.dim b then raise WrongDimension;
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0 ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i + A.unsafe_get b i)
done;
res
let mult ?res a b =
if A.dim a <> A.dim b then raise WrongDimension;
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0 ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i * A.unsafe_get b i)
done;
res
let scalar_add ?res a ~x =
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0 ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i + x)
done;
res
let scalar_mult ?res a ~x =
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0 ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i * x)
done;
res
let dot_product a b =
if A.dim a <> A.dim b then raise WrongDimension;
let r = ref 0 in
for i = 0 to A.dim a - 1 do
r := !r + (A.unsafe_get a i * A.unsafe_get b i)
done;
!r
let sum_elt a =
let r = ref 0 in
for i = 0 to A.dim a - 1 do
r := !r + A.unsafe_get a i
done;
!r
let product_elt a =
let r = ref 1 in
for i = 0 to A.dim a - 1 do
r := !r * A.unsafe_get a i
done;
!r
module Infix = struct
let ( + ) a b = add a b
let ( * ) a b = mult a b
let ( +! ) a x = scalar_add a ~x
let ( *! ) a x = scalar_mult a ~x
end
include Infix
end
module Float = struct
type elt = float
type ('a, 'perm) t = (elt, 'a, 'perm) array_
let add ?res a b =
if A.dim a <> A.dim b then raise WrongDimension;
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0. ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i +. A.unsafe_get b i)
done;
res
let mult ?res a b =
if A.dim a <> A.dim b then raise WrongDimension;
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0. ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i *. A.unsafe_get b i)
done;
res
let scalar_add ?res a ~x =
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0. ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i +. x)
done;
res
let scalar_mult ?res a ~x =
let res = match res with
| Some r ->
if A.dim a <> A.dim r then raise WrongDimension;
r
| None -> make ~x:0. ~kind:(A.kind a) (A.dim a)
in
for i = 0 to A.dim a - 1 do
A.set res i (A.unsafe_get a i *. x)
done;
res
let dot_product a b =
if A.dim a <> A.dim b then raise WrongDimension;
let r = ref 0. in
for i = 0 to A.dim a - 1 do
r := !r +. (A.unsafe_get a i *. A.unsafe_get b i)
done;
!r
let sum_elt a =
let r = ref 0. in
for i = 0 to A.dim a - 1 do
r := !r +. A.unsafe_get a i
done;
!r
let product_elt a =
let r = ref 1. in
for i = 0 to A.dim a - 1 do
r := !r *. A.unsafe_get a i
done;
!r
module Infix = struct
let ( + ) a b = add a b
let ( * ) a b = mult a b
let ( +! ) a x = scalar_add a ~x
let ( *! ) a x = scalar_mult a ~x
end
include Infix
end
let to_list a =
let l = foldi (fun acc _ x -> x::acc) [] a in
List.rev l
let to_array a =
if A.dim a = 0 then [||]
else (
let b = Array.make (A.dim a) (A.get a 0) in
for i = 1 to A.dim a - 1 do
Array.unsafe_set b i (A.unsafe_get a i)
done;
b
)
let to_seq a yield = iter a ~f:yield
let of_array ~kind a = A.of_array kind Bigarray.c_layout a
exception OfYojsonError of string
let to_yojson (f:'a -> json) a : json =
let l = foldi (fun l _ x -> f x :: l) [] a in
`List (List.rev l)
let int_to_yojson i = `Int i
let int_of_yojson = function
| `Int i -> `Ok i
| `Float f -> `Ok (int_of_float f)
| `String s -> (try `Ok (int_of_string s) with _ -> `Error "expected int")
| _ -> `Error "expected int"
let float_to_yojson f = `Float f
let float_of_yojson = function
| `Float f -> `Ok f
| `Int i -> `Ok (float_of_int i)
| _ -> `Error "expected float"
let of_yojson
~(kind:('a,'b) Bigarray.kind)
(f: json -> 'a or_error)
(j : json) : ('a,'b,'perm) t or_error
=
let unwrap_ = function
| `Ok x -> x
| `Error msg -> raise (OfYojsonError msg)
in
let map_l l = List.map (fun x -> unwrap_ (f x)) l
and of_list l =
let a = make ~kind (List.length l) in
List.iteri (fun i b -> set a i b) l;
a
in
try
match j with
| `List l -> `Ok (of_list (map_l l))
| _ -> raise (OfYojsonError "invalid json (expected list)")
with OfYojsonError msg ->
`Error msg
module View = struct
type 'a t = {
len : int;
view : 'a view
}
and _ view =
| Arr : ('a, _, _) array_ -> 'a view
| Map : ('a -> 'b) * 'a t -> 'b view
| Map2 : ('a -> 'b -> 'c) * 'a t * 'b t -> 'c view
| Select : (int, _, _) array_ * 'a t -> 'a view
| SelectA : int array * 'a t -> 'a view
| SelectV : int t * 'a t -> 'a view
| Raw :
('a, 'b, [>`R]) array_ *
(('a, 'b, [>`R]) array_ -> int) *
(('a, 'b, [>`R]) array_ -> int -> 'a) ->
'a view
let length t = t.len
let rec get
: type a. a t -> int -> a
= fun v i -> match v.view with
| Arr a -> A.get a i
| Map (f, a) -> f (get a i)
| Map2 (f, a1, a2) -> f (get a1 i) (get a2 i)
| Select (idx, a) -> get a (A.get idx i)
| SelectA (idx, a) -> get a (Array.get idx i)
| SelectV (idx, a) -> get a (get idx i)
| Raw (a, _, f) -> f a i
let rec iteri
: type a. f:(int -> a -> unit) -> a t -> unit
= fun ~f v -> match v.view with
| Arr a ->
for i = 0 to A.dim a - 1 do
f i (A.unsafe_get a i)
done
| Map (g, a') ->
iteri a' ~f:(fun i x -> f i (g x))
| Map2 (g, a1, a2) ->
iteri a1 ~f:(fun i x -> let y = get a2 i in f i (g x y))
| Select (idx, a) ->
for i = 0 to A.dim idx - 1 do
let j = A.unsafe_get idx i in
f i (get a j)
done
| SelectA (idx, a) ->
Array.iteri (fun i j -> f i (get a j)) idx
| SelectV (idx, a) ->
for i=0 to length idx - 1 do
let j = get idx i in
f i (get a j)
done
| Raw (a, len, g) ->
for i=0 to len a - 1 do
f i (g a i)
done
let of_array a = {len=A.dim a; view=Arr a}
let map ~f a = {len=length a; view=Map(f, a)}
let map2 ~f a b =
if length a <> length b then raise WrongDimension;
{len=length a; view=Map2(f, a, b)}
let select ~idx a = {len=A.dim idx; view=Select(idx,a)}
let select_a ~idx a = {len=Array.length idx; view=SelectA(idx,a)}
let select_view ~idx a = {len=length idx; view=SelectV(idx,a)}
let foldi f acc a =
let acc = ref acc in
iteri a ~f:(fun i x -> acc := f !acc i x);
!acc
let raw ~length ~get a = {len=length a; view=Raw (a, length, get) }
module type S = sig
type elt
val mult : elt t -> elt t -> elt t
val add : elt t -> elt t -> elt t
val sum : elt t -> elt
val prod : elt t -> elt
val add_scalar : elt t -> x:elt -> elt t
val mult_scalar : elt t -> x:elt -> elt t
end
module Int = struct
type elt = int
let add a b = map2 ~f:(+) a b
let mult a b = map2 ~f:( * ) a b
let sum a = foldi (fun acc _ x -> acc+x) 0 a
let prod a = foldi (fun acc _ x -> acc*x) 1 a
let add_scalar a ~x = map ~f:(fun y -> x+y) a
let mult_scalar a ~x = map ~f:(fun y -> x*y) a
end
module Float = struct
type elt = float
let add a b = map2 ~f:(+.) a b
let mult a b = map2 ~f:( *. ) a b
let sum a = foldi (fun acc _ x -> acc+.x) 0. a
let prod a = foldi (fun acc _ x -> acc*.x) 1. a
let add_scalar a ~x = map ~f:(fun y -> x+.y) a
let mult_scalar a ~x = map ~f:(fun y -> x*.y) a
end
let to_array ?res ?kind a =
let res = match res, kind with
| Some r, None ->
if A.dim r <> length a then raise WrongDimension;
r
| None, Some kind -> A.create kind Bigarray.c_layout (length a)
| None, None
| Some _, Some _ -> invalid_arg "View.to_array"
in
iteri a ~f:(fun i x -> A.unsafe_set res i x);
res
end

View file

@ -1,371 +0,0 @@
(*
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 Bigarrays of dimension 1}
@deprecated do not use, this was always experimental
{b NOTE this module will be removed soon and should not be depended upon}
{b status: deprecated}
@since 0.12 *)
(** {2 used types} *)
type 'a printer = Format.formatter -> 'a -> unit
type 'a sequence = ('a -> unit) -> unit
type 'a or_error = [`Ok of 'a | `Error of string]
type random = Random.State.t
type json = [ `Assoc of (string * json) list
| `Bool of bool
| `Float of float
| `Int of int
| `List of json list
| `Null
| `String of string ]
type 'a to_json = 'a -> json
type 'a of_json = json -> 'a or_error
(** {2 Type Declarations} *)
type ('a, 'b, 'perm) t constraint 'perm = [< `R | `W]
(** Array of OCaml values of type ['a] with C representation of type [b']
with permissions ['perm] *)
type ('a, 'b, 'perm) array_ = ('a, 'b, 'perm) t
exception WrongDimension
(** Raised when arrays do not have expected length *)
(** {2 Basic Operations} *)
val make : ?x:'a -> kind:('a,'b) Bigarray.kind -> int -> ('a, 'b, 'perm) t
(** New array with undefined elements
@param kind the kind of bigarray
@param x optional element to fill every slot
@param n the number of elements *)
val make_int : int -> (int, Bigarray.int_elt, 'perm) t
val make_char : int -> (char, Bigarray.int8_unsigned_elt, 'perm) t
val make_int8s : int -> (int, Bigarray.int8_signed_elt, 'perm) t
val make_int8u : int -> (int, Bigarray.int8_unsigned_elt, 'perm) t
val make_int16s : int -> (int, Bigarray.int16_signed_elt, 'perm) t
val make_int16u : int -> (int, Bigarray.int16_unsigned_elt, 'perm) t
val make_int32 : int -> (int32, Bigarray.int32_elt, 'perm) t
val make_int64 : int -> (int64, Bigarray.int64_elt, 'perm) t
val make_native : int -> (nativeint, Bigarray.nativeint_elt, 'perm) t
val make_float32 : int -> (float, Bigarray.float32_elt, 'perm) t
val make_float64 : int -> (float, Bigarray.float64_elt, 'perm) t
val make_complex32 : int -> (Complex.t, Bigarray.complex32_elt, 'perm) t
val make_complex64 : int -> (Complex.t, Bigarray.complex64_elt, 'perm) t
val init : kind:('a, 'b) Bigarray.kind -> f:(int -> 'a) -> int -> ('a, 'b, 'perm) t
(** Initialize with given size and initialization function *)
val of_bigarray : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t -> ('a, 'b, 'perm) t
(** Convert from a big array *)
val to_bigarray : ('a, 'b, [`R | `W]) t -> ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
(** Obtain the underlying array *)
val ro : ('a, 'b, [>`R]) t -> ('a, 'b, [`R]) t
(** Change permission (old reference to array might still be mutable!) *)
val wo : ('a, 'b, [>`W]) t -> ('a, 'b, [`W]) t
(** Change permission *)
val length : (_, _, [>`R]) t -> int
(** Number of elements *)
val set : ('a, _, [>`W]) t -> int -> 'a -> unit
(** set n-th element *)
val get : ('a, _, [>`R]) t -> int -> 'a
(** Get n-th element *)
val fill : ('a, _, [>`W]) t -> 'a -> unit
(** [fill a x] fills [a] with [x] *)
val sub : ('a, 'b, 'perm) t -> int -> int -> ('a, 'b, 'perm) t
(** [sub a i len] takes the slice of length [len] starting at offset [i] *)
val blit : ('a, 'b, [>`R]) t -> ('a, 'b, [>`W]) t -> unit
(** blit the first array to the second *)
val copy : ('a, 'b, [>`R]) t -> ('a, 'b, 'perm) t
(** Fresh copy *)
val iter : f:('a -> unit) -> ('a, _, [>`R]) t -> unit
(** [iter a ~f] calls [f v] where [get a i = v] for each [i < length a].
It iterates on all bits in increasing order *)
val iteri : f:(int -> 'a -> unit) -> ('a, _, [>`R]) t -> unit
(** [iteri a ~f] calls [f i v] where [get a i = v] for each [i < length a].
It iterates on all elements in increasing order *)
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> ('a, _, [>`R]) t -> 'b
val for_all : f:('a -> bool) -> ('a, _, [>`R]) t -> bool
val exists : f:('a -> bool) -> ('a, _, [>`R]) t -> bool
val pp : 'a printer -> ('a, _, [>`R]) t printer
(** Print the SDR nicely *)
(** {2 Boolean Vectors} *)
module Bool : sig
type ('b, 'perm) t = (int, 'b, 'perm) array_
(** A simple bitvector based on some integral type ['b] *)
val get : (_, [>`R]) t -> int -> bool
val set : (_, [>`W]) t -> int -> bool -> unit
val zeroes : int -> (Bigarray.int8_unsigned_elt, 'perm) t
val ones : int -> (Bigarray.int8_unsigned_elt, 'perm) t
val iter_zeroes : f:(int -> unit) -> (_, [>`R]) t -> unit
(** [iter_ones ~f a] calls [f i] for every index [i] such that [get a i = false] *)
val iter_ones : f:(int -> unit) -> (_, [>`R]) t -> unit
(** [iter_ones ~f a] calls [f i] for every index [i] such that [get a i = true] *)
val cardinal : (_, [>`R]) t -> int
(** Number of ones *)
val pp : (_,[>`R]) t printer
(** Print the bitvector nicely *)
(** {6 Operations} *)
val or_ : ?res:('b, [>`W] as 'perm) t -> ('b, [>`R]) t -> ('b, [>`R]) t -> ('b, 'perm) t
(** [or_ a b ~into] puts the boolean "or" of [a] and [b] in [into]
expects [length into = max (length a) (length b)]
@raise WrongDimension if dimensions do not match *)
val and_ : ?res:('b, [>`W] as 'perm) t -> ('b, [>`R]) t -> ('b, [>`R]) t -> ('b, 'perm) t
(** Boolean conjunction. See {!or} for the parameters *)
val not_ : ?res:('b, [>`W] as 'perm) t -> ('b, [>`R]) t -> ('b, 'perm) t
(** Boolean negation (negation of a 0 becomes a 1) *)
val mix : ?res:('b, [>`W] as 'perm) t -> ('b, [>`R]) t -> ('b, [>`R]) t -> ('b, 'perm) t
(** [mix a b ~into] assumes [length a + length b = length into] and
mixes (interleaves) bits of [a] and [b] in [into].
@raise WrongDimension if dimensions do not match *)
val convolution : ?res:('b, [>`W] as 'perm) t -> ('b,[>`R]) t -> by:('b, [>`R]) t -> ('b,'perm) t
(** [convolution a ~by:b ~into] assumes [length into = length a >= length b]
and computes the boolean convolution of [a] by [b]
@raise WrongDimension if dimensions do not match *)
end
(** {2 Operations} *)
val map :
?res:('a, 'b, ([>`W] as 'perm)) t ->
f:('a -> 'a) ->
('a, 'b, [>`R]) t ->
('a, 'b, 'perm) t
val map2 :
?res:('a, 'b, ([>`W] as 'perm)) t ->
f:('a -> 'a2 -> 'a) ->
('a, 'b, [>`R]) t ->
('a2, _, [>`R]) t ->
('a, 'b, 'perm) t
val append :
?res:('a, 'b, ([>`W] as 'perm)) t ->
('a, 'b, [>`R]) t ->
('a, 'b, [>`R]) t ->
('a, 'b, 'perm) t
(** [append a b ~into] assumes [length a + length b = length into] and
copies [a] and [b] side by side in [into]
@raise WrongDimension if dimensions do not match *)
val filter :
?res:(Bigarray.int8_unsigned_elt, [>`W] as 'perm) Bool.t ->
f:('a -> bool) ->
('a, 'b, [>`R]) t ->
(Bigarray.int8_unsigned_elt, 'perm) Bool.t
module type S = sig
type elt
type ('a, 'perm) t = (elt, 'a, 'perm) array_
val add :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
('a, [>`R]) t ->
('a, 'perm) t
(** Elementwise sum
@raise WrongDimension if dimensions do not fit *)
val mult :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
('a, [>`R]) t ->
('a, 'perm) t
(** Elementwise product *)
val scalar_add :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
x:elt ->
('a, 'perm) t
(** @raise WrongDimension if dimensions do not fit *)
val scalar_mult :
?res:('a, [>`W] as 'perm) t ->
('a, [>`R]) t ->
x:elt ->
('a, 'perm) t
(** @raise WrongDimension if dimensions do not fit *)
val sum_elt : (_, [>`R]) t -> elt
(** Efficient sum of elements *)
val product_elt : (_, [>`R]) t -> elt
(** Efficient product of elements *)
val dot_product : (_, [>`R]) t -> (_, [>`R]) t -> elt
(** [dot_product a b] returns [sum_i a(i)*b(i)] with the given
sum and product, on [elt].
[dot_product a b = sum_elt (product a b)]
@raise WrongDimension if [a] and [b] do not have the same size *)
module Infix : sig
val ( * ) : ('a, [>`R]) t -> ('a, [>`R]) t -> ('a, 'perm) t
(** Alias to {!mult} *)
val ( + ) : ('a, [>`R]) t -> (_, [>`R]) t -> ('a, 'perm) t
(** Alias to {!add} *)
val ( *! ) : ('a, [>`R]) t -> elt -> ('a, 'perm) t
(** Alias to {!scalar_mult} *)
val ( +! ) : ('a, [>`R]) t -> elt -> ('a, 'perm) t
(** Alias to {!scalar_add} *)
end
include module type of Infix
end
module Int : S with type elt = int
module Float : S with type elt = float
(** {2 Conversions} *)
val to_list : ('a, _, [>`R]) t -> 'a list
val to_array : ('a, _, [>`R]) t -> 'a array
val to_seq : ('a, _, [>`R]) t -> 'a sequence
val of_array : kind:('a, 'b) Bigarray.kind -> 'a array -> ('a, 'b, 'perm) t
(** {2 Serialization} *)
val to_yojson : 'a to_json -> ('a, _, [>`R]) t to_json
val of_yojson : kind:('a, 'b) Bigarray.kind -> 'a of_json -> ('a, 'b, 'perm) t of_json
val int_to_yojson : int to_json
val int_of_yojson : int of_json
val float_to_yojson : float to_json
val float_of_yojson : float of_json
(** {2 Views} *)
module View : sig
type 'a t
(** A view on an array or part of an array *)
val of_array : ('a, _, [>`R]) array_ -> 'a t
val get : 'a t -> int -> 'a
(** [get v i] returns the [i]-th element of [v]. Caution, this is not
as cheap as a regular array indexing, and it might involve recursion.
@raise Invalid_argument if index out of bounds *)
val length : _ t -> int
(** [length v] is the number of elements of [v] *)
val map : f:('a -> 'b) -> 'a t -> 'b t
(** Map values *)
val map2 : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** Map values
@raise WrongDimension if lengths do not fit *)
val select : idx:(int, _, [>`R]) array_ -> 'a t -> 'a t
(** [select ~idx v] is the view that has length [length idx]
and such that [get (select ~idx a) i = get a (get idx i)] *)
val select_a : idx:int array -> 'a t -> 'a t
(** See {!select} *)
val select_view : idx:int t -> 'a t -> 'a t
(** See {!select} *)
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** Fold on values with their index *)
val iteri : f:(int -> 'a -> unit) -> 'a t -> unit
(** [iteri ~f v] iterates on elements of [v] with their index *)
module type S = sig
type elt
val mult : elt t -> elt t -> elt t
val add : elt t -> elt t -> elt t
val sum : elt t -> elt
val prod : elt t -> elt
val add_scalar : elt t -> x:elt -> elt t
val mult_scalar : elt t -> x:elt -> elt t
end
module Int : sig
include S with type elt = int
end
module Float : sig
include S with type elt = float
(* TODO: more, like trigo functions *)
end
val raw :
length:(('a, 'b, [>`R]) array_ -> int) ->
get:(('a, 'b, [>`R]) array_ -> int -> 'a) ->
('a, 'b, [>`R]) array_ ->
'a t
val to_array :
?res:('a, 'b, [>`W] as 'perm) array_ ->
?kind:('a, 'b) Bigarray.kind ->
'a t ->
('a, 'b, 'perm) array_
(** [to_array v] returns a fresh copy of the content of [v].
Exactly one of [res] and [kind] must be provided *)
end

View file

@ -1,213 +0,0 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** {1 Interface to 1-dimension Bigarrays of bytes (char)} *)
module B = Bigarray.Array1
type t = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
let create size = B.create Bigarray.char Bigarray.c_layout size
let empty = create 0
let init size f =
let a = create size in
for i = 0 to size-1 do
B.unsafe_set a i (f i)
done;
a
let fill = B.fill
let get = B.get
let set = B.set
let size = B.dim
let length = B.dim
let sub = B.sub
let blit a i b j len =
let a' = sub a i len in
let b' = sub b j len in
B.blit a' b'
let copy a =
let b = create (size a) in
B.blit a b;
b
(*$T
copy (of_string "abcd") |> to_string = "abcd"
*)
let fold f acc a =
let rec fold' f acc a i len =
if i = len then acc
else
let acc = f acc (get a i) in
fold' f acc a (i+1) len
in
fold' f acc a 0 (size a)
let iter f a =
let n = size a in
for i = 0 to n-1 do
f (get a i)
done
let rec equal_rec a b i len =
i = len
||
( get a i = get b i && equal_rec a b (i+1) len)
let equal a b =
size a = size b
&&
equal_rec a b 0 (size a)
(*$Q
Q.(pair printable_string printable_string) (fun (s1, s2) -> \
let a1 = of_string s1 and a2 = of_string s2 in \
equal a1 a2 = (s1 = s2))
*)
let rec compare_rec a b i len_a len_b =
if i=len_a && i=len_b then 0
else if i=len_a then -1
else if i=len_b then 1
else
match Char.compare (get a i) (get b i) with
| 0 -> compare_rec a b (i+1) len_a len_b
| n -> n
let compare a b =
compare_rec a b 0 (size a) (size b)
(*$T
compare (of_string "abc") (of_string "abd") < 0
compare (of_string "abc") (of_string "abcd") < 0
compare (of_string "abcd") (of_string "abc") > 0
compare (of_string "abc") (of_string "b") < 0
*)
(*$Q
Q.(pair string string) (fun (s1, s2) -> \
let a1 = of_string s1 and a2 = of_string s2 in \
CCInt.sign (compare a1 a2) = CCInt.sign (String.compare s1 s2))
*)
(** {2 Conversions} *)
let to_bytes a =
Bytes.init (size a) (fun i -> B.unsafe_get a i)
let of_bytes b =
init (Bytes.length b) (fun i -> Bytes.get b i)
let of_bytes_slice b i len =
if i < 0 || i+len > Bytes.length b then invalid_arg "CCBigstring";
init len (fun j -> Bytes.get b (i+j))
let sub_bytes a i len =
if i < 0 || i+len > size a then invalid_arg "CCBigstring";
Bytes.init len (fun j -> B.get a (i+j))
let blit_to_bytes a i b j len =
if i < 0 || j < 0 || i+len > size a || j+len > Bytes.length b
then invalid_arg "CCBigstring";
for x=0 to len-1 do
Bytes.set b (j+x) (B.get a (i+x))
done
let blit_of_bytes a i b j len =
if i < 0 || j < 0 || i+len > Bytes.length a || j+len > size b
then invalid_arg "CCBigstring";
for x=0 to len-1 do
B.set b (j+x) (Bytes.get a (i+x))
done
let to_string a =
CCString.init (size a) (fun i -> B.unsafe_get a i)
let of_string s =
init (String.length s) (fun i -> String.get s i)
let of_string_slice s i len =
if i < 0 || i+len > String.length s then invalid_arg "CCBigstring";
init len (fun j -> String.get s (i+j))
let sub_string a i len =
if i < 0 || i+len > size a then invalid_arg "CCBigstring";
CCString.init len (fun j -> B.get a (i+j))
(*$T
of_string_slice "abcde" 1 3 |> to_string = "bcd"
*)
let blit_of_string a i b j len =
if i < 0 || j < 0 || i+len > String.length a || j+len > size b
then invalid_arg "CCBigstring";
for x=0 to len-1 do
B.set b (j+x) (String.get a (i+x))
done
type 'a gen = unit -> 'a option
type 'a sequence = ('a -> unit) -> unit
type 'a printer = Format.formatter -> 'a -> unit
let to_seq a k = iter k a
let to_gen a =
let i = ref 0 in
let n = size a in
fun () ->
if !i = n then None
else (
let x = get a !i in
incr i;
Some x
)
(*$T
of_string "abcd" |> to_gen |> Gen.to_string = "abcd"
*)
let to_seq_slice a i len =
to_seq (sub a i len)
let to_gen_slice a i len =
to_gen (sub a i len)
let print out s =
Format.pp_print_string out "bigstring \"";
iter
(function
| '\n' -> Format.pp_print_string out "\\n"
| '\t' -> Format.pp_print_string out "\\t"
| '\\' -> Format.pp_print_string out "\\\\"
| c -> Format.pp_print_char out c
) s;
Format.pp_print_char out '"'
(** {2 Memory-map} *)
let map_file_descr ?pos ?(shared=false) fd len =
B.map_file fd ?pos Bigarray.char Bigarray.c_layout shared len
let with_map_file ?pos ?len ?(mode=0o644) ?(flags=[Open_rdonly]) ?shared name f =
let ic = open_in_gen flags mode name in
let len = match len with
| None -> in_channel_length ic
| Some n -> n
in
let a = map_file_descr ?pos ?shared (Unix.descr_of_in_channel ic) len in
try
let x = f a in
close_in ic;
x
with e ->
close_in ic;
raise e

View file

@ -1,116 +0,0 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** {1 Interface to 1-dimension Bigarrays of bytes (char)}
@deprecated use the package [bigstring] instead.
{b status: deprecated, do not use anymore}
@since 0.7 *)
type t = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
val create : int -> t
(** Create a new bigstring of the given size. *)
val empty : t
(** Empty string *)
val init : int -> (int -> char) -> t
(** Initialize with the given function (called at every index) *)
val fill : t -> char -> unit
(** Fill with a single byte *)
val size : t -> int
(** Number of bytes *)
val length : t -> int
(** Alias for [size].
@since 0.8 *)
val get : t -> int -> char
val set : t -> int -> char -> unit
val blit : t -> int -> t -> int -> int -> unit
(** Blit a slice of the bigstring into another *)
val copy : t -> t
(** Copy of the string *)
val sub : t -> int -> int -> t
(** [sub s i len] takes a slice of length [len] from the string [s], starting
at offset [i].
@raise Invalid_argument if [i, len] doesn't designate a valid substring *)
val fold : ('a -> char -> 'a) -> 'a -> t -> 'a
val iter : (char -> unit) -> t -> unit
val equal : t -> t -> bool
val compare : t -> t -> int
(** Lexicographic order *)
(** {2 Conversions} *)
val to_bytes : t -> Bytes.t
val of_bytes : Bytes.t -> t
val of_bytes_slice : Bytes.t -> int -> int -> t
val sub_bytes : t -> int -> int -> Bytes.t
val blit_to_bytes : t -> int -> Bytes.t -> int -> int -> unit
val blit_of_bytes : Bytes.t -> int -> t -> int -> int -> unit
val to_string : t -> string
val of_string : string -> t
val of_string_slice : string -> int -> int -> t
val sub_string : t -> int -> int -> string
val blit_of_string : string -> int -> t -> int -> int -> unit
type 'a gen = unit -> 'a option
type 'a sequence = ('a -> unit) -> unit
type 'a printer = Format.formatter -> 'a -> unit
val to_seq : t -> char sequence
val to_gen : t -> char gen
val to_seq_slice : t -> int -> int -> char sequence
val to_gen_slice : t -> int -> int -> char gen
val print : t printer
(** @since 0.13 *)
(** {2 Memory-map} *)
val with_map_file :
?pos:int64 -> ?len:int -> ?mode:int -> ?flags:open_flag list -> ?shared:bool ->
string -> (t -> 'a) -> 'a
(** [with_map_file name f] maps the file into memory, opening it, and
call [f] with a slice [pos.... pos+len] of the bytes of the file
where [len] is the length of the file if not provided.
When [f] returns, the file is closed.
@param pos offset in the file (default 0)
@param shared if true, modifications are shared between processes that
have mapped this file (requires the filedescr to be open in write mode).
@param mode the mode for the file, if it's created
@param flags opening flags (default rdonly)
see {!Bigarray.Array1.map_file} for more details *)
val map_file_descr : ?pos:int64 -> ?shared:bool -> Unix.file_descr -> int -> t
(** [map_file_descr descr len] is a lower-level access to an underlying file descriptor.
@param shared if true, modifications are shared between processes that
have mapped this file (requires the filedescr to be open in write mode).
see {!Bigarray.Array1.map_file} for more details *)

323
src/cbor/containers_cbor.ml Normal file
View file

@ -0,0 +1,323 @@
module Fmt = CCFormat
type t =
[ `Null
| `Undefined
| `Simple of int
| `Bool of bool
| `Int of int64
| `Float of float
| `Bytes of string
| `Text of string
| `Array of t list
| `Map of (t * t) list
| `Tag of int * t
]
let rec pp_diagnostic out (self : t) =
match self with
| `Null -> Fmt.string out "null"
| `Undefined -> Fmt.string out "undefined"
| `Simple i -> Fmt.fprintf out "simple(%d)" i
| `Bool b -> Fmt.bool out b
| `Int i -> Fmt.int64 out i
| `Float f -> Fmt.float out f
| `Bytes b -> Fmt.fprintf out "h'%s'" (CCString.to_hex b)
| `Text s -> Fmt.fprintf out "%S" s
| `Array l ->
Fmt.fprintf out "[@[";
List.iteri
(fun i x ->
if i > 0 then Fmt.fprintf out ",@ ";
pp_diagnostic out x)
l;
Fmt.fprintf out "@]]"
| `Map l ->
Fmt.fprintf out "{@[";
List.iteri
(fun i (k, v) ->
if i > 0 then Fmt.fprintf out ",@ ";
Fmt.fprintf out "@[%a:@ %a@]" pp_diagnostic k pp_diagnostic v)
l;
Fmt.fprintf out "@]}"
| `Tag (i, x) -> Fmt.fprintf out "%d(@[%a@])" i pp_diagnostic x
let to_string_diagnostic (self : t) : string =
Format.asprintf "@[<h>%a@]" pp_diagnostic self
exception Indefinite
let[@inline] i64_to_int i =
let j = Int64.to_int i in
if Int64.(of_int j = i) then
j
else
failwith "int64 does not fit in int"
let decode_exn (s : string) : t =
let b = Bytes.unsafe_of_string s in
let i = ref 0 in
(* currently at end delimiter? *)
let[@inline] is_break_stop_code () = Char.code s.[!i] = 0b111_11111 in
let[@inline] read_i8 () =
let c = Char.code s.[!i] in
incr i;
c
in
let[@inline] read_i16 () =
let c = Bytes.get_uint16_be b !i in
i := !i + 2;
c
in
let[@inline] read_i32 () =
let c = Bytes.get_int32_be b !i in
i := !i + 4;
c
in
let[@inline] read_i64 () =
let c = Bytes.get_int64_be b !i in
i := !i + 8;
c
in
let reserve_n n =
let j = !i in
if j + n > String.length s then failwith "cbor: cannot extract slice";
i := !i + n;
j
in
(* read integer value from least significant bits *)
let read_int ~allow_indefinite low =
match low with
| _ when low < 0 -> failwith "cbor: invalid length"
| _ when low < 24 -> Int64.of_int low
| 24 -> Int64.of_int (read_i8 ())
| 25 -> Int64.of_int (read_i16 ())
| 26 -> Int64.of_int32 (read_i32 ())
| 27 -> read_i64 ()
| 28 | 29 | 30 -> failwith "cbor: invalid length"
| 31 ->
if allow_indefinite then
raise_notrace Indefinite
else
failwith "cbor: invalid integer 31 in this context"
| _ -> assert false
in
(* appendix D
double decode_half(unsigned char *halfp) {
unsigned half = (halfp[0] << 8) + halfp[1];
unsigned exp = (half >> 10) & 0x1f;
unsigned mant = half & 0x3ff;
double val;
if (exp == 0) val = ldexp(mant, -24);
else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
else val = mant == 0 ? INFINITY : NAN;
return half & 0x8000 ? -val : val;
}
*)
let decode_f16 (half : int) : float =
(* exponent is bits 15:10 *)
let exp = (half lsr 10) land 0x1f in
(* mantissa is bits 9:0 *)
let mant = half land 0x3ff in
let value =
if exp = 0 then
ldexp (float mant) (-24)
else if exp <> 31 then
ldexp (float (mant + 1024)) (exp - 25)
else if mant = 0 then
infinity
else
nan
in
if half land 0x8000 <> 0 then
-.value
else
value
in
(* roughly follow https://www.rfc-editor.org/rfc/rfc8949.html#pseudocode *)
let rec read_value () =
let c = read_i8 () in
let high = (c land 0b111_00000) lsr 5 in
let low = c land 0b000_11111 in
match high with
| 0 -> `Int (read_int ~allow_indefinite:false low)
| 1 ->
let i = read_int ~allow_indefinite:false low in
`Int Int64.(sub minus_one i)
| 2 ->
let s = read_bytes ~ty:`Bytes low in
`Bytes s
| 3 ->
let s = read_bytes ~ty:`String low in
`Text s
| 4 ->
let l =
match read_int ~allow_indefinite:true low |> i64_to_int with
| len -> List.init len (fun _ -> read_value ())
| exception Indefinite ->
let l = ref [] in
while not (is_break_stop_code ()) do
l := read_value () :: !l
done;
incr i;
(* consume stop code *)
List.rev !l
in
`Array l
| 5 ->
let l =
match read_int ~allow_indefinite:true low |> i64_to_int with
| len -> List.init len (fun _ -> read_pair ())
| exception Indefinite ->
let l = ref [] in
while not (is_break_stop_code ()) do
l := read_pair () :: !l
done;
incr i;
(* consume stop code *)
List.rev !l
in
`Map l
| 6 ->
let tag = read_int ~allow_indefinite:false low |> i64_to_int in
let v = read_value () in
`Tag (tag, v)
| 7 ->
(* simple or float,
https://www.rfc-editor.org/rfc/rfc8949.html#fpnocont *)
let i = read_int ~allow_indefinite:false low in
(match low with
| 20 -> `Bool false
| 21 -> `Bool true
| 22 -> `Null
| 23 -> `Undefined
| _ when low <= 24 -> `Simple (i64_to_int i)
| 25 ->
(* float16 *)
`Float (decode_f16 (Int64.to_int i))
| 26 ->
(* float 32 *)
`Float (Int32.float_of_bits (Int64.to_int32 i))
| 27 ->
(* float 64 *)
`Float (Int64.float_of_bits i)
| 28 | 29 | 30 -> failwith "cbor: malformed"
| 31 -> failwith "uncaught 'break' stop code"
| _ -> assert false (* unreachable *))
| _ ->
(* unreachable *)
assert false
and read_bytes ~ty low =
match read_int ~allow_indefinite:true low |> i64_to_int with
| exception Indefinite ->
let buf = Buffer.create 32 in
while not (is_break_stop_code ()) do
match read_value (), ty with
| `Text s, `String | `Bytes s, `Bytes -> Buffer.add_string buf s
| _ -> failwith "cbor: invalid chunk in indefinite length string/byte"
done;
incr i;
(* consume stop code *)
Buffer.contents buf
| len ->
let off = reserve_n len in
String.sub s off len
and read_pair () =
let k = read_value () in
let v = read_value () in
k, v
in
read_value ()
let decode s = try Ok (decode_exn s) with Failure s -> Error s
let encode ?(buf = Buffer.create 32) (self : t) : string =
Buffer.clear buf;
let[@inline] add_byte (high : int) (low : int) =
let i = (high lsl 5) lor low in
assert (i land 0xff == i);
Buffer.add_char buf (Char.unsafe_chr i)
in
let add_i64 (i : int64) = Buffer.add_int64_be buf i in
(* add unsigned integer, including first tag byte *)
let add_uint (high : int) (x : int64) =
assert (x >= 0L);
if x < 24L then
add_byte high (i64_to_int x)
else if x <= 0xffL then (
add_byte high 24;
Buffer.add_char buf (Char.unsafe_chr (i64_to_int x))
) else if x <= 0xff_ffL then (
add_byte high 25;
Buffer.add_uint16_be buf (i64_to_int x)
) else if x <= 0xff_ff_ff_ffL then (
add_byte high 26;
Buffer.add_int32_be buf (Int64.to_int32 x)
) else (
add_byte high 27;
Buffer.add_int64_be buf x
)
in
let rec encode_val (self : t) : unit =
match self with
| `Bool false -> add_byte 7 20
| `Bool true -> add_byte 7 21
| `Null -> add_byte 7 22
| `Undefined -> add_byte 7 23
| `Simple i ->
if i < 24 then
add_byte 7 i
else if i <= 0xff then (
add_byte 7 24;
Buffer.add_char buf (Char.unsafe_chr i)
) else
failwith "cbor: simple value too high (above 255)"
| `Float f ->
add_byte 7 27;
(* float 64 *)
add_i64 (Int64.bits_of_float f)
| `Array l ->
add_uint 4 (Int64.of_int (List.length l));
List.iter encode_val l
| `Map l ->
add_uint 5 (Int64.of_int (List.length l));
List.iter
(fun (k, v) ->
encode_val k;
encode_val v)
l
| `Text s ->
add_uint 3 (Int64.of_int (String.length s));
Buffer.add_string buf s
| `Bytes s ->
add_uint 2 (Int64.of_int (String.length s));
Buffer.add_string buf s
| `Tag (t, v) ->
add_uint 6 (Int64.of_int t);
encode_val v
| `Int i ->
if i >= Int64.zero then
add_uint 0 i
else if Int64.(add min_int 2L) > i then (
(* large negative int, be careful. encode [(-i)-1] via int64. *)
add_byte 1 27;
Buffer.add_int64_be buf Int64.(neg (add 1L i))
) else
add_uint 1 Int64.(sub (neg i) one)
in
encode_val self;
Buffer.contents buf

View file

@ -0,0 +1,32 @@
(** CBOR encoder/decoder.
The type is chosen to be compatible with ocaml-cbor.
See {{: https://www.rfc-editor.org/rfc/rfc8949.html} the RFC}.
{b note} this is experimental.
@since 3.9
*)
type t =
[ `Null
| `Undefined
| `Simple of int
| `Bool of bool
| `Int of int64
| `Float of float
| `Bytes of string
| `Text of string
| `Array of t list
| `Map of (t * t) list
| `Tag of int * t
]
val pp_diagnostic : t CCFormat.printer
val to_string_diagnostic : t -> string
val encode : ?buf:Buffer.t -> t -> string
val decode : string -> (t, string) result
val decode_exn : string -> t
(** Like {!decode}.
@raise Failure if the string isn't valid *)

7
src/cbor/dune Normal file
View file

@ -0,0 +1,7 @@
(library
(name containers_cbor)
(libraries containers)
(preprocess
(action
(run %{project_root}/src/core/cpp/cpp.exe %{input-file})))
(public_name containers.cbor))

3671
src/cbor/rfc8949.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,143 @@
(** {1 Code generators} *)
module Fmt = CCFormat
let spf = Printf.sprintf
let fpf = Fmt.fprintf
type code =
| Base of { pp: unit Fmt.printer }
| Struct of string * code list
| Sig of string * code list
module Code = struct
type t = code
let in_struct m (cs : t list) : t = Struct (m, cs)
let in_sig m (cs : t list) : t = Sig (m, cs)
let rec pp_rec out c =
let ppl = Fmt.(list ~sep:(return "@ ") pp_rec) in
match c with
| Base { pp } -> pp out ()
| Struct (m, cs) ->
fpf out "@[<hv2>module %s = struct@ %a@;<1 -2>end@]" m ppl cs
| Sig (m, cs) -> fpf out "@[<hv2>module %s : sig@ %a@;<1 -2>end@]" m ppl cs
let pp out c = fpf out "@[<v>%a@]" pp_rec c
let to_string c = Fmt.to_string pp c
let mk_pp pp = Base { pp }
let mk_str s = Base { pp = Fmt.const Fmt.string s }
end
module Bitfield = struct
type field = {
f_name: string;
f_offset: int;
f_def: field_def;
}
and field_def =
| F_bit
| F_int of { width: int }
type t = {
name: string;
mutable fields: field list;
mutable width: int;
emit_failure_if_too_wide: bool;
}
let make ?(emit_failure_if_too_wide = true) ~name () : t =
{ name; fields = []; width = 0; emit_failure_if_too_wide }
let total_width self = self.width
let field_bit self f_name =
let f_offset = total_width self in
let f = { f_name; f_offset; f_def = F_bit } in
self.fields <- f :: self.fields;
self.width <- 1 + self.width
let field_int self ~width f_name : unit =
let f_offset = total_width self in
let f = { f_name; f_offset; f_def = F_int { width } } in
self.fields <- f :: self.fields;
self.width <- self.width + width
let empty_name self =
if self.name = "t" then
"empty"
else
spf "empty_%s" self.name
let gen_ml self : code =
Code.mk_pp @@ fun out () ->
fpf out "@[<v>type %s = int@," self.name;
fpf out "@[let %s : %s = 0@]@," (empty_name self) self.name;
List.iter
(fun f ->
let inline = "[@inline]" in
(* TODO: option to enable/disable that *)
let off = f.f_offset in
match f.f_def with
| F_bit ->
let x_lsr =
if off = 0 then
"x"
else
spf "(x lsr %d)" off
in
fpf out "@[let%s get_%s (x:%s) : bool = (%s land 1) <> 0@]@," inline
f.f_name self.name x_lsr;
let mask_shifted = 1 lsl off in
fpf out
"@[<2>let%s set_%s (v:bool) (x:%s) : %s =@ if v then x lor %d else \
x land (lnot %d)@]@,"
inline f.f_name self.name self.name mask_shifted mask_shifted
| F_int { width } ->
let mask0 = (1 lsl width) - 1 in
fpf out "@[let%s get_%s (x:%s) : int = ((x lsr %d) land %d)@]@,"
inline f.f_name self.name off mask0;
fpf out
"@[<2>let%s set_%s (i:int) (x:%s) : %s =@ assert ((i land %d) == \
i);@ ((x land (lnot %d)) lor (i lsl %d))@]@,"
inline f.f_name self.name self.name mask0 (mask0 lsl off) off)
(List.rev self.fields);
(* check width *)
if self.emit_failure_if_too_wide then
fpf out
"(* check that int size is big enough *)@,\
@[let () = assert (Sys.int_size >= %d);;@]"
(total_width self);
fpf out "@]"
let gen_mli self : code =
Code.mk_pp @@ fun out () ->
fpf out "@[<v>type %s = private int@," self.name;
fpf out "@[<v>val %s : %s@," (empty_name self) self.name;
List.iter
(fun f ->
match f.f_def with
| F_bit ->
fpf out "@[val get_%s : %s -> bool@]@," f.f_name self.name;
fpf out "@[val set_%s : bool -> %s -> %s@]@," f.f_name self.name
self.name
| F_int { width } ->
fpf out "@[val get_%s : %s -> int@]@," f.f_name self.name;
fpf out
"@,@[(** %d bits integer *)@]@,@[val set_%s : int -> %s -> %s@]@,"
width f.f_name self.name self.name)
(List.rev self.fields);
fpf out "@]"
end
let emit_chan oc cs =
let fmt = Fmt.formatter_of_out_channel oc in
List.iter (fun c -> Fmt.fprintf fmt "@[%a@]@." Code.pp c) cs;
Fmt.fprintf fmt "@?"
let emit_file file cs = CCIO.with_out file (fun oc -> emit_chan oc cs)
let emit_string cs : string =
Fmt.asprintf "@[<v>%a@]" (Fmt.list ~sep:(Fmt.return "@ ") Code.pp) cs

View file

@ -0,0 +1,86 @@
(** {1 Code generators}
The code generator library is designed to be used from a build system
(for example, from [dune]) to generate efficient code for features
that are harder to provide at runtime.
The idea is that the build system should invoke some OCaml script
that depends on [containers.codegen]; the script uses the DSL below
to describe what code to generate (e.g. a description of a bitfield type)
and emits a [.ml] file (and possibly a [.mli] file).
For example, the build script might contain:
{[
module CG = Containers_codegen
let () =
let module B = CG.Bitfield in
let b = B.make ~name:"t" () in
B.field_bit b "x";
B.field_bit b "y";
B.field_bit b "z";
B.field_int b ~width:5 "foo";
CG.emit_file "foo.mli" [B.gen_mli b];
CG.emit_file "foo.ml" [B.gen_ml b];
()
]}
and this will produce [foo.ml] and [foo.mli] with a bitfield containing
[x], [y], and [z].
*)
module Fmt = CCFormat
type code
(** {2 Representation of OCaml code} *)
module Code : sig
type t = code
val pp : t Fmt.printer
val to_string : t -> string
val mk_pp : unit Fmt.printer -> t
val mk_str : string -> t
val in_struct : string -> t list -> t
val in_sig : string -> t list -> t
end
(** {2 Generate efficient bitfields that fit in an integer} *)
module Bitfield : sig
type t
val make : ?emit_failure_if_too_wide:bool -> name:string -> unit -> t
(** Make a new bitfield with the given name.
@param name the name of the generated type
@param emit_failure_if_too_wide if true, generated code includes a runtime
assertion that {!Sys.int_size} is wide enough to support this type *)
val field_bit : t -> string -> unit
(** [field_bit ty name] adds a field of size [1] to the bitfield [ty],
with name [name]. The generate code will provide get/set for
a boolean. *)
val field_int : t -> width:int -> string -> unit
(** [field_int ty name ~width] adds a field of size [width] to
the bitfield with name [name].
The accessors will be for integers of [width] bits, and the
setter might assert that the provided integer fits. *)
val total_width : t -> int
(** Total width in bits of the given bitfield. *)
val gen_mli : t -> code
(** Generate code for the type signature for the given bitfield *)
val gen_ml : t -> code
(** Generate code for the implementation for the given bitfield *)
end
val emit_file : string -> code list -> unit
(** [emit_file file cs] emits code fragments [cs] into the given file
at path [file] *)
val emit_chan : out_channel -> code list -> unit
val emit_string : code list -> string

6
src/codegen/dune Normal file
View file

@ -0,0 +1,6 @@
(library
(name containers_codegen)
(public_name containers.codegen)
(synopsis "code generators for Containers")
(libraries containers)
(flags :standard -warn-error -a+8))

25
src/codegen/tests/dune Normal file
View file

@ -0,0 +1,25 @@
; emit tests
(executable
(name emit_tests)
(modules emit_tests)
(flags :standard -warn-error -a+8)
(libraries containers containers.codegen))
(rule
(targets test_bitfield.ml test_bitfield.mli)
(action
(run ./emit_tests.exe)))
; run tests
(executables
(names test_bitfield)
(modules test_bitfield)
(flags :standard -warn-error -a+8)
(libraries containers))
(rule
(alias runtest)
(action
(run ./test_bitfield.exe)))

View file

@ -0,0 +1,58 @@
module CG = Containers_codegen
module Vec = CCVector
let spf = Printf.sprintf
let emit_bitfields () =
let module B = CG.Bitfield in
let ml = Vec.create () in
let mli = Vec.create () in
(let b = B.make ~name:"t" () in
B.field_bit b "x";
B.field_bit b "y";
B.field_bit b "z";
B.field_int b ~width:5 "foo";
Vec.push ml (CG.Code.in_struct "T1" [ B.gen_ml b ]);
Vec.push mli (CG.Code.in_sig "T1" [ B.gen_mli b ]);
(* check width *)
Vec.push ml
(CG.Code.mk_str (spf "let() = assert (%d = 8);;" (B.total_width b)));
());
Vec.push ml
@@ CG.Code.mk_str
{|
let n_fails = ref 0;;
at_exit (fun () -> if !n_fails > 0 then exit 1);;
let assert_true line s =
if not s then ( incr n_fails; Printf.eprintf "test failure at %d\n%!" line);;
|};
let test1 =
{|
assert_true __LINE__ T1.(get_y (empty |> set_x true |> set_y true |> set_foo 10));;
assert_true __LINE__ T1.(get_x (empty |> set_x true |> set_y true |> set_foo 10));;
assert_true __LINE__ T1.(get_y (empty |> set_x true |> set_z true
|> set_y false |> set_x false |> set_y true));;
assert_true __LINE__ T1.(get_z (empty |> set_z true));;
assert_true __LINE__ T1.(not @@ get_x (empty |> set_z true));;
assert_true __LINE__ T1.(not @@ get_y (empty |> set_z true |> set_x true));;
assert_true __LINE__ T1.(not @@ get_y (empty |> set_z true |> set_foo 18));;
(* check width of foo *)
assert_true __LINE__ T1.(try ignore (empty |> set_foo (1 lsl 6)); false with _ -> true);;
assert_true __LINE__ T1.(12 = get_foo (empty |> set_x true |> set_foo 12 |> set_x false));;
assert_true __LINE__ T1.(24 = get_foo (empty |> set_y true |> set_foo 24 |> set_z true));;
|}
|> CG.Code.mk_str
in
Vec.push ml test1;
CG.emit_file "test_bitfield.ml" (Vec.to_list ml);
CG.emit_file "test_bitfield.mli" (Vec.to_list mli);
()
let () =
emit_bitfields ();
()

File diff suppressed because it is too large Load diff

View file

@ -1,223 +1,312 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** {1 Array utils} *)
(** Array utils *)
type 'a iter = ('a -> unit) -> unit
(** Fast internal iterator.
@since 2.8 *)
type 'a sequence = ('a -> unit) -> unit
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
type 'a gen = unit -> 'a option
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a random_gen = Random.State.t -> 'a
(** {2 Abstract Signature} *)
module type S = sig
type 'a t
(** Array, or sub-array, containing elements of type ['a] *)
val empty : 'a t
val equal : 'a equal -> 'a t equal
val compare : 'a ord -> 'a t ord
val get : 'a t -> int -> 'a
val get_safe : 'a t -> int -> 'a option
(** [get_safe a i] returns [Some a.(i)] if [i] is a valid index
@since 0.18 *)
val set : 'a t -> int -> 'a -> unit
val length : _ t -> int
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a
(** Fold left on array, with index *)
val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a
(** Fold left on array until a stop condition via [('a, `Stop)] is
indicated by the accumulator
@since 0.8 *)
val iter : ('a -> unit) -> 'a t -> unit
val iteri : (int -> 'a -> unit) -> 'a t -> unit
val blit : 'a t -> int -> 'a t -> int -> int -> unit
(** [blit from i into j len] copies [len] elements from the first array
to the second. See {!Array.blit}. *)
val reverse_in_place : 'a t -> unit
(** Reverse the array in place *)
val find : ('a -> 'b option) -> 'a t -> 'b option
(** [find f a] returns [Some y] if there is an element [x] such
that [f x = Some y], else it returns [None] *)
val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option
(** Like {!find}, but also pass the index to the predicate function.
@since 0.3.4 *)
val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],
and [p x] holds. Otherwise returns [None]
@since 0.3.4 *)
val lookup : ?cmp:'a ord -> 'a -> 'a t -> int option
(** Lookup the index of some value in a sorted array.
@return [None] if the key is not present, or
[Some i] ([i] the index of the key) otherwise *)
val lookup_exn : ?cmp:'a ord -> 'a -> 'a t -> int
(** Same as {!lookup_exn}, but
@raise Not_found if the key is not present *)
val bsearch : ?cmp:('a -> 'a -> int) -> 'a -> 'a t ->
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
(** [bsearch ?cmp x arr] finds the index of the object [x] in the array [arr],
provided [arr] is {b sorted} using [cmp]. If the array is not sorted,
the result is not specified (may raise Invalid_argument).
Complexity: O(log n) where n is the length of the array
(dichotomic search).
@return
- [`At i] if [cmp arr.(i) x = 0] (for some i)
- [`All_lower] if all elements of [arr] are lower than [x]
- [`All_bigger] if all elements of [arr] are bigger than [x]
- [`Just_after i] if [arr.(i) < x < arr.(i+1)]
- [`Empty] if the array is empty
@raise Invalid_argument if the array is found to be unsorted w.r.t [cmp]
@since 0.13 *)
val for_all : ('a -> bool) -> 'a t -> bool
val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** Forall on pairs of arrays.
@raise Invalid_argument if they have distinct lengths *)
val exists : ('a -> bool) -> 'a t -> bool
val exists2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** Exists on pairs of arrays.
@raise Invalid_argument if they have distinct lengths *)
val shuffle : 'a t -> unit
(** Shuffle randomly the array, in place *)
val shuffle_with : Random.State.t -> 'a t -> unit
(** Like shuffle but using a specialized random state *)
val random_choose : 'a t -> 'a random_gen
(** Choose an element randomly.
@raise Not_found if the array/slice is empty *)
val to_seq : 'a t -> 'a sequence
val to_gen : 'a t -> 'a gen
val to_klist : 'a t -> 'a klist
(** {2 IO} *)
val pp: ?sep:string -> (Buffer.t -> 'a -> unit) ->
Buffer.t -> 'a t -> unit
(** Print an array of items with printing function *)
val pp_i: ?sep:string -> (Buffer.t -> int -> 'a -> unit) ->
Buffer.t -> 'a t -> unit
(** Print an array, giving the printing function both index and item *)
val print : ?sep:string -> (Format.formatter -> 'a -> unit) ->
Format.formatter -> 'a t -> unit
(** Print an array of items with printing function *)
end
type 'a printer = Format.formatter -> 'a -> unit
(** {2 Arrays} *)
type 'a t = 'a array
include module type of Array
(** @inline *)
include S with type 'a t := 'a t
val empty : 'a t
(** [empty] is the empty array, physically equal to [[||]]. *)
val map : ('a -> 'b) -> 'a t -> 'b t
val equal : 'a equal -> 'a t equal
(** [equal eq a1 a2] is [true] if the lengths of [a1] and [a2] are the same
and if their corresponding elements test equal, using [eq]. *)
val compare : 'a ord -> 'a t ord
(** [compare cmp a1 a2] compares arrays [a1] and [a2] using the function comparison [cmp]. *)
val swap : 'a t -> int -> int -> unit
(** [swap a i j] swaps elements at indices [i] and [j].
@since 1.4 *)
val get_safe : 'a t -> int -> 'a option
(** [get_safe a i] returns [Some a.(i)] if [i] is a valid index.
@since 0.18 *)
val map_inplace : ('a -> 'a) -> 'a t -> unit
(** [map_inplace f a] replace all elements of [a] by its image by [f].
@since 3.8 *)
val mapi_inplace : (int -> 'a -> 'a) -> 'a t -> unit
(** [mapi_inplace f a] replace all elements of [a] by its image by [f].
@since 3.10 *)
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
(** [fold f init a] computes [f ((f (f init a.(0)) a.(1))) a.(n-1)],
where [n] is the length of the array [a].
Same as {!Array.fold_left}*)
val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a
(** [foldi f init a] is just like {!fold}, but it also passes in the index
of each element as the second argument to the folded function [f]. *)
val fold_while : ('a -> 'b -> 'a * [ `Stop | `Continue ]) -> 'a -> 'b t -> 'a
(** [fold_while f init a] folds left on array [a] until a stop condition via [('a, `Stop)]
is indicated by the accumulator.
@since 0.8 *)
val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a t -> 'acc * 'b t
(** [fold_map f init a] is a [fold_left]-like function, but it also maps the
array to another array.
@since 1.2, but only
@since 2.1 with labels *)
val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc t
(** [scan_left f init a] returns the array
[ [|init; f init x0; f (f init a.(0)) a.(1); |] ].
@since 1.2, but only
@since 2.1 with labels *)
val reverse_in_place : 'a t -> unit
(** [reverse_in_place a] reverses the array [a] in place. *)
val sorted : ('a -> 'a -> int) -> 'a t -> 'a array
(** [sorted f a] makes a copy of [a] and sorts it with [f].
@since 1.0 *)
val sort_indices : ('a -> 'a -> int) -> 'a t -> int array
(** [sort_indices f a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the index at which the [i]-th element of [sorted f a]
appears in [a]. [a] is not modified.
In other words, [map (fun i -> a.(i)) (sort_indices f a) = sorted f a].
[sort_indices] yields the inverse permutation of {!sort_ranking}.
@since 1.0 *)
val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
(** [sort_ranking f a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the index at which the [i]-th element of [a] appears
in [sorted f a]. [a] is not modified.
In other words, [map (fun i -> (sorted f a).(i)) (sort_ranking f a) = a].
[sort_ranking] yields the inverse permutation of {!sort_indices}.
In the absence of duplicate elements in [a], we also have
[lookup_exn a.(i) (sorted a) = (sorted_ranking a).(i)].
@since 1.0 *)
val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool
(** [mem ~eq x a] return true if x is present in [a]. Linear time.
@since 3.0
*)
val find_map : ('a -> 'b option) -> 'a t -> 'b option
(** [find_map f a] returns [Some y] if there is an element [x] such
that [f x = Some y]. Otherwise returns [None].
@since 1.3, but only
@since 2.1 with labels *)
val find_map_i : (int -> 'a -> 'b option) -> 'a t -> 'b option
(** [find_map_i f a] is like {!find_map}, but the index of the element is also passed
to the predicate function [f].
@since 1.3, but only
@since 2.1 with labels *)
val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
(** [find_idx f a] returns [Some (i,x)] where [x] is the [i]-th element of [a],
and [f x] holds. Otherwise returns [None].
@since 0.3.4 *)
val max : ('a -> 'a -> int) -> 'a t -> 'a option
(** [max cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e]
is a maximum element in [a] with respect to [cmp].
@since 3.12 *)
val max_exn : ('a -> 'a -> int) -> 'a t -> 'a
(** [max_exn cmp a] is like {!max}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val argmax : ('a -> 'a -> int) -> 'a t -> int option
(** [argmax cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i]
is the index of a maximum element in [a] with respect to [cmp].
@since 3.12 *)
val argmax_exn : ('a -> 'a -> int) -> 'a t -> int
(** [argmax_exn cmp a] is like {!argmax}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val min : ('a -> 'a -> int) -> 'a t -> 'a option
(** [min cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e]
is a minimum element in [a] with respect to [cmp].
@since 3.12 *)
val min_exn : ('a -> 'a -> int) -> 'a t -> 'a
(** [min_exn cmp a] is like {!min}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val argmin : ('a -> 'a -> int) -> 'a t -> int option
(** [argmin cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i]
is the index of a minimum element in [a] with respect to [cmp].
@since 3.12 *)
val argmin_exn : ('a -> 'a -> int) -> 'a t -> int
(** [argmin_exn cmp a] is like {!argmin}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val lookup : cmp:'a ord -> 'a -> 'a t -> int option
(** [lookup ~cmp key a] lookups the index of some key [key] in a sorted array [a].
Undefined behavior if the array [a] is not sorted wrt [~cmp].
Complexity: [O(log (n))] (dichotomic search).
@return [None] if the key [key] is not present, or
[Some i] ([i] the index of the key) otherwise. *)
val lookup_exn : cmp:'a ord -> 'a -> 'a t -> int
(** [lookup_exn ~cmp key a] is like {!lookup}, but
@raise Not_found if the key [key] is not present. *)
val bsearch :
cmp:('a -> 'a -> int) ->
'a ->
'a t ->
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
(** [bsearch ~cmp key a] finds the index of the object [key] in the array [a],
provided [a] is {b sorted} using [cmp]. If the array is not sorted,
the result is not specified (may raise Invalid_argument).
Complexity: [O(log n)] where n is the length of the array [a]
(dichotomic search).
@return
- [`At i] if [cmp a.(i) key = 0] (for some i).
- [`All_lower] if all elements of [a] are lower than [key].
- [`All_bigger] if all elements of [a] are bigger than [key].
- [`Just_after i] if [a.(i) < key < a.(i+1)].
- [`Empty] if the array [a] is empty.
@raise Invalid_argument if the array is found to be unsorted w.r.t [cmp].
@since 0.13 *)
val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
(** [for_all2 f [|a1; …; an|] [|b1; …; bn|]] is [true] if each pair of elements [ai bi]
satisfies the predicate [f].
That is, it returns [(f a1 b1) && (f a2 b2) && && (f an bn)].
@raise Invalid_argument if arrays have distinct lengths.
Allow different types.
@since 0.20 *)
val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
(** [exists2 f [|a1; …; an|] [|b1; …; bn|]] is [true] if any pair of elements [ai bi]
satisfies the predicate [f].
That is, it returns [(f a1 b1) || (f a2 b2) || || (f an bn)].
@raise Invalid_argument if arrays have distinct lengths.
Allow different types.
@since 0.20 *)
val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc
(** [fold2 f init a b] fold on two arrays [a] and [b] stepwise.
It computes [f ( (f init a1 b1) ) an bn].
@raise Invalid_argument if [a] and [b] have distinct lengths.
@since 0.20 *)
val shuffle : 'a t -> unit
(** [shuffle a] randomly shuffles the array [a], in place. *)
val shuffle_with : Random.State.t -> 'a t -> unit
(** [shuffle_with rs a] randomly shuffles the array [a] (like {!shuffle}) but a specialized random
state [rs] is used to control the random numbers being produced during shuffling (for reproducibility). *)
val random_choose : 'a t -> 'a random_gen
(** [random_choose a rs] randomly chooses an element of [a].
@raise Not_found if the array/slice is empty. *)
val to_string : ?sep:string -> ('a -> string) -> 'a array -> string
(** [to_string ~sep item_to_string a] print [a] to a string using [sep] as a separator
between elements of [a].
@since 2.7 *)
val to_iter : 'a t -> 'a iter
(** [to_iter a] returns an [iter] of the elements of an array [a].
The input array [a] is shared with the sequence and modification of it will result
in modification of the iterator.
@since 2.8 *)
val to_seq : 'a t -> 'a Seq.t
(** [to_seq a] returns a [Seq.t] of the elements of an array [a].
The input array [a] is shared with the sequence and modification of it will result
in modification of the sequence.
Renamed from [to_std_seq] since 3.0.
@since 3.0
*)
val to_gen : 'a t -> 'a gen
(** [to_gen a] returns a [gen] of the elements of an array [a]. *)
(** {2 IO} *)
val pp :
?pp_start:unit printer ->
?pp_stop:unit printer ->
?pp_sep:unit printer ->
'a printer ->
'a t printer
(** [pp ~pp_start ~pp_stop ~pp_sep pp_item ppf a] formats the array [a] on [ppf].
Each element is formatted with [pp_item], [pp_start] is called at the beginning,
[pp_stop] is called at the end, [pp_sep] is called between each elements.
By defaults [pp_start] and [pp_stop] does nothing and [pp_sep] defaults to
(fun out -> Format.fprintf out ",@ "). *)
val pp_i :
?pp_start:unit printer ->
?pp_stop:unit printer ->
?pp_sep:unit printer ->
(int -> 'a printer) ->
'a t printer
(** [pp_i ~pp_start ~pp_stop ~pp_sep pp_item ppf a] prints the array [a] on [ppf].
The printing function [pp_item] is giving both index and element.
[pp_start] is called at the beginning,
[pp_stop] is called at the end, [pp_sep] is called between each elements.
By defaults [pp_start] and [pp_stop] does nothing and [pp_sep] defaults to
(fun out -> Format.fprintf out ",@ "). *)
val rev : 'a t -> 'a t
(** [rev a] copies the array [a] and reverses it in place.
@since 0.20 *)
val filter : ('a -> bool) -> 'a t -> 'a t
(** Filter elements out of the array. Only the elements satisfying
the given predicate will be kept. *)
(** [filter f a] filters elements out of the array [a]. Only the elements satisfying
the given predicate [f] will be kept. *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
(** Map each element into another value, or discard it *)
(** [filter_map f [|a1; …; an|]] calls [(f a1)(f an)] and returns an array [b] consisting
of all elements [bi] such as [f ai = Some bi]. When [f] returns [None], the corresponding
element of [a] is discarded. *)
val monoid_product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** [monoid_product f a b] passes all combinaisons of tuples from the two arrays [a] and [b]
to the function [f].
@since 2.8 *)
val flat_map : ('a -> 'b t) -> 'a t -> 'b array
(** Transform each element into an array, then flatten *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Infix version of {!flat_map} *)
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
(** Infix version of {!map}
@since 0.8 *)
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
(** Infix version of {!map}
@since 0.8 *)
(** [flat_map f a] transforms each element of [a] into an array, then flattens. *)
val except_idx : 'a t -> int -> 'a list
(** Remove given index, obtaining the list of the other elements *)
val (--) : int -> int -> int t
(** Range array *)
val (--^) : int -> int -> int t
(** Range array, excluding right bound
@since 0.17 *)
(** [except_idx a i] removes the element of [a] at given index [i], and returns
the list of the other elements. *)
val random : 'a random_gen -> 'a t random_gen
val random_non_empty : 'a random_gen -> 'a t random_gen
val random_len : int -> 'a random_gen -> 'a t random_gen
(** {2 Slices}
A slice is a part of an array, that requires no copying and shares
its storage with the original array.
All indexing in a slice is relative to the beginning of a slice, not
to the underlying array (meaning a slice is effectively like
a regular array) *)
module Sub : sig
type 'a t
(** A slice is an array, an offset, and a length *)
val make : 'a array -> int -> len:int -> 'a t
(** Create a slice.
@raise Invalid_argument if the slice isn't valid *)
val of_slice : ('a array * int * int) -> 'a t
(** Make a sub-array from a triple [(arr, i, len)] where [arr] is the array,
[i] the offset in [arr], and [len] the number of elements of the slice.
@raise Invalid_argument if the slice isn't valid (See {!make}) *)
val to_slice : 'a t -> ('a array * int * int)
(** Convert into a triple [(arr, i, len)] where [len] is the length of
the subarray of [arr] starting at offset [i] *)
val full : 'a array -> 'a t
(** Slice that covers the full array *)
val underlying : 'a t -> 'a array
(** Underlying array (shared). Modifying this array will modify the slice *)
val copy : 'a t -> 'a array
(** Copy into a new array *)
val sub : 'a t -> int -> int -> 'a t
(** Sub-slice *)
include S with type 'a t := 'a t
end
(** {2 Generic Functions} *)
module type MONO_ARRAY = sig
@ -225,15 +314,48 @@ module type MONO_ARRAY = sig
type t
val length : t -> int
val get : t -> int -> elt
val set : t -> int -> elt -> unit
end
val sort_generic :
(module MONO_ARRAY with type t = 'arr and type elt = 'elt) ->
?cmp:('elt -> 'elt -> int) -> 'arr -> unit
(** Sort the array, without allocating (eats stack space though). Performance
might be lower than {!Array.sort}.
cmp:('elt -> 'elt -> int) ->
'arr ->
unit
(** [sort_generic (module M) ~cmp a] sorts the array [a], without allocating (eats stack space though).
Performance might be lower than {!Array.sort}.
@since 0.14 *)
(** {3 Infix Operators}
It is convenient to [open CCArray.Infix] to access the infix operators
without cluttering the scope too much.
@since 2.7 *)
module Infix : sig
val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t
(** [a >>= f] is the infix version of {!flat_map}. *)
val ( >>| ) : 'a t -> ('a -> 'b) -> 'b t
(** [a >>| f] is the infix version of {!map}.
@since 0.8 *)
val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t
(** [a >|= f] is the infix version of {!map}.
@since 0.8 *)
val ( -- ) : int -> int -> int t
(** [x -- y] creates an array containing integers in the range [x .. y]. Bounds included. *)
val ( --^ ) : int -> int -> int t
(** [x --^ y] creates an array containing integers in the range [x .. y]. Right bound excluded.
@since 0.17 *)
val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
val ( and+ ) : 'a t -> 'b t -> ('a * 'b) t
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
val ( and* ) : 'a t -> 'b t -> ('a * 'b) t
end
include module type of Infix

View file

@ -0,0 +1,3 @@
(* This file is free software, part of containers. See file "license" for more details. *)
include CCArray

377
src/core/CCArrayLabels.mli Normal file
View file

@ -0,0 +1,377 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** Array utils (Labeled version of {!CCArray}) *)
type 'a iter = ('a -> unit) -> unit
(** Fast internal iterator.
@since 2.8 *)
type 'a gen = unit -> 'a option
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a random_gen = Random.State.t -> 'a
type 'a printer = Format.formatter -> 'a -> unit
(** {2 Arrays} *)
include module type of ArrayLabels with module Floatarray = Array.Floatarray
(** @inline *)
val empty : 'a t
(** [empty] is the empty array, physically equal to [[||]]. *)
val equal : 'a equal -> 'a t equal
(** [equal eq a1 a2] is [true] if the lengths of [a1] and [a2] are the same
and if their corresponding elements test equal, using [eq]. *)
val compare : 'a ord -> 'a t ord
(** [compare cmp a1 a2] compares arrays [a1] and [a2] using the function comparison [cmp]. *)
val swap : 'a t -> int -> int -> unit
(** [swap a i j] swaps elements at indices [i] and [j].
@since 1.4 *)
val get_safe : 'a t -> int -> 'a option
(** [get_safe a i] returns [Some a.(i)] if [i] is a valid index.
@since 0.18 *)
val map_inplace : f:('a -> 'a) -> 'a t -> unit
(** [map_inplace ~f a] replace all elements of [a] by its image by [f].
@since 3.8 *)
val mapi_inplace : f:(int -> 'a -> 'a) -> 'a t -> unit
(** [mapi_inplace ~f a] replace all elements of [a] by its image by [f].
@since 3.10 *)
val fold : f:('a -> 'b -> 'a) -> init:'a -> 'b t -> 'a
(** [fold ~f ~init a] computes [f ((f (f init a.(0)) a.(1))) a.(n-1)],
where [n] is the length of the array [a].
Same as {!ArrayLabels.fold_left} *)
val foldi : f:('a -> int -> 'b -> 'a) -> init:'a -> 'b t -> 'a
(** [foldi ~f ~init a] is just like {!fold}, but it also passes in the index
of each element as the second argument to the folded function [f]. *)
val fold_while :
f:('a -> 'b -> 'a * [ `Stop | `Continue ]) -> init:'a -> 'b t -> 'a
(** [fold_while ~f ~init a] folds left on array [a] until a stop condition via [('a, `Stop)]
is indicated by the accumulator.
@since 0.8 *)
val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a t -> 'acc * 'b t
(** [fold_map ~f ~init a] is a [fold_left]-like function, but it also maps the
array to another array.
@since 1.2, but only
@since 2.1 with labels *)
val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a t -> 'acc t
(** [scan_left ~f ~init a] returns the array
[ [|init; f init x0; f (f init a.(0)) a.(1); |] ].
@since 1.2, but only
@since 2.1 with labels *)
val reverse_in_place : 'a t -> unit
(** [reverse_in_place a] reverses the array [a] in place. *)
val sorted : f:('a -> 'a -> int) -> 'a t -> 'a array
(** [sorted ~f a] makes a copy of [a] and sorts it with [f].
@since 1.0 *)
val sort_indices : f:('a -> 'a -> int) -> 'a t -> int array
(** [sort_indices ~f a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the index at which the [i]-th element of [sorted f a]
appears in [a]. [a] is not modified.
In other words, [map (fun i -> a.(i)) (sort_indices f a) = sorted f a].
[sort_indices] yields the inverse permutation of {!sort_ranking}.
@since 1.0 *)
val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array
(** [sort_ranking ~f a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the index at which the [i]-th element of [a] appears
in [sorted f a]. [a] is not modified.
In other words, [map (fun i -> (sorted f a).(i)) (sort_ranking f a) = a].
[sort_ranking] yields the inverse permutation of {!sort_indices}.
In the absence of duplicate elements in [a], we also have
[lookup_exn a.(i) (sorted a) = (sorted_ranking a).(i)].
@since 1.0 *)
val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool
(** [mem ~eq x a] return true if x is present in [a]. Linear time.
@since 3.0
*)
val find_map : f:('a -> 'b option) -> 'a t -> 'b option
(** [find_map ~f a] returns [Some y] if there is an element [x] such
that [f x = Some y]. Otherwise returns [None].
@since 1.3, but only
@since 2.1 with labels *)
val find_map_i : f:(int -> 'a -> 'b option) -> 'a t -> 'b option
(** [find_map_i ~f a] is like {!find_map}, but the index of the element is also passed
to the predicate function [f].
@since 1.3, but only
@since 2.1 with labels *)
val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option
(** [find_idx ~f a] returns [Some (i,x)] where [x] is the [i]-th element of [a],
and [f x] holds. Otherwise returns [None].
@since 0.3.4 *)
val max : cmp:('a -> 'a -> int) -> 'a t -> 'a option
(** [max ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e]
is a maximum element in [a] with respect to [cmp].
@since 3.12 *)
val max_exn : cmp:('a -> 'a -> int) -> 'a t -> 'a
(** [max_exn ~cmp a] is like {!max}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val argmax : cmp:('a -> 'a -> int) -> 'a t -> int option
(** [argmax ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i]
is the index of a maximum element in [a] with respect to [cmp].
@since 3.12 *)
val argmax_exn : cmp:('a -> 'a -> int) -> 'a t -> int
(** [argmax_exn ~cmp a] is like {!argmax}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val min : cmp:('a -> 'a -> int) -> 'a t -> 'a option
(** [min ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e]
is a minimum element in [a] with respect to [cmp].
@since 3.12 *)
val min_exn : cmp:('a -> 'a -> int) -> 'a t -> 'a
(** [min_exn ~cmp a] is like {!min}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val argmin : cmp:('a -> 'a -> int) -> 'a t -> int option
(** [argmin ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i]
is the index of a minimum element in [a] with respect to [cmp].
@since 3.12 *)
val argmin_exn : cmp:('a -> 'a -> int) -> 'a t -> int
(** [argmin_exn ~cmp a] is like {!argmin}, but
@raise Invalid_argument if [a] is empty.
@since 3.12 *)
val lookup : cmp:('a ord[@keep_label]) -> key:'a -> 'a t -> int option
(** [lookup ~cmp ~key a] lookups the index of some key [key] in a sorted array [a].
Undefined behavior if the array [a] is not sorted wrt [cmp].
Complexity: [O(log (n))] (dichotomic search).
@return [None] if the key [key] is not present, or
[Some i] ([i] the index of the key) otherwise. *)
val lookup_exn : cmp:('a ord[@keep_label]) -> key:'a -> 'a t -> int
(** [lookup_exn ~cmp ~key a] is like {!lookup}, but
@raise Not_found if the key [key] is not present. *)
val bsearch :
cmp:(('a -> 'a -> int)[@keep_label]) ->
key:'a ->
'a t ->
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
(** [bsearch ~cmp ~key a] finds the index of the object [key] in the array [a],
provided [a] is {b sorted} using [cmp]. If the array is not sorted,
the result is not specified (may raise Invalid_argument).
Complexity: [O(log n)] where n is the length of the array [a]
(dichotomic search).
@return
- [`At i] if [cmp a.(i) key = 0] (for some i).
- [`All_lower] if all elements of [a] are lower than [key].
- [`All_bigger] if all elements of [a] are bigger than [key].
- [`Just_after i] if [a.(i) < key < a.(i+1)].
- [`Empty] if the array [a] is empty.
@raise Invalid_argument if the array is found to be unsorted w.r.t [cmp].
@since 0.13 *)
val for_all2 : f:('a -> 'b -> bool) -> 'a t -> 'b t -> bool
(** [for_all2 ~f [|a1; …; an|] [|b1; …; bn|]] is [true] if each pair of elements [ai bi]
satisfies the predicate [f].
That is, it returns [(f a1 b1) && (f a2 b2) && && (f an bn)].
@raise Invalid_argument if arrays have distinct lengths.
Allow different types.
@since 0.20 *)
val exists2 : f:('a -> 'b -> bool) -> 'a t -> 'b t -> bool
(** [exists2 ~f [|a1; …; an|] [|b1; …; bn|]] is [true] if any pair of elements [ai bi]
satisfies the predicate [f].
That is, it returns [(f a1 b1) || (f a2 b2) || || (f an bn)].
@raise Invalid_argument if arrays have distinct lengths.
Allow different types.
@since 0.20 *)
val fold2 : f:('acc -> 'a -> 'b -> 'acc) -> init:'acc -> 'a t -> 'b t -> 'acc
(** [fold2 ~f ~init a b] fold on two arrays [a] and [b] stepwise.
It computes [f ( (f init a1 b1) ) an bn].
@raise Invalid_argument if [a] and [b] have distinct lengths.
@since 0.20 *)
val iter2 : f:('a -> 'b -> unit) -> 'a t -> 'b t -> unit
(** [iter2 ~f a b] iterates on the two arrays [a] and [b] stepwise.
It is equivalent to [f a0 b0; ; f a.(length a - 1) b.(length b - 1); ()].
@raise Invalid_argument if [a] and [b] have distinct lengths.
@since 0.20 *)
val shuffle : 'a t -> unit
(** [shuffle a] randomly shuffles the array [a], in place. *)
val shuffle_with : Random.State.t -> 'a t -> unit
(** [shuffle_with rs a] randomly shuffles the array [a] (like {!shuffle}) but a specialized random
state [rs] is used to control the random numbers being produced during shuffling (for reproducibility). *)
val random_choose : 'a t -> 'a random_gen
(** [random_choose a rs] randomly chooses an element of [a].
@raise Not_found if the array/slice is empty. *)
val to_string : ?sep:string -> ('a -> string) -> 'a array -> string
(** [to_string ~sep item_to_string a] print [a] to a string using [sep] as a separator
between elements of [a].
@since 2.7 *)
val to_iter : 'a t -> 'a iter
(** [to_iter a] returns an [iter] of the elements of an array [a].
The input array [a] is shared with the sequence and modification of it will result
in modification of the iterator.
@since 2.8 *)
val to_seq : 'a t -> 'a Seq.t
(** [to_seq a] returns a [Seq.t] of the elements of an array [a].
The input array [a] is shared with the sequence and modification of it will result
in modification of the sequence.
Renamed from [to_std_seq] since 3.0.
@since 3.0
*)
val to_gen : 'a t -> 'a gen
(** [to_gen a] returns a [gen] of the elements of an array [a]. *)
(** {2 IO} *)
val pp :
?pp_start:unit printer ->
?pp_stop:unit printer ->
?pp_sep:unit printer ->
'a printer ->
'a t printer
(** [pp ~pp_start ~pp_stop ~pp_sep pp_item ppf a] formats the array [a] on [ppf].
Each element is formatted with [pp_item], [pp_start] is called at the beginning,
[pp_stop] is called at the end, [pp_sep] is called between each elements.
By defaults [pp_start] and [pp_stop] does nothing and [pp_sep] defaults to
(fun out -> Format.fprintf out ",@ "). *)
val pp_i :
?pp_start:unit printer ->
?pp_stop:unit printer ->
?pp_sep:unit printer ->
(int -> 'a printer) ->
'a t printer
(** [pp_i ~pp_start ~pp_stop ~pp_sep pp_item ppf a] prints the array [a] on [ppf].
The printing function [pp_item] is giving both index and element.
[pp_start] is called at the beginning,
[pp_stop] is called at the end, [pp_sep] is called between each elements.
By defaults [pp_start] and [pp_stop] does nothing and [pp_sep] defaults to
(fun out -> Format.fprintf out ",@ "). *)
val map2 : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** [map2 ~f a b] applies function [f] to all elements of [a] and [b],
and builds an array with the results returned by [f]:
[[| f a.(0) b.(0); ; f a.(length a - 1) b.(length b - 1)|]].
@raise Invalid_argument if [a] and [b] have distinct lengths.
@since 0.20 *)
val rev : 'a t -> 'a t
(** [rev a] copies the array [a] and reverses it in place.
@since 0.20 *)
val filter : f:('a -> bool) -> 'a t -> 'a t
(** [filter ~f a] filters elements out of the array [a]. Only the elements satisfying
the given predicate [f] will be kept. *)
val filter_map : f:('a -> 'b option) -> 'a t -> 'b t
(** [filter_map ~f [|a1; …; an|]] calls [(f a1)(f an)] and returns an array [b] consisting
of all elements [bi] such as [f ai = Some bi]. When [f] returns [None], the corresponding
element of [a] is discarded. *)
val monoid_product : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** [monoid_product ~f a b] passes all combinaisons of tuples from the two arrays [a] and [b]
to the function [f].
@since 2.8 *)
val flat_map : f:('a -> 'b t) -> 'a t -> 'b array
(** [flat_map ~f a] transforms each element of [a] into an array, then flattens. *)
val except_idx : 'a t -> int -> 'a list
(** [except_idx a i] removes the element of [a] at given index [i], and returns
the list of the other elements. *)
val random : 'a random_gen -> 'a t random_gen
val random_non_empty : 'a random_gen -> 'a t random_gen
val random_len : int -> 'a random_gen -> 'a t random_gen
(** {2 Generic Functions} *)
module type MONO_ARRAY = sig
type elt
type t
val length : t -> int
val get : t -> int -> elt
val set : t -> int -> elt -> unit
end
val sort_generic :
(module MONO_ARRAY with type t = 'arr and type elt = 'elt) ->
cmp:(('elt -> 'elt -> int)[@keep_label]) ->
'arr ->
unit
(** [sort_generic (module M) ~cmp a] sorts the array [a], without allocating (eats stack space though).
Performance might be lower than {!Array.sort}.
@since 0.14 *)
(** {3 Infix Operators}
It is convenient to [open CCArray.Infix] to access the infix operators
without cluttering the scope too much.
@since 2.7 *)
module Infix : sig
val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t
(** [a >>= f] is the infix version of {!flat_map}. *)
val ( >>| ) : 'a t -> ('a -> 'b) -> 'b t
(** [a >>| f] is the infix version of {!map}.
@since 0.8 *)
val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t
(** [a >|= f] is the infix version of {!map}.
@since 0.8 *)
val ( -- ) : int -> int -> int t
(** [x -- y] creates an array containing integers in the range [x .. y]. Bounds included. *)
val ( --^ ) : int -> int -> int t
(** [x --^ y] creates an array containing integers in the range [x .. y]. Right bound excluded.
@since 0.17 *)
val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
val ( and+ ) : 'a t -> 'b t -> ('a * 'b) t
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
val ( and* ) : 'a t -> 'b t -> ('a * 'b) t
end
include module type of Infix

69
src/core/CCAtomic.ml Normal file
View file

@ -0,0 +1,69 @@
[@@@ifge 4.12]
include Atomic
[@@@else_]
open Stdlib (* for == *)
type 'a t = { mutable x: 'a }
let[@inline] make x = { x }
let[@inline] get { x } = x
let[@inline] set r x = r.x <- x
let[@inline never] exchange r x =
(* atomic *)
let y = r.x in
r.x <- x;
(* atomic *)
y
let[@inline never] compare_and_set r seen v =
(* atomic *)
if r.x == seen then (
r.x <- v;
(* atomic *)
true
) else
false
let[@inline never] fetch_and_add r x =
(* atomic *)
let v = r.x in
r.x <- x + r.x;
(* atomic *)
v
let[@inline never] incr r =
(* atomic *)
r.x <- 1 + r.x
(* atomic *)
let[@inline never] decr r =
(* atomic *)
r.x <- r.x - 1
(* atomic *)
[@@@endif]
(** Update loop with a compare-and-swap, and some basic backoff behavior.
[update_cas atomic f] is, in essence,
[let res, x = f !atomic in atomic := x; res]
done atomically. [f] might be called multiple times and must be as cheap
as possible.
@since NEXT_RELEASE *)
let update_cas (type res) (self : 'a t) (f : 'a -> res * 'a) : res =
let exception Ret of res in
let backoff = ref 1 in
try
while true do
let old_val = get self in
let res, new_val = f old_val in
if compare_and_set self old_val new_val then raise_notrace (Ret res);
Containers_domain.relax_loop !backoff;
backoff := min 128 (2 * !backoff)
done;
assert false
with Ret r -> r

View file

@ -1,16 +1,30 @@
(* This file is free software, part of containers. See file "license" for more details. *)
type t = bool
let equal (a:bool) b = a=b
let equal (a : bool) b = Stdlib.( = ) a b
let compare (a : bool) b = Stdlib.compare a b
let compare (a:bool) b = Pervasives.compare a b
let if_then f x =
if x then
Some (f ())
else
None
let negate x = not x
let if_then_else f g x =
if x then
f ()
else
g ()
type 'a printer = Buffer.t -> 'a -> unit
type 'a formatter = Format.formatter -> 'a -> unit
let to_int (x : bool) : int =
if x then
1
else
0
let pp buf = Printf.bprintf buf "%B"
let print fmt = Format.pp_print_bool fmt
let of_int x : t = x <> 0
type 'a printer = Format.formatter -> 'a -> unit
let pp = Format.pp_print_bool

View file

@ -1,22 +1,31 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** {1 Basic Bool functions} *)
(** Basic Bool functions *)
type t = bool
val compare : t -> t -> int
(** Total ordering on booleans, similar to {!Pervasives.compare} *)
(** [compare b1 b2] is the total ordering on booleans [b1] and [b2], similar to {!Stdlib.compare}. *)
val equal : t -> t -> bool
(** [equal b1 b2] is [true] if [b1] and [b2] are the same. *)
val negate : t -> t
(** Negation on booleans (functional version of [not]) *)
val if_then : (unit -> 'a) -> t -> 'a option
(** [if_then f x] is [Some (f ())] if [x] is true and None otherwise.
@since 3.13 *)
type 'a printer = Buffer.t -> 'a -> unit
type 'a formatter = Format.formatter -> 'a -> unit
val if_then_else : (unit -> 'a) -> (unit -> 'a) -> t -> 'a
(** [if_then_else f g x] is [f ()] if [x] is true and [g ()] otherwise.
@since 3.13 *)
val to_int : t -> int
(** [to_int true = 1], [to_int false = 0].
@since 2.7 *)
val of_int : int -> t
(** [of_int i] is the same as [i <> 0]
@since 2.7 *)
type 'a printer = Format.formatter -> 'a -> unit
val pp : t printer
(** Printer for booleans *)
val print : t formatter

139
src/core/CCByte_buffer.ml Normal file
View file

@ -0,0 +1,139 @@
type 'a iter = ('a -> unit) -> unit
type t = {
mutable bs: bytes;
mutable len: int;
}
let create ?(cap = 0) () : t =
let bs =
if cap = 0 then
Bytes.unsafe_of_string ""
else
Bytes.create cap
in
{ len = 0; bs }
let[@inline] capacity self : int = Bytes.length self.bs
let[@inline] bytes self = self.bs
let[@inline] length self = self.len
let[@inline] is_empty self = self.len = 0
let[@inline] clear self = self.len <- 0
let grow_cap_ self =
min Sys.max_string_length
(let n = capacity self in
n + (n lsl 1) + 5)
let grow_to_ self newcap =
if newcap = capacity self then invalid_arg "byte_buf: cannot grow further";
let newbytes = Bytes.create newcap in
Bytes.blit self.bs 0 newbytes 0 self.len;
self.bs <- newbytes
let[@inline never] grow_ self =
let newcap = grow_cap_ self in
grow_to_ self newcap
let[@inline never] ensure_cap_grow_ self n =
(* new capacity, make sure it's at least [grow_cap_] so
that repeated calls to [ensure_cap] have the amortized complexity *)
let newcap = max n (grow_cap_ self) in
grow_to_ self newcap
let[@inline] ensure_cap self n =
if n > capacity self then ensure_cap_grow_ self n
let[@inline] ensure_free self n =
if n > capacity self - self.len then ensure_cap_grow_ self (self.len + n)
let[@inline] shrink_to self n = if self.len > n then self.len <- n
let append_buf (self : t) buf : unit =
let n = Buffer.length buf in
ensure_cap self (length self + n);
Buffer.blit buf 0 self.bs self.len n;
self.len <- self.len + n
let append_subbytes self b off len =
ensure_cap self (length self + len);
Bytes.blit b off self.bs self.len len;
self.len <- self.len + len
let[@inline] append_bytes self b = append_subbytes self b 0 (Bytes.length b)
let[@inline] append_string self s = append_bytes self (Bytes.unsafe_of_string s)
let[@inline] append_substring self s off len =
append_subbytes self (Bytes.unsafe_of_string s) off len
let[@inline] add_char_unsafe_ self c =
Bytes.unsafe_set self.bs self.len c;
self.len <- self.len + 1
let[@inline] add_char self c =
if self.len = capacity self then grow_ self;
add_char_unsafe_ self c
let[@inline] unsafe_get self i = Bytes.unsafe_get self.bs i
let[@inline] unsafe_set self i c = Bytes.unsafe_set self.bs i c
let[@inline] get self i =
if i < 0 || i >= self.len then invalid_arg "Byte_buf.get";
unsafe_get self i
let[@inline] set self i c =
if i < 0 || i >= self.len then invalid_arg "Byte_buf.set";
unsafe_set self i c
let[@inline] contents self = Bytes.sub_string self.bs 0 self.len
let[@inline] contents_bytes self = Bytes.sub self.bs 0 self.len
let[@inline] append_iter self i = i (add_char self)
let[@inline] append_seq self seq = Seq.iter (add_char self) seq
let[@inline] to_slice self = CCByte_slice.create ~len:self.len self.bs
let fold_left f acc self =
let { bs; len } = self in
(* capture current content *)
let acc = ref acc in
for i = 0 to len do
acc := f !acc (Bytes.unsafe_get bs i)
done;
!acc
let[@inline] iter f self =
(* capture current content *)
let { bs; len } = self in
for i = 0 to len do
f (Bytes.unsafe_get bs i)
done
let[@inline] iteri f self =
let { bs; len } = self in
for i = 0 to len do
f i (Bytes.unsafe_get bs i)
done
let of_seq seq =
let self = create ~cap:32 () in
append_seq self seq;
self
let of_iter iter =
let self = create ~cap:32 () in
append_iter self iter;
self
let to_iter self yield = iter yield self
let to_seq self =
let { bs; len } = self in
let rec s i () =
if i = len then
Seq.Nil
else
Seq.Cons (Bytes.unsafe_get bs i, s (i + 1))
in
s 0
(* TODO: unicode operators.*)

111
src/core/CCByte_buffer.mli Normal file
View file

@ -0,0 +1,111 @@
(** Byte buffer.
A dynamic vector of bytes that doesn't hide its internal from you.
Same use case as [Buffer.t] but with more power.
@since 3.7
*)
type t = {
mutable bs: bytes; (** The backing bytes buffer *)
mutable len: int;
(** Length of the "active" slice in [bs]. The actual content
of the buffer is [bs[0]..bs[len-1]]. What comes after
is undefined garbage. *)
}
(** The byte buffer.
The definition is public since 3.13.1 . *)
type 'a iter = ('a -> unit) -> unit
val create : ?cap:int -> unit -> t
(** Create a new buffer with given initial capacity. *)
val length : t -> int
(** Current length. *)
val is_empty : t -> bool
(** [is_empty b] is [length b=0] *)
val capacity : t -> int
(** Current capacity (size of the array returned by {!bytes}) *)
val bytes : t -> bytes
(** Access the underlying byte buffer. This buffer can change after
operations that affect the capacity (e.g. {!add_char}). *)
val clear : t -> unit
(** [clear buf] sets [buf.len <- 0]. This doesn't resize the byte buffer. *)
val ensure_cap : t -> int -> unit
(** [ensure_cap self n] ensures that [capacity self >= n].
@raise Invalid_argument if this requires the buffer to grow beyond system limits. *)
val ensure_free : t -> int -> unit
(** [ensure_free buf n] ensures that the free space at the end of the
buffer is at least [n].
@raise Invalid_argument if this requires the buffer to grow beyond system limits. *)
val shrink_to : t -> int -> unit
(** [shrink_to buf n] reduces [length buf] to at most [n].
Does nothing if the length is already <= n. *)
val add_char : t -> char -> unit
(** Push a character at the end.
@raise Invalid_argument if this requires the buffer to grow beyond system limits. *)
val append_bytes : t -> bytes -> unit
(** Add bytes at the end *)
val append_subbytes : t -> bytes -> int -> int -> unit
(** Add byte slice at the end *)
val append_string : t -> string -> unit
(** Add string at the end *)
val append_substring : t -> string -> int -> int -> unit
(** Add substring at the end *)
val append_buf : t -> Buffer.t -> unit
(** Add content of the buffer at the end *)
val append_iter : t -> char iter -> unit
(** Adds characters from the iter *)
val append_seq : t -> char Seq.t -> unit
(** Adds characters from the seq *)
val get : t -> int -> char
(** Get the char at the given offset *)
val unsafe_get : t -> int -> char
(** Get the char at the given offset, unsafe (no bound check) *)
val set : t -> int -> char -> unit
(** Set the char at the given offset *)
val unsafe_set : t -> int -> char -> unit
(** Set the char at the given offset, unsafe (no bound check) *)
val to_slice : t -> CCByte_slice.t
(** [to_slice buf] returns a slice of the current content.
The slice shares the same byte array as [buf] (until [buf] is resized).
@since 3.13.1 *)
val contents : t -> string
(** Copy the internal data to a string. Allocates. *)
val contents_bytes : t -> bytes
(** Copy the internal data to a {!bytes}. Allocates. *)
val iter : (char -> unit) -> t -> unit
(** Iterate on the content *)
val iteri : (int -> char -> unit) -> t -> unit
(** Iterate with index.
@since 3.13.1 *)
val fold_left : ('a -> char -> 'a) -> 'a -> t -> 'a
val of_iter : char iter -> t
val of_seq : char Seq.t -> t
val to_iter : t -> char iter
val to_seq : t -> char Seq.t

42
src/core/CCByte_slice.ml Normal file
View file

@ -0,0 +1,42 @@
type t = {
bs: bytes;
mutable off: int;
mutable len: int;
}
let show self = Printf.sprintf "<slice len=%d>" self.len
let pp out self = Format.pp_print_string out (show self)
let create ?(off = 0) ?len bs =
let len =
match len with
| None -> Bytes.length bs - off
| Some n ->
if n < 0 || off + n > Bytes.length bs then
invalid_arg "Bslice: invalid length";
n
in
{ bs; off; len }
let[@inline] unsafe_of_string ?off ?len s =
create ?off ?len (Bytes.unsafe_of_string s)
let[@inline] len self = self.len
let[@inline] contents self = Bytes.sub_string self.bs self.off self.len
let[@inline] get self i : char =
if i >= self.len then invalid_arg "Bslice: out of bound access";
Bytes.unsafe_get self.bs (self.off + i)
let[@inline] set self i c : unit =
if i >= self.len then invalid_arg "Bslice: out of bound access";
Bytes.unsafe_set self.bs (self.off + i) c
let sub self off len =
if off + len > self.len then invalid_arg "Bslice: invalid length";
{ bs = self.bs; off = self.off + off; len }
let[@inline] consume self n : unit =
if n > self.len then invalid_arg "Bslice: consuming too many bytes";
self.off <- self.off + n;
self.len <- self.len - n

49
src/core/CCByte_slice.mli Normal file
View file

@ -0,0 +1,49 @@
(** A simple byte slice.
@since 3.13.1 *)
type t = {
bs: bytes; (** The bytes, potentially shared between many slices *)
mutable off: int; (** Offset in [bs] *)
mutable len: int;
(** Length of the slice. Valid indices are [bs[off]…bs[off+len-1]],
inclusive. *)
}
val show : t -> string
(** Simple printer (summary, doesn't show the content) *)
val pp : Format.formatter -> t -> unit
(** Simple printer (summary, doesn't show the content) *)
val create : ?off:int -> ?len:int -> bytes -> t
(** [create bs] creates a slice of [bs].
@param off optional starting offset
@param len length of the slice *)
val unsafe_of_string : ?off:int -> ?len:int -> string -> t
(** [unsafe_of_string s] makes a slice from a string.
This is unsafe because mutating the bytes is forbidden
(just like with {!Bytes.unsafe_of_string} *)
val len : t -> int
(** Access the length *)
val get : t -> int -> char
(** [get sl i] gets the [i]-th byte of the slice. Same as [sl.bs.[sl.off + i]].
@raise Invalid_argument if out of bounds. *)
val set : t -> int -> char -> unit
(** [set sl i c] sets the [i]-th byte to [c].
@raise Invalid_argument if out of bounds. *)
val consume : t -> int -> unit
(** [consume sl n] moves the offset forward by [n] bytes, and
reduces [len] by [n] bytes. *)
val contents : t -> string
(** A copy of the contents of the slice. Allocates. *)
val sub : t -> int -> int -> t
(** [sub sl off len] makes a new slice with the same
backing [bs]. *)

View file

@ -0,0 +1,297 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** {1 Simple S-expression parsing/printing} *)
type 'a or_error = ('a, string) result
type 'a gen = unit -> 'a option
module type SEXP = CCSexp_intf.BASIC_SEXP
module type S = CCSexp_intf.S0
let equal_string (a : string) b = Stdlib.( = ) a b
let compare_string (a : string) b = Stdlib.compare a b
let _with_in filename f =
let ic = open_in filename in
try
let x = f ic in
close_in ic;
x
with e ->
close_in ic;
Error (Printexc.to_string e)
let _with_out filename f =
let oc = open_out filename in
try
let x = f oc in
close_out oc;
x
with e ->
close_out oc;
raise e
module Make (Sexp : SEXP) = struct
type t = Sexp.t
type sexp = t
let atom = Sexp.atom
let list = Sexp.list
let of_int x = Sexp.atom (string_of_int x)
let of_float x = Sexp.atom (string_of_float x)
let of_bool x = Sexp.atom (string_of_bool x)
let of_unit = Sexp.list []
let of_list l = Sexp.list l
let of_rev_list l = Sexp.list (List.rev l)
let of_pair (x, y) = Sexp.list [ x; y ]
let of_triple (x, y, z) = Sexp.list [ x; y; z ]
let of_quad (x, y, z, u) = Sexp.list [ x; y; z; u ]
let of_variant name args = Sexp.list (Sexp.atom name :: args)
let of_field name t = Sexp.list [ Sexp.atom name; t ]
let of_record l = Sexp.list (List.map (fun (n, x) -> of_field n x) l)
(** {3 Printing} *)
let rec to_buf b t =
Sexp.match_ t
~atom:(fun s -> Printf.bprintf b "%d:%s" (String.length s) s)
~list:(function
| [] -> Buffer.add_string b "()"
| [ x ] -> Printf.bprintf b "(%a)" to_buf x
| l ->
Buffer.add_char b '(';
List.iter (to_buf b) l;
Buffer.add_char b ')')
let to_string t =
let b = Buffer.create 128 in
to_buf b t;
Buffer.contents b
let rec pp_noindent fmt t =
Sexp.match_ t
~atom:(fun s -> Format.fprintf fmt "%d:%s" (String.length s) s)
~list:(function
| [] -> Format.pp_print_string fmt "()"
| [ x ] -> Format.fprintf fmt "(%a)" pp_noindent x
| l ->
Format.fprintf fmt "(";
List.iter (pp_noindent fmt) l;
Format.fprintf fmt ")")
let pp = pp_noindent
let rec to_chan oc t =
Sexp.match_ t
~atom:(fun s -> Printf.fprintf oc "%d:%s" (String.length s) s)
~list:(function
| [] -> output_string oc "()"
| [ x ] -> Printf.fprintf oc "(%a)" to_chan x
| l ->
output_char oc '(';
List.iter (to_chan oc) l;
output_char oc ')')
let to_file_iter filename iter =
_with_out filename (fun oc -> iter (fun t -> to_chan oc t))
let to_file filename t = to_file_iter filename (fun k -> k t)
(** {3 Parsing} *)
module type INPUT = sig
exception EOF
val read_char : unit -> char
val read_string : int -> string
end
module Decoder (I : INPUT) = struct
let[@inline] is_num_ c =
Char.code c >= Char.code '0' && Char.code c <= Char.code '9'
let[@inline] as_num_ c = Char.code c - Char.code '0'
let next_ () : sexp or_error * bool =
let rec read_string_len n =
match I.read_char () with
| c when is_num_ c -> read_string_len ((n * 10) + as_num_ c)
| ':' ->
let s = I.read_string n in
atom s
| _ -> failwith "expected string length"
and eat_colon () =
match I.read_char () with
| ':' -> ()
| _ -> failwith "expected ':'"
and read_in_paren acc =
match I.read_char () with
| ')' -> list (List.rev acc)
| c when is_num_ c ->
let sexp = read_string_len (as_num_ c) in
read_in_paren (sexp :: acc)
| '(' ->
let sexp = read_in_paren [] in
read_in_paren (sexp :: acc)
| _ -> failwith "expected list of sexprs"
in
(* read a S-expr *)
try
match I.read_char () with
| exception I.EOF -> Error "unexpected EOF", true
| '(' -> Ok (read_in_paren []), false
| '0' ->
eat_colon ();
Ok (atom ""), false
| c when is_num_ c -> Ok (read_string_len (as_num_ c)), false
| _ -> Error "unexpected char, expected toplevel sexpr", false
with Failure e -> Error e, false
let to_list () : _ or_error =
let rec iter acc =
match next_ () with
| Error _, true -> Ok (List.rev acc)
| Ok x, _ -> iter (x :: acc)
| (Error _ as res), _ -> res
in
try iter [] with e -> Error (Printexc.to_string e)
let[@inline] next_or_error () : _ or_error = fst (next_ ())
end
[@@inline]
module Decoder_str (X : sig
val s : string
end) =
Decoder (struct
exception EOF
let i = ref 0
let n = String.length X.s
let read_char () =
if !i >= n then raise_notrace EOF;
let c = String.unsafe_get X.s !i in
incr i;
c
let read_string len =
if !i + len > n then raise_notrace EOF;
let res = String.sub X.s !i len in
i := !i + len;
res
end)
[@@inline]
let parse_string s : t or_error =
let module D = Decoder_str (struct
let s = s
end) in
D.next_or_error ()
let parse_string_list s : t list or_error =
let module D = Decoder_str (struct
let s = s
end) in
D.to_list ()
module Decoder_ic (X : sig
val ic : in_channel
end) =
Decoder (struct
exception EOF = End_of_file
let[@inline] read_char () = input_char X.ic
let read_string n =
match n with
| 0 -> ""
| 1 -> String.make 1 (read_char ())
| _ ->
let buf = Bytes.make n '\000' in
let i = ref 0 in
while !i < n do
let len = input X.ic buf !i (n - !i) in
i := !i + len
done;
Bytes.unsafe_to_string buf
end)
[@@inline]
let parse_chan_ ?file ic : sexp or_error =
let module D = Decoder_ic (struct
let ic = ic
end) in
match D.next_or_error (), file with
| Error s, Some file -> Error (Printf.sprintf "%s in '%s'" s file)
| r, _ -> r
let parse_chan_list_ ?file ic =
let module D = Decoder_ic (struct
let ic = ic
end) in
match D.to_list (), file with
| Error s, Some file -> Error (Printf.sprintf "%s in '%s'" s file)
| r, _ -> r
let parse_chan ic = parse_chan_ ic
let parse_chan_list ic = parse_chan_list_ ic
let parse_chan_gen ic =
let module D = Decoder_ic (struct
let ic = ic
end) in
fun () ->
match D.next_ () with
| _, true -> None
| Error e, _ -> Some (Error e)
| Ok x, _ -> Some (Ok x)
let parse_file filename = _with_in filename (parse_chan_ ~file:filename)
let parse_file_list filename =
_with_in filename (parse_chan_list_ ~file:filename)
end
type t =
[ `Atom of string
| `List of t list
]
let rec equal a b =
match a, b with
| `Atom s1, `Atom s2 -> equal_string s1 s2
| `List l1, `List l2 ->
(try List.for_all2 equal l1 l2 with Invalid_argument _ -> false)
| `Atom _, _ | `List _, _ -> false
let rec compare_list a b =
match a, b with
| [], [] -> 0
| [], _ :: _ -> -1
| _ :: _, [] -> 1
| x :: xs, y :: ys ->
(match compare x y with
| 0 -> compare_list xs ys
| c -> c)
and compare a b =
match a, b with
| `Atom s1, `Atom s2 -> compare_string s1 s2
| `List l1, `List l2 -> compare_list l1 l2
| `Atom _, _ -> -1
| `List _, _ -> 1
module Basic_ = struct
type nonrec t = t
let atom x = `Atom x
let list x = `List x
let match_ x ~atom ~list =
match x with
| `Atom x -> atom x
| `List l -> list l
end
include (Make (Basic_) : S with type t := t)

View file

@ -0,0 +1,33 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** Canonical S-expressions
See {{: https://en.wikipedia.org/wiki/Canonical_S-expressions} wikipedia}.
These S-expressions are binary safe.
@since 3.3
*)
type 'a or_error = ('a, string) result
type 'a gen = unit -> 'a option
module type SEXP = CCSexp_intf.BASIC_SEXP
module type S = CCSexp_intf.S0
(** {2 Parser and printer} *)
module Make (Sexp : SEXP) : S with type t = Sexp.t
(** {2 Basics} *)
type t =
[ `Atom of string
| `List of t list
]
(** A simple, structural representation of S-expressions.
Compatible with {!CCSexp}. *)
include S with type t := t
val equal : t -> t -> bool
val compare : t -> t -> int
val atom : string -> t

Some files were not shown because too many files have changed in this diff Show more