Utils: fix Utils.take_n in presence of duplicates

This commit is contained in:
Grégoire Henry 2017-08-22 21:55:31 +02:00
parent 662cc6a8ee
commit 2c8b46a835
3 changed files with 98 additions and 13 deletions

View File

@ -210,35 +210,40 @@ let take_n_unsorted n l =
| x :: xs -> loop (x :: acc) (pred n) xs in | x :: xs -> loop (x :: acc) (pred n) xs in
loop [] n l loop [] n l
module Bounded(E: Set.OrderedType) = struct module Bounded(E: Set.OrderedType) : sig
(* TODO one day replace list by an heap array *) type t
val create: int -> t
val insert: E.t -> t -> unit
val get: t -> E.t list
end = struct
(* TODO one day replace the list by an heap array *)
type t = { type t = {
bound : int ; bound : int ;
mutable size : int ; mutable size : int ;
mutable data : E.t list ; mutable data : E.t list ;
} }
let create bound = { bound ; size = 0 ; data = [] }
let create bound =
if bound <= 0 then invalid_arg "Utils.Bounded(_).create" ;
{ bound ; size = 0 ; data = [] }
let rec push x = function let rec push x = function
| [] -> [x] | [] -> [x]
| (y :: xs) as ys -> | (y :: xs) as ys ->
let c = compare x y in if E.compare x y <= 0
if c < 0 then x :: ys else if c = 0 then ys else y :: push x xs then x :: ys
else y :: push x xs
let replace x xs =
match xs with
| y :: xs when compare x y > 0 ->
push x xs
| xs -> xs
let insert x t = let insert x t =
if t.size < t.bound then begin if t.size < t.bound then begin
t.size <- t.size + 1 ; t.size <- t.size + 1 ;
t.data <- push x t.data t.data <- push x t.data
end else if E.compare (List.hd t.data) x < 0 then end else if E.compare (List.hd t.data) x < 0 then
t.data <- replace x t.data t.data <- push x (List.tl t.data)
let get { data } = data let get { data } = data

View File

@ -2,6 +2,7 @@
SRCDIR=../../src SRCDIR=../../src
TESTS := \ TESTS := \
utils \
merkle \ merkle \
data-encoding \ data-encoding \
stream-data-encoding \ stream-data-encoding \
@ -55,8 +56,27 @@ test-merkle: ${LIB} ${TEST_MERKLE_IMPLS:.ml=.cmx}
clean:: clean::
rm -f test-merkle rm -f test-merkle
############################################################################ ############################################################################
## Data_encoding ## Utils
.PHONY:run-test-utils
run-test-utils:
@echo
./test-utils
TEST_UTILS_IMPLS := \
test_utils.ml
test-utils: ${LIB} ${TEST_UTILS_IMPLS:.ml=.cmx}
@echo LINK $(notdir $@)
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
clean::
rm -f test-utils
############################################################################
## Utils
.PHONY:run-test-data-encoding .PHONY:run-test-data-encoding
run-test-data-encoding: run-test-data-encoding:

60
test/utils/test_utils.ml Normal file
View File

@ -0,0 +1,60 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2016. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Error_monad
open Hash
let rec (--) i j =
if j < i then []
else i :: (i+1) -- j
let rec permut = function
| [] -> [[]]
| x :: xs ->
let insert xs =
let rec loop acc left right =
match right with
| [] -> List.rev (x :: left) :: acc
| y :: ys ->
loop
((List.rev_append left (x :: right)) :: acc)
(y :: left) ys in
loop [] [] xs in
List.concat (List.map insert (permut xs))
let test_take_n _ =
ListLabels.iter (permut [1;2;3;4;5;6;7;8;9]) ~f:begin fun xs ->
Assert.equal ~msg:__LOC__ (take_n ~compare 1 xs) [9]
end ;
ListLabels.iter (permut [1;2;3;4;5;6;7;8;9]) ~f:begin fun xs ->
Assert.equal ~msg:__LOC__ (take_n ~compare 3 xs) [7;8;9]
end ;
let inv_compare x y = compare y x in
ListLabels.iter (permut [1;2;3;4;5;6;7;8;9]) ~f:begin fun xs ->
Assert.equal ~msg:__LOC__ (take_n ~compare:inv_compare 3 xs) [3;2;1]
end ;
(* less elements than the bound. *)
ListLabels.iter (permut [1;2;3;4;5;6;7;8;9]) ~f:begin fun xs ->
Assert.equal ~msg:__LOC__ (take_n ~compare 12 xs) [1;2;3;4;5;6;7;8;9]
end ;
(* with duplicates. *)
ListLabels.iter (permut [1;2;3;3;4;5;5;5;6]) ~f:begin fun xs ->
Assert.equal ~msg:__LOC__ (take_n ~compare 3 xs) [5;5;6]
end ;
ListLabels.iter (permut [1;2;3;3;4;5;5;5;6]) ~f:begin fun xs ->
Assert.equal ~msg:__LOC__ (take_n ~compare 5 xs) [4;5;5;5;6]
end ;
return ()
let tests : (string * (string -> unit tzresult Lwt.t)) list = [
"take_n", test_take_n ;
]
let () =
Test.run "utils." tests