From d6120d478464c0ac327663935292b5ad0806360a Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 10 May 2017 08:58:51 +0200 Subject: [PATCH] add `CCSimple_queue` to containers.data --- _oasis | 2 +- doc/intro.txt | 1 + src/data/CCSimple_queue.ml | 79 +++++++++++++++++++++++++++++++++++++ src/data/CCSimple_queue.mli | 59 +++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 src/data/CCSimple_queue.ml create mode 100644 src/data/CCSimple_queue.mli diff --git a/_oasis b/_oasis index aaf86b7b..550ef65f 100644 --- a/_oasis +++ b/_oasis @@ -67,7 +67,7 @@ Library "containers_data" CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl, CCMixmap, CCRingBuffer, CCIntMap, CCPersistentArray, CCMixset, CCGraph, CCHashSet, CCBitField, - CCHashTrie, CCWBTree, CCRAL, + CCHashTrie, CCWBTree, CCRAL, CCSimple_queue, CCImmutArray, CCHet, CCZipper BuildDepends: bytes # BuildDepends: bytes, bisect_ppx diff --git a/doc/intro.txt b/doc/intro.txt index 72eb19d2..01244284 100644 --- a/doc/intro.txt +++ b/doc/intro.txt @@ -93,6 +93,7 @@ CCPersistentArray CCPersistentHashtbl CCRAL CCRingBuffer +CCSimple_queue CCTrie CCWBTree } diff --git a/src/data/CCSimple_queue.ml b/src/data/CCSimple_queue.ml new file mode 100644 index 00000000..0b16449b --- /dev/null +++ b/src/data/CCSimple_queue.ml @@ -0,0 +1,79 @@ + +(* This file is free software, part of containers. See file "license" for more details. *) + +(** {1 Functional queues (fifo)} *) + +type 'a t = { + hd : 'a list; + tl : 'a list; +} (** Queue containing elements of type 'a *) + +let empty = { + hd = []; + tl = []; +} + +(* invariant: if hd=[], then tl=[] *) +let _make hd tl = match hd with + | [] -> {hd=List.rev tl; tl=[] } + | _::_ -> {hd; tl; } + +let is_empty q = q.hd = [] + +let push x q = {q with tl = x :: q.tl; } + +let snoc q x = push x q + +let peek_exn q = + match q.hd with + | [] -> assert (q.tl = []); raise (Invalid_argument "Queue.peek") + | x::_ -> x + +let peek q = match q.hd with + | [] -> None + | x::_ -> Some x + +let pop_exn q = + match q.hd with + | [] -> assert (q.tl = []); raise (Invalid_argument "Queue.peek") + | x::hd' -> + let q' = _make hd' q.tl in + x, q' + +let pop q = + try Some (pop_exn q) + with Invalid_argument _ -> None + +let junk q = + try + let _, q' = pop_exn q in + q' + with Invalid_argument _ -> q + +(** Append two queues. Elements from the second one come + after elements of the first one *) +let append q1 q2 = + { hd=q1.hd; + tl=q2.tl @ (List.rev_append q2.hd q1.tl); + } + +let map f q = { hd=List.map f q.hd; tl=List.map f q.tl; } + +let size q = List.length q.hd + List.length q.tl + +let (>|=) q f = map f q + +let fold f acc q = + let acc' = List.fold_left f acc q.hd in + List.fold_right (fun x acc -> f acc x) q.tl acc' + +let iter f q = fold (fun () x -> f x) () q + +type 'a sequence = ('a -> unit) -> unit + +let to_seq q = fun k -> iter k q + +let of_seq seq = + let q = ref empty in + seq (fun x -> q := push x !q); + !q diff --git a/src/data/CCSimple_queue.mli b/src/data/CCSimple_queue.mli new file mode 100644 index 00000000..1b3085af --- /dev/null +++ b/src/data/CCSimple_queue.mli @@ -0,0 +1,59 @@ + +(* This file is free software, part of containers. See file "license" for more details. *) + +(** {1 Functional queues (fifo)} *) + +(** Simple implementation of functional queues + @since NEXT_RELEASE *) + +type +'a t +(** Queue containing elements of type 'a *) + +val empty : 'a t + +val is_empty : 'a t -> bool + +val push : 'a -> 'a t -> 'a t +(** Push element at the end of the queue *) + +val snoc : 'a t -> 'a -> 'a t +(** Flip version of {!push} *) + +val peek : 'a t -> 'a option +(** First element of the queue *) + +val peek_exn : 'a t -> 'a +(** Same as {!peek} but + @raise Invalid_argument if the queue is empty *) + +val pop : 'a t -> ('a * 'a t) option +(** Get and remove the first element *) + +val pop_exn : 'a t -> ('a * 'a t) +(** Same as {!pop}, but fails on empty queues. + @raise Invalid_argument if the queue is empty *) + +val junk : 'a t -> 'a t +(** Remove first element. If the queue is empty, do nothing. *) + +val append : 'a t -> 'a t -> 'a t +(** Append two queues. Elements from the second one come + after elements of the first one. + Linear in the size of the second queue. *) + +val map : ('a -> 'b) -> 'a t -> 'b t +(** Map values *) + +val (>|=) : 'a t -> ('a -> 'b) -> 'b t + +val size : 'a t -> int +(** Number of elements in the queue (linear in time) *) + +val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b + +val iter : ('a -> unit) -> 'a t -> unit + +type 'a sequence = ('a -> unit) -> unit +val to_seq : 'a t -> 'a sequence +val of_seq : 'a sequence -> 'a t +