mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-08 12:15:32 -05:00
split CCList.Zipper into its own module, CCZipper in containers.data
This commit is contained in:
parent
6ff6c51687
commit
2c00983262
5 changed files with 170 additions and 176 deletions
2
_oasis
2
_oasis
|
|
@ -60,7 +60,7 @@ Library "containers_data"
|
||||||
CCMixmap, CCRingBuffer, CCIntMap, CCPersistentArray,
|
CCMixmap, CCRingBuffer, CCIntMap, CCPersistentArray,
|
||||||
CCMixset, CCHashconsedSet, CCGraph, CCHashSet, CCBitField,
|
CCMixset, CCHashconsedSet, CCGraph, CCHashSet, CCBitField,
|
||||||
CCHashTrie, CCBloom, CCWBTree, CCRAL, CCAllocCache,
|
CCHashTrie, CCBloom, CCWBTree, CCRAL, CCAllocCache,
|
||||||
CCImmutArray, CCHet
|
CCImmutArray, CCHet, CCZipper
|
||||||
BuildDepends: bytes
|
BuildDepends: bytes
|
||||||
# BuildDepends: bytes, bisect_ppx
|
# BuildDepends: bytes, bisect_ppx
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
|
|
|
||||||
|
|
@ -975,88 +975,6 @@ module Assoc = struct
|
||||||
*)
|
*)
|
||||||
end
|
end
|
||||||
|
|
||||||
(** {2 Zipper} *)
|
|
||||||
|
|
||||||
module Zipper = struct
|
|
||||||
type 'a t = 'a list * 'a list
|
|
||||||
|
|
||||||
let empty = [], []
|
|
||||||
|
|
||||||
let is_empty = function
|
|
||||||
| [], [] -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let to_list (l,r) = List.rev_append l r
|
|
||||||
|
|
||||||
let to_rev_list (l,r) = List.rev_append r l
|
|
||||||
|
|
||||||
(*$Q
|
|
||||||
Q.(pair (list small_int)(list small_int)) (fun z -> \
|
|
||||||
Zipper.to_list z = List.rev (Zipper.to_rev_list z))
|
|
||||||
*)
|
|
||||||
|
|
||||||
let make l = [], l
|
|
||||||
|
|
||||||
let left = function
|
|
||||||
| x::l, r -> l, x::r
|
|
||||||
| [], r -> [], r
|
|
||||||
|
|
||||||
let left_exn = function
|
|
||||||
| x::l, r -> l, x::r
|
|
||||||
| [], _ -> invalid_arg "zipper.left_exn"
|
|
||||||
|
|
||||||
let right = function
|
|
||||||
| l, x::r -> x::l, r
|
|
||||||
| l, [] -> l, []
|
|
||||||
|
|
||||||
let right_exn = function
|
|
||||||
| l, x::r -> x::l, r
|
|
||||||
| _, [] -> invalid_arg "zipper.right_exn"
|
|
||||||
|
|
||||||
let modify f z = match z with
|
|
||||||
| l, [] ->
|
|
||||||
begin match f None with
|
|
||||||
| None -> z
|
|
||||||
| Some x -> l, [x]
|
|
||||||
end
|
|
||||||
| l, x::r ->
|
|
||||||
begin match f (Some x) with
|
|
||||||
| None -> l,r
|
|
||||||
| Some _ -> l, x::r
|
|
||||||
end
|
|
||||||
|
|
||||||
let is_focused = function
|
|
||||||
| _, [] -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let focused = function
|
|
||||||
| _, x::_ -> Some x
|
|
||||||
| _, [] -> None
|
|
||||||
|
|
||||||
let focused_exn = function
|
|
||||||
| _, x::_ -> x
|
|
||||||
| _, [] -> raise Not_found
|
|
||||||
|
|
||||||
let insert x (l,r) = l, x::r
|
|
||||||
|
|
||||||
let remove (l,r) = match r with
|
|
||||||
| [] -> l, []
|
|
||||||
| _ :: r' -> l, r'
|
|
||||||
|
|
||||||
(*$Q
|
|
||||||
Q.(triple int (list small_int)(list small_int)) (fun (x,l,r) -> \
|
|
||||||
Zipper.insert x (l,r) |> Zipper.remove = (l,r))
|
|
||||||
*)
|
|
||||||
|
|
||||||
let drop_before (_, r) = [], r
|
|
||||||
|
|
||||||
let drop_after (l, r) = match r with
|
|
||||||
| [] -> l, []
|
|
||||||
| x :: _ -> l, [x]
|
|
||||||
|
|
||||||
let drop_after_and_focused (l, _) = l, []
|
|
||||||
end
|
|
||||||
|
|
||||||
(** {2 References on Lists} *)
|
(** {2 References on Lists} *)
|
||||||
|
|
||||||
module Ref = struct
|
module Ref = struct
|
||||||
|
|
|
||||||
|
|
@ -341,99 +341,6 @@ module Assoc : sig
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
end
|
end
|
||||||
|
|
||||||
(** {2 Zipper} *)
|
|
||||||
|
|
||||||
module Zipper : sig
|
|
||||||
type 'a t = 'a list * 'a list
|
|
||||||
(** The pair [l, r] represents the list [List.rev_append l r], but
|
|
||||||
with the focus on [r]. *)
|
|
||||||
|
|
||||||
val empty : 'a t
|
|
||||||
(** Empty zipper *)
|
|
||||||
|
|
||||||
val is_empty : _ t -> bool
|
|
||||||
(** Empty zipper? Returns true iff the two lists are empty. *)
|
|
||||||
|
|
||||||
(*$T
|
|
||||||
Zipper.(is_empty empty)
|
|
||||||
not ([42] |> Zipper.make |> Zipper.right |> Zipper.is_empty)
|
|
||||||
*)
|
|
||||||
|
|
||||||
val to_list : 'a t -> 'a list
|
|
||||||
(** Convert the zipper back to a list.
|
|
||||||
[to_list (l,r)] is [List.rev_append l r] *)
|
|
||||||
|
|
||||||
val to_rev_list : 'a t -> 'a list
|
|
||||||
(** Convert the zipper back to a {i reversed} list.
|
|
||||||
In other words, [to_list (l,r)] is [List.rev_append r l]
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val make : 'a list -> 'a t
|
|
||||||
(** Create a zipper pointing at the first element of the list *)
|
|
||||||
|
|
||||||
val left : 'a t -> 'a t
|
|
||||||
(** Go to the left, or do nothing if the zipper is already at leftmost pos *)
|
|
||||||
|
|
||||||
val left_exn : 'a t -> 'a t
|
|
||||||
(** Go to the left, or
|
|
||||||
@raise Invalid_argument if the zipper is already at leftmost pos
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val right : 'a t -> 'a t
|
|
||||||
(** Go to the right, or do nothing if the zipper is already at rightmost pos *)
|
|
||||||
|
|
||||||
val right_exn : 'a t -> 'a t
|
|
||||||
(** Go to the right, or
|
|
||||||
@raise Invalid_argument if the zipper is already at rightmost pos
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val modify : ('a option -> 'a option) -> 'a t -> 'a t
|
|
||||||
(** Modify the current element, if any, by returning a new element, or
|
|
||||||
returning [None] if the element is to be deleted *)
|
|
||||||
|
|
||||||
val insert : 'a -> 'a t -> 'a t
|
|
||||||
(** Insert an element at the current position. If an element was focused,
|
|
||||||
[insert x l] adds [x] just before it, and focuses on [x]
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val remove : 'a t -> 'a t
|
|
||||||
(** [remove l] removes the current element, if any.
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val is_focused : _ t -> bool
|
|
||||||
(** Is the zipper focused on some element? That is, will {!focused}
|
|
||||||
return a [Some v]?
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val focused : 'a t -> 'a option
|
|
||||||
(** Returns the focused element, if any. [focused zip = Some _] iff
|
|
||||||
[empty zip = false] *)
|
|
||||||
|
|
||||||
val focused_exn : 'a t -> 'a
|
|
||||||
(** Returns the focused element, or
|
|
||||||
@raise Not_found if the zipper is at an end *)
|
|
||||||
|
|
||||||
val drop_before : 'a t -> 'a t
|
|
||||||
(** Drop every element on the "left" (calling {!left} then will do nothing).
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val drop_after : 'a t -> 'a t
|
|
||||||
(** Drop every element on the "right" (calling {!right} then will do nothing),
|
|
||||||
keeping the focused element, if any.
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
val drop_after_and_focused : 'a t -> 'a t
|
|
||||||
(** Drop every element on the "right" (calling {!right} then will do nothing),
|
|
||||||
{i including} the focused element if it is present.
|
|
||||||
@since 0.14 *)
|
|
||||||
|
|
||||||
(*$=
|
|
||||||
([1], [2]) (Zipper.drop_after ([1], [2;3]))
|
|
||||||
([1], []) (Zipper.drop_after ([1], []))
|
|
||||||
([1], []) (Zipper.drop_after_and_focused ([1], [2;3]))
|
|
||||||
*)
|
|
||||||
end
|
|
||||||
|
|
||||||
(** {2 References on Lists}
|
(** {2 References on Lists}
|
||||||
@since 0.3.3 *)
|
@since 0.3.3 *)
|
||||||
|
|
||||||
|
|
|
||||||
82
src/data/CCZipper.ml
Normal file
82
src/data/CCZipper.ml
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
(** {1 List Zipper} *)
|
||||||
|
|
||||||
|
type 'a t = 'a list * 'a list
|
||||||
|
|
||||||
|
let empty = [], []
|
||||||
|
|
||||||
|
let is_empty = function
|
||||||
|
| [], [] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let to_list (l,r) = List.rev_append l r
|
||||||
|
|
||||||
|
let to_rev_list (l,r) = List.rev_append r l
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(pair (list small_int)(list small_int)) (fun z -> \
|
||||||
|
to_list z = List.rev (to_rev_list z))
|
||||||
|
*)
|
||||||
|
|
||||||
|
let make l = [], l
|
||||||
|
|
||||||
|
let left = function
|
||||||
|
| x::l, r -> l, x::r
|
||||||
|
| [], r -> [], r
|
||||||
|
|
||||||
|
let left_exn = function
|
||||||
|
| x::l, r -> l, x::r
|
||||||
|
| [], _ -> invalid_arg "zipper.left_exn"
|
||||||
|
|
||||||
|
let right = function
|
||||||
|
| l, x::r -> x::l, r
|
||||||
|
| l, [] -> l, []
|
||||||
|
|
||||||
|
let right_exn = function
|
||||||
|
| l, x::r -> x::l, r
|
||||||
|
| _, [] -> invalid_arg "zipper.right_exn"
|
||||||
|
|
||||||
|
let modify f z = match z with
|
||||||
|
| l, [] ->
|
||||||
|
begin match f None with
|
||||||
|
| None -> z
|
||||||
|
| Some x -> l, [x]
|
||||||
|
end
|
||||||
|
| l, x::r ->
|
||||||
|
begin match f (Some x) with
|
||||||
|
| None -> l,r
|
||||||
|
| Some _ -> l, x::r
|
||||||
|
end
|
||||||
|
|
||||||
|
let is_focused = function
|
||||||
|
| _, [] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let focused = function
|
||||||
|
| _, x::_ -> Some x
|
||||||
|
| _, [] -> None
|
||||||
|
|
||||||
|
let focused_exn = function
|
||||||
|
| _, x::_ -> x
|
||||||
|
| _, [] -> raise Not_found
|
||||||
|
|
||||||
|
let insert x (l,r) = l, x::r
|
||||||
|
|
||||||
|
let remove (l,r) = match r with
|
||||||
|
| [] -> l, []
|
||||||
|
| _ :: r' -> l, r'
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(triple int (list small_int)(list small_int)) (fun (x,l,r) -> \
|
||||||
|
insert x (l,r) |> remove = (l,r))
|
||||||
|
*)
|
||||||
|
|
||||||
|
let drop_before (_, r) = [], r
|
||||||
|
|
||||||
|
let drop_after (l, r) = match r with
|
||||||
|
| [] -> l, []
|
||||||
|
| x :: _ -> l, [x]
|
||||||
|
|
||||||
|
let drop_after_and_focused (l, _) = l, []
|
||||||
87
src/data/CCZipper.mli
Normal file
87
src/data/CCZipper.mli
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
(** {1 List Zipper}
|
||||||
|
|
||||||
|
@since 1.0 *)
|
||||||
|
|
||||||
|
type 'a t = 'a list * 'a list
|
||||||
|
(** The pair [l, r] represents the list [List.rev_append l r], but
|
||||||
|
with the focus on [r]. *)
|
||||||
|
|
||||||
|
val empty : 'a t
|
||||||
|
(** Empty zipper *)
|
||||||
|
|
||||||
|
val is_empty : _ t -> bool
|
||||||
|
(** Empty zipper? Returns true iff the two lists are empty. *)
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
(is_empty empty)
|
||||||
|
not ([42] |> make |> right |> is_empty)
|
||||||
|
*)
|
||||||
|
|
||||||
|
val to_list : 'a t -> 'a list
|
||||||
|
(** Convert the zipper back to a list.
|
||||||
|
[to_list (l,r)] is [List.rev_append l r] *)
|
||||||
|
|
||||||
|
val to_rev_list : 'a t -> 'a list
|
||||||
|
(** Convert the zipper back to a {i reversed} list.
|
||||||
|
In other words, [to_list (l,r)] is [List.rev_append r l] *)
|
||||||
|
|
||||||
|
val make : 'a list -> 'a t
|
||||||
|
(** Create a zipper pointing at the first element of the list *)
|
||||||
|
|
||||||
|
val left : 'a t -> 'a t
|
||||||
|
(** Go to the left, or do nothing if the zipper is already at leftmost pos *)
|
||||||
|
|
||||||
|
val left_exn : 'a t -> 'a t
|
||||||
|
(** Go to the left, or
|
||||||
|
@raise Invalid_argument if the zipper is already at leftmost pos *)
|
||||||
|
|
||||||
|
val right : 'a t -> 'a t
|
||||||
|
(** Go to the right, or do nothing if the zipper is already at rightmost pos *)
|
||||||
|
|
||||||
|
val right_exn : 'a t -> 'a t
|
||||||
|
(** Go to the right, or
|
||||||
|
@raise Invalid_argument if the zipper is already at rightmost pos *)
|
||||||
|
|
||||||
|
val modify : ('a option -> 'a option) -> 'a t -> 'a t
|
||||||
|
(** Modify the current element, if any, by returning a new element, or
|
||||||
|
returning [None] if the element is to be deleted *)
|
||||||
|
|
||||||
|
val insert : 'a -> 'a t -> 'a t
|
||||||
|
(** Insert an element at the current position. If an element was focused,
|
||||||
|
[insert x l] adds [x] just before it, and focuses on [x] *)
|
||||||
|
|
||||||
|
val remove : 'a t -> 'a t
|
||||||
|
(** [remove l] removes the current element, if any. *)
|
||||||
|
|
||||||
|
val is_focused : _ t -> bool
|
||||||
|
(** Is the zipper focused on some element? That is, will {!focused}
|
||||||
|
return a [Some v]? *)
|
||||||
|
|
||||||
|
val focused : 'a t -> 'a option
|
||||||
|
(** Returns the focused element, if any. [focused zip = Some _] iff
|
||||||
|
[empty zip = false] *)
|
||||||
|
|
||||||
|
val focused_exn : 'a t -> 'a
|
||||||
|
(** Returns the focused element, or
|
||||||
|
@raise Not_found if the zipper is at an end *)
|
||||||
|
|
||||||
|
val drop_before : 'a t -> 'a t
|
||||||
|
(** Drop every element on the "left" (calling {!left} then will do nothing). *)
|
||||||
|
|
||||||
|
val drop_after : 'a t -> 'a t
|
||||||
|
(** Drop every element on the "right" (calling {!right} then will do nothing),
|
||||||
|
keeping the focused element, if any. *)
|
||||||
|
|
||||||
|
val drop_after_and_focused : 'a t -> 'a t
|
||||||
|
(** Drop every element on the "right" (calling {!right} then will do nothing),
|
||||||
|
{i including} the focused element if it is present. *)
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
([1], [2]) (drop_after ([1], [2;3]))
|
||||||
|
([1], []) (drop_after ([1], []))
|
||||||
|
([1], []) (drop_after_and_focused ([1], [2;3]))
|
||||||
|
*)
|
||||||
|
|
||||||
Loading…
Add table
Reference in a new issue