From 88f006171ffe5f6c2a8d2b21cafaeee00be6ee3b Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 12 May 2014 14:45:12 +0200 Subject: [PATCH] circular lists --- _oasis | 2 +- _tags | 3 +- circList.ml | 114 ++++++++++++++++++++++++++++++++++++++++++++++ circList.mli | 81 ++++++++++++++++++++++++++++++++ containers.mlpack | 3 +- containers.odocl | 3 +- setup.ml | 9 ++-- 7 files changed, 207 insertions(+), 8 deletions(-) create mode 100644 circList.ml create mode 100644 circList.mli diff --git a/_oasis b/_oasis index efd56b7d..af93e4c0 100644 --- a/_oasis +++ b/_oasis @@ -41,7 +41,7 @@ Library "containers" UnionFind, SmallSet, Leftistheap, AbsSet, CSM, MultiMap, ActionMan, BV, QCheck, BencodeOnDisk, Show, TTree, HGraph, Automaton, Conv, Levenshtein, Bidir, Iteratee, - Ty, Tell, BencodeStream, RatTerm, Cause, KMP + Ty, Tell, BencodeStream, RatTerm, Cause, KMP, CircList BuildDepends: unix Library "containers_thread" diff --git a/_tags b/_tags index a0ddaf26..b2c21e26 100644 --- a/_tags +++ b/_tags @@ -1,5 +1,5 @@ # OASIS_START -# DO NOT EDIT (digest: 13877dc814f0b2dee886bafc27842dfc) +# DO NOT EDIT (digest: e6a4388a1190cdbd6a00960fb2e08d7f) # Ignore VCS directories, you can use the same kind of rule outside # OASIS_START/STOP if you want to exclude directories that contains # useless stuff for the build process @@ -63,6 +63,7 @@ "ratTerm.cmx": for-pack(Containers) "cause.cmx": for-pack(Containers) "KMP.cmx": for-pack(Containers) +"circList.cmx": for-pack(Containers) # Library containers_thread "threads/containers_thread.cmxs": use_containers_thread : package(threads) diff --git a/circList.ml b/circList.ml new file mode 100644 index 00000000..9a63e380 --- /dev/null +++ b/circList.ml @@ -0,0 +1,114 @@ + +(* +copyright (c) 2013-2014, simon cruanes +all rights reserved. + +redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. redistributions in binary +form must reproduce the above copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other materials provided with +the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*) + +(** {1 Functional Circular List} + +Those are infinite lists that are built from a finite list of +elements, and cycles through them. *) + +type 'a t = { + front : 'a list; + f_len : int; + rear : 'a list; + r_len : int; +} +(* invariant: if front=[] then rear=[] *) + +let make f f_len r r_len = match f with + | [] -> + assert (f_len = 0); + { front=List.rev r; f_len=r_len; rear=[]; r_len=0; } + | _::_ -> {front=f; f_len; rear=r; r_len; } + +let singleton x = make [x] 1 [] 0 + +let of_list l = make l (List.length l) [] 0 + +let length l = l.f_len + l.r_len + +let cons x l = make (x::l.front) (l.f_len+1) l.rear l.r_len + +let snoc l x = make l.front l.f_len (x::l.rear) (l.r_len+1) + +let next l = match l.front with + | [] -> assert false + | x::l' -> + x, make l' (l.f_len-1) l.rear l.r_len + +let rev l = make l.rear l.r_len l.front l.f_len + +let find p l = + let rec _find p i l = + if i = 0 then None + else + let x, l' = next l in + if p x then Some x else _find p (i-1) l' + in + _find p (length l) l + +let mem ?(eq=fun x y -> x=y) x l = + match find (eq x) l with + | None -> false + | Some _ -> true + +let exists p l = match find p l with + | None -> false + | Some _ -> true + +let for_all p l = + let rec _check i l = + i = 0 || + ( let x, l' = next l in + p x && _check (i-1) l') + in + _check (length l) l + +let fold f acc l = + let rec _fold acc i l = + if i=0 then acc + else + let x, l' = next l in + let acc = f acc x in + _fold acc (i-1) l' + in + _fold acc (length l) l + +type 'a gen = unit -> 'a option +type 'a sequence = ('a -> unit) -> unit + +let gen l = + let l = ref l in + fun () -> + let x, l' = next !l in + l := l'; + Some x + +let seq l k = + let r' = lazy (List.rev l.rear) in + while true do + List.iter k l.front; + List.iter k (Lazy.force r') + done diff --git a/circList.mli b/circList.mli new file mode 100644 index 00000000..fdec46ef --- /dev/null +++ b/circList.mli @@ -0,0 +1,81 @@ + +(* +copyright (c) 2013-2014, simon cruanes +all rights reserved. + +redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. redistributions in binary +form must reproduce the above copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other materials provided with +the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*) + +(** {1 Functional Circular List} + +Those are infinite lists that are built from a finite list of +elements, and cycles through them. +Unless specified otherwise, operations have an amortized cost in O(1). *) + +type +'a t + +val singleton : 'a -> 'a t +(** list that cycles on one element *) + +val of_list : 'a list -> 'a t +(** build a circular list from a list. Linear in the length + of the list *) + +val length : 'a t -> int +(** length of the cycle. *) + +val cons : 'a -> 'a t -> 'a t +(** [cons x l] adds [x] at the beginning of [l] *) + +val snoc : 'a t -> 'a -> 'a t +(** [snoc l x] adds [x] at the end of [l] *) + +val next : 'a t -> 'a * 'a t +(** obtain the next element, and the list rotated by one. *) + +val rev : 'a t -> 'a t +(** reverse the traversal (goes right-to-left from now). *) + +val find : ('a -> bool) -> 'a t -> 'a option +(** [find p l] returns [Some x] where [p x] is [true] + and [x] belongs to [l], or [None] if no such + element exists *) + +val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool +(** does the element belong to the infinite list? *) + +val exists : ('a -> bool) -> 'a t -> bool + +val for_all : ('a -> bool) -> 'a t -> bool + +val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b +(** fold through each element of the list exactly once. *) + +(** {2 Iterators} *) + +type 'a gen = unit -> 'a option +type 'a sequence = ('a -> unit) -> unit + +val gen : 'a t -> 'a gen +(** Generator on elements of the list *) + +val seq : 'a t -> 'a sequence +(** Sequence of elements of the list *) diff --git a/containers.mlpack b/containers.mlpack index d5f309a5..9366fbca 100644 --- a/containers.mlpack +++ b/containers.mlpack @@ -1,5 +1,5 @@ # OASIS_START -# DO NOT EDIT (digest: 404fe51c40218ed7bf430446cec5efde) +# DO NOT EDIT (digest: 157f88a0bbe94188791880b268b7df2a) Cache Deque Gen @@ -48,4 +48,5 @@ BencodeStream RatTerm Cause KMP +CircList # OASIS_STOP diff --git a/containers.odocl b/containers.odocl index d5f309a5..9366fbca 100644 --- a/containers.odocl +++ b/containers.odocl @@ -1,5 +1,5 @@ # OASIS_START -# DO NOT EDIT (digest: 404fe51c40218ed7bf430446cec5efde) +# DO NOT EDIT (digest: 157f88a0bbe94188791880b268b7df2a) Cache Deque Gen @@ -48,4 +48,5 @@ BencodeStream RatTerm Cause KMP +CircList # OASIS_STOP diff --git a/setup.ml b/setup.ml index 9a2d285c..550ad810 100644 --- a/setup.ml +++ b/setup.ml @@ -1,7 +1,7 @@ (* setup.ml generated for the first time by OASIS v0.3.0 *) (* OASIS_START *) -(* DO NOT EDIT (digest: b545212f57a5e5b473eeea4866484af0) *) +(* DO NOT EDIT (digest: 6abff81b4f6ff21a732c0e62491fa464) *) (* Regenerated by OASIS v0.4.4 Visit http://oasis.forge.ocamlcore.org for more information and @@ -7006,7 +7006,8 @@ let setup_t = "BencodeStream"; "RatTerm"; "Cause"; - "KMP" + "KMP"; + "CircList" ]; lib_pack = true; lib_internal_modules = []; @@ -7393,7 +7394,7 @@ let setup_t = }; oasis_fn = Some "_oasis"; oasis_version = "0.4.4"; - oasis_digest = Some "\228\227\"@\138\216\007\132\190[\139\215a\153B<"; + oasis_digest = Some "\174j\228\162\204\138v>\191a1\251\130\209\232\003"; oasis_exec = None; oasis_setup_args = []; setup_update = false @@ -7401,6 +7402,6 @@ let setup_t = let setup () = BaseSetup.setup setup_t;; -# 7405 "setup.ml" +# 7406 "setup.ml" (* OASIS_STOP *) let () = setup ();;