diff --git a/src/bounded_queue/bounded_queue_intf.mli b/src/bounded_queue/bounded_queue_intf.mli index 8f940a3d..532b1d4f 100644 --- a/src/bounded_queue/bounded_queue_intf.mli +++ b/src/bounded_queue/bounded_queue_intf.mli @@ -35,6 +35,8 @@ module type BOUNDED_QUEUE = sig (** [of_list_exn ~capacity list] creates a new queue from a list. @raises Full if the length of [list] is greater than [capacity]. + + 🐌 This is a linear-time operation. {[ # open Saturn.Bounded_queue @@ -107,7 +109,9 @@ module type BOUNDED_QUEUE = sig queue is full. *) end -(** {1 Examples} +(** {1 Examples} *) + +(** {2 Sequential example} An example top-level session: {[ # open Saturn.Bounded_queue @@ -135,9 +139,16 @@ end - : int option = None # pop_exn t Exception: Saturn__Bounded_queue.Empty.]} +*) + +(** {2 Multicore example} + + Note: The barrier is used in this example solely to make the results more + interesting by increasing the likelihood of parallelism. Spawning a domain is + a costly operation, especially compared to the relatively small amount of work + being performed here. In practice, using a barrier in this manner is unnecessary. - A multicore example: - {@ocaml non-deterministic[ + {@ocaml non-deterministic=command[ # open Saturn.Bounded_queue # let t :int t = create ~capacity:4 () val t : int t = diff --git a/src/bounded_stack.mli b/src/bounded_stack.mli index 5974aeed..fd13ad30 100644 --- a/src/bounded_stack.mli +++ b/src/bounded_stack.mli @@ -22,6 +22,7 @@ val of_list_exn : ?capacity:int -> 'a list -> 'a t @raises Full if the [list] is longer than the capacity of the stack. + 🐌 This is a linear-time operation. {[ # open Saturn.Bounded_stack # let t : int t = of_list_exn [1;2;3;4] @@ -106,18 +107,23 @@ val push_exn : 'a t -> 'a -> unit val try_push : 'a t -> 'a -> bool (** [try_push stack element] tries to add [element] to the top of the [stack]. Returns [true] if the element was successfully added, or [false] if the - stack is full. *) + stack is full. +*) val push_all_exn : 'a t -> 'a list -> unit (** [push_all_exn stack elements] adds all [elements] to the top of the [stack]. - @raises Full if the [stack] is full. *) + @raises Full if the [stack] is full. + + 🐌 This is a linear-time operation on the size of [elements]. *) val try_push_all : 'a t -> 'a list -> bool (** [try_push_all stack elements] tries to add all [elements] to the top of the [stack]. Returns [true] if the elements were successfully added, or [false] if the stack is full. +🐌 This is a linear-time operation on the size of [elements]. + {[ # let t : int t = create () val t : int t = @@ -142,21 +148,29 @@ bottom. val of_seq : ?capacity:int -> 'a Seq.t -> 'a t (** [of_seq seq] creates a stack from a [seq]. It must be finite. - @raises Full if the [list] is longer than the capacity of the stack. + @raises Full if the [seq] is longer than the capacity of the stack. + + 🐌 This is a linear-time operation. *) val add_seq_exn : 'a t -> 'a Seq.t -> unit (** [add_seq_exn stack seq] adds all elements of [seq] to the top of the [stack]. [seq] must be finite. -@raises Full if the [seq] is too long to fit in the stack. *) +@raises Full if the [seq] is too long to fit in the stack. + +🐌 This is a linear-time operation on the size of [seq]. *) val try_add_seq : 'a t -> 'a Seq.t -> bool (** [try_add_seq stack seq] tries to add all elements of [seq] to the top of the [stack]. Returns [true] if the elements were successfully added, or [false] if -the [seq] is too long to fit in the stack. *) +the [seq] is too long to fit in the stack. + +🐌 This is a linear-time operation. *) + +(** {1 Examples} *) -(** {1 Examples} +(** {2 Sequential example} An example top-level session: {[ # open Saturn.Bounded_stack @@ -176,27 +190,36 @@ the [seq] is too long to fit in the stack. *) - : int option = None # pop_exn t Exception: Saturn__Bounded_stack.Empty.]} +*) + +(** {2 Multicore example} + Note: The barrier is used in this example solely to make the results more + interesting by increasing the likelihood of parallelism. Spawning a domain is + a costly operation, especially compared to the relatively small amount of work + being performed here. In practice, using a barrier in this manner is unnecessary. - A multicore example: - {@ocaml non-deterministic[ + + {@ocaml non-deterministic=command[ # open Saturn.Bounded_stack # let t :int t = create () val t : int t = # let barrier = Atomic.make 2 val barrier : int Atomic.t = + # let pusher () = Atomic.decr barrier; while Atomic.get barrier != 0 do Domain.cpu_relax () done; - try_push_all t [1;2;3] |> ignore; push_exn t 42; push_exn t 12 val pusher : unit -> unit = + # let popper () = Atomic.decr barrier; while Atomic.get barrier != 0 do Domain.cpu_relax () done; List.init 6 (fun i -> Domain.cpu_relax (); pop_opt t) val popper : unit -> int option list = + # let domain_pusher = Domain.spawn pusher val domain_pusher : unit Domain.t = # let domain_popper = Domain.spawn popper @@ -206,5 +229,4 @@ the [seq] is too long to fit in the stack. *) # Domain.join domain_popper - : int option list = [Some 42; Some 3; Some 2; Some 1; None; Some 12] ]} - *) diff --git a/src/treiber_stack.mli b/src/treiber_stack.mli index 3980a9bd..f0647ed4 100644 --- a/src/treiber_stack.mli +++ b/src/treiber_stack.mli @@ -74,6 +74,8 @@ val push : 'a t -> 'a -> unit val push_all : 'a t -> 'a list -> unit (** [push_all stack elements] adds all [elements] to the top of the [stack]. + 🐌 This is a linear-time operation on the size of [elements]. + {[ # let t : int t = create () val t : int t = @@ -96,13 +98,19 @@ bottom. 🐌 This is a linear time operation. *) val of_seq : 'a Seq.t -> 'a t -(** [of_seq seq] creates a stack from a [seq]. It must be finite. *) +(** [of_seq seq] creates a stack from a [seq]. It must be finite. + + 🐌 This is a linear-time operation. *) val add_seq : 'a t -> 'a Seq.t -> unit (** [add_seq stack seq] adds all elements of [seq] to the top of the -[stack]. [seq] must be finite. *) +[stack]. [seq] must be finite. + + 🐌 This is a linear-time operation on the size of [elements]. *) -(** {1 Examples} +(** {1 Examples} *) + +(** {2 Sequential example} An example top-level session: {[ # open Saturn.Stack @@ -120,14 +128,21 @@ val add_seq : 'a t -> 'a Seq.t -> unit - : int list = [2; 1; 42] # pop_exn t Exception: Saturn__Treiber_stack.Empty.]} +*) - A multicore example: - {@ocaml non-deterministic[ +(** {2 Multicore example} + Note: The barrier is used in this example solely to make the results more + interesting by increasing the likelihood of parallelism. Spawning a domain is + a costly operation, especially compared to the relatively small amount of work + being performed here. In practice, using a barrier in this manner is unnecessary. + + {@ocaml non-deterministic=command[ # open Saturn.Stack # let t : int t = create () val t : int t = # let barrier = Atomic.make 2 val barrier : int Atomic.t = + # let pusher () = Atomic.decr barrier; while Atomic.get barrier != 0 do Domain.cpu_relax () done; @@ -135,11 +150,13 @@ val add_seq : 'a t -> 'a Seq.t -> unit push t 42; push t 12 val pusher : unit -> unit = + # let popper () = Atomic.decr barrier; while Atomic.get barrier != 0 do Domain.cpu_relax () done; List.init 6 (fun i -> Domain.cpu_relax (); pop_opt t) val popper : unit -> int option list = + # let domain_pusher = Domain.spawn pusher val domain_pusher : unit Domain.t = # let domain_popper = Domain.spawn popper @@ -149,5 +166,4 @@ val add_seq : 'a t -> 'a Seq.t -> unit # Domain.join domain_popper - : int option list = [Some 42; Some 3; Some 2; Some 1; None; Some 12] ]} - *)