vendored lwt-dllist, moved data structures to separate library

This commit is contained in:
tali 2024-01-31 16:02:40 -05:00
parent 47185c83e1
commit 484941c3ce
14 changed files with 205 additions and 53 deletions

View File

@ -1,7 +1,3 @@
open! Import
include (val Logging.sublogs logger "Wheel")
type ('k, 'v) t = { type ('k, 'v) t = {
mutable index : int; mutable index : int;
entries : ('k, 'v) entry array; entries : ('k, 'v) entry array;

101
lib/data/dllist.ml Normal file
View File

@ -0,0 +1,101 @@
(* This file was originally part of lwt-dllist, which is licensed
under MIT: https://github.com/ocsigen/lwt/blob/master/LICENSE.md. *)
type 'a t = {
mutable prev : 'a t;
mutable next : 'a t;
}
type 'a node = {
mutable node_prev : 'a t;
mutable node_next : 'a t;
mutable node_active : bool;
node_data : 'a;
}
(* XXX: technically [.node_next]/[.node_prev] *are* mutated in [remove] but they are [Obj.magic]'d
into ['a t] first.*)
[@@warning "-69"]
external seq_of_node : 'a node -> 'a t = "%identity"
external node_of_seq : 'a t -> 'a node = "%identity"
let create () =
let rec seq = { prev = seq; next = seq } in
seq
let is_empty seq = seq.next == seq
let remove node =
if node.node_active then begin
node.node_active <- false;
let seq = seq_of_node node in
seq.prev.next <- seq.next;
seq.next.prev <- seq.prev
end
let add_l data seq =
let node = { node_prev = seq; node_next = seq.next; node_data = data; node_active = true } in
seq.next.prev <- seq_of_node node;
seq.next <- seq_of_node node;
node
let add_r data seq =
let node = { node_prev = seq.prev; node_next = seq; node_data = data; node_active = true } in
seq.prev.next <- seq_of_node node;
seq.prev <- seq_of_node node;
node
let take_l seq =
if is_empty seq then raise Not_found;
begin
let node = node_of_seq seq.next in
remove node;
node.node_data
end
let take_r seq =
if is_empty seq then raise Not_found;
begin
let node = node_of_seq seq.prev in
remove node;
node.node_data
end
let fold_r f seq acc =
let rec loop curr acc =
if curr == seq then
acc
else
let node = node_of_seq curr in
if node.node_active then
loop node.node_prev (f node.node_data acc)
else
loop node.node_prev acc
in
loop seq.prev acc
let find f seq =
let rec loop curr =
if curr == seq then
raise Not_found
else
let node = node_of_seq curr in
if node.node_active && f node.node_data then
node.node_data
else
loop node.node_next
in
loop seq.next
let exists f seq =
let rec loop curr =
if curr == seq then
false
else
let node = node_of_seq curr in
if node.node_active && f node.node_data then
true
else
loop node.node_next
in
loop seq.next

66
lib/data/dllist.mli Normal file
View File

@ -0,0 +1,66 @@
(* This file was originally part of lwt-dllist, which is licensed
under MIT: https://github.com/ocsigen/lwt/blob/master/LICENSE.md. *)
type 'a t
(** Type of a sequence holding values of type ['a] *)
type 'a node
(** Type of a node holding one value of type ['a] in a sequence *)
(** {2 Operation on nodes} *)
val remove : 'a node -> unit
(** Removes a node from the sequence it is part of. It does nothing
if the node has already been removed. *)
(** {2 Operations on sequence} *)
val create : unit -> 'a t
(** [create ()] creates a new empty sequence *)
val is_empty : 'a t -> bool
(** Returns [true] iff the given sequence is empty *)
val add_l : 'a -> 'a t -> 'a node
(** [add_l x s] adds [x] to the left of the sequence [s] *)
val add_r : 'a -> 'a t -> 'a node
(** [add_r x s] adds [x] to the right of the sequence [s] *)
val take_l : 'a t -> 'a
(** [take_l x s] removes and returns the leftmost element of [s]
@raise Not_found if the sequence is empty *)
val take_r : 'a t -> 'a
(** [take_l x s] removes and returns the rightmost element of [s]
@raise Not_found if the sequence is empty *)
(** {2 Sequence iterators} *)
(** Note: it is OK to remove a node while traversing a sequence *)
(* val fold_l : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b *)
(* (\** [fold_l f s] is: *)
(* {[ *)
(* fold_l f s x = f en (... (f e2 (f e1 x))) *)
(* ]} *)
(* where [e1], [e2], ..., [en] are the elements of [s] *)
(* *\) *)
val fold_r : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b
(** [fold_r f s] is:
{[
fold_r f s x = f e1 (f e2 (... (f en x)))
]}
where [e1], [e2], ..., [en] are the elements of [s]
*)
val find : ('a -> bool) -> 'a t -> 'a
(** [find_node_l f s] returns the first element of [s] starting from the left
that satisfies [f] or raises [Not_found] if none exists. *)
val exists : ('a -> bool) -> 'a t -> bool
(** [find_node_l f s] returns [true] if some node [s] starting from the left
that satisfies [f] or returns [false] if none exists. *)

5
lib/data/dune Normal file
View File

@ -0,0 +1,5 @@
(library
(package talircd)
(name data)
(inline_tests)
(preprocess (pps ppx_expect)))

21
lib/data/list.ml Normal file
View File

@ -0,0 +1,21 @@
include Stdlib.List
let flat_map f xs =
let rec iter = function
| [] -> []
| x :: xs -> append_then_iter xs (f x)
[@@tail_mod_cons]
and append_then_iter xs = function
| [] -> iter xs
| y :: ys -> y :: append_then_iter xs ys
[@@tail_mod_cons]
in
iter xs
let iter_up_to f xs ~limit =
let rec iter n = function
| x :: xs when n > 0 ->
f x; iter (n - 1) xs
| _ -> ()
in
iter limit xs

View File

@ -1,5 +1,3 @@
open Import
let%expect_test _ = let%expect_test _ =
let print_list print_ele xs = let print_list print_ele xs =
let rec iter pre post = function let rec iter pre post = function

View File

@ -1,7 +1,3 @@
open Import
include (val Logging.sublogs logger "Wheel")
type 'a t = { type 'a t = {
entries : 'a Dllist.t array; entries : 'a Dllist.t array;
mutable index : int; mutable index : int;
@ -21,7 +17,7 @@ let add t v =
let[@tail_mod_cons] rec empty t = let[@tail_mod_cons] rec empty t =
match Dllist.take_l (queue t) with match Dllist.take_l (queue t) with
| x -> x :: empty t | x -> x :: empty t
| exception Dllist.Empty -> [] | exception Not_found -> []
let tick t = let tick t =
t.index <- (t.index + 1) mod Array.length t.entries; t.index <- (t.index + 1) mod Array.length t.entries;

View File

@ -2,7 +2,7 @@
(package talircd) (package talircd)
(name server) (name server)
(libraries (libraries
lwt lwt.unix lwt-dllist fmt lwt lwt.unix fmt
logging irc) logging irc data)
(inline_tests) (inline_tests)
(preprocess (pps ppx_expect))) (preprocess (pps ppx_expect)))

View File

@ -1,5 +1,5 @@
include Data
include Irc include Irc
module Dllist = Lwt_dllist
type sockaddr = Unix.sockaddr type sockaddr = Unix.sockaddr
type fd = Lwt_unix.file_descr type fd = Lwt_unix.file_descr
@ -16,28 +16,4 @@ module Result_syntax = struct
let ( let+ ) r f = Result.map f r let ( let+ ) r f = Result.map f r
end end
module List = struct
include List
let flat_map f xs =
let rec iter = function
| [] -> []
| x :: xs -> append_then_iter xs (f x)
[@@tail_mod_cons]
and append_then_iter xs = function
| [] -> iter xs
| y :: ys -> y :: append_then_iter xs ys
[@@tail_mod_cons]
in
iter xs
let iter_up_to f xs ~limit =
let rec iter n = function
| x :: xs when n > 0 ->
f x; iter (n - 1) xs
| _ -> ()
in
iter limit xs
end
include (val Logging.logs "Irc") include (val Logging.logs "Irc")

View File

@ -36,5 +36,5 @@ module Bcc = struct
let rec send_all msg = let rec send_all msg =
match Dllist.take_l _recipients with match Dllist.take_l _recipients with
| obx -> obx.bcc_incl <- false; send obx msg; send_all msg | obx -> obx.bcc_incl <- false; send obx msg; send_all msg
| exception Dllist.Empty -> () | exception Not_found -> ()
end end

View File

@ -57,8 +57,8 @@ let join chan user =
end end
let membership chan user = let membership chan user =
Dllist.find_node_l (fun mem -> mem.mem_chan == chan) Dllist.find (fun mem -> mem.mem_chan == chan)
user.membership |> Dllist.get user.membership
let part mem = let part mem =
try try

View File

@ -46,19 +46,12 @@ let channels t =
Dllist.fold_r (fun m xs -> m.mem_chan :: xs) t.membership [] Dllist.fold_r (fun m xs -> m.mem_chan :: xs) t.membership []
let highest_membership_priv t = let highest_membership_priv t =
Dllist.fold_l (fun m p -> max m.mem_priv p) t.membership Normal Dllist.fold_r (fun m p -> max m.mem_priv p) t.membership Normal
let is_member t chan = let is_member t chan =
try Dllist.exists (fun m -> m.mem_chan == chan)
Dllist.find_node_l (fun m -> m.mem_chan == chan) t.membership
t.membership |> ignore;
true
with Not_found ->
false
let find_common_channel t1 t2 = let find_common_channel t1 t2 =
let node = let mem = Dllist.find (fun m -> is_member t2 m.mem_chan) t1.membership in
Dllist.find_node_l (fun m -> is_member t2 m.mem_chan) mem.mem_chan
t1.membership
in
(Dllist.get node).mem_chan