mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-17 08:06:41 -05:00
Compare commits
45 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1b13f1c7f | ||
|
|
f51b56ffbc | ||
|
|
02c4d51fd0 | ||
|
|
7c8adbd9fc | ||
|
|
954ea61d22 | ||
|
|
b069461fe2 | ||
|
|
f13fb6f471 | ||
|
|
01402388e4 | ||
|
|
14ad490c7e | ||
|
|
3b49ad2a4e | ||
|
|
1a11459991 | ||
|
|
0290aa9754 | ||
|
|
9df429005d | ||
|
|
99dba20fa6 | ||
|
|
f934db1e9c | ||
|
|
14ad8c1f2a | ||
|
|
0ff9614520 | ||
|
|
ab7d0fcc09 | ||
|
|
b55d3cfe6a | ||
|
|
4613aafb30 | ||
|
|
4294dc7ca3 | ||
|
|
31ad563044 | ||
|
|
2dcaa12fb7 | ||
|
|
bace9fe209 | ||
|
|
1486cbf5a1 | ||
|
|
b95e2de65b | ||
|
|
f310bc5771 | ||
|
|
6d962a70d0 | ||
|
|
517d4605d5 | ||
|
|
b0f673fbbb | ||
|
|
c6f6a012b4 | ||
|
|
1e06423e87 | ||
|
|
8bb3801a52 | ||
|
|
d29ed7ee72 | ||
|
|
330cba94de | ||
|
|
699b370220 | ||
|
|
85ca948012 | ||
|
|
6c8569a7d9 | ||
|
|
1498158a4f | ||
|
|
d8c00f96be | ||
|
|
510db54150 | ||
|
|
2e8d70f073 | ||
|
|
2fda76a5f7 | ||
|
|
cad41d70d6 | ||
|
|
b140a50c46 |
62 changed files with 752 additions and 146 deletions
28
.github/workflows/format.yml
vendored
Normal file
28
.github/workflows/format.yml
vendored
Normal 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
|
||||||
|
|
||||||
4
.github/workflows/gh-pages.yml
vendored
4
.github/workflows/gh-pages.yml
vendored
|
|
@ -13,9 +13,9 @@ jobs:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
|
|
||||||
- name: Use OCaml
|
- name: Use OCaml
|
||||||
uses: ocaml/setup-ocaml@v2
|
uses: ocaml/setup-ocaml@v3
|
||||||
with:
|
with:
|
||||||
ocaml-compiler: '4.14'
|
ocaml-compiler: '5.2'
|
||||||
dune-cache: false
|
dune-cache: false
|
||||||
|
|
||||||
- name: Deps
|
- name: Deps
|
||||||
|
|
|
||||||
26
.github/workflows/main.yml
vendored
26
.github/workflows/main.yml
vendored
|
|
@ -19,14 +19,14 @@ jobs:
|
||||||
- '4.08'
|
- '4.08'
|
||||||
- '4.10'
|
- '4.10'
|
||||||
- '4.14'
|
- '4.14'
|
||||||
- '5.2'
|
- '5.3'
|
||||||
- 'ocaml-variants.5.0.0+options,ocaml-option-bytecode-only'
|
- 'ocaml-variants.5.0.0+options,ocaml-option-bytecode-only'
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
||||||
uses: ocaml/setup-ocaml@v2
|
uses: ocaml/setup-ocaml@v3
|
||||||
with:
|
with:
|
||||||
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
||||||
dune-cache: true
|
dune-cache: true
|
||||||
|
|
@ -52,7 +52,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
||||||
uses: ocaml/setup-ocaml@v2
|
uses: ocaml/setup-ocaml@v3
|
||||||
with:
|
with:
|
||||||
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
||||||
dune-cache: true
|
dune-cache: true
|
||||||
|
|
@ -62,23 +62,3 @@ jobs:
|
||||||
opam install containers-data --deps-only # no test deps
|
opam install containers-data --deps-only # no test deps
|
||||||
- run: opam exec -- dune build '@install'
|
- run: opam exec -- dune build '@install'
|
||||||
- run: opam exec -- dune runtest -j 1 -p containers --profile=release # test only core on non-ubuntu platform
|
- run: opam exec -- dune runtest -j 1 -p containers --profile=release # test only core on non-ubuntu platform
|
||||||
|
|
||||||
format:
|
|
||||||
name: format
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
ocaml-compiler:
|
|
||||||
- '5.1'
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@main
|
|
||||||
- name: Use OCaml ${{ matrix.ocaml-compiler }}
|
|
||||||
uses: ocaml/setup-ocaml@v2
|
|
||||||
with:
|
|
||||||
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
|
||||||
dune-cache: true
|
|
||||||
allow-prerelease-opam: true
|
|
||||||
|
|
||||||
- run: opam install ocamlformat.0.24.1
|
|
||||||
- run: opam exec -- make format-check
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
version = 0.24.1
|
version = 0.27.0
|
||||||
profile=conventional
|
profile=conventional
|
||||||
margin=80
|
margin=80
|
||||||
if-then-else=k-r
|
if-then-else=k-r
|
||||||
|
|
@ -12,3 +12,4 @@ field-space=tight-decl
|
||||||
leading-nested-match-parens=true
|
leading-nested-match-parens=true
|
||||||
module-item-spacing=compact
|
module-item-spacing=compact
|
||||||
quiet=true
|
quiet=true
|
||||||
|
parse-docstrings=false
|
||||||
|
|
|
||||||
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -1,6 +1,17 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
## main
|
## 3.16
|
||||||
|
|
||||||
|
|
||||||
|
- breaking: Renamed predicate parameter of `take_while`, `rtake_while` from `p` to `f`, aligining it with pre-existing `drop_while`.
|
||||||
|
|
||||||
|
- feat: add `containers.leb128` library
|
||||||
|
- feat: add `CCFun.with_return`
|
||||||
|
- Added functions to the `Char` module to check common character properties.
|
||||||
|
- feat: add `CCVector.findi`
|
||||||
|
|
||||||
|
|
||||||
|
- fix: compat with OCaml 5.4
|
||||||
|
- fix: oob(!!) in CCHash.bytes
|
||||||
|
|
||||||
## 3.15
|
## 3.15
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,9 @@ module PersistentHashtbl (H : Hashtbl.HashedType) = struct
|
||||||
t := Add (k, v', t');
|
t := Add (k, v', t');
|
||||||
Table.remove tbl k;
|
Table.remove tbl k;
|
||||||
t'
|
t'
|
||||||
with Not_found -> (* not member, nothing to do *)
|
with Not_found ->
|
||||||
t
|
(* not member, nothing to do *)
|
||||||
|
t
|
||||||
|
|
||||||
(*$R
|
(*$R
|
||||||
let h = H.of_seq my_seq in
|
let h = H.of_seq my_seq in
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,14 @@ module L = struct
|
||||||
else
|
else
|
||||||
Sek.Persistent.of_list 0 [ x; x + 1; x + 2; x + 3 ]
|
Sek.Persistent.of_list 0 [ x; x + 1; x + 2; x + 3 ]
|
||||||
|
|
||||||
|
let f_pvec x =
|
||||||
|
if x mod 10 = 0 then
|
||||||
|
Pvec.empty
|
||||||
|
else if x mod 5 = 1 then
|
||||||
|
Pvec.of_list [ x; x + 1 ]
|
||||||
|
else
|
||||||
|
Pvec.of_list [ x; x + 1; x + 2; x + 3 ]
|
||||||
|
|
||||||
let flat_map_kont f l =
|
let flat_map_kont f l =
|
||||||
let rec aux f l kont =
|
let rec aux f l kont =
|
||||||
match l with
|
match l with
|
||||||
|
|
@ -118,6 +126,7 @@ module L = struct
|
||||||
let l = CCList.(1 -- n) in
|
let l = CCList.(1 -- n) in
|
||||||
let ral = CCRAL.of_list l in
|
let ral = CCRAL.of_list l in
|
||||||
let sek = Sek.Persistent.of_list 0 l in
|
let sek = Sek.Persistent.of_list 0 l in
|
||||||
|
let pvec = Pvec.of_list l in
|
||||||
let flatten_map_ l () =
|
let flatten_map_ l () =
|
||||||
ignore @@ Sys.opaque_identity @@ List.flatten (CCList.map f_ l)
|
ignore @@ Sys.opaque_identity @@ List.flatten (CCList.map f_ l)
|
||||||
and flatmap_kont l () = ignore @@ Sys.opaque_identity @@ flat_map_kont f_ l
|
and flatmap_kont l () = ignore @@ Sys.opaque_identity @@ flat_map_kont f_ l
|
||||||
|
|
@ -128,6 +137,8 @@ module L = struct
|
||||||
ignore @@ Sys.opaque_identity @@ CCRAL.flat_map f_ral_ l
|
ignore @@ Sys.opaque_identity @@ CCRAL.flat_map f_ral_ l
|
||||||
and flatmap_sek s () =
|
and flatmap_sek s () =
|
||||||
ignore @@ Sys.opaque_identity @@ Sek.Persistent.flatten_map 0 f_sek_ s
|
ignore @@ Sys.opaque_identity @@ Sek.Persistent.flatten_map 0 f_sek_ s
|
||||||
|
and flat_map_pvec v () =
|
||||||
|
ignore @@ Sys.opaque_identity @@ Pvec.flat_map f_pvec v
|
||||||
in
|
in
|
||||||
B.throughputN time ~repeat
|
B.throughputN time ~repeat
|
||||||
[
|
[
|
||||||
|
|
@ -137,6 +148,7 @@ module L = struct
|
||||||
"flatten o map", flatten_map_ l, ();
|
"flatten o map", flatten_map_ l, ();
|
||||||
"ral_flatmap", flatmap_ral_ ral, ();
|
"ral_flatmap", flatmap_ral_ ral, ();
|
||||||
"sek_flatmap", flatmap_sek sek, ();
|
"sek_flatmap", flatmap_sek sek, ();
|
||||||
|
"pvec.flatmap", flat_map_pvec pvec, ();
|
||||||
]
|
]
|
||||||
|
|
||||||
(* APPEND *)
|
(* APPEND *)
|
||||||
|
|
@ -284,7 +296,7 @@ module L = struct
|
||||||
for i = 0 to n - 1 do
|
for i = 0 to n - 1 do
|
||||||
opaque_ignore (CCRAL.set l i (-i))
|
opaque_ignore (CCRAL.set l i (-i))
|
||||||
done
|
done
|
||||||
(* TODO: implement set
|
(* TODO: implement set
|
||||||
and bench_funvec l () =
|
and bench_funvec l () =
|
||||||
for _i = 0 to n-1 do opaque_ignore (CCFun_vec.set (* TODO *)) done
|
for _i = 0 to n-1 do opaque_ignore (CCFun_vec.set (* TODO *)) done
|
||||||
*)
|
*)
|
||||||
|
|
@ -810,8 +822,8 @@ module Tbl = struct
|
||||||
end in
|
end in
|
||||||
(module T)
|
(module T)
|
||||||
|
|
||||||
let persistent_hashtbl_ref :
|
let persistent_hashtbl_ref : type a.
|
||||||
type a. a key_type -> (module MUT with type key = a) =
|
a key_type -> (module MUT with type key = a) =
|
||||||
fun key ->
|
fun key ->
|
||||||
let (module Key), name = arg_make key in
|
let (module Key), name = arg_make key in
|
||||||
let module T = Ref_impl.PersistentHashtbl (Key) in
|
let module T = Ref_impl.PersistentHashtbl (Key) in
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,8 @@ module Bitfield = struct
|
||||||
if self.emit_failure_if_too_wide then
|
if self.emit_failure_if_too_wide then
|
||||||
fpf out
|
fpf out
|
||||||
"(* check that int size is big enough *)@,\
|
"(* check that int size is big enough *)@,\
|
||||||
@[let () = assert (Sys.int_size >= %d);;@]" (total_width self);
|
@[let () = assert (Sys.int_size >= %d);;@]"
|
||||||
|
(total_width self);
|
||||||
fpf out "@]"
|
fpf out "@]"
|
||||||
|
|
||||||
let gen_mli self : code =
|
let gen_mli self : code =
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ let sort_indices cmp a =
|
||||||
Array.sort (fun k1 k2 -> cmp a.(k1) a.(k2)) b;
|
Array.sort (fun k1 k2 -> cmp a.(k1) a.(k2)) b;
|
||||||
b
|
b
|
||||||
|
|
||||||
let sort_ranking cmp a = sort_indices compare (sort_indices cmp a)
|
let sort_ranking cmp a = sort_indices CCInt.compare (sort_indices cmp a)
|
||||||
|
|
||||||
let rev a =
|
let rev a =
|
||||||
let b = Array.copy a in
|
let b = Array.copy a in
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,24 @@ let[@inline never] decr r =
|
||||||
(* atomic *)
|
(* atomic *)
|
||||||
|
|
||||||
[@@@endif]
|
[@@@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
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,12 @@ module Infix = struct
|
||||||
end
|
end
|
||||||
|
|
||||||
include Infix
|
include Infix
|
||||||
|
|
||||||
|
let is_uppercase_ascii c = c > '\064' && c < '\091'
|
||||||
|
let is_lowercase_ascii c = c > '\096' && c < '\123'
|
||||||
|
|
||||||
|
let is_letter_ascii c =
|
||||||
|
(is_lowercase_ascii [@inlined]) c || (is_uppercase_ascii [@inlined]) c
|
||||||
|
|
||||||
|
let is_digit_ascii c = c > '\047' && c < '\058'
|
||||||
|
let is_whitespace_ascii c = c = '\032' || (c > '\008' && c < '\014')
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,32 @@ val pp_buf : Buffer.t -> t -> unit
|
||||||
val pp : Format.formatter -> t -> unit
|
val pp : Format.formatter -> t -> unit
|
||||||
(** Renamed from [print] since 2.0. *)
|
(** Renamed from [print] since 2.0. *)
|
||||||
|
|
||||||
|
val is_uppercase_ascii : t -> bool
|
||||||
|
(** [is_uppercase_ascii c] is true exactly when [c] is an
|
||||||
|
uppercase ASCII character, i.e. ['\064'] < [c] < ['\091'].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
|
val is_lowercase_ascii : t -> bool
|
||||||
|
(** [is_lowercase_ascii c] is true exactly when [c] is a
|
||||||
|
lowercase ASCII character, i.e. ['\096'] < [c] < ['\123'].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
|
val is_letter_ascii : t -> bool
|
||||||
|
(** [is_letter_ascii c] is true exactly when [c] is an ASCII
|
||||||
|
letter, i.e. [is_uppercase_ascii c || is_lowercase_ascii c].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
|
val is_digit_ascii : t -> bool
|
||||||
|
(** [is_digit_ascii c] is true exactly when [c] is an
|
||||||
|
ASCII digit, i.e. ['\047'] < [c] < ['\058'].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
|
val is_whitespace_ascii : t -> bool
|
||||||
|
(** [is_whitespace_ascii c] is true exactly when [c] is an ASCII
|
||||||
|
whitespace character as defined by Unicode, i.e. either [c = ' ']
|
||||||
|
or ['\008'] < [c] < ['\014'].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
(** {2 Infix Operators}
|
(** {2 Infix Operators}
|
||||||
|
|
||||||
@since 3.3 *)
|
@since 3.3 *)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
(** Either Monad
|
(** Either Monad
|
||||||
|
|
||||||
Module that is compatible with Either form OCaml 4.12 but can be use with any
|
Module that is compatible with Either from OCaml 4.12 but can be use with any
|
||||||
ocaml version compatible with container
|
ocaml version compatible with container
|
||||||
|
|
||||||
@since 3.2
|
@since 3.2
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,13 @@ let rec iterate n f x =
|
||||||
else
|
else
|
||||||
iterate (n - 1) f (f x)
|
iterate (n - 1) f (f x)
|
||||||
|
|
||||||
|
let[@inline] with_return (type ret) f : ret =
|
||||||
|
let exception E of ret in
|
||||||
|
let return x = raise_notrace (E x) in
|
||||||
|
match f return with
|
||||||
|
| res -> res
|
||||||
|
| exception E res -> res
|
||||||
|
|
||||||
module Infix = struct
|
module Infix = struct
|
||||||
(* default implem for some operators *)
|
(* default implem for some operators *)
|
||||||
let ( %> ) = compose
|
let ( %> ) = compose
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,22 @@ val iterate : int -> ('a -> 'a) -> 'a -> 'a
|
||||||
[x], [iterate 1 f x] is [f x], [iterate 2 f x] is [f (f x)], etc.
|
[x], [iterate 1 f x] is [f x], [iterate 2 f x] is [f (f x)], etc.
|
||||||
@since 2.1 *)
|
@since 2.1 *)
|
||||||
|
|
||||||
|
val with_return : (('ret -> 'a) -> 'ret) -> 'ret
|
||||||
|
(** [with_return f] is [f return], where [return] is a function
|
||||||
|
that can be invoked to exit the scope early.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
{[
|
||||||
|
let find_array arr x =
|
||||||
|
let@ return = with_return in
|
||||||
|
for i = 0 to Array.length arr-1 do
|
||||||
|
if arr.(i) = x then return i;
|
||||||
|
done;
|
||||||
|
-1
|
||||||
|
]}
|
||||||
|
|
||||||
|
@since 3.15 *)
|
||||||
|
|
||||||
(** {2 Infix}
|
(** {2 Infix}
|
||||||
|
|
||||||
Infix operators. *)
|
Infix operators. *)
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,9 @@ let int = hash_int_
|
||||||
let bool b =
|
let bool b =
|
||||||
hash_int_
|
hash_int_
|
||||||
(if b then
|
(if b then
|
||||||
1
|
1
|
||||||
else
|
else
|
||||||
2)
|
2)
|
||||||
|
|
||||||
let char x = hash_int_ (Char.code x)
|
let char x = hash_int_ (Char.code x)
|
||||||
|
|
||||||
|
|
@ -101,7 +101,7 @@ let max_len_b_ = 128
|
||||||
|
|
||||||
let bytes (x : bytes) =
|
let bytes (x : bytes) =
|
||||||
let h = ref fnv_offset_basis in
|
let h = ref fnv_offset_basis in
|
||||||
for i = 0 to min max_len_b_ (Bytes.length x) do
|
for i = 0 to min max_len_b_ (Bytes.length x - 1) do
|
||||||
(h := Int64.(mul !h fnv_prime));
|
(h := Int64.(mul !h fnv_prime));
|
||||||
let byte = Char.code (Bytes.unsafe_get x i) in
|
let byte = Char.code (Bytes.unsafe_get x i) in
|
||||||
h := Int64.(logxor !h (of_int byte))
|
h := Int64.(logxor !h (of_int byte))
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ val partition_map :
|
||||||
('a -> [< `Left of 'b | `Right of 'c | `Drop ]) ->
|
('a -> [< `Left of 'b | `Right of 'c | `Drop ]) ->
|
||||||
'a list ->
|
'a list ->
|
||||||
'b list * 'c list
|
'b list * 'c list
|
||||||
[@@ocaml.deprecated "use CCList.partition_filter_map instead"]
|
[@@ocaml.deprecated "use CCList.partition_filter_map instead"]
|
||||||
(** @deprecated use {!partition_filter_map} instead
|
(** @deprecated use {!partition_filter_map} instead
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
||||||
|
|
@ -384,7 +384,7 @@ val mguard : bool -> unit t
|
||||||
@since 3.1 *)
|
@since 3.1 *)
|
||||||
|
|
||||||
val return : 'a -> 'a t
|
val return : 'a -> 'a t
|
||||||
(** [return x] is [x]. *)
|
(** [return x] is [[x]]. *)
|
||||||
|
|
||||||
val take : int -> 'a t -> 'a t
|
val take : int -> 'a t -> 'a t
|
||||||
(** [take n l] takes the [n] first elements of the list [l], drop the rest. *)
|
(** [take n l] takes the [n] first elements of the list [l], drop the rest. *)
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ val partition_map :
|
||||||
f:('a -> [< `Left of 'b | `Right of 'c | `Drop ]) ->
|
f:('a -> [< `Left of 'b | `Right of 'c | `Drop ]) ->
|
||||||
'a list ->
|
'a list ->
|
||||||
'b list * 'c list
|
'b list * 'c list
|
||||||
[@@ocaml.deprecated "use CCList.partition_filter_map instead"]
|
[@@ocaml.deprecated "use CCList.partition_filter_map instead"]
|
||||||
(** @deprecated use {!partition_filter_map} instead *)
|
(** @deprecated use {!partition_filter_map} instead *)
|
||||||
|
|
||||||
val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t
|
val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ val value : 'a t -> default:'a -> 'a
|
||||||
@since 2.8 *)
|
@since 2.8 *)
|
||||||
|
|
||||||
val get_exn : 'a t -> 'a
|
val get_exn : 'a t -> 'a
|
||||||
[@@ocaml.deprecated "use CCOption.get_exn_or instead"]
|
[@@ocaml.deprecated "use CCOption.get_exn_or instead"]
|
||||||
(** [get_exn o] returns [x] if [o] is [Some x] or fails if [o] is [None].
|
(** [get_exn o] returns [x] if [o] is [Some x] or fails if [o] is [None].
|
||||||
@raise Invalid_argument if the option is [None].
|
@raise Invalid_argument if the option is [None].
|
||||||
@deprecated use {!get_exn_or} instead
|
@deprecated use {!get_exn_or} instead
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ val poly : 'a t
|
||||||
@since 3.6 *)
|
@since 3.6 *)
|
||||||
|
|
||||||
val compare : 'a t
|
val compare : 'a t
|
||||||
[@@deprecated "use CCOrd.poly instead, this name is too general"]
|
[@@deprecated "use CCOrd.poly instead, this name is too general"]
|
||||||
(** Polymorphic "magic" comparison.
|
(** Polymorphic "magic" comparison.
|
||||||
@deprecated since 3.6 in favor of {!poly}. The reason is that
|
@deprecated since 3.6 in favor of {!poly}. The reason is that
|
||||||
[compare] is easily shadowed, can shadow other comparators, and is just
|
[compare] is easily shadowed, can shadow other comparators, and is just
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,7 @@ val optional : _ t -> unit t
|
||||||
@since 3.6 *)
|
@since 3.6 *)
|
||||||
|
|
||||||
val try_ : 'a t -> 'a t
|
val try_ : 'a t -> 'a t
|
||||||
[@@deprecated "plays no role anymore, just replace [try foo] with [foo]"]
|
[@@deprecated "plays no role anymore, just replace [try foo] with [foo]"]
|
||||||
(** [try_ p] is just like [p] (it used to play a role in backtracking
|
(** [try_ p] is just like [p] (it used to play a role in backtracking
|
||||||
semantics but no more).
|
semantics but no more).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ val ( -- ) : int -> int -> int t
|
||||||
[a] and [b] (therefore, never empty). *)
|
[a] and [b] (therefore, never empty). *)
|
||||||
|
|
||||||
val ( --^ ) : int -> int -> int t
|
val ( --^ ) : int -> int -> int t
|
||||||
(** [a -- b] is the integer range from [a] to [b], where [b] is excluded. *)
|
(** [a --^ b] is the integer range from [a] to [b], where [b] is excluded. *)
|
||||||
|
|
||||||
(** {2 Operations on two Collections} *)
|
(** {2 Operations on two Collections} *)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -585,6 +585,24 @@ let take n s =
|
||||||
else
|
else
|
||||||
s
|
s
|
||||||
|
|
||||||
|
let take_while f s =
|
||||||
|
let i = ref 0 in
|
||||||
|
while !i < String.length s && f (String.unsafe_get s !i) do
|
||||||
|
incr i
|
||||||
|
done;
|
||||||
|
String.sub s 0 !i
|
||||||
|
|
||||||
|
let rtake_while f s =
|
||||||
|
let s_len_pred = String.length s - 1 in
|
||||||
|
let i = ref s_len_pred in
|
||||||
|
while !i >= 0 && f (String.unsafe_get s !i) do
|
||||||
|
decr i
|
||||||
|
done;
|
||||||
|
if !i < s_len_pred then
|
||||||
|
String.sub s (!i + 1) (s_len_pred - !i)
|
||||||
|
else
|
||||||
|
""
|
||||||
|
|
||||||
let drop n s =
|
let drop n s =
|
||||||
if n < String.length s then
|
if n < String.length s then
|
||||||
String.sub s n (String.length s - n)
|
String.sub s n (String.length s - n)
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,16 @@ val take : int -> string -> string
|
||||||
(** [take n s] keeps only the [n] first chars of [s].
|
(** [take n s] keeps only the [n] first chars of [s].
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val take_while : (char -> bool) -> string -> string
|
||||||
|
(** [take_while f s] keeps only the longest prefix [t] of [s] such that every
|
||||||
|
character [c] in [t] satisfies [f c].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
|
val rtake_while : (char -> bool) -> string -> string
|
||||||
|
(** [rtake_while f s] keeps only the longest suffix [t] of [s] such that every
|
||||||
|
character [c] in [t] satisfies [f c].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
val drop : int -> string -> string
|
val drop : int -> string -> string
|
||||||
(** [drop n s] removes the [n] first chars of [s].
|
(** [drop n s] removes the [n] first chars of [s].
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,16 @@ val take : int -> string -> string
|
||||||
(** [take n s] keeps only the [n] first chars of [s].
|
(** [take n s] keeps only the [n] first chars of [s].
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val take_while : f:(char -> bool) -> string -> string
|
||||||
|
(** [take_while ~f s] keeps only the longest prefix [t] of [s] such that every
|
||||||
|
character [c] in [t] satisfies [f c].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
|
val rtake_while : f:(char -> bool) -> string -> string
|
||||||
|
(** [rtake_while ~f s] keeps only the longest suffix [t] of [s] such that every
|
||||||
|
character [c] in [t] satisfies [f c].
|
||||||
|
@since 3.16 *)
|
||||||
|
|
||||||
val drop : int -> string -> string
|
val drop : int -> string -> string
|
||||||
(** [drop n s] removes the [n] first chars of [s].
|
(** [drop n s] removes the [n] first chars of [s].
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,10 @@ let next_ (type a) (st : Dec.t) ~(yield : uchar -> a) ~(stop : unit -> a) () : a
|
||||||
(* except for first, each char gives 6 bits *)
|
(* except for first, each char gives 6 bits *)
|
||||||
let next = (acc lsl 6) lor (c land 0b111111) in
|
let next = (acc lsl 6) lor (c land 0b111111) in
|
||||||
if j = n_bytes then
|
if j = n_bytes then
|
||||||
if (* done reading the codepoint *)
|
if
|
||||||
Uchar.is_valid next then (
|
(* done reading the codepoint *)
|
||||||
|
Uchar.is_valid next
|
||||||
|
then (
|
||||||
st.i <- st.i + j + 1;
|
st.i <- st.i + j + 1;
|
||||||
(* +1 for first char *)
|
(* +1 for first char *)
|
||||||
yield (Uchar.unsafe_of_int next)
|
yield (Uchar.unsafe_of_int next)
|
||||||
|
|
|
||||||
|
|
@ -475,7 +475,7 @@ let for_all p v =
|
||||||
|
|
||||||
let member ~eq x v = exists (eq x) v
|
let member ~eq x v = exists (eq x) v
|
||||||
|
|
||||||
let find_internal_ p v =
|
let find_internal_i_ p v =
|
||||||
let n = v.size in
|
let n = v.size in
|
||||||
let rec check i =
|
let rec check i =
|
||||||
if i = n then
|
if i = n then
|
||||||
|
|
@ -483,15 +483,18 @@ let find_internal_ p v =
|
||||||
else (
|
else (
|
||||||
let x = v.vec.(i) in
|
let x = v.vec.(i) in
|
||||||
if p x then
|
if p x then
|
||||||
x
|
i, x
|
||||||
else
|
else
|
||||||
check (i + 1)
|
check (i + 1)
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
check 0
|
check 0
|
||||||
|
|
||||||
let find_exn p v = try find_internal_ p v with Not_found -> raise Not_found
|
let find_exn p v =
|
||||||
let find p v = try Some (find_internal_ p v) with Not_found -> None
|
try snd (find_internal_i_ p v) with Not_found -> raise Not_found
|
||||||
|
|
||||||
|
let find p v = try Some (snd @@ find_internal_i_ p v) with Not_found -> None
|
||||||
|
let findi p v = try Some (find_internal_i_ p v) with Not_found -> None
|
||||||
|
|
||||||
let find_map f v =
|
let find_map f v =
|
||||||
let n = v.size in
|
let n = v.size in
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,10 @@ val for_all : ('a -> bool) -> ('a, _) t -> bool
|
||||||
val find : ('a -> bool) -> ('a, _) t -> 'a option
|
val find : ('a -> bool) -> ('a, _) t -> 'a option
|
||||||
(** Find an element that satisfies the predicate. *)
|
(** Find an element that satisfies the predicate. *)
|
||||||
|
|
||||||
|
val findi : ('a -> bool) -> ('a, _) t -> (int * 'a) option
|
||||||
|
(** Find an element and its index that satisfies the predicate.
|
||||||
|
@since 3.15 *)
|
||||||
|
|
||||||
val find_exn : ('a -> bool) -> ('a, _) t -> 'a
|
val find_exn : ('a -> bool) -> ('a, _) t -> 'a
|
||||||
(** Find an element that satisfies the predicate, or
|
(** Find an element that satisfies the predicate, or
|
||||||
@raise Not_found if no element does. *)
|
@raise Not_found if no element does. *)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
(action
|
(action
|
||||||
(run %{project_root}/src/core/cpp/cpp.exe %{input-file})))
|
(run %{project_root}/src/core/cpp/cpp.exe %{input-file})))
|
||||||
(flags :standard -nolabels -open CCMonomorphic)
|
(flags :standard -nolabels -open CCMonomorphic)
|
||||||
(libraries either containers.monomorphic))
|
(libraries either containers.monomorphic containers.domain))
|
||||||
|
|
||||||
(ocamllex
|
(ocamllex
|
||||||
(modules CCSexp_lex))
|
(modules CCSexp_lex))
|
||||||
|
|
|
||||||
|
|
@ -407,9 +407,9 @@ let pp out bv =
|
||||||
iter bv (fun _i b ->
|
iter bv (fun _i b ->
|
||||||
Format.pp_print_char out
|
Format.pp_print_char out
|
||||||
(if b then
|
(if b then
|
||||||
'1'
|
'1'
|
||||||
else
|
else
|
||||||
'0'));
|
'0'));
|
||||||
Format.pp_print_string out "}"
|
Format.pp_print_string out "}"
|
||||||
|
|
||||||
module Internal_ = struct
|
module Internal_ = struct
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,7 @@ let _empty = Shallow Zero
|
||||||
let _single x = Shallow (One x)
|
let _single x = Shallow (One x)
|
||||||
let _double x y = Shallow (Two (x, y))
|
let _double x y = Shallow (Two (x, y))
|
||||||
|
|
||||||
let _deep :
|
let _deep : type l0 l1.
|
||||||
type l0 l1.
|
|
||||||
int ->
|
int ->
|
||||||
('a, l0 succ) digit ->
|
('a, l0 succ) digit ->
|
||||||
('a * 'a) t lazy_t ->
|
('a * 'a) t lazy_t ->
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ val ( -- ) : int -> int -> int t
|
||||||
@since 0.10 *)
|
@since 0.10 *)
|
||||||
|
|
||||||
val ( --^ ) : int -> int -> int t
|
val ( --^ ) : int -> int -> int t
|
||||||
(** [a -- b] is the integer range from [a] to [b], where [b] is excluded.
|
(** [a --^ b] is the integer range from [a] to [b], where [b] is excluded.
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
||||||
val pp : 'a printer -> 'a t printer
|
val pp : 'a printer -> 'a t printer
|
||||||
|
|
|
||||||
|
|
@ -221,8 +221,7 @@ module Traverse = struct
|
||||||
]
|
]
|
||||||
|
|
||||||
type ('v, 'e) t =
|
type ('v, 'e) t =
|
||||||
[ `Enter of
|
[ `Enter of 'v * int * ('v, 'e) path
|
||||||
'v * int * ('v, 'e) path
|
|
||||||
(* unique index in traversal, path from start *)
|
(* unique index in traversal, path from start *)
|
||||||
| `Exit of 'v
|
| `Exit of 'v
|
||||||
| `Edge of 'v * 'e * 'v * edge_kind
|
| `Edge of 'v * 'e * 'v * edge_kind
|
||||||
|
|
|
||||||
|
|
@ -150,8 +150,7 @@ module Traverse : sig
|
||||||
]
|
]
|
||||||
|
|
||||||
type ('v, 'e) t =
|
type ('v, 'e) t =
|
||||||
[ `Enter of
|
[ `Enter of 'v * int * ('v, 'e) path
|
||||||
'v * int * ('v, 'e) path
|
|
||||||
(* unique index in traversal, path from start *)
|
(* unique index in traversal, path from start *)
|
||||||
| `Exit of 'v
|
| `Exit of 'v
|
||||||
| `Edge of 'v * 'e * 'v * edge_kind
|
| `Edge of 'v * 'e * 'v * edge_kind
|
||||||
|
|
|
||||||
|
|
@ -199,11 +199,13 @@ module A_SPARSE = struct
|
||||||
arr.(real_idx) <- x;
|
arr.(real_idx) <- x;
|
||||||
if real_idx > 0 then Array.blit a.arr 0 arr 0 real_idx;
|
if real_idx > 0 then Array.blit a.arr 0 arr 0 real_idx;
|
||||||
(if real_idx < n then
|
(if real_idx < n then
|
||||||
let open Stdlib in
|
let open Stdlib in
|
||||||
Array.blit a.arr real_idx arr (real_idx + 1) (n - real_idx));
|
Array.blit a.arr real_idx arr (real_idx + 1) (n - real_idx));
|
||||||
{ a with bits; arr }
|
{ a with bits; arr }
|
||||||
) else if (* replace element at [real_idx] *)
|
) else if
|
||||||
mut then (
|
(* replace element at [real_idx] *)
|
||||||
|
mut
|
||||||
|
then (
|
||||||
a.arr.(real_idx) <- x;
|
a.arr.(real_idx) <- x;
|
||||||
a
|
a
|
||||||
) else (
|
) else (
|
||||||
|
|
@ -230,8 +232,8 @@ module A_SPARSE = struct
|
||||||
let arr = Array.make Stdlib.(n + 1) x in
|
let arr = Array.make Stdlib.(n + 1) x in
|
||||||
if real_idx > 0 then Array.blit a.arr 0 arr 0 real_idx;
|
if real_idx > 0 then Array.blit a.arr 0 arr 0 real_idx;
|
||||||
(if real_idx < n then
|
(if real_idx < n then
|
||||||
let open Stdlib in
|
let open Stdlib in
|
||||||
Array.blit a.arr real_idx arr (real_idx + 1) (n - real_idx));
|
Array.blit a.arr real_idx arr (real_idx + 1) (n - real_idx));
|
||||||
{ a with bits; arr }
|
{ a with bits; arr }
|
||||||
) else (
|
) else (
|
||||||
let x = f a.arr.(real_idx) in
|
let x = f a.arr.(real_idx) in
|
||||||
|
|
|
||||||
|
|
@ -66,11 +66,10 @@ let rec cut_depth n t () =
|
||||||
(** {2 Graph Traversals} *)
|
(** {2 Graph Traversals} *)
|
||||||
|
|
||||||
(** Abstract Set structure *)
|
(** Abstract Set structure *)
|
||||||
class type ['a] pset =
|
class type ['a] pset = object
|
||||||
object
|
method add : 'a -> 'a pset
|
||||||
method add : 'a -> 'a pset
|
method mem : 'a -> bool
|
||||||
method mem : 'a -> bool
|
end
|
||||||
end
|
|
||||||
|
|
||||||
let set_of_cmp (type elt) ~cmp () =
|
let set_of_cmp (type elt) ~cmp () =
|
||||||
let module S = Set.Make (struct
|
let module S = Set.Make (struct
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,10 @@ val cut_depth : int -> 'a t -> 'a t
|
||||||
(** {2 Graph Traversals} *)
|
(** {2 Graph Traversals} *)
|
||||||
|
|
||||||
(** Abstract Set structure *)
|
(** Abstract Set structure *)
|
||||||
class type ['a] pset =
|
class type ['a] pset = object
|
||||||
object
|
method add : 'a -> 'a pset
|
||||||
method add : 'a -> 'a pset
|
method mem : 'a -> bool
|
||||||
method mem : 'a -> bool
|
end
|
||||||
end
|
|
||||||
|
|
||||||
val set_of_cmp : cmp:('a -> 'a -> int) -> unit -> 'a pset
|
val set_of_cmp : cmp:('a -> 'a -> int) -> unit -> 'a pset
|
||||||
(** Build a set structure given a total ordering. *)
|
(** Build a set structure given a total ordering. *)
|
||||||
|
|
|
||||||
|
|
@ -295,9 +295,9 @@ module Make (H : HashedType) : S with type key = H.t = struct
|
||||||
{
|
{
|
||||||
length =
|
length =
|
||||||
(if is_new then
|
(if is_new then
|
||||||
t.length + 1
|
t.length + 1
|
||||||
else
|
else
|
||||||
t.length);
|
t.length);
|
||||||
arr = Arr a;
|
arr = Arr a;
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
|
|
|
||||||
|
|
@ -225,12 +225,12 @@ module Make (W : WORD) : S with type char_ = W.char_ and type key = W.t = struct
|
||||||
let rebuild' new_child =
|
let rebuild' new_child =
|
||||||
rebuild
|
rebuild
|
||||||
(if is_empty new_child then
|
(if is_empty new_child then
|
||||||
t
|
t
|
||||||
else (
|
else (
|
||||||
let map = M.singleton c new_child in
|
let map = M.singleton c new_child in
|
||||||
let map = M.add c' t' map in
|
let map = M.add c' t' map in
|
||||||
_mk_node None map
|
_mk_node None map
|
||||||
))
|
))
|
||||||
in
|
in
|
||||||
empty, rebuild'
|
empty, rebuild'
|
||||||
)
|
)
|
||||||
|
|
@ -242,9 +242,9 @@ module Make (W : WORD) : S with type char_ = W.char_ and type key = W.t = struct
|
||||||
let rebuild' new_child =
|
let rebuild' new_child =
|
||||||
rebuild
|
rebuild
|
||||||
(if is_empty new_child then
|
(if is_empty new_child then
|
||||||
_mk_node value (M.remove c map)
|
_mk_node value (M.remove c map)
|
||||||
else
|
else
|
||||||
_mk_node value (M.add c new_child map))
|
_mk_node value (M.add c new_child map))
|
||||||
in
|
in
|
||||||
t', rebuild'
|
t', rebuild'
|
||||||
with Not_found ->
|
with Not_found ->
|
||||||
|
|
|
||||||
7
src/domain/containers_domain.mli
Normal file
7
src/domain/containers_domain.mli
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
(** A partial stub for {!Domain}. *)
|
||||||
|
|
||||||
|
val is_main_domain : unit -> bool
|
||||||
|
val cpu_relax : unit -> unit
|
||||||
|
|
||||||
|
val relax_loop : int -> unit
|
||||||
|
(** Call {!cpu_relax} n times *)
|
||||||
14
src/domain/dune
Normal file
14
src/domain/dune
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
(library
|
||||||
|
(name containers_domain)
|
||||||
|
(synopsis "Compatibility library for the Domain module")
|
||||||
|
(public_name containers.domain)
|
||||||
|
(modules containers_domain))
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(modules gen)
|
||||||
|
(name gen))
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets containers_domain.ml)
|
||||||
|
(action
|
||||||
|
(run ./gen.exe)))
|
||||||
28
src/domain/gen.ml
Normal file
28
src/domain/gen.ml
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
let domain_4 =
|
||||||
|
{|
|
||||||
|
let is_main_domain () = true
|
||||||
|
let cpu_relax = ignore
|
||||||
|
let relax_loop : int -> unit = ignore
|
||||||
|
|}
|
||||||
|
|
||||||
|
let domain_5 =
|
||||||
|
{|
|
||||||
|
let is_main_domain = Domain.is_main_domain
|
||||||
|
let cpu_relax = Domain.cpu_relax
|
||||||
|
let relax_loop i =
|
||||||
|
for _j = 1 to i do cpu_relax () done
|
||||||
|
|}
|
||||||
|
|
||||||
|
let write_file file s =
|
||||||
|
let oc = open_out file in
|
||||||
|
output_string oc s;
|
||||||
|
close_out oc
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let version = Scanf.sscanf Sys.ocaml_version "%d.%d.%s" (fun x y _ -> x, y) in
|
||||||
|
write_file "containers_domain.ml"
|
||||||
|
(if version >= (5, 0) then
|
||||||
|
domain_5
|
||||||
|
else
|
||||||
|
domain_4);
|
||||||
|
()
|
||||||
98
src/leb128/containers_leb128.ml
Normal file
98
src/leb128/containers_leb128.ml
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
(* adapted from ocaml-protoc from code by c-cube *)
|
||||||
|
|
||||||
|
module Byte_slice = CCByte_slice
|
||||||
|
module Byte_buffer = CCByte_buffer
|
||||||
|
|
||||||
|
module Decode = struct
|
||||||
|
let skip (sl : Byte_slice.t) off : int =
|
||||||
|
let shift = ref 0 in
|
||||||
|
let continue = ref true in
|
||||||
|
|
||||||
|
let off = ref off in
|
||||||
|
let n_consumed = ref 0 in
|
||||||
|
|
||||||
|
while !continue do
|
||||||
|
if sl.len <= 0 then invalid_arg "out of bound";
|
||||||
|
incr n_consumed;
|
||||||
|
let b = Char.code (Bytes.get sl.bs !off) in
|
||||||
|
let cur = b land 0x7f in
|
||||||
|
if cur <> b then (
|
||||||
|
(* at least one byte follows this one *)
|
||||||
|
incr off;
|
||||||
|
shift := !shift + 7
|
||||||
|
) else if !shift < 63 || b land 0x7f <= 1 then
|
||||||
|
continue := false
|
||||||
|
else
|
||||||
|
invalid_arg "leb128 varint is too long"
|
||||||
|
done;
|
||||||
|
|
||||||
|
!n_consumed
|
||||||
|
|
||||||
|
let u64 (sl : Byte_slice.t) (off : int) : int64 * int =
|
||||||
|
let shift = ref 0 in
|
||||||
|
let res = ref 0L in
|
||||||
|
let continue = ref true in
|
||||||
|
|
||||||
|
let off = ref off in
|
||||||
|
let n_consumed = ref 0 in
|
||||||
|
|
||||||
|
while !continue do
|
||||||
|
if sl.len <= 0 then invalid_arg "out of bound";
|
||||||
|
incr n_consumed;
|
||||||
|
let b = Char.code (Bytes.get sl.bs !off) in
|
||||||
|
let cur = b land 0x7f in
|
||||||
|
if cur <> b then (
|
||||||
|
(* at least one byte follows this one *)
|
||||||
|
(res := Int64.(logor !res (shift_left (of_int cur) !shift)));
|
||||||
|
incr off;
|
||||||
|
shift := !shift + 7
|
||||||
|
) else if !shift < 63 || b land 0x7f <= 1 then (
|
||||||
|
(res := Int64.(logor !res (shift_left (of_int b) !shift)));
|
||||||
|
continue := false
|
||||||
|
) else
|
||||||
|
invalid_arg "leb128 varint is too long"
|
||||||
|
done;
|
||||||
|
|
||||||
|
!res, !n_consumed
|
||||||
|
|
||||||
|
let[@inline] uint_truncate sl off =
|
||||||
|
let v, n_consumed = u64 sl off in
|
||||||
|
Int64.to_int v, n_consumed
|
||||||
|
|
||||||
|
let[@inline] decode_zigzag (v : int64) : int64 =
|
||||||
|
Int64.(logxor (shift_right v 1) (neg (logand v Int64.one)))
|
||||||
|
|
||||||
|
let[@inline] i64 sl off : int64 * int =
|
||||||
|
let v, n_consumed = u64 sl off in
|
||||||
|
decode_zigzag v, n_consumed
|
||||||
|
|
||||||
|
let[@inline] int_truncate sl off =
|
||||||
|
let v, n_consumed = u64 sl off in
|
||||||
|
Int64.to_int (decode_zigzag v), n_consumed
|
||||||
|
end
|
||||||
|
|
||||||
|
module Encode = struct
|
||||||
|
let[@inline] encode_zigzag (i : int64) : int64 =
|
||||||
|
Int64.(logxor (shift_left i 1) (shift_right i 63))
|
||||||
|
|
||||||
|
external varint_size : (int64[@unboxed]) -> int
|
||||||
|
= "caml_cc_leb128_varint_size_byte" "caml_cc_leb128_varint_size"
|
||||||
|
[@@noalloc]
|
||||||
|
(** Compute how many bytes this int would occupy as varint *)
|
||||||
|
|
||||||
|
external varint_slice : bytes -> (int[@untagged]) -> (int64[@unboxed]) -> unit
|
||||||
|
= "caml_cc_leb128_varint_byte" "caml_cc_leb128_varint"
|
||||||
|
[@@noalloc]
|
||||||
|
(** Write this int as varint into the given slice *)
|
||||||
|
|
||||||
|
let[@inline] u64 (buf : Byte_buffer.t) (i : int64) =
|
||||||
|
let n = varint_size i in
|
||||||
|
Byte_buffer.ensure_free buf n;
|
||||||
|
assert (buf.len + n <= Bytes.length buf.bs);
|
||||||
|
varint_slice buf.bs buf.len i;
|
||||||
|
buf.len <- buf.len + n
|
||||||
|
|
||||||
|
let[@inline] i64 buf i : unit = u64 buf (encode_zigzag i)
|
||||||
|
let[@inline] uint buf i : unit = u64 buf (Int64.of_int i)
|
||||||
|
let[@inline] int buf i : unit = u64 buf (encode_zigzag (Int64.of_int i))
|
||||||
|
end
|
||||||
49
src/leb128/containers_leb128.mli
Normal file
49
src/leb128/containers_leb128.mli
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
(** LEB128 encoding and decoding.
|
||||||
|
|
||||||
|
See https://en.wikipedia.org/wiki/LEB128 . *)
|
||||||
|
|
||||||
|
module Byte_slice = CCByte_slice
|
||||||
|
module Byte_buffer = CCByte_buffer
|
||||||
|
|
||||||
|
module Decode : sig
|
||||||
|
val decode_zigzag : int64 -> int64
|
||||||
|
(** Turn an unsigned integer into a signed one.
|
||||||
|
|
||||||
|
See https://en.wikipedia.org/wiki/Variable-length_quantity#Zigzag_encoding
|
||||||
|
*)
|
||||||
|
|
||||||
|
val skip : Byte_slice.t -> int -> int
|
||||||
|
(** [skip slice off] reads an integer at offset [off], and returns how many
|
||||||
|
bytes the integer occupies. *)
|
||||||
|
|
||||||
|
val u64 : Byte_slice.t -> int -> int64 * int
|
||||||
|
(** [u64 slice off] reads an integer at offset [off], and returns a pair
|
||||||
|
[v, n_consumed]. [v] is the read integer, [n_consumed] is the number of
|
||||||
|
bytes consumed during reading. *)
|
||||||
|
|
||||||
|
val i64 : Byte_slice.t -> int -> int64 * int
|
||||||
|
(** Read a signed int64 by reading a u64 and zigzag decoding it *)
|
||||||
|
|
||||||
|
val int_truncate : Byte_slice.t -> int -> int * int
|
||||||
|
(** Like {!i64} but truncates to integer. Returns a pair [v, n_consumed]. *)
|
||||||
|
|
||||||
|
val uint_truncate : Byte_slice.t -> int -> int * int
|
||||||
|
(** Like {!u64} but truncates to integer. *)
|
||||||
|
end
|
||||||
|
|
||||||
|
module Encode : sig
|
||||||
|
val encode_zigzag : int64 -> int64
|
||||||
|
(** Turn a signed int64 into a u64 via zigzag encoding. *)
|
||||||
|
|
||||||
|
val u64 : Byte_buffer.t -> int64 -> unit
|
||||||
|
(** Write a unsigned int *)
|
||||||
|
|
||||||
|
val i64 : Byte_buffer.t -> int64 -> unit
|
||||||
|
(** Write a signed int via zigzag encoding *)
|
||||||
|
|
||||||
|
val uint : Byte_buffer.t -> int -> unit
|
||||||
|
(** Turn an uint into a u64 and write it *)
|
||||||
|
|
||||||
|
val int : Byte_buffer.t -> int -> unit
|
||||||
|
(** Turn an int into a int64 and write it *)
|
||||||
|
end
|
||||||
11
src/leb128/dune
Normal file
11
src/leb128/dune
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
(library
|
||||||
|
(name containers_leb128)
|
||||||
|
(public_name containers.leb128)
|
||||||
|
(synopsis
|
||||||
|
"LEB128 encoding (https://en.wikipedia.org/wiki/LEB128) for cephalopod")
|
||||||
|
(libraries containers)
|
||||||
|
(foreign_stubs
|
||||||
|
(language c)
|
||||||
|
(flags :standard -std=c99 -O2)
|
||||||
|
(names stubs))
|
||||||
|
(ocamlopt_flags :standard -inline 100))
|
||||||
73
src/leb128/stubs.c
Normal file
73
src/leb128/stubs.c
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
|
||||||
|
// readapted from ocaml-protoc, original code also from c-cube
|
||||||
|
|
||||||
|
#include <caml/alloc.h>
|
||||||
|
#include <caml/memory.h>
|
||||||
|
#include <caml/mlvalues.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static inline int ix_leb128_varint_size(uint64_t i) {
|
||||||
|
/* generated with:
|
||||||
|
for i in range(1,10):
|
||||||
|
ceiling = (1 << (i*7))-1
|
||||||
|
print(f'if (i <= {ceiling}L) return {i};')
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (i <= 127L) return 1;
|
||||||
|
if (i <= 16383L) return 2;
|
||||||
|
if (i <= 2097151L) return 3;
|
||||||
|
if (i <= 268435455L) return 4;
|
||||||
|
if (i <= 34359738367L) return 5;
|
||||||
|
if (i <= 4398046511103L) return 6;
|
||||||
|
if (i <= 562949953421311L) return 7;
|
||||||
|
if (i <= 72057594037927935L) return 8;
|
||||||
|
if (i <= 9223372036854775807L) return 9;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of bytes for i
|
||||||
|
CAMLprim value caml_cc_leb128_varint_size(int64_t i) {
|
||||||
|
int res = ix_leb128_varint_size(i);
|
||||||
|
return Val_int(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// boxed version, for bytecode
|
||||||
|
CAMLprim value caml_cc_leb128_varint_size_byte(value v_i) {
|
||||||
|
CAMLparam1(v_i);
|
||||||
|
|
||||||
|
int64_t i = Int64_val(v_i);
|
||||||
|
int res = ix_leb128_varint_size(i);
|
||||||
|
CAMLreturn(Val_int(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
// write i at str[idx…] in varint
|
||||||
|
static inline void ix_leb128_varint(unsigned char *str, uint64_t i) {
|
||||||
|
while (true) {
|
||||||
|
uint64_t cur = i & 0x7f;
|
||||||
|
if (cur == i) {
|
||||||
|
*str = (unsigned char)cur;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*str = (unsigned char)(cur | 0x80);
|
||||||
|
i = i >> 7;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write `i` starting at `idx`
|
||||||
|
CAMLprim value caml_cc_leb128_varint(value _str, intnat idx, int64_t i) {
|
||||||
|
unsigned char *str = Bytes_val(_str);
|
||||||
|
ix_leb128_varint(str + idx, i);
|
||||||
|
return Val_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAMLprim value caml_cc_leb128_varint_byte(value _str, value _idx, value _i) {
|
||||||
|
CAMLparam3(_str, _idx, _i);
|
||||||
|
unsigned char *str = Bytes_val(_str);
|
||||||
|
int idx = Int_val(_idx);
|
||||||
|
int64_t i = Int64_val(_i);
|
||||||
|
ix_leb128_varint(str + idx, i);
|
||||||
|
CAMLreturn(Val_unit);
|
||||||
|
}
|
||||||
|
|
@ -37,9 +37,8 @@ val ( >=. ) : float -> float -> bool
|
||||||
(** {2 Shadow Dangerous Operators} *)
|
(** {2 Shadow Dangerous Operators} *)
|
||||||
|
|
||||||
val ( == ) : [ `Consider_using_CCEqual_physical ]
|
val ( == ) : [ `Consider_using_CCEqual_physical ]
|
||||||
[@@ocaml.deprecated "Please use CCEqual.physical or Stdlib.(==) instead."]
|
[@@ocaml.deprecated "Please use CCEqual.physical or Stdlib.(==) instead."]
|
||||||
|
|
||||||
val ( != ) : [ `Consider_using_CCEqual_physical ]
|
val ( != ) : [ `Consider_using_CCEqual_physical ]
|
||||||
[@@ocaml.deprecated
|
[@@ocaml.deprecated "Please use [not CCEqual.physical] or Stdlib.(!=) instead."]
|
||||||
"Please use [not CCEqual.physical] or Stdlib.(!=) instead."]
|
|
||||||
(** @since 2.1 *)
|
(** @since 2.1 *)
|
||||||
|
|
|
||||||
|
|
@ -455,9 +455,9 @@ let of_seq ?(sep = nil) f seq : t =
|
||||||
| Seq.Cons (x, tl) ->
|
| Seq.Cons (x, tl) ->
|
||||||
let x = f x in
|
let x = f x in
|
||||||
(if first then
|
(if first then
|
||||||
x
|
x
|
||||||
else
|
else
|
||||||
sep ^ x)
|
sep ^ x)
|
||||||
^ loop false tl
|
^ loop false tl
|
||||||
in
|
in
|
||||||
loop true seq
|
loop true seq
|
||||||
|
|
|
||||||
|
|
@ -352,6 +352,8 @@ let append a b =
|
||||||
else
|
else
|
||||||
fold_left push a b
|
fold_left push a b
|
||||||
|
|
||||||
|
let flat_map f v : _ t = fold_left (fun acc x -> append acc (f x)) empty v
|
||||||
|
|
||||||
let rec equal_tree eq t1 t2 =
|
let rec equal_tree eq t1 t2 =
|
||||||
match t1, t2 with
|
match t1, t2 with
|
||||||
| Empty, Empty -> true
|
| Empty, Empty -> true
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,11 @@ val append : 'a t -> 'a t -> 'a t
|
||||||
|
|
||||||
val map : ('a -> 'b) -> 'a t -> 'b t
|
val map : ('a -> 'b) -> 'a t -> 'b t
|
||||||
|
|
||||||
|
val flat_map : ('a -> 'b t) -> 'a t -> 'b t
|
||||||
|
(** A basic, fairly slow [flat_map] operation like {!CCList.flat_map}.
|
||||||
|
It exists for convenience but is not where this data structure shines.
|
||||||
|
@since NEXT_RELEASE *)
|
||||||
|
|
||||||
val choose : 'a t -> 'a option
|
val choose : 'a t -> 'a option
|
||||||
(** Return an element. It is unspecified which one is returned. *)
|
(** Return an element. It is unspecified which one is returned. *)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,9 @@ let gen_c : Cbor.t Q.Gen.t =
|
||||||
in
|
in
|
||||||
frequency
|
frequency
|
||||||
(if size > 0 then
|
(if size > 0 then
|
||||||
base @ rec_
|
base @ rec_
|
||||||
else
|
else
|
||||||
base)
|
base)
|
||||||
|
|
||||||
let rec shrink (c : Cbor.t) : Cbor.t Q.Iter.t =
|
let rec shrink (c : Cbor.t) : Cbor.t Q.Iter.t =
|
||||||
let open Q.Iter in
|
let open Q.Iter in
|
||||||
|
|
@ -99,12 +99,28 @@ let rec shrink (c : Cbor.t) : Cbor.t Q.Iter.t =
|
||||||
let+ s = Q.Shrink.string s in
|
let+ s = Q.Shrink.string s in
|
||||||
`Bytes s
|
`Bytes s
|
||||||
|
|
||||||
let arb = Q.make ~shrink ~print:Cbor.to_string_diagnostic gen_c;;
|
let arb = Q.make ~shrink ~print:Cbor.to_string_diagnostic gen_c
|
||||||
|
|
||||||
|
let rec eq_c c c' =
|
||||||
|
match c, c' with
|
||||||
|
| `Null, `Null | `Undefined, `Undefined -> true
|
||||||
|
| `Simple i, `Simple i' -> Int.equal i i'
|
||||||
|
| `Bool b, `Bool b' -> Bool.equal b b'
|
||||||
|
| `Int i, `Int i' -> Int64.equal i i'
|
||||||
|
| `Float f, `Float f' -> Float.equal f f'
|
||||||
|
| `Bytes s, `Bytes s' -> String.equal s s'
|
||||||
|
| `Text t, `Text t' -> String.equal t t'
|
||||||
|
| `Array a, `Array a' -> CCList.equal eq_c a a'
|
||||||
|
| `Map m, `Map m' ->
|
||||||
|
CCList.equal (fun (t0, t1) (t0', t1') -> eq_c t0 t0' && eq_c t1 t1') m m'
|
||||||
|
| `Tag (i, t), `Tag (i', t') -> Int.equal i i' && eq_c t t'
|
||||||
|
| _ -> false
|
||||||
|
;;
|
||||||
|
|
||||||
q ~count:1_000 ~long_factor:10 arb @@ fun c ->
|
q ~count:1_000 ~long_factor:10 arb @@ fun c ->
|
||||||
let s = Cbor.encode c in
|
let s = Cbor.encode c in
|
||||||
let c' = Cbor.decode_exn s in
|
let c' = Cbor.decode_exn s in
|
||||||
if not (c = c') then
|
if not (eq_c c c') then
|
||||||
Q.Test.fail_reportf "@[<hv2>roundtrip failed:@ from %a@ to %a@]"
|
Q.Test.fail_reportf "@[<hv2>roundtrip failed:@ from %a@ to %a@]"
|
||||||
Cbor.pp_diagnostic c Cbor.pp_diagnostic c';
|
Cbor.pp_diagnostic c Cbor.pp_diagnostic c';
|
||||||
true
|
true
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,76 @@ eq None (of_int 257);;
|
||||||
q
|
q
|
||||||
(Q.string_of_size (Q.Gen.return 1))
|
(Q.string_of_size (Q.Gen.return 1))
|
||||||
(fun s -> Stdlib.( = ) (to_string s.[0]) s)
|
(fun s -> Stdlib.( = ) (to_string s.[0]) s)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q (Q.int_range 65 90 |> Q.map Char.chr) CCChar.is_uppercase_ascii;;
|
||||||
|
|
||||||
|
q
|
||||||
|
(Q.int_range 0 64 |> Q.map Char.chr)
|
||||||
|
(fun c -> not @@ CCChar.is_uppercase_ascii c)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q
|
||||||
|
(Q.int_range 91 127 |> Q.map Char.chr)
|
||||||
|
(fun c -> not @@ CCChar.is_uppercase_ascii c)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q (Q.int_range 97 122 |> Q.map Char.chr) CCChar.is_lowercase_ascii;;
|
||||||
|
|
||||||
|
q
|
||||||
|
(Q.int_range 0 96 |> Q.map Char.chr)
|
||||||
|
(fun c -> not @@ CCChar.is_lowercase_ascii c)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q
|
||||||
|
(Q.int_range 123 127 |> Q.map Char.chr)
|
||||||
|
(fun c -> not @@ CCChar.is_lowercase_ascii c)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q (Q.int_range 48 57 |> Q.map Char.chr) CCChar.is_digit_ascii;;
|
||||||
|
q (Q.int_range 0 47 |> Q.map Char.chr) (fun c -> not @@ CCChar.is_digit_ascii c)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q
|
||||||
|
(Q.int_range 58 127 |> Q.map Char.chr)
|
||||||
|
(fun c -> not @@ CCChar.is_digit_ascii c)
|
||||||
|
;;
|
||||||
|
|
||||||
|
eq true
|
||||||
|
(Stdlib.List.for_all CCChar.is_whitespace_ascii
|
||||||
|
[ '\n'; '\t'; ' '; '\010'; '\011'; '\012'; '\013' ])
|
||||||
|
;;
|
||||||
|
|
||||||
|
eq false
|
||||||
|
(Stdlib.List.exists CCChar.is_whitespace_ascii
|
||||||
|
[
|
||||||
|
'H';
|
||||||
|
'e';
|
||||||
|
'l';
|
||||||
|
'l';
|
||||||
|
'o';
|
||||||
|
'!';
|
||||||
|
'-';
|
||||||
|
'-';
|
||||||
|
'N';
|
||||||
|
'O';
|
||||||
|
't';
|
||||||
|
'h';
|
||||||
|
'i';
|
||||||
|
'n';
|
||||||
|
'a';
|
||||||
|
'\055';
|
||||||
|
'k';
|
||||||
|
'a';
|
||||||
|
'g';
|
||||||
|
'$';
|
||||||
|
'$';
|
||||||
|
'$';
|
||||||
|
'%';
|
||||||
|
'^';
|
||||||
|
'b';
|
||||||
|
'c';
|
||||||
|
'h';
|
||||||
|
'\008';
|
||||||
|
'h';
|
||||||
|
])
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,15 @@ true
|
||||||
t @@ fun () -> CCFun.((succ %> string_of_int) 2 = "3");;
|
t @@ fun () -> CCFun.((succ %> string_of_int) 2 = "3");;
|
||||||
t @@ fun () -> CCFun.((( * ) 3 % succ) 5 = 18);;
|
t @@ fun () -> CCFun.((( * ) 3 % succ) 5 = 18);;
|
||||||
t @@ fun () -> CCFun.(succ @@ ( * ) 2 @@ pred @@ 3 = 5)
|
t @@ fun () -> CCFun.(succ @@ ( * ) 2 @@ pred @@ 3 = 5)
|
||||||
|
|
||||||
|
let find_array arr x =
|
||||||
|
let@ return = with_return in
|
||||||
|
for i = 0 to Array.length arr - 1 do
|
||||||
|
if arr.(i) = x then return i
|
||||||
|
done;
|
||||||
|
-1
|
||||||
|
;;
|
||||||
|
|
||||||
|
eq 1 @@ find_array [| "a"; "b"; "c" |] "b";;
|
||||||
|
eq 2 @@ find_array [| "a"; "b"; "c" |] "c";;
|
||||||
|
eq (-1) @@ find_array [| "a"; "b"; "c" |] "hello"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ t @@ fun () -> char 'c' >= 0;;
|
||||||
t @@ fun () -> int 152352 = int 152352;;
|
t @@ fun () -> int 152352 = int 152352;;
|
||||||
t @@ fun () -> list_comm int [ 1; 2 ] = list_comm int [ 2; 1 ];;
|
t @@ fun () -> list_comm int [ 1; 2 ] = list_comm int [ 2; 1 ];;
|
||||||
t @@ fun () -> list_comm int [ 1; 2 ] <> list_comm int [ 2; 3 ];;
|
t @@ fun () -> list_comm int [ 1; 2 ] <> list_comm int [ 2; 3 ];;
|
||||||
|
t @@ fun () -> string "abcd" >= 0;;
|
||||||
|
t @@ fun () -> string "abc" <> string "abcd";;
|
||||||
|
|
||||||
q Q.int (fun i ->
|
q Q.int (fun i ->
|
||||||
Q.assume (i >= 0);
|
Q.assume (i >= 0);
|
||||||
|
|
|
||||||
|
|
@ -183,10 +183,11 @@ let arb_csexp_arb =
|
||||||
let genstr = Q.Gen.(string_size ~gen:genchar (0 -- 15)) in
|
let genstr = Q.Gen.(string_size ~gen:genchar (0 -- 15)) in
|
||||||
Q.make ~print:Sexp0.to_string ~shrink:shrink_csexp (gen_csexp genstr)
|
Q.make ~print:Sexp0.to_string ~shrink:shrink_csexp (gen_csexp genstr)
|
||||||
|
|
||||||
module Make (X : sig
|
module Make
|
||||||
val arb : Csexp.t Q.arbitrary
|
(X : sig
|
||||||
end)
|
val arb : Csexp.t Q.arbitrary
|
||||||
() =
|
end)
|
||||||
|
() =
|
||||||
struct
|
struct
|
||||||
open X;;
|
open X;;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,9 +162,9 @@ q
|
||||||
let e = edit_distance s1 s2 in
|
let e = edit_distance s1 s2 in
|
||||||
let e' = edit_distance ~cutoff:3 s1 s2 in
|
let e' = edit_distance ~cutoff:3 s1 s2 in
|
||||||
(if e' < 3 then
|
(if e' < 3 then
|
||||||
e = e'
|
e = e'
|
||||||
else
|
else
|
||||||
e >= 3)
|
e >= 3)
|
||||||
&&
|
&&
|
||||||
if e <= 3 then
|
if e <= 3 then
|
||||||
e = e'
|
e = e'
|
||||||
|
|
@ -229,7 +229,28 @@ t @@ fun () -> not (suffix ~suf:"cd" "abcde");;
|
||||||
t @@ fun () -> not (suffix ~suf:"abcd" "cd");;
|
t @@ fun () -> not (suffix ~suf:"abcd" "cd");;
|
||||||
eq ("ab", "cd") (take_drop 2 "abcd");;
|
eq ("ab", "cd") (take_drop 2 "abcd");;
|
||||||
eq ("abc", "") (take_drop 3 "abc");;
|
eq ("abc", "") (take_drop 3 "abc");;
|
||||||
eq ("abc", "") (take_drop 5 "abc")
|
eq ("abc", "") (take_drop 5 "abc");;
|
||||||
|
|
||||||
|
q
|
||||||
|
Q.(printable_string)
|
||||||
|
(fun s ->
|
||||||
|
let predicate c = Char.code c mod 2 = 0 in
|
||||||
|
let prefix = take_while predicate s in
|
||||||
|
let suffix = drop_while predicate s in
|
||||||
|
if prefix ^ suffix <> s then
|
||||||
|
Q.Test.fail_reportf "s=%S, pre=%S, post=%S" s prefix suffix;
|
||||||
|
true)
|
||||||
|
;;
|
||||||
|
|
||||||
|
q
|
||||||
|
Q.(printable_string)
|
||||||
|
(fun s ->
|
||||||
|
let predicate c = Char.code c mod 2 = 0 in
|
||||||
|
let prefix = rdrop_while predicate s in
|
||||||
|
let suffix = rtake_while predicate s in
|
||||||
|
if prefix ^ suffix <> s then
|
||||||
|
Q.Test.fail_reportf "s=%S, pre=%S, post=%S" s prefix suffix;
|
||||||
|
true)
|
||||||
|
|
||||||
let eq' = eq ~printer:Q.Print.(option string);;
|
let eq' = eq ~printer:Q.Print.(option string);;
|
||||||
|
|
||||||
|
|
@ -280,6 +301,23 @@ eq ~printer:CCFun.id "" (unlines []);;
|
||||||
eq ~printer:CCFun.id "ab\nc\n" (unlines [ "ab"; "c" ]);;
|
eq ~printer:CCFun.id "ab\nc\n" (unlines [ "ab"; "c" ]);;
|
||||||
q Q.printable_string (fun s -> trim (unlines (lines s)) = trim s);;
|
q Q.printable_string (fun s -> trim (unlines (lines s)) = trim s);;
|
||||||
q Q.printable_string (fun s -> trim (unlines_gen (lines_gen s)) = trim s);;
|
q Q.printable_string (fun s -> trim (unlines_gen (lines_gen s)) = trim s);;
|
||||||
|
eq ~printer:CCFun.id "" (take_while (Char.equal 'c') "heloo_cc");;
|
||||||
|
eq ~printer:CCFun.id "" (take_while (Char.equal 'c') "");;
|
||||||
|
eq ~printer:CCFun.id "c" (take_while (Char.equal 'c') "c");;
|
||||||
|
eq ~printer:CCFun.id "ccc" (take_while (Char.equal 'c') "cccujsuy");;
|
||||||
|
|
||||||
|
eq ~printer:CCFun.id "THIS"
|
||||||
|
(take_while (fun c -> Char.code c < 91) "THISisNotWHAtIwANTED")
|
||||||
|
;;
|
||||||
|
|
||||||
|
eq ~printer:CCFun.id "cc" (rtake_while (Char.equal 'c') "heloo_cc");;
|
||||||
|
eq ~printer:CCFun.id "" (rtake_while (Char.equal 'c') "");;
|
||||||
|
eq ~printer:CCFun.id "c" (rtake_while (Char.equal 'c') "c");;
|
||||||
|
eq ~printer:CCFun.id "" (rtake_while (Char.equal 'c') "cccujsuy");;
|
||||||
|
|
||||||
|
eq ~printer:CCFun.id "ANTED"
|
||||||
|
(rtake_while (fun c -> Char.code c < 91) "THISisNotWHAtIwANTED")
|
||||||
|
;;
|
||||||
|
|
||||||
q
|
q
|
||||||
Q.(small_list small_string)
|
Q.(small_list small_string)
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ let arb_uchar =
|
||||||
let rec gen =
|
let rec gen =
|
||||||
lazy
|
lazy
|
||||||
(let open Q.Gen in
|
(let open Q.Gen in
|
||||||
Q.Gen.int_range Uchar.(to_int min) Uchar.(to_int max) >>= fun n ->
|
Q.Gen.int_range Uchar.(to_int min) Uchar.(to_int max) >>= fun n ->
|
||||||
try return (Uchar.of_int n) with _ -> Lazy.force gen)
|
try return (Uchar.of_int n) with _ -> Lazy.force gen)
|
||||||
in
|
in
|
||||||
Q.make
|
Q.make
|
||||||
~print:(fun c -> Printf.sprintf "<uchar '%d'>" (Uchar.to_int c))
|
~print:(fun c -> Printf.sprintf "<uchar '%d'>" (Uchar.to_int c))
|
||||||
|
|
|
||||||
|
|
@ -640,9 +640,9 @@ module Op = struct
|
||||||
@@ List.flatten
|
@@ List.flatten
|
||||||
[
|
[
|
||||||
(if size > 0 then
|
(if size > 0 then
|
||||||
nonzero
|
nonzero
|
||||||
else
|
else
|
||||||
[]);
|
[]);
|
||||||
[
|
[
|
||||||
1, return Clear;
|
1, return Clear;
|
||||||
1, return Clear_and_shrink;
|
1, return Clear_and_shrink;
|
||||||
|
|
@ -747,16 +747,16 @@ module Ref_ = struct
|
||||||
| Set_bool (i, b) ->
|
| Set_bool (i, b) ->
|
||||||
apply_op self
|
apply_op self
|
||||||
(if b then
|
(if b then
|
||||||
Set i
|
Set i
|
||||||
else
|
else
|
||||||
Reset i)
|
Reset i)
|
||||||
| Flip i ->
|
| Flip i ->
|
||||||
self.size <- max self.size (i + 1);
|
self.size <- max self.size (i + 1);
|
||||||
apply_op self
|
apply_op self
|
||||||
(if Intset.mem i self.set then
|
(if Intset.mem i self.set then
|
||||||
Reset i
|
Reset i
|
||||||
else
|
else
|
||||||
Set i)
|
Set i)
|
||||||
| Clear -> self.set <- Intset.empty
|
| Clear -> self.set <- Intset.empty
|
||||||
| Clear_and_shrink ->
|
| Clear_and_shrink ->
|
||||||
self.set <- Intset.empty;
|
self.set <- Intset.empty;
|
||||||
|
|
|
||||||
|
|
@ -173,12 +173,12 @@ module Op = struct
|
||||||
1, return (Check_to_gen, size);
|
1, return (Check_to_gen, size);
|
||||||
];
|
];
|
||||||
(if size > 0 then
|
(if size > 0 then
|
||||||
[
|
[
|
||||||
1, return (Pop, size - 1);
|
1, return (Pop, size - 1);
|
||||||
(1, 0 -- (size - 1) >|= fun x -> Check_get x, size);
|
(1, 0 -- (size - 1) >|= fun x -> Check_get x, size);
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
[]);
|
[]);
|
||||||
[
|
[
|
||||||
( 1,
|
( 1,
|
||||||
small_list gen_x >|= fun l ->
|
small_list gen_x >|= fun l ->
|
||||||
|
|
|
||||||
|
|
@ -108,15 +108,14 @@ let t1 = H.of_list [ 1, "a"; 2, "b1" ] in
|
||||||
let t2 = H.of_list [ 2, "b2"; 3, "c" ] in
|
let t2 = H.of_list [ 2, "b2"; 3, "c" ] in
|
||||||
let t =
|
let t =
|
||||||
H.merge
|
H.merge
|
||||||
~f:
|
~f:(fun _ -> function
|
||||||
(fun _ -> function
|
| `Right v2 -> Some v2
|
||||||
| `Right v2 -> Some v2
|
| `Left v1 -> Some v1
|
||||||
| `Left v1 -> Some v1
|
| `Both (s1, s2) ->
|
||||||
| `Both (s1, s2) ->
|
if s1 < s2 then
|
||||||
if s1 < s2 then
|
Some s1
|
||||||
Some s1
|
else
|
||||||
else
|
Some s2)
|
||||||
Some s2)
|
|
||||||
t1 t2
|
t1 t2
|
||||||
in
|
in
|
||||||
assert_equal ~printer:string_of_int 3 (H.length t);
|
assert_equal ~printer:string_of_int 3 (H.length t);
|
||||||
|
|
|
||||||
|
|
@ -118,9 +118,9 @@ let rec sorted ~rev = function
|
||||||
| [] | [ _ ] -> true
|
| [] | [ _ ] -> true
|
||||||
| x :: (y :: _ as tl) ->
|
| x :: (y :: _ as tl) ->
|
||||||
(if rev then
|
(if rev then
|
||||||
x >= y
|
x >= y
|
||||||
else
|
else
|
||||||
x <= y)
|
x <= y)
|
||||||
&& sorted ~rev tl
|
&& sorted ~rev tl
|
||||||
|
|
||||||
let gen_str = Q.small_printable_string;;
|
let gen_str = Q.small_printable_string;;
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,8 @@ module Ref_impl = struct
|
||||||
let to_list l = l
|
let to_list l = l
|
||||||
let to_seq = CCSeq.of_list
|
let to_seq = CCSeq.of_list
|
||||||
let add_list l l2 : _ t = List.append l l2
|
let add_list l l2 : _ t = List.append l l2
|
||||||
|
let append self l2 : _ t = List.append self l2
|
||||||
|
let flat_map sub l : _ t = CCList.flat_map (fun x -> sub @ [ x ]) l
|
||||||
|
|
||||||
let to_list_via_reviter m =
|
let to_list_via_reviter m =
|
||||||
let l = ref [] in
|
let l = ref [] in
|
||||||
|
|
@ -159,7 +161,9 @@ module Op = struct
|
||||||
| Push of 'a
|
| Push of 'a
|
||||||
| Pop
|
| Pop
|
||||||
(* TODO: set *)
|
(* TODO: set *)
|
||||||
|
| Append of 'a list
|
||||||
| Add_list of 'a list
|
| Add_list of 'a list
|
||||||
|
| Flat_map of 'a list
|
||||||
| Check_get of int
|
| Check_get of int
|
||||||
| Check_choose
|
| Check_choose
|
||||||
| Check_is_empty
|
| Check_is_empty
|
||||||
|
|
@ -176,6 +180,8 @@ module Op = struct
|
||||||
| Push _ :: tl -> loop (size + 1) tl
|
| Push _ :: tl -> loop (size + 1) tl
|
||||||
| Pop :: tl -> size >= 0 && loop (size - 1) tl
|
| Pop :: tl -> size >= 0 && loop (size - 1) tl
|
||||||
| Add_list l :: tl -> loop (size + List.length l) tl
|
| Add_list l :: tl -> loop (size + List.length l) tl
|
||||||
|
| Append l :: tl -> loop (size + List.length l) tl
|
||||||
|
| Flat_map sub :: tl -> loop (size * (1 + List.length sub)) tl
|
||||||
| Check_get x :: tl -> x < size && loop size tl
|
| Check_get x :: tl -> x < size && loop size tl
|
||||||
| Check_choose :: tl
|
| Check_choose :: tl
|
||||||
| Check_is_empty :: tl
|
| Check_is_empty :: tl
|
||||||
|
|
@ -194,6 +200,8 @@ module Op = struct
|
||||||
| Push x -> spf "push %s" (show_x x)
|
| Push x -> spf "push %s" (show_x x)
|
||||||
| Pop -> "pop"
|
| Pop -> "pop"
|
||||||
| Add_list l -> spf "add_list [%s]" (String.concat ";" @@ List.map show_x l)
|
| Add_list l -> spf "add_list [%s]" (String.concat ";" @@ List.map show_x l)
|
||||||
|
| Append l -> spf "append [%s]" (String.concat ";" @@ List.map show_x l)
|
||||||
|
| Flat_map l -> spf "flat_map [%s]" (String.concat ";" @@ List.map show_x l)
|
||||||
| Check_get i -> spf "check_get %d" i
|
| Check_get i -> spf "check_get %d" i
|
||||||
| Check_choose -> "check_choose"
|
| Check_choose -> "check_choose"
|
||||||
| Check_is_empty -> "check_is_empty"
|
| Check_is_empty -> "check_is_empty"
|
||||||
|
|
@ -211,6 +219,8 @@ module Op = struct
|
||||||
| Push x -> shrink_x x >|= fun x -> Push x
|
| Push x -> shrink_x x >|= fun x -> Push x
|
||||||
| Pop -> empty
|
| Pop -> empty
|
||||||
| Add_list l -> list ~shrink:shrink_x l >|= fun x -> Add_list x
|
| Add_list l -> list ~shrink:shrink_x l >|= fun x -> Add_list x
|
||||||
|
| Append l -> list ~shrink:shrink_x l >|= fun x -> Append x
|
||||||
|
| Flat_map l -> list ~shrink:shrink_x l >|= fun x -> Flat_map x
|
||||||
| Check_get _ | Check_choose | Check_is_empty | Check_len | Check_to_list
|
| Check_get _ | Check_choose | Check_is_empty | Check_len | Check_to_list
|
||||||
| Check_to_gen | Check_last | Check_rev_iter | Check_iter ->
|
| Check_to_gen | Check_last | Check_rev_iter | Check_iter ->
|
||||||
empty
|
empty
|
||||||
|
|
@ -242,16 +252,22 @@ module Op = struct
|
||||||
1, return (Check_rev_iter, size);
|
1, return (Check_rev_iter, size);
|
||||||
];
|
];
|
||||||
(if size > 0 then
|
(if size > 0 then
|
||||||
[
|
[
|
||||||
1, return (Pop, size - 1);
|
1, return (Pop, size - 1);
|
||||||
(1, 0 -- (size - 1) >|= fun x -> Check_get x, size);
|
(1, 0 -- (size - 1) >|= fun x -> Check_get x, size);
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
[]);
|
[]);
|
||||||
[
|
[
|
||||||
( 1,
|
( 1,
|
||||||
small_list gen_x >|= fun l ->
|
small_list gen_x >|= fun l ->
|
||||||
Add_list l, size + List.length l );
|
Add_list l, size + List.length l );
|
||||||
|
( 1,
|
||||||
|
small_list gen_x >|= fun l ->
|
||||||
|
Append l, size + List.length l );
|
||||||
|
( 1,
|
||||||
|
list_size (0 -- 5) gen_x >|= fun l ->
|
||||||
|
Flat_map l, size * (1 + List.length l) );
|
||||||
];
|
];
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
|
|
@ -292,6 +308,12 @@ let check_ops ~show_x (ops : 'a Op.t list) : unit =
|
||||||
| Op.Add_list l ->
|
| Op.Add_list l ->
|
||||||
cur := add_list !cur l;
|
cur := add_list !cur l;
|
||||||
cur_ref := Ref_impl.add_list !cur_ref l
|
cur_ref := Ref_impl.add_list !cur_ref l
|
||||||
|
| Op.Append l ->
|
||||||
|
cur := append !cur (of_list l);
|
||||||
|
cur_ref := Ref_impl.append !cur_ref l
|
||||||
|
| Op.Flat_map sub ->
|
||||||
|
cur := flat_map (fun x -> push (of_list sub) x) !cur;
|
||||||
|
cur_ref := Ref_impl.flat_map sub !cur_ref
|
||||||
| Op.Check_get i -> if get !cur i <> Ref_impl.get i !cur_ref then fail ()
|
| Op.Check_get i -> if get !cur i <> Ref_impl.get i !cur_ref then fail ()
|
||||||
| Op.Check_is_empty ->
|
| Op.Check_is_empty ->
|
||||||
if is_empty !cur <> Ref_impl.is_empty !cur_ref then fail ()
|
if is_empty !cur <> Ref_impl.is_empty !cur_ref then fail ()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue