This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
15
unikernel/duniverse/ke/.gitignore
vendored
Normal file
15
unikernel/duniverse/ke/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
_build
|
||||
setup.data
|
||||
setup.log
|
||||
doc/*.html
|
||||
*.native
|
||||
*.byte
|
||||
*.so
|
||||
lib/decompress_conf.ml
|
||||
*.tar.gz
|
||||
_tests
|
||||
lib_test/files
|
||||
zpipe
|
||||
c/dpipe
|
||||
*.merlin
|
||||
*.install
|
||||
7
unikernel/duniverse/ke/.ocamlformat
Normal file
7
unikernel/duniverse/ke/.ocamlformat
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
version=0.21.0
|
||||
module-item-spacing=compact
|
||||
break-struct=natural
|
||||
break-infix=fit-or-vertical
|
||||
parens-tuple=always
|
||||
wrap-comments=false
|
||||
break-collection-expressions=wrap
|
||||
13
unikernel/duniverse/ke/.travis.yml
Normal file
13
unikernel/duniverse/ke/.travis.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
language: c
|
||||
install:
|
||||
- wget https://raw.githubusercontent.com/ocaml/ocaml-travisci-skeleton/master/.travis-opam.sh
|
||||
- wget https://raw.githubusercontent.com/dinosaure/ocaml-travisci-skeleton/master/.travis-docgen.sh
|
||||
script: bash -ex .travis-opam.sh
|
||||
sudo: true
|
||||
env:
|
||||
matrix:
|
||||
- PACKAGE="ke" OCAML_VERSION=4.03 TESTS=true
|
||||
- PACKAGE="ke" OCAML_VERSION=4.04 TESTS=true
|
||||
- PACKAGE="ke" OCAML_VERSION=4.05 TESTS=true
|
||||
- PACKAGE="ke" OCAML_VERSION=4.06 TESTS=true
|
||||
- PACKAGE="ke" OCAML_VERSION=4.07 TESTS=true
|
||||
45
unikernel/duniverse/ke/CHANGES.md
Normal file
45
unikernel/duniverse/ke/CHANGES.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
### v0.6 2022-04-07 Paris (France)
|
||||
|
||||
* Require OCaml 4.08 and remove `bigarray-compat` dependency (@hannesm, #17)
|
||||
|
||||
### v0.5 2022-03-18 Paris (France)
|
||||
|
||||
* Remove `{build}` directive into the OPAM file (@CraigFe, #10)
|
||||
* Add `unsafe_bigarray` into `Rke.Weighted` (@anmonteiro, #11)
|
||||
* Lint OPAM file (@kit-ty-kate, #12)
|
||||
* Fix the distribution and the CI (@dinosaure, #13)
|
||||
* Update the distribution with `cmdliner.1.1.0` (@dinosaure, #15)
|
||||
|
||||
### v0.4 2019-07-24 Мостар (Боснa и Херцеговина)
|
||||
|
||||
* Call `dune subst` only when we _pin_ `ke`
|
||||
* Update documentation (@dinosaure, @Drup)
|
||||
- Typography
|
||||
- Documentation about `Fke.tail{,_exn}`
|
||||
- Documentation about `Fke.rev_iter`
|
||||
* Add `Fke.tail{,_exn}` (@dinosaure, #8)
|
||||
* Add `Fke.rev_iter` (@dinosaure, #9)
|
||||
* Compatible with `mirage`, dependance with `bigarray-compat` (@dinosaure, @TheLortex, #8)
|
||||
* Update OPAM file (@dinosaure)
|
||||
|
||||
### v0.3 2019-04-10 Paris (France)
|
||||
|
||||
* Add `Rke.{,Weighted}.compress` function (fuzzed)
|
||||
* Update `bechamel` benchmark
|
||||
* Add `Rke{,.Weighted}.N.peek` function
|
||||
* Fix bug on `Rke.Weighted.N.keep` function
|
||||
* Add some tests
|
||||
|
||||
### v0.2 2019-01-14 Paris (France)
|
||||
|
||||
* Add pretty-printer
|
||||
* Randomize `pop` action on the fuzzer
|
||||
* Add tests on `Rke` and `Rke.Weighted` (with `alcotest`)
|
||||
* Fix bug retrieved by `ocaml-git` (see 453633b)
|
||||
* Add `rev_iter` function
|
||||
* Fix bug on `Rke.N.keep_exn` (see 3951501)
|
||||
* Add Travis CI support
|
||||
|
||||
### v0.1 2018-12-20 Paris (France)
|
||||
|
||||
* First release
|
||||
20
unikernel/duniverse/ke/LICENSE.md
Normal file
20
unikernel/duniverse/ke/LICENSE.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Romain Calascibetta
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
46
unikernel/duniverse/ke/README.md
Normal file
46
unikernel/duniverse/ke/README.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Ke - Fast implementation of Queue in OCaml
|
||||
==========================================
|
||||
|
||||

|
||||
|
||||
Queue or FIFO is one of the most famous data-structure used in several
|
||||
algorithms. `Ke` provides some implementations of it in a functionnal or
|
||||
imperative way.
|
||||
|
||||
It is a little library with benchmark
|
||||
([`bechamel`](https://github.com/dinosaure/bechamel.git) or `core_bench`),
|
||||
fuzzer and tests.
|
||||
|
||||
From what we know, `Ke.Rke` is the faster implementation than `Queue` from the
|
||||
standard library or the `base` package. It is limited by some kind of data (see
|
||||
[`Bigarray.kind`]()) but enough for a large amount of algorithms. The fast
|
||||
operation is to put some elements faster than a sequence of `Queue.push`, and
|
||||
get some elements faster than a sequence of `Queue.pop`.
|
||||
|
||||
Then we provide a functionnal interface `Fke` or an imperative interface `Rke`.
|
||||
|
||||
We extended implementations to have a limit of elements to store (see
|
||||
`Rke.Weighted` and `Fke.Weigted`). The purpose of it is to limit memory
|
||||
consumption of queue when we use it in some contexts (like _encoder_).
|
||||
|
||||
Again, as a part of the MirageOS project, `Ke` does not rely on C stubs,
|
||||
`Obj.magic` and so on.
|
||||
|
||||
Author: Romain Calascibetta <romain.calascibetta@gmail.com>
|
||||
|
||||
Documentation: https://mirage.github.io/ke/
|
||||
|
||||
Notes about Implementations
|
||||
===========================
|
||||
|
||||
The functionnal implementation `Fke` is come from the Okazaki's queue
|
||||
implementation with GADT to discard impossible case.
|
||||
|
||||
`Rke`, `Rke.Weighted` and `Fke.Weighted` was limited by kind and follow Xen's
|
||||
implementation of the shared memory ring-buffer. Length of the internal buffer
|
||||
is, in any case, a power of two - that means, in some context, for a large
|
||||
amount of elements, this kind of queue does not fit on your request.
|
||||
|
||||
Fuzzer was made to compare the standard Queue (as an oracle) with `Rke` and
|
||||
`Fke`. We construct a set of actions (`push` and `pop`) and ensure (by GADT) to
|
||||
never `pop` an empty queue.
|
||||
179
unikernel/duniverse/ke/bench/bench_with_bechamel.ml
Normal file
179
unikernel/duniverse/ke/bench/bench_with_bechamel.ml
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
open Bechamel
|
||||
open Toolkit
|
||||
|
||||
let random ln =
|
||||
let ic = open_in "/dev/urandom" in
|
||||
let rs = Bytes.create ln in
|
||||
really_input ic rs 0 ln;
|
||||
close_in ic;
|
||||
Bytes.unsafe_to_string rs
|
||||
|
||||
let push_fke n =
|
||||
let raw = random n in
|
||||
let data = List.init n (String.get raw) in
|
||||
Staged.stage (fun () -> List.fold_left Ke.Fke.push Ke.Fke.empty data)
|
||||
|
||||
let push_rke n =
|
||||
let queue = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () -> String.iter (Ke.Rke.push queue) raw)
|
||||
|
||||
let push_rke_n n =
|
||||
let queue = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
let raw = random n in
|
||||
let blit src src_off dst dst_off len =
|
||||
Bigstringaf.unsafe_blit_from_string src ~src_off dst ~dst_off ~len
|
||||
in
|
||||
Staged.stage (fun () -> Ke.Rke.N.push queue ~blit ~length:String.length raw)
|
||||
|
||||
let push_queue n =
|
||||
let queue = Queue.create () in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () -> String.iter (fun chr -> Queue.add chr queue) raw)
|
||||
|
||||
let push_and_pop_fke n =
|
||||
let raw = random n in
|
||||
let data = List.init n (String.get raw) in
|
||||
Staged.stage (fun () ->
|
||||
let q = List.fold_left Ke.Fke.push Ke.Fke.empty data in
|
||||
let rec go q =
|
||||
if not (Ke.Fke.is_empty q) then
|
||||
let _, q = Ke.Fke.pop_exn q in
|
||||
go q
|
||||
else ()
|
||||
in
|
||||
go q)
|
||||
|
||||
let push_and_pop_rke n =
|
||||
let queue = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () ->
|
||||
String.iter (Ke.Rke.push queue) raw;
|
||||
while not (Ke.Rke.is_empty queue) do
|
||||
ignore (Ke.Rke.pop queue)
|
||||
done)
|
||||
|
||||
let push_and_pop_queue n =
|
||||
let queue = Queue.create () in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () ->
|
||||
String.iter (fun chr -> Queue.add chr queue) raw;
|
||||
while not (Queue.is_empty queue) do
|
||||
ignore (Queue.pop queue)
|
||||
done)
|
||||
|
||||
let test_push_fke =
|
||||
Test.make_indexed ~name:"Fke.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_fke
|
||||
|
||||
let test_push_rke =
|
||||
Test.make_indexed ~name:"Rke.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_rke
|
||||
|
||||
let test_push_rke_n =
|
||||
Test.make_indexed ~name:"Rke.N.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_rke_n
|
||||
|
||||
let test_push_queue =
|
||||
Test.make_indexed ~name:"Queue.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_queue
|
||||
|
||||
let tests_push =
|
||||
[ test_push_fke; test_push_rke; test_push_rke_n; test_push_queue ]
|
||||
|
||||
let big_push_fke n =
|
||||
Staged.stage @@ fun () ->
|
||||
let q = ref Ke.Fke.empty in
|
||||
for i = 1 to n do
|
||||
q := Ke.Fke.push !q i
|
||||
done
|
||||
|
||||
let big_push_rke n =
|
||||
Staged.stage @@ fun () ->
|
||||
let q = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
for i = 1 to n do
|
||||
Ke.Rke.push q (Obj.magic i)
|
||||
done
|
||||
|
||||
let big_push_queue n =
|
||||
Staged.stage @@ fun () ->
|
||||
let q = Queue.create () in
|
||||
for i = 1 to n do
|
||||
Queue.push i q
|
||||
done
|
||||
|
||||
let test_big_push_fke =
|
||||
Test.make_indexed ~name:"Fke.big_push" ~args:[ 10; 1_000_000 ] big_push_fke
|
||||
|
||||
let test_big_push_rke =
|
||||
Test.make_indexed ~name:"Rke.big_push" ~args:[ 10; 1_000_000 ] big_push_rke
|
||||
|
||||
let test_big_push_queue =
|
||||
Test.make_indexed ~name:"Queue.big_push" ~args:[ 10; 1_000_000 ]
|
||||
big_push_queue
|
||||
|
||||
let tests_big_push =
|
||||
[ test_big_push_fke; test_big_push_rke; test_big_push_queue ]
|
||||
|
||||
let test_push_and_pop_fke =
|
||||
Test.make_indexed ~name:"Fke.push & Fke.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_fke
|
||||
|
||||
let test_push_and_pop_rke =
|
||||
Test.make_indexed ~name:"Rke.push & Rke.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_rke
|
||||
|
||||
let test_push_and_pop_queue =
|
||||
Test.make_indexed ~name:"Queue.push & Queue.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_queue
|
||||
|
||||
let tests_push_and_pop =
|
||||
[ test_push_and_pop_fke; test_push_and_pop_rke; test_push_and_pop_queue ]
|
||||
|
||||
let () = Bechamel_notty.Unit.add Instance.monotonic_clock "ns"
|
||||
let () = Bechamel_notty.Unit.add Instance.minor_allocated "w"
|
||||
let () = Bechamel_notty.Unit.add Instance.major_allocated "mw"
|
||||
let () = Bechamel_notty.Unit.add Bechamel_perf.Instance.cpu_clock "ns"
|
||||
let ( <.> ) f g x = f (g x)
|
||||
|
||||
let () =
|
||||
let ols =
|
||||
Analyze.ols ~r_square:true ~bootstrap:0 ~predictors:Measure.[| run |]
|
||||
in
|
||||
let instances =
|
||||
Instance.
|
||||
[ minor_allocated; major_allocated; Bechamel_perf.Instance.cpu_clock ]
|
||||
in
|
||||
let tests =
|
||||
match Sys.argv with
|
||||
| [| _ |] -> []
|
||||
| [| _; "push" |] -> tests_push
|
||||
| [| _; "push&pop" |] -> tests_push_and_pop
|
||||
| [| _; "big-push" |] -> tests_big_push
|
||||
| [| _; "all" |] -> tests_push @ tests_big_push @ tests_push_and_pop
|
||||
| _ -> Fmt.invalid_arg "%s {push|all}" Sys.argv.(1)
|
||||
in
|
||||
let cfg = Benchmark.cfg ~limit:3000 () in
|
||||
let raw_results = List.map (Benchmark.all cfg instances) tests in
|
||||
let results =
|
||||
List.map
|
||||
(fun raw_results ->
|
||||
List.map
|
||||
(fun instance -> Analyze.all ols instance raw_results)
|
||||
instances
|
||||
|> Analyze.merge ols instances)
|
||||
raw_results
|
||||
in
|
||||
let rect = { Bechamel_notty.w = 80; h = 1 } in
|
||||
List.iter
|
||||
(Notty_unix.(output_image <.> eol)
|
||||
<.> Bechamel_notty.Multiple.image_of_ols_results ~rect
|
||||
~predictor:Measure.run)
|
||||
results
|
||||
194
unikernel/duniverse/ke/bench/bench_with_core.ml
Normal file
194
unikernel/duniverse/ke/bench/bench_with_core.ml
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
open Core
|
||||
open Core_bench
|
||||
|
||||
let random ln =
|
||||
let open Stdlib in
|
||||
let ic = open_in "/dev/urandom" in
|
||||
let rs = Bytes.create ln in
|
||||
really_input ic rs 0 ln;
|
||||
close_in ic;
|
||||
Bytes.unsafe_to_string rs
|
||||
|
||||
let push_fke n =
|
||||
let raw = random n in
|
||||
let data = List.init n ~f:(String.get raw) in
|
||||
Staged.stage (fun () -> List.fold_left ~f:Ke.Fke.push ~init:Ke.Fke.empty data)
|
||||
|
||||
let push_rke n =
|
||||
let queue = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () -> String.iter ~f:(Ke.Rke.push queue) raw)
|
||||
|
||||
let push_rke_n n =
|
||||
let queue = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
let raw = random n in
|
||||
let blit src src_off dst dst_off len =
|
||||
Bigstringaf.unsafe_blit_from_string src ~src_off dst ~dst_off ~len
|
||||
in
|
||||
Staged.stage (fun () -> Ke.Rke.N.push queue ~blit ~length:String.length raw)
|
||||
|
||||
let push_queue n =
|
||||
let queue = Queue.create () in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () ->
|
||||
String.iter ~f:(fun chr -> Queue.enqueue queue chr) raw)
|
||||
|
||||
let push_stdlib_queue n =
|
||||
let open Stdlib in
|
||||
let queue = Queue.create () in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () -> String.iter (fun chr -> Queue.push chr queue) raw)
|
||||
|
||||
let push_and_pop_fke n =
|
||||
let raw = random n in
|
||||
let data = List.init n ~f:(String.get raw) in
|
||||
Staged.stage (fun () ->
|
||||
let q = List.fold_left ~f:Ke.Fke.push ~init:Ke.Fke.empty data in
|
||||
let rec go q =
|
||||
if not (Ke.Fke.is_empty q) then
|
||||
let _, q = Ke.Fke.pop_exn q in
|
||||
go q
|
||||
else ()
|
||||
in
|
||||
go q)
|
||||
|
||||
let push_and_pop_rke n =
|
||||
let queue = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () ->
|
||||
String.iter ~f:(Ke.Rke.push queue) raw;
|
||||
while not (Ke.Rke.is_empty queue) do
|
||||
ignore (Ke.Rke.pop queue)
|
||||
done)
|
||||
|
||||
let push_and_pop_queue n =
|
||||
let queue = Queue.create () in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () ->
|
||||
String.iter ~f:(fun chr -> Queue.enqueue queue chr) raw;
|
||||
while not (Queue.is_empty queue) do
|
||||
ignore (Queue.dequeue_exn queue)
|
||||
done)
|
||||
|
||||
let push_and_pop_stdlib_queue n =
|
||||
let open Stdlib in
|
||||
let queue = Queue.create () in
|
||||
let raw = random n in
|
||||
Staged.stage (fun () ->
|
||||
String.iter (fun chr -> Queue.push chr queue) raw;
|
||||
while not (Queue.is_empty queue) do
|
||||
ignore (Queue.pop queue)
|
||||
done)
|
||||
|
||||
let big_push_fke n =
|
||||
Staged.stage @@ fun () ->
|
||||
let q = ref Ke.Fke.empty in
|
||||
for i = 1 to n do
|
||||
q := Ke.Fke.push !q i
|
||||
done
|
||||
|
||||
let big_push_rke n =
|
||||
Staged.stage @@ fun () ->
|
||||
let q = Ke.Rke.create ~capacity:n Bigarray.Char in
|
||||
for i = 1 to n do
|
||||
Ke.Rke.push q (Obj.magic i)
|
||||
done
|
||||
|
||||
let big_push_queue n =
|
||||
Staged.stage @@ fun () ->
|
||||
let q = Queue.create () in
|
||||
for i = 1 to n do
|
||||
Queue.enqueue q i
|
||||
done
|
||||
|
||||
let big_push_stdlib_queue n =
|
||||
let open Stdlib in
|
||||
Staged.stage @@ fun () ->
|
||||
let q = Queue.create () in
|
||||
for i = 1 to n do
|
||||
Queue.push i q
|
||||
done
|
||||
|
||||
open Bench
|
||||
|
||||
let test_big_push_fke =
|
||||
Test.create_indexed ~name:"Fke.big_push" ~args:[ 10; 1_000_000 ] big_push_fke
|
||||
|
||||
let test_big_push_rke =
|
||||
Test.create_indexed ~name:"Rke.big_push" ~args:[ 10; 1_000_000 ] big_push_rke
|
||||
|
||||
let test_big_push_queue =
|
||||
Test.create_indexed ~name:"Queue.big_push" ~args:[ 10; 1_000_000 ]
|
||||
big_push_queue
|
||||
|
||||
let test_big_push_stdlib_queue =
|
||||
Test.create_indexed ~name:"Stdlib.Queue.big_push" ~args:[ 10; 1_000_000 ]
|
||||
big_push_stdlib_queue
|
||||
|
||||
let tests_big_push =
|
||||
[
|
||||
test_big_push_fke; test_big_push_rke; test_big_push_queue;
|
||||
test_big_push_stdlib_queue;
|
||||
]
|
||||
|
||||
let test_push_fke =
|
||||
Test.create_indexed ~name:"Fke.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_fke
|
||||
|
||||
let test_push_rke =
|
||||
Test.create_indexed ~name:"Rke.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_rke
|
||||
|
||||
let test_push_rke_n =
|
||||
Test.create_indexed ~name:"Rke.N.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_rke_n
|
||||
|
||||
let test_push_queue =
|
||||
Test.create_indexed ~name:"Queue.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_queue
|
||||
|
||||
let test_push_stdlib_queue =
|
||||
Test.create_indexed ~name:"Stdlib.Queue.push"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_stdlib_queue
|
||||
|
||||
let tests_push =
|
||||
[
|
||||
test_push_fke; test_push_rke; test_push_rke_n; test_push_queue;
|
||||
test_push_stdlib_queue;
|
||||
]
|
||||
|
||||
let test_push_and_pop_fke =
|
||||
Test.create_indexed ~name:"Fke.push & Fke.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_fke
|
||||
|
||||
let test_push_and_pop_rke =
|
||||
Test.create_indexed ~name:"Rke.push & Rke.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_rke
|
||||
|
||||
let test_push_and_pop_queue =
|
||||
Test.create_indexed ~name:"Queue.push & Queue.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_queue
|
||||
|
||||
let test_push_and_pop_stdlib_queue =
|
||||
Test.create_indexed ~name:"Stdlib.Queue.push & Stdlib.Queue.pop"
|
||||
~args:[ 100; 500; 1000; 5000; 10000 ]
|
||||
push_and_pop_stdlib_queue
|
||||
|
||||
let tests_push_and_pop =
|
||||
[
|
||||
test_push_and_pop_fke; test_push_and_pop_rke; test_push_and_pop_queue;
|
||||
test_push_and_pop_stdlib_queue;
|
||||
]
|
||||
|
||||
let command =
|
||||
Bench.make_command (tests_push @ tests_big_push @ tests_push_and_pop)
|
||||
|
||||
let () = Command_unix.run command
|
||||
103
unikernel/duniverse/ke/bench/bfs.ml
Normal file
103
unikernel/duniverse/ke/bench/bfs.ml
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
module type F_PROBLEM = sig
|
||||
type state
|
||||
type move
|
||||
|
||||
val success : state -> bool
|
||||
val moves : state -> (move * state) list
|
||||
|
||||
type table
|
||||
|
||||
val create : unit -> table
|
||||
val add : table -> state -> unit
|
||||
val mem : table -> state -> bool
|
||||
val clear : table -> unit
|
||||
end
|
||||
|
||||
module type M_PROBLEM = sig
|
||||
type move
|
||||
|
||||
val success : unit -> bool
|
||||
val moves : unit -> move list
|
||||
val do_move : move -> unit
|
||||
val undo_move : move -> unit
|
||||
val add : unit -> unit
|
||||
val mem : unit -> bool
|
||||
val clear : unit -> unit
|
||||
end
|
||||
|
||||
module F (Q : Ke.Sigs.M) (P : F_PROBLEM) = struct
|
||||
let search s0 =
|
||||
let visited = P.create () in
|
||||
let already s =
|
||||
P.mem visited s
|
||||
||
|
||||
(P.add visited s;
|
||||
false)
|
||||
in
|
||||
let _ = already s0 in
|
||||
let q = Q.create () in
|
||||
Q.push q ([], s0);
|
||||
let rec bfs () =
|
||||
if Q.is_empty q then raise Not_found;
|
||||
let path, s = Q.pop_exn q in
|
||||
if P.success s then (s, List.rev path)
|
||||
else (
|
||||
List.iter
|
||||
(fun (m, s') -> if not (already s') then Q.push q (m :: path, s'))
|
||||
(P.moves s);
|
||||
bfs ())
|
||||
in
|
||||
bfs ()
|
||||
end
|
||||
|
||||
module M (Q : Ke.Sigs.M) (P : M_PROBLEM) = struct
|
||||
let rec cut_head n l = if n == 0 then l else cut_head (pred n) (List.tl l)
|
||||
|
||||
let common_psuffix (n1, l1) (n2, l2) =
|
||||
let rec suffix l1 l2 =
|
||||
if l1 == l2 then l1 else suffix (List.tl l1) (List.tl l2)
|
||||
in
|
||||
if n1 < n2 then suffix l1 (cut_head (n2 - n1) l2)
|
||||
else if n2 < n1 then suffix (cut_head (n1 - n2) l1) l2
|
||||
else suffix l1 l2
|
||||
|
||||
let search () =
|
||||
let already () =
|
||||
P.mem ()
|
||||
||
|
||||
(P.add ();
|
||||
false)
|
||||
in
|
||||
let q = Q.create () in
|
||||
Q.push q (0, []);
|
||||
let cpath = ref (0, []) in
|
||||
let rec restore_state path =
|
||||
let suf = common_psuffix path !cpath in
|
||||
let rec backward = function
|
||||
| m :: r as p when p != suf ->
|
||||
P.undo_move m;
|
||||
backward r
|
||||
| _ -> ()
|
||||
in
|
||||
let rec forward = function
|
||||
| m :: r as p when p != suf ->
|
||||
forward r;
|
||||
P.do_move m
|
||||
| _ -> ()
|
||||
in
|
||||
backward (snd !cpath);
|
||||
forward (snd path);
|
||||
cpath := path
|
||||
in
|
||||
let rec bfs () =
|
||||
if Q.is_empty q then raise Not_found;
|
||||
let ((n, path) as s) = Q.pop_exn q in
|
||||
restore_state s;
|
||||
if P.success () then List.rev path
|
||||
else if not (already ()) then (
|
||||
List.iter (fun m -> Q.push q (succ n, m :: path)) (P.moves ());
|
||||
bfs ())
|
||||
else bfs ()
|
||||
in
|
||||
bfs ()
|
||||
end
|
||||
19
unikernel/duniverse/ke/bench/dune
Normal file
19
unikernel/duniverse/ke/bench/dune
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
(executable
|
||||
(name bench_with_bechamel)
|
||||
(modules bench_with_bechamel)
|
||||
(libraries notty.unix bigstringaf ke bechamel bechamel-perf bechamel-notty))
|
||||
|
||||
(executable
|
||||
(name bench_with_core)
|
||||
(modules bench_with_core)
|
||||
(libraries bigstringaf core_bench ke core core_unix.command_unix))
|
||||
|
||||
(rule
|
||||
(alias runbench)
|
||||
(action
|
||||
(run ./bench_with_bechamel.exe)))
|
||||
|
||||
(rule
|
||||
(alias runbench)
|
||||
(action
|
||||
(run ./bench_with_core.exe)))
|
||||
4
unikernel/duniverse/ke/database.json
Normal file
4
unikernel/duniverse/ke/database.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[
|
||||
{"name": "First node", "time": "0", "ancestors": []},
|
||||
{"name": "Second node", "time": "1", "ancestors": [0]}
|
||||
]
|
||||
3
unikernel/duniverse/ke/dune-project
Normal file
3
unikernel/duniverse/ke/dune-project
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(lang dune 2.0)
|
||||
(name ke)
|
||||
(version v0.6)
|
||||
3
unikernel/duniverse/ke/example/dune
Normal file
3
unikernel/duniverse/ke/example/dune
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(name packer)
|
||||
(libraries psq ke jsonm fmt rresult cmdliner ocplib-json-typed lwt lwt.unix))
|
||||
323
unikernel/duniverse/ke/example/packer.ml
Normal file
323
unikernel/duniverse/ke/example/packer.ml
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
let () = Printexc.record_backtrace true
|
||||
|
||||
module type GRAPH = sig
|
||||
type t
|
||||
type id
|
||||
type value
|
||||
type error = private [> `Not_found ]
|
||||
|
||||
val pp_error : error Fmt.t
|
||||
val preds : value -> id list
|
||||
val get : t -> id -> (value, error) result Lwt.t
|
||||
val compare : value -> value -> int
|
||||
end
|
||||
|
||||
module Make (Q : Ke.Sigs.R) (G : GRAPH with type id = nativeint) = struct
|
||||
open Lwt
|
||||
|
||||
exception Graph of G.error
|
||||
|
||||
module Node = struct
|
||||
type t = { value : G.value; mutable color : [ `White | `Black ] }
|
||||
|
||||
let compare a b = G.compare a.value b.value
|
||||
end
|
||||
|
||||
module Pq = Psq.Make (Nativeint) (Node)
|
||||
module Map = Map.Make (Nativeint)
|
||||
|
||||
let pack graph exclude roots =
|
||||
let store = Hashtbl.create 128 in
|
||||
let memoize get id =
|
||||
try
|
||||
let ret = Hashtbl.find store id in
|
||||
Lwt.return (Some ret)
|
||||
with Not_found -> (
|
||||
get id >>= function
|
||||
| Ok value ->
|
||||
let node = { Node.value; color = `White } in
|
||||
Hashtbl.add store id node;
|
||||
Lwt.return (Some node)
|
||||
| Error `Not_found -> Lwt.return None
|
||||
| Error err -> Lwt.fail (Graph err))
|
||||
in
|
||||
let preds v = G.preds v in
|
||||
let get = memoize (G.get graph) in
|
||||
let all_blacks pq =
|
||||
Pq.fold
|
||||
(fun _ -> function
|
||||
| { Node.color = `Black; _ } -> ( && ) true
|
||||
| _ -> ( && ) false)
|
||||
true pq
|
||||
in
|
||||
let propagate { Node.value; color } =
|
||||
let p = preds value in
|
||||
let q = Q.create ~capacity:(List.length p) Bigarray.Nativeint in
|
||||
let rec go () =
|
||||
match Q.pop q with
|
||||
| Some id -> (
|
||||
try
|
||||
let node = Hashtbl.find store id in
|
||||
node.Node.color <- color;
|
||||
go (List.iter (Q.push q) (preds node.Node.value))
|
||||
with Not_found -> go ())
|
||||
| None -> ()
|
||||
in
|
||||
List.iter (Q.push q) p;
|
||||
go ()
|
||||
in
|
||||
let rec garbage pq =
|
||||
if all_blacks pq then Lwt.return ()
|
||||
else
|
||||
match Pq.pop pq with
|
||||
| Some ((_, { Node.value; color = `Black }), pq) ->
|
||||
Lwt_list.fold_left_s
|
||||
(fun pq id ->
|
||||
get id >>= function
|
||||
| Some ({ Node.color = `White; _ } as node) ->
|
||||
node.Node.color <- `Black;
|
||||
propagate node;
|
||||
Lwt.return (Pq.add id node pq)
|
||||
| Some node -> Lwt.return (Pq.add id node pq)
|
||||
| None -> Lwt.return pq)
|
||||
pq (preds value)
|
||||
>>= garbage
|
||||
| Some ((_, { Node.value; _ }), pq) ->
|
||||
Lwt_list.fold_left_s
|
||||
(fun pq id ->
|
||||
get id >>= function
|
||||
| None -> Lwt.return pq
|
||||
| Some node -> Lwt.return (Pq.add id node pq))
|
||||
pq (preds value)
|
||||
>>= garbage
|
||||
| None -> Lwt.return ()
|
||||
in
|
||||
let collect () =
|
||||
Hashtbl.fold
|
||||
(fun id -> function
|
||||
| { Node.color = `White; value } -> Map.add id value
|
||||
| _ -> fun acc -> acc)
|
||||
store Map.empty
|
||||
in
|
||||
Lwt_list.map_s
|
||||
(fun id ->
|
||||
get id >>= function
|
||||
| Some node -> Lwt.return (Some (id, node))
|
||||
| None -> Lwt.return None)
|
||||
roots
|
||||
>>= fun roots ->
|
||||
Lwt_list.map_s
|
||||
(fun id ->
|
||||
get id >>= function
|
||||
| Some node ->
|
||||
node.Node.color <- `Black;
|
||||
Lwt.return (Some (id, node))
|
||||
| None -> Lwt.return None)
|
||||
exclude
|
||||
>|= List.append roots
|
||||
>|= List.fold_left
|
||||
(fun acc -> function None -> acc | Some x -> x :: acc)
|
||||
[]
|
||||
>|= Pq.of_list
|
||||
>>= fun pq -> garbage pq >|= collect
|
||||
end
|
||||
|
||||
module Git = struct
|
||||
type t = unit
|
||||
type id = nativeint
|
||||
type value = { name : string; time : int64; ancestors : nativeint list }
|
||||
type error = [ `Not_found ]
|
||||
|
||||
let pp_error ppf = function `Not_found -> Fmt.string ppf "`Not_found"
|
||||
let store : (id, value) Hashtbl.t = Hashtbl.create 16
|
||||
let preds { ancestors; _ } = ancestors
|
||||
|
||||
let get () id =
|
||||
try Lwt.return_ok (Hashtbl.find store id)
|
||||
with Not_found -> Lwt.return_error `Not_found
|
||||
|
||||
let compare { time = a; _ } { time = b; _ } = Int64.compare a b
|
||||
end
|
||||
|
||||
module Packer = Make (Ke.Rke) (Git)
|
||||
|
||||
let json =
|
||||
let open Json_encoding in
|
||||
let name = req "name" string in
|
||||
let time = req "time" (conv Int64.to_string Int64.of_string string) in
|
||||
let ancestors =
|
||||
req "ancestors" (list (conv Nativeint.to_int32 Nativeint.of_int32 int32))
|
||||
in
|
||||
conv
|
||||
(fun { Git.name; time; ancestors } -> (name, time, ancestors))
|
||||
(fun (name, time, ancestors) -> { Git.name; time; ancestors })
|
||||
(obj3 name time ancestors)
|
||||
|
||||
type await = [ `Await ]
|
||||
type error = [ `Error of Jsonm.error ]
|
||||
type eoi = [ `End ]
|
||||
type value = [ `Null | `Bool of bool | `String of string | `Float of float ]
|
||||
|
||||
let pp_json ppf v =
|
||||
let rec pp_value ppf = function
|
||||
| `Bool v -> Fmt.bool ppf v
|
||||
| `String v -> Fmt.quote Fmt.text ppf v
|
||||
| `Float v -> Fmt.float ppf v
|
||||
| `Null -> Fmt.string ppf "<null>"
|
||||
| `A l -> pp_arr ppf l
|
||||
| `O l -> pp_obj ppf l
|
||||
and pp_arr ppf arr = Fmt.(using Array.of_list (Dump.array pp_value)) ppf arr
|
||||
and pp_obj ppf obj =
|
||||
Fmt.Dump.iter_bindings
|
||||
(fun f -> List.iter (fun (k, v) -> f k v))
|
||||
Fmt.(any "object")
|
||||
Fmt.string pp_value ppf obj
|
||||
in
|
||||
pp_value ppf v
|
||||
|
||||
let of_database ic : Git.value list =
|
||||
let decoder = Jsonm.decoder (`Channel ic) in
|
||||
|
||||
let error (`Error err) = Fmt.invalid_arg "%a" Jsonm.pp_error err in
|
||||
let end_of_input `End = Fmt.invalid_arg "Unexpected end of input" in
|
||||
|
||||
let rec arr acc k =
|
||||
match Jsonm.decode decoder with
|
||||
| #await -> assert false
|
||||
| #error as v -> error v
|
||||
| #eoi as v -> end_of_input v
|
||||
| `Lexeme `Ae -> k (`A (List.rev acc))
|
||||
| `Lexeme v -> base (fun v -> arr (v :: acc) k) v
|
||||
and name n k =
|
||||
match Jsonm.decode decoder with
|
||||
| #await -> assert false
|
||||
| #error as v -> error v
|
||||
| #eoi as v -> end_of_input v
|
||||
| `Lexeme v -> base (fun v -> k (n, v)) v
|
||||
and obj acc k =
|
||||
match Jsonm.decode decoder with
|
||||
| #await -> assert false
|
||||
| #error as v -> error v
|
||||
| #eoi as v -> end_of_input v
|
||||
| `Lexeme `Oe -> k (`O (List.rev acc))
|
||||
| `Lexeme (`Name n) -> name n (fun v -> obj (v :: acc) k)
|
||||
| `Lexeme v -> Fmt.invalid_arg "Unexpected lexeme: %a" Jsonm.pp_lexeme v
|
||||
and base k = function
|
||||
| #value as v -> k v
|
||||
| `Os -> obj [] k
|
||||
| `As -> arr [] k
|
||||
| `Ae | `Oe -> Fmt.invalid_arg "Unexpected end of array/object"
|
||||
| `Name n -> Fmt.invalid_arg "Unexpected key: %s" n
|
||||
in
|
||||
|
||||
let go k =
|
||||
match Jsonm.decode decoder with
|
||||
| #await -> assert false
|
||||
| #error as v -> error v
|
||||
| #eoi as v -> end_of_input v
|
||||
| `Lexeme (#Jsonm.lexeme as lexeme) -> base k lexeme
|
||||
in
|
||||
|
||||
go Json_encoding.(destruct (list json))
|
||||
|
||||
let flat_json json : Jsonm.lexeme list =
|
||||
let rec arr acc k = function
|
||||
| [] -> k (List.rev (`Ae :: acc))
|
||||
| (#value as x) :: r -> arr (x :: acc) k r
|
||||
| `A l :: r -> arr [ `As ] (fun l -> arr (List.rev_append l acc) k r) l
|
||||
| `O l :: r -> obj [ `Os ] (fun l -> arr (List.rev_append l acc) k r) l
|
||||
and obj acc k = function
|
||||
| [] -> k (List.rev (`Oe :: acc))
|
||||
| (n, x) :: r ->
|
||||
base (fun v -> obj (List.rev_append v (`Name n :: acc)) k r) x
|
||||
and base k = function
|
||||
| `A l -> arr [ `As ] k l
|
||||
| `O l -> obj [ `Os ] k l
|
||||
| #value as x -> k [ x ]
|
||||
in
|
||||
|
||||
base (fun l -> l) json
|
||||
|
||||
external identity : 'a -> 'a = "%identity"
|
||||
|
||||
let show ppf map =
|
||||
let json =
|
||||
Json_encoding.(
|
||||
construct (list json) (List.map snd (Packer.Map.bindings map)))
|
||||
in
|
||||
let raw = Bytes.create 0x800 in
|
||||
let encoder = Jsonm.encoder `Manual in
|
||||
let rec write k = function
|
||||
| `Ok -> k ()
|
||||
| `Partial ->
|
||||
Fmt.string ppf (Bytes.sub_string raw 0 (Jsonm.Manual.dst_rem encoder));
|
||||
Jsonm.Manual.dst encoder raw 0 (Bytes.length raw);
|
||||
write k (Jsonm.encode encoder `Await)
|
||||
in
|
||||
let rec go k = function
|
||||
| [] -> write k (Jsonm.encode encoder `End)
|
||||
| lexeme :: r ->
|
||||
write (fun () -> go k r) (Jsonm.encode encoder (`Lexeme lexeme))
|
||||
in
|
||||
let lexemes = flat_json json in
|
||||
go identity lexemes
|
||||
|
||||
let run database exclude roots =
|
||||
let graph = of_database (open_in database) in
|
||||
let () =
|
||||
List.iteri
|
||||
(fun id value -> Hashtbl.add Git.store (Nativeint.of_int id) value)
|
||||
graph
|
||||
in
|
||||
match
|
||||
Lwt_main.run
|
||||
Lwt.Infix.(
|
||||
Packer.pack () exclude roots >|= Fmt.fmt "%a\n%!" Fmt.stdout show)
|
||||
with
|
||||
| () -> `Ok ()
|
||||
| exception Packer.Graph err ->
|
||||
`Error (false, Fmt.str "Retrieve an error: %a." Git.pp_error err)
|
||||
|
||||
open Cmdliner
|
||||
|
||||
let database =
|
||||
let parser s =
|
||||
if Sys.file_exists s then Ok s
|
||||
else Rresult.R.error_msgf "File %s does not exists" s
|
||||
in
|
||||
let pp = Fmt.string in
|
||||
Arg.conv (parser, pp)
|
||||
|
||||
let id =
|
||||
let parser s =
|
||||
match Nativeint.of_string_opt s with
|
||||
| Some n -> Ok n
|
||||
| None -> Rresult.R.error_msgf "Invalid id: %s" s
|
||||
in
|
||||
let pp = Fmt.nativeint in
|
||||
Arg.conv (parser, pp)
|
||||
|
||||
let database =
|
||||
let doc = "Database of graph." in
|
||||
Arg.(
|
||||
required
|
||||
& opt (some database) None
|
||||
& info [ "d"; "database" ] ~doc ~docv:"<FILE>")
|
||||
|
||||
let roots =
|
||||
let doc = "Roots of graph." in
|
||||
Arg.(non_empty & opt (list id) [] & info [ "r"; "roots" ] ~doc ~docv:"<LST>")
|
||||
|
||||
let exclude =
|
||||
let doc = "Excluded nodes of graph." in
|
||||
Arg.(
|
||||
non_empty & opt (list id) [] & info [ "e"; "exclude" ] ~doc ~docv:"<LST>")
|
||||
|
||||
let command =
|
||||
let doc = "Example of ke." in
|
||||
let exits = Cmd.Exit.defaults in
|
||||
Cmd.v
|
||||
(Cmd.info "packer" ~version:"dev" ~doc ~exits)
|
||||
Term.(ret (const run $ database $ exclude $ roots))
|
||||
|
||||
let () = Cmd.(exit @@ eval command)
|
||||
3
unikernel/duniverse/ke/fuzz/dune
Normal file
3
unikernel/duniverse/ke/fuzz/dune
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(name fuzz)
|
||||
(libraries crowbar bigstringaf ke))
|
||||
278
unikernel/duniverse/ke/fuzz/fuzz.ml
Normal file
278
unikernel/duniverse/ke/fuzz/fuzz.ml
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
type 'a action = Push of 'a * 'a action | Pop of 'a action | Empty
|
||||
|
||||
exception Invalid
|
||||
|
||||
external identity : 'a -> 'a = "%identity"
|
||||
|
||||
let valid a =
|
||||
let rec go k = function
|
||||
| Empty -> k 0
|
||||
| Push (_, a) -> go (fun len -> k (succ len)) a
|
||||
| Pop a -> go (function 0 -> raise Invalid | n -> k (pred n)) a
|
||||
in
|
||||
go identity a
|
||||
|
||||
let push x a = Push (x, a)
|
||||
let empty = Empty
|
||||
let pop a = Pop a
|
||||
let () = assert (valid empty = 0)
|
||||
let () = assert (valid (push 0 empty) = 1)
|
||||
let () = assert (valid (push 1 (push 0 empty)) = 2)
|
||||
let () = assert (valid (pop (push 0 empty)) = 0)
|
||||
|
||||
let () =
|
||||
assert (match valid (pop empty) with _ -> false | exception Invalid -> true)
|
||||
|
||||
module Peano = struct type zero = Zero type 'a succ = Succ end
|
||||
module Refl = struct type ('a, 'b) t = Refl : ('a, 'a) t end
|
||||
|
||||
module Value = struct
|
||||
type 'a value =
|
||||
| Zero : Peano.zero value
|
||||
| Succ : 'a value -> 'a Peano.succ value
|
||||
|
||||
type t = V : 'a value -> t
|
||||
|
||||
let of_int n =
|
||||
let rec go k = function
|
||||
| 0 -> k (V Zero)
|
||||
| n -> go (fun (V n) -> k (V (Succ n))) (pred n)
|
||||
in
|
||||
if n < 0 then Fmt.invalid_arg "Value.of_int" else go identity n
|
||||
|
||||
let to_int v =
|
||||
let rec go : type a. (int -> 'r) -> a value -> 'r =
|
||||
fun k -> function Zero -> k 0 | Succ x -> go (fun v -> k (succ v)) x
|
||||
in
|
||||
go identity v
|
||||
|
||||
let () = assert (to_int Zero = 0)
|
||||
let () = assert (to_int (Succ Zero) = 1)
|
||||
let () = assert (to_int (Succ (Succ Zero)) = 2)
|
||||
let pp : t Fmt.t = fun ppf (V v) -> Fmt.int ppf (to_int v)
|
||||
|
||||
let is_zero : type a. a value -> (a, Peano.zero) Refl.t option = function
|
||||
| Zero -> Some Refl.Refl
|
||||
| Succ _ -> None
|
||||
|
||||
type 'a is_not_zero =
|
||||
| Is_not_zero : ('a, _ Peano.succ) Refl.t -> 'a is_not_zero
|
||||
|
||||
let is_not_zero : type a. a value -> a is_not_zero option = function
|
||||
| Zero -> None
|
||||
| Succ _ -> Some (Is_not_zero Refl.Refl)
|
||||
end
|
||||
|
||||
module Stack = struct
|
||||
type ('a, 'l) action =
|
||||
| Push : 'a * ('a, 'l) action -> ('a, 'l Peano.succ) action
|
||||
| Pop : ('a, 'l Peano.succ) action -> ('a, 'l) action
|
||||
| Empty : ('a, Peano.zero) action
|
||||
|
||||
type 'a t = V : ('a, 'l) action -> 'a t
|
||||
|
||||
let rec pp : type l. 'a Fmt.t -> ('a, l) action Fmt.t =
|
||||
fun pp_elt ppf -> function
|
||||
| Push (v, a) ->
|
||||
Fmt.pf ppf "@[<1>(Push %a)]" Fmt.(Dump.pair pp_elt (pp pp_elt)) (v, a)
|
||||
| Pop a -> Fmt.pf ppf "@[<1>(Pop %a)]" (pp pp_elt) a
|
||||
| Empty -> Fmt.pf ppf "Empty"
|
||||
|
||||
let rec length : type a l. (a, l) action -> l Value.value = function
|
||||
| Empty -> Value.Zero
|
||||
| Pop a -> ( match length a with Value.Succ x -> x)
|
||||
| Push (_, a) -> Value.Succ (length a)
|
||||
|
||||
let is_empty : type l. ('a, l) action -> (l, Peano.zero) Refl.t option =
|
||||
function
|
||||
| Empty -> Some Refl.Refl
|
||||
| Push _ -> None
|
||||
| Pop a -> (
|
||||
match length a with
|
||||
| Value.Succ Value.Zero -> Some Refl.Refl
|
||||
| Value.Succ _ -> None)
|
||||
|
||||
type 'a is_not_empty =
|
||||
| Is_not_empty : ('a, _ Peano.succ) Refl.t -> 'a is_not_empty
|
||||
|
||||
let is_not_empty : type l. ('a, l) action -> l is_not_empty option = function
|
||||
| Empty -> None
|
||||
| Push _ -> Some (Is_not_empty Refl.Refl)
|
||||
| Pop a -> (
|
||||
match length a with
|
||||
| Value.Succ Value.Zero -> None
|
||||
| Value.Succ (Value.Succ _) -> Some (Is_not_empty Refl.Refl))
|
||||
end
|
||||
|
||||
open Crowbar
|
||||
|
||||
type tree = Tree of Value.t * tree list * bool
|
||||
|
||||
let rec list_of_tree (Tree (v, x, pop)) : [ `Push of Value.t | `Pop ] list =
|
||||
if pop then [ `Push v ] @ List.concat (List.map list_of_tree x) @ [ `Pop ]
|
||||
else [ `Push v ] @ List.concat (List.map list_of_tree x)
|
||||
|
||||
let generate : tree gen =
|
||||
let value = map [ range 30 ] Value.of_int in
|
||||
fix @@ fun m -> map [ value; list m; bool ] (fun v l pop -> Tree (v, l, pop))
|
||||
|
||||
let action_of_tree tree : Value.t Stack.t =
|
||||
let lst = list_of_tree tree in
|
||||
List.fold_left
|
||||
(fun (Stack.V acc) -> function
|
||||
| `Push v -> Stack.(V (Push (v, acc)))
|
||||
| `Pop -> (
|
||||
match Stack.is_not_empty acc with
|
||||
| Some (Stack.Is_not_empty Refl.Refl) -> Stack.V (Stack.Pop acc)
|
||||
| None -> bad_test ()))
|
||||
Stack.(V Empty)
|
||||
lst
|
||||
|
||||
(* XXX(dinosaure): [Stdlib.Queue] is oracle. *)
|
||||
|
||||
module Compare = struct
|
||||
exception Not_equal
|
||||
|
||||
let fke q fke =
|
||||
let q' = Queue.copy q in
|
||||
try
|
||||
Ke.Fke.iter
|
||||
(fun x ->
|
||||
let x' = Queue.pop q' in
|
||||
if x <> x' then raise Not_equal)
|
||||
fke;
|
||||
true
|
||||
with Not_equal | Queue.Empty -> false
|
||||
|
||||
let rke q rke =
|
||||
let q' = Queue.copy q in
|
||||
try
|
||||
Ke.Rke.iter
|
||||
(fun x ->
|
||||
let x' = Queue.pop q' in
|
||||
if x <> x' then raise Not_equal)
|
||||
rke;
|
||||
true
|
||||
with Not_equal | Queue.Empty -> false
|
||||
end
|
||||
|
||||
let iter iter pp_name pp_elt ppf v =
|
||||
let is_first = ref true in
|
||||
let pp_elt v =
|
||||
if !is_first then is_first := false else Fmt.pf ppf "@ ";
|
||||
Fmt.pf ppf "@[%a@]" pp_elt v
|
||||
in
|
||||
Fmt.pf ppf "@[<1>(%a@ " pp_name v;
|
||||
iter pp_elt v;
|
||||
Fmt.pf ppf ")@]"
|
||||
|
||||
let pp_fke pp_elt = iter Ke.Fke.iter (Fmt.any "fke") pp_elt
|
||||
let pp_rke pp_elt = iter Ke.Rke.iter (Fmt.any "rke") pp_elt
|
||||
|
||||
let rke_of_action a =
|
||||
let q =
|
||||
Ke.Rke.create ~capacity:(Value.to_int (Stack.length a)) Bigarray.Int
|
||||
in
|
||||
let rec go : type l. (Value.t, l) Stack.action -> unit = function
|
||||
| Stack.Empty -> ()
|
||||
| Stack.Push (Value.V v, a) ->
|
||||
go a;
|
||||
Ke.Rke.push q (Value.to_int v)
|
||||
| Stack.Pop a ->
|
||||
go a;
|
||||
ignore @@ Ke.Rke.pop_exn q
|
||||
in
|
||||
go a;
|
||||
q
|
||||
|
||||
let queue_of_action a =
|
||||
let q = Queue.create () in
|
||||
let rec go : type l. (Value.t, l) Stack.action -> unit = function
|
||||
| Stack.Empty -> ()
|
||||
| Stack.Push (Value.V v, a) ->
|
||||
go a;
|
||||
Queue.push (Value.to_int v) q
|
||||
| Stack.Pop a ->
|
||||
go a;
|
||||
ignore @@ Queue.pop q
|
||||
in
|
||||
go a;
|
||||
q
|
||||
|
||||
let fke_of_action a =
|
||||
let rec go : type l. (int Ke.Fke.t -> 'r) -> (Value.t, l) Stack.action -> 'r =
|
||||
fun k -> function
|
||||
| Stack.Empty -> k Ke.Fke.empty
|
||||
| Stack.Push (Value.V v, a) ->
|
||||
go
|
||||
(fun q ->
|
||||
let q = Ke.Fke.push q (Value.to_int v) in
|
||||
k q)
|
||||
a
|
||||
| Stack.Pop a ->
|
||||
go
|
||||
(fun q ->
|
||||
let _, q = Ke.Fke.pop_exn q in
|
||||
k q)
|
||||
a
|
||||
in
|
||||
go identity a
|
||||
|
||||
let () =
|
||||
add_test ~name:"queue" [ map [ generate ] action_of_tree ]
|
||||
@@ fun (Stack.V a) ->
|
||||
let fke = fke_of_action a in
|
||||
let rke = rke_of_action a in
|
||||
let queue = queue_of_action a in
|
||||
if not (Compare.fke queue fke) then
|
||||
failf "%a <> %a" Fmt.(Dump.queue int) queue (pp_fke Fmt.int) fke;
|
||||
if not (Compare.rke queue rke) then
|
||||
failf "%a <> %a" Fmt.(Dump.queue int) queue (pp_rke Fmt.int) rke;
|
||||
()
|
||||
|
||||
let ( >>= ) = dynamic_bind
|
||||
let failf fmt = Fmt.kstr fail fmt
|
||||
|
||||
let blit src src_off dst dst_off len =
|
||||
let a = Bigarray.Array1.sub src src_off len in
|
||||
let b = Bigarray.Array1.sub dst dst_off len in
|
||||
Bigarray.Array1.blit a b
|
||||
|
||||
let blit_from_string src src_off dst dst_off len =
|
||||
Bigstringaf.blit_from_string src ~src_off dst ~dst_off ~len
|
||||
|
||||
let () =
|
||||
add_test ~name:"compress-and-push"
|
||||
[ range 0x100 >>= bytes_fixed; range 0x100 >>= bytes_fixed ]
|
||||
@@ fun fill0 fill1 ->
|
||||
let capacity = String.length fill0 + String.length fill1 in
|
||||
let q, capacity = Ke.Rke.Weighted.create ~capacity Bigarray.Char in
|
||||
match
|
||||
Ke.Rke.Weighted.N.push q ~blit:blit_from_string ~length:String.length fill0
|
||||
with
|
||||
| Some [ fill0' ] -> (
|
||||
let fill0' = Bigstringaf.create (Bigstringaf.length fill0') in
|
||||
Ke.Rke.Weighted.compress q;
|
||||
Ke.Rke.Weighted.N.keep_exn q ~blit ~length:Bigstringaf.length fill0';
|
||||
match
|
||||
Ke.Rke.Weighted.N.push q ~blit:blit_from_string ~length:String.length
|
||||
fill1
|
||||
with
|
||||
| Some [ fill1' ] ->
|
||||
let a =
|
||||
Bigstringaf.memcmp_string fill0' 0 fill0 0 (String.length fill0)
|
||||
in
|
||||
let b =
|
||||
Bigstringaf.memcmp_string fill1' 0 fill1 0 (String.length fill1)
|
||||
in
|
||||
if a <> 0 || b <> 0 then failf "Queue differs from inputs"
|
||||
| Some _ -> failf "push returns multiple payloads"
|
||||
| None ->
|
||||
if String.length fill0 + String.length fill1 <= capacity then
|
||||
failf "push fails for unknow reason"
|
||||
else bad_test ())
|
||||
| Some _ -> failf "push returns multiple payloads."
|
||||
| None ->
|
||||
if String.length fill0 <= capacity then
|
||||
failf "push fails for unknow reason"
|
||||
else bad_test ()
|
||||
34
unikernel/duniverse/ke/ke.opam
Normal file
34
unikernel/duniverse/ke/ke.opam
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
version: "0.6"
|
||||
opam-version: "2.0"
|
||||
name: "ke"
|
||||
maintainer: "Romain Calascibetta <romain.calascibetta@gmail.com>"
|
||||
authors: "Romain Calascibetta <romain.calascibetta@gmail.com>"
|
||||
homepage: "https://github.com/mirage/ke"
|
||||
bug-reports: "https://github.com/mirage/ke/issues"
|
||||
dev-repo: "git+https://github.com/mirage/ke.git"
|
||||
doc: "https://mirage.github.io/ke/"
|
||||
license: "MIT"
|
||||
synopsis: "Queue implementation"
|
||||
description: """Queue implementation in OCaml (functional and imperative queue)"""
|
||||
|
||||
build: [ "dune" "build" "-p" name "-j" jobs ]
|
||||
run-test: [ "dune" "runtest" "-p" name "-j" jobs ]
|
||||
|
||||
depends: [
|
||||
"ocaml" {>= "4.08.0"}
|
||||
"dune" {>= "2.0"}
|
||||
"fmt" {>= "0.8.7"}
|
||||
"alcotest" {with-test}
|
||||
"bigstringaf" {with-test}
|
||||
"bechamel" {with-test}
|
||||
"bechamel-notty" {with-test}
|
||||
"bechamel-perf" {with-test}
|
||||
"ocplib-json-typed" {with-test}
|
||||
"core_bench" {with-test & >= "v0.15"}
|
||||
"lwt" {with-test}
|
||||
"crowbar" {with-test}
|
||||
"rresult" {with-test}
|
||||
"jsonm" {with-test}
|
||||
"psq" {with-test}
|
||||
"cmdliner" {>= "1.1.0" & with-test}
|
||||
]
|
||||
4
unikernel/duniverse/ke/lib/dune
Normal file
4
unikernel/duniverse/ke/lib/dune
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
(library
|
||||
(name ke)
|
||||
(public_name ke)
|
||||
(libraries fmt))
|
||||
352
unikernel/duniverse/ke/lib/fke.ml
Normal file
352
unikernel/duniverse/ke/lib/fke.ml
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
[@@@warning "-37"]
|
||||
|
||||
module Peano = struct
|
||||
type zero = Zero
|
||||
type 'a succ = Succ
|
||||
type one = zero succ
|
||||
type two = zero succ succ
|
||||
type three = zero succ succ
|
||||
end
|
||||
|
||||
type ('a, 'l) digit =
|
||||
| Zero : ('a, Peano.zero) digit
|
||||
| One : 'a -> ('a, Peano.one) digit
|
||||
| Two : 'a * 'a -> ('a, Peano.two) digit
|
||||
| Three : 'a * 'a * 'a -> ('a, Peano.three) digit
|
||||
|
||||
type 'a t =
|
||||
| Shallow : ('a, 'l) digit -> 'a t
|
||||
| Deep : {
|
||||
s : int;
|
||||
f : ('a, 'f Peano.succ) digit;
|
||||
m : ('a * 'a) t Lazy.t;
|
||||
r : ('a, 'r Peano.succ) digit;
|
||||
}
|
||||
-> 'a t
|
||||
|
||||
let empty = Shallow Zero
|
||||
|
||||
exception Empty
|
||||
|
||||
let _one x = Shallow (One x)
|
||||
let _two x y = Shallow (Two (x, y))
|
||||
let _three x y z = Shallow (Three (x, y, z))
|
||||
let _deep s f m r = Deep { s; f; m; r }
|
||||
|
||||
let is_empty : type a. a t -> bool = function
|
||||
| Shallow Zero -> true
|
||||
| Shallow _ | Deep _ -> false
|
||||
|
||||
let rec push : type a. a t -> a -> a t =
|
||||
fun q x ->
|
||||
match q with
|
||||
| Shallow Zero -> _one x
|
||||
| Shallow (One y) -> _two y x
|
||||
| Shallow (Two (y, z)) -> _three y z x
|
||||
| Shallow (Three (a, b, c)) ->
|
||||
_deep 4 (Two (a, b)) (Lazy.from_val empty) (Two (c, x))
|
||||
| Deep { s; f; m; r = One y } -> _deep (s + 1) f m (Two (y, x))
|
||||
| Deep { s; f; m; r = Two (y, z) } -> _deep (s + 1) f m (Three (y, z, x))
|
||||
| Deep { s; f; m = (lazy q'); r = Three (y, z, z') } ->
|
||||
_deep (s + 1) f (lazy (push q' (y, z))) (Two (z', x))
|
||||
|
||||
let rec pop_exn : type a. a t -> a * a t =
|
||||
fun q ->
|
||||
match q with
|
||||
| Shallow Zero -> raise Empty
|
||||
| Shallow (One x) -> (x, empty)
|
||||
| Shallow (Two (x, y)) -> (x, _one y)
|
||||
| Shallow (Three (x, y, z)) -> (x, _two y z)
|
||||
| Deep { s; f = One x; m = (lazy q'); r } ->
|
||||
if is_empty q' then (x, Shallow r)
|
||||
else
|
||||
let (y, z), q' = pop_exn q' in
|
||||
(x, _deep (s - 1) (Two (y, z)) (Lazy.from_val q') r)
|
||||
| Deep { s; f = Two (x, y); m; r } -> (x, _deep (s - 1) (One y) m r)
|
||||
| Deep { s; f = Three (x, y, z); m; r } -> (x, _deep (s - 1) (Two (y, z)) m r)
|
||||
|
||||
let rec tail_exn : type a. a t -> a t * a =
|
||||
fun q ->
|
||||
match q with
|
||||
| Shallow Zero -> raise Empty
|
||||
| Shallow (One x) -> (empty, x)
|
||||
| Shallow (Two (x, y)) -> (_one x, y)
|
||||
| Shallow (Three (x, y, z)) -> (_two x y, z)
|
||||
| Deep { s; f; m = (lazy q'); r = One x } ->
|
||||
if is_empty q' then (Shallow f, x)
|
||||
else
|
||||
let q'', (y, z) = tail_exn q' in
|
||||
(_deep (s - 1) f (Lazy.from_val q'') (Two (y, z)), x)
|
||||
| Deep { s; f; m; r = Two (x, y) } -> (_deep (s - 1) f m (One x), y)
|
||||
| Deep { s; f; m; r = Three (x, y, z) } -> (_deep (s - 1) f m (Two (x, y)), z)
|
||||
|
||||
let peek_exn : type a. a t -> a =
|
||||
fun q ->
|
||||
match q with
|
||||
| Shallow Zero -> raise Empty
|
||||
| Shallow (One x) -> x
|
||||
| Shallow (Two (x, _)) -> x
|
||||
| Shallow (Three (x, _, _)) -> x
|
||||
| Deep { f = One x; _ } -> x
|
||||
| Deep { f = Two (x, _); _ } -> x
|
||||
| Deep { f = Three (x, _, _); _ } -> x
|
||||
|
||||
let pop q = try Some (pop_exn q) with Empty -> None
|
||||
let tail q = try Some (tail_exn q) with Empty -> None
|
||||
let peek q = try Some (peek_exn q) with Empty -> None
|
||||
|
||||
let rec cons : type a. a t -> a -> a t =
|
||||
fun q x ->
|
||||
match q with
|
||||
| Shallow Zero -> _one x
|
||||
| Shallow (One y) -> _two x y
|
||||
| Shallow (Two (y, z)) -> _three x y z
|
||||
| Shallow (Three (y, z, z')) ->
|
||||
_deep 4 (Two (x, y)) (Lazy.from_val empty) (Two (z, z'))
|
||||
| Deep { s; f = One y; m; r } -> _deep (s + 1) (Two (x, y)) m r
|
||||
| Deep { s; f = Two (y, z); m; r } -> _deep (s + 1) (Three (x, y, z)) m r
|
||||
| Deep { s; f = Three (y, z, z'); m = (lazy q'); r } ->
|
||||
_deep (s + 1) (Three (x, y, z)) (lazy (cons q' (z, z'))) r
|
||||
|
||||
let iter : type a. (a -> unit) -> a t -> unit =
|
||||
fun f q ->
|
||||
let rec go : type a. (a -> unit) -> a t -> unit =
|
||||
fun f -> function
|
||||
| Shallow Zero -> ()
|
||||
| Shallow (One x) -> f x
|
||||
| Shallow (Two (x, y)) ->
|
||||
f x;
|
||||
f y
|
||||
| Shallow (Three (x, y, z)) ->
|
||||
f x;
|
||||
f y;
|
||||
f z
|
||||
| Deep { f = hd; m = (lazy q); r = tl; _ } ->
|
||||
go f (Shallow hd);
|
||||
go
|
||||
(fun (x, y) ->
|
||||
f x;
|
||||
f y)
|
||||
q;
|
||||
go f (Shallow tl)
|
||||
in
|
||||
go f q
|
||||
|
||||
let rev_iter : type a. (a -> unit) -> a t -> unit =
|
||||
fun f q ->
|
||||
let rec go : type a. (a -> unit) -> a t -> unit =
|
||||
fun f -> function
|
||||
| Shallow Zero -> ()
|
||||
| Shallow (One x) -> f x
|
||||
| Shallow (Two (y, x)) ->
|
||||
f x;
|
||||
f y
|
||||
| Shallow (Three (z, y, x)) ->
|
||||
f x;
|
||||
f y;
|
||||
f z
|
||||
| Deep { f = hd; m = (lazy q); r = tl; _ } ->
|
||||
go f (Shallow tl);
|
||||
go
|
||||
(fun (y, x) ->
|
||||
f x;
|
||||
f y)
|
||||
q;
|
||||
go f (Shallow hd)
|
||||
in
|
||||
go f q
|
||||
|
||||
let fold : type acc x. (acc -> x -> acc) -> acc -> x t -> acc =
|
||||
fun f a q ->
|
||||
let rec go : type acc x. (acc -> x -> acc) -> acc -> x t -> acc =
|
||||
fun f a -> function
|
||||
| Shallow Zero -> a
|
||||
| Shallow (One x) -> f a x
|
||||
| Shallow (Two (x, y)) -> f (f a x) y
|
||||
| Shallow (Three (x, y, z)) -> f (f (f a x) y) z
|
||||
| Deep { f = hd; m = (lazy q); r = tl; _ } ->
|
||||
let a = go f a (Shallow hd) in
|
||||
let a = go (fun a (x, y) -> f (f a x) y) a q in
|
||||
go f a (Shallow tl)
|
||||
in
|
||||
go f a q
|
||||
|
||||
let length = function
|
||||
| Deep { s; _ } -> s
|
||||
| Shallow Zero -> 0
|
||||
| Shallow (One _) -> 1
|
||||
| Shallow (Two _) -> 2
|
||||
| Shallow (Three _) -> 3
|
||||
|
||||
let pp ?sep pp_elt = Fmt.iter ?sep iter pp_elt
|
||||
let dump pp_elt = Fmt.Dump.iter iter (Fmt.any "fke") pp_elt
|
||||
|
||||
module Weighted = struct
|
||||
type ('a, 'b) t = {
|
||||
r : int;
|
||||
w : int;
|
||||
c : int;
|
||||
k : ('a, 'b) Bigarray.kind;
|
||||
v : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t;
|
||||
}
|
||||
|
||||
exception Empty
|
||||
exception Full
|
||||
|
||||
let[@inline always] mask t v = v land (t.c - 1)
|
||||
let[@inline always] empty t = t.r = t.w
|
||||
let[@inline always] size t = t.w - t.r
|
||||
let[@inline always] full t = size t = t.c
|
||||
let[@inline always] available t = t.c - (t.w - t.r)
|
||||
let is_empty t = (empty [@inlined]) t
|
||||
let length q = size q
|
||||
|
||||
let[@inline always] to_power_of_two v =
|
||||
let res = ref (pred v) in
|
||||
res := !res lor (!res lsr 1);
|
||||
res := !res lor (!res lsr 2);
|
||||
res := !res lor (!res lsr 4);
|
||||
res := !res lor (!res lsr 8);
|
||||
res := !res lor (!res lsr 16);
|
||||
succ !res
|
||||
|
||||
let[@inline always] is_power_of_two v = v <> 0 && v land (lnot v + 1) = v
|
||||
|
||||
let create ?capacity kind =
|
||||
let capacity =
|
||||
match capacity with
|
||||
| None | Some 0 -> 1
|
||||
| Some n ->
|
||||
if n < 0 then Fmt.invalid_arg "Rke.Weighted.create"
|
||||
else to_power_of_two n
|
||||
in
|
||||
( {
|
||||
r = 0;
|
||||
w = 0;
|
||||
c = capacity;
|
||||
k = kind;
|
||||
v = Bigarray.Array1.create kind Bigarray.c_layout capacity;
|
||||
},
|
||||
capacity )
|
||||
|
||||
let copy t =
|
||||
let v = Bigarray.Array1.create t.k Bigarray.c_layout t.c in
|
||||
Bigarray.Array1.blit t.v v;
|
||||
{ r = t.r; w = t.w; c = t.c; v; k = t.k }
|
||||
|
||||
let from v =
|
||||
if not (is_power_of_two (Bigarray.Array1.dim v)) then
|
||||
Fmt.invalid_arg "RBA.from";
|
||||
let c = Bigarray.Array1.dim v in
|
||||
let k = Bigarray.Array1.kind v in
|
||||
{ r = 0; w = 0; c; k; v }
|
||||
|
||||
let push_exn t v =
|
||||
if (full [@inlined]) t then raise Full;
|
||||
Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t t.w) v;
|
||||
{ t with w = t.w + 1 }
|
||||
|
||||
let push t v = try Some (push_exn t v) with Full -> None
|
||||
|
||||
let cons_exn t v =
|
||||
if (full [@inlined]) t then raise Full;
|
||||
let i = t.r - 1 in
|
||||
Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t i) v;
|
||||
{ t with r = i }
|
||||
|
||||
let cons t v = try Some (cons_exn t v) with Full -> None
|
||||
|
||||
let pop_exn t =
|
||||
if (empty [@inlined]) t then raise Empty;
|
||||
let r = Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r) in
|
||||
(r, { t with r = t.r + 1 })
|
||||
|
||||
let pop t = try Some (pop_exn t) with Empty -> None
|
||||
|
||||
let peek_exn t =
|
||||
if (empty [@inlined]) t then raise Empty;
|
||||
Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r)
|
||||
|
||||
let peek t = try Some (peek_exn t) with Empty -> None
|
||||
|
||||
module N = struct
|
||||
type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit
|
||||
type 'a length = 'a -> int
|
||||
|
||||
let push_exn t ~blit ~length ?(off = 0) ?len v =
|
||||
let len = match len with None -> length v - off | Some len -> len in
|
||||
if (available [@inlined]) t < len then raise Full;
|
||||
let msk = (mask [@inlined]) t t.w in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
let ret =
|
||||
if rst > 0 then (
|
||||
blit v off t.v msk pre;
|
||||
blit v (off + pre) t.v 0 rst;
|
||||
[
|
||||
Bigarray.Array1.sub t.v ((mask [@inlined]) t t.w) pre;
|
||||
Bigarray.Array1.sub t.v 0 rst;
|
||||
])
|
||||
else (
|
||||
blit v off t.v msk len;
|
||||
[ Bigarray.Array1.sub t.v ((mask [@inlined]) t t.w) len ])
|
||||
in
|
||||
(ret, { t with w = t.w + len })
|
||||
|
||||
let push t ~blit ~length ?off ?len v =
|
||||
try Some (push_exn t ~blit ~length ?off ?len v) with Full -> None
|
||||
|
||||
let keep_exn t ~blit ~length ?(off = 0) ?len v =
|
||||
let len = match len with None -> length v | Some len -> len in
|
||||
if (size [@inlined]) t < len then raise Empty;
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then (
|
||||
blit t.v msk v off pre;
|
||||
blit t.v 0 v (off + pre) rst)
|
||||
else blit t.v msk v off len
|
||||
|
||||
let keep t ~blit ~length ?off ?len v =
|
||||
try Some (keep_exn t ~blit ~length ?off ?len v) with Empty -> None
|
||||
|
||||
let unsafe_shift t len = { t with r = t.r + len }
|
||||
|
||||
let shift_exn t len =
|
||||
if (size [@inlined]) t < len then raise Empty;
|
||||
unsafe_shift t len
|
||||
|
||||
let shift t len = try Some (shift_exn t len) with Empty -> None
|
||||
end
|
||||
|
||||
let iter f t =
|
||||
let idx = ref t.r in
|
||||
let max = t.w in
|
||||
while !idx <> max do
|
||||
f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx));
|
||||
incr idx
|
||||
done
|
||||
|
||||
let rev_iter f t =
|
||||
if t.r == t.w then ()
|
||||
else
|
||||
let idx = ref (pred t.w) in
|
||||
let min = t.r in
|
||||
while
|
||||
f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx));
|
||||
!idx <> min
|
||||
do
|
||||
decr idx
|
||||
done
|
||||
|
||||
let fold f a t =
|
||||
let a = ref a in
|
||||
iter (fun x -> a := f !a x) t;
|
||||
!a
|
||||
|
||||
let clear t = { t with r = 0; w = 0 }
|
||||
let unsafe_bigarray { v; _ } = v
|
||||
let pp ?sep pp_elt = Fmt.iter ?sep iter pp_elt
|
||||
let dump pp_elt = Fmt.Dump.iter iter (Fmt.any "fke:weighted") pp_elt
|
||||
end
|
||||
2
unikernel/duniverse/ke/lib/fke.mli
Normal file
2
unikernel/duniverse/ke/lib/fke.mli
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
include Sigs.F
|
||||
module Weighted : Sigs.Weighted.F
|
||||
3
unikernel/duniverse/ke/lib/ke.ml
Normal file
3
unikernel/duniverse/ke/lib/ke.ml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module Sigs = Sigs
|
||||
module Fke = Fke
|
||||
module Rke = Rke
|
||||
3
unikernel/duniverse/ke/lib/ke.mli
Normal file
3
unikernel/duniverse/ke/lib/ke.mli
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module Sigs = Sigs
|
||||
module Fke = Fke
|
||||
module Rke = Rke
|
||||
400
unikernel/duniverse/ke/lib/rke.ml
Normal file
400
unikernel/duniverse/ke/lib/rke.ml
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
type ('a, 'b) t = {
|
||||
mutable r : int;
|
||||
mutable w : int;
|
||||
mutable c : int;
|
||||
k : ('a, 'b) Bigarray.kind;
|
||||
mutable v : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t;
|
||||
}
|
||||
|
||||
exception Empty
|
||||
|
||||
external ( = ) : 'a -> 'a -> bool = "%equal"
|
||||
|
||||
let ( = ) (a : int) b = a = b
|
||||
let[@inline always] mask t v = v land (t.c - 1)
|
||||
let[@inline always] empty t = t.r = t.w
|
||||
let[@inline always] size t = t.w - t.r
|
||||
let[@inline always] available t = t.c - (t.w - t.r)
|
||||
let[@inline always] full t = size t = t.c
|
||||
let length q = size q
|
||||
|
||||
let[@inline always] to_power_of_two v =
|
||||
let res = ref (pred v) in
|
||||
res := !res lor (!res lsr 1);
|
||||
res := !res lor (!res lsr 2);
|
||||
res := !res lor (!res lsr 4);
|
||||
res := !res lor (!res lsr 8);
|
||||
res := !res lor (!res lsr 16);
|
||||
succ !res
|
||||
|
||||
let[@inline always] is_power_of_two v = v <> 0 && v land (lnot v + 1) = v
|
||||
let is_empty t = (empty [@inlined]) t
|
||||
|
||||
let create ?capacity kind =
|
||||
let capacity =
|
||||
match capacity with
|
||||
| None | Some 0 -> 1
|
||||
| Some n ->
|
||||
if n < 0 then Fmt.invalid_arg "Rke.create" else to_power_of_two n
|
||||
in
|
||||
{
|
||||
r = 0;
|
||||
w = 0;
|
||||
c = capacity;
|
||||
k = kind;
|
||||
v = Bigarray.Array1.create kind Bigarray.c_layout capacity;
|
||||
}
|
||||
|
||||
let capacity { c; _ } = c
|
||||
|
||||
let copy t =
|
||||
let v = Bigarray.Array1.create t.k Bigarray.c_layout t.c in
|
||||
Bigarray.Array1.blit t.v v;
|
||||
{ r = t.r; w = t.w; c = t.c; v; k = t.k }
|
||||
|
||||
let grow t want =
|
||||
let max : int -> int -> int = max in
|
||||
let c = to_power_of_two (max 1 (max want (size t))) in
|
||||
if c <> Bigarray.Array1.dim t.v then (
|
||||
let dst = Bigarray.Array1.create t.k Bigarray.c_layout c in
|
||||
let sze = (size [@inlined]) t in
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = sze - pre in
|
||||
(if rst > 0 then (
|
||||
Bigarray.Array1.(blit (sub t.v msk pre) (sub dst 0 pre));
|
||||
Bigarray.Array1.(blit (sub t.v 0 rst) (sub dst pre rst)))
|
||||
else Bigarray.Array1.(blit (sub t.v msk sze) (sub dst 0 sze)));
|
||||
t.v <- dst;
|
||||
t.w <- sze;
|
||||
t.c <- c;
|
||||
t.r <- 0)
|
||||
|
||||
let push t v =
|
||||
if (full [@inlined]) t then grow t (2 * (size [@inlined]) t);
|
||||
Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t t.w) v;
|
||||
t.w <- t.w + 1
|
||||
|
||||
let cons t v =
|
||||
if (full [@inlined]) t then grow t (2 * (size [@inlined]) t);
|
||||
let i = t.r - 1 in
|
||||
Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t i) v;
|
||||
t.r <- i
|
||||
|
||||
let pop_exn t =
|
||||
if (empty [@inlined]) t then raise Empty;
|
||||
let r = Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r) in
|
||||
t.r <- t.r + 1;
|
||||
r
|
||||
|
||||
let pop t = try Some (pop_exn t) with Empty -> None
|
||||
|
||||
let peek_exn t =
|
||||
if (empty [@inlined]) t then raise Empty;
|
||||
Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r)
|
||||
|
||||
let peek t = try Some (peek_exn t) with Empty -> None
|
||||
|
||||
let blit src src_off dst dst_off len =
|
||||
let a = Bigarray.Array1.sub src src_off len in
|
||||
let b = Bigarray.Array1.sub dst dst_off len in
|
||||
Bigarray.Array1.blit a b
|
||||
|
||||
let compress t =
|
||||
let len = length t in
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then (
|
||||
if (available [@inlined]) t >= pre then (
|
||||
(* XXX(dinosaure): in this case, [pre + rst <= msk], so [blit] will not
|
||||
overlap bytes at the end of [t.v] (at offset [msk]). *)
|
||||
blit t.v 0 t.v pre rst;
|
||||
blit t.v msk t.v 0 pre)
|
||||
else
|
||||
let tmp = Bigarray.Array1.create t.k Bigarray.c_layout pre in
|
||||
blit t.v msk tmp 0 pre;
|
||||
blit t.v 0 t.v pre rst;
|
||||
blit tmp 0 t.v 0 pre)
|
||||
else blit t.v msk t.v 0 len;
|
||||
t.r <- 0;
|
||||
t.w <- len
|
||||
|
||||
module N = struct
|
||||
type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit
|
||||
type 'a length = 'a -> int
|
||||
|
||||
let push t ~blit ~length ?(off = 0) ?len v =
|
||||
let len = match len with None -> length v - off | Some len -> len in
|
||||
if (available [@inlined]) t < len then grow t (len + (size [@inlined]) t);
|
||||
let msk = (mask [@inlined]) t t.w in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then (
|
||||
blit v off t.v msk pre;
|
||||
blit v (off + pre) t.v 0 rst)
|
||||
else blit v off t.v msk len;
|
||||
t.w <- t.w + len
|
||||
|
||||
let keep_exn t ~blit ~length ?(off = 0) ?len v =
|
||||
let len = match len with None -> length v - off | Some len -> len in
|
||||
if (size [@inlined]) t < len then raise Empty;
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then (
|
||||
blit t.v msk v off pre;
|
||||
blit t.v 0 v (off + pre) rst)
|
||||
else blit t.v msk v off len
|
||||
|
||||
let keep t ~blit ~length ?off ?len v =
|
||||
try Some (keep_exn t ~blit ~length ?off ?len v) with Empty -> None
|
||||
|
||||
let peek t =
|
||||
let len = (size [@inlined]) t in
|
||||
if len == 0 then []
|
||||
else
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then
|
||||
[ Bigarray.Array1.sub t.v msk pre; Bigarray.Array1.sub t.v 0 rst ]
|
||||
else [ Bigarray.Array1.sub t.v msk len ]
|
||||
|
||||
let unsafe_shift t len = t.r <- t.r + len
|
||||
|
||||
let shift_exn t len =
|
||||
if (size [@inlined]) t < len then raise Empty;
|
||||
unsafe_shift t len
|
||||
|
||||
let shift t len = try Some (shift_exn t len) with Empty -> None
|
||||
end
|
||||
|
||||
let iter f t =
|
||||
let idx = ref t.r in
|
||||
let max = t.w in
|
||||
while !idx <> max do
|
||||
f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx));
|
||||
incr idx
|
||||
done
|
||||
|
||||
let rev_iter f t =
|
||||
if t.r == t.w then ()
|
||||
else
|
||||
let idx = ref (pred t.w) in
|
||||
let min = t.r in
|
||||
while
|
||||
f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx));
|
||||
!idx <> min
|
||||
do
|
||||
decr idx
|
||||
done
|
||||
|
||||
let fold f a t =
|
||||
let a = ref a in
|
||||
iter (fun x -> a := f !a x) t;
|
||||
!a
|
||||
|
||||
let pp ?sep pp_elt = Fmt.iter ?sep iter pp_elt
|
||||
let dump pp_elt = Fmt.Dump.iter iter (Fmt.any "rke") pp_elt
|
||||
|
||||
let clear q =
|
||||
q.r <- 0;
|
||||
q.w <- 0
|
||||
|
||||
module Weighted = struct
|
||||
type ('a, 'b) t = {
|
||||
mutable r : int;
|
||||
mutable w : int;
|
||||
c : int;
|
||||
k : ('a, 'b) Bigarray.kind;
|
||||
v : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t;
|
||||
}
|
||||
|
||||
exception Empty
|
||||
exception Full
|
||||
|
||||
let[@inline always] mask t v = v land (t.c - 1)
|
||||
let[@inline always] empty t = t.r = t.w
|
||||
let[@inline always] size t = t.w - t.r
|
||||
let[@inline always] full t = size t = t.c
|
||||
let[@inline always] available t = t.c - (t.w - t.r)
|
||||
let is_empty t = (empty [@inlined]) t
|
||||
let length q = size q
|
||||
|
||||
let create ?capacity kind =
|
||||
let capacity =
|
||||
match capacity with
|
||||
| None | Some 0 -> 1
|
||||
| Some n ->
|
||||
if n < 0 then Fmt.invalid_arg "Rke.Weighted.create"
|
||||
else to_power_of_two n
|
||||
in
|
||||
( {
|
||||
r = 0;
|
||||
w = 0;
|
||||
c = capacity;
|
||||
k = kind;
|
||||
v = Bigarray.Array1.create kind Bigarray.c_layout capacity;
|
||||
},
|
||||
capacity )
|
||||
|
||||
let copy t =
|
||||
let v = Bigarray.Array1.create t.k Bigarray.c_layout t.c in
|
||||
Bigarray.Array1.blit t.v v;
|
||||
{ r = t.r; w = t.w; c = t.c; v; k = t.k }
|
||||
|
||||
let from v =
|
||||
if not (is_power_of_two (Bigarray.Array1.dim v)) then
|
||||
Fmt.invalid_arg "RBA.from";
|
||||
let c = Bigarray.Array1.dim v in
|
||||
let k = Bigarray.Array1.kind v in
|
||||
{ r = 0; w = 0; c; k; v }
|
||||
|
||||
let push_exn t v =
|
||||
if (full [@inlined]) t then raise Full;
|
||||
Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t t.w) v;
|
||||
t.w <- t.w + 1
|
||||
|
||||
let push t v = try Some (push_exn t v) with Full -> None
|
||||
|
||||
let cons_exn t v =
|
||||
if (full [@inlined]) t then raise Full;
|
||||
let i = t.r - 1 in
|
||||
Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t i) v;
|
||||
t.r <- i
|
||||
|
||||
let cons t v = try Some (cons_exn t v) with Full -> None
|
||||
|
||||
let pop_exn t =
|
||||
if (empty [@inlined]) t then raise Empty;
|
||||
let r = Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r) in
|
||||
t.r <- t.r + 1;
|
||||
r
|
||||
|
||||
let pop t = try Some (pop_exn t) with Empty -> None
|
||||
|
||||
let peek_exn t =
|
||||
if (empty [@inlined]) t then raise Empty;
|
||||
Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r)
|
||||
|
||||
let peek t = try Some (peek_exn t) with Empty -> None
|
||||
|
||||
let compress t =
|
||||
let len = length t in
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then (
|
||||
if (available [@inlined]) t >= pre then (
|
||||
(* XXX(dinosaure): in this case, [pre + rst <= msk], so [blit] will not
|
||||
overlap bytes at the end of [t.v] (at offset [msk]). *)
|
||||
blit t.v 0 t.v pre rst;
|
||||
blit t.v msk t.v 0 pre)
|
||||
else
|
||||
let tmp = Bigarray.Array1.create t.k Bigarray.c_layout pre in
|
||||
blit t.v msk tmp 0 pre;
|
||||
blit t.v 0 t.v pre rst;
|
||||
blit tmp 0 t.v 0 pre)
|
||||
else blit t.v msk t.v 0 len;
|
||||
t.r <- 0;
|
||||
t.w <- len
|
||||
|
||||
module N = struct
|
||||
type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit
|
||||
type 'a length = 'a -> int
|
||||
|
||||
let push_exn t ~blit ~length ?(off = 0) ?len v =
|
||||
let len = match len with None -> length v - off | Some len -> len in
|
||||
if (available [@inlined]) t < len then raise Full;
|
||||
let msk = (mask [@inlined]) t t.w in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
let ret =
|
||||
if rst > 0 then (
|
||||
blit v off t.v msk pre;
|
||||
blit v (off + pre) t.v 0 rst;
|
||||
[
|
||||
Bigarray.Array1.sub t.v ((mask [@inlined]) t t.w) pre;
|
||||
Bigarray.Array1.sub t.v 0 rst;
|
||||
])
|
||||
else (
|
||||
blit v off t.v msk len;
|
||||
[ Bigarray.Array1.sub t.v ((mask [@inlined]) t t.w) len ])
|
||||
in
|
||||
t.w <- t.w + len;
|
||||
ret
|
||||
|
||||
let push t ~blit ~length ?off ?len v =
|
||||
try Some (push_exn t ~blit ~length ?off ?len v) with Full -> None
|
||||
|
||||
let keep_exn t ~blit ~length ?(off = 0) ?len v =
|
||||
let len = match len with None -> length v - off | Some len -> len in
|
||||
if (size [@inlined]) t < len then raise Empty;
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then (
|
||||
blit t.v msk v off pre;
|
||||
blit t.v 0 v (off + pre) rst)
|
||||
else blit t.v msk v off len
|
||||
|
||||
let keep t ~blit ~length ?off ?len v =
|
||||
try Some (keep_exn t ~blit ~length ?off ?len v) with Empty -> None
|
||||
|
||||
let peek t =
|
||||
let len = (size [@inlined]) t in
|
||||
if len == 0 then []
|
||||
else
|
||||
let msk = (mask [@inlined]) t t.r in
|
||||
let pre = t.c - msk in
|
||||
let rst = len - pre in
|
||||
if rst > 0 then
|
||||
[ Bigarray.Array1.sub t.v msk pre; Bigarray.Array1.sub t.v 0 rst ]
|
||||
else [ Bigarray.Array1.sub t.v msk len ]
|
||||
|
||||
let unsafe_shift t len = t.r <- t.r + len
|
||||
|
||||
let shift_exn t len =
|
||||
if (size [@inlined]) t < len then raise Empty;
|
||||
unsafe_shift t len
|
||||
|
||||
let shift t len = try Some (shift_exn t len) with Empty -> None
|
||||
end
|
||||
|
||||
let iter f t =
|
||||
let idx = ref t.r in
|
||||
let max = t.w in
|
||||
while !idx <> max do
|
||||
f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx));
|
||||
incr idx
|
||||
done
|
||||
|
||||
let rev_iter f t =
|
||||
if t.r == t.w then ()
|
||||
else
|
||||
let idx = ref (pred t.w) in
|
||||
let min = t.r in
|
||||
while
|
||||
f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx));
|
||||
!idx <> min
|
||||
do
|
||||
decr idx
|
||||
done
|
||||
|
||||
let fold f a t =
|
||||
let a = ref a in
|
||||
iter (fun x -> a := f !a x) t;
|
||||
!a
|
||||
|
||||
let pp ?sep pp_elt = Fmt.iter ?sep iter pp_elt
|
||||
let dump pp_elt = Fmt.Dump.iter iter (Fmt.any "rke:weighted") pp_elt
|
||||
|
||||
let clear q =
|
||||
q.r <- 0;
|
||||
q.w <- 0
|
||||
|
||||
let unsafe_bigarray { v; _ } = v
|
||||
end
|
||||
2
unikernel/duniverse/ke/lib/rke.mli
Normal file
2
unikernel/duniverse/ke/lib/rke.mli
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
include Sigs.R
|
||||
module Weighted : Sigs.Weighted.R
|
||||
532
unikernel/duniverse/ke/lib/sigs.ml
Normal file
532
unikernel/duniverse/ke/lib/sigs.ml
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
module type F = sig
|
||||
type 'a t
|
||||
(** The type of queues containing elements of type ['a]. *)
|
||||
|
||||
exception Empty
|
||||
(** Raised when {!peek_exn} or {!pop_exn} is applied to an empty queue. *)
|
||||
|
||||
val empty : 'a t
|
||||
(** An empty queue. *)
|
||||
|
||||
val is_empty : 'a t -> bool
|
||||
(** Return [true] if the given queue is empty, [false] otherwise. *)
|
||||
|
||||
val length : 'a t -> int
|
||||
(** Number of elements in the queue. *)
|
||||
|
||||
val push : 'a t -> 'a -> 'a t
|
||||
(** Push element at the end of the queue. *)
|
||||
|
||||
val cons : 'a t -> 'a -> 'a t
|
||||
(** Push element at the front of the queue. *)
|
||||
|
||||
val peek : 'a t -> 'a option
|
||||
(** [peek q] returns the first element in the queue [q], without removing it
|
||||
from the queue. If [q] is empty, it returns [None]. *)
|
||||
|
||||
val peek_exn : 'a t -> 'a
|
||||
(** Same as {!peek} but it raises an exception if [q] is empty. *)
|
||||
|
||||
val pop : 'a t -> ('a * 'a t) option
|
||||
(** Get and remove the first element. If [q] is empty, it returns [None]. *)
|
||||
|
||||
val pop_exn : 'a t -> 'a * 'a t
|
||||
(** Same as {!pop} but it raises an exception if [q] is empty. *)
|
||||
|
||||
val tail : 'a t -> ('a t * 'a) option
|
||||
(** Get and remove the {b last} element. If [q] is empty, it returns [None]. *)
|
||||
|
||||
val tail_exn : 'a t -> 'a t * 'a
|
||||
(** Same as {!tail} but it raises an exception if [q] is empty. *)
|
||||
|
||||
val iter : ('a -> unit) -> 'a t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the least
|
||||
recently entered to the most recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val rev_iter : ('a -> unit) -> 'a t -> unit
|
||||
(** [rev_iter f q] applies [f] in turn to all elements of [q], from the most
|
||||
recently entered to the least recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val fold : ('acc -> 'x -> 'acc) -> 'acc -> 'x t -> 'acc
|
||||
(** [fold f a q] is equivalent to [List.fold_left f a l], where [l] is the
|
||||
list of [q]'s elements. The queue remains unchanged. *)
|
||||
|
||||
val pp : ?sep:unit Fmt.t -> 'a Fmt.t -> 'a t Fmt.t
|
||||
(** Pretty-printer of {!t}. *)
|
||||
|
||||
val dump : 'a Fmt.t -> 'a t Fmt.t
|
||||
(** Human-readable pretty-printer of {!t}. *)
|
||||
end
|
||||
|
||||
module type R = sig
|
||||
type ('a, 'b) t
|
||||
(** The type of queues containing elements of type ['a]. *)
|
||||
|
||||
exception Empty
|
||||
(** Raised when {!peek_exn}, {!pop_exn}, {!N.keep_exn} or {!N.shift_exn} is
|
||||
applied to an empty queue. *)
|
||||
|
||||
val is_empty : ('a, 'b) t -> bool
|
||||
(** Return [true] if the given queue is empty, [false] otherwise. *)
|
||||
|
||||
val create : ?capacity:int -> ('a, 'b) Bigarray.kind -> ('a, 'b) t
|
||||
(** Return a new queue, initially empty. *)
|
||||
|
||||
val capacity : ('a, 'b) t -> int
|
||||
(** Returns how many objects [t] can store. *)
|
||||
|
||||
val length : ('a, 'b) t -> int
|
||||
(** Number of elements in the queue. *)
|
||||
|
||||
val push : ('a, 'b) t -> 'a -> unit
|
||||
(** [push q x] adds the elements [x] at the end of the queue [q]. *)
|
||||
|
||||
val pop : ('a, 'b) t -> 'a option
|
||||
(** [pop q] removes and returns the first element in queue [q]. If [q] is
|
||||
empty, it returns [None]. *)
|
||||
|
||||
val pop_exn : ('a, 'b) t -> 'a
|
||||
(** [pop_exn] is the same as {!pop} but it raises {!Empty} when the given
|
||||
queue [q] is empty. *)
|
||||
|
||||
val peek : ('a, 'b) t -> 'a option
|
||||
(** [peek q] returns the first element in the queue [q], without removing it
|
||||
from the queue. If [q] is empty, it returns [None]. *)
|
||||
|
||||
val peek_exn : ('a, 'b) t -> 'a
|
||||
(** Same as {!peek} but it raises {!Empty} if [q] is empty. *)
|
||||
|
||||
val cons : ('a, 'b) t -> 'a -> unit
|
||||
(** [cons q x] adds element [x] at the front of the given queue [q]. It
|
||||
returns [None] if it fails. *)
|
||||
|
||||
val copy : ('a, 'b) t -> ('a, 'b) t
|
||||
(** Return a copy of the given queue. *)
|
||||
|
||||
val clear : ('a, 'b) t -> unit
|
||||
(** Discard all elements from a queue. *)
|
||||
|
||||
val compress : ('a, 'b) t -> unit
|
||||
(** Compress queue, read cursor will be setted to [0] and data will be move
|
||||
to. This operation allows to provide much more space for a
|
||||
{!push}/{!N.push} operation - but it can not ensure enough free space. *)
|
||||
|
||||
module N : sig
|
||||
type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
(** The type of the internal bigarray of {!t}. *)
|
||||
|
||||
type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit
|
||||
(** The type of the [blit] function. *)
|
||||
|
||||
type 'a length = 'a -> int
|
||||
(** The type of the [length] function. *)
|
||||
|
||||
val push :
|
||||
('a, 'b) t ->
|
||||
blit:('src, ('a, 'b) bigarray) blit ->
|
||||
length:'src length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'src ->
|
||||
unit
|
||||
(** [push q ~blit ~length ?off ?len src] {i blits} elements in [src] to the
|
||||
given queue [q] at the end (like a fast iterative {!R.push}). Default
|
||||
value of [off] is [0]. Default value of [len] is [length src - off]. *)
|
||||
|
||||
val keep_exn :
|
||||
('a, 'b) t ->
|
||||
blit:(('a, 'b) bigarray, 'dst) blit ->
|
||||
length:'dst length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'dst ->
|
||||
unit
|
||||
(** [keep_exn q ~blit ~length ?off ?len dst] {i blits} elements of the given
|
||||
queue [q] in [dst] from the front to the end of [dst] (like a fast
|
||||
iterative {!R.pop_exn}). Default value of [off] is [0]. Default value of
|
||||
[len] is [length dst - off]. If the given [q] does not have enough
|
||||
elements to write on [dst], it raises {!Empty} and the given queue is
|
||||
unchanged. *)
|
||||
|
||||
val keep :
|
||||
('a, 'b) t ->
|
||||
blit:(('a, 'b) bigarray, 'dst) blit ->
|
||||
length:'dst length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'dst ->
|
||||
unit option
|
||||
(** Same as {!keep_exn} but if it fails, it returns [None]. *)
|
||||
|
||||
val peek : ('a, 'b) t -> ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t list
|
||||
(** Returns a sub-part of available to read payloads. *)
|
||||
|
||||
val unsafe_shift : ('a, 'b) t -> int -> unit
|
||||
(** [unsafe_shift q l] discards [l] elements in the given queue [q] without
|
||||
any verification. Mostly used after {!keep_exn}, if the last one does not
|
||||
raise {!Empty}, it's safe to use it. *)
|
||||
|
||||
val shift_exn : ('a, 'b) t -> int -> unit
|
||||
(** [shift_exn q l] discards [l] elements in the given queue [q]. If [q]
|
||||
does not have enough elements, it raises {!Empty} and the given queue is
|
||||
unchanged. *)
|
||||
|
||||
val shift : ('a, 'b) t -> int -> unit option
|
||||
(** Same as {!shift_exn} but if it fails, it returns [None]. *)
|
||||
end
|
||||
|
||||
val iter : ('a -> unit) -> ('a, 'b) t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the least
|
||||
recently entered to the most recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val rev_iter : ('a -> unit) -> ('a, 'b) t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the most
|
||||
recently entered to the least recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val fold : ('acc -> 'x -> 'acc) -> 'acc -> ('x, 'b) t -> 'acc
|
||||
(** [fold f a q] is equivalent to [List.fold_left f a l], where [l] is the
|
||||
list of [q]'s elements. The queue remains unchanged. *)
|
||||
|
||||
val pp : ?sep:unit Fmt.t -> 'a Fmt.t -> ('a, 'b) t Fmt.t
|
||||
(** Pretty-printer of {!t}. *)
|
||||
|
||||
val dump : 'a Fmt.t -> ('a, 'b) t Fmt.t
|
||||
(** Human-readable pretty-printer of {!t}. *)
|
||||
end
|
||||
|
||||
module Weighted = struct
|
||||
module type R = sig
|
||||
type ('a, 'b) t
|
||||
(** The type of queues containing elements of type ['a]. *)
|
||||
|
||||
exception Full
|
||||
(** Raised when {!push_exn} or {!N.push_exn} is applied to an empty queue. *)
|
||||
|
||||
exception Empty
|
||||
(** Raised when {!peek_exn}, {!pop_exn} is applied to an empty queue. *)
|
||||
|
||||
val is_empty : ('a, 'b) t -> bool
|
||||
(** Return [true] if the given queue is empty, [false] otherwise. *)
|
||||
|
||||
val create : ?capacity:int -> ('a, 'b) Bigarray.kind -> ('a, 'b) t * int
|
||||
(** Return a new queue, initially empty with the real capacity of it. *)
|
||||
|
||||
val length : ('a, 'b) t -> int
|
||||
(** Number of elements in the queue. *)
|
||||
|
||||
val available : ('a, 'b) t -> int
|
||||
(** Free cells availables on the queue. *)
|
||||
|
||||
val push_exn : ('a, 'b) t -> 'a -> unit
|
||||
(** [push_exn q x] adds the elements [x] at the end of the queue [q]. It
|
||||
raises {!Full} if the given queue [q] is full. *)
|
||||
|
||||
val push : ('a, 'b) t -> 'a -> unit option
|
||||
(** [push q x] is the same as {!push_exn} but returns [None] if it fails. *)
|
||||
|
||||
val pop : ('a, 'b) t -> 'a option
|
||||
(** [pop q] removes and returns the first element in the given queue [q]. If
|
||||
[q] is empty, it returns [None]. *)
|
||||
|
||||
val pop_exn : ('a, 'b) t -> 'a
|
||||
(** [pop_exn q] is the same as {!pop} but it raises an {!Empty} if the given
|
||||
queue is empty. *)
|
||||
|
||||
val peek : ('a, 'b) t -> 'a option
|
||||
(** [peek q] returns the first element in the given queue [q]. If [q] is
|
||||
empty, it returns [None]. *)
|
||||
|
||||
val peek_exn : ('a, 'b) t -> 'a
|
||||
(** [peek_exn q] returns the first element in the given queue [q]. If [q] is
|
||||
empty, it raises {!Empty}. *)
|
||||
|
||||
val cons_exn : ('a, 'b) t -> 'a -> unit
|
||||
(** [cons_exn q x] adds element [x] at the front of the given queue [q]. It
|
||||
raises {!Full} if the queue is full. *)
|
||||
|
||||
val cons : ('a, 'b) t -> 'a -> unit option
|
||||
(** [cons q x] adds element [x] at the front of the given queue [q]. It
|
||||
returns [None] if it fails. *)
|
||||
|
||||
val copy : ('a, 'b) t -> ('a, 'b) t
|
||||
(** Return a copy of the given queue. *)
|
||||
|
||||
val clear : ('a, 'b) t -> unit
|
||||
(** Discard all elements from a queue. *)
|
||||
|
||||
val compress : ('a, 'b) t -> unit
|
||||
(** Compress queue, read cursor will be setted to [0] and data will be move
|
||||
to. This operation allows to provide much more space for a
|
||||
{!push}/{!N.push} operation - but it can not ensure enough free space. *)
|
||||
|
||||
module N : sig
|
||||
type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
(** The type of the internal bigarray of {!t}. *)
|
||||
|
||||
type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit
|
||||
(** The type of the [blit] function. *)
|
||||
|
||||
type 'a length = 'a -> int
|
||||
(** The type of the [length] function. *)
|
||||
|
||||
val push_exn :
|
||||
('a, 'b) t ->
|
||||
blit:('src, ('a, 'b) bigarray) blit ->
|
||||
length:'src length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'src ->
|
||||
('a, 'b) bigarray list
|
||||
(** [push_exn q ~blit ~length ?off ?len src] {i blits} elements in [src]
|
||||
to the given queue [q] at the end (like a fast iterative {!R.push}).
|
||||
Default value of [off] is [0]. Default value of [len] is [length src - off].
|
||||
It returns a list of internal {!bigarray}s which contain [dst].
|
||||
If the given [q] does not have enough free space to write [src], it
|
||||
raises {!Full} and the given queue is unchanged. *)
|
||||
|
||||
val push :
|
||||
('a, 'b) t ->
|
||||
blit:('src, ('a, 'b) bigarray) blit ->
|
||||
length:'src length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'src ->
|
||||
('a, 'b) bigarray list option
|
||||
(** Same as {!push_exn} but it returns [None] if it fails. *)
|
||||
|
||||
val keep_exn :
|
||||
('a, 'b) t ->
|
||||
blit:(('a, 'b) bigarray, 'dst) blit ->
|
||||
length:'dst length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'dst ->
|
||||
unit
|
||||
(** [keep_exn q ~blit ~length ?off ?len dst] {i blits} elements of the
|
||||
given queue [q] in [dst] from the front to the end of [dst] (like a
|
||||
fast iterative {!R.pop_exn}). Default value of [off] is [0]. Default
|
||||
value of [len] is [length dst - off]. If the given [q] does not have
|
||||
enough elements to write on [dst], it raises {!Empty}. In any case, the
|
||||
given queue is unchanged. *)
|
||||
|
||||
val keep :
|
||||
('a, 'b) t ->
|
||||
blit:(('a, 'b) bigarray, 'dst) blit ->
|
||||
length:'dst length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'dst ->
|
||||
unit option
|
||||
(** Same as {!keep_exn} but if it fails, it returns [None]. *)
|
||||
|
||||
val peek :
|
||||
('a, 'b) t -> ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t list
|
||||
(** Returns a sub-part of available to read payloads. *)
|
||||
|
||||
val unsafe_shift : ('a, 'b) t -> int -> unit
|
||||
(** [unsafe_shift q l] discards [l] elements in the given queue [q]
|
||||
without any verification. Mostly used after {!keep_exn}, if the last
|
||||
one does not raise {!Empty}, it's safe to use it. *)
|
||||
|
||||
val shift_exn : ('a, 'b) t -> int -> unit
|
||||
(** [shift_exn q l] discards [l] elements in the given queue [q]. If [q]
|
||||
does not have enough elements, it raises {!Empty} and the given queue
|
||||
is unchanged. *)
|
||||
|
||||
val shift : ('a, 'b) t -> int -> unit option
|
||||
(** Same as {!shift_exn} but if it fails, it returns [None]. *)
|
||||
end
|
||||
|
||||
val iter : ('a -> unit) -> ('a, 'b) t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the least
|
||||
recently entered to the most recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val rev_iter : ('a -> unit) -> ('a, 'b) t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the most
|
||||
recently entered to the least recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val fold : ('acc -> 'x -> 'acc) -> 'acc -> ('x, 'b) t -> 'acc
|
||||
(** [fold f a q] is equivalent to [List.fold_left f a l], where [l] is the
|
||||
list of [q]'s elements. The queue remains unchanged. *)
|
||||
|
||||
val pp : ?sep:unit Fmt.t -> 'a Fmt.t -> ('a, 'b) t Fmt.t
|
||||
(** Pretty-printer of {!t}. *)
|
||||
|
||||
val dump : 'a Fmt.t -> ('a, 'b) t Fmt.t
|
||||
(** Human-readable pretty-printer of {!t}. *)
|
||||
|
||||
val unsafe_bigarray :
|
||||
('a, 'b) t -> ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
(** / **)
|
||||
|
||||
val from : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t -> ('a, 'b) t
|
||||
end
|
||||
|
||||
module type F = sig
|
||||
type ('a, 'b) t
|
||||
(** The type of queues containing elements of type ['a]. *)
|
||||
|
||||
exception Empty
|
||||
(** Raised when {!push_exn} or {!N.push_exn} is applied to an empty queue. *)
|
||||
|
||||
exception Full
|
||||
(** Raised when {!peek_exn}, {!pop_exn} is applied to an empty queue. *)
|
||||
|
||||
val is_empty : ('a, 'b) t -> bool
|
||||
(** Return [true] if the given queue is empty, [false] otherwise. *)
|
||||
|
||||
val create : ?capacity:int -> ('a, 'b) Bigarray.kind -> ('a, 'b) t * int
|
||||
(** Return a new queue, initially empty with the real capacity of it. *)
|
||||
|
||||
val length : ('a, 'b) t -> int
|
||||
(** Number of elements in the queue. *)
|
||||
|
||||
val available : ('a, 'b) t -> int
|
||||
(** Free cells availables on the queue. *)
|
||||
|
||||
val push_exn : ('a, 'b) t -> 'a -> ('a, 'b) t
|
||||
(** [push_exn q x] adds the elements [x] at the end of the queue [q] and
|
||||
returns the new queue [q']. It raises {!Full} if the given queue [q] is
|
||||
full. *)
|
||||
|
||||
val push : ('a, 'b) t -> 'a -> ('a, 'b) t option
|
||||
(** [push q x] is the same as {!push_exn} but returns [None] if it fails. *)
|
||||
|
||||
val pop : ('a, 'b) t -> ('a * ('a, 'b) t) option
|
||||
(** [pop q] removes and returns the first element in the given queue [q] and
|
||||
returns the new queue [q']. If [q] is empty, it returns [None]. *)
|
||||
|
||||
val pop_exn : ('a, 'b) t -> 'a * ('a, 'b) t
|
||||
(** [pop_exn q] is the same as {!pop} but it raises an {!Empty} if the given
|
||||
queue is empty. *)
|
||||
|
||||
val peek : ('a, 'b) t -> 'a option
|
||||
(** [peek q] returns the first element in the given queue [q]. If [q] is
|
||||
empty, it returns [None]. The given queue [q] is unchanged. *)
|
||||
|
||||
val peek_exn : ('a, 'b) t -> 'a
|
||||
(** [peek_exn q] returns the first element in the given queue [q]. If [q] is
|
||||
empty, it raises {!Empty}. *)
|
||||
|
||||
val cons : ('a, 'b) t -> 'a -> ('a, 'b) t option
|
||||
(** [cons q x] adds element [x] at the front of the given queue [q]. It
|
||||
returns [None] if it fails or the new queue [q']. *)
|
||||
|
||||
val cons_exn : ('a, 'b) t -> 'a -> ('a, 'b) t
|
||||
(** [cons q x] adds element [x] at the front of the given queue [q]. It
|
||||
raises {!Empty} if the given queue [q] is full or the new queue [q']. *)
|
||||
|
||||
val copy : ('a, 'b) t -> ('a, 'b) t
|
||||
(** Return a copy of the given queue. *)
|
||||
|
||||
val clear : ('a, 'b) t -> ('a, 'b) t
|
||||
(** Discard all elements from a queue. *)
|
||||
|
||||
module N : sig
|
||||
type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
(** The type of the internal bigarray of {!t}. *)
|
||||
|
||||
type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit
|
||||
(** The type of the [blit] function. *)
|
||||
|
||||
type 'a length = 'a -> int
|
||||
(** The type of the [length] function. *)
|
||||
|
||||
val push_exn :
|
||||
('a, 'b) t ->
|
||||
blit:('src, ('a, 'b) bigarray) blit ->
|
||||
length:'src length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'src ->
|
||||
('a, 'b) bigarray list * ('a, 'b) t
|
||||
(** [push_exn q ~blit ~length ?off ?len src] {i blits} elements in [src]
|
||||
to the given queue [q] at the end (like a fast iterative {!R.push}).
|
||||
Default value of [off] is [0]. Default value of [len] is [length src - off].
|
||||
It returns a list of internal {!bigarray}s which contain [dst].
|
||||
If the given [q] does not have enough free space to write [src], it
|
||||
raises {!Full} and the given queue is unchanged. *)
|
||||
|
||||
val push :
|
||||
('a, 'b) t ->
|
||||
blit:('src, ('a, 'b) bigarray) blit ->
|
||||
length:'src length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'src ->
|
||||
(('a, 'b) bigarray list * ('a, 'b) t) option
|
||||
(** Same as {!push_exn} but it returns [None] if it fails. *)
|
||||
|
||||
val keep_exn :
|
||||
('a, 'b) t ->
|
||||
blit:(('a, 'b) bigarray, 'dst) blit ->
|
||||
length:'dst length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'dst ->
|
||||
unit
|
||||
(** [keep_exn q ~blit ~length ?off ?len dst] {i blits} elements of the
|
||||
given queue [q] in [dst] from the front to the end of [dst] (like a
|
||||
fast iterative {!R.pop_exn}). Default value of [off] is [0]. Default
|
||||
value of [len] is [length dst - off]. If the given [q] does not have
|
||||
enough elements to write on [dst], it raises {!Empty}. In any case, the
|
||||
given queue is unchanged. *)
|
||||
|
||||
val keep :
|
||||
('a, 'b) t ->
|
||||
blit:(('a, 'b) bigarray, 'dst) blit ->
|
||||
length:'dst length ->
|
||||
?off:int ->
|
||||
?len:int ->
|
||||
'dst ->
|
||||
unit option
|
||||
(** Same as {!keep_exn} but if it fails, it returns [None]. *)
|
||||
|
||||
val unsafe_shift : ('a, 'b) t -> int -> ('a, 'b) t
|
||||
(** [unsafe_shift q l] discards [l] elements in the given queue [q]
|
||||
without any verification. Mostly used after {!keep_exn}, if the last
|
||||
one does not raise {!Empty}, it's safe to use it. *)
|
||||
|
||||
val shift_exn : ('a, 'b) t -> int -> ('a, 'b) t
|
||||
(** [shift_exn q l] discards [l] elements in the given queue [q]. If [q]
|
||||
does not have enough elements, it raises {!Empty} and the given queue
|
||||
is unchanged. *)
|
||||
|
||||
val shift : ('a, 'b) t -> int -> ('a, 'b) t option
|
||||
(** Same as {!shift_exn} but if it fails, it returns [None]. *)
|
||||
end
|
||||
|
||||
val iter : ('a -> unit) -> ('a, 'b) t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the least
|
||||
recently entered to the most recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val rev_iter : ('a -> unit) -> ('a, 'b) t -> unit
|
||||
(** [iter f q] applies [f] in turn to all elements of [q], from the most
|
||||
recently entered to the least recently entered. The queue itself is
|
||||
unchanged. *)
|
||||
|
||||
val fold : ('acc -> 'x -> 'acc) -> 'acc -> ('x, 'b) t -> 'acc
|
||||
(** [fold f a q] is equivalent to [List.fold_left f a l], where [l] is the
|
||||
list of [q]'s elements. The queue remains unchanged. *)
|
||||
|
||||
val pp : ?sep:unit Fmt.t -> 'a Fmt.t -> ('a, 'b) t Fmt.t
|
||||
(** Pretty-printer of {!t}. *)
|
||||
|
||||
val dump : 'a Fmt.t -> ('a, 'b) t Fmt.t
|
||||
(** Human-readable pretty-printer of {!t}. *)
|
||||
|
||||
(** / **)
|
||||
|
||||
val unsafe_bigarray :
|
||||
('a, 'b) t -> ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t
|
||||
|
||||
val from : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t -> ('a, 'b) t
|
||||
end
|
||||
end
|
||||
10
unikernel/duniverse/ke/test/dune
Normal file
10
unikernel/duniverse/ke/test/dune
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
(executable
|
||||
(name test)
|
||||
(libraries bigstringaf alcotest ke))
|
||||
|
||||
(rule
|
||||
(alias runtest)
|
||||
(deps
|
||||
(:exe test.exe))
|
||||
(action
|
||||
(run %{exe} --color=always)))
|
||||
331
unikernel/duniverse/ke/test/test.ml
Normal file
331
unikernel/duniverse/ke/test/test.ml
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
let () = Printexc.record_backtrace true
|
||||
|
||||
module Option = struct
|
||||
let map f = function Some x -> Some (f x) | None -> None
|
||||
end
|
||||
|
||||
module type Q = sig
|
||||
type t
|
||||
|
||||
exception Empty
|
||||
|
||||
val available : t -> int
|
||||
val fold : ('a -> int -> 'a) -> 'a -> t -> 'a
|
||||
val create : unit -> t
|
||||
val push : t -> int -> unit
|
||||
val pop_exn : t -> int
|
||||
val peek_exn : t -> int
|
||||
val is_empty : t -> bool
|
||||
val length : t -> int
|
||||
val iter : (int -> unit) -> t -> unit
|
||||
val copy : t -> t
|
||||
val clear : t -> unit
|
||||
val compress : t -> unit
|
||||
end
|
||||
|
||||
(* XXX(dinosaure): from [ocaml]. *)
|
||||
module Make (Q : Q) = struct
|
||||
let to_list q = Q.fold (fun a x -> x :: a) [] q |> List.rev
|
||||
|
||||
let test_0 =
|
||||
Alcotest.test_case "test-0" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
Alcotest.(check (list int)) "[ ]" (to_list q) [];
|
||||
Q.push q 1;
|
||||
Alcotest.(check (list int)) "[ 1 ]" (to_list q) [ 1 ];
|
||||
Q.push q 2;
|
||||
Alcotest.(check (list int)) "[ 1; 2 ]" (to_list q) [ 1; 2 ];
|
||||
Q.push q 3;
|
||||
Alcotest.(check (list int)) "[ 1; 2; 3 ]" (to_list q) [ 1; 2; 3 ];
|
||||
Q.push q 4;
|
||||
Alcotest.(check (list int)) "[ 1; 2; 3; 4 ]" (to_list q) [ 1; 2; 3; 4 ];
|
||||
let n = Q.pop_exn q in
|
||||
Alcotest.(check (list int)) "[ 2; 3; 4 ]" (to_list q) [ 2; 3; 4 ];
|
||||
Alcotest.(check int) "1" n 1;
|
||||
let n = Q.pop_exn q in
|
||||
Alcotest.(check (list int)) "[ 3; 4 ]" (to_list q) [ 3; 4 ];
|
||||
Alcotest.(check int) "2" n 2;
|
||||
let n = Q.pop_exn q in
|
||||
Alcotest.(check (list int)) "[ 4 ]" (to_list q) [ 4 ];
|
||||
Alcotest.(check int) "3" n 3;
|
||||
let n = Q.pop_exn q in
|
||||
Alcotest.(check (list int)) "[ ]" (to_list q) [];
|
||||
Alcotest.(check int) "4" n 4;
|
||||
Alcotest.check_raises "exception" Q.Empty (fun () -> ignore (Q.pop_exn q))
|
||||
|
||||
let test_1 =
|
||||
Alcotest.test_case "test-1" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
Alcotest.(check (list int)) "empty" (to_list q) [];
|
||||
Q.push q 1;
|
||||
let n = Q.pop_exn q in
|
||||
Alcotest.(check int) "1" n 1;
|
||||
Alcotest.check_raises "exception" Q.Empty (fun () -> ignore (Q.pop_exn q));
|
||||
Q.push q 2;
|
||||
let n = Q.pop_exn q in
|
||||
Alcotest.(check int) "2" n 2;
|
||||
Alcotest.check_raises "exception" Q.Empty (fun () -> ignore (Q.pop_exn q));
|
||||
Alcotest.(check bool) "empty" (Q.is_empty q) true
|
||||
|
||||
let test_2 =
|
||||
Alcotest.test_case "test-2" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
Q.push q 1;
|
||||
Alcotest.(check int) "[ 1 ]" (Q.peek_exn q) 1;
|
||||
Q.push q 2;
|
||||
Alcotest.(check int) "[ 1; 2 ]" (Q.peek_exn q) 1;
|
||||
Q.push q 3;
|
||||
Alcotest.(check int) "[ 1; 2; 3 ]" (Q.peek_exn q) 1;
|
||||
Alcotest.(check int) "peek" (Q.peek_exn q) 1;
|
||||
Alcotest.(check int) "pop" (Q.pop_exn q) 1;
|
||||
Alcotest.(check int) "peek" (Q.peek_exn q) 2;
|
||||
Alcotest.(check int) "pop" (Q.pop_exn q) 2;
|
||||
Alcotest.(check int) "peek" (Q.peek_exn q) 3;
|
||||
Alcotest.(check int) "pop" (Q.pop_exn q) 3;
|
||||
Alcotest.check_raises "exception" Q.Empty (fun () -> ignore (Q.pop_exn q));
|
||||
Alcotest.check_raises "exception" Q.Empty (fun () -> ignore (Q.pop_exn q));
|
||||
Alcotest.(check bool) "empty" (Q.is_empty q) true
|
||||
|
||||
let test_3 =
|
||||
Alcotest.test_case "test-3" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
for i = 1 to 10 do
|
||||
Q.push q i
|
||||
done;
|
||||
Q.clear q;
|
||||
Alcotest.(check int) "length" (Q.length q) 0;
|
||||
Alcotest.check_raises "exception" Q.Empty (fun () -> ignore (Q.pop_exn q));
|
||||
Q.push q 42;
|
||||
Alcotest.(check int) "[ 42 ]" (Q.pop_exn q) 42
|
||||
|
||||
let test_4 =
|
||||
Alcotest.test_case "test-4" `Quick @@ fun () ->
|
||||
let q1 = Q.create () in
|
||||
for i = 1 to 10 do
|
||||
Q.push q1 i
|
||||
done;
|
||||
let q2 = Q.copy q1 in
|
||||
Alcotest.(check (list int))
|
||||
"[ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ]" (to_list q1)
|
||||
[ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ];
|
||||
Alcotest.(check (list int))
|
||||
"[ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ]" (to_list q2)
|
||||
[ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ];
|
||||
Alcotest.(check int) "length" (Q.length q1) 10;
|
||||
Alcotest.(check int) "length" (Q.length q2) 10;
|
||||
for i = 1 to 10 do
|
||||
Alcotest.(check int) (string_of_int i) (Q.pop_exn q1) i
|
||||
done;
|
||||
for i = 1 to 10 do
|
||||
Alcotest.(check int) (string_of_int i) (Q.pop_exn q2) i
|
||||
done
|
||||
|
||||
let test_5 =
|
||||
Alcotest.test_case "test-5" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
Alcotest.(check bool) "is_empty" (Q.is_empty q) true;
|
||||
for i = 1 to 10 do
|
||||
Q.push q i;
|
||||
Alcotest.(check int) "length" (Q.length q) i;
|
||||
Alcotest.(check bool) "is_not_empty" (not (Q.is_empty q)) true
|
||||
done;
|
||||
for i = 10 downto 1 do
|
||||
Alcotest.(check int) "length" (Q.length q) i;
|
||||
Alcotest.(check bool) "is_not_empty" (not (Q.is_empty q)) true;
|
||||
ignore (Q.pop_exn q)
|
||||
done;
|
||||
Alcotest.(check int) "length" (Q.length q) 0;
|
||||
Alcotest.(check bool) "is_empty" (Q.is_empty q) true
|
||||
|
||||
let test_6 =
|
||||
Alcotest.test_case "test-6" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
for i = 1 to 10 do
|
||||
Q.push q i
|
||||
done;
|
||||
let i = ref 1 in
|
||||
Q.iter
|
||||
(fun j ->
|
||||
Alcotest.(check int) "iter" !i j;
|
||||
incr i)
|
||||
q
|
||||
|
||||
let test_7 =
|
||||
Alcotest.test_case "test-7" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
for i = 1 to 10 do
|
||||
Q.push q i
|
||||
done;
|
||||
for _ = 1 to 10 do
|
||||
ignore (Q.pop_exn q)
|
||||
done;
|
||||
for i = 1 to 10 do
|
||||
Q.push q i
|
||||
done;
|
||||
let expect = [ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ] in
|
||||
Alcotest.(check (list int))
|
||||
"[ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ]" (to_list q) expect;
|
||||
Q.compress q;
|
||||
Alcotest.(check (list int))
|
||||
"[ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ]" (to_list q) expect
|
||||
|
||||
let test_8 =
|
||||
Alcotest.test_case "test-8" `Quick @@ fun () ->
|
||||
let q = Q.create () in
|
||||
let m = Q.available q in
|
||||
for i = 1 to m / 2 do
|
||||
Q.push q i
|
||||
done;
|
||||
for _ = 1 to m / 2 do
|
||||
ignore (Q.pop_exn q)
|
||||
done;
|
||||
for i = 1 to m do
|
||||
Q.push q i
|
||||
done;
|
||||
let expect = to_list q in
|
||||
for _ = 1 to m do
|
||||
ignore (Q.pop_exn q)
|
||||
done;
|
||||
for i = 1 to m do
|
||||
Q.push q i
|
||||
done;
|
||||
Alcotest.(check (list int)) "filled" (to_list q) expect;
|
||||
Q.compress q;
|
||||
Alcotest.(check (list int)) "filled" (to_list q) expect
|
||||
end
|
||||
|
||||
module Test_rke = Make (struct
|
||||
type t = (int, Bigarray.int_elt) Ke.Rke.t
|
||||
|
||||
module W : sig
|
||||
exception Empty
|
||||
end = struct
|
||||
include Ke.Rke
|
||||
end
|
||||
|
||||
include W
|
||||
|
||||
let available = Ke.Rke.capacity
|
||||
let fold = Ke.Rke.fold
|
||||
let create () = Ke.Rke.create ~capacity:0x100 Bigarray.Int
|
||||
let push = Ke.Rke.push
|
||||
let pop_exn = Ke.Rke.pop_exn
|
||||
let peek_exn = Ke.Rke.peek_exn
|
||||
let is_empty = Ke.Rke.is_empty
|
||||
let length = Ke.Rke.length
|
||||
let iter = Ke.Rke.iter
|
||||
let copy = Ke.Rke.copy
|
||||
let clear = Ke.Rke.clear
|
||||
let compress = Ke.Rke.compress
|
||||
end)
|
||||
|
||||
module Test_weighted_rke = Make (struct
|
||||
type t = (int, Bigarray.int_elt) Ke.Rke.Weighted.t
|
||||
|
||||
module W : sig
|
||||
exception Empty
|
||||
end = struct
|
||||
include Ke.Rke.Weighted
|
||||
end
|
||||
|
||||
include W
|
||||
|
||||
let available = Ke.Rke.Weighted.available
|
||||
let fold = Ke.Rke.Weighted.fold
|
||||
|
||||
let create () =
|
||||
let q, _ = Ke.Rke.Weighted.create ~capacity:0x100 Bigarray.Int in
|
||||
q
|
||||
|
||||
let push = Ke.Rke.Weighted.push_exn
|
||||
let pop_exn = Ke.Rke.Weighted.pop_exn
|
||||
let peek_exn = Ke.Rke.Weighted.peek_exn
|
||||
let is_empty = Ke.Rke.Weighted.is_empty
|
||||
let length = Ke.Rke.Weighted.length
|
||||
let iter = Ke.Rke.Weighted.iter
|
||||
let copy = Ke.Rke.Weighted.copy
|
||||
let clear = Ke.Rke.Weighted.clear
|
||||
let compress = Ke.Rke.Weighted.compress
|
||||
end)
|
||||
|
||||
module Test_blit = struct
|
||||
module Q = Ke.Rke.Weighted
|
||||
|
||||
let blit_to_bytes src src_off dst dst_off len =
|
||||
Bigstringaf.blit_to_bytes src ~src_off dst ~dst_off ~len
|
||||
|
||||
let blit_of_string src src_off dst dst_off len =
|
||||
Bigstringaf.blit_from_string src ~src_off dst ~dst_off ~len
|
||||
|
||||
let blit_of_bytes src src_off dst dst_off len =
|
||||
Bigstringaf.blit_from_bytes src ~src_off dst ~dst_off ~len
|
||||
|
||||
let test_0 =
|
||||
Alcotest.test_case "peek/keep" `Quick @@ fun () ->
|
||||
let q, _ = Q.create ~capacity:0x100 Bigarray.Char in
|
||||
let _ =
|
||||
Q.N.push_exn q ~blit:blit_of_string ~length:String.length "deadbeef"
|
||||
in
|
||||
let res = Q.N.peek q in
|
||||
Alcotest.(check (list string))
|
||||
"peek:deadbeef" [ "deadbeef" ]
|
||||
(List.map Bigstringaf.to_string res);
|
||||
let tmp = Bytes.create (String.length "deadbeef") in
|
||||
let _ = Q.N.keep_exn q ~blit:blit_to_bytes ~length:Bytes.length tmp in
|
||||
Alcotest.(check string)
|
||||
"keep:deadbeef" "deadbeef"
|
||||
(Bytes.unsafe_to_string tmp)
|
||||
|
||||
let test_1 =
|
||||
Alcotest.test_case "shift" `Quick @@ fun () ->
|
||||
let q, _ = Q.create ~capacity:0x100 Bigarray.Char in
|
||||
let _ =
|
||||
Q.N.push_exn q ~blit:blit_of_string ~length:String.length "deadbeef"
|
||||
in
|
||||
Q.N.shift_exn q (String.length "deadbeef");
|
||||
let res = Q.N.peek q in
|
||||
Alcotest.(check (list string))
|
||||
"peek:empty" []
|
||||
(List.map Bigstringaf.to_string res)
|
||||
|
||||
let test_2 =
|
||||
Alcotest.test_case "push" `Quick @@ fun () ->
|
||||
let q, capacity = Q.create ~capacity:0x10 Bigarray.Char in
|
||||
match
|
||||
Q.N.push q ~blit:blit_of_string ~length:String.length
|
||||
(String.make capacity '\000')
|
||||
with
|
||||
| Some res ->
|
||||
Alcotest.(check (list string))
|
||||
"push:0x00"
|
||||
[ String.make capacity '\000' ]
|
||||
(List.map Bigstringaf.to_string res);
|
||||
let res =
|
||||
Q.N.push q ~blit:blit_of_string ~length:String.length "\x42"
|
||||
in
|
||||
Alcotest.(check (option (list string)))
|
||||
"push:0x42" None
|
||||
(Option.map (List.map Bigstringaf.to_string) res)
|
||||
| None ->
|
||||
Alcotest.failf "Impossible to push %S" (String.make capacity '\000')
|
||||
end
|
||||
|
||||
let () =
|
||||
Alcotest.run "ke"
|
||||
[
|
||||
( "rke",
|
||||
[
|
||||
Test_rke.test_0; Test_rke.test_1; Test_rke.test_2; Test_rke.test_3;
|
||||
Test_rke.test_4; Test_rke.test_5; Test_rke.test_6; Test_rke.test_7;
|
||||
Test_rke.test_8;
|
||||
] );
|
||||
( "rke:weighted",
|
||||
[
|
||||
Test_weighted_rke.test_0; Test_weighted_rke.test_1;
|
||||
Test_weighted_rke.test_2; Test_weighted_rke.test_3;
|
||||
Test_weighted_rke.test_4; Test_weighted_rke.test_5;
|
||||
Test_weighted_rke.test_6; Test_weighted_rke.test_7;
|
||||
Test_weighted_rke.test_8; Test_blit.test_0; Test_blit.test_1;
|
||||
Test_blit.test_2;
|
||||
] );
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue