Module Incremental__Node
A module internal to Incremental. Users should see Incremental_intf
.
A Node.t
is one node in the incremental DAG. The key invariants of a node t
are:
- if
is_necessary t
, thent.height > c.height
, for all childrenc
oft
. - if
is_necessary t
, thent.height > Scope.height t.created_in
. is_necessary p
for all parentsp
oft
.t.height < p.height
for all parentsp
oft
.needs_to_be_computed t = is_in_recompute_heap t
.
Outside of stabilization, when the recompute heap is empty, the invariant implies that if is_necessary t
, then t.recomputed_at >= c.changed_at
for all children c
of t
. I.e. it implies that all necessary nodes aren't stale.
module Packed : sig ... end
For performance reasons, we do not use an OCaml existential type for
Node.Packed.t
:
include module type of sig ... end with module Packed := Incremental__.Types.Node.Packed
type 'a t
= 'a Incremental__Types.Node.t
=
{
id : Incremental__.Node_id.t;
mutable recomputed_at : Incremental__.Stabilization_num.t;
mutable value_opt : 'a Incremental__.Import.Uopt.t;
mutable kind : 'a Incremental__Types.Kind.t;
mutable cutoff : 'a Incremental__.Cutoff.t;
mutable changed_at : Incremental__.Stabilization_num.t;
mutable num_on_update_handlers : int;
mutable num_parents : int;
mutable parent1_and_beyond : Incremental__Types.Node.Packed.t Incremental__.Import.Uopt.t array;
mutable parent0 : Incremental__Types.Node.Packed.t Incremental__.Import.Uopt.t;
mutable created_in : Incremental__Types.Scope.t;
mutable next_node_in_same_scope : Incremental__Types.Node.Packed.t Incremental__.Import.Uopt.t;
mutable height : int;
mutable height_in_recompute_heap : int;
mutable prev_in_recompute_heap : Incremental__Types.Node.Packed.t Incremental__.Import.Uopt.t;
mutable next_in_recompute_heap : Incremental__Types.Node.Packed.t Incremental__.Import.Uopt.t;
mutable height_in_adjust_heights_heap : int;
mutable next_in_adjust_heights_heap : Incremental__Types.Node.Packed.t Incremental__.Import.Uopt.t;
mutable old_value_opt : 'a Incremental__.Import.Uopt.t;
mutable observers : 'a Incremental__Types.Internal_observer.t Incremental__.Import.Uopt.t;
mutable is_in_handle_after_stabilization : bool;
mutable on_update_handlers : 'a Incremental__.On_update_handler.t list;
mutable my_parent_index_in_child_at_index : int array;
mutable my_child_index_in_parent_at_index : int array;
mutable force_necessary : bool;
mutable user_info : Core_kernel.Info.t option;
creation_backtrace : Core_kernel.Backtrace.t option;
}
val sexp_of_t : ('a -> Ppx_sexp_conv_lib.Sexp.t) -> 'a t -> Ppx_sexp_conv_lib.Sexp.t
module Packed = Incremental__Types.Node.Packed
val is_valid : 'a t -> bool
val is_necessary : 'a t -> bool
val type_equal_if_phys_same : 'a t -> 'b t -> ('a, 'b) Core_kernel.Type_equal.t option
include Core_kernel.Invariant.S1 with type 'a t := 'a t
val invariant : 'a Base__.Invariant_intf.inv -> 'a t Base__.Invariant_intf.inv
val create : Incremental__.Scope.t -> 'a Incremental__.Kind.t -> 'a t
val set_kind : 'a t -> 'a Incremental__.Kind.t -> unit
One should only set the kind of a node using
set_kind
-- usingt.kind <-
will violate invariants.
val same : _ t -> _ t -> bool
val iteri_children : _ t -> f:(int -> Packed.t -> unit) -> unit
iteri_children t ~f
appliesf
to all children oft
.
val get_parent : _ t -> index:int -> Packed.t
get_parent t ~index
raises unless0 <= index < t.num_parents
.
val add_parent : child:'a t -> parent:'b t -> child_index:int -> unit
val remove_parent : child:'a t -> parent:'b t -> child_index:int -> unit
val swap_children_except_in_kind : _ t -> child1:_ t -> child_index1:int -> child2:_ t -> child_index2:int -> unit
val is_const : _ t -> bool
val is_in_recompute_heap : _ t -> bool
val is_necessary : _ t -> bool
is_necessary t
ifft
is a descendant of an observer ort
is aFreeze
node.
val is_valid : _ t -> bool
is_valid t
returnstrue
iff the left-hand-side oft
's defining bind hasn't changed sincet
was created.
val should_be_invalidated : _ t -> bool
should_be_invalidated t
returnstrue
ifft
has an invalid child that implies thatt
should be invalid. It doesn't take into accountt.created_in
.
val edge_is_stale : child:_ t -> parent:_ t -> bool
edge_is_stale
returnstrue
iffchild
has changed sinceparent
was computed, and impliesis_stale parent
.edge_is_stale
is constant-time.
val is_stale : _ t -> bool
is_stale t
is true ift
has never been computed or if some child changed sincet
was last computed.is_stale
doesn't take into accountt.created_in
.
val needs_to_be_computed : _ t -> bool
needs_to_be_computed
isis_necessary t && is_stale t
val value_exn : 'a t -> 'a
Getting the value of a node.
value_exn t
raises iffUopt.is_none t.value_opt
.unsafe_value t
is safe iffUopt.is_some t.value_opt
.
val unsafe_value : 'a t -> 'a
val get_cutoff : 'a t -> 'a Incremental__.Cutoff.t
val set_cutoff : 'a t -> 'a Incremental__.Cutoff.t -> unit
val on_update : 'a t -> 'a Incremental__.On_update_handler.t -> unit
on_update t on_update_handler
adds an on-update handler tot
.
val run_on_update_handlers : 'a t -> 'a Incremental__.On_update_handler.Node_update.t -> now:Incremental__.Stabilization_num.t -> unit
run_on_update_handlers t node_update ~now
runst
's on-update handlers, except those created at the stabilizationnow
.
val keep_node_creation_backtrace : bool Core_kernel.ref
val user_info : _ t -> Core_kernel.Info.t option
val set_user_info : _ t -> Core_kernel.Info.t option -> unit
val has_child : _ t -> child:_ t -> bool
These functions are meant for debug, as they are not very efficient.