···11+v0.4 - Alpha 0.4 UNRELEASED
22+======
33+44+- Add Lwd.update (by @OlivierNicole and @Julow) and Lwd.may_update functions
55+- Lwd.set: change binding before invalidation, otherwise the old value could be re-observed (reported by @voodoos)
66+- brr-lwd: support declarative events and set of css classes
77+- Nottui: fix treatment of some terminal events that were delayed because of improper buffer flushing, reported by @darrenldl
88+99+v0.3 - Alpha 0.3
1010+======
1111+Mon Sep 5 10:57:53 JST 2022
1212+1313+- Add [Lwd_seq.sort_uniq] function
1414+- Make [Lwd_seq.t] injective
1515+- Fix a bug breaking invariants in Lwd_table.remove
1616+- Documentation update contributed by @shubhamkumar13
1717+- Option to disable the default Quit behavior of Nottui contributed by @OhadRau
1818+1919+v0.2 - Alpha 0.2
2020+======
2121+Sun Feb 20 20:49:47 JST 2022
2222+2323+- Lwd.fix operator helps working with graphs that cannot be evaluated in a
2424+ single pass
2525+- brr-lwd library integrates Lwd with Brr library, for writing javascript
2626+ applications
2727+2828+Bug fixes:
2929+- fixed invalidation in Lwd
3030+- restored some internal invariants in Lwd_seq
3131+- fixed behavior of Notty sensors
3232+3333+v0.1 - Alpha 0.1
3434+======
3535+Wed Sep 23 14:51:17 CEST 2020
3636+3737+Preview release, the API is not yet stabilized.
3838+Most features are there, except support for overlays (menu, dialog windows,
3939+popup, ...) in Nottui.
4040+4141+Libraries included in this release:
4242+- Lwd, the definition of reactive documents
4343+- Nottui, reactive terminal interfaces using Notty & Lwd
4444+- Nottui-lwt, an asynchronous mainloop for Nottui
4545+- Tyxml-lwd, strongly-typed reactive webpages in Jsoo using Tyxml & Lwd
+21
forks/lwd/LICENSE
···11+MIT License
22+33+Copyright (c) 2019 Frédéric Bour
44+55+Permission is hereby granted, free of charge, to any person obtaining a copy
66+of this software and associated documentation files (the "Software"), to deal
77+in the Software without restriction, including without limitation the rights
88+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99+copies of the Software, and to permit persons to whom the Software is
1010+furnished to do so, subject to the following conditions:
1111+1212+The above copyright notice and this permission notice shall be included in all
1313+copies or substantial portions of the Software.
1414+1515+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121+SOFTWARE.
···11+# Lwd: a "lightweight document" library
22+33+`Lwd` is a library that lets you build values that changes over time. It is a simple form of incremental computation, in the like of [Incremental](https://github.com/janestreet/incremental) and [React](https://github.com/dbuenzli/react).
44+55+It is only about interactivity. A bunch of companion libraries make it usable in different settings:
66+77+- [Nottui](lib/nottui) renders user interface in the terminal
88+- [Nottui-lwt](lib/nottui-lwt) add support for concurrent/asynchronous UI to Nottui
99+- [Nottui-pretty](lib/nottui-pretty) is an interactive pretty-printer (based on [Pprint](https://github.com/fpottier/pprint))
1010+- [Tyxml-lwd](lib/tyxml-lwd) is a Js_of_ocaml library for making interactive applications, using Lwd for updating the DOM and [Tyxml](https://github.com/ocsigen/tyxml) for writing typesafe HTML Document.
1111+1212+```shell
1313+$ opam pin add tyxml https://github.com/ocsigen/tyxml.git#wraps
1414+```
1515+1616+[TOC]
1717+1818+## Documents?
1919+2020+`Lwd` shines when constructing a single value, which we call a document, by aggregating many sub-documents. These sub-documents might be updated independently and we want to keep a consistent view on the aggregated document: when we observe it, it should be the aggregate of the sub-documents in their current version.
2121+2222+We will illustrate that with some examples. First we need to define the syntax for the final document:
2323+2424+```ocaml
2525+type hypertext =
2626+ | Text of string
2727+ | Link of (unit -> unit) * hypertext
2828+ | List of hypertext list
2929+```
3030+3131+A value of type `hypertext` will be interpreted by a backend. The interpretation is roughly as follows:
3232+3333+- `Text str` simply displays the string `str` to the user (for instance on a terminal)
3434+- `Link (callback, hypertext')` displays the document `hypertext'`.
3535+ If the backend determines that the user is interacting with the content in this sub-document, `callback` is called.
3636+- `List (doc1 :: doc2 :: ...)` displays `doc1` followed by `doc2` followed by `...`.
3737+3838+To keep the example simple, we didn't say anything about styling nor how interactions are determined. For instance, the backend could display plain text in a default color, switch to another color for text below a `Link _` constructor, and keep track of _focus_ by cycling between links when `<TAB>` is pressed and choosing a different color for the focused link.
3939+4040+A navigation menu could look like:
4141+4242+```ocaml
4343+let newline = Text "\n" in
4444+List [
4545+ Text "Welcome to my cafe"; newline;
4646+ Link (display_drink, Text "See drink options"); newline;
4747+ Link (display_food, Text "See food options"); newline;
4848+]
4949+```
5050+5151+We don't yet know how to implement the `display_drink` and `display_food` function but we have enough infrastructure to receive user intent. To complete the task, we will look at the idea of implementing a function that "changes its mind": it returned a value but, because of some circumstances, decide that another value should have been returned.
5252+5353+### Counting clicks
5454+5555+Let's imagine we want to make a button that counts the number of times it has been clicked: at first it displays 0, when triggered the 0 switch to 1, etc.
5656+5757+```ocaml
5858+let counter = ref 0
5959+let on_click () = counter := !counter + 1
6060+6161+let button clicks =
6262+ Link (on_click, Text ("Clicked " ^ string_of_int clicks ^ " times"))
6363+6464+let document = button !counter
6565+```
6666+6767+We now have a counter that is incremented when the button is clicked. However the content of the button is not updated.
6868+6969+This is where `Lwd` comes into play: the `Lwd.var` type behaves almost like a reference but also tracks data dependencies. Let's update the example:
7070+7171+```ocaml
7272+let counter = Lwd.var 0
7373+let on_click () = Lwd.set counter (Lwd.peek counter + 1)
7474+7575+let button clicks =
7676+ Link (on_click, Text ("Clicked " ^ string_of_int clicks ^ " times"))
7777+7878+let document = Lwd.map ~f:button (Lwd.get counter)
7979+```
8080+8181+We make use of the following `Lwd` functions:
8282+8383+```ocaml
8484+(* Variable manipulation function *)
8585+val Lwd.var : 'a -> 'a Lwd.var
8686+val Lwd.set : 'a Lwd.var -> 'a -> unit
8787+val Lwd.peek : 'a Lwd.var -> 'a
8888+```
8989+9090+`var`, `set` and `peek` behave like `ref`, `:=` and `!`. They allocate a mutable cell, change its value and read the value at current time.
9191+9292+```ocaml
9393+val Lwd.get : 'a Lwd.var -> 'a Lwd.t
9494+```
9595+9696+`Lwd.get` reads a mutable cell, but while `Lwd.peek` returns the value immediately, `Lwd.get` lets you access the value wrapped in the `Lwd.t` type.
9797+9898+`Lwd` lets you build graph of computations with mutable inputs. The inputs or sources of the graph are made of `Lwd.var` while the inner nodes are built using combinators.
9999+100100+Here `Lwd.map : ~f:('a -> 'b) -> 'a Lwd.t -> 'b Lwd.t` apply a transformation to a varying value. That value might depend on arbitrary inputs, and if one of these input changes, the transformation will be recomputed too.
101101+102102+When the `Link` is triggered, the counter is incremented. Because `document` depends on the value of the counter it is invalidated.
103103+104104+### Building computation graph
105105+106106+`Lwd.t` implements a few abstractions that should be familiar to seasoned functional programmers:
107107+108108+- it is a _functor_. With `Lwd.map : ~f:('a -> 'b) -> 'a Lwd.t -> 'b Lwd.t` you can transform values and chain the transformations
109109+- it is an _applicative functor_. With `Lwd.map2 : ~f:('a -> 'b -> 'c) -> 'a Lwd.t -> 'b Lwd.t > 'c Lwd.t` you can connect two different chains (making the computation tree shaped, actually with sharing it will form a DAG)
110110+- and, although this should in general be avoided, a _monad_. With `Lwd.join : 'a Lwd.t Lwd.t -> 'a Lwd.t` you can have a first pipeline that computes another pipeline and inject the inner one.
111111+112112+### Consuming computation graph
113113+114114+So far we described how to build values of type `a Lwd.t` but we don't have a way to get access to those `a` outside of the _Lwd_ graph.
115115+116116+That's what `Lwd.root`s are for:
117117+118118+```ocaml
119119+type 'a Lwd.root
120120+val Lwd.observe : ?on_invalidate:('a -> unit) -> 'a t -> 'a root
121121+val Lwd.set_on_invalidate : 'a root -> ('a -> unit) -> unit
122122+123123+val Lwd.sample : 'a root -> 'a
124124+val Lwd.is_damaged : 'a root -> bool
125125+val Lwd.release : 'a root -> unit
126126+```
127127+128128+When you are interested in accessing the content of an `a Lwd.t` value, you create a root by `observe`-ing it.
129129+130130+`Lwd.sample` lets you access the value at the current time.
131131+132132+After calling `Lwd.sample`, the `on_invalidate` callback might be invoked if the value is invalidated: some input changed, the value you sampled is out of date.
133133+134134+When you are done with the `root` and are no longer interested in observing the value, you should call `release`. This call to `release` is very important: the `root` maintain the whole graph alive, so forgetting to `release` leads to memory leaks. After releasing, the on_invalidate callback will not be invoked.
135135+136136+A root can be in three possible states:
137137+138138+- released
139139+- damaged
140140+- sampled
141141+142142+When created, the root is in the `released` state: it does not maintain the graph alive.
143143+144144+Calling `sample` switches the root from the `released` to the `sampled` state.
145145+146146+```mermaid
147147+graph TD;
148148+ R[Released]
149149+ S[Sampled]
150150+ D[Damaged]
151151+ s{"call to sample"}
152152+ i{"graph input change,<br/>call <tt>on_invalidate</tt>"}
153153+ r{"call to release"}
154154+ R-->s
155155+ s-->S
156156+ D-->s
157157+ S-->i
158158+ i-->D
159159+ S-->r
160160+ D-->r
161161+ r-->R
162162+```
163163+164164+## Relation to HTML, DOM, and reactive UI libraries
165165+166166+**Syntax, data description and HTML.** To introduce our first example, we had to build a syntax using the simple `hypertext` algebraic data type. This type serves as an interface between the application and the interactive system: values of this type are produced by the front-end, like our example codes, and consumed by a back-end.
167167+168168+In the case of a web browser, the surface syntax is `HTML` which is much richer and more expressive than `hypertext` but ultimately is just data: a static description of some pieces of information.
169169+170170+**Adding programming languages.** Because static description are too limited for modern websites, Web browsers support the Javascript programming language. Pieces of javascript code can be put in the middle of the HTML syntax.
171171+172172+Similarly the `unit -> unit` parameter of the `Link` constructor allows to inject arbitrary OCaml code in the middle of an `hypertext` document.
173173+174174+**Making things interactive.** Being able to execute arbitrary piece of codes is not enough to make a document interactive: to make things dynamic the code needs to change the contents of the document in return.
175175+176176+Ultimately, interaction comes from this mutual dependency between document and code:
177177+178178+- the document contains codes that are executed in certain circumstances (determined by the meaning of elements of the document).
179179+- when executed, a code can change the document, producing new elements associated to new codes.
180180+- this updated document can then execute new pieces of code, that may update the document, and so on...
181181+182182+**The DOM.** Web browser's solution to allowing document update is the Document Object Model abstraction. The idea is to derive mutable data structures from the syntactic specification: each syntactic construction has a corresponding "DOM class" that can store the same information in mutable fields. Applied to our hypertext example:
183183+184184+```ocaml
185185+type hypertext_dom =
186186+ | Text of { mutable text: string }
187187+ | Link of { mutable callback: (unit -> unit)
188188+ ; mutable child: hypertext_dom }
189189+ | List of { mutable children: hypertext_dom list }
190190+```
191191+192192+While this might be a natural derivation in imperative languages, it proved difficult and error-prone to manipulate. Thousands of Javascript libraries were proposed to ease DOM manipulation.
193193+194194+Some successful ones drew inspiration from functional programming, in the sense that they discouraged side-effects, producing new documents rather than modifying existing ones.
195195+196196+_Lwd_ rethinks this scaffolding: rather than starting from a static description, deriving mutable data structures to bring dynamism, and then restricting the mutations to make it manageable, we propose to keep the syntax as it is, lift the document in an `Lwd.t` computation graph and use variables nodes to express parts that can changes.
197197+198198+**Reactive UI.** It is difficult to make a fair comparison with these libraries as the term is loosely defined and there many competing approaches. Furthermore Lwd can be presented as an alternative to the DOM so it is effective at a lower-level than what common reactive libraries target.
199199+200200+That being said, we will try to address the following questions:
201201+202202+- can reactive libraries, to a reasonable extent, be reimplemented on top of _Lwd_ rather than _DOM_?
203203+- can _Lwd_ be conveniently used without such layer?
204204+205205+The first question can be answered positively with a naive encoding: put `Lwd.var` everywhere, essentially keeping enough "degrees of freedom" to change things as needed later. No static structure is enforced this way.
206206+207207+To answer the second question, it is interesting to observe that there is no concept of "diffing" here. _Lwd_ does not try to see if things have changed in order to update them. Rather, if an input change, the whole branch that depends on it is recomputed.
208208+209209+So it is not VDOM/Diffing that could make Lwd convenient. Instead, it is the fact that most of the time, dependencies are made explicit.
210210+Let's consider a component that changes its color when it is focused. With `Lwd` (and `Nottui`), this could be expressed as:
211211+212212+```ocaml
213213+let focus = Focus.make () in
214214+let color status =
215215+ if Focus.has_focus status then blue else black
216216+in
217217+button ~focus ~color:(Lwd.map ~f:color (Focus.status focus)))
218218+```
219219+220220+The color of the button is defined declaratively: it cannot be changed elsewhere, no other part of the code can mutate it. It is this explicit declaration of dependencies that make it possible to reason about the code, to enforce invariants and to encapsulate behaviors.
221221+222222+`Lwd.var` is the escape hatch one can use to recover imperative code. But rather than being the default, it has to be opted in and can be exposed to a limited scope only.
+19
forks/lwd/TODO.md
···11+- Document implementation
22+- Switch to labelled interface
33+- Make "window manager" a core Nottui concept:
44+ - applications start by creating a window manager
55+ - main loop runs a window manager and not a ui Lwd.t
66+ - main loop quit when there is no window scheduled
77+- Benchmark "compact" trace representation:
88+ It should consume a bit less memory (that should be observable in misc
99+ example with a million edit fields) and should not affect runtime
1010+ performance... However it seems to do so (in misc and stress),
1111+ especially in bytecode, maybe because of the additional recursive functions.
1212+- Add a standard mainloop / update scheduler to Tyxml-lwd:
1313+ - it should take into account different roots
1414+ (multiple sub-trees of the DOM that are maintained by lwd)
1515+ - it should support "unstable" documents (those that need more than one
1616+ update cycle):
1717+ - provide different levels of logging for profiling unstable parts?
1818+ - maybe split update cycles in different chunks, so that we can still
1919+ produce a frame within time budget when a fixpoint cannot be reached
···11+module type MUTEX = sig
22+(** Locks for mutual exclusion with support for multiple concurrency backends.
33+44+ This module provides a unified interface for mutexes that can work with
55+ different concurrency backends (OCaml standard library, Picos, etc.).
66+ It extends the standard OCaml mutex interface with additional functionality
77+ for acquiring multiple mutexes atomically.
88+*)
99+1010+type t
1111+(** The type of mutexes. *)
1212+1313+val create : unit -> t
1414+(** Return a new mutex. *)
1515+1616+val lock : t -> unit
1717+(** Lock the given mutex. Only one thread can have the mutex locked
1818+ at any time. A thread that attempts to lock a mutex already locked
1919+ by another thread will suspend until the other thread unlocks
2020+ the mutex.
2121+2222+ @raise Sys_error if the mutex is already locked by the thread calling
2323+ {!lock}.
2424+2525+ @before 4.12 {!Sys_error} was not raised for recursive locking
2626+ (platform-dependent behaviour) *)
2727+2828+val try_lock : t -> bool
2929+(** Same as {!lock}, but does not suspend the calling thread if
3030+ the mutex is already locked: just return [false] immediately
3131+ in that case. If the mutex is unlocked, lock it and
3232+ return [true]. *)
3333+3434+val unlock : t -> unit
3535+(** Unlock the given mutex. Other threads suspended trying to lock
3636+ the mutex will restart. The mutex must have been previously locked
3737+ by the thread that calls {!unlock}.
3838+ @raise Sys_error if the mutex is unlocked or was locked by another thread.
3939+4040+ @before 4.12 {!Sys_error} was not raised when unlocking an unlocked mutex
4141+ or when unlocking a mutex from a different thread. *)
4242+4343+val protect : t -> (unit -> 'a) -> 'a
4444+(** [protect mutex f] runs [f()] in a critical section where [mutex]
4545+ is locked (using {!lock}); it then takes care of releasing [mutex],
4646+ whether [f()] returned a value or raised an exception.
4747+4848+ The unlocking operation is guaranteed to always takes place,
4949+ even in the event an asynchronous exception (e.g. {!Sys.Break}) is raised
5050+ in some signal handler.
5151+5252+ @since 5.1 *)
5353+5454+val lock_all : t list -> bool
5555+(** [lock_all mutexes] attempts to acquire all mutexes in the list atomically.
5656+ It uses {!try_lock} for each mutex in the order provided. If any mutex
5757+ cannot be acquired, it releases all previously acquired mutexes and
5858+ returns [false]. If all mutexes are successfully acquired, it returns [true].
5959+6060+ This function is useful for avoiding deadlocks when multiple mutexes
6161+ need to be acquired simultaneously.
6262+6363+ @return [true] if all mutexes were successfully acquired, [false] otherwise.
6464+6565+ Note: The caller is responsible for unlocking all mutexes that were
6666+ successfully acquired when this function returns [true]. *)
6767+end
···11+(* Default stdlib mutex implementation, actual implementation is in lwd_impl.ml *)
22+include Lwd_impl.Make(Mutex_backend.Stdlib)
+162
forks/lwd/lib/lwd/lwd.mli
···11+type +'a t
22+(** A dynamic document of type ['a]. Documents can be produced in several
33+ different ways:
44+55+ - operators, such as {!map}, {!bind}, {!app}, {!pair}, etc.
66+ combine several documents into one. The result is (lazily)
77+ updated whenever the sub-documents are.
88+99+ - variables {!var}, a mutable reference.
1010+ - primitive documents {!prim}, providing custom leaves to trees of
1111+ documents.
1212+*)
1313+1414+val return : 'a -> 'a t
1515+(** The content document with the given value inside *)
1616+1717+val pure : 'a -> 'a t
1818+(** Alias to {!return} *)
1919+2020+val map : 'a t -> f:('a -> 'b) -> 'b t
2121+(** [map d ~f] is the document that has value [f x] whenever [d] has value [x] *)
2222+2323+val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
2424+(** [map2 d1 d2 ~f] is the document that has value [f x1 x2] whenever
2525+ [d1] has value [x1] and [d2] has value [x2] *)
2626+2727+val join : 'a t t -> 'a t
2828+(** Monadic operator [join d] is the document pointed to by document [d].
2929+ This is powerful but potentially costly in case of recomputation.
3030+*)
3131+3232+val bind : 'a t -> f:('a -> 'b t) -> 'b t
3333+(** Monadic bind, a mix of {!join} and {!map} *)
3434+3535+val app : ('a -> 'b) t -> 'a t -> 'b t
3636+(** Applicative: [app df dx] is the document that has value [f x]
3737+ whenever [df] has value [f] and [dx] has value [x] *)
3838+3939+val pair : 'a t -> 'b t -> ('a * 'b) t
4040+(** [pair a b] is [map2 (fun x y->x,y) a b] *)
4141+4242+val is_pure : 'a t -> 'a option
4343+(** [is_pure x] will return [Some v] if [x] was built with [pure v] or
4444+ [return v].
4545+4646+ Normal code should not rely on the "reactive-ness" of a value, but this is
4747+ often useful for optimising reactive data structures.
4848+*)
4949+5050+type 'a var
5151+(** The workhorse of Lwd: a mutable variable that also tracks dependencies.
5252+ Every time {!set} is called, all documents that depend on this variable
5353+ via {!map}, {!bind}, etc. will be at least partially invalidated
5454+ and will be recomputed incrementally on demand. *)
5555+5656+val var : 'a -> 'a var
5757+(** Create a new variable with the given initial value *)
5858+5959+val get : 'a var -> 'a t
6060+(** A document that reflects the current content of a variable *)
6161+6262+val set : 'a var -> 'a -> unit
6363+(** Change the variable's content, invalidating all documents depending
6464+ on it. *)
6565+6666+val peek_stable : 'a var -> 'a
6767+(** Same as `peek` but if it is called during recomputation of the document, it will always return the value as it was at the start of the recomputation. This can be important for ui consistency. *)
6868+6969+val peek : 'a var -> 'a
7070+(** Observe the current value of the variable, without any dependency
7171+ tracking. *)
7272+7373+val update : ('a -> 'a) -> 'a var -> unit
7474+(** Modify a variable based on its currently observed value. *)
7575+7676+val may_update : ('a -> 'a option) -> 'a var -> unit
7777+(** Conditionnally modify a variable based on its currently observed value. *)
7878+7979+type +'a prim
8080+(** A primitive document. It can correspond, for example, to
8181+ a primitive UI element.
8282+8383+ A primitive is a resource with [acquire] and [release] functions
8484+ to manage its lifecycle. *)
8585+8686+val prim : acquire:('a prim -> 'a) -> release:('a prim -> 'a -> unit) -> 'a prim
8787+(** create a new primitive document.
8888+ @param acquire is called when the document becomes observed (indirectly)
8989+ via at least one {!root}. The resulting primitive is passed as an argument
9090+ to support certain recursive use cases.
9191+ @param release is called when the document is no longer observed.
9292+ Internal resources can be freed. *)
9393+9494+val get_prim : 'a prim -> 'a t
9595+val invalidate : 'a prim -> unit
9696+9797+(** Some document might change variables during their evaluation.
9898+ These are called "unstable" documents.
9999+100100+ Evaluating these might need many passes to eventually converge to a value.
101101+ The `fix` operator tries to stabilize a sub-document by repeating
102102+ evaluation until a stable condition is reached.
103103+*)
104104+val fix : 'a t -> wrt:_ t -> 'a t
105105+106106+val default_unsafe_mutation_logger : unit -> unit
107107+val unsafe_mutation_logger : (unit -> unit) ref
108108+109109+(** Releasing unused graphs *)
110110+type release_failure = exn * Printexc.raw_backtrace
111111+112112+exception Release_failure of exn option * release_failure list
113113+114114+type release_queue
115115+val make_release_queue : unit -> release_queue
116116+val flush_release_queue : release_queue -> release_failure list
117117+118118+type +'a root
119119+(** A root of computation, whose value(s) over time we're interested in. *)
120120+121121+val observe : ?on_invalidate:('a -> unit) -> 'a t -> 'a root
122122+(** [observe x] creates a root that contains document [x].
123123+ @param on_invalidate is called whenever the root is invalidated
124124+ because the content of [x] has changed. This can be useful to
125125+ perform side-effects such as re-rendering some UI. *)
126126+127127+val set_on_invalidate : 'a root -> ('a -> unit) -> unit
128128+(** Change the callback for the root.
129129+ See [observe] for more details. *)
130130+131131+val sample : release_queue -> 'a root -> 'a
132132+(** Force the computation of the value for this root.
133133+ The value is cached, so this is idempotent, until the next invalidation. *)
134134+135135+val is_damaged : 'a root -> bool
136136+(** [is_damaged root] is true if the root doesn't have a valid value in
137137+ cache. This can be the case if the value was never computed, or
138138+ if it was computed and then invalidated. *)
139139+140140+val release : release_queue -> 'a root -> unit
141141+(** Forget about this root and release sub-values no longer reachable from
142142+ any root. *)
143143+144144+val quick_sample : 'a root -> 'a
145145+146146+val quick_release : 'a root -> unit
147147+148148+module Infix : sig
149149+150150+ (** Lwd map operaor*)
151151+ val (>|=) : 'a t -> ('a -> 'b) -> 'b t
152152+153153+ (** Lwd bind operaor*)
154154+ val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
155155+156156+ (** Lwd application operator *)
157157+ val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
158158+159159+end
160160+161161+(* For debug purposes *)
162162+val dump_trace : 'a t -> unit
+824
forks/lwd/lib/lwd/lwd_impl.ml
···11+module Make (Mutex : Mutex_backend.MUTEX) = struct
22+33+(** Create-only version of [Obj.t] *)
44+module Any : sig
55+ type t
66+ val any : 'a -> t
77+end = struct
88+ type t = Obj.t
99+ let any = Obj.repr
1010+end
1111+1212+type 'a eval =
1313+ | Eval_none
1414+ | Eval_progress
1515+ | Eval_some of 'a
1616+ | Eval_invalid_next
1717+1818+type 'a t_ =
1919+ | Pure of 'a
2020+ | Operator : {
2121+ mutex : Mutex.t;
2222+ mutable value : 'a eval; (* cached value *)
2323+ mutable trace : trace; (* list of parents this can invalidate *)
2424+ mutable trace_idx : trace_idx; (* list of direct children that can invalidate this *)
2525+ desc: 'a desc;
2626+ } -> 'a t_
2727+ | Root : {
2828+ mutex : Mutex.t;
2929+ mutable value : 'a eval; (* cached value *)
3030+ mutable trace_idx : trace_idx; (* list of direct children that can invalidate this *)
3131+ mutable on_invalidate : 'a -> unit;
3232+ mutable acquired : bool;
3333+ child : 'a t_;
3434+ } -> 'a t_
3535+3636+and _ desc =
3737+ | Map : 'a t_ * ('a -> 'b) -> 'b desc
3838+ | Map2 : 'a t_ * 'b t_ * ('a -> 'b -> 'c) -> 'c desc
3939+ | Pair : 'a t_ * 'b t_ -> ('a * 'b) desc
4040+ | App : ('a -> 'b) t_ * 'a t_ -> 'b desc
4141+ | Join : { child : 'a t_ t_; mutable intermediate : 'a t_ option } -> 'a desc
4242+ | Var : { mutable binding : 'a; mutable nextVal: 'a option } -> 'a desc
4343+ | Prim : { acquire : 'a t -> 'a;
4444+ release : 'a t -> 'a -> unit } -> 'a desc
4545+ | Fix : { doc : 'a t_; wrt : _ t_ } -> 'a desc
4646+4747+(* a set of (active) parents for a ['a t], used during invalidation *)
4848+and trace =
4949+ | T0
5050+ | T1 : _ t_ -> trace
5151+ | T2 : _ t_ * _ t_ -> trace
5252+ | T3 : _ t_ * _ t_ * _ t_ -> trace
5353+ | T4 : _ t_ * _ t_ * _ t_ * _ t_ -> trace
5454+ | Tn : { mutable active : int; mutable count : int;
5555+ mutable entries : Any.t t_ array } -> trace
5656+5757+(* a set of direct children for a composite document *)
5858+and trace_idx =
5959+ | I0
6060+ | I1 : { mutable idx : int ;
6161+ obj : 'a t_;
6262+ mutable next : trace_idx } -> trace_idx
6363+6464+(* The type system cannot see that t is covariant in its parameter.
6565+ Use the Force to convince it. *)
6666+and +'a t
6767+external inj : 'a t_ -> 'a t = "%identity"
6868+external prj : 'a t -> 'a t_ = "%identity"
6969+external prj2 : 'a t t -> 'a t_ t_ = "%identity"
7070+7171+(* Basic combinators *)
7272+let return x = inj (Pure x)
7373+let pure x = inj (Pure x)
7474+7575+let is_pure x = match prj x with
7676+ | Pure x -> Some x
7777+ | _ -> None
7878+7979+let dummy = Pure (Any.any ())
8080+8181+let operator desc =
8282+ Operator { value = Eval_none; trace = T0; desc; trace_idx = I0 ;mutex= Mutex.create () }
8383+8484+let map x ~f = inj (
8585+ match prj x with
8686+ | Pure vx -> Pure (f vx)
8787+ | x -> operator (Map (x, f))
8888+ )
8989+9090+let map2 x y ~f = inj (
9191+ match prj x, prj y with
9292+ | Pure vx, Pure vy -> Pure (f vx vy)
9393+ | x, y -> operator (Map2 (x, y, f))
9494+ )
9595+9696+9797+let pair x y = inj (
9898+ match prj x, prj y with
9999+ | Pure vx, Pure vy -> Pure (vx, vy)
100100+ | x, y -> operator (Pair (x, y))
101101+ )
102102+103103+let app f x = inj (
104104+ match prj f, prj x with
105105+ | Pure vf, Pure vx -> Pure (vf vx)
106106+ | f, x -> operator (App (f, x))
107107+ )
108108+109109+let join child = inj (
110110+ match prj2 child with
111111+ | Pure v -> v
112112+ | child -> operator (Join { child; intermediate = None })
113113+ )
114114+115115+let bind x ~f = join (map ~f x)
116116+117117+(* Management of trace indices *)
118118+119119+let addr oc obj =
120120+ Printf.fprintf oc "0x%08x" (Obj.magic obj : int)
121121+122122+external t_equal : _ t_ -> _ t_ -> bool = "%eq"
123123+external obj_t : 'a t_ -> Any.t t_ = "%identity"
124124+125125+let rec dump_trace : type a. a t_ -> unit =
126126+ fun obj -> match obj with
127127+ | Pure _ -> Printf.eprintf "%a: Pure _\n%!" addr obj
128128+ | Operator t ->
129129+ Printf.eprintf "%a: Operator _ -> %a\n%!" addr obj dump_trace_aux t.trace;
130130+ begin match t.trace with
131131+ | T0 -> ()
132132+ | T1 a -> dump_trace a
133133+ | T2 (a,b) -> dump_trace a; dump_trace b
134134+ | T3 (a,b,c) -> dump_trace a; dump_trace b; dump_trace c
135135+ | T4 (a,b,c,d) -> dump_trace a; dump_trace b; dump_trace c; dump_trace d
136136+ | Tn t -> Array.iter dump_trace t.entries
137137+ end
138138+ | Root _ -> Printf.eprintf "%a: Root _\n%!" addr obj
139139+140140+and dump_trace_aux oc = function
141141+ | T0 -> Printf.fprintf oc "T0"
142142+ | T1 a -> Printf.fprintf oc "T1 %a" addr a
143143+ | T2 (a,b) ->
144144+ Printf.fprintf oc "T2 (%a, %a)" addr a addr b
145145+ | T3 (a,b,c) ->
146146+ Printf.fprintf oc "T3 (%a, %a, %a)" addr a addr b addr c
147147+ | T4 (a,b,c,d) ->
148148+ Printf.fprintf oc "T4 (%a, %a, %a, %a)" addr a addr b addr c addr d
149149+ | Tn t ->
150150+ Printf.fprintf oc "Tn {active = %d; count = %d; entries = "
151151+ t.active t.count;
152152+ Array.iter (Printf.fprintf oc "(%a)" addr) t.entries;
153153+ Printf.fprintf oc "}"
154154+155155+let dump_trace x = dump_trace (obj_t (prj x))
156156+157157+let add_idx obj idx = function
158158+ | Pure _ -> assert false
159159+ | Root t' -> t'.trace_idx <- I1 { idx; obj; next = t'.trace_idx }
160160+ | Operator t' -> t'.trace_idx <- I1 { idx; obj; next = t'.trace_idx }
161161+162162+let rec rem_idx_rec obj = function
163163+ | I0 -> assert false
164164+ | I1 t as self ->
165165+ if t_equal t.obj obj
166166+ then (t.idx, t.next)
167167+ else (
168168+ let idx, result = rem_idx_rec obj t.next in
169169+ t.next <- result;
170170+ (idx, self)
171171+ )
172172+173173+(* remove [obj] from the lwd's trace. *)
174174+let rem_idx obj = function
175175+ | Pure _ -> assert false
176176+ | Root t' ->
177177+ let idx, trace_idx = rem_idx_rec obj t'.trace_idx in
178178+ t'.trace_idx <- trace_idx; idx
179179+ | Operator t' ->
180180+ let idx, trace_idx = rem_idx_rec obj t'.trace_idx in
181181+ t'.trace_idx <- trace_idx; idx
182182+183183+(* move [obj] from old index to new index. *)
184184+let rec mov_idx_rec obj oldidx newidx = function
185185+ | I0 -> assert false
186186+ | I1 t ->
187187+ if t.idx = oldidx && t_equal t.obj obj
188188+ then t.idx <- newidx
189189+ else mov_idx_rec obj oldidx newidx t.next
190190+191191+let mov_idx obj oldidx newidx = function
192192+ | Pure _ -> assert false
193193+ | Root t' -> mov_idx_rec obj oldidx newidx t'.trace_idx
194194+ | Operator t' -> mov_idx_rec obj oldidx newidx t'.trace_idx
195195+196196+let rec get_idx_rec obj = function
197197+ | I0 -> assert false
198198+ | I1 t ->
199199+ if t_equal t.obj obj
200200+ then t.idx
201201+ else get_idx_rec obj t.next
202202+203203+(* find index of [obj] in the given lwd *)
204204+let get_idx obj = function
205205+ | Pure _ -> assert false
206206+ | Root t' -> get_idx_rec obj t'.trace_idx
207207+ | Operator t' -> get_idx_rec obj t'.trace_idx
208208+209209+type status =
210210+ | Neutral
211211+ | Safe
212212+ | Unsafe of (unit->unit) list ref
213213+214214+(*
215215+Sensitivity is used to indicate to when reading a root node, that one of the child operater nodes was being evaluated.
216216+I think this is needed because the child cound have multiple roots and we need to indicate that to all of them
217217+*)
218218+type sensitivity =
219219+ | Strong
220220+ | Fragile
221221+222222+(* Propagating invalidation recursively.
223223+ Each document is invalidated at most once,
224224+ and only if it has [t.value = Some _]. *)
225225+let rec invalidate_node : type a . status ref -> sensitivity -> a t_ -> unit =
226226+ (*sensitivity indicates that a parent is being evaluated*)
227227+ fun status sensitivity node ->
228228+ match node, sensitivity with
229229+ | Pure _, _ -> assert false
230230+ | Root ({value; on_invalidate; _} as t), _ ->
231231+ (match value with
232232+ | Eval_none | Eval_invalid_next -> ()
233233+ | Eval_progress ->
234234+ t.value <- Eval_invalid_next
235235+ | Eval_some x ->
236236+ t.value <- Eval_none;
237237+ on_invalidate x
238238+ )
239239+ | Operator { value = Eval_none | Eval_invalid_next; _ }, _ -> ()
240240+ | Operator { desc = Fix { wrt = Operator { value = Eval_none | Eval_invalid_next; _ }; _ }; _ }, Fragile ->
241241+ (match !status with
242242+ | Safe | Unsafe _ -> ()
243243+ | Neutral -> status := Safe)
244244+ | Operator { desc = Fix { wrt = Operator { value = Eval_some _; _ }; _ }; _ }, Fragile
245245+ -> ()
246246+ | Operator t, _ ->
247247+ let sensitivity =
248248+ match t.value with Eval_progress -> Fragile | _ -> sensitivity
249249+ in
250250+ t.value <- Eval_none;
251251+ (* invalidate parents recursively *)
252252+ invalidate_trace status sensitivity t.trace
253253+254254+(* invalidate recursively documents in the given trace *)
255255+and invalidate_trace status sensitivity = function
256256+ | T0 -> ()
257257+ | T1 x -> invalidate_node status sensitivity x
258258+ | T2 (x, y) ->
259259+ invalidate_node status sensitivity x;
260260+ invalidate_node status sensitivity y
261261+ | T3 (x, y, z) ->
262262+ invalidate_node status sensitivity x;
263263+ invalidate_node status sensitivity y;
264264+ invalidate_node status sensitivity z
265265+ | T4 (x, y, z, w) ->
266266+ invalidate_node status sensitivity x;
267267+ invalidate_node status sensitivity y;
268268+ invalidate_node status sensitivity z;
269269+ invalidate_node status sensitivity w
270270+ | Tn t ->
271271+ let active = t.active in
272272+ t.active <- 0;
273273+ for i = 0 to active - 1 do
274274+ invalidate_node status sensitivity t.entries.(i)
275275+ done
276276+277277+let default_unsafe_mutation_logger () =
278278+ let callstack = Printexc.get_callstack 20 in
279279+ Printf.fprintf stderr
280280+ "Lwd: unsafe mutation (variable invalidated during evaluation) at\n%a"
281281+ Printexc.print_raw_backtrace callstack
282282+283283+let unsafe_mutation_logger = ref default_unsafe_mutation_logger
284284+285285+286286+(**
287287+288288+289289+ @param ~was_delayed: set to true if the function call was put on hold untill the current root had finished being evaluated
290290+*)
291291+let do_invalidate sensitivity (node : 'a t_) =
292292+ let status = ref Neutral in
293293+ invalidate_node status sensitivity node;
294294+(* Variables *)
295295+type 'a var = 'a t_
296296+let var x = operator (Var {binding = x;nextVal=None})
297297+let get x = inj x
298298+299299+let set (vx:'a var) x : unit =
300300+ match vx with
301301+ | (Operator ({desc = Var v; _} )as node) ->
302302+ v.binding <- x;
303303+ v.nextVal <- None;
304304+ (let rec climb (parents: Any.t t_ list) =
305305+ let new_parents : Any.t t_ list = List.fold_left (fun acc p ->
306306+ match p with
307307+ | Pure _ -> acc
308308+ | Root r ->
309309+ if Mutex.try_lock r.mutex then (
310310+ (match r.value with
311311+ | Eval_some v ->
312312+ r.value <- Eval_none;
313313+ r.on_invalidate v
314314+ | Eval_none | Eval_invalid_next -> ()
315315+ | Eval_progress -> r.value <- Eval_invalid_next
316316+ );
317317+ Mutex.unlock r.mutex;
318318+ acc
319319+ ) else (
320320+ Mutex.protect r.mutex (fun () ->
321321+ if r.value = Eval_progress then r.value <- Eval_invalid_next
322322+ );
323323+ acc
324324+ )
325325+ | Operator o ->
326326+ if Mutex.try_lock o.mutex then (
327327+ let continue =
328328+ match o.value with
329329+ | Eval_some _ -> o.value <- Eval_none; true
330330+ | Eval_none | Eval_invalid_next -> false
331331+ | Eval_progress -> o.value <- Eval_invalid_next; false
332332+ in
333333+ Mutex.unlock o.mutex;
334334+ if continue then (
335335+ match o.trace with
336336+ | T0 -> acc
337337+ | T1 p1 -> obj_t p1 :: acc
338338+ | T2 (p1, p2) -> obj_t p1 :: obj_t p2 :: acc
339339+ | T3 (p1, p2, p3) -> obj_t p1 :: obj_t p2 :: obj_t p3 :: acc
340340+ | T4 (p1, p2, p3, p4) -> obj_t p1 :: obj_t p2 :: obj_t p3 :: obj_t p4 :: acc
341341+ | Tn t -> Array.to_list t.entries |> List.rev_append acc
342342+ ) else acc
343343+ ) else (
344344+ Mutex.protect o.mutex (fun () ->
345345+ if o.value = Eval_progress then o.value <- Eval_invalid_next
346346+ );
347347+ acc
348348+ )
349349+ ) [] parents in
350350+ if new_parents <> [] then climb new_parents
351351+ in
352352+ match node with
353353+ | Operator o ->
354354+ let initial_parents : Any.t t_ list =
355355+ match o.trace with
356356+ | T0 -> []
357357+ | T1 p1 -> [obj_t p1]
358358+ | T2 (p1, p2) -> [obj_t p1; obj_t p2]
359359+ | T3 (p1, p2, p3) -> [obj_t p1; obj_t p2; obj_t p3]
360360+ | T4 (p1, p2, p3, p4) -> [obj_t p1; obj_t p2; obj_t p3; obj_t p4]
361361+ | Tn t -> Array.to_list t.entries
362362+ in
363363+ climb initial_parents
364364+ | _ -> ()
365365+ )
366366+ | _ -> assert false
367367+368368+let peek_stable = function
369369+ | Operator ({desc = Var v; _}) -> v.binding
370370+ | _ -> assert false
371371+372372+let peek = function
373373+ | Operator ({desc = Var v; _}) -> v.nextVal |>Option.value ~default: v.binding
374374+ | _ -> assert false
375375+376376+let update f v = set v (f (peek v))
377377+378378+let may_update f v =
379379+ match f (peek v) with
380380+ | None -> ()
381381+ | Some x -> set v x
382382+383383+(* Primitives *)
384384+type 'a prim = 'a t
385385+let prim ~acquire ~release =
386386+ inj (operator (Prim { acquire; release }))
387387+let get_prim x = x
388388+389389+let invalidate x = match prj x with
390390+ | Operator {desc = Prim p; value; _} as t ->
391391+ (* the value is invalidated, be sure to invalidate all parents as well *)
392392+ begin match value with
393393+ | Eval_none | Eval_invalid_next -> ()
394394+ | Eval_progress -> do_invalidate Fragile t;
395395+ | Eval_some v ->
396396+ do_invalidate Strong t;
397397+ p.release x v
398398+ end
399399+ | _ -> assert false
400400+401401+(* Fix point *)
402402+403403+let fix doc ~wrt = match prj wrt with
404404+ | Root _ -> assert false
405405+ | Pure _ -> doc
406406+ | Operator _ as wrt -> inj (operator (Fix {doc = prj doc; wrt}))
407407+408408+type release_list =
409409+ | Release_done
410410+ | Release_more :
411411+ { origin : 'a t_; element : 'b t_; next : release_list } -> release_list
412412+413413+type release_queue = release_list ref
414414+let make_release_queue () = ref Release_done
415415+416416+type release_failure = exn * Printexc.raw_backtrace
417417+418418+(* [sub_release [] origin self] is called when [origin] is released,
419419+ where [origin] is reachable from [self]'s trace.
420420+ We're going to remove [origin] from that trace as [origin] is now dead.
421421+422422+ [sub_release] cannot raise.
423423+ If a primitive raises, the exception is caught and a warning is emitted. *)
424424+let rec sub_release
425425+ : type a b . release_failure list -> a t_ -> b t_ -> release_failure list
426426+ = fun failures origin -> function
427427+ | Root _ -> assert false
428428+ | Pure _ -> failures
429429+ | Operator t as self ->
430430+ (* compute [t.trace \ {origin}] *)
431431+ let trace = match t.trace with
432432+ | T0 -> assert false
433433+ | T1 x -> assert (t_equal x origin); T0
434434+ | T2 (x, y) ->
435435+ if t_equal x origin then T1 y
436436+ else if t_equal y origin then T1 x
437437+ else assert false
438438+ | T3 (x, y, z) ->
439439+ if t_equal x origin then T2 (y, z)
440440+ else if t_equal y origin then T2 (x, z)
441441+ else if t_equal z origin then T2 (x, y)
442442+ else assert false
443443+ | T4 (x, y, z, w) ->
444444+ if t_equal x origin then T3 (y, z, w)
445445+ else if t_equal y origin then T3 (x, z, w)
446446+ else if t_equal z origin then T3 (x, y, w)
447447+ else if t_equal w origin then T3 (x, y, z)
448448+ else assert false
449449+ | Tn tn as trace ->
450450+ let revidx = rem_idx self origin in
451451+ assert (t_equal tn.entries.(revidx) origin);
452452+ let count = tn.count - 1 in
453453+ tn.count <- count;
454454+ if revidx < count then (
455455+ let obj = tn.entries.(count) in
456456+ tn.entries.(revidx) <- obj;
457457+ tn.entries.(count) <- dummy;
458458+ mov_idx self count revidx obj
459459+ ) else
460460+ tn.entries.(revidx) <- dummy;
461461+ if tn.active > count then tn.active <- count;
462462+ if count = 4 then (
463463+ (* downgrade to [T4] to save space *)
464464+ let a = tn.entries.(0) and b = tn.entries.(1) in
465465+ let c = tn.entries.(2) and d = tn.entries.(3) in
466466+ ignore (rem_idx self a : int);
467467+ ignore (rem_idx self b : int);
468468+ ignore (rem_idx self c : int);
469469+ ignore (rem_idx self d : int);
470470+ T4 (a, b, c, d)
471471+ ) else (
472472+ let len = Array.length tn.entries in
473473+ if count <= len lsr 2 then
474474+ Tn { active = tn.active; count = tn.count;
475475+ entries = Array.sub tn.entries 0 (len lsr 1) }
476476+ else
477477+ trace
478478+ )
479479+ in
480480+ t.trace <- trace;
481481+ match trace with
482482+ | T0 ->
483483+ (* [self] is not active anymore, since it's not reachable
484484+ from any root. We can release its cached value and
485485+ recursively release its subtree. *)
486486+ let value = t.value in
487487+ t.value <- Eval_progress;
488488+ begin match t.desc with
489489+ | Map (x, _) -> sub_release failures self x
490490+ | Map2 (x, y, _) ->
491491+ sub_release (sub_release failures self x) self y
492492+ | Pair (x, y) ->
493493+ sub_release (sub_release failures self x) self y
494494+ | App (x, y) ->
495495+ sub_release (sub_release failures self x) self y
496496+ | Join ({ child; intermediate } as t) ->
497497+ let failures = sub_release failures self child in
498498+ begin match intermediate with
499499+ | None -> failures
500500+ | Some child' ->
501501+ t.intermediate <- None;
502502+ sub_release failures self child'
503503+ end
504504+ | Var _ -> failures
505505+ | Fix {doc; wrt} ->
506506+ sub_release (sub_release failures self wrt) self doc
507507+ | Prim t ->
508508+ begin match value with
509509+ | Eval_none | Eval_invalid_next | Eval_progress -> failures
510510+ | Eval_some x ->
511511+ begin match t.release (inj self) x with
512512+ | () -> failures
513513+ | exception exn ->
514514+ let bt = Printexc.get_raw_backtrace () in
515515+ (exn, bt) :: failures
516516+ end
517517+ end
518518+ end
519519+ | _ -> failures
520520+521521+(* [sub_acquire] cannot raise *)
522522+let rec sub_acquire : type a b . a t_ -> b t_ -> unit = fun origin ->
523523+ function
524524+ | Root _ -> assert false
525525+ | Pure _ -> ()
526526+ | Operator t as self ->
527527+ (*lock the mutex, because we are making changes within this node *)
528528+ Mutex.protect t.mutex @@ fun _->
529529+ (* [acquire] is true if this is the first time this operator
530530+ is used, in which case we need to acquire its children *)
531531+ let acquire = match t.trace with T0 -> true | _ -> false in
532532+ let trace = match t.trace with
533533+ | T0 -> T1 origin
534534+ | T1 x -> T2 (origin, x)
535535+ | T2 (x, y) -> T3 (origin, x, y)
536536+ | T3 (x, y, z) -> T4 (origin, x, y, z)
537537+ | T4 (x, y, z, w) ->
538538+ let obj_origin = obj_t origin in
539539+ let entries =
540540+ [| obj_t x; obj_t y; obj_t z; obj_t w; obj_origin; dummy; dummy; dummy |]
541541+ in
542542+ for i = 0 to 4 do add_idx self i entries.(i) done;
543543+ Tn { active = 5; count = 5; entries }
544544+ | Tn tn as trace ->
545545+ let index = tn.count in
546546+ let entries, trace =
547547+ (* possibly resize array [entries] *)
548548+ if index < Array.length tn.entries then (
549549+ tn.count <- tn.count + 1;
550550+ (tn.entries, trace)
551551+ ) else (
552552+ let entries = Array.make (index * 2) dummy in
553553+ Array.blit tn.entries 0 entries 0 index;
554554+ (entries, Tn { active = tn.active; count = index + 1; entries })
555555+ )
556556+ in
557557+ let obj_origin = obj_t origin in
558558+ entries.(index) <- obj_origin;
559559+ add_idx self index obj_origin;
560560+ trace
561561+ in
562562+ t.trace <- trace;
563563+ if acquire then (
564564+ (* acquire immediate children, and so on recursively *)
565565+ match t.desc with
566566+ | Map (x, _) -> sub_acquire self x
567567+ | Map2 (x, y, _) ->
568568+ sub_acquire self x;
569569+ sub_acquire self y
570570+ | Pair (x, y) ->
571571+ sub_acquire self x;
572572+ sub_acquire self y
573573+ | App (x, y) ->
574574+ sub_acquire self x;
575575+ sub_acquire self y
576576+ | Fix {doc; wrt} ->
577577+ sub_acquire self doc;
578578+ sub_acquire self wrt
579579+ | Join { child; intermediate } ->
580580+ sub_acquire self child;
581581+ begin match intermediate with
582582+ | None -> ()
583583+ | Some _ ->
584584+ assert false (* this can't initialized already, first-time acquire *)
585585+ end
586586+ | Var _ -> ()
587587+ | Prim _ -> ()
588588+ )
589589+590590+(* make sure that [origin] is in [self.trace], passed as last arg. *)
591591+let activate_tracing self origin = function
592592+ | Tn tn ->
593593+ let idx = get_idx self origin in (* index of [self] in [origin.trace_idx] *)
594594+ let active = tn.active in
595595+ (* [idx < active] means [self] is already traced by [origin].
596596+ We only have to add [self] to the entries if [idx >= active]. *)
597597+ if idx >= active then (
598598+ tn.active <- active + 1;
599599+ );
600600+ if idx > active then (
601601+ (* swap with last entry in [tn.entries] *)
602602+ let old = tn.entries.(active) in
603603+ tn.entries.(idx) <- old;
604604+ tn.entries.(active) <- obj_t origin;
605605+ mov_idx self active idx old;
606606+ mov_idx self idx active origin
607607+ )
608608+ | _ -> ()
609609+610610+let sub_is_damaged = function
611611+ | Root _ -> assert false
612612+ | Pure _ -> false
613613+ | Operator {value; _} ->
614614+ match value with
615615+ | Eval_none | Eval_invalid_next -> true
616616+ | Eval_some _ -> false
617617+ | Eval_progress -> assert false
618618+619619+(* [sub_sample origin self] computes a value for [self].
620620+621621+ [sub_sample] raise if any user-provided computation raises.
622622+ Graph will be left in a coherent state but exception will be propagated
623623+ to the observer. *)
624624+let sub_sample queue =
625625+ let rec aux : type a b . a t_ -> b t_ -> b = fun origin ->
626626+ function
627627+ | Root _ -> assert false
628628+ | Pure x -> x
629629+ | Operator t as self ->
630630+ (* lock the mutex, examine cached value *)
631631+ Mutex.lock t.mutex;
632632+ match t.value with
633633+ | Eval_some value ->
634634+ Mutex.unlock t.mutex;
635635+ activate_tracing self origin t.trace;
636636+ value
637637+ | Eval_none ->
638638+ t.value <- Eval_progress;
639639+ Mutex.unlock t.mutex;
640640+641641+ (* compute value without holding the lock *)
642642+ let result : b =
643643+ match t.desc with
644644+ | Map (x, f) -> f (aux self x)
645645+ | Map2 (x, y, f) -> f (aux self x) (aux self y)
646646+ | Pair (x, y) -> (aux self x, aux self y)
647647+ | App (f, x) -> (aux self f) (aux self x)
648648+ | Fix { doc; wrt } ->
649649+ let _ = aux self wrt in
650650+ let result = aux self doc in
651651+ if sub_is_damaged wrt then aux origin self
652652+ else (
653653+ if sub_is_damaged doc then do_invalidate Fragile self;
654654+ result)
655655+ | Join x ->
656656+ let intermediate =
657657+ (* We haven't touched any state yet,
658658+ it is safe for [aux] to raise *)
659659+ aux self x.child
660660+ in
661661+ begin
662662+ match x.intermediate with
663663+ | None ->
664664+ x.intermediate <- Some intermediate;
665665+ sub_acquire self intermediate
666666+ | Some x' when x' != intermediate ->
667667+ queue :=
668668+ Release_more
669669+ { origin = self; element = x'; next = !queue };
670670+ x.intermediate <- Some intermediate;
671671+ sub_acquire self intermediate
672672+ | Some _ -> ()
673673+ end;
674674+ aux self intermediate
675675+ | Var x -> x.binding
676676+ | Prim t -> t.acquire (inj self)
677677+ in
678678+679679+ (* lock again and finalize *)
680680+ Mutex.lock t.mutex;
681681+ begin
682682+ match t.value with
683683+ | Eval_progress -> t.value <- Eval_some result
684684+ | Eval_invalid_next -> t.value <- Eval_none
685685+ | Eval_none | Eval_some _ -> ()
686686+ end;
687687+ Mutex.unlock t.mutex;
688688+689689+ (* Re-evaluate if the node was invalidated during computation *)
690690+ if t.value == Eval_none then aux origin self
691691+ else (
692692+ (* [self] just became active, so it may invalidate [origin] in case its
693693+ value changes because of [t.desc], like if it's a variable and gets
694694+ mutated, or if it's a primitive that gets invalidated.
695695+ We need to put [origin] into [self.trace] in case it isn't there yet. *)
696696+ activate_tracing self origin t.trace;
697697+ result)
698698+ | Eval_progress | Eval_invalid_next ->
699699+ Mutex.unlock t.mutex;
700700+ (* spin and retry *)
701701+ let rec spin () =
702702+ match t.value with
703703+ | Eval_progress | Eval_invalid_next ->
704704+ Domain.cpu_relax ();
705705+ spin ()
706706+ | Eval_none | Eval_some _ -> ()
707707+ in
708708+ spin ();
709709+ aux origin self
710710+ in
711711+ aux
712712+713713+type 'a root = 'a t
714714+715715+let observe ?(on_invalidate = ignore) child : _ root =
716716+ let root =
717717+ Root
718718+ { child = prj child
719719+ ; value = Eval_none
720720+ ; on_invalidate
721721+ ; trace_idx = I0
722722+ ; acquired = false
723723+ ; mutex= Mutex.create()
724724+ }
725725+ in
726726+ inj root
727727+728728+exception Release_failure of exn option * release_failure list
729729+730730+let raw_flush_release_queue queue =
731731+ let rec aux failures = function
732732+ | Release_done -> failures
733733+ | Release_more t ->
734734+ let failures = sub_release failures t.origin t.element in
735735+ aux failures t.next
736736+ in
737737+ aux [] queue
738738+739739+let flush_release_queue queue =
740740+ let queue' = !queue in
741741+ queue := Release_done;
742742+ raw_flush_release_queue queue'
743743+744744+let sample queue x = match prj x with
745745+ | Pure _ | Operator _ -> assert false
746746+ | Root t as self ->
747747+ (*lock the root mutex while sampling*)
748748+ Mutex.protect t.mutex @@ fun _->
749749+ match t.value with
750750+ | Eval_some value -> value
751751+ | _ ->
752752+ (
753753+ (* no cached value, compute it now *)
754754+ if not t.acquired then (
755755+ t.acquired <- true;
756756+ sub_acquire self t.child;
757757+ );
758758+ t.value <- Eval_progress;
759759+ let value = sub_sample queue self t.child in
760760+ begin match t.value with
761761+ | Eval_progress -> t.value <- Eval_some value; (* cache value *)
762762+ | Eval_none | Eval_some _ | Eval_invalid_next -> ()
763763+ end;
764764+ value
765765+ )
766766+767767+let is_damaged x =
768768+ match prj x with
769769+ | Pure _ | Operator _ -> assert false
770770+ | Root {value;_}->
771771+ (* NOTE: I don't think i need a mutex here*)
772772+ (match value with
773773+ | Eval_some _ -> false
774774+ | Eval_none | Eval_progress | Eval_invalid_next -> true
775775+ )
776776+777777+let release queue x = match prj x with
778778+ | Pure _ | Operator _ -> assert false
779779+ | Root t as self ->
780780+ Mutex.protect t.mutex @@ fun _->
781781+ if t.acquired then (
782782+ (* release subtree, remove cached value *)
783783+ t.value <- Eval_none;
784784+ t.acquired <- false;
785785+ queue := Release_more { origin = self; element = t.child; next = !queue }
786786+ )
787787+788788+let set_on_invalidate x f =
789789+ match prj x with
790790+ | Pure _ | Operator _ -> assert false
791791+ | Root t ->
792792+ t.on_invalidate <- f
793793+794794+let flush_or_fail main_exn queue =
795795+ match flush_release_queue queue with
796796+ | [] -> ()
797797+ | failures -> raise (Release_failure (main_exn, failures))
798798+799799+let quick_sample root =
800800+ let queue = ref Release_done in
801801+ match sample queue root with
802802+ | result -> flush_or_fail None queue; result
803803+ | exception exn -> flush_or_fail (Some exn) queue; raise exn
804804+805805+let quick_release root =
806806+ let queue = ref Release_done in
807807+ release queue root;
808808+ flush_or_fail None queue
809809+810810+module Infix = struct
811811+ let (>>=) x f = bind x ~f
812812+ let (>|=) x f = map x ~f
813813+ let (<*>) = app
814814+end
815815+816816+(*$R
817817+ let x = var 0 in
818818+ let y = map ~f:succ (get x) in
819819+ let o_y = Lwd.observe y in
820820+ assert_equal 1 (quick_sample o_y);
821821+ set x 10;
822822+ assert_equal 11 (quick_sample o_y);
823823+ *)
824824+end
+12
forks/lwd/lib/lwd/lwd_infix.ml
···11+(*BEGIN LETOP*)
22+let (let$) : 'a Lwd.t -> ('a -> 'b) -> 'b Lwd.t = Lwd.Infix.(>|=)
33+let (and$) : 'a Lwd.t -> 'b Lwd.t -> ('a * 'b) Lwd.t = Lwd.pair
44+let (let$*) : 'a Lwd.t -> ('a -> 'b Lwd.t) -> 'b Lwd.t = Lwd.Infix.(>>=)
55+(*END*)
66+77+let ($=) : 'a Lwd.var -> 'a -> unit = Lwd.set
88+let ($<-) : 'a Lwd_table.row -> 'a -> unit = Lwd_table.set
99+1010+let ( |>$ ) v f = Lwd.map ~f v
1111+let ( >> ) f g x = g (f x)
1212+
+23
forks/lwd/lib/lwd/lwd_infix.mli
···11+(*BEGIN LETOP*)
22+val (let$) : 'a Lwd.t -> ('a -> 'b) -> 'b Lwd.t
33+(** Alias to {!Lwd.map'} suitable for let-op bindings *)
44+55+val (let$*) : 'a Lwd.t -> ('a -> 'b Lwd.t) -> 'b Lwd.t
66+(** Alias to {!Lwd.bind} suitable for let-op bindings *)
77+88+val (and$) : 'a Lwd.t -> 'b Lwd.t -> ('a * 'b) Lwd.t
99+(** Alias to {!Lwd.pair} suitable for let-op bindings *)
1010+(*END*)
1111+1212+val ($=) : 'a Lwd.var -> 'a -> unit
1313+(** Infix alias to {!Lwd.set} *)
1414+1515+val ($<-) : 'a Lwd_table.row -> 'a -> unit
1616+(** Infix alias to {!Lwd_table.set} *)
1717+1818+val ( |>$ ):'a Lwd.t -> ('a -> 'b) -> 'b Lwd.t
1919+(** Used to pipe with Lwd.map *)
2020+2121+val ( >> ):('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
2222+(** Function composition operator *)
2323+
+908
forks/lwd/lib/lwd/lwd_seq.ml
···11+(*BEGIN INJECTIVITY*)
22+type !+'a t =
33+(*ELSE*)
44+type +'a t =
55+(*END*)
66+ | Nil
77+ | Leaf of { mutable mark: int; v: 'a; }
88+ | Join of { mutable mark: int; l: 'a t; r: 'a t; }
99+1010+type 'a seq = 'a t
1111+1212+let empty = Nil
1313+1414+let element v = Leaf { mark = 0; v }
1515+1616+let mask_bits = 2
1717+1818+let maxi a b : int = if b > a then b else a
1919+2020+let rank = function
2121+ | Nil -> 0
2222+ | Leaf t ->
2323+ if t.mark <> 0 then
2424+ invalid_arg "Lwd_seq.rank: node is marked";
2525+ 0
2626+ | Join t ->
2727+ if t.mark land mask_bits <> 0 then
2828+ invalid_arg "Lwd_seq.rank: node is marked";
2929+ t.mark lsr mask_bits
3030+3131+let concat a b = match a, b with
3232+ | Nil, x | x, Nil -> x
3333+ | l, r -> Join { mark = (maxi (rank l) (rank r) + 1) lsl mask_bits; l; r }
3434+3535+type ('a, 'b) view =
3636+ | Empty
3737+ | Element of 'a
3838+ | Concat of 'b * 'b
3939+4040+let view = function
4141+ | Nil -> Empty
4242+ | Leaf t -> Element t.v
4343+ | Join t -> Concat (t.l, t.r)
4444+4545+module Balanced : sig
4646+ type 'a t = private 'a seq
4747+ val empty : 'a t
4848+ val element : 'a -> 'a t
4949+ val concat : 'a t -> 'a t -> 'a t
5050+5151+ val view : 'a t -> ('a, 'a t) view
5252+end = struct
5353+ type 'a t = 'a seq
5454+5555+ let empty = empty
5656+ let element = element
5757+5858+ let check l r = abs (l - r) <= 1
5959+6060+ let rec node_left l r =
6161+ let ml = rank l in
6262+ let mr = rank r in
6363+ if check ml mr then concat l r else match l with
6464+ | Nil | Leaf _ -> assert false
6565+ | Join t ->
6666+ if check (rank t.l) ml
6767+ then concat t.l (node_left t.r r)
6868+ else match t.r with
6969+ | Nil | Leaf _ -> assert false
7070+ | Join tr ->
7171+ let trr = node_left tr.r r in
7272+ if check (1 + maxi (rank t.l) (rank tr.l)) (rank trr)
7373+ then concat (concat t.l tr.l) trr
7474+ else concat t.l (concat tr.l trr)
7575+7676+ let rec node_right l r =
7777+ let ml = rank l in
7878+ let mr = rank r in
7979+ if check mr ml then concat l r else match r with
8080+ | Nil | Leaf _ -> assert false
8181+ | Join t ->
8282+ if check (rank t.r) mr
8383+ then concat (node_right l t.l) t.r
8484+ else match t.l with
8585+ | Nil | Leaf _ -> assert false
8686+ | Join tl ->
8787+ let tll = node_right l tl.l in
8888+ if check (1 + maxi (rank tl.r) (rank t.r)) (rank tll)
8989+ then concat tll (concat tl.r t.r)
9090+ else concat (concat tll tl.r) t.r
9191+9292+ let concat l r =
9393+ let ml = rank l in
9494+ let mr = rank r in
9595+ if check ml mr
9696+ then concat l r
9797+ else if ml <= mr
9898+ then node_right l r
9999+ else node_left l r
100100+101101+ let view = view
102102+end
103103+104104+module Marking : sig
105105+ type mark = (*private*) int
106106+ val is_shared : mark -> bool
107107+ val is_not_shared : mark -> bool
108108+ val is_none : mark -> bool
109109+ val is_both : mark -> bool
110110+ val is_old : mark -> bool
111111+ val is_new : mark -> bool
112112+ (*val has_old : mark -> bool*)
113113+ (*val has_new : mark -> bool*)
114114+ val set_both : mark -> mark
115115+ val unmark : mark -> mark
116116+ val get_index : mark -> int
117117+ val with_index_new : int -> mark
118118+119119+ type stats
120120+ val marked : stats -> int
121121+ val shared : stats -> int
122122+ val blocked : stats -> int
123123+124124+ type traversal
125125+ val old_stats : traversal -> stats
126126+ val new_stats : traversal -> stats
127127+128128+ val unsafe_traverse : old_root:_ seq -> new_root:_ seq -> traversal
129129+130130+ val restore : _ seq -> unit
131131+end = struct
132132+ type mark = int
133133+134134+ let mask_none = 0
135135+ let mask_old = 1
136136+ let mask_new = 2
137137+ let mask_both = 3
138138+139139+ let is_shared m = m = -1
140140+ let is_not_shared m = m <> -1
141141+ let is_none m = m land mask_both = mask_none
142142+ let is_both m = m land mask_both = mask_both
143143+ let is_old m = m land mask_both = mask_old
144144+ let is_new m = m land mask_both = mask_new
145145+ (*let has_old m = m land mask_old <> 0*)
146146+ (*let has_new m = m land mask_new <> 0*)
147147+ let set_both m = m lor mask_both
148148+149149+ let get_index m = m lsr mask_bits
150150+ let with_index_new index = (index lsl mask_bits) lor mask_new
151151+152152+ let unmark m = m land lnot mask_both
153153+154154+ type stats = {
155155+ mutable marked: int;
156156+ mutable shared: int;
157157+ mutable blocked: int;
158158+ }
159159+ let marked s = s.marked
160160+ let shared s = s.shared
161161+ let blocked s = s.blocked
162162+163163+ let mk_stats () = { marked = 0; shared = 0; blocked = 0 }
164164+165165+ let new_marked stats = stats.marked <- stats.marked + 1
166166+ let new_shared stats = stats.shared <- stats.shared + 1
167167+ let new_blocked stats = stats.blocked <- stats.blocked + 1
168168+169169+ let rec block stats mask = function
170170+ | Nil -> ()
171171+ | Leaf t' ->
172172+ let mark = t'.mark in
173173+ if mark land mask_both <> mask_both && mark land mask_both <> 0
174174+ then (
175175+ if mark land mask = 0 then new_marked stats else assert false;
176176+ new_blocked stats;
177177+ t'.mark <- mark lor mask_both
178178+ )
179179+ | Join t' ->
180180+ let mark = t'.mark in
181181+ if mark land mask_both <> mask_both && mark land mask_both <> 0
182182+ then (
183183+ if mark land mask = 0 then new_marked stats else assert false;
184184+ new_blocked stats;
185185+ t'.mark <- mark lor mask_both;
186186+ block stats mask t'.l;
187187+ block stats mask t'.r;
188188+ )
189189+190190+ let enqueue stats q mask = function
191191+ | Nil -> ()
192192+ | Leaf t' ->
193193+ let mark = t'.mark in
194194+ if mark land mask = 0 then (
195195+ (* Not yet seen *)
196196+ new_marked stats;
197197+ if mark land mask_both <> 0 then (
198198+ (* Newly shared, clear mask *)
199199+ t'.mark <- -1;
200200+ new_blocked stats;
201201+ new_shared stats;
202202+ ) else
203203+ t'.mark <- mark lor mask;
204204+ );
205205+ if mark <> -1 && mark land mask_both = mask_both then (
206206+ t'.mark <- -1;
207207+ new_shared stats
208208+ )
209209+ | Join t' as t ->
210210+ let mark = t'.mark in
211211+ if mark land mask = 0 then (
212212+ (* Not yet seen *)
213213+ new_marked stats;
214214+ if mark land mask_both <> 0 then (
215215+ (* Newly shared, clear mask *)
216216+ t'.mark <- -1;
217217+ new_blocked stats;
218218+ new_shared stats;
219219+ block stats mask t'.l;
220220+ block stats mask t'.r;
221221+ ) else (
222222+ (* First mark *)
223223+ t'.mark <- mark lor mask;
224224+ Queue.push t q
225225+ )
226226+ );
227227+ if mark <> -1 && mark land mask_both = mask_both then (
228228+ t'.mark <- -1;
229229+ new_shared stats
230230+ )
231231+232232+ let dequeue stats q mask =
233233+ match Queue.pop q with
234234+ | Join t ->
235235+ if t.mark land mask_both = mask then (
236236+ enqueue stats q mask t.l;
237237+ enqueue stats q mask t.r;
238238+ )
239239+ | _ -> assert false
240240+241241+ let traverse1 stats q mask =
242242+ while not (Queue.is_empty q) do
243243+ dequeue stats q mask
244244+ done
245245+246246+ let rec traverse sold snew qold qnew =
247247+ if Queue.is_empty qold then
248248+ traverse1 snew qnew mask_new
249249+ else if Queue.is_empty qnew then
250250+ traverse1 sold qold mask_old
251251+ else (
252252+ dequeue sold qold mask_old;
253253+ dequeue snew qnew mask_new;
254254+ traverse sold snew qold qnew
255255+ )
256256+257257+ type traversal = {
258258+ old_stats: stats;
259259+ new_stats: stats;
260260+ }
261261+262262+ let old_stats tr = tr.old_stats
263263+ let new_stats tr = tr.new_stats
264264+265265+ let unsafe_traverse ~old_root ~new_root =
266266+ let old_stats = mk_stats () in
267267+ let new_stats = mk_stats () in
268268+ let old_queue = Queue.create () in
269269+ let new_queue = Queue.create () in
270270+ enqueue old_stats old_queue mask_old old_root;
271271+ enqueue new_stats new_queue mask_new new_root;
272272+ traverse old_stats new_stats old_queue new_queue;
273273+ {old_stats; new_stats}
274274+275275+ let restore = function
276276+ | Nil -> ()
277277+ | Leaf t -> t.mark <- 0
278278+ | Join t ->
279279+ t.mark <- (maxi (rank t.l) (rank t.r) + 1) lsl mask_bits
280280+end
281281+282282+(* Marks go through many states.
283283+284284+ A mark is usually split in two parts:
285285+ - the mask, made of the two least significant bits
286286+ - the index is an unsigned integer formed of all the remaining bits
287287+288288+ The exception is the distinguished mask with value -1 (all bits set to 1)
289289+ that denote a "locked" node.
290290+291291+ When the mask is 0, the index denotes the rank of the node: the depth of
292292+ the tree rooted at this node.
293293+ When the mask is non-zero, the index meaning is left to the traversal
294294+ algorithm.
295295+ Restoring the mark sets the mask to 0 and the indext to the rank,
296296+ but is only possible when the children of the node are themselves restored.
297297+*)
298298+299299+module Reducer = struct
300300+ type (+'a, 'b) xform =
301301+ | XEmpty
302302+ | XLeaf of { a: 'a t; mutable b: 'b option; }
303303+ | XJoin of { a: 'a t; mutable b: 'b option;
304304+ l: ('a, 'b) xform; r: ('a, 'b) xform; }
305305+306306+ type ('a, 'b) unmark_state = {
307307+ dropped : 'b option array;
308308+ mutable dropped_leaf : int;
309309+ mutable dropped_join : int;
310310+ shared : 'a seq array;
311311+ shared_x : ('a, 'b) xform list array;
312312+ mutable shared_index: int;
313313+ }
314314+315315+ let next_shared_index st =
316316+ let result = st.shared_index in
317317+ st.shared_index <- result + 1;
318318+ result
319319+320320+ let rec unblock = function
321321+ | XEmpty -> ()
322322+ | XLeaf {a = Nil | Join _; _} -> assert false
323323+ | XJoin {a = Nil | Leaf _; _} -> assert false
324324+ | XLeaf {a = Leaf t'; _} ->
325325+ let mark = t'.mark in
326326+ if Marking.is_not_shared mark && Marking.is_both mark then
327327+ t'.mark <- Marking.unmark mark;
328328+ | XJoin {a = Join t'; l; r; _} ->
329329+ let mark = t'.mark in
330330+ if Marking.is_not_shared mark && Marking.is_both mark then (
331331+ t'.mark <- Marking.unmark mark;
332332+ unblock l;
333333+ unblock r
334334+ )
335335+336336+ let rec unmark_old st = function
337337+ | XEmpty -> ()
338338+ | XLeaf {a = Nil | Join _; _} -> assert false
339339+ | XJoin {a = Nil | Leaf _; _} -> assert false
340340+ | XLeaf {a = Leaf t' as a; b} as t ->
341341+ let mark = t'.mark in
342342+ if Marking.is_old mark then (
343343+ let dropped_leaf = st.dropped_leaf in
344344+ if dropped_leaf > -1 then (
345345+ st.dropped.(dropped_leaf) <- b;
346346+ st.dropped_leaf <- dropped_leaf + 1;
347347+ assert (st.dropped_leaf <= st.dropped_join);
348348+ );
349349+ t'.mark <- Marking.unmark mark
350350+ ) else if Marking.is_shared mark then (
351351+ let index = next_shared_index st in
352352+ st.shared.(index) <- a;
353353+ st.shared_x.(index) <- [t];
354354+ t'.mark <- Marking.with_index_new index;
355355+ ) else if Marking.is_new mark then (
356356+ let index = Marking.get_index mark in
357357+ st.shared_x.(index) <- t :: st.shared_x.(index);
358358+ ) else if Marking.is_both mark then (
359359+ assert false
360360+ (*t'.mark <- mark land lnot both_mask*)
361361+ )
362362+ | XJoin {a = Join t' as a; l; r; b} as t ->
363363+ let mark = t'.mark in
364364+ if Marking.is_shared mark then (
365365+ let index = next_shared_index st in
366366+ st.shared.(index) <- a;
367367+ st.shared_x.(index) <- [t];
368368+ t'.mark <- Marking.with_index_new index;
369369+ unblock l;
370370+ unblock r;
371371+ ) else if Marking.is_old mark then (
372372+ if st.dropped_join > -1 then (
373373+ let dropped_join = st.dropped_join - 1 in
374374+ st.dropped.(dropped_join) <- b;
375375+ st.dropped_join <- dropped_join;
376376+ assert (st.dropped_leaf <= st.dropped_join);
377377+ );
378378+ t'.mark <- Marking.unmark mark;
379379+ unmark_old st l;
380380+ unmark_old st r;
381381+ ) else if Marking.is_new mark then (
382382+ let index = mark lsr mask_bits in
383383+ st.shared_x.(index) <- t :: st.shared_x.(index);
384384+ ) else if Marking.is_both mark then (
385385+ assert false
386386+ )
387387+388388+ let prepare_shared st =
389389+ for i = 0 to st.shared_index - 1 do
390390+ begin match st.shared.(i) with
391391+ | Nil -> ()
392392+ | Leaf t -> t.mark <- Marking.set_both t.mark
393393+ | Join t -> t.mark <- Marking.set_both t.mark
394394+ end;
395395+ match st.shared_x.(i) with
396396+ | [] -> assert false
397397+ | [_] -> ()
398398+ | xs -> st.shared_x.(i) <- List.rev xs
399399+ done
400400+401401+ let rec unmark_new st = function
402402+ | Nil -> XEmpty
403403+ | Leaf t' as t ->
404404+ let mark = t'.mark in
405405+ if Marking.is_not_shared mark && Marking.is_both mark then (
406406+ let index = mark lsr mask_bits in
407407+ match st.shared_x.(index) with
408408+ | [] -> XLeaf {a = t; b = None}
409409+ | x :: xs -> st.shared_x.(index) <- xs; x
410410+ ) else (
411411+ t'.mark <- 0;
412412+ XLeaf {a = t; b = None}
413413+ )
414414+ | Join t' as t ->
415415+ let mark = t'.mark in
416416+ if mark = -1 then (
417417+ let index = next_shared_index st in
418418+ t'.mark <- 0;
419419+ st.shared.(index) <- t;
420420+ let l = unmark_new st t'.l in
421421+ let r = unmark_new st t'.r in
422422+ XJoin {a = t; b = None; l; r}
423423+ ) else if Marking.is_both mark then (
424424+ let index = mark lsr mask_bits in
425425+ match st.shared_x.(index) with
426426+ | [] -> assert false
427427+ | x :: xs ->
428428+ st.shared_x.(index) <- xs;
429429+ if xs == [] then t'.mark <- 0;
430430+ x
431431+ ) else (
432432+ t'.mark <- Marking.unmark t'.mark;
433433+ let l = unmark_new st t'.l in
434434+ let r = unmark_new st t'.r in
435435+ XJoin {a = t; b = None; l; r}
436436+ )
437437+438438+ type 'b dropped = {
439439+ leaves: int;
440440+ table: 'b option array;
441441+ extra_leaf: 'b list;
442442+ extra_join: 'b list;
443443+ }
444444+445445+ let no_dropped =
446446+ { leaves = 0; table = [||]; extra_leaf = []; extra_join = [] }
447447+448448+ let diff get_dropped xold tnew = match xold, tnew with
449449+ | XEmpty, Nil -> no_dropped, XEmpty
450450+ | (XLeaf {a; _} | XJoin {a; _}), _ when a == tnew -> no_dropped, xold
451451+ | _ ->
452452+ let traversal =
453453+ Marking.unsafe_traverse
454454+ ~old_root:(match xold with
455455+ | XEmpty -> empty
456456+ | (XLeaf {a; _} | XJoin {a; _}) -> a
457457+ )
458458+ ~new_root:tnew
459459+ in
460460+ let sold = Marking.old_stats traversal in
461461+ let snew = Marking.new_stats traversal in
462462+ let nb_dropped =
463463+ Marking.marked sold - (Marking.blocked sold + Marking.blocked snew)
464464+ in
465465+ let nb_shared =
466466+ Marking.shared sold + Marking.shared snew
467467+ in
468468+ let st = {
469469+ dropped = if get_dropped then Array.make nb_dropped None else [||];
470470+ dropped_leaf = if get_dropped then 0 else - 1;
471471+ dropped_join = if get_dropped then nb_dropped else - 1;
472472+ shared = Array.make nb_shared Nil;
473473+ shared_x = Array.make nb_shared [];
474474+ shared_index = 0;
475475+ } in
476476+ (*Printf.eprintf "sold.shared:%d sold.marked:%d sold.blocked:%d\n%!"
477477+ sold.shared sold.marked sold.blocked;
478478+ Printf.eprintf "snew.shared:%d snew.marked:%d snew.blocked:%d\n%!"
479479+ snew.shared snew.marked snew.blocked;*)
480480+ unmark_old st xold;
481481+ assert (st.dropped_leaf = st.dropped_join);
482482+ prepare_shared st;
483483+ let result = unmark_new st tnew in
484484+ (*Printf.eprintf "new_computed:%d%!\n" !new_computed;*)
485485+ for i = st.shared_index - 1 downto 0 do
486486+ Marking.restore st.shared.(i)
487487+ done;
488488+ if get_dropped then (
489489+ let xleaf = ref [] in
490490+ let xjoin = ref [] in
491491+ for i = 0 to st.shared_index - 1 do
492492+ List.iter (function
493493+ | XLeaf { b = Some b; _} -> xleaf := b :: !xleaf
494494+ | XJoin { b = Some b; _} -> xjoin := b :: !xjoin
495495+ | _ -> ()
496496+ ) st.shared_x.(i)
497497+ done;
498498+ ({ leaves = st.dropped_leaf;
499499+ table = st.dropped;
500500+ extra_leaf = !xleaf;
501501+ extra_join = !xjoin }, result)
502502+ ) else
503503+ no_dropped, result
504504+505505+ type ('a, 'b) map_reduce = {
506506+ map: 'a -> 'b;
507507+ reduce: 'b -> 'b -> 'b;
508508+ }
509509+510510+ let eval map_reduce = function
511511+ | XEmpty -> None
512512+ | other ->
513513+ let rec aux = function
514514+ | XEmpty | XLeaf {a = Nil | Join _; _} -> assert false
515515+ | XLeaf {b = Some b; _} | XJoin {b = Some b; _} -> b
516516+ | XLeaf ({a = Leaf t';_ } as t) ->
517517+ let result = map_reduce.map t'.v in
518518+ t.b <- Some result;
519519+ result
520520+ | XJoin t ->
521521+ let l = aux t.l and r = aux t.r in
522522+ let result = map_reduce.reduce l r in
523523+ t.b <- Some result;
524524+ result
525525+ in
526526+ Some (aux other)
527527+528528+ type ('a, 'b) reducer = ('a, 'b) map_reduce * ('a, 'b) xform
529529+530530+ let make ~map ~reduce = ({map; reduce}, XEmpty)
531531+532532+ let reduce (map_reduce, tree : _ reducer) =
533533+ eval map_reduce tree
534534+535535+ let update (map_reduce, old_tree : _ reducer) new_tree : _ reducer =
536536+ let _, tree = diff false old_tree new_tree in
537537+ (map_reduce, tree)
538538+539539+ let update_and_get_dropped (map_reduce, old_tree : _ reducer) new_tree
540540+ : _ dropped * _ reducer =
541541+ let dropped, tree = diff true old_tree new_tree in
542542+ (dropped, (map_reduce, tree))
543543+544544+ let fold_dropped kind f dropped acc =
545545+ let acc = ref acc in
546546+ let start, bound = match kind with
547547+ | `All -> 0, Array.length dropped.table
548548+ | `Map -> 0, dropped.leaves
549549+ | `Reduce -> dropped.leaves, Array.length dropped.table
550550+ in
551551+ for i = start to bound - 1 do
552552+ match dropped.table.(i) with
553553+ | None -> ()
554554+ | Some x -> acc := f x !acc
555555+ done;
556556+ begin match kind with
557557+ | `All | `Map ->
558558+ List.iter (fun x -> acc := f x !acc) dropped.extra_leaf
559559+ | `Reduce -> ()
560560+ end;
561561+ begin match kind with
562562+ | `All | `Reduce ->
563563+ List.iter (fun x -> acc := f x !acc) dropped.extra_join
564564+ | `Map -> ()
565565+ end;
566566+ !acc
567567+end
568568+569569+(* Lwd interface *)
570570+571571+let rec pure_map_reduce map reduce = function
572572+ | Nil -> assert false
573573+ | Leaf t -> map t.v
574574+ | Join t ->
575575+ reduce
576576+ (pure_map_reduce map reduce t.l)
577577+ (pure_map_reduce map reduce t.r)
578578+579579+let fold ~map ~reduce seq =
580580+ match Lwd.is_pure seq with
581581+ | Some Nil -> Lwd.pure None
582582+ | Some other -> Lwd.pure (Some (pure_map_reduce map reduce other))
583583+ | None ->
584584+ let reducer = ref (Reducer.make ~map ~reduce) in
585585+ Lwd.map seq ~f:begin fun seq ->
586586+ let reducer' = Reducer.update !reducer seq in
587587+ reducer := reducer';
588588+ Reducer.reduce reducer'
589589+ end
590590+591591+let fold_monoid map (zero, reduce) seq =
592592+ match Lwd.is_pure seq with
593593+ | Some Nil -> Lwd.pure zero
594594+ | Some other -> Lwd.pure (pure_map_reduce map reduce other)
595595+ | None ->
596596+ let reducer = ref (Reducer.make ~map ~reduce) in
597597+ Lwd.map seq ~f:begin fun seq ->
598598+ let reducer' = Reducer.update !reducer seq in
599599+ reducer := reducer';
600600+ match Reducer.reduce reducer' with
601601+ | None -> zero
602602+ | Some x -> x
603603+ end
604604+605605+let monoid = (empty, concat)
606606+607607+let transform_list ls f =
608608+ Lwd_utils.map_reduce f monoid ls
609609+610610+let of_list ls = transform_list ls element
611611+612612+let rec of_sub_array f arr i j =
613613+ if j < i then empty
614614+ else if j = i then f arr.(i)
615615+ else
616616+ let k = i + (j - i) / 2 in
617617+ concat (of_sub_array f arr i k) (of_sub_array f arr (k + 1) j)
618618+619619+let transform_array arr f = of_sub_array f arr 0 (Array.length arr - 1)
620620+621621+let of_array arr = transform_array arr element
622622+623623+let to_list x =
624624+ let rec fold x acc = match x with
625625+ | Nil -> acc
626626+ | Leaf t -> t.v :: acc
627627+ | Join t -> fold t.l (fold t.r acc)
628628+ in
629629+ fold x []
630630+631631+let to_array x =
632632+ let rec count = function
633633+ | Nil -> 0
634634+ | Leaf _ -> 1
635635+ | Join t -> count t.l + count t.r
636636+ in
637637+ match count x with
638638+ | 0 -> [||]
639639+ | n ->
640640+ let rec first = function
641641+ | Nil -> assert false
642642+ | Leaf t -> t.v
643643+ | Join t -> first t.l
644644+ in
645645+ let first = first x in
646646+ let arr = Array.make n first in
647647+ let rec fold i = function
648648+ | Nil -> i
649649+ | Leaf t -> arr.(i) <- t.v; i + 1
650650+ | Join t ->
651651+ let i = fold i t.l in
652652+ let i = fold i t.r in
653653+ i
654654+ in
655655+ let _ : int = fold 0 x in
656656+ arr
657657+658658+let lwd_empty : 'a t Lwd.t = Lwd.pure Nil
659659+let lwd_monoid : 'a. 'a t Lwd.t Lwd_utils.monoid =
660660+ (lwd_empty, fun x y -> Lwd.map2 ~f:concat x y)
661661+662662+let map f seq =
663663+ fold_monoid (fun x -> element (f x)) monoid seq
664664+665665+let filter f seq =
666666+ fold_monoid (fun x -> if f x then element x else empty) monoid seq
667667+668668+let filter_map f seq =
669669+ let select x = match f x with
670670+ | Some y -> element y
671671+ | None -> empty
672672+ in
673673+ fold_monoid select monoid seq
674674+675675+let bind (seq : 'a seq Lwd.t) (f : 'a -> 'b seq Lwd.t) : 'b seq Lwd.t =
676676+ Lwd.join (fold_monoid f lwd_monoid seq)
677677+678678+let seq_bind (seq : 'a seq Lwd.t) (f : 'a -> 'b seq) : 'b seq Lwd.t =
679679+ fold_monoid f monoid seq
680680+681681+let lift (seq : 'a Lwd.t seq Lwd.t) : 'a seq Lwd.t =
682682+ bind seq (Lwd.map ~f:element)
683683+684684+module BalancedTree : sig
685685+ type 'a t =
686686+ | Leaf
687687+ | Node of {
688688+ rank: int;
689689+ l: 'a t;
690690+ x: int * 'a seq;
691691+ r: 'a t;
692692+ mutable seq: 'a seq;
693693+ }
694694+ val leaf : 'a t
695695+ (*val node : 'a t -> int * 'a seq -> 'a t -> 'a t*)
696696+697697+ val insert : cmp:('a -> 'a -> int) -> int -> 'a seq -> 'a t -> 'a t
698698+ (*val union : cmp:('a -> 'a -> int) -> 'a t -> 'a t -> 'a t*)
699699+end = struct
700700+ type 'a t =
701701+ | Leaf
702702+ | Node of {
703703+ rank: int;
704704+ l: 'a t;
705705+ x: int * 'a seq;
706706+ r: 'a t;
707707+ mutable seq: 'a seq;
708708+ }
709709+710710+ let leaf = Leaf
711711+712712+ let rank = function
713713+ | Leaf -> 0
714714+ | Node t -> t.rank
715715+716716+ let check l r = abs (l - r) <= 1
717717+718718+ let node l x r =
719719+ Node {l; x; r; seq = empty; rank = maxi (rank l) (rank r) + 1}
720720+721721+ let rec node_left l x r =
722722+ let ml = rank l in
723723+ let mr = rank r in
724724+ if check ml mr then node l x r else match l with
725725+ | Leaf -> assert false
726726+ | Node t ->
727727+ if check (rank t.l) ml
728728+ then node t.l t.x (node_left t.r x r)
729729+ else match t.r with
730730+ | Leaf -> assert false
731731+ | Node tr ->
732732+ let trr = node_left tr.r x r in
733733+ if check (1 + maxi (rank t.l) (rank tr.l)) (rank trr)
734734+ then node (node t.l t.x tr.l) tr.x trr
735735+ else node t.l t.x (node tr.l tr.x trr)
736736+737737+ let rec node_right l x r =
738738+ let ml = rank l in
739739+ let mr = rank r in
740740+ if check mr ml then node l x r else match r with
741741+ | Leaf -> assert false
742742+ | Node t ->
743743+ if check (rank t.r) mr
744744+ then node (node_right l x t.l) t.x t.r
745745+ else match t.l with
746746+ | Leaf -> assert false
747747+ | Node tl ->
748748+ let tll = node_right l x tl.l in
749749+ if check (1 + maxi (rank tl.r) (rank t.r)) (rank tll)
750750+ then node tll tl.x (node tl.r t.x t.r)
751751+ else node (node tll tl.x tl.r) t.x t.r
752752+753753+ let node l x r =
754754+ let ml = rank l in
755755+ let mr = rank r in
756756+ if check ml mr
757757+ then node l x r
758758+ else if ml <= mr
759759+ then node_right l x r
760760+ else node_left l x r
761761+762762+ let rec join l r = match l, r with
763763+ | Leaf, t | t, Leaf -> t
764764+ | Node tl, Node tr ->
765765+ if tl.rank <= tr.rank then
766766+ node (join l tr.l) tr.x tr.r
767767+ else
768768+ node tl.l tl.x (join tl.r r)
769769+770770+ let get_element = function
771771+ | Nil | Join _ -> assert false
772772+ | Leaf {v;_} -> v
773773+774774+ (*let rec split ~cmp k = function
775775+ | Leaf -> Leaf, 0, Leaf
776776+ | Node t ->
777777+ let c = cmp k (get_element (snd (t.x))) in
778778+ if c < 0 then
779779+ let l', v', r' = split ~cmp k t.l in
780780+ l', v', join r' t.r
781781+ else if c > 0 then
782782+ let l', v', r' = split ~cmp k t.r in
783783+ join t.l l', v', r'
784784+ else
785785+ (t.l, fst t.x, t.r)
786786+787787+ let rec union ~cmp t1 t2 =
788788+ match t1, t2 with
789789+ | Leaf, t | t, Leaf -> t
790790+ | Node t1, t2 ->
791791+ let m1, k1 = t1.x in
792792+ let l2, m2, r2 = split ~cmp (get_element k1) t2 in
793793+ let l' = union ~cmp t1.l l2 in
794794+ let r' = union ~cmp t1.r r2 in
795795+ let m = m1 + m2 in
796796+ if m = 0 then
797797+ join l' r'
798798+ else (
799799+ assert (m > 0);
800800+ node l' (m, k1) r';
801801+ )
802802+ *)
803803+804804+ let insert ~cmp m1 s t =
805805+ assert (m1 <> 0);
806806+ let rec aux = function
807807+ | Leaf -> node Leaf (m1, s) Leaf
808808+ | Node t ->
809809+ let m2, x = t.x in
810810+ let c = cmp (get_element s) (get_element x) in
811811+ if c = 0 then
812812+ let m = m1 + m2 in
813813+ if m = 0 then
814814+ join t.l t.r
815815+ else
816816+ node t.l (m, x) t.r
817817+ else if c < 0 then
818818+ let l' = aux t.l in
819819+ node l' t.x t.r
820820+ else
821821+ let r' = aux t.r in
822822+ node t.l t.x r'
823823+ in
824824+ aux t
825825+end
826826+827827+let rec seq_of_tree = function
828828+ | BalancedTree.Leaf -> empty
829829+ | BalancedTree.Node t ->
830830+ match t.seq with
831831+ | Nil ->
832832+ let sl = seq_of_tree t.l in
833833+ let sr = seq_of_tree t.r in
834834+ assert (fst t.x > 0);
835835+ let seq = concat sl (concat (snd t.x) sr) in
836836+ t.seq <- seq;
837837+ seq
838838+ | seq -> seq
839839+840840+let sort_uniq cmp seq =
841841+ let previous_seq = ref empty in
842842+ let previous_tree = ref BalancedTree.leaf in
843843+ let f new_seq =
844844+ let old_seq = !previous_seq in
845845+ let old_tree = !previous_tree in
846846+ let _ = Marking.unsafe_traverse ~old_root:old_seq ~new_root:new_seq in
847847+ let rec unblock = function
848848+ | Nil -> ()
849849+ | Leaf t -> t.mark <- Marking.unmark t.mark
850850+ | Join t as seq ->
851851+ let mark = t.mark in
852852+ unblock t.l;
853853+ unblock t.r;
854854+ if Marking.is_shared mark then (
855855+ Marking.restore seq;
856856+ ) else if Marking.is_both mark then (
857857+ t.mark <- Marking.unmark mark;
858858+ ) else
859859+ assert (Marking.is_none mark)
860860+ in
861861+ let rec unmark_new tree = function
862862+ | Nil -> tree
863863+ | Leaf t as seq ->
864864+ let mark = t.mark in
865865+ t.mark <- 0;
866866+ if Marking.is_new mark then
867867+ BalancedTree.insert ~cmp (+1) seq tree
868868+ else (
869869+ assert (Marking.is_both mark || Marking.is_none mark);
870870+ tree
871871+ )
872872+ | Join t as seq ->
873873+ let mark = t.mark in
874874+ if Marking.is_new mark then (
875875+ t.mark <- Marking.unmark mark;
876876+ unmark_new (unmark_new tree t.l) t.r
877877+ ) else (
878878+ unblock seq;
879879+ tree
880880+ )
881881+ in
882882+ let rec unmark_old tree = function
883883+ | Nil -> tree
884884+ | Leaf t as seq ->
885885+ let mark = t.mark in
886886+ t.mark <- 0;
887887+ if Marking.is_old mark then
888888+ BalancedTree.insert ~cmp (-1) seq tree
889889+ else (
890890+ assert (Marking.is_both mark || Marking.is_none mark);
891891+ tree
892892+ )
893893+ | Join t as seq ->
894894+ let mark = t.mark in
895895+ if Marking.is_old mark then (
896896+ t.mark <- Marking.unmark mark;
897897+ unmark_old (unmark_old tree t.l) t.r
898898+ ) else (
899899+ unblock seq;
900900+ tree
901901+ )
902902+ in
903903+ let new_tree = unmark_old (unmark_new old_tree new_seq) old_seq in
904904+ previous_seq := new_seq;
905905+ previous_tree := new_tree;
906906+ seq_of_tree new_tree
907907+ in
908908+ Lwd.map seq ~f
+209
forks/lwd/lib/lwd/lwd_seq.mli
···11+(** {1 Sequence manipulation}
22+33+ [Lwd_seq] is an ordered collection with a pure interface.
44+ Changes to collections are easy to track.
55+66+ A collection can be transformed with the usual map, filter and fold
77+ combinators. If the collection is updated, shared elements (in the sense of
88+ physical sharing), the result of the previous transformation will be reused
99+ for these elements.
1010+1111+ The book-keeping overhead is O(n) in the number of changes, so O(1) per
1212+ element.
1313+*)
1414+1515+(*BEGIN INJECTIVITY*)
1616+type !+'a t
1717+type !+'a seq = 'a t
1818+(*ELSE*)
1919+type +'a t
2020+type +'a seq = 'a t
2121+(*END*)
2222+2323+(** The type of sequences *)
2424+2525+(** {2 Primitive constructors} *)
2626+2727+val empty : 'a seq
2828+(** A sequence with no element. *)
2929+3030+val element : 'a -> 'a seq
3131+(** A singleton sequence. The physical identity of the element is considered
3232+ when reusing previous computations.
3333+3434+ If you do:
3535+3636+ {[let x1 = element x
3737+ let x2 = element x]}
3838+3939+ Then [x1] and [x2] are seen as different elements and no sharing will be
4040+ done during transformation.
4141+*)
4242+4343+val concat : 'a seq -> 'a seq -> 'a seq
4444+(** Concatenate two sequences into a bigger one.
4545+ As for [element], the physical identity of a sequence is considered for
4646+ reuse.
4747+*)
4848+4949+(** {2 Looking at sequence contents} *)
5050+5151+type ('a, 'b) view =
5252+ | Empty
5353+ | Element of 'a
5454+ | Concat of 'b * 'b
5555+5656+val view : 'a seq -> ('a, 'a seq) view
5757+(** View how a sequence is defined *)
5858+5959+(** {2 Conversion between sequences, lists and arrays} *)
6060+6161+val transform_list : 'a list -> ('a -> 'b seq) -> 'b seq
6262+(** Produce a sequence by transforming each element of a list and concatenating
6363+ all results. *)
6464+6565+val transform_array : 'a array -> ('a -> 'b seq) -> 'b seq
6666+(** Produce a sequence by transforming each element of an array and
6767+ concatenating all results. *)
6868+6969+val of_list : 'a list -> 'a seq
7070+(** Produce a sequence from a list *)
7171+7272+val of_array : 'a array -> 'a seq
7373+(** Produce a sequence from an array *)
7474+7575+val to_list : 'a seq -> 'a list
7676+(** Produce a list from a sequence *)
7777+7878+val to_array : 'a seq -> 'a array
7979+(** Produce an array from a sequence *)
8080+8181+(** {2 Balanced variant of sequences} *)
8282+8383+module Balanced : sig
8484+8585+ (** A variant of the sequence type that guarantees that the depth of a
8686+ transformation, measured as the number of nested [concat] nodes, grows in
8787+ O(log n) where n is the number of elements in the sequnce.
8888+8989+ This is useful to prevent stack overflows and to avoid degenerate cases
9090+ where a single element changes, but it is at the end of a linear sequence
9191+ of [concat] nodes, thus making the total work O(n).
9292+ For instance, in:
9393+9494+ {[concat e1 (concat e2 (concat e3 (... (concat e_n))...))]}
9595+9696+ If [e_n] changes, the whole spine has to be recomputed.
9797+9898+ Using [Balanced.concat], the representation will be re-balanced
9999+ internally. Then [Balanced.view] should be used to access the balanced
100100+ sequence.
101101+102102+ When working with balanced sequences in a transformation pipeline, it is
103103+ only useful to balance the first sequence of the pipeline. Derived
104104+ sequence will have a depth bounded by the depth of the first one.
105105+ *)
106106+107107+ type 'a t = private 'a seq
108108+ (** Type of balanced sequences *)
109109+110110+ val empty : 'a t
111111+ val element : 'a -> 'a t
112112+ val concat : 'a t -> 'a t -> 'a t
113113+114114+ val view : 'a t -> ('a, 'a t) view
115115+end
116116+117117+(** {2 Transforming sequences} *)
118118+119119+(**
120120+ All sequences live in [Lwd] monad: if a sequence changes slightly, parts
121121+ that have not changed will not be re-transformed.
122122+*)
123123+124124+val fold :
125125+ map:('a -> 'b) -> reduce:('b -> 'b -> 'b) -> 'a seq Lwd.t -> 'b option Lwd.t
126126+(** [fold ~map ~reduce] transforms a sequence.
127127+ If the sequence is non-empty, the [map] function is applied to element
128128+ nodes and the [reduce] function is used to combine transformed concatenated
129129+ nodes.
130130+ If the sequence is empty, None is returned.
131131+*)
132132+133133+val fold_monoid :
134134+ ('a -> 'b) -> 'b Lwd_utils.monoid -> 'a seq Lwd.t -> 'b Lwd.t
135135+(** Like [fold], but reduction and default value are defined by a [monoid] *)
136136+137137+val map :
138138+ ('a -> 'b) -> 'a seq Lwd.t -> 'b seq Lwd.t
139139+(** [map f] transforms a sequence by applying [f] to each element. *)
140140+141141+val filter :
142142+ ('a -> bool) -> 'a seq Lwd.t -> 'a seq Lwd.t
143143+(** [filter p] transforms a sequence by keeping elements that satisfies [p]. *)
144144+145145+val filter_map :
146146+ ('a -> 'b option) -> 'a seq Lwd.t -> 'b seq Lwd.t
147147+(** Filter and map elements at the same time *)
148148+149149+val lift : 'a Lwd.t seq Lwd.t -> 'a seq Lwd.t
150150+(** Remove a layer of [Lwd] inside a sequence. *)
151151+152152+val bind : 'a seq Lwd.t -> ('a -> 'b seq Lwd.t) -> 'b seq Lwd.t
153153+(** Sequence forms a monad too... *)
154154+155155+val seq_bind : 'a seq Lwd.t -> ('a -> 'b seq) -> 'b seq Lwd.t
156156+(** Sequence forms a monad too... *)
157157+158158+val monoid : 'a t Lwd_utils.monoid
159159+(** Monoid instance for sequences *)
160160+161161+val lwd_monoid : 'a t Lwd.t Lwd_utils.monoid
162162+(** Monoid instance for reactive sequences *)
163163+164164+val sort_uniq : ('a -> 'a -> int) -> 'a seq Lwd.t -> 'a seq Lwd.t
165165+166166+(** {2 Low-level interface for observing changes} *)
167167+168168+module Reducer : sig
169169+ (* The interface allows to implement incremental sequence transformation
170170+ outside of the [Lwd] monad.
171171+ Actually, the Lwd functions above are implemented on top of this
172172+ interface.
173173+ *)
174174+175175+ (* A [('a, 'b) reducer] value stores the state necessary to incrementally
176176+ transform an ['a seq] to ['b].
177177+ In essence, the Lwd functions just hide a reducer value.
178178+ *)
179179+ type ('a, 'b) reducer
180180+181181+ (* A new reducer that transforms sequences with the given [map] and [reduce]
182182+ functions. The reducer starts from the [empty] sequence. *)
183183+ val make : map:('a -> 'b) -> reduce:('b -> 'b -> 'b) -> ('a, 'b) reducer
184184+185185+ (* Updates the [reducer] to transform another sequence.
186186+ Intermediate nodes are reused when possible.
187187+ Only the "reuse plan" is computed by [update], actual transformation is
188188+ done by the [reduce] function.
189189+ *)
190190+ val update : ('a, 'b) reducer -> 'a seq -> ('a, 'b) reducer
191191+192192+ (* Returns the reduced ['b] value if the sequence is non-empty or [None] if
193193+ the sequence is empty.
194194+ Because transformation is done lazily, [reduce] is the only function
195195+ that can call [map] and [reduce].
196196+ *)
197197+ val reduce : ('a, 'b) reducer -> 'b option
198198+199199+ (* Sometimes it is important to track the elements that disappeared from a
200200+ sequence. The ['b dropped] type represent all the intermediate result that
201201+ were referenced by a reducer and are no longer after an update.
202202+ *)
203203+ type 'b dropped
204204+ val update_and_get_dropped :
205205+ ('a, 'b) reducer -> 'a seq -> 'b dropped * ('a, 'b) reducer
206206+207207+ val fold_dropped :
208208+ [<`All|`Map|`Reduce] -> ('a -> 'b -> 'b) -> 'a dropped -> 'b -> 'b
209209+end
+579
forks/lwd/lib/lwd/lwd_table.ml
···11+type 'a binding =
22+ | Bound of { value : 'a ; mutable valid : bool }
33+ | Unbound
44+55+type 'a tree =
66+ | Leaf
77+ | Node of {
88+ mutable version : int;
99+ mutable left : 'a tree;
1010+ mutable binding : 'a binding;
1111+ mutable right : 'a tree;
1212+ mutable parent : 'a tree;
1313+ mutable size : int;
1414+ }
1515+ | Root of {
1616+ mutable version : int;
1717+ mutable child : 'a tree;
1818+ mutable generation : unit ref;
1919+ mutable on_invalidate : Obj.t Lwd.prim list;
2020+ }
2121+2222+type 'a t = 'a tree
2323+type 'a row = 'a tree
2424+2525+let not_origin = ref () (* not {!origin} *)
2626+let origin = ref () (* not {!not_origin} *)
2727+2828+let make () =
2929+ Root { child = Leaf; generation = origin; version = 0; on_invalidate = [] }
3030+3131+let set_parent ~parent = function
3232+ | Root _ -> assert false
3333+ | Node n -> n.parent <- parent
3434+ | Leaf -> ()
3535+3636+let reparent ~parent ~oldchild ~newchild =
3737+ match parent with
3838+ | Root r ->
3939+ assert (r.child == oldchild);
4040+ r.child <- newchild
4141+ | Node n when n.left == oldchild ->
4242+ n.left <- newchild
4343+ | Node n when n.right == oldchild ->
4444+ n.right <- newchild
4545+ | Leaf | Node _ -> assert false
4646+4747+let make_node set ~left ~right ~parent =
4848+ let binding = match set with
4949+ | None -> Unbound
5050+ | Some value -> Bound { value ; valid = true }
5151+ in
5252+ let node = Node { left; right; parent; version = 0; size = 0; binding } in
5353+ set_parent left ~parent:node;
5454+ set_parent right ~parent:node;
5555+ node
5656+5757+let rec raw_invalidate = function
5858+ | Node { size = 0; _ } -> ()
5959+ | Node t ->
6060+ t.size <- 0;
6161+ raw_invalidate t.parent
6262+ | Root r ->
6363+ List.iter Lwd.invalidate r.on_invalidate
6464+ | Leaf -> assert false
6565+6666+let prepend ?set = function
6767+ | Root r as parent ->
6868+ raw_invalidate parent;
6969+ let node = make_node set ~left:Leaf ~right:r.child ~parent in
7070+ r.child <- node;
7171+ node
7272+ | Leaf | Node _ -> assert false
7373+7474+let prepend' x set = ignore (prepend x ~set)
7575+7676+let append ?set = function
7777+ | Root r as parent ->
7878+ raw_invalidate parent;
7979+ let node = make_node set ~left:r.child ~right:Leaf ~parent in
8080+ r.child <- node;
8181+ node
8282+ | Leaf | Node _ -> assert false
8383+8484+let append' x set = ignore (append x ~set)
8585+8686+let before ?set = function
8787+ | Node { parent = Leaf ; _ } | Leaf -> Leaf
8888+ | Node n as parent ->
8989+ raw_invalidate parent;
9090+ let node = make_node set ~left:n.left ~right:Leaf ~parent in
9191+ n.left <- node;
9292+ node
9393+ | Root _ -> assert false
9494+9595+let after ?set = function
9696+ | Node { parent = Leaf ; _ } | Leaf -> Leaf
9797+ | Node n as parent ->
9898+ raw_invalidate parent;
9999+ let node = make_node set ~left:Leaf ~right:n.right ~parent in
100100+ n.right <- node;
101101+ node
102102+ | Root _ -> assert false
103103+104104+let get = function
105105+ | Node { binding = Bound { value ; _ } ; _ } -> Some value
106106+ | Leaf | Root _ | Node { binding = Unbound ; _ } -> None
107107+108108+let invalidate_binding = function
109109+ | Unbound -> ()
110110+ | Bound b -> b.valid <- false
111111+112112+let set_binding x = function
113113+ | Root _ -> assert false
114114+ | Leaf | Node { parent = Leaf; _ } -> ()
115115+ | Node n as t ->
116116+ raw_invalidate t;
117117+ invalidate_binding n.binding;
118118+ n.binding <- x
119119+120120+let set t value = set_binding (Bound { value; valid = true }) t
121121+let unset t = set_binding Unbound t
122122+123123+let is_bound = function
124124+ | Leaf | Node { parent = Leaf; _ } -> false
125125+ | Root _ | Node _ -> true
126126+127127+let rec join left = function
128128+ | Root _ | Leaf -> assert false
129129+ | Node ({ left = Leaf; _ } as n) as self ->
130130+ n.left <- left;
131131+ set_parent left ~parent:self;
132132+ self
133133+ | Node node ->
134134+ join left node.left
135135+136136+let remove = function
137137+ | Root _ | Leaf | Node {parent = Leaf; _} -> ()
138138+ | Node ({left; right; parent; _} as n) as t ->
139139+ invalidate_binding n.binding;
140140+ n.left <- Leaf;
141141+ n.right <- Leaf;
142142+ n.parent <- Leaf;
143143+ n.binding <- Unbound;
144144+ n.version <- max_int;
145145+ let join, invalid = match left, right with
146146+ | Leaf, other | other, Leaf -> (other, parent)
147147+ | _ -> (right, join left right)
148148+ in
149149+ reparent ~parent ~oldchild:t ~newchild:join;
150150+ set_parent join ~parent;
151151+ raw_invalidate invalid
152152+153153+let rec clear = function
154154+ | Leaf -> ()
155155+ | Node ({left; right; _} as n) ->
156156+ invalidate_binding n.binding;
157157+ n.left <- Leaf;
158158+ n.right <- Leaf;
159159+ n.parent <- Leaf;
160160+ n.binding <- Unbound;
161161+ n.version <- max_int;
162162+ clear left;
163163+ clear right
164164+ | Root r as root ->
165165+ let child = r.child in
166166+ r.child <- Leaf;
167167+ clear child;
168168+ raw_invalidate root
169169+170170+(* Tree balancing *)
171171+172172+let size = function
173173+ | Node node ->
174174+ assert (node.size <> 0);
175175+ node.size
176176+ | Leaf -> 0
177177+ | Root _ -> assert false
178178+179179+(** [smaller_ell smin smax] iff
180180+ - [smin] is less than [smax]
181181+ - [smin] and [smax] differs by less than two magnitude orders, i.e
182182+ msbs(smin) >= msbs(smax) - 1
183183+ where msbs is the index of the most significant bit set *)
184184+let smaller_ell smin smax = (smin < smax) && ((smin land smax) lsl 1 < smax)
185185+186186+(** [disbalanced smin smax] check if two sub-trees of size [smin] and [smax],
187187+ are disbalanczed. That is, msbs(smin) < msbs(smax) - 1 *)
188188+let disbalanced smin smax = smaller_ell smin (smax lsr 1)
189189+190190+let reparent ~parent ~oldchild ~newchild =
191191+ match parent with
192192+ | Root r ->
193193+ assert (r.child == oldchild);
194194+ r.child <- newchild;
195195+ | Node n when n.left == oldchild ->
196196+ n.left <- newchild
197197+ | Node n when n.right == oldchild ->
198198+ n.right <- newchild
199199+ | Leaf | Node _ -> assert false
200200+201201+let rec rot_left version = function
202202+ | Node ({ right = (Node rn) as r; _} as sn) as s ->
203203+ let parent = sn.parent in
204204+ let rl = match rn.left with
205205+ | Root _ -> assert false
206206+ | Leaf -> Leaf
207207+ | (Node rln) as rl ->
208208+ rln.parent <- s;
209209+ rl
210210+ in
211211+ rn.left <- s;
212212+ sn.right <- rl;
213213+ sn.parent <- r;
214214+ rn.parent <- parent;
215215+ reparent ~parent ~oldchild:s ~newchild:r;
216216+ ignore (balance version s);
217217+ balance version r
218218+ | _ -> assert false
219219+220220+and rot_right version = function
221221+ | Node ({ left = (Node ln) as l; _} as sn) as s ->
222222+ let parent = sn.parent in
223223+ let lr = match ln.right with
224224+ | Root _ -> assert false
225225+ | Leaf -> Leaf
226226+ | (Node lrn) as lr ->
227227+ lrn.parent <- s;
228228+ lr
229229+ in
230230+ ln.right <- s;
231231+ sn.left <- lr;
232232+ sn.parent <- l;
233233+ ln.parent <- parent;
234234+ reparent ~parent ~oldchild:s ~newchild:l;
235235+ ignore (balance version s);
236236+ balance version l
237237+ | _ -> assert false
238238+239239+and inc_left version = function
240240+ | Root _ | Leaf -> assert false
241241+ | Node {right; _} as self ->
242242+ begin match right with
243243+ | Node rn when smaller_ell (size rn.right) (size rn.left) ->
244244+ ignore (rot_right version right)
245245+ | _ -> ()
246246+ end;
247247+ rot_left version self
248248+249249+and inc_right version = function
250250+ | Root _ | Leaf -> assert false
251251+ | Node {left; _} as self ->
252252+ begin match left with
253253+ | Node ln when smaller_ell (size ln.left) (size ln.right) ->
254254+ ignore (rot_left version left)
255255+ | _ -> ()
256256+ end;
257257+ rot_right version self
258258+259259+and balance version = function
260260+ | Root _ | Leaf -> assert false
261261+ | Node node as self ->
262262+ let sl = size node.left and sr = size node.right in
263263+ if sl < sr then (
264264+ if disbalanced sl sr
265265+ then inc_left version self
266266+ else (node.version <- version; node.size <- 1 + sl + sr; self)
267267+ ) else (
268268+ if disbalanced sr sl
269269+ then inc_right version self
270270+ else (node.version <- version; node.size <- 1 + sl + sr; self)
271271+ )
272272+273273+let rec compute_sub_size version = function
274274+ | Root _ -> ()
275275+ | Leaf -> ()
276276+ | Node node as self ->
277277+ if node.size = 0 then
278278+ match node.left with
279279+ | Node {size = 0; _} ->
280280+ compute_sub_size version node.left
281281+ | _ ->
282282+ match node.right with
283283+ | Node {size = 0; _} ->
284284+ compute_sub_size version node.right
285285+ | _ ->
286286+ let parent = node.parent in
287287+ ignore (balance version self);
288288+ compute_sub_size version parent
289289+290290+let rec reset_version version = function
291291+ | Leaf -> ()
292292+ | Node n ->
293293+ n.version <- version;
294294+ reset_version version n.left;
295295+ reset_version version n.right
296296+ | Root _ -> assert false
297297+298298+let rebalance = function
299299+ | Root r ->
300300+ begin match r.child with
301301+ | Node { size = 0; _ } ->
302302+ let version = succ r.version in
303303+ let version =
304304+ if version = max_int then (
305305+ r.generation <- ref ();
306306+ reset_version 0 r.child;
307307+ 0
308308+ )
309309+ else version
310310+ in
311311+ r.version <- version;
312312+ compute_sub_size version r.child;
313313+ version
314314+ | Node _ | Leaf -> r.version
315315+ | Root _ -> assert false
316316+ end
317317+ | _ -> assert false
318318+319319+let plus (zero, plus) x y =
320320+ if x == zero then y
321321+ else if y == zero then x
322322+ else plus x y
323323+324324+type ('a, 'b) reduction_tree =
325325+ | Red_leaf
326326+ | Red_node of {
327327+ cell: 'a row;
328328+ binding: 'a binding;
329329+ reduction: 'b;
330330+ aggregate: 'b;
331331+ left : ('a, 'b) reduction_tree;
332332+ right : ('a, 'b) reduction_tree;
333333+ }
334334+335335+type ('a, 'b) reduction = {
336336+ mutable version: int;
337337+ source: 'a tree;
338338+ mutable result : ('a, 'b) reduction_tree;
339339+ mutable generation: unit ref;
340340+ mapper: 'a row -> 'a -> 'b;
341341+ monoid: 'b Lwd_utils.monoid;
342342+}
343343+344344+345345+let extract_bindings tree =
346346+ let rec aux acc = function
347347+ | Red_leaf -> acc
348348+ | Red_node rnode ->
349349+ let acc = aux acc rnode.right in
350350+ let acc = match rnode.binding with
351351+ | Unbound -> acc
352352+ | Bound { valid = false; _ } -> acc
353353+ | _ -> (rnode.binding, rnode.reduction) :: acc
354354+ in
355355+ aux acc rnode.left
356356+ in
357357+ aux [] tree
358358+359359+let full_rebuild red tree =
360360+ let bindings = ref (extract_bindings red.result) in
361361+ let rec aux = function
362362+ | Node node as cell ->
363363+ let left = aux node.left in
364364+ let reduction =
365365+ match node.binding, !bindings with
366366+ | Unbound, _ -> fst red.monoid
367367+ | binding, ((binding', reduction) :: bindings')
368368+ when binding == binding' ->
369369+ bindings := bindings';
370370+ reduction
371371+ | Bound b, _ -> assert b.valid; red.mapper cell b.value
372372+ in
373373+ let right = aux node.right in
374374+ let aggregate = match left with
375375+ | Red_leaf -> reduction
376376+ | Red_node r -> plus red.monoid r.aggregate reduction
377377+ in
378378+ let aggregate = match right with
379379+ | Red_leaf -> aggregate
380380+ | Red_node r -> plus red.monoid aggregate r.aggregate
381381+ in
382382+ Red_node {
383383+ cell;
384384+ binding = node.binding;
385385+ reduction;
386386+ aggregate;
387387+ left;
388388+ right;
389389+ }
390390+ | Leaf -> Red_leaf
391391+ | Root _ -> assert false
392392+ in
393393+ let result = aux tree in
394394+ assert (!bindings = []);
395395+ result
396396+397397+let extract_fringe version tree =
398398+ let rec aux acc = function
399399+ | Red_leaf -> acc
400400+ | Red_node rnode as tree ->
401401+ match rnode.cell with
402402+ | Node node when node.version <= version -> tree :: acc
403403+ | _ ->
404404+ let acc = aux acc rnode.right in
405405+ let acc = match rnode.binding with
406406+ | Unbound -> acc
407407+ | Bound { valid = false; _ } -> acc
408408+ | _ -> tree :: acc
409409+ in
410410+ aux acc rnode.left
411411+ in
412412+ aux [] tree
413413+414414+let incremental_rebuild red version tree =
415415+ let fringe = ref (extract_fringe version red.result) in
416416+ let rec aux = function
417417+ | Node node as cell when node.version <= version ->
418418+ begin match !fringe with
419419+ | (Red_node rnode as reduction) :: fringe' ->
420420+ assert (rnode.cell == cell);
421421+ fringe := fringe';
422422+ reduction
423423+ | _ -> assert false
424424+ end
425425+ | Node node as cell ->
426426+ let left = aux node.left in
427427+ let reduction =
428428+ match node.binding, !fringe with
429429+ | Unbound, _ -> fst red.monoid
430430+ | binding, (Red_node rnode :: fringe')
431431+ when binding == rnode.binding ->
432432+ fringe := fringe';
433433+ rnode.reduction
434434+ | Bound b, _ ->
435435+ assert b.valid; red.mapper cell b.value
436436+ in
437437+ let right = aux node.right in
438438+ let aggregate = match left with
439439+ | Red_leaf -> reduction
440440+ | Red_node r -> plus red.monoid r.aggregate reduction
441441+ in
442442+ let aggregate = match right with
443443+ | Red_leaf -> aggregate
444444+ | Red_node r -> plus red.monoid aggregate r.aggregate
445445+ in
446446+ Red_node {
447447+ cell;
448448+ binding = node.binding;
449449+ reduction;
450450+ aggregate;
451451+ left;
452452+ right;
453453+ }
454454+ | Root _ | Leaf -> Red_leaf
455455+ in
456456+ let result = aux tree in
457457+ assert (!fringe = []);
458458+ result
459459+460460+let eval red =
461461+ match red.source with
462462+ | Leaf | Node _ -> assert false
463463+ | Root root ->
464464+ let version = rebalance red.source in
465465+ if true then (
466466+ if red.generation != root.generation then (
467467+ red.generation <- root.generation;
468468+ red.result <- full_rebuild red root.child;
469469+ ) else (
470470+ red.result <- incremental_rebuild red red.version root.child
471471+ );
472472+ ) else (
473473+ red.result <- full_rebuild red root.child;
474474+ );
475475+ red.version <- version;
476476+ match red.result with
477477+ | Red_leaf -> fst red.monoid
478478+ | Red_node r -> r.aggregate
479479+480480+let opaque : 'a Lwd.prim -> Obj.t Lwd.prim = Obj.magic
481481+482482+let map_reduce mapper monoid source =
483483+ let reduction = {
484484+ source; mapper; monoid;
485485+ result = Red_leaf;
486486+ generation = not_origin;
487487+ version = 0;
488488+ } in
489489+ let prim = Lwd.prim
490490+ ~acquire:(fun self ->
491491+ match reduction.source with
492492+ | Leaf | Node _ -> assert false
493493+ | Root root ->
494494+ root.on_invalidate <- opaque self :: root.on_invalidate;
495495+ reduction
496496+ )
497497+ ~release:(fun self reduction ->
498498+ match reduction.source with
499499+ | Leaf | Node _ -> assert false
500500+ | Root root ->
501501+ root.on_invalidate <-
502502+ List.filter ((!=) (opaque self)) root.on_invalidate
503503+ )
504504+ in
505505+ Lwd.map ~f:eval (Lwd.get_prim prim)
506506+507507+let reduce monoid source = map_reduce (fun _ x -> x) monoid source
508508+509509+let rec iter f = function
510510+ | Leaf -> ()
511511+ | Node t ->
512512+ iter f t.left;
513513+ begin match t.binding with
514514+ | Bound x -> f x.value
515515+ | Unbound -> ()
516516+ end;
517517+ iter f t.right
518518+ | Root t ->
519519+ iter f t.child
520520+521521+let rec left_most : 'a row -> 'a row option = function
522522+ | Root _ -> assert false
523523+ | Leaf -> None
524524+ | Node n as self ->
525525+ match left_most n.left with
526526+ | Some _ as x -> x
527527+ | None -> Some self
528528+529529+let rec right_most : 'a row -> 'a row option = function
530530+ | Root _ -> assert false
531531+ | Leaf -> None
532532+ | Node n as self ->
533533+ match right_most n.right with
534534+ | Some _ as x -> x
535535+ | None -> Some self
536536+537537+let first : 'a t -> 'a row option = function
538538+ | Leaf | Node _ -> assert false
539539+ | Root root -> left_most root.child
540540+541541+let last : 'a t -> 'a row option = function
542542+ | Leaf | Node _ -> assert false
543543+ | Root root -> right_most root.child
544544+545545+let next : 'a row -> 'a row option = function
546546+ | Root _ -> assert false
547547+ | Leaf -> None
548548+ | Node n as self ->
549549+ match left_most n.right with
550550+ | Some _ as x -> x
551551+ | None ->
552552+ let rec walk_root self = function
553553+ | Leaf -> assert false
554554+ | Root _ -> None
555555+ | Node n' as parent ->
556556+ if n'.left == self then Some parent else (
557557+ assert (n'.right == self);
558558+ walk_root parent n'.parent
559559+ )
560560+ in
561561+ walk_root self n.parent
562562+563563+let prev : 'a row -> 'a row option = function
564564+ | Root _ -> assert false
565565+ | Leaf -> None
566566+ | Node n as self ->
567567+ match right_most n.left with
568568+ | Some _ as x -> x
569569+ | None ->
570570+ let rec walk_root self = function
571571+ | Leaf -> assert false
572572+ | Root _ -> None
573573+ | Node n' as parent ->
574574+ if n'.right == self then Some parent else (
575575+ assert (n'.left == self);
576576+ walk_root parent n'.parent
577577+ )
578578+ in
579579+ walk_root self n.parent
+102
forks/lwd/lib/lwd/lwd_table.mli
···11+(** {1 Table manipulation}
22+33+ [Lwd_table] is an ordered collection with an impure interface.
44+ It is designed to be efficient in an interactive setting.
55+66+ The interface mimics the one of a doubly-linked lists: from a node, called
77+ row, you can iterate backward and forward, insert and delete other nodes,
88+ and change the value it is bound to.
99+1010+ The sequence of nodes can be observed by map/reduce operations, that will
1111+ be recomputed efficiently when sequence changes.
1212+*)
1313+1414+type 'a t
1515+type 'a row
1616+(** The type of tables *)
1717+1818+val make : unit -> 'a t
1919+(** Create a new table *)
2020+2121+(** {2 Inserting rows} *)
2222+2323+val prepend : ?set:'a -> 'a t -> 'a row
2424+(** Insert and return a new row at the start of a table.
2525+ It can be optionnally initialized to the value of [set]. *)
2626+2727+val append : ?set:'a -> 'a t -> 'a row
2828+(** Insert and return a new row at the end of a table.
2929+ It can be optionnally initialized to the value of [set]. *)
3030+3131+val prepend' : 'a t -> 'a -> unit
3232+(* Insert a new initialized row at start of a table *)
3333+3434+val append' : 'a t -> 'a -> unit
3535+(* Insert a new initialized row at end of a table *)
3636+3737+val before : ?set:'a -> 'a row -> 'a row
3838+(** Insert and return a new row just before an existing row.
3939+ It can be optionnally initialized to the value of [set].
4040+4141+ If the input row is unbound ([is_bound] returns false), the returned row is
4242+ too.
4343+*)
4444+4545+val after : ?set:'a -> 'a row -> 'a row
4646+(** Insert and return a new row just after an existing row.
4747+ It can be optionnally initialized to the value of [set].
4848+4949+ If the input row is unbound ([is_bound] returns false), the returned row is
5050+ too.
5151+*)
5252+5353+(** {2 Iterating over rows} *)
5454+5555+val first : 'a t -> 'a row option
5656+(** Returns the first row of a table, or [None] if the table is empty *)
5757+5858+val last : 'a t -> 'a row option
5959+(** Returns the last row of a table, or [None] if the table is empty *)
6060+6161+val next : 'a row -> 'a row option
6262+(** Returns the row next to another one, or [None] if the input row is unbound
6363+ or is the last row *)
6464+6565+val prev : 'a row -> 'a row option
6666+(** Returns the row just before another one, or [None] if the input row is
6767+ unbound or is the first row *)
6868+6969+(** {2 Accessing and changing row contents} *)
7070+7171+val get : 'a row -> 'a option
7272+(** Get the value associated with a row, if any, or [None] if the row is
7373+ unbound *)
7474+7575+val set : 'a row -> 'a -> unit
7676+(** Set the value associated with a row, or do nothing if the row is unbound *)
7777+7878+val unset : 'a row -> unit
7979+(** Unset the value associated with a row *)
8080+8181+(** {2 Removing rows} *)
8282+8383+val is_bound : 'a row -> bool
8484+(** Returns [true] iff the row is bound in a table (it has not beem [remove]d
8585+ yet, the table has not been [clear]ed) *)
8686+8787+val remove : 'a row -> unit
8888+(** [remove] a row from its table, [is_bound] will be [true] after that *)
8989+9090+val clear : 'a t -> unit
9191+(** Remove all rows from a table *)
9292+9393+(** {2 Observing table contents} *)
9494+9595+val reduce : 'a Lwd_utils.monoid -> 'a t -> 'a Lwd.t
9696+(** Observe the content of a table by reducing it with a monoid *)
9797+9898+val map_reduce : ('a row -> 'a -> 'b) -> 'b Lwd_utils.monoid -> 'a t -> 'b Lwd.t
9999+(** Observe the content of a table by mapping and reducing it *)
100100+101101+val iter : ('a -> unit) -> 'a t -> unit
102102+(** Immediate, non reactive, iteration over elements of a table *)
+474
forks/lwd/lib/lwd/lwd_trace_debug.ml
···11+type 'a t =
22+ | Pure of 'a
33+ | Impure : {
44+ mutable value : 'a option;
55+ mutable trace : trace;
66+ mutable trace_idx : trace_idx;
77+ desc: 'a desc;
88+ } -> 'a t
99+ | Root : {
1010+ mutable on_invalidate : 'a -> unit;
1111+ mutable value : 'a option;
1212+ child : 'a t;
1313+ mutable trace_idx : trace_idx;
1414+ } -> 'a t
1515+1616+and _ desc =
1717+ | Map : 'a t * ('a -> 'b) -> 'b desc
1818+ | Map2 : 'a t * 'b t * ('a -> 'b -> 'c) -> 'c desc
1919+ | Pair : 'a t * 'b t -> ('a * 'b) desc
2020+ | App : ('a -> 'b) t * 'a t -> 'b desc
2121+ | Bind : { child : 'a t; map : 'a -> 'b t;
2222+ mutable intermediate : 'b t option } -> 'b desc
2323+ | Var : { mutable binding : 'a } -> 'a desc
2424+ | Prim : { acquire : unit -> 'a;
2525+ release : 'a -> unit;
2626+ mutable acquired : 'a option } -> 'a desc
2727+2828+and trace =
2929+ | T0
3030+ (*| T1 : _ t -> trace
3131+ | T2 : _ t * _ t -> trace
3232+ | T3 : _ t * _ t * _ t -> trace
3333+ | T4 : _ t * _ t * _ t * _ t -> trace*)
3434+ | Tn : { mutable active : int; mutable count : int;
3535+ mutable entries : Obj.t t array } -> trace
3636+3737+and trace_idx =
3838+ | I0
3939+ | I1 : { mutable idx : int ;
4040+ obj : 'a t;
4141+ mutable next : trace_idx } -> trace_idx
4242+4343+(* Basic combinators *)
4444+let return x = Pure x
4545+let pure x = Pure x
4646+4747+let dummy = Pure (Obj.repr ())
4848+4949+let impure desc =
5050+ Impure { value = None; trace = T0; desc; trace_idx = I0 }
5151+5252+let map f x = impure (Map (x, f))
5353+let map2 f x y = impure (Map2 (x, y, f))
5454+let map' x f = impure (Map (x, f))
5555+let map2' x y f = impure (Map2 (x, y, f))
5656+let pair x y = impure (Pair (x, y))
5757+let app f x = impure (App (f, x))
5858+let bind child map = impure (Bind { child; map; intermediate = None })
5959+let id x = x
6060+let join child = impure (Bind { child; map = id; intermediate = None })
6161+6262+(* Management of trace indexes *)
6363+6464+external t_equal : _ t -> _ t -> bool = "%eq"
6565+external obj_t : 'a t -> Obj.t t = "%identity"
6666+6767+let debug_trace_idx (type a) (self : a t) idx =
6868+ let rec gather = function
6969+ | I0 -> []
7070+ | I1 {obj = obj1; next = I1 {obj = obj2; _}; _}
7171+ when t_equal obj1 obj2 && (
7272+ let self = match self with
7373+ | Pure _ | Root _ -> assert false
7474+ | Impure t ->
7575+ match t.desc with
7676+ | Map (t1, _) ->
7777+ Printf.sprintf "Map (%x, _)" (Obj.magic t1)
7878+ | Map2 (t1, t2, _) ->
7979+ Printf.sprintf "Map2 (%x, %x, _)" (Obj.magic t1) (Obj.magic t2)
8080+ | Pair (t1, t2) ->
8181+ Printf.sprintf "Pair (%x, %x)" (Obj.magic t1) (Obj.magic t2)
8282+ | App (t1, t2) ->
8383+ Printf.sprintf "App (%x, %x)" (Obj.magic t1) (Obj.magic t2)
8484+ | Bind {child; intermediate = None; _} ->
8585+ Printf.sprintf "Bind (%x)" (Obj.magic child)
8686+ | Bind {child; intermediate = Some i; _} ->
8787+ Printf.sprintf "Bind (%x, %x)" (Obj.magic child) (Obj.magic i)
8888+ | Var _ -> "Var _"
8989+ | Prim _ -> "Prim _"
9090+ in
9191+ Printf.eprintf "%x: %s\n" (Obj.magic obj1) self;
9292+ false
9393+ ) -> assert false
9494+ | I1 t ->
9595+ begin match t.obj with
9696+ | Impure {trace = Tn {active; count; entries}; _} ->
9797+ if not (t.idx < count) then (
9898+ prerr_endline
9999+ (Printexc.raw_backtrace_to_string (Printexc.get_callstack 10));
100100+ assert false
101101+ );
102102+ assert (entries.(t.idx) == obj_t self);
103103+ if t.idx > active then (
104104+ match self with
105105+ | Root { value = None; _ } | Impure { value = None; _} -> ()
106106+ | _ -> assert false
107107+ )
108108+ | Impure {trace = T0; _} -> () (* invariant temporary broken, can't do much *)
109109+ | _ ->
110110+ prerr_endline
111111+ (Printexc.raw_backtrace_to_string (Printexc.get_callstack 10));
112112+ assert false
113113+ end;
114114+ Printf.sprintf "%x@%d" (Obj.magic t.obj) t.idx :: gather t.next
115115+ in
116116+ Printf.eprintf "idx : [%s]\n" (String.concat "; " (gather idx));
117117+ idx
118118+119119+let debug_trace = function
120120+ | T0 -> Printf.eprintf "empty trace"
121121+ | Tn tn ->
122122+ Printf.eprintf "trace: {active = %d; count = %d; capacity = %d}\n"
123123+ tn.active tn.count (Array.length tn.entries)
124124+125125+let add_idx obj idx = function
126126+ | Pure _ -> assert false
127127+ | Root t' as self->
128128+ t'.trace_idx <- debug_trace_idx self (I1 { idx; obj; next = t'.trace_idx })
129129+ | Impure t' as self->
130130+ t'.trace_idx <- debug_trace_idx self (I1 { idx; obj; next = t'.trace_idx })
131131+132132+let rec rem_idx obj = function
133133+ | I0 -> assert false
134134+ | I1 t as self ->
135135+ if t_equal t.obj obj
136136+ then (t.idx, t.next)
137137+ else
138138+ let idx, result = rem_idx obj t.next in
139139+ t.next <- result;
140140+ (idx, self)
141141+142142+let rem_idx obj = function
143143+ | Pure _ -> assert false
144144+ | Root t' as self ->
145145+ let idx, trace_idx = rem_idx obj t'.trace_idx in
146146+ t'.trace_idx <- debug_trace_idx self trace_idx; idx
147147+ | Impure t' as self ->
148148+ let idx, trace_idx = rem_idx obj t'.trace_idx in
149149+ t'.trace_idx <- debug_trace_idx self trace_idx; idx
150150+151151+let rec mov_idx obj oldidx newidx = function
152152+ | I0 -> assert false
153153+ | I1 t ->
154154+ if t.idx = oldidx && t_equal t.obj obj
155155+ then t.idx <- newidx
156156+ else mov_idx obj oldidx newidx t.next
157157+158158+let mov_idx obj oldidx newidx = function
159159+ | Pure _ -> assert false
160160+ | Root t' -> mov_idx obj oldidx newidx t'.trace_idx
161161+ | Impure t' -> mov_idx obj oldidx newidx t'.trace_idx
162162+163163+let rec get_idx obj = function
164164+ | I0 -> assert false
165165+ | I1 t ->
166166+ if t_equal t.obj obj
167167+ then t.idx
168168+ else get_idx obj t.next
169169+170170+let get_idx obj = function
171171+ | Pure _ -> assert false
172172+ | Root t' as self -> get_idx obj (debug_trace_idx self t'.trace_idx)
173173+ | Impure t' as self -> get_idx obj (debug_trace_idx self t'.trace_idx)
174174+175175+(* Propagating invalidation *)
176176+let rec invalidate_node : type a . a t -> unit = function
177177+ | Pure _ -> assert false
178178+ | Root { value = None; _ } -> ()
179179+ | Root ({ value = Some x; _ } as t) ->
180180+ t.value <- None;
181181+ t.on_invalidate x
182182+ | Impure t ->
183183+ begin match t.value with
184184+ | None -> ()
185185+ | Some _ ->
186186+ t.value <- None;
187187+ debug_trace t.trace;
188188+ invalidate_trace t.trace
189189+ end
190190+191191+and invalidate_trace = function
192192+ | T0 -> ()
193193+ (*| T1 x -> invalidate_node x
194194+ | T2 (x, y) ->
195195+ invalidate_node x;
196196+ invalidate_node y
197197+ | T3 (x, y, z) ->
198198+ invalidate_node x;
199199+ invalidate_node y;
200200+ invalidate_node z
201201+ | T4 (x, y, z, w) ->
202202+ invalidate_node x;
203203+ invalidate_node y;
204204+ invalidate_node z;
205205+ invalidate_node w*)
206206+ | Tn t ->
207207+ let active = t.active in
208208+ t.active <- 0;
209209+ for i = 0 to active - 1 do
210210+ invalidate_node t.entries.(i)
211211+ done
212212+213213+(* Variables *)
214214+type 'a var = 'a t
215215+let var x = impure (Var {binding = x})
216216+let get x = x
217217+218218+let set vx x =
219219+ match vx with
220220+ | Impure ({desc = Var v; _}) ->
221221+ invalidate_node vx;
222222+ v.binding <- x
223223+ | _ -> assert false
224224+225225+let peek = function
226226+ | Impure ({desc = Var v; _}) -> v.binding
227227+ | _ -> assert false
228228+229229+(* Primitives *)
230230+type 'a prim = 'a t
231231+let prim ~acquire ~release =
232232+ impure (Prim { acquire; release; acquired = None })
233233+let get_prim x = x
234234+let invalidate = invalidate_node
235235+236236+let rec sub_release : type a b . a t -> b t -> unit = fun origin ->
237237+ function
238238+ | Root _ -> assert false
239239+ | Pure _ -> ()
240240+ | Impure t as self ->
241241+ let trace = match t.trace with
242242+ | T0 -> assert false
243243+ (*| T1 x -> assert (t_equal x origin); T0
244244+ | T2 (x, y) ->
245245+ if t_equal x origin then T1 y
246246+ else if t_equal y origin then T1 x
247247+ else assert false
248248+ | T3 (x, y, z) ->
249249+ if t_equal x origin then T2 (y, z)
250250+ else if t_equal y origin then T2 (x, z)
251251+ else if t_equal z origin then T2 (x, y)
252252+ else assert false
253253+ | T4 (x, y, z, w) ->
254254+ if t_equal x origin then T3 (y, z, w)
255255+ else if t_equal y origin then T3 (x, z, w)
256256+ else if t_equal z origin then T3 (x, y, w)
257257+ else assert false*)
258258+ | Tn tn as trace ->
259259+ let revidx = rem_idx self origin in
260260+ assert (t_equal tn.entries.(revidx) origin);
261261+ let count = tn.count - 1 in
262262+ tn.count <- count;
263263+ if revidx < count then (
264264+ let obj = tn.entries.(count) in
265265+ tn.entries.(revidx) <- obj;
266266+ mov_idx self count revidx obj
267267+ );
268268+ tn.entries.(count) <- dummy;
269269+ if tn.active > count then tn.active <- count;
270270+ (*if count = 4 then (
271271+ let a = tn.entries.(0) and b = tn.entries.(1) in
272272+ let c = tn.entries.(2) and d = tn.entries.(3) in
273273+ ignore (rem_idx self a : int);
274274+ ignore (rem_idx self b : int);
275275+ ignore (rem_idx self c : int);
276276+ ignore (rem_idx self d : int);
277277+ T4 (a, b, c, d)*)
278278+ if count = 0 then (
279279+ T0
280280+ ) else
281281+ let len = Array.length tn.entries in
282282+ if count <= len lsr 2 then
283283+ Tn { active = tn.active; count = tn.count;
284284+ entries = Array.sub tn.entries 0 (len lsr 1) }
285285+ else
286286+ trace
287287+ in
288288+ t.trace <- trace;
289289+ match trace with
290290+ | T0 ->
291291+ t.value <- None;
292292+ begin match t.desc with
293293+ | Map (x, _) -> sub_release self x
294294+ | Map2 (x, y, _) ->
295295+ sub_release self x;
296296+ sub_release self y
297297+ | Pair (x, y) ->
298298+ sub_release self x;
299299+ sub_release self y
300300+ | App (x, y) ->
301301+ sub_release self x;
302302+ sub_release self y
303303+ | Bind ({ child; intermediate; map = _ } as t) ->
304304+ sub_release self child;
305305+ begin match intermediate with
306306+ | None -> ()
307307+ | Some child' ->
308308+ t.intermediate <- None;
309309+ sub_release self child'
310310+ end
311311+ | Var _ -> ()
312312+ | Prim t ->
313313+ let x = match t.acquired with None -> assert false | Some x -> x in
314314+ t.acquired <- None;
315315+ t.release x
316316+ end
317317+ | _ -> ()
318318+319319+let rec sub_acquire : type a b . a t -> b t -> unit = fun origin ->
320320+ function
321321+ | Root _ -> assert false
322322+ | Pure _ -> ()
323323+ | Impure t as self ->
324324+ let acquire = match t.trace with T0 -> true | _ -> false in
325325+ let trace = match t.trace with
326326+ (*| T0 -> T1 origin
327327+ | T1 x -> T2 (origin, x)
328328+ | T2 (x, y) -> T3 (origin, x, y)
329329+ | T3 (x, y, z) -> T4 (origin, x, y, z)
330330+ | T4 (x, y, z, w) ->
331331+ let obj = obj_t origin in
332332+ let entries =
333333+ [| obj_t x; obj_t y; obj_t z; obj_t w; obj; dummy; dummy; dummy |]
334334+ in
335335+ for i = 0 to 4 do add_idx self i entries.(i) done;
336336+ Tn { active = 5; count = 5; entries }*)
337337+ | T0 ->
338338+ let obj = obj_t origin in
339339+ let entries = [| obj; dummy; dummy; dummy |] in
340340+ add_idx self 0 obj;
341341+ Tn { active = 1; count = 1; entries }
342342+ | Tn tn as trace ->
343343+ let index = tn.count in
344344+ let entries, trace =
345345+ if index < Array.length tn.entries then (
346346+ tn.count <- tn.count + 1;
347347+ (tn.entries, trace)
348348+ ) else (
349349+ let entries = Array.make (index * 2) dummy in
350350+ Array.blit tn.entries 0 entries 0 index;
351351+ (entries, Tn { active = tn.active; count = index + 1; entries })
352352+ )
353353+ in
354354+ let obj = obj_t origin in
355355+ entries.(index) <- obj;
356356+ add_idx self index obj;
357357+ trace
358358+ in
359359+ t.trace <- trace;
360360+ if acquire then
361361+ match t.desc with
362362+ | Map (x, _) -> sub_acquire self x
363363+ | Map2 (x, y, _) ->
364364+ sub_acquire self x;
365365+ sub_acquire self y
366366+ | Pair (x, y) ->
367367+ sub_acquire self x;
368368+ sub_acquire self y
369369+ | App (x, y) ->
370370+ sub_acquire self x;
371371+ sub_acquire self y
372372+ | Bind { child; intermediate; map = _ } ->
373373+ sub_acquire self child;
374374+ begin match intermediate with
375375+ | None -> ()
376376+ | Some _ -> assert false
377377+ end
378378+ | Var _ -> ()
379379+ | Prim t ->
380380+ begin match t.acquired with
381381+ | None -> t.acquired <- Some (t.acquire ())
382382+ | Some _ -> ()
383383+ end
384384+385385+let rec sub_sample : type a b . a t -> b t -> b = fun origin ->
386386+ function
387387+ | Root _ -> assert false
388388+ | Pure x -> x
389389+ | Impure t as self ->
390390+ begin match t.trace with
391391+ | Tn tn ->
392392+ let idx = get_idx self origin in
393393+ let active = tn.active in
394394+ if idx >= active then
395395+ tn.active <- active + 1;
396396+ if idx > active then (
397397+ let old = tn.entries.(active) in
398398+ tn.entries.(idx) <- old;
399399+ tn.entries.(active) <- obj_t origin;
400400+ mov_idx self active idx old;
401401+ mov_idx self idx active origin
402402+ )
403403+ | _ -> ()
404404+ end;
405405+ match t.value with
406406+ | Some value -> value
407407+ | None ->
408408+ let value : b = match t.desc with
409409+ | Map (x, f) -> f (sub_sample self x)
410410+ | Map2 (x, y, f) -> f (sub_sample self x) (sub_sample self y)
411411+ | Pair (x, y) -> (sub_sample self x, sub_sample self y)
412412+ | App (f, x) -> (sub_sample self f) (sub_sample self x)
413413+ | Bind x ->
414414+ let old_intermediate = x.intermediate in
415415+ let intermediate = x.map (sub_sample self x.child) in
416416+ x.intermediate <- Some intermediate;
417417+ sub_acquire self intermediate;
418418+ let result = sub_sample self intermediate in
419419+ begin match old_intermediate with
420420+ | Some x' -> sub_release self x'
421421+ | None -> ()
422422+ end;
423423+ result
424424+ | Var x -> x.binding
425425+ | Prim t ->
426426+ begin match t.acquired with
427427+ | Some x -> x
428428+ | None -> assert false
429429+ end
430430+ in
431431+ t.value <- Some value;
432432+ value
433433+434434+type 'a root = 'a t
435435+436436+let observe ?(on_invalidate=ignore) child =
437437+ let root = Root { child; value = None; on_invalidate; trace_idx = I0 } in
438438+ sub_acquire root child;
439439+ root
440440+441441+let sample = function
442442+ | Pure _ | Impure _ -> assert false
443443+ | Root t as self ->
444444+ match t.value with
445445+ | Some value -> value
446446+ | None ->
447447+ let value = sub_sample self t.child in
448448+ t.value <- Some value;
449449+ value
450450+451451+let is_damaged = function
452452+ | Pure _ | Impure _ -> assert false
453453+ | Root { value = None ; _ } -> true
454454+ | Root { value = Some _ ; _ } -> false
455455+456456+let release = function
457457+ | Pure _ | Impure _ -> assert false
458458+ | Root t as self ->
459459+ begin match t.value with
460460+ | None -> ()
461461+ | Some _ -> t.value <- None;
462462+ end;
463463+ sub_release self t.child
464464+465465+let set_on_invalidate x f =
466466+ match x with
467467+ | Pure _ | Impure _ -> assert false
468468+ | Root t -> t.on_invalidate <- f
469469+470470+module Infix = struct
471471+ let (let$) = bind
472472+ let (and$) = pair
473473+ let ($=) = set
474474+end
+76
forks/lwd/lib/lwd/lwd_utils.ml
···11+22+type 'a monoid = 'a * ('a -> 'a -> 'a)
33+44+let lift_monoid (zero, plus) =
55+ (Lwd.return zero, Lwd.map2 ~f:plus)
66+77+let map_reduce inj (zero, plus) items =
88+ let rec cons_monoid c xs v =
99+ match xs with
1010+ | (c', v') :: xs when c = c' ->
1111+ cons_monoid (c + 1) xs (plus v' v)
1212+ | xs -> (c, v) :: xs
1313+ in
1414+ let cons_monoid xs v = cons_monoid 0 xs (inj v) in
1515+ match List.fold_left cons_monoid [] items with
1616+ | [] -> zero
1717+ | (_,x) :: xs ->
1818+ List.fold_left (fun acc (_, v) -> plus v acc) x xs
1919+2020+let reduce monoid items = map_reduce (fun x -> x) monoid items
2121+2222+let rec cons_lwd_monoid plus c xs v =
2323+ match xs with
2424+ | (c', v') :: xs when c = c' ->
2525+ cons_lwd_monoid plus (c + 1) xs (Lwd.map2 ~f:plus v' v)
2626+ | xs -> (c, v) :: xs
2727+2828+let pack (zero, plus) items =
2929+ match List.fold_left (cons_lwd_monoid plus 0) [] items with
3030+ | [] -> Lwd.return zero
3131+ | (_,x) :: xs ->
3232+ List.fold_left (fun acc (_, v) -> Lwd.map2 ~f:plus v acc) x xs
3333+3434+let pack_seq (zero, plus) items =
3535+ match Seq.fold_left (cons_lwd_monoid plus 0) [] items with
3636+ | [] -> Lwd.return zero
3737+ | (_,x) :: xs ->
3838+ List.fold_left (fun acc (_, v) -> Lwd.map2 ~f:plus v acc) x xs
3939+4040+let rec map_l (f:'a -> 'b Lwd.t) (l:'a list) : 'b list Lwd.t =
4141+ match l with
4242+ | [] -> Lwd.return []
4343+ | x :: tl -> Lwd.map2 ~f:List.cons (f x) (map_l f tl)
4444+4545+let flatten_l (l:'a Lwd.t list) : 'a list Lwd.t =
4646+ map_l (fun x->x) l
4747+4848+(** {1 Miscellaneous functions}
4949+5050+ I don't know where to put these, but they are useful, especially for
5151+ UI-related computations.
5252+*)
5353+5454+let mini a b : int = if b < a then b else a
5555+5656+let maxi a b : int = if b > a then b else a
5757+5858+let clampi x ~min ~max : int =
5959+ if x < min then
6060+ min
6161+ else if x > max then
6262+ max
6363+ else
6464+ x
6565+6666+let minf a b : float = if b < a then b else a
6767+6868+let maxf a b : float = if b > a then b else a
6969+7070+let clampf x ~min ~max : float =
7171+ if x < min then
7272+ min
7373+ else if x > max then
7474+ max
7575+ else
7676+ x
+62
forks/lwd/lib/lwd/lwd_utils.mli
···11+type 'a monoid = 'a * ('a -> 'a -> 'a)
22+(** A monoid, defined by a default element and an associative operation *)
33+44+val lift_monoid : 'a monoid -> 'a Lwd.t monoid
55+(** Use a monoid inside [Lwd] *)
66+77+(** {1 List reduction functions}
88+99+ All reductions are balanced, relying on operator associativity.
1010+1111+ [fold_left] would compute a chain like:
1212+ [fold f [a; b; c; d] = f a (f b (f c d)]
1313+1414+ [reduce] uses tree-shaped computations like:
1515+ [reduce f [a; b; c; d] = f (f a b) (f c d)]
1616+1717+ The depth of the computation grows in O(log n) where n is the length of the
1818+ input sequence.
1919+*)
2020+2121+val pack : 'a monoid -> 'a Lwd.t list -> 'a Lwd.t
2222+(** Reduce a list of elements in [Lwd] monad *)
2323+2424+val pack_seq : 'a monoid -> 'a Lwd.t Seq.t -> 'a Lwd.t
2525+(** Reduce an (OCaml) [Seq.t] with a monoid *)
2626+2727+val reduce : 'a monoid -> 'a list -> 'a
2828+(** Reduce a list with a monoid **)
2929+3030+val map_reduce : ('a -> 'b) -> 'b monoid -> 'a list -> 'b
3131+(** Map and reduce a list with a monoid **)
3232+3333+(** {1 Other Lwd list functions} *)
3434+3535+val map_l : ('a -> 'b Lwd.t) -> 'a list -> 'b list Lwd.t
3636+3737+val flatten_l : 'a Lwd.t list -> 'a list Lwd.t
3838+(** Commute [Lwd] and [list] *)
3939+4040+(** {1 Miscellaneous functions}
4141+4242+ I don't know where to put these, but they are useful, especially for
4343+ UI-related computations.
4444+*)
4545+4646+val mini : int -> int -> int
4747+(** Minimum of two integers *)
4848+4949+val maxi : int -> int -> int
5050+(** Maximum of two integers *)
5151+5252+val clampi : int -> min:int -> max:int -> int
5353+(** Clamp an integer between two bounds. *)
5454+5555+val minf : float -> float -> float
5656+(** Minimum of two floats *)
5757+5858+val maxf : float -> float -> float
5959+(** Maximum of two floats *)
6060+6161+val clampf : float -> min:float -> max:float -> float
6262+(** Clamp a float between two bounds. *)
+39
forks/lwd/lib/lwd/mutex_backend.ml
···11+(** Backend selection for mutex implementations. *)
22+33+module type MUTEX = sig
44+ include module type of Mutex
55+ val lock_all : t list -> bool
66+end
77+88+module Stdlib : MUTEX = struct
99+ include Mutex
1010+1111+ let lock_all mutexes =
1212+ let rec try_lock_all acc = function
1313+ | [] ->
1414+ (* All mutexes acquired successfully *)
1515+ true
1616+ | mutex :: rest ->
1717+ if try_lock mutex then
1818+ try_lock_all (mutex :: acc) rest
1919+ else begin
2020+ (* Failed to acquire current mutex, release all previously acquired ones *)
2121+ List.iter unlock acc;
2222+ false
2323+ end
2424+ in
2525+ try_lock_all [] mutexes
2626+end
2727+2828+(* Picos implementation - only available if picos is linked *)
2929+module Picos : MUTEX = struct
3030+ (* This is a placeholder implementation that will be replaced
3131+ when picos is available. For now, it falls back to stdlib. *)
3232+ include Stdlib
3333+end
3434+3535+(* Default backend - can be changed at compile time *)
3636+module Default = Stdlib
3737+3838+(* Functor to create a mutex module from any backend *)
3939+module Make (Backend : MUTEX) = Backend
+19
forks/lwd/lib/lwd/mutex_stdlib.ml
···11+(** OCaml standard library implementation of the mutex interface. *)
22+33+include Mutex
44+55+let lock_all mutexes =
66+ let rec try_lock_all acc = function
77+ | [] ->
88+ (* All mutexes acquired successfully *)
99+ true
1010+ | mutex :: rest ->
1111+ if try_lock mutex then
1212+ try_lock_all (mutex :: acc) rest
1313+ else begin
1414+ (* Failed to acquire current mutex, release all previously acquired ones *)
1515+ List.iter unlock acc;
1616+ false
1717+ end
1818+ in
1919+ try_lock_all [] mutexes
+36
forks/lwd/lib/lwd/pp.ml
···11+let version =
22+ Scanf.sscanf Sys.ocaml_version "%d.%d" (fun major minor -> (major, minor))
33+44+let ic =
55+ if Array.length Sys.argv = 1 then (
66+ Printf.eprintf
77+ "Usage: %s <input-file>\n\
88+ Expecting a filename as argument.\n"
99+ Sys.argv.(0);
1010+ exit 1
1111+ ) else if not (Sys.file_exists Sys.argv.(1)) then (
1212+ Printf.eprintf
1313+ "Usage: %s <input-file>\n\
1414+ Cannot find file %S.\n"
1515+ Sys.argv.(0)
1616+ Sys.argv.(1);
1717+ exit 1
1818+ ) else
1919+ open_in_bin Sys.argv.(1)
2020+2121+let () =
2222+ let enable_output = ref true in
2323+ let change_output v =
2424+ print_newline ();
2525+ enable_output := v
2626+ in
2727+ try
2828+ while true do
2929+ match input_line ic with
3030+ | "(*BEGIN LETOP*)" -> change_output (version >= (4, 08))
3131+ | "(*BEGIN INJECTIVITY*)" -> change_output (version >= (4, 12))
3232+ | "(*ELSE*)" -> change_output (not !enable_output)
3333+ | "(*END*)" -> change_output true
3434+ | line -> if !enable_output then print_endline line
3535+ done
3636+ with End_of_file -> ()
+18
forks/lwd/lib/lwd/select_version.ml
···11+let () =
22+ let version =
33+ Scanf.sscanf Sys.ocaml_version "%d.%d" (fun major minor -> (major, minor))
44+ in
55+ let basename =
66+ if version < (4, 08) then "lwd_infix_compat" else "lwd_infix_letop"
77+ in
88+ let file =
99+ match Sys.argv.(1) with
1010+ | "intf" -> basename ^ ".mli"
1111+ | "impl" -> basename ^ ".ml"
1212+ | _ -> assert false
1313+ in
1414+ let ic = open_in_bin file in
1515+ let length = in_channel_length ic in
1616+ let content = really_input_string ic length in
1717+ close_in ic;
1818+ print_string content
···11+22+(** Picos implementation of the mutex interface. *)
33+44+(* Note: This implementation requires the picos library to be available.
55+ You may need to add picos as a dependency in your dune-project file. *)
66+77+(* We'll use Picos's synchronization primitives to implement mutexes.
88+ Since Picos doesn't have a direct mutex equivalent, we'll implement
99+ one using Picos's basic synchronization primitives. *)
1010+1111+type t = {
1212+ mutable locked : bool;
1313+ mutable owner : Picos.Fiber.t option;
1414+ waiters : Picos.Trigger.t list ref;
1515+}
1616+1717+let create () = {
1818+ locked = false;
1919+ owner = None;
2020+ waiters = ref [];
2121+}
2222+2323+let lock mutex =
2424+ let rec try_acquire () =
2525+ if not mutex.locked then begin
2626+ mutex.locked <- true;
2727+ mutex.owner <- Some (Picos.Fiber.current ());
2828+ end else begin
2929+ (* Create a trigger to wait for the mutex to be released *)
3030+ let trigger = Picos.Trigger.create () in
3131+ mutex.waiters := trigger :: !(mutex.waiters);
3232+ match Picos.await trigger with
3333+ | None -> (* Cancelled *) raise (Sys_error "Mutex lock cancelled")
3434+ | Some (exn, _) -> raise exn
3535+ end
3636+ in
3737+ try_acquire ()
3838+3939+let try_lock mutex =
4040+ if not mutex.locked then begin
4141+ mutex.locked <- true;
4242+ mutex.owner <- Some (Picos.Fiber.current ());
4343+ true
4444+ end else
4545+ false
4646+4747+let unlock mutex =
4848+ if not mutex.locked then
4949+ raise (Sys_error "Mutex is not locked")
5050+ else
5151+ let current_fiber = Picos.Fiber.current () in
5252+ match mutex.owner with
5353+ | None -> raise (Sys_error "Mutex has no owner")
5454+ | Some owner ->
5555+ if not (Picos.Fiber.equal current_fiber owner) then
5656+ raise (Sys_error "Mutex was locked by another fiber")
5757+ else begin
5858+ mutex.locked <- false;
5959+ mutex.owner <- None;
6060+ (* Wake up one waiter if any *)
6161+ match !(mutex.waiters) with
6262+ | [] -> ()
6363+ | trigger :: rest ->
6464+ mutex.waiters := rest;
6565+ Picos.Trigger.signal trigger ()
6666+ end
6767+6868+let protect mutex f =
6969+ lock mutex;
7070+ try
7171+ let result = f () in
7272+ unlock mutex;
7373+ result
7474+ with exn ->
7575+ unlock mutex;
7676+ raise exn
7777+7878+let lock_all mutexes =
7979+ let rec try_lock_all acc = function
8080+ | [] ->
8181+ (* All mutexes acquired successfully *)
8282+ true
8383+ | mutex :: rest ->
8484+ if try_lock mutex then
8585+ try_lock_all (mutex :: acc) rest
8686+ else begin
8787+ (* Failed to acquire current mutex, release all previously acquired ones *)
8888+ List.iter unlock acc;
8989+ false
9090+ end
9191+ in
9292+ try_lock_all [] mutexes
···11+Plans to make it multithreaded
22+33+44+My initial approach was to schedule the chagnes to the lwd varaiables untill a root has finished evaluating. However, this doesn't work if you have two roots that can be evaulated in paralell.
55+66+I could:
77+1. Pervent roots from being evaluated in paralell
88+2. Could i just prevent any nodes being evaluated in paralell.
99+Imagine two roots share a node and are being evaluated in paralell
1010+```mermaid
1111+A1[root]--> B1[shared]
1212+A1-->B2
1313+A2-->B1
1414+A2-->B3
1515+B1--> C1[lwd var]
1616+```
1717+If, while setting the lwd.var we can either lock the node, or lock the root that is holding the node we can safely update $
1818+1919+if we just locked the node, currently the root could be evaluating a parent node while we lock it... but does that matter?
2020+no.. not really.... if the root holds all locked nodes locked untill the evaluation is finished we are actually safe to set a varaible and it'll still ensure consitency
2121+2222+2323+So, by that logic:
2424+A root should lock and hold locked all nodes it touches while evaluating, this ensures that it will experience consitency.
2525+Infact, we don't need to hold all nodes locked, we could just lock all leaf nodes that still have a path to the parent node,
2626+but we could unlock any node that has been fully calculated that isn't a leaf, sometimes a leaf could connect to two different mid nodes so we can't neciserily unlock them
2727+2828+if we can lock a node while setting an lwd var we are safe to do set it, otherwise we have to wait until it's finished evaluating.
2929+in a concurrent enviroment this is okay, because we can just wait for the unlock in the background.
3030+In a non concurrent environment, I think we could locate the root node that locked it, and then add the setting operation to a "post eval" list.
3131+We would have to decide if it should set and then eval while holding the lock and further delay another root evaluation, or let the other root evaluate, or set it, let the root evaluate and then revaluate ourself.
3232+3333+3434+If two graphs are evaluating at the same time and one encounters a locked node from another, the second should move on if possible and then just wait
3535+3636+3737+Could i just used the cached value if a node is locked. no, because it could be recomputing
3838+3939+## How to handle invalidation during re-evaluation:
4040+I guess I could actually just cancel and reschedule rendering, but that could block rendering forever if rendering takes a long time. and a new event comes in
4141+4242+Or I could walk upwards towards each root, locking as i go. however, if there is an evaluation occuring, they will not be able to keep evaluating.
4343+4444+I could introduce a rule that says, if a node is locked because of invalidation, the node should use the cached value.
4545+We can be very sure the node will eventually get recomputed, but the invalidation would have to be in it's own process and constantly trying to work its way up the node graph.
4646+4747+4848+I don't like the idea of
4949+5050+In a concurrent environment i could just drop the recomputation into it's own process and move on, in a single threaded environment the simplest way would be to schedule the update and locking on the root node that currently holds the lock.
5151+5252+5353+5454+5555+- what if we split up invalidation into two parts? currently invalid and next invalid we just set next invalid on all the items without doing any locking. Then when the currently invalidating root node is done, it sets currently invalid to true as it unlocks the node.
5656+5757+5858+5959+## So full explanation:
6060+6161+- to recompute: a root node should walk down the tree of invalidated nodes locking as it goes, then unlock them once done.
6262+- to update a variable a leaf node should lock itself, apply an update and then walk up the tree, marking locking each node and marking it invalid
6363+- if a root node that is currently traversing down the nodes
6464+6565+6666+6767+6868+6969+## invalidate next:
7070+- evaluation starts at the root node, locking as it goes.
7171+- when updating a variable walk up the tree of nodes. When we encounter a locked node (one that is currently being evaluated) we mark it as invalidate-next.
7272+- if we encounter a node that is currently marked invalidated we can just stop
7373+- if we encounter an unlocked node that is marked computed, we mark it invalid
7474+- when a node is finished evaluating it checks to see if it is marked (invalidate next) if it is, we re check the children to find the invalid children and evalute it again.
7575+- this process may need to have some smart locking of this invalidate next status so that the checking and updating of the status doesn't encounter a scenario where we check the node status and then mark it invalidate next and then concurrently the node is marked evaluted by another thread
···11open Nottui
22open! Lwd_infix
3344-54let is_double_click =
65 let k = ref 0 in
76 let last = ref (0, 0.0) in
···1413 let k, t = !last in
1514 k = k' && t +. 0.4 >= time
1615 in
1717- last := (k', time);
1616+ last := k', time;
1817 result
1818+;;
19192020let remember_width ~wref ui =
2121 wref := max (Ui.layout_spec ui).Ui.w !wref;
2222- Ui.resize ~w:!wref ui
2222+ Ui.resize ~w:!wref ui
2323+;;
23242425let rec dir ?(initial_path = []) ?after_width:(wref = ref 0) path =
2526 let column = Lwd.var (Lwd.return Ui.empty) in
···2829 let directories = Lwd_table.make () in
2930 let files = Lwd_table.make () in
3031 let body =
3131-3232- (W.vbox
3333- [
3434- Lwd_table.reduce Ui.pack_y directories;
3535- Lwd_table.reduce Ui.pack_y files;
3636- ])
3737- |>W.Scroll.v_area
3232+ W.vbox [ Lwd_table.reduce Ui.pack_y directories; Lwd_table.reduce Ui.pack_y files ]
3333+ |> W.Scroll.v_area
3834 in
3935 let rec set_constrain constrain =
4036 let header =
4137 Ui.mouse_area
4238 (fun ~x:_ ~y:_ -> function
4343- | `Left ->
4444- set_constrain false;
4545- Lwd.set after (Lwd.return Ui.empty);
4646- `Handled | _ -> `Unhandled)
3939+ | `Left ->
4040+ set_constrain false;
4141+ Lwd.set after (Lwd.return Ui.empty);
4242+ `Handled
4343+ | _ -> `Unhandled)
4744 header
4845 in
4946 let t = W.vbox [ Lwd.return header; body ] in
5047 let t =
5151- if constrain then Lwd.map ~f:(Ui.resize ~w:12 ) t
4848+ if constrain
4949+ then Lwd.map ~f:(Ui.resize ~w:12) t
5250 else Lwd.map ~f:(remember_width ~wref) t
5351 in
5452 Lwd.set column (Lwd_utils.pack Ui.pack_x [ t; Lwd.join (Lwd.get after) ])
···5856 let goto ?initial_path name =
5957 set_constrain true;
6058 let t =
6161- try dir ?initial_path ~after_width (Filename.concat path name)
6262- with exn ->
6363- Lwd.return (W.string ~attr:Notty.(A.bg A.red) (Printexc.to_string exn))
5959+ try dir ?initial_path ~after_width (Filename.concat path name) with
6060+ | exn -> Lwd.return (W.string ~attr:Notty.(A.bg A.red) (Printexc.to_string exn))
6461 in
6562 Lwd.set after (Lwd.map ~f:(Ui.join_x (W.string " ")) t)
6663 in
6764 let highlighted_cell = ref None in
6865 let rec render_directory ?(highlight = false) cell name =
6969- if highlight then (
7070- ( match !highlighted_cell with
7171- | None -> ()
7272- | Some (cell, name) -> render_directory cell name );
7373- highlighted_cell := Some (cell, name) );
6666+ if highlight
6767+ then (
6868+ (match !highlighted_cell with
6969+ | None -> ()
7070+ | Some (cell, name) -> render_directory cell name);
7171+ highlighted_cell := Some (cell, name));
7472 Lwd_table.set cell
7573 @@ Ui.mouse_area
7674 (fun ~x:_ ~y:_ -> function
7777- | `Left ->
7878- render_directory ~highlight:true cell name;
7979- goto name;
8080- `Handled | _ -> `Unhandled)
8181- (W.string
8282- ~attr:Notty.(A.bg (if highlight then A.lightblue else A.blue))
8383- name)
7575+ | `Left ->
7676+ render_directory ~highlight:true cell name;
7777+ goto name;
7878+ `Handled
7979+ | _ -> `Unhandled)
8080+ (W.string ~attr:Notty.(A.bg (if highlight then A.lightblue else A.blue)) name)
8481 in
8582 let add_directory name =
8686- if name <> "" && name.[0] <> '.' then
8383+ if name <> "" && name.[0] <> '.'
8484+ then (
8785 let highlight =
8888- match initial_path with x :: _ when x = name -> true | _ -> false
8686+ match initial_path with
8787+ | x :: _ when x = name -> true
8888+ | _ -> false
8989 in
9090- render_directory ~highlight (Lwd_table.append directories) name
9090+ render_directory ~highlight (Lwd_table.append directories) name)
9191 in
9292 let add_file name =
9393 let is_double_click = is_double_click () in
9494 Lwd_table.set (Lwd_table.append files)
9595 @@ Ui.mouse_area
9696 (fun ~x:_ ~y:_ -> function
9797- | `Left ->
9898- if is_double_click () then
9999- ignore
100100- ( Sys.command
101101- ( "xdg-open "
102102- ^ Filename.quote (Filename.concat path name) )
103103- : int );
104104- `Handled | _ -> `Unhandled)
9797+ | `Left ->
9898+ if is_double_click ()
9999+ then
100100+ ignore
101101+ (Sys.command ("xdg-open " ^ Filename.quote (Filename.concat path name))
102102+ : int);
103103+ `Handled
104104+ | _ -> `Unhandled)
105105 (W.string name)
106106 in
107107 let entries = Sys.readdir path in
108108 Array.sort String.compare entries;
109109 Array.iter
110110 (fun name ->
111111- let path = Filename.concat path name in
112112- try if Sys.is_directory path then add_directory name else add_file name
113113- with exn ->
114114- let text =
115115- match exn with Sys_error _ -> name | exn -> Printexc.to_string exn
116116- in
117117- Lwd_table.append' files (W.string ~attr:Notty.(A.bg A.red) text))
111111+ let path = Filename.concat path name in
112112+ try if Sys.is_directory path then add_directory name else add_file name with
113113+ | exn ->
114114+ let text =
115115+ match exn with
116116+ | Sys_error _ -> name
117117+ | exn -> Printexc.to_string exn
118118+ in
119119+ Lwd_table.append' files (W.string ~attr:Notty.(A.bg A.red) text))
118120 entries;
119119- (match initial_path with [] -> () | x :: xs -> goto ~initial_path:xs x);
121121+ (match initial_path with
122122+ | [] -> ()
123123+ | x :: xs -> goto ~initial_path:xs x);
120124 Lwd.join (Lwd.get column)
125125+;;
121126122127let gravity_pad = Gravity.make ~h:`Negative ~v:`Negative
123123-124128let gravity_crop = Gravity.make ~h:`Positive ~v:`Negative
125129126130let () =
···133137 in
134138 let body = Lwd.var (Lwd.pure Ui.empty) in
135139 let wm = W.Old.window_manager (Lwd.join (Lwd.get body)) in
136136- let ui = W.vbox [
137137- W.Old.main_menu_item wm "Quit" (fun () -> exit 0);
138138- dir ~initial_path "/"
139139- ]
140140+ let ui =
141141+ W.vbox [ W.Old.main_menu_item wm "Quit" (fun () -> exit 0); dir ~initial_path "/" ]
140142 in
141143 Lwd.set body (Lwd.map ~f:(Ui.resize ~pad:gravity_pad ~crop:gravity_crop) ui);
142144 Ui_loop.run (W.Old.window_manager_view wm)
143143-145145+;;
+13-9
forks/nottui/examples/stress.ml
···11open Nottui
2233-43(* App-specific widgets *)
5465let strict_table () =
76 let columns = Lwd_table.make () in
87 let cells =
98 Array.init 100 (fun _ ->
1010- let rows = Lwd_table.make () in
1111- Lwd_table.append' columns rows;
1212- Array.init 100 (fun _ -> Lwd_table.append rows ~set:0))
99+ let rows = Lwd_table.make () in
1010+ Lwd_table.append' columns rows;
1111+ Array.init 100 (fun _ -> Lwd_table.append rows ~set:0))
1312 in
1413 let render_cell _ v = W.string (string_of_int v) in
1514 let render_column _ rows = Lwd_table.map_reduce render_cell Ui.pack_y rows in
1615 let table =
1717- Lwd_table.map_reduce render_column
1818- (Lwd_utils.lift_monoid Ui.pack_x)
1919- columns
1616+ Lwd_table.map_reduce render_column (Lwd_utils.lift_monoid Ui.pack_x) columns
2017 in
2121- (cells, Lwd.join table |> W.Scroll.area)
1818+ cells, Lwd.join table |> W.Scroll.area
1919+;;
22202321(* Entry point *)
24222523(*let () = Statmemprof_emacs.start 1E-4 30 5*)
26242725let walk cell =
2828- let v = match Lwd_table.get cell with None -> 0 | Some x -> x in
2626+ let v =
2727+ match Lwd_table.get cell with
2828+ | None -> 0
2929+ | Some x -> x
3030+ in
2931 Lwd_table.set cell (v + Random.int 20 - 10)
3232+;;
30333134let () =
3235 let cells, table = strict_table () in
···3942 done;
4043 Lwd.quick_release root;
4144 Notty_unix.Term.release term
4545+;;
+30-24
forks/nottui/lib/nottui-lwt/nottui_lwt.ml
···22open Nottui
33open Notty_lwt
4455-type event = [
66- | `Key of Unescape.key
55+type event =
66+ [ `Key of Unescape.key
77 | `Mouse of Unescape.mouse
88 | `Paste of Unescape.paste
99 | `Resize of int * int
1010-]
1010+ ]
11111212let copy_until quit ~f input =
1313 let quit = Lwt.map (fun () -> None) quit in
1414 let stream, push = Lwt_stream.create () in
1515 let rec aux () =
1616- Lwt.bind (Lwt.choose [quit; Lwt_stream.peek input]) @@ fun result ->
1616+ Lwt.bind (Lwt.choose [ quit; Lwt_stream.peek input ]) @@ fun result ->
1717 match result with
1818 | None ->
1919 push None;
···2424 in
2525 Lwt.async aux;
2626 stream
2727+;;
27282829let render ?quit ~size events doc =
2930 let renderer = Renderer.make () in
3031 let refresh_stream, push_refresh = Lwt_stream.create () in
3132 let root =
3232- Lwd.observe ~on_invalidate:(fun _ ->
3333- if not (Lwt_stream.is_closed refresh_stream) then
3434- push_refresh (Some ())
3535- ) doc
3333+ Lwd.observe
3434+ ~on_invalidate:(fun _ ->
3535+ if not (Lwt_stream.is_closed refresh_stream) then push_refresh (Some ()))
3636+ doc
3637 in
3737- let quit, do_quit = match quit with
3838+ let quit, do_quit =
3939+ match quit with
3840 | Some quit -> quit, None
3939- | None -> let t, u = Lwt.wait () in t, Some u
4141+ | None ->
4242+ let t, u = Lwt.wait () in
4343+ t, Some u
4044 in
4141- let events = copy_until quit events ~f:(fun e ->
4242- (e : [`Resize of _ | Unescape.event] :> [`Resize of _ | Ui.event]))
4545+ let events =
4646+ copy_until quit events ~f:(fun e ->
4747+ (e : [ `Resize of _ | Unescape.event ] :> [ `Resize of _ | Ui.event ]))
4348 in
4449 let size = ref size in
4550 let result, push = Lwt_stream.create () in
···5156 in
5257 refresh ();
5358 let process_event = function
5454- | `Key (`ASCII 'q', [`Meta]) as event ->
5555- begin match do_quit with
5656- | Some u -> Lwt.wakeup u ()
5757- | None -> ignore (Renderer.dispatch_event renderer event)
5858- end
5959- | #Ui.event as event ->
6060- ignore (Renderer.dispatch_event renderer event)
5959+ | `Key (`ASCII 'q', [ `Meta ]) as event ->
6060+ (match do_quit with
6161+ | Some u -> Lwt.wakeup u ()
6262+ | None -> ignore (Renderer.dispatch_event renderer event))
6363+ | #Ui.event as event -> ignore (Renderer.dispatch_event renderer event)
6164 | `Resize size' ->
6265 size := size';
6366 refresh ()
6467 in
6568 Lwt.async (fun () ->
6666- Lwt.finalize
6767- (fun () -> Lwt_stream.iter process_event events)
6868- (fun () -> push None; Lwt.return_unit)
6969- );
6969+ Lwt.finalize
7070+ (fun () -> Lwt_stream.iter process_event events)
7171+ (fun () ->
7272+ push None;
7373+ Lwt.return_unit));
7074 Lwt.async (fun () -> Lwt_stream.iter refresh refresh_stream);
7175 result
7676+;;
72777378let run ?quit doc =
7479 let term = Term.create () in
7580 let images = render ?quit ~size:(Term.size term) (Term.events term) doc in
7681 Lwt.finalize
7782 (fun () -> Lwt_stream.iter_s (Term.image term) images)
7878- (fun () -> (Term.release term))
8383+ (fun () -> Term.release term)
8484+;;
+11-6
forks/nottui/lib/nottui-lwt/nottui_lwt.mli
···77 synchronize threads.
88*)
991010-type event = [
1111- | `Key of Unescape.key
1010+(** FIXME: Refactor to use [Nottui.Ui.event]? *)
1111+type event =
1212+ [ `Key of Unescape.key
1213 | `Mouse of Unescape.mouse
1314 | `Paste of Unescape.paste
1415 | `Resize of int * int
1515-]
1616-(** FIXME: Refactor to use [Nottui.Ui.event]? *)
1616+ ]
17171818-val render : ?quit:unit Lwt.t -> size:int * int -> event Lwt_stream.t -> ui Lwd.t -> image Lwt_stream.t
1918(** Turn a stream of events into a stream of images. *)
1919+val render
2020+ : ?quit:unit Lwt.t
2121+ -> size:int * int
2222+ -> event Lwt_stream.t
2323+ -> ui Lwd.t
2424+ -> image Lwt_stream.t
20252121-val run : (*?term:Term.t ->*) ?quit:unit Lwt.t -> ui Lwd.t -> unit Lwt.t
2226(** Run mainloop in [Lwt], until the [quit] promise is fulfilled.
23272428 The ui is a normal [Lwd.t] value, but events are free to spawn asynchronous
2529 [Lwt] threads.
2630*)
3131+val run : ?quit:(*?term:Term.t ->*) unit Lwt.t -> ui Lwd.t -> unit Lwt.t
+207-162
forks/nottui/lib/nottui-pretty/nottui_pretty.ml
···17171818(* A type of integers with infinity. *)
19192020-type requirement =
2121- int (* with infinity *)
2020+type requirement = int (* with infinity *)
22212322(* Infinity is encoded as [max_int]. *)
24232525-let infinity : requirement =
2626- max_int
2424+let infinity : requirement = max_int
27252826(* Addition of integers with infinity. *)
29273030-let (++) (x : requirement) (y : requirement) : requirement =
3131- if x = infinity || y = infinity
3232- then infinity
3333- else x + y
2828+let ( ++ ) (x : requirement) (y : requirement) : requirement =
2929+ if x = infinity || y = infinity then infinity else x + y
3030+;;
34313532(* --------------------------------------------------------------------------
3633 UI cache
···6663 FUTURE WORK: since flat layout never changes, it might be worth caching
6764 separately flat and non-flat results. Flat cache would actually be a lazy
6865 computation.
6969- *)
6666+*)
70677168(* We use a few OCaml tricks to implement caching without introducing too
7269 much indirections.
···9087 It can only occur when someone put a `Hardline` in a flat document.
9188 They lied: the document should have been flat, but it is not.
9289 Nevertheless, I chose to accept this case. *)
9393- Flat_span : { prefix: ui; body: ui; suffix: ui } -> flat ui_cache
9090+ Flat_span :
9191+ { prefix : ui
9292+ ; body : ui
9393+ ; suffix : ui
9494+ }
9595+ -> flat ui_cache
9496 | (* A line in a non-flat context *)
9595- Nonflat_line : { min_rem: int; max_rem: int; ui: ui; } -> nonflat ui_cache
9797+ Nonflat_line :
9898+ { min_rem : int
9999+ ; max_rem : int
100100+ ; ui : ui
101101+ }
102102+ -> nonflat ui_cache
96103 | (* A span in a non-flat context *)
9797- Nonflat_span : {
9898- min_rem: int; max_rem: int; prefix: ui;
9999- min_wid: int; max_wid: int; body: ui; suffix: ui;
100100- } -> nonflat ui_cache
104104+ Nonflat_span :
105105+ { min_rem : int
106106+ ; max_rem : int
107107+ ; prefix : ui
108108+ ; min_wid : int
109109+ ; max_wid : int
110110+ ; body : ui
111111+ ; suffix : ui
112112+ }
113113+ -> nonflat ui_cache
101114102115(* The type of an actual cache slot (stored in document nodes).
103116 It hides the category of the node. *)
···110123type t =
111124 | Blank of int
112125 | Ui of Nottui.ui
113113- | If_flat of { then_: t; else_: t }
126126+ | If_flat of
127127+ { then_ : t
128128+ ; else_ : t
129129+ }
114130 | Hardline
115115- | Cat of { req: requirement; lhs: t; rhs: t; mutable cache : ui_cache_slot }
116116- | Nest of { req: requirement; indent: int; doc: t }
117117- | Group of { req: requirement; doc: t; mutable cache : ui_cache_slot }
131131+ | Cat of
132132+ { req : requirement
133133+ ; lhs : t
134134+ ; rhs : t
135135+ ; mutable cache : ui_cache_slot
136136+ }
137137+ | Nest of
138138+ { req : requirement
139139+ ; indent : int
140140+ ; doc : t
141141+ }
142142+ | Group of
143143+ { req : requirement
144144+ ; doc : t
145145+ ; mutable cache : ui_cache_slot
146146+ }
118147119148(* Only [Cat] and [Group] nodes are cached.
120149 This is because [Cat] is the only place where two sub-documents are
···125154 should normally only have a fixed nesting ([Nest (Nest (Nest ...))] cannot
126155 happen). I suspect that caching is not beneficial, if detrimental, to these
127156 cases.
128128- *)
157157+*)
129158130159(* -------------------------------------------------------------------------- *)
131160···136165 | Ui ui -> Nottui.Ui.layout_width ui
137166 | If_flat t -> requirement t.then_
138167 | Hardline -> infinity
139139- | Cat {req; _} | Nest {req; _} | Group {req; _} -> req
168168+ | Cat { req; _ } | Nest { req; _ } | Group { req; _ } -> req
169169+;;
140170141171(* -------------------------------------------------------------------------- *)
142172143173(* Document constructors. *)
144174145175let empty = Blank 0
146146-147176let ui ui = Ui ui
148148-149177let hardline = Hardline
150178151179let blank = function
152180 | 0 -> Blank 0
153181 | 1 -> Blank 1
154182 | n -> Blank n
155155-156156-let if_flat (If_flat {then_; _} | then_) else_ =
157157- If_flat { then_; else_ }
183183+;;
158184159159-let internal_break i =
160160- if_flat (blank i) hardline
185185+let if_flat (If_flat { then_; _ } | then_) else_ = If_flat { then_; else_ }
186186+let internal_break i = if_flat (blank i) hardline
161187162188let break =
163189 let break0 = internal_break 0 in
···166192 | 0 -> break0
167193 | 1 -> break1
168194 | i -> internal_break i
195195+;;
169196170170-let (^^) x y =
197197+let ( ^^ ) x y =
171198 match x, y with
172172- | (Blank 0, t) | (t, Blank 0) -> t
199199+ | Blank 0, t | t, Blank 0 -> t
173200 | Blank i, Blank j -> Blank (i + j)
174201 | lhs, rhs ->
175175- Cat {req = requirement lhs ++ requirement rhs; lhs; rhs;
176176- cache = Cache Uncached}
202202+ Cat { req = requirement lhs ++ requirement rhs; lhs; rhs; cache = Cache Uncached }
203203+;;
177204178205let nest indent doc =
179206 assert (indent >= 0);
180207 match doc with
181181- | Nest t -> Nest {req = t.req; indent = indent + t.indent; doc = t.doc}
182182- | doc -> Nest {req = requirement doc; indent; doc}
208208+ | Nest t -> Nest { req = t.req; indent = indent + t.indent; doc = t.doc }
209209+ | doc -> Nest { req = requirement doc; indent; doc }
210210+;;
183211184212let group = function
185213 | Group _ as doc -> doc
186214 | doc ->
187215 let req = requirement doc in
188188- if req = infinity then doc else Group {req; doc; cache = Cache Uncached}
216216+ if req = infinity then doc else Group { req; doc; cache = Cache Uncached }
217217+;;
189218190219(* -------------------------------------------------------------------------- *)
191220···194223(* Some intermediate UI *)
195224196225let blank_ui n = Ui.space n 0
197197-198198-let flat_hardline =
199199- Flat_span { prefix = Ui.empty; body = Ui.empty; suffix = Ui.empty; }
226226+let flat_hardline = Flat_span { prefix = Ui.empty; body = Ui.empty; suffix = Ui.empty }
200227201228let mk_body body1 suffix prefix body2 =
202229 Ui.join_y body1 (Ui.join_y (Ui.join_x suffix prefix) body2)
230230+;;
203231204232let mk_pad indent body suffix =
205233 let pad = Ui.space indent 0 in
206206- (Ui.join_x pad body, Ui.join_x pad suffix)
234234+ Ui.join_x pad body, Ui.join_x pad suffix
235235+;;
207236208237(* Flat renderer *)
209238210210-let flat_cache (Cache slot) = match slot with
239239+let flat_cache (Cache slot) =
240240+ match slot with
211241 | Flat_line _ as ui -> Some ui
212242 | Flat_span _ as ui -> Some ui
213243 | _ -> None
244244+;;
214245215246let rec pretty_flat = function
216247 | Ui ui -> Flat_line ui
···218249 | Hardline -> flat_hardline
219250 | If_flat t -> pretty_flat t.then_
220251 | Cat t ->
221221- begin match flat_cache t.cache with
222222- | Some ui -> ui
223223- | None ->
224224- let result =
225225- let lhs = pretty_flat t.lhs and rhs = pretty_flat t.rhs in
226226- match lhs, rhs with
227227- | Flat_line l, Flat_line r ->
228228- Flat_line (Ui.join_x l r)
229229- | Flat_line l, Flat_span r ->
230230- Flat_span {r with prefix = Ui.join_x l r.prefix}
231231- | Flat_span l, Flat_line r ->
232232- Flat_span {l with suffix = Ui.join_x l.suffix r}
233233- | Flat_span l, Flat_span r ->
234234- Flat_span {prefix = l.prefix;
235235- body = mk_body l.body l.suffix r.prefix r.body;
236236- suffix = r.suffix}
237237- in
238238- t.cache <- Cache result;
239239- result
240240- end
252252+ (match flat_cache t.cache with
253253+ | Some ui -> ui
254254+ | None ->
255255+ let result =
256256+ let lhs = pretty_flat t.lhs
257257+ and rhs = pretty_flat t.rhs in
258258+ match lhs, rhs with
259259+ | Flat_line l, Flat_line r -> Flat_line (Ui.join_x l r)
260260+ | Flat_line l, Flat_span r -> Flat_span { r with prefix = Ui.join_x l r.prefix }
261261+ | Flat_span l, Flat_line r -> Flat_span { l with suffix = Ui.join_x l.suffix r }
262262+ | Flat_span l, Flat_span r ->
263263+ Flat_span
264264+ { prefix = l.prefix
265265+ ; body = mk_body l.body l.suffix r.prefix r.body
266266+ ; suffix = r.suffix
267267+ }
268268+ in
269269+ t.cache <- Cache result;
270270+ result)
241271 | Nest t ->
242242- begin match pretty_flat t.doc with
243243- | Flat_line _ as ui -> ui
244244- | Flat_span s ->
245245- let body, suffix = mk_pad t.indent s.body s.suffix in
246246- Flat_span {s with body; suffix}
247247- end
272272+ (match pretty_flat t.doc with
273273+ | Flat_line _ as ui -> ui
274274+ | Flat_span s ->
275275+ let body, suffix = mk_pad t.indent s.body s.suffix in
276276+ Flat_span { s with body; suffix })
248277 | Group t ->
249249- begin match flat_cache t.cache with
250250- | Some ui -> ui
251251- | None ->
252252- let result = pretty_flat t.doc in
253253- t.cache <- Cache result;
254254- result
255255- end
278278+ (match flat_cache t.cache with
279279+ | Some ui -> ui
280280+ | None ->
281281+ let result = pretty_flat t.doc in
282282+ t.cache <- Cache result;
283283+ result)
284284+;;
256285257286(* Nonflat renderer.
258287···269298270299let mini, maxi = Lwd_utils.(mini, maxi)
271300272272-let (+++) i j = let result = i + j in if result < 0 then max_int else result
301301+let ( +++ ) i j =
302302+ let result = i + j in
303303+ if result < 0 then max_int else result
304304+;;
273305274274-let nonflat_line ui =
275275- Nonflat_line {min_rem = min_int; max_rem = max_int; ui}
306306+let nonflat_line ui = Nonflat_line { min_rem = min_int; max_rem = max_int; ui }
276307277277-let nonflat_cache (Cache slot) rem wid = match slot with
308308+let nonflat_cache (Cache slot) rem wid =
309309+ match slot with
278310 | Nonflat_line t' as t when t'.min_rem <= rem && rem < t'.max_rem -> Some t
279311 | Nonflat_span t' as t
280280- when t'.min_rem <= rem && rem < t'.max_rem &&
281281- t'.min_wid <= wid && wid < t'.max_wid -> Some t
312312+ when t'.min_rem <= rem && rem < t'.max_rem && t'.min_wid <= wid && wid < t'.max_wid ->
313313+ Some t
282314 | _ -> None
315315+;;
283316284284-let span_hardline = Nonflat_span {
285285- min_rem = min_int; max_rem = max_int;
286286- min_wid = min_int; max_wid = max_int;
287287- prefix = Ui.empty; body = Ui.empty; suffix = Ui.empty;
288288- }
317317+let span_hardline =
318318+ Nonflat_span
319319+ { min_rem = min_int
320320+ ; max_rem = max_int
321321+ ; min_wid = min_int
322322+ ; max_wid = max_int
323323+ ; prefix = Ui.empty
324324+ ; body = Ui.empty
325325+ ; suffix = Ui.empty
326326+ }
327327+;;
289328290290-let rec pretty (rem: int) (wid : int) = function
329329+let rec pretty (rem : int) (wid : int) = function
291330 | Ui ui -> nonflat_line ui
292331 | Blank n -> nonflat_line (blank_ui n)
293332 | Hardline -> span_hardline
294333 | If_flat t -> pretty rem wid t.else_
295334 | Cat t ->
296296- begin match nonflat_cache t.cache rem wid with
297297- | Some ui -> ui
298298- | None ->
299299- let lhs = pretty rem wid t.lhs in
300300- let result = match lhs with
301301- | Nonflat_line l ->
302302- let lw = Ui.layout_width l.ui in
303303- begin match pretty (rem - lw) wid t.rhs with
304304- | Nonflat_line r ->
305305- Nonflat_line {
306306- min_rem = maxi l.min_rem (r.min_rem + lw);
307307- max_rem = mini l.max_rem (r.max_rem +++ lw);
308308- ui = Ui.join_x l.ui r.ui;
309309- }
310310- | Nonflat_span r ->
311311- Nonflat_span {
312312- r with
313313- min_rem = maxi l.min_rem (r.min_rem + lw);
314314- max_rem = mini l.max_rem (r.max_rem +++ lw);
315315- prefix = Ui.join_x l.ui r.prefix;
316316- }
317317- end
318318- | Nonflat_span l ->
319319- let lw = Ui.layout_width l.suffix in
320320- begin match pretty (wid - lw) wid t.rhs with
321321- | Nonflat_line r ->
322322- Nonflat_span {
323323- l with
324324- min_wid = maxi l.min_wid (r.min_rem + lw);
325325- max_wid = mini l.max_wid (r.max_rem +++ lw);
326326- suffix = Ui.join_x l.suffix r.ui;
335335+ (match nonflat_cache t.cache rem wid with
336336+ | Some ui -> ui
337337+ | None ->
338338+ let lhs = pretty rem wid t.lhs in
339339+ let result =
340340+ match lhs with
341341+ | Nonflat_line l ->
342342+ let lw = Ui.layout_width l.ui in
343343+ (match pretty (rem - lw) wid t.rhs with
344344+ | Nonflat_line r ->
345345+ Nonflat_line
346346+ { min_rem = maxi l.min_rem (r.min_rem + lw)
347347+ ; max_rem = mini l.max_rem (r.max_rem +++ lw)
348348+ ; ui = Ui.join_x l.ui r.ui
327349 }
328328- | Nonflat_span r ->
329329- Nonflat_span {
330330- prefix = l.prefix; min_rem = l.min_rem; max_rem = l.max_rem;
331331- min_wid = maxi (maxi l.min_wid (r.min_rem + lw)) r.min_wid;
332332- max_wid = mini (mini l.max_wid (r.max_rem +++ lw)) r.max_wid;
333333- body = mk_body l.body l.suffix r.prefix r.body;
334334- suffix = r.suffix;
350350+ | Nonflat_span r ->
351351+ Nonflat_span
352352+ { r with
353353+ min_rem = maxi l.min_rem (r.min_rem + lw)
354354+ ; max_rem = mini l.max_rem (r.max_rem +++ lw)
355355+ ; prefix = Ui.join_x l.ui r.prefix
356356+ })
357357+ | Nonflat_span l ->
358358+ let lw = Ui.layout_width l.suffix in
359359+ (match pretty (wid - lw) wid t.rhs with
360360+ | Nonflat_line r ->
361361+ Nonflat_span
362362+ { l with
363363+ min_wid = maxi l.min_wid (r.min_rem + lw)
364364+ ; max_wid = mini l.max_wid (r.max_rem +++ lw)
365365+ ; suffix = Ui.join_x l.suffix r.ui
335366 }
336336- end
337337- in
338338- t.cache <- Cache result;
339339- result
340340- end
367367+ | Nonflat_span r ->
368368+ Nonflat_span
369369+ { prefix = l.prefix
370370+ ; min_rem = l.min_rem
371371+ ; max_rem = l.max_rem
372372+ ; min_wid = maxi (maxi l.min_wid (r.min_rem + lw)) r.min_wid
373373+ ; max_wid = mini (mini l.max_wid (r.max_rem +++ lw)) r.max_wid
374374+ ; body = mk_body l.body l.suffix r.prefix r.body
375375+ ; suffix = r.suffix
376376+ })
377377+ in
378378+ t.cache <- Cache result;
379379+ result)
341380 | Nest t ->
342342- begin match pretty rem (wid - t.indent) t.doc with
343343- | Nonflat_line _ as ui -> ui
344344- | Nonflat_span s ->
345345- let body, suffix = mk_pad t.indent s.body s.suffix in
346346- Nonflat_span {
347347- min_rem = s.min_rem; max_rem = s.max_rem;
348348- min_wid = s.min_wid + t.indent;
349349- max_wid = s.max_wid +++ t.indent;
350350- prefix = s.prefix; body; suffix;
351351- }
352352- end
381381+ (match pretty rem (wid - t.indent) t.doc with
382382+ | Nonflat_line _ as ui -> ui
383383+ | Nonflat_span s ->
384384+ let body, suffix = mk_pad t.indent s.body s.suffix in
385385+ Nonflat_span
386386+ { min_rem = s.min_rem
387387+ ; max_rem = s.max_rem
388388+ ; min_wid = s.min_wid + t.indent
389389+ ; max_wid = s.max_wid +++ t.indent
390390+ ; prefix = s.prefix
391391+ ; body
392392+ ; suffix
393393+ })
353394 | Group t as self ->
354354- begin if t.req <= rem then
355355- match pretty_flat self with
356356- | Flat_line ui ->
357357- Nonflat_line { min_rem = t.req; max_rem = max_int; ui }
358358- | Flat_span ui ->
359359- Nonflat_span {
360360- min_rem = t.req; max_rem = max_int;
361361- min_wid = min_int; max_wid = max_int;
362362- prefix = ui.prefix;
363363- body = ui.body;
364364- suffix = ui.suffix;
365365- }
366366- else match nonflat_cache t.cache rem wid with
367367- | Some ui -> ui
368368- | None ->
369369- let result = match pretty rem wid t.doc with
370370- | Nonflat_line ui -> Nonflat_line {ui with max_rem = t.req}
371371- | Nonflat_span ui ->
372372- Nonflat_span {ui with max_rem = mini t.req ui.max_rem}
373373- in
374374- t.cache <- Cache result;
375375- result
376376- end
395395+ if t.req <= rem
396396+ then (
397397+ match pretty_flat self with
398398+ | Flat_line ui -> Nonflat_line { min_rem = t.req; max_rem = max_int; ui }
399399+ | Flat_span ui ->
400400+ Nonflat_span
401401+ { min_rem = t.req
402402+ ; max_rem = max_int
403403+ ; min_wid = min_int
404404+ ; max_wid = max_int
405405+ ; prefix = ui.prefix
406406+ ; body = ui.body
407407+ ; suffix = ui.suffix
408408+ })
409409+ else (
410410+ match nonflat_cache t.cache rem wid with
411411+ | Some ui -> ui
412412+ | None ->
413413+ let result =
414414+ match pretty rem wid t.doc with
415415+ | Nonflat_line ui -> Nonflat_line { ui with max_rem = t.req }
416416+ | Nonflat_span ui -> Nonflat_span { ui with max_rem = mini t.req ui.max_rem }
417417+ in
418418+ t.cache <- Cache result;
419419+ result)
420420+;;
377421378422(* -------------------------------------------------------------------------- *)
379423···383427 match pretty width width doc with
384428 | Nonflat_line t -> t.ui
385429 | Nonflat_span t -> Ui.join_y t.prefix (Ui.join_y t.body t.suffix)
430430+;;
+1-1
forks/nottui/lib/nottui/nottui.ml
···11include Nottui_main
22-module W=Widgets
22+module W = Widgets
+36-20
forks/nottui/lib/nottui/nottui_main.ml
···1414 (** request the focus and add to the focus stack *)
1515 val request_reversable : handle -> unit
16161717- (** Release the focus (if the handle has it) and restore the last focus on the stack *)
1717+ (** Release the focus (if the handle has it) and restore the last focus on the
1818+ stack *)
1819 val release_reversable : handle -> unit
19202021 type status =
···6162 let clock = ref 0
6263 let currently_focused : var ref = ref (make () |> fst)
6364 let focus_stack : var list ref = ref []
6464- let focus_stack_to_str ()=
6565- (!focus_stack|>List.map Lwd.peek|>List.map (string_of_int)|>String.concat ","|>Printf.sprintf "[%s]")
6565+6666+ let focus_stack_to_str () =
6767+ !focus_stack
6868+ |> List.map Lwd.peek
6969+ |> List.map string_of_int
7070+ |> String.concat ","
7171+ |> Printf.sprintf "[%s]"
7272+ ;;
66736767- let focusLock= Mutex.create()
7474+ let focusLock = Mutex.create ()
68756976 let request_var (v : var) =
7077 incr clock;
···7279 currently_focused := v
7380 ;;
74817575- let request ((v, _) : handle) =
7676- Mutex.protect focusLock @@ fun _->
7777- request_var v
8282+ let request ((v, _) : handle) = Mutex.protect focusLock @@ fun _ -> request_var v
78837984 let release ((v, _) : handle) =
8080- Mutex.protect focusLock @@ fun _->
8585+ Mutex.protect focusLock @@ fun _ ->
8186 incr clock;
8287 Lwd.set v 0
8388 ;;
84898590 let var_equal a b = Lwd.peek a = Lwd.peek b
8686-87918892 let request_reversable ((v, _) : handle) =
8989- Mutex.protect focusLock @@ fun _->
9393+ Mutex.protect focusLock @@ fun _ ->
9094 Log.debug (fun m -> m "Maybe requesting reversable focus %d" (Lwd.peek v));
9195 if not @@ var_equal !currently_focused v
9296 then (
9397 focus_stack := !currently_focused :: !focus_stack;
9498 request_var v;
9595- Log.debug (fun m -> m "Requested reversable focus %d. stack:%s" (Lwd.peek v) (focus_stack_to_str ())))
9999+ Log.debug (fun m ->
100100+ m "Requested reversable focus %d. stack:%s" (Lwd.peek v) (focus_stack_to_str ())))
96101 ;;
9710298103 let release_reversable ((v, _) : handle) =
99104 (* Mutex.protect focusLock @@ fun _-> *)
100105 Log.debug (fun m ->
101101- m "Maybe release or remove %d from reversable focus stack. stack: %s" (Lwd.peek v) (focus_stack_to_str ()));
106106+ m
107107+ "Maybe release or remove %d from reversable focus stack. stack: %s"
108108+ (Lwd.peek v)
109109+ (focus_stack_to_str ()));
102110 (* we should only release if we actually have the focus*)
103111 if var_equal !currently_focused v
104112 then (
···323331324332 let pp_main_key ppf = function
325333 | #Unescape.special as special -> pp_special_key ppf special
326326- | `Uchar u ->
327327- if Uchar.is_char u then
328328- Format.fprintf ppf "'%c'" (Uchar.to_char u)
329329- else
330330- Format.fprintf ppf "U+%04X" (Uchar.to_int u)
334334+ | `Uchar u ->
335335+ if Uchar.is_char u
336336+ then Format.fprintf ppf "'%c'" (Uchar.to_char u)
337337+ else Format.fprintf ppf "U+%04X" (Uchar.to_int u)
331338 | `ASCII c -> Format.fprintf ppf "'%c'" c
332339 | #semantic_key as sem -> pp_semantic_key ppf sem
333340 ;;
···702709 else a, b
703710 ;;
704711712712+ (** Allows the element to stretch if possible up to it's max and then returns
713713+ the position change + dimension. *)
705714 let pack ~max ~fixed ~stretch total g1 g2 =
706715 (*flex is the space we should expand into if we stretch*)
707716 let flex = total - fixed in
···714723 in
715724 let gravity = if flex >= 0 then g1 else g2 in
716725 match gravity with
726726+ (*if the gravity is negative then ofcourse it won't move even if it expands so we return 0 position change *)
717727 | `Negative -> 0, fixed
718728 | `Neutral -> flex / 2, fixed
719729 | `Positive -> flex, fixed)
···748758 update_sensors ox oy sw sh mw mh t;
749759 sensor ()
750760 | Resize (t, g, _) ->
761761+ (* think this is the real width and the real height plus the change in x and y position to account for that changed size*)
751762 let open Gravity in
752763 let dx, rw = pack ~max:t.mw ~fixed:t.w ~stretch:t.sw sw (h (p1 g)) (h (p2 g)) in
753764 let dy, rh = pack ~max:t.mh ~fixed:t.h ~stretch:t.sh sh (v (p1 g)) (v (p2 g)) in
···11361147 ?process_event:bool
11371148 -> ?timeout:float
11381149 -> renderer:Renderer.t
11391139- -> cache: image option ref
11501150+ -> cache:image option ref
11401151 -> Term.t
11411152 -> ui Lwd.root
11421153 -> unit
···11661177 let size = Term.size term in
11671178 let image =
11681179 if (not (Lwd.is_damaged root)) && !cache |> Option.is_some
11691169- then !cache |> Option.get
11801180+ then
11811181+ let a= !cache |> Option.get in
11821182+ Log.debug (fun m -> m "not damaged and cache is some returning cached image");
11831183+ a
11701184 else (
11711185 let rec stabilize () =
11861186+ Log.debug (fun m -> m "damaged stabilizing");
11721187 let tree = Lwd.quick_sample root in
11731188 Renderer.update renderer size tree;
11741189 let image = Renderer.image renderer in
···12351250 let root = Lwd.observe ~on_invalidate t in
12361251 let cache = ref None in
12371252 let rec loop () =
12531253+ Log.debug (fun m -> m "loop");
12381254 let quit = Lwd.quick_sample quit in
12391255 if not quit
12401256 then (
12411241- step ~process_event:true ?timeout:tick_period ~renderer ~cache term root ;
12571257+ step ~process_event:true ?timeout:tick_period ~renderer ~cache term root;
12421258 tick ();
12431259 loop ())
12441260 in
···3344let neutral_grav = Gravity.make ~h:`Neutral ~v:`Neutral
55let make_even num = num + (num mod 2 * 1)
66-76let empty_lwd = Lwd.return Ui.empty
87let mini, maxi, clampi = Lwd_utils.(mini, maxi, clampi)
99-108let attr_clickable = A.(bg lightblue)
1191210(** This is for shifting something away from the edge it is pushed against *)
1311let pad_edge x_pad y_pad grav ui =
1412 let y_pad =
1513 match grav |> Gravity.v with
1616- | `Negative ->
1717- -y_pad
1818- | `Neutral ->
1919- 0
2020- | `Positive ->
2121- y_pad
1414+ | `Negative -> -y_pad
1515+ | `Neutral -> 0
1616+ | `Positive -> y_pad
2217 in
2318 match grav |> Gravity.h with
2424- | `Negative ->
2525- ui |> Ui.shift_area (-x_pad) y_pad
2626- | `Neutral ->
2727- ui
2828- | `Positive ->
2929- ui |> Ui.shift_area x_pad y_pad
1919+ | `Negative -> ui |> Ui.shift_area (-x_pad) y_pad
2020+ | `Neutral -> ui
2121+ | `Positive -> ui |> Ui.shift_area x_pad y_pad
3022;;
31233224(** Ui element from a string *)
···8880 let content =
8981 Ui.atom @@ I.hcat [ I.string A.(st underline) (if text = "" then " " else text) ]
9082 in
9191- let handler = (fun x->
9292- x|>function
8383+ let handler =
8484+ fun x ->
8585+ x |> function
9386 | `ASCII 'U', [ `Ctrl ] ->
9487 on_change "";
9588 `Handled (* clear *)
···111104 | `Enter, _ ->
112105 on_submit text;
113106 `Handled
114114- | _ ->
115115- `Unhandled
116116- )
107107+ | _ -> `Unhandled
117108 in
118109 Ui.keyboard_area ~focus handler content
119110 in
···130121(** Stacks Ui elements infront of one another *)
131122let zbox l = Lwd_utils.pack Ui.pack_z l
132123133133-134124(** Horizontal/vertical box. We fill lines until there is no room,
135125 and then go to the next ligne. All widgets in a line are considered to
136126 have the same height.
137127 @param width dynamic width (default 80) *)
138128let flex_box ?(w = Lwd.return 80) (l : Ui.t Lwd.t list) : Ui.t Lwd.t =
139129 let open Lwd.Infix in
140140- Lwd_utils.flatten_l l
141141- >>= fun l ->
142142- w
143143- >|= fun w_limit ->
130130+ Lwd_utils.flatten_l l >>= fun l ->
131131+ w >|= fun w_limit ->
144132 let rec box_render (acc : Ui.t) (i : int) l : Ui.t =
145133 match l with
146134 | [] -> acc
···155143 box_render Ui.empty 0 l
156144;;
157145158158-module List = struct
146146+module List = struct
159147 include List
160148161161-(** intersperse elements of the list with items *)
162162-let intersperse t ~sep =
163163- match t with
164164- | [] -> []
165165- | x :: xs -> x :: fold_right (fun y acc -> sep :: y :: acc) xs []
166166-;;
149149+ (** intersperse elements of the list with items *)
150150+ let intersperse t ~sep =
151151+ match t with
152152+ | [] -> []
153153+ | x :: xs -> x :: fold_right (fun y acc -> sep :: y :: acc) xs []
154154+ ;;
167155end
168156169157(** [on_focus f ui]
···179167let is_focused ~focus f ui =
180168 Lwd.map2 ui (focus |> Focus.status) ~f:(fun ui focus -> f ui (focus |> Focus.has_focus))
181169;;
182182-
···11open Notty
22open Nottui_main
33include module type of Shared
44-val empty_lwd : ui Lwd.t
5455+val empty_lwd : ui Lwd.t
6677(** Vertical pane that can be dragged to be bigger or smaller *)
88val v_pane : ui Lwd.t -> ui Lwd.t -> ui Lwd.t
991010(** horizontal pane that can be dragged to be bigger or smaller *)
1111-val h_pane : ?splitter_color:(Notty.A.color)-> ui Lwd.t -> ui Lwd.t -> ui Lwd.t
1212-1111+val h_pane : ?splitter_color:Notty.A.color -> ui Lwd.t -> ui Lwd.t -> ui Lwd.t
13121413(** An editable text field.
1514 Supports navigating with arrow keys *)
1616-val edit_field :
1717- ?focus:Focus.handle ->
1818- (string * int) Lwd.t ->
1919- on_change:(string * int -> unit) ->
2020- on_submit:(string * int -> unit) -> ui Lwd.t
2121-1515+val edit_field
1616+ : ?focus:Focus.handle
1717+ -> (string * int) Lwd.t
1818+ -> on_change:(string * int -> unit)
1919+ -> on_submit:(string * int -> unit)
2020+ -> ui Lwd.t
22212322(** Shows the summary when folded, calls [f()] to compute a sub-widget when clicked on. Useful for displaying deep trees. Mouse only *)
2424-val unfoldable :
2525- ?folded_by_default:bool ->
2626- ui Lwd.t -> (unit -> ui Lwd.t) -> ui Lwd.t
2727-2323+val unfoldable : ?folded_by_default:bool -> ui Lwd.t -> (unit -> ui Lwd.t) -> ui Lwd.t
28242929-val grid :
3030- ?max_h:int -> ?max_w:int ->
3131- ?pad:gravity -> ?crop:gravity -> ?bg:attr ->
3232- ?h_space:int -> ?v_space:int ->
3333- ?headers:ui Lwd.t list ->
3434- ui Lwd.t list list -> ui Lwd.t
2525+val grid
2626+ : ?max_h:int
2727+ -> ?max_w:int
2828+ -> ?pad:gravity
2929+ -> ?crop:gravity
3030+ -> ?bg:attr
3131+ -> ?h_space:int
3232+ -> ?v_space:int
3333+ -> ?headers:ui Lwd.t list
3434+ -> ui Lwd.t list list
3535+ -> ui Lwd.t
35363637(** A clickable button that calls [f] when clicked, labelled with a string. *)
3738val button : ?attr:attr -> string -> (unit -> unit) -> ui
3838-39394040(** A toggle button that invokes the callback when toggled*)
4141val toggle : ?init:bool -> string Lwd.t -> (bool -> unit) -> ui Lwd.t
+10-12
forks/nottui/lib/nottui/widgets/old.ml
···5555 let catchall =
5656 Ui.mouse_area
5757 (fun ~x:_ ~y:_ -> function
5858- | `Left ->
5959- Lwd_table.remove row;
6060- `Handled
6161- | _ -> `Handled)
5858+ | `Left ->
5959+ Lwd_table.remove row;
6060+ `Handled
6161+ | _ -> `Handled)
6262 (Ui.resize ~sw:1 ~sh:1 ~mw:1000 ~mh:1000 Ui.empty)
6363 in
6464 Ui.join_z catchall @@ Ui.join_y v_pad @@ Ui.join_x h_pad @@ Ui.join_z bg body)
···305305 | [] -> Lwd.return Ui.empty
306306 | _ ->
307307 let cur = Lwd.var 0 in
308308- Lwd.get cur
309309- >>= fun idx_sel ->
308308+ Lwd.get cur >>= fun idx_sel ->
310309 let _, f = List.nth tabs idx_sel in
311310 let tab_bar =
312311 tabs
···315314 let tab_annot = printf ~attr "[%s]" s in
316315 Ui.mouse_area
317316 (fun ~x:_ ~y:_ l ->
318318- if l = `Left
319319- then (
320320- Lwd.set cur i;
321321- `Handled)
322322- else `Unhandled)
317317+ if l = `Left
318318+ then (
319319+ Lwd.set cur i;
320320+ `Handled)
321321+ else `Unhandled)
323322 tab_annot)
324323 |> Ui.hcat
325324 in
326325 f () >|= Ui.join_y tab_bar
327326;;
328328-
+8-15
forks/nottui/lib/nottui/widgets/overlays.ml
···2525let set_bg ~attr ui =
2626 let size = Lwd.var (0, 0) in
2727 W.zbox
2828- [ (size
2929- |> Lwd.get
3030- |>$ fun (w, h) -> I.char attr ' ' w h |> Ui.atom |> Ui.resize ~w:0 ~h:0)
2828+ [ ( size |> Lwd.get |>$ fun (w, h) ->
2929+ I.char attr ' ' w h |> Ui.atom |> Ui.resize ~w:0 ~h:0 )
3130 ; ui |>$ Ui.size_sensor (fun ~w ~h -> if (w, h) <> Lwd.peek size then size $= (w, h))
3231 ]
3332;;
···5049 let$* show_prompt_val = show_prompt in
5150 let prompt_ui =
5251 show_prompt_val
5353- |> Option.map
5454- @@ fun (label, label_bottom, on_exit, prompt_content) ->
5252+ |> Option.map @@ fun (label, label_bottom, on_exit, prompt_content) ->
5553 (*we need focus because the base ui is rendering first and so *)
5654 Focus.request_reversable focus;
5755 let$* label_bottom = label_bottom in
···9694 let prompt_args =
9795 let$ show_prompt_val = Lwd.get show_prompt_var in
9896 show_prompt_val
9999- |> Option.map
100100- @@ fun { label; pre_fill; on_exit } ->
9797+ |> Option.map @@ fun { label; pre_fill; on_exit } ->
10198 let on_exit result =
10299 Focus.release_reversable focus;
103100 show_prompt_var $= None;
···147144 let prompt_args =
148145 let$ show_prompt_val = Lwd.get show_prompt_var in
149146 show_prompt_val
150150- |> Option.map
151151- @@ fun { label; items; on_exit } ->
147147+ |> Option.map @@ fun { label; items; on_exit } ->
152148 let on_exit result =
153149 Focus.release_reversable focus;
154150 show_prompt_var $= None;
···195191 let prompt_args =
196192 let$ show_prompt_val = Lwd.get show_prompt_var in
197193 show_prompt_val
198198- |> Option.map
199199- @@ fun { label; items; filter_predicate; on_exit } ->
194194+ |> Option.map @@ fun { label; items; filter_predicate; on_exit } ->
200195 let on_exit result =
201196 Focus.release_reversable focus;
202197 show_prompt_var $= None;
···230225 let$ prompt_field = content in
231226 prompt_field |> Ui.resize ~w:5 ~sw:1
232227 in
233233- ui
234234- |> BB.focusable ~focus ~label_top:label ?on_key
235235- |> clear_bg
228228+ ui |> BB.focusable ~focus ~label_top:label ?on_key |> clear_bg
236229 (*This is a little confusing, but by wrapping the content in 2 nested keyboard areas we make it the user cannot escape the popup.
237230 becasue focus moves between keyboard areas within a current keyboard area by adding 2 we make escape impossible *)
238231 (* |> Lwd.map ~f:(fun ui -> *)
239239- (* ui |> Ui.keyboard_area (fun x -> `Unhandled)) *)
232232+ (* ui |> Ui.keyboard_area (fun x -> `Unhandled)) *)
240233 | None ->
241234 Focus.release_reversable focus;
242235 Ui.empty |> Lwd.pure
+45-44
forks/nottui/lib/nottui/widgets/overlays.mli
···1010(**Clears anything behind the given area*)
1111val clear_bg : Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
12121313-1414-1515- (** Config for a text_prompt*)
1616-type text_prompt_data = {
1717- label : string;
1818- pre_fill : string;
1919- on_exit : [ `Closed | `Finished of string ] -> unit;
2020-}
1313+(** Config for a text_prompt*)
1414+type text_prompt_data =
1515+ { label : string
1616+ ; pre_fill : string
1717+ ; on_exit : [ `Closed | `Finished of string ] -> unit
1818+ }
21192220(** Text box prompt that takes user input then calls [on_exit] with the result.
23212422This will display ontop of any ui it is passed when show_prompt_var is [Some].*)
25232626-val text_prompt :
2727- ?pad_h:int ->
2828- ?pad_w:int ->
2929- ?modify_body:(Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t) ->
3030- ?focus:Nottui_main.Focus.handle ->
3131- ?char_count:bool ->
3232- show_prompt_var:text_prompt_data option Lwd.var ->
3333- Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
2424+val text_prompt
2525+ : ?pad_h:int
2626+ -> ?pad_w:int
2727+ -> ?modify_body:(Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t)
2828+ -> ?focus:Nottui_main.Focus.handle
2929+ -> ?char_count:bool
3030+ -> show_prompt_var:text_prompt_data option Lwd.var
3131+ -> Nottui_main.ui Lwd.t
3232+ -> Nottui_main.ui Lwd.t
34333534(** Config for a selection_list_prompt*)
3636-type 'a selection_list_prompt_data = {
3737- label : string;
3838- items : 'a Selection_list.multi_selectable_item list Lwd.t;
3939- on_exit : [ `Closed | `Finished of 'a ] -> unit;
4040-}
3535+type 'a selection_list_prompt_data =
3636+ { label : string
3737+ ; items : 'a Selection_list.multi_selectable_item list Lwd.t
3838+ ; on_exit : [ `Closed | `Finished of 'a ] -> unit
3939+ }
41404241(** Selection_list prompt.
43424443This will display ontop of any ui it is passed when show_prompt_var is [Some].
4544@param modify_body Function that takes the completed body of the prompt, incase you want to resize it or otherwise change it
4645*)
4747-val selection_list_prompt :
4848- ?pad_w:int ->
4949- ?pad_h:int ->
5050- ?modify_body:(Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t) ->
5151- ?focus:Nottui_main.Focus.handle ->
5252- show_prompt_var:'a selection_list_prompt_data option Lwd.var ->
5353- Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
5454-4646+val selection_list_prompt
4747+ : ?pad_w:int
4848+ -> ?pad_h:int
4949+ -> ?modify_body:(Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t)
5050+ -> ?focus:Nottui_main.Focus.handle
5151+ -> show_prompt_var:'a selection_list_prompt_data option Lwd.var
5252+ -> Nottui_main.ui Lwd.t
5353+ -> Nottui_main.ui Lwd.t
55545655type 'a filterable_selection_list_prompt_data =
5756 { label : string
5857 ; items : 'a Selection_list.multi_selectable_item list Lwd.t
5959- ;filter_predicate:(string-> 'a-> bool)
5858+ ; filter_predicate : string -> 'a -> bool
6059 ; on_exit : [ `Closed | `Finished of 'a ] -> unit
6160 }
6161+6262(** Selection_list prompt that is filterable.
63636464This will display ontop of any ui it is passed when show_prompt_var is [Some].
6565@param modify_body Function that takes the completed body of the prompt, incase you want to resize it or otherwise change it
6666*)
6767-val selection_list_prompt_filterable :
6868- ?pad_w:int ->
6969- ?pad_h:int ->
7070- ?modify_body:(Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t) ->
7171- ?focus:Nottui_main.Focus.handle ->
7272- show_prompt_var:'a filterable_selection_list_prompt_data option Lwd.var ->
7373- Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
7474-6767+val selection_list_prompt_filterable
6868+ : ?pad_w:int
6969+ -> ?pad_h:int
7070+ -> ?modify_body:(Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t)
7171+ -> ?focus:Nottui_main.Focus.handle
7272+ -> show_prompt_var:'a filterable_selection_list_prompt_data option Lwd.var
7373+ -> Nottui_main.ui Lwd.t
7474+ -> Nottui_main.ui Lwd.t
75757676- (**This is a simple popup that can show ontop of other ui elements *)
7777-val popup :
7878- ?focus:Nottui_main.Focus.handle ->
7979- ?on_key:(Nottui_main.Ui.key->Nottui_main.Ui.may_handle)->
8080- show_popup_var:(Nottui_main.ui Lwd.t * string) option Lwd.var ->
8181- Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
7676+(**This is a simple popup that can show ontop of other ui elements *)
7777+val popup
7878+ : ?focus:Nottui_main.Focus.handle
7979+ -> ?on_key:(Nottui_main.Ui.key -> Nottui_main.Ui.may_handle)
8080+ -> show_popup_var:(Nottui_main.ui Lwd.t * string) option Lwd.var
8181+ -> Nottui_main.ui Lwd.t
8282+ -> Nottui_main.ui Lwd.t
+5-1
forks/nottui/lib/nottui/widgets/scroll.mli
···22val v_area : ?reset_on_content_change:bool -> Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
3344(** A scroll area that allows keyboard scrolling in both x and y directions*)
55-val area : ?reset_on_content_change:bool -> ?focus:Nottui_main.Focus.status -> Nottui_main.ui Lwd.t -> Nottui_main.ui Lwd.t
55+val area
66+ : ?reset_on_content_change:bool
77+ -> ?focus:Nottui_main.Focus.status
88+ -> Nottui_main.ui Lwd.t
99+ -> Nottui_main.ui Lwd.t
610711(** A scroll area that allows keyboard scrolling in both x and y directions and has no limits.
812 This might be useful if you have some very dynamic content and the usual scroll area doesn't know how big things are*)
+69-72
forks/nottui/lib/nottui/widgets/selection_list.ml
···1616 | Filler of Ui.t Lwd.t
17171818module MyMap = Map.Make (Int)
1919-let singe_space= Shared.string " ";;
1919+2020+let singe_space = Shared.string " "
20212122(** Get a map of all the selectable items*)
2223let get_selectable_items_map (items : 'a maybe_multi_selectable array Lwd.t) =
···2627 items
2728 |> Array.fold_left
2829 (fun map item ->
2929- match item with
3030- | Selectable item -> MyMap.add item.id (item.id, item) map
3131- | Filler _ -> map)
3030+ match item with
3131+ | Selectable item -> MyMap.add item.id (item.id, item) map
3232+ | Filler _ -> map)
3233 MyMap.empty
3334 in
3435 selectable_items
···4647 items
4748 |> Array.fold_left
4849 (fun (i, selectable_count) item ->
4949- match item with
5050- | Selectable item ->
5151- (*copy any seletable items to the new array*)
5252- Array.set selectable_items selectable_count (i, item);
5353- i + 1, selectable_count + 1
5454- | Filler _ -> i + 1, selectable_count)
5050+ match item with
5151+ | Selectable item ->
5252+ (*copy any seletable items to the new array*)
5353+ Array.set selectable_items selectable_count (i, item);
5454+ i + 1, selectable_count + 1
5555+ | Filler _ -> i + 1, selectable_count)
5556 (0, 0)
5657 in
5758 Array.sub selectable_items 0 final_len
···6061;;
61626263let multi_selection_list_exclusions
6363- ?(focus = Focus.make ())
6464- ?reset_selections
6565- ?(on_selection_change = fun ~hovered ~selected -> ())
6666- ~custom_handler
6767- (items : 'a maybe_multi_selectable array Lwd.t)
6464+ ?(focus = Focus.make ())
6565+ ?reset_selections
6666+ ?(on_selection_change = fun ~hovered ~selected -> ())
6767+ ~custom_handler
6868+ (items : 'a maybe_multi_selectable array Lwd.t)
6869 =
6970 (*
7071 The rough overview is:
···111112 selectable_items
112113 |> Array.fold_left
113114 (fun (count, acc) (idx, item) ->
114114- let nCount = count + 1 in
115115- match acc with
116116- | `Found _ -> nCount, acc
117117- | `Same_idx _ ->
118118- if item.id = hovered_id
119119- then nCount, `Found (item.id, idx, count)
120120- else nCount, acc
121121- | `Searching _ ->
122122- if item.id = hovered_id
123123- then nCount, `Found (item.id, idx, count)
124124- else if count == hovered_selection_idx
125125- then nCount, `Same_idx (item.id, idx, count)
126126- else nCount, `Searching (item.id, idx, count))
115115+ let nCount = count + 1 in
116116+ match acc with
117117+ | `Found _ -> nCount, acc
118118+ | `Same_idx _ ->
119119+ if item.id = hovered_id
120120+ then nCount, `Found (item.id, idx, count)
121121+ else nCount, acc
122122+ | `Searching _ ->
123123+ if item.id = hovered_id
124124+ then nCount, `Found (item.id, idx, count)
125125+ else if count == hovered_selection_idx
126126+ then nCount, `Same_idx (item.id, idx, count)
127127+ else nCount, `Searching (item.id, idx, count))
127128 (0, `Searching (0, 0, 0))
128129 |> snd
129130 |> function
···144145 and$ _ = Lwd.get hover_changed
145146 and$ selected_items = Lwd.get selected_items_var in
146147 (* FIXME: can i just get rid of all the other parts of the hovered var now that we store the id?*)
147147- let hovered_id, _, _= !hovered_var in
148148+ let hovered_id, _, _ = !hovered_var in
148149 (*==== Rendering The list ====*)
149150 (* Ui.vcat can be a little weird when the *)
150151 if items |> Array.length = 0
···154155 |> Array.mapi (fun i x ->
155156 match x with
156157 (*Becasue selectable has a space used for the selection pointer, filler also needs a space*)
157157- | Filler ui -> ui|>$(fun x-> Ui.hcat[ singe_space ; x])
158158+ | Filler ui -> ui |>$ fun x -> Ui.hcat [ singe_space; x ]
158159 | Selectable x ->
159160 let hovered = hovered_id == x.id in
160161 let selected = selected_items |> MyMap.mem x.id in
···251252;;
252253253254let selection_list_exclusions
254254- ?(focus = Focus.make ())
255255- ?(on_selection_change = fun _ -> ())
256256- ~custom_handler
257257- (items : 'a maybe_multi_selectable array Lwd.t)
255255+ ?(focus = Focus.make ())
256256+ ?(on_selection_change = fun _ -> ())
257257+ ~custom_handler
258258+ (items : 'a maybe_multi_selectable array Lwd.t)
258259 =
259260 (*
260261 The rough overview is:
···300301 |> Array.mapi (fun i x ->
301302 match x with
302303 (*Becasue selectable has a space used for the selection pointer, filler also needs a space*)
303303- | Filler ui -> ui|>$(fun x-> Ui.hcat[ singe_space ; x])
304304+ | Filler ui -> ui |>$ fun x -> Ui.hcat [ singe_space; x ]
304305 | Selectable x ->
305306 if hovered == i
306307 then
···393394;;
394395395396let multi_selection_list_custom
396396- ?(focus = Focus.make ())
397397- ?reset_selections
398398- ?(on_selection_change = fun ~hovered ~selected -> ())
399399- ~custom_handler
400400- (items : 'a multi_selectable_item list Lwd.t)
397397+ ?(focus = Focus.make ())
398398+ ?reset_selections
399399+ ?(on_selection_change = fun ~hovered ~selected -> ())
400400+ ~custom_handler
401401+ (items : 'a multi_selectable_item list Lwd.t)
401402 =
402403 multi_selection_list_exclusions
403404 ~focus
404405 ?reset_selections
405406 ~on_selection_change
406407 ~custom_handler
407407- (items
408408- |>$ fun items ->
409409- let selectable_items = Array.make (List.length items) (Obj.magic ()) in
410410- items |> List.iteri (fun i x -> Array.set selectable_items i (Selectable x));
411411- selectable_items)
408408+ ( items |>$ fun items ->
409409+ let selectable_items = Array.make (List.length items) (Obj.magic ()) in
410410+ items |> List.iteri (fun i x -> Array.set selectable_items i (Selectable x));
411411+ selectable_items )
412412;;
413413414414let selection_list_custom
415415- ?(focus = Focus.make ())
416416- ?(on_selection_change = fun _ -> ())
417417- ~custom_handler
418418- (items : 'a multi_selectable_item list Lwd.t)
415415+ ?(focus = Focus.make ())
416416+ ?(on_selection_change = fun _ -> ())
417417+ ~custom_handler
418418+ (items : 'a multi_selectable_item list Lwd.t)
419419 =
420420 selection_list_exclusions
421421 ~focus
422422 ~on_selection_change
423423 ~custom_handler
424424- (items
425425- |>$ fun items ->
426426- let selectable_items = Array.make (List.length items) (Obj.magic ()) in
427427- items |> List.iteri (fun i x -> Array.set selectable_items i (Selectable x));
428428- selectable_items)
424424+ ( items |>$ fun items ->
425425+ let selectable_items = Array.make (List.length items) (Obj.magic ()) in
426426+ items |> List.iteri (fun i x -> Array.set selectable_items i (Selectable x));
427427+ selectable_items )
429428;;
430429431430let filterable_selection_list_custom
432432- ?(focus = Focus.make ())
433433- ~(filter_predicate : string -> 'a -> bool)
434434- ~custom_handler
435435- ~filter_text_var
436436- (items : 'a multi_selectable_item list Lwd.t)
431431+ ?(focus = Focus.make ())
432432+ ~(filter_predicate : string -> 'a -> bool)
433433+ ~custom_handler
434434+ ~filter_text_var
435435+ (items : 'a multi_selectable_item list Lwd.t)
437436 =
438437 (*filter the list whenever the input changes*)
439438 let items =
···454453;;
455454456455let filterable_selection_list
457457- ?(pad_w = 1)
458458- ?(pad_h = 0)
459459- ?(focus = Focus.make ())
460460- ~filter_predicate
461461- ?(on_esc = fun _ -> ())
462462- ~on_confirm
463463- list_items
456456+ ?(pad_w = 1)
457457+ ?(pad_h = 0)
458458+ ?(focus = Focus.make ())
459459+ ~filter_predicate
460460+ ?(on_esc = fun _ -> ())
461461+ ~on_confirm
462462+ list_items
464463 =
465464 let filter_text_var = Lwd.var "" in
466465 let filter_text_ui =
···490489 let max_width = Lwd.var 5 in
491490 vbox
492491 [ filter_text_ui |> Border_box.box ~pad_w ~pad_h
493493- ; (list_ui
494494- |> Border_box.box ~pad_w ~pad_h
495495- |>$ fun x ->
496496- let mw = (x |> Ui.layout_spec).mw in
497497- if mw > Lwd.peek max_width then max_width $= mw;
498498- x)
492492+ ; ( list_ui |> Border_box.box ~pad_w ~pad_h |>$ fun x ->
493493+ let mw = (x |> Ui.layout_spec).mw in
494494+ if mw > Lwd.peek max_width then max_width $= mw;
495495+ x )
499496 ]
500497 |> Lwd.map2 (Lwd.get max_width) ~f:(fun mw ui -> ui |> Ui.resize ~mw)
501498;;
···44(**Selectable list item with a ui and some data *)
55type 'a multi_selectable_item =
66 { data : 'a
77- (**info attached to each ui elment in the list, used for filtering and on_select callback *)
77+ (**info attached to each ui elment in the list, used for filtering and on_select callback *)
88 ; id : int
99 ; ui : selected:bool -> hovered:bool -> Ui.t Lwd.t
1010 }
···88open Notty
99open Notty_unix
10101111+module Log = (val Logs.src_log (Logs.Src.create "nottui_picos") : Logs.LOG)
1212+1113(*Super simple method for tracking invalidations that occur outside of a computation using picos.
1214We already track and apply invaldations that happen within a ui recompute
1315*)
···1719 let start_tracking tracker = tracker := Computation.create ()
1820 let create () : t = Computation.create () |> ref
1921 let invalidated_evt tracker = Event.from_computation !tracker
2222+ (* TODO: add a slight delay to the invalidation so that if many invalidations come in concurrently it batches them. Something like 5ms *)
2023 let invalidate (tracker : t) = Computation.finish !tracker
2124end
2225···3437 ; It.invalidated_evt invalidation_tracker
3538 |> Event.map (fun _ -> `LwdStateUpdate)
3639 ]
3737- in
4040+ in
3841 ret
3942 in
4043 select ()
···5356 let size = Term.size term in
5457 let image =
5558 if (not (Lwd.is_damaged root)) && !cache |> Option.is_some
5656- then !cache |> Option.get
5959+ then
6060+ let a= !cache |> Option.get in
6161+ (* Log.debug (fun m -> m "not damaged and cache is some returning cached image"); *)
6262+ a
5763 else (
5864 let rec stabilize () =
6565+ (* Log.debug (fun m -> m "stabilize"); *)
6666+ let start_time = Unix.gettimeofday () in
5967 let tree = Lwd.quick_sample root in
6868+ let end_time = Unix.gettimeofday () in
6969+ let duration = end_time -. start_time in
7070+ Printf.eprintf "%f" duration;
6071 Renderer.update renderer size tree;
6172 It.start_tracking invalidation_tracker;
6273 let image = Renderer.image renderer in
7474+6375 (* If we are already damaged then we should re-calculate*)
6476 if Lwd.is_damaged root then stabilize () else image
6577 in
6678 stabilize ())
6779 in
6880 cache := Some image;
8181+ (* Log.debug (fun m -> m "redrawing terminal with image: hash: %d" (Hashtbl.hash image)); *)
6982 Term.image term image;
7083 (* Now we wait for another event or the timeout*)
7184 if process_event
···103116 a := !a + 1;
104117 let cache = ref None in
105118 Ui_loop.Internal.run_with_term
119119+ (* tracks root invalidation so we can recompute on invalidation*)
106120 ~on_invalidate:(fun _ -> It.invalidate invalidation_tracker)
107121 ~step:
108122 (step
···11-type post = {
22- id : int;
33- title : string;
44- url : string;
55- score : int;
66- comments : int;
77- kids: int list;
88-}
11+type post =
22+ { id : int
33+ ; title : string
44+ ; url : string
55+ ; score : int
66+ ; comments : int
77+ ; kids : int list
88+ }
991010(** generates a list of child ids, skewed twards low numbers *)
1111-let generate_kids_list()=
1212-1313-List.init (Float.pow ((Random.float 10.0)/. 3.0) 6.0|>Int.of_float) (fun _ -> Random.int 10000000 + 2000000)
1111+let generate_kids_list () =
1212+ List.init
1313+ (Float.pow (Random.float 10.0 /. 3.0) 6.0 |> Int.of_float)
1414+ (fun _ -> Random.int 10000000 + 2000000)
1515+;;
14161517(** returns a list of posts from hackernews*)
1618let fake_posts () =
1717- let titles = [
1818- "OCaml 5.0 Released: What’s New?";
1919- "Why Functional Programming Matters";
2020- "Building Scalable Systems with OCaml";
2121- "Understanding Type Systems";
2222- "Introduction to Category Theory";
2323- "The Future of Multi-Core OCaml";
2424- "How to Contribute to Open Source Projects";
2525- "OCaml vs Haskell: A Comparison";
2626- "Getting Started with MirageOS";
2727- "Real-World Applications of OCaml"
2828- ] in
2929- let urls = [
3030- "https://ocaml.com/ocaml-5-released";
3131- "https://functional.com/functional-programming-matters";
3232- "https://scaleable.com/building-scalable-systems";
3333- "https://understanding.com/understanding-type-systems";
3434- "https://theory.com/introduction-to-category-theory";
3535- "https://multicore.com/future-of-multicore-ocaml";
3636- "https://contrib.com/contributing-to-open-source";
3737- "https://haskell.com/ocaml-vs-haskell";
3838- "https://migrations.com/getting-started-mirageos";
3939- "https://realworldocaml.com/real-world-applications-ocaml"
4040- ] in
1919+ let titles =
2020+ [ "OCaml 5.0 Released: What’s New?"
2121+ ; "Why Functional Programming Matters"
2222+ ; "Building Scalable Systems with OCaml"
2323+ ; "Understanding Type Systems"
2424+ ; "Introduction to Category Theory"
2525+ ; "The Future of Multi-Core OCaml"
2626+ ; "How to Contribute to Open Source Projects"
2727+ ; "OCaml vs Haskell: A Comparison"
2828+ ; "Getting Started with MirageOS"
2929+ ; "Real-World Applications of OCaml"
3030+ ]
3131+ in
3232+ let urls =
3333+ [ "https://ocaml.com/ocaml-5-released"
3434+ ; "https://functional.com/functional-programming-matters"
3535+ ; "https://scaleable.com/building-scalable-systems"
3636+ ; "https://understanding.com/understanding-type-systems"
3737+ ; "https://theory.com/introduction-to-category-theory"
3838+ ; "https://multicore.com/future-of-multicore-ocaml"
3939+ ; "https://contrib.com/contributing-to-open-source"
4040+ ; "https://haskell.com/ocaml-vs-haskell"
4141+ ; "https://migrations.com/getting-started-mirageos"
4242+ ; "https://realworldocaml.com/real-world-applications-ocaml"
4343+ ]
4444+ in
4145 let rec make_posts ids titles urls scores comments acc =
4242- match (ids, titles, urls, scores, comments) with
4343- | ([], [], [], [], []) -> List.rev acc
4444- | (id::ids_tail, title::titles_tail, url::urls_tail, score::scores_tail, comment::comments_tail) ->
4545- let post = {id; title; url; score; comments = comment; kids=generate_kids_list()} in
4646- make_posts ids_tail titles_tail urls_tail scores_tail comments_tail (post :: acc)
4646+ match ids, titles, urls, scores, comments with
4747+ | [], [], [], [], [] -> List.rev acc
4848+ | ( id :: ids_tail
4949+ , title :: titles_tail
5050+ , url :: urls_tail
5151+ , score :: scores_tail
5252+ , comment :: comments_tail ) ->
5353+ let post =
5454+ { id; title; url; score; comments = comment; kids = generate_kids_list () }
5555+ in
5656+ make_posts ids_tail titles_tail urls_tail scores_tail comments_tail (post :: acc)
4757 | _ -> acc
4858 in
4949- let ids = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in
5050- let scores = [120; 85; 99; 75; 110; 95; 130; 90; 70; 80] in
5151- let comments = [15; 25; 30; 20; 35; 40; 50; 45; 10; 5] in
5959+ let ids = [ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ] in
6060+ let scores = [ 120; 85; 99; 75; 110; 95; 130; 90; 70; 80 ] in
6161+ let comments = [ 15; 25; 30; 20; 35; 40; 50; 45; 10; 5 ] in
5262 make_posts ids titles urls scores comments []
6363+;;
53645454- type comment = {
5555- by : string;
5656- id : int;
5757- kids : int list;
5858- parent : int;
5959- text : string;
6060- time : int;
6161- comment_type : string;
6262-}
6565+type comment =
6666+ { by : string
6767+ ; id : int
6868+ ; kids : int list
6969+ ; parent : int
7070+ ; text : string
7171+ ; time : int
7272+ ; comment_type : string
7373+ }
63746475let generate_fake_comment parent_id comment_id =
6565- let authors = ["ocaml_fan"; "functional_guru"; "type_safety_advocate"; "pattern_matcher"; "monad_master"] in
6666- let texts = [
6767- "Great article! I've been using OCaml for years and it never ceases to amaze me.";
6868- "I disagree with some points, but overall a good read.";
6969- "Has anyone tried implementing this in a production environment?";
7070- "This reminds me of a similar approach we took in our project. It worked wonders!";
7171- "I'd love to see a follow-up article exploring this topic further.";
7272- "The author makes some interesting points, but I think they're overlooking some key issues.";
7373- "This is a game-changer for functional programming. Can't wait to try it out!";
7474- "I'm skeptical about the performance claims. Has anyone done benchmarks?";
7575- "As always, it depends on the specific use case. YMMV.";
7676- "I've been waiting for something like this for a long time. Thanks for sharing!"
7777- ] in
7878- {
7979- by = List.nth authors (Random.int (List.length authors));
8080- id = comment_id;
8181- kids = generate_kids_list();
8282- parent = parent_id;
8383- text = List.nth texts (Random.int (List.length texts));
8484- time = int_of_float (Unix.time ()) - Random.int 86400; (* Random time within last 24 hours *)
8585- comment_type = "comment";
7676+ let authors =
7777+ [ "ocaml_fan"
7878+ ; "functional_guru"
7979+ ; "type_safety_advocate"
8080+ ; "pattern_matcher"
8181+ ; "monad_master"
8282+ ]
8383+ in
8484+ let texts =
8585+ [ "Great article! I've been using OCaml for years and it never ceases to amaze me."
8686+ ; "I disagree with some points, but overall a good read."
8787+ ; "Has anyone tried implementing this in a production environment?"
8888+ ; "This reminds me of a similar approach we took in our project. It worked wonders!"
8989+ ; "I'd love to see a follow-up article exploring this topic further."
9090+ ; "The author makes some interesting points, but I think they're overlooking some \
9191+ key issues."
9292+ ; "This is a game-changer for functional programming. Can't wait to try it out!"
9393+ ; "I'm skeptical about the performance claims. Has anyone done benchmarks?"
9494+ ; "As always, it depends on the specific use case. YMMV."
9595+ ; "I've been waiting for something like this for a long time. Thanks for sharing!"
9696+ ]
9797+ in
9898+ { by = List.nth authors (Random.int (List.length authors))
9999+ ; id = comment_id
100100+ ; kids = generate_kids_list ()
101101+ ; parent = parent_id
102102+ ; text = List.nth texts (Random.int (List.length texts))
103103+ ; time = int_of_float (Unix.time ()) - Random.int 86400
104104+ ; (* Random time within last 24 hours *)
105105+ comment_type = "comment"
86106 }
107107+;;
8710888109(*generates a comment with some number of children mostly those comments will have no children, but some will*)
8989-let generate_fake_comments count parent_id =
9090- List.init count (fun _ -> generate_fake_comment parent_id (Random.int 10000000 + 2000000))
110110+let generate_fake_comments count parent_id =
111111+ List.init count (fun _ ->
112112+ generate_fake_comment parent_id (Random.int 10000000 + 2000000))
113113+;;
+4-5
forks/nottui/tutorial/src/tangle.ml
···48484949 (* Parser for $#<number> fold <name> *)
5050 let parse_fold =
5151- string "$#" *> parse_number
5252- <* string " fold "
5353- >>= fun n -> take_while1 Char.(fun c -> c <> '\n') >>| fun name -> Fold (n, name)
5151+ string "$#" *> parse_number <* string " fold " >>= fun n ->
5252+ take_while1 Char.(fun c -> c <> '\n') >>| fun name -> Fold (n, name)
5453 ;;
55545655 (* Combine all parsers *)
···169168 files
170169 |> List.filter_map ~f:(fun f ->
171170 let path = Stdlib.Filename.concat input_path f in
172172- if (not (Stdlib.Filename.check_suffix f ".md"))
173173- && not (Stdlib.Sys.is_directory path)
171171+ if
172172+ (not (Stdlib.Filename.check_suffix f ".md")) && not (Stdlib.Sys.is_directory path)
174173 then Some path
175174 else None)
176175 in
···11+setting value
22+finished setting value
33+setting value
44+finished setting value
55+setting value
66+finished setting value
77+setting value
88+finished setting value
99+setting value
1010+finished setting value
1111+setting value
1212+finished setting value
1313+setting value
1414+finished setting value
1515+setting value
1616+finished setting value
1717+setting value
1818+finished setting value
1919+setting value
2020+finished setting value
2121+setting value
2222+finished setting value
2323+setting value
2424+finished setting value
2525+setting value
2626+finished setting value
2727+setting value
2828+finished setting value
2929+setting value
3030+finished setting value
3131+setting value
3232+finished setting value
3333+setting value
3434+finished setting value
3535+setting value
3636+finished setting value
3737+setting value
3838+finished setting value
3939+setting value
4040+finished setting value
4141+setting value
4242+finished setting value
4343+setting value
4444+finished setting value
4545+setting value
4646+finished setting value
4747+setting value
4848+finished setting value
4949+setting value
5050+finished setting value
5151+setting value
5252+finished setting value
5353+setting value
5454+finished setting value
5555+setting value
5656+finished setting value
5757+setting value
5858+finished setting value
5959+setting value
6060+finished setting value
6161+setting value
6262+setting value
6363+finished setting value
6464+finished setting value
6565+setting value
6666+finished setting value
6767+setting value
6868+finished setting value
6969+setting value
7070+finished setting value
7171+setting value
7272+finished setting value
7373+setting value
7474+finished setting value
7575+setting value
7676+finished setting value
7777+setting value
7878+finished setting value
7979+setting value
8080+finished setting value
8181+setting value
8282+finished setting value
8383+setting value
8484+finished setting value
8585+setting value
8686+finished setting value
8787+setting value
8888+finished setting value
8989+setting value
9090+finished setting value
9191+setting value
9292+finished setting value
9393+setting value
9494+finished setting value
9595+setting value
9696+finished setting value
9797+setting value
9898+finished setting value
9999+setting value
100100+finished setting value
101101+setting value
102102+finished setting value
103103+setting value
104104+finished setting value
105105+setting value
106106+finished setting value
107107+setting value
108108+finished setting value
109109+setting value
110110+finished setting value
111111+setting value
112112+finished setting value
113113+setting value
114114+finished setting value
115115+setting value
116116+finished setting value
117117+setting value
118118+finished setting value
119119+setting value
120120+finished setting value
121121+setting value
122122+finished setting value
123123+setting value
124124+finished setting value
125125+setting value
126126+finished setting value
127127+setting value
128128+finished setting value
129129+setting value
130130+finished setting value
131131+setting value
132132+finished setting value
133133+setting value
134134+finished setting value
135135+setting value
136136+finished setting value
137137+setting value
138138+finished setting value
139139+setting value
140140+finished setting value
141141+setting value
142142+finished setting value
143143+setting value
144144+finished setting value
145145+setting value
146146+finished setting value
147147+setting value
148148+finished setting value
149149+setting value
150150+finished setting value
151151+setting value
152152+finished setting value
153153+setting value
154154+finished setting value
155155+setting value
156156+finished setting value
157157+setting value
158158+finished setting value
159159+setting value
160160+finished setting value
161161+setting value
162162+finished setting value
163163+setting value
164164+finished setting value
165165+setting value
166166+finished setting value
167167+setting value
168168+finished setting value
169169+setting value
170170+finished setting value
171171+setting value
172172+finished setting value
173173+setting value
174174+finished setting value
175175+setting value
176176+finished setting value
177177+setting value
178178+finished setting value
179179+setting value
180180+finished setting value
181181+setting value
182182+finished setting value
183183+setting value
184184+finished setting value
185185+setting value
186186+finished setting value
187187+setting value
188188+finished setting value
189189+setting value
190190+finished setting value
191191+setting value
192192+finished setting value
193193+setting value
194194+finished setting value
195195+setting value
196196+finished setting value
197197+setting value
198198+finished setting value
199199+setting value
200200+finished setting value
201201+setting value
202202+finished setting value
203203+setting value
204204+finished setting value
205205+setting value
206206+finished setting value
207207+setting value
208208+finished setting value
209209+setting value
210210+finished setting value
211211+setting value
212212+finished setting value
213213+setting value
214214+finished setting value
215215+setting value
216216+finished setting value
217217+setting value
218218+finished setting value
219219+setting value
220220+finished setting value
221221+setting value
222222+finished setting value
223223+setting value
224224+finished setting value
225225+setting value
226226+finished setting value
227227+setting value
228228+finished setting value
229229+setting value
230230+finished setting value
231231+setting value
232232+finished setting value
233233+setting value
234234+finished setting value
235235+setting value
236236+finished setting value
237237+setting value
238238+finished setting value
239239+setting value
240240+finished setting value
241241+setting value
242242+finished setting value
243243+setting value
244244+finished setting value
245245+setting value
246246+finished setting value
247247+setting value
248248+finished setting value
249249+setting value
250250+finished setting value
251251+setting value
252252+finished setting value
253253+setting value
254254+finished setting value
255255+setting value
256256+finished setting value
257257+setting value
258258+finished setting value
259259+setting value
260260+finished setting value
261261+setting value
262262+finished setting value
263263+setting value
264264+setting value
265265+finished setting value
266266+finished setting value
267267+setting value
268268+finished setting value
269269+setting value
270270+finished setting value
271271+setting value
272272+finished setting value
273273+setting value
274274+finished setting value
275275+setting value
276276+finished setting value
277277+setting value
278278+finished setting value
279279+setting value
280280+finished setting value
281281+setting value
282282+finished setting value
283283+setting value
284284+finished setting value
285285+setting value
286286+finished setting value
287287+setting value
288288+finished setting value
289289+setting value
290290+finished setting value
291291+setting value
292292+finished setting value
293293+setting value
294294+finished setting value
295295+setting value
296296+finished setting value
297297+setting value
298298+finished setting value
299299+setting value
300300+finished setting value
301301+setting value
302302+finished setting value
303303+setting value
304304+finished setting value
305305+setting value
306306+finished setting value
307307+setting value
308308+finished setting value
309309+setting value
310310+finished setting value
311311+setting value
312312+finished setting value
313313+setting value
314314+finished setting value
315315+setting value
316316+finished setting value
317317+setting value
318318+finished setting value
319319+setting value
320320+finished setting value
321321+setting value
322322+finished setting value
323323+setting value
324324+finished setting value
325325+setting value
326326+finished setting value
327327+setting value
328328+finished setting value
329329+setting value
330330+finished setting value
331331+setting value
332332+finished setting value
333333+setting value
334334+finished setting value
335335+setting value
336336+finished setting value
337337+setting value
338338+finished setting value
339339+setting value
340340+finished setting value
341341+setting value
342342+finished setting value
343343+setting value
344344+finished setting value
345345+setting value
346346+finished setting value
347347+setting value
348348+finished setting value
349349+setting value
350350+finished setting value
351351+setting value
352352+finished setting value
353353+setting value
354354+finished setting value
355355+setting value
356356+finished setting value
357357+setting value
358358+finished setting value
359359+setting value
360360+finished setting value
361361+setting value
362362+finished setting value
363363+setting value
364364+finished setting value
365365+setting value
366366+finished setting value
367367+setting value
368368+finished setting value
369369+setting value
370370+finished setting value
371371+setting value
372372+finished setting value
373373+setting value
374374+finished setting value
375375+setting value
376376+finished setting value
377377+setting value
378378+finished setting value
379379+setting value
380380+finished setting value
381381+setting value
382382+finished setting value
383383+setting value
384384+finished setting value
385385+setting value
386386+finished setting value
387387+setting value
388388+finished setting value
389389+setting value
390390+finished setting value
391391+setting value
392392+finished setting value
393393+setting value
394394+finished setting value
395395+setting value
396396+finished setting value
397397+setting value
398398+finished setting value
399399+setting value
400400+finished setting value
401401+setting value
402402+finished setting value
403403+setting value
404404+finished setting value
405405+setting value
406406+finished setting value
407407+setting value
408408+finished setting value
409409+setting value
410410+finished setting value
411411+setting value
412412+finished setting value
413413+setting value
414414+finished setting value
415415+setting value
416416+finished setting value
417417+setting value
418418+finished setting value
419419+setting value
420420+finished setting value
421421+setting value
422422+finished setting value
423423+setting value
424424+finished setting value
425425+setting value
426426+finished setting value
427427+setting value
428428+finished setting value
429429+setting value
430430+finished setting value
431431+setting value
432432+finished setting value
433433+setting value
434434+finished setting value
435435+setting value
436436+finished setting value
437437+setting value
438438+finished setting value
439439+setting value
440440+finished setting value
441441+setting value
442442+finished setting value
443443+setting value
444444+finished setting value
445445+setting value
446446+finished setting value
447447+setting value
448448+finished setting value
449449+setting value
450450+finished setting value
451451+setting value
452452+finished setting value
453453+setting value
454454+finished setting value
455455+setting value
456456+finished setting value
457457+setting value
458458+finished setting value
459459+setting value
460460+finished setting value
461461+setting value
462462+finished setting value
463463+setting value
464464+finished setting value
465465+setting value
466466+finished setting value
467467+setting value
468468+finished setting value
469469+setting value
470470+finished setting value
471471+setting value
472472+finished setting value
473473+setting value
474474+finished setting value
475475+setting value
476476+finished setting value
477477+setting value
478478+finished setting value
479479+setting value
480480+finished setting value
481481+setting value
482482+finished setting value
483483+setting value
484484+finished setting value
485485+setting value
486486+finished setting value
487487+setting value
488488+finished setting value
489489+setting value
490490+finished setting value
491491+setting value
492492+finished setting value
493493+setting value
494494+finished setting value
495495+setting value
496496+finished setting value
497497+setting value
498498+finished setting value
499499+setting value
500500+finished setting value
501501+setting value
502502+finished setting value
503503+setting value
504504+finished setting value
505505+setting value
506506+finished setting value
507507+setting value
508508+finished setting value
509509+setting value
510510+finished setting value
511511+setting value
512512+finished setting value
513513+setting value
514514+finished setting value
515515+setting value
516516+finished setting value
517517+setting value
518518+finished setting value
519519+setting value
520520+finished setting value
521521+setting value
522522+finished setting value
523523+setting value
524524+finished setting value
525525+setting value
526526+finished setting value
527527+setting value
528528+finished setting value
529529+setting value
530530+finished setting value
531531+setting value
532532+finished setting value
533533+setting value
534534+finished setting value
535535+setting value
536536+finished setting value
537537+setting value
538538+finished setting value
539539+setting value
540540+finished setting value
541541+setting value
542542+finished setting value
543543+setting value
544544+finished setting value
545545+setting value
546546+finished setting value
547547+setting value
548548+finished setting value
549549+setting value
550550+finished setting value
551551+setting value
552552+finished setting value
553553+setting value
554554+finished setting value
555555+setting value
556556+finished setting value
557557+setting value
558558+finished setting value
559559+setting value
560560+finished setting value
561561+setting value
562562+finished setting value
563563+setting value
564564+finished setting value
565565+setting value
566566+finished setting value
567567+setting value
568568+finished setting value
569569+setting value
570570+finished setting value
571571+setting value
572572+finished setting value
573573+setting value
574574+finished setting value
575575+setting value
576576+finished setting value
577577+setting value
578578+finished setting value
579579+setting value
580580+finished setting value
581581+setting value
582582+finished setting value
583583+setting value
584584+finished setting value
585585+setting value
586586+finished setting value
587587+setting value
588588+finished setting value
589589+setting value
590590+finished setting value
591591+setting value
592592+finished setting value
593593+setting value
594594+finished setting value
595595+setting value
596596+finished setting value
597597+setting value
598598+finished setting value
599599+setting value
600600+finished setting value
601601+setting value
602602+finished setting value
603603+setting value
604604+finished setting value
605605+setting value
606606+finished setting value
607607+setting value
608608+finished setting value
609609+setting value
610610+finished setting value
611611+setting value
612612+finished setting value
613613+setting value
614614+finished setting value
615615+setting value
616616+setting value
617617+finished setting value
618618+setting value
619619+finished setting value
620620+finished setting value
621621+setting value
622622+finished setting value
623623+setting value
624624+finished setting value
625625+setting value
626626+finished setting value
627627+setting value
628628+finished setting value
629629+setting value
630630+finished setting value
631631+setting value
632632+finished setting value
633633+setting value
634634+finished setting value
635635+setting value
636636+finished setting value
637637+setting value
638638+finished setting value
639639+setting value
640640+finished setting value
641641+setting value
642642+finished setting value
643643+setting value
644644+finished setting value
645645+setting value
646646+finished setting value
647647+setting value
648648+finished setting value
649649+setting value
650650+finished setting value
651651+setting value
652652+finished setting value
653653+setting value
654654+finished setting value
655655+setting value
656656+finished setting value
657657+setting value
658658+finished setting value
659659+setting value
660660+finished setting value
661661+setting value
662662+finished setting value
663663+setting value
664664+finished setting value
665665+setting value
666666+finished setting value
667667+setting value
668668+finished setting value
669669+setting value
670670+finished setting value
671671+setting value
672672+finished setting value
673673+setting value
674674+finished setting value
675675+setting value
676676+finished setting value
677677+setting value
678678+finished setting value
679679+setting value
680680+finished setting value
681681+setting value
682682+finished setting value
683683+setting value
684684+finished setting value
685685+setting value
686686+finished setting value
687687+setting value
688688+finished setting value
689689+setting value
690690+finished setting value
691691+setting value
692692+finished setting value
693693+setting value
694694+finished setting value
695695+setting value
696696+finished setting value
697697+setting value
698698+finished setting value
699699+setting value
700700+finished setting value
701701+setting value
702702+finished setting value
703703+setting value
704704+finished setting value
705705+setting value
706706+finished setting value
707707+setting value
708708+finished setting value
709709+setting value
710710+finished setting value
711711+setting value
712712+finished setting value
713713+setting value
714714+finished setting value
715715+setting value
716716+finished setting value
717717+setting value
718718+finished setting value
719719+setting value
720720+finished setting value
721721+setting value
722722+finished setting value
723723+setting value
724724+finished setting value
725725+setting value
726726+finished setting value
727727+setting value
728728+finished setting value
729729+setting value
730730+finished setting value
731731+setting value
732732+finished setting value
733733+setting value
734734+finished setting value
735735+setting value
736736+finished setting value
737737+setting value
738738+finished setting value
739739+setting value
740740+finished setting value
741741+setting value
742742+finished setting value
743743+setting value
744744+finished setting value
745745+setting value
746746+finished setting value
747747+setting value
748748+finished setting value
749749+setting value
750750+finished setting value
751751+setting value
752752+finished setting value
753753+setting value
754754+finished setting value
755755+setting value
756756+finished setting value
757757+setting value
758758+finished setting value
759759+setting value
760760+finished setting value
761761+setting value
762762+finished setting value
763763+setting value
764764+finished setting value
765765+setting value
766766+finished setting value
767767+setting value
768768+finished setting value
769769+setting value
770770+finished setting value
771771+setting value
772772+finished setting value
773773+setting value
774774+finished setting value
775775+setting value
776776+finished setting value
777777+setting value
778778+finished setting value
779779+setting value
780780+finished setting value
781781+setting value
782782+finished setting value
783783+setting value
784784+finished setting value
785785+setting value
786786+finished setting value
787787+setting value
788788+finished setting value
789789+setting value
790790+finished setting value
791791+setting value
792792+finished setting value
793793+setting value
794794+finished setting value
795795+setting value
796796+finished setting value
797797+setting value
798798+finished setting value
799799+setting value
800800+finished setting value
801801+setting value
802802+finished setting value
803803+setting value
804804+finished setting value
805805+setting value
806806+finished setting value
807807+setting value
808808+finished setting value
809809+setting value
810810+finished setting value
811811+setting value
812812+setting value
813813+finished setting value
814814+finished setting value
815815+setting value
816816+finished setting value
817817+setting value
818818+finished setting value
819819+setting value
820820+finished setting value
821821+setting value
822822+finished setting value
823823+setting value
824824+finished setting value
825825+setting value
826826+finished setting value
827827+setting value
828828+finished setting value
829829+setting value
830830+finished setting value
831831+setting value
832832+finished setting value
833833+setting value
834834+finished setting value
835835+setting value
836836+finished setting value
837837+setting value
838838+finished setting value
839839+setting value
840840+finished setting value
841841+setting value
842842+finished setting value
843843+setting value
844844+finished setting value
845845+setting value
846846+finished setting value
847847+setting value
848848+finished setting value
849849+setting value
850850+finished setting value
851851+setting value
852852+finished setting value
853853+setting value
854854+finished setting value
855855+setting value
856856+finished setting value
857857+setting value
858858+finished setting value
859859+setting value
860860+finished setting value
861861+setting value
862862+finished setting value
863863+setting value
864864+finished setting value
865865+setting value
866866+finished setting value
867867+setting value
868868+finished setting value
869869+setting value
870870+finished setting value
871871+setting value
872872+finished setting value
873873+setting value
874874+finished setting value
875875+setting value
876876+finished setting value
877877+setting value
878878+finished setting value
879879+setting value
880880+finished setting value
881881+setting value
882882+finished setting value
883883+setting value
884884+finished setting value
885885+setting value
886886+finished setting value
887887+setting value
888888+finished setting value
889889+setting value
890890+finished setting value
891891+setting value
892892+finished setting value
893893+setting value
894894+finished setting value
895895+setting value
896896+finished setting value
897897+setting value
898898+finished setting value
899899+setting value
900900+finished setting value
901901+setting value
902902+finished setting value
903903+setting value
904904+finished setting value
905905+setting value
906906+finished setting value
907907+setting value
908908+finished setting value
909909+setting value
910910+finished setting value
911911+setting value
912912+finished setting value
913913+setting value
914914+finished setting value
915915+setting value
916916+finished setting value
917917+setting value
918918+finished setting value
919919+setting value
920920+finished setting value
921921+setting value
922922+finished setting value
923923+setting value
924924+finished setting value
925925+setting value
926926+finished setting value
927927+setting value
928928+finished setting value
929929+setting value
930930+finished setting value
931931+setting value
932932+finished setting value
933933+setting value
934934+finished setting value
935935+setting value
936936+finished setting value
937937+setting value
938938+finished setting value
939939+setting value
940940+finished setting value
941941+setting value
942942+finished setting value
943943+setting value
944944+finished setting value
945945+setting value
946946+finished setting value
947947+setting value
948948+finished setting value
949949+setting value
950950+finished setting value
951951+setting value
952952+finished setting value
953953+setting value
954954+finished setting value
955955+setting value
956956+finished setting value
957957+setting value
958958+finished setting value
959959+setting value
960960+finished setting value
961961+setting value
962962+finished setting value
963963+setting value
964964+finished setting value
965965+setting value
966966+finished setting value
967967+setting value
968968+finished setting value
969969+setting value
970970+finished setting value
971971+setting value
972972+finished setting value
973973+setting value
974974+finished setting value
975975+setting value
976976+finished setting value
977977+setting value
978978+finished setting value
979979+setting value
980980+finished setting value
981981+setting value
982982+finished setting value
983983+setting value
984984+finished setting value
985985+setting value
986986+finished setting value
987987+setting value
988988+finished setting value
989989+setting value
990990+finished setting value
991991+setting value
992992+finished setting value
993993+setting value
994994+finished setting value
995995+setting value
996996+finished setting value
997997+setting value
998998+finished setting value
999999+setting value
10001000+finished setting value
10011001+setting value
10021002+finished setting value
10031003+setting value
10041004+finished setting value
10051005+setting value
10061006+finished setting value
10071007+setting value
10081008+finished setting value
10091009+setting value
10101010+finished setting value
10111011+setting value
10121012+finished setting value
10131013+setting value
10141014+finished setting value
10151015+setting value
10161016+finished setting value
10171017+setting value
10181018+finished setting value
10191019+setting value
10201020+finished setting value
10211021+setting value
10221022+finished setting value
10231023+setting value
10241024+finished setting value
10251025+setting value
10261026+finished setting value
10271027+setting value
10281028+finished setting value
10291029+setting value
10301030+finished setting value
10311031+setting value
10321032+setting value
10331033+finished setting value
10341034+finished setting value
10351035+setting value
10361036+finished setting value
10371037+setting value
10381038+finished setting value
10391039+setting value
10401040+finished setting value
10411041+setting value
10421042+finished setting value
10431043+setting value
10441044+finished setting value
10451045+setting value
10461046+finished setting value
10471047+setting value
10481048+finished setting value
10491049+setting value
10501050+finished setting value
10511051+setting value
10521052+finished setting value
10531053+setting value
10541054+finished setting value
10551055+setting value
10561056+finished setting value
10571057+setting value
10581058+finished setting value
10591059+setting value
10601060+finished setting value
10611061+setting value
10621062+finished setting value
10631063+setting value
10641064+finished setting value
10651065+setting value
10661066+finished setting value
10671067+setting value
10681068+finished setting value
10691069+setting value
10701070+finished setting value
10711071+setting value
10721072+finished setting value
10731073+setting value
10741074+finished setting value
10751075+setting value
10761076+finished setting value
10771077+setting value
10781078+finished setting value
10791079+setting value
10801080+finished setting value
10811081+setting value
10821082+finished setting value
10831083+setting value
10841084+finished setting value
10851085+setting value
10861086+finished setting value
10871087+setting value
10881088+finished setting value
10891089+setting value
10901090+finished setting value
10911091+setting value
10921092+finished setting value
10931093+setting value
10941094+finished setting value
10951095+setting value
10961096+finished setting value
10971097+setting value
10981098+finished setting value
10991099+setting value
11001100+finished setting value
11011101+setting value
11021102+setting value
11031103+finished setting value
11041104+finished setting value
11051105+setting value
11061106+finished setting value
11071107+setting value
11081108+finished setting value
11091109+setting value
11101110+finished setting value
11111111+setting value
11121112+finished setting value
11131113+setting value
11141114+finished setting value
11151115+setting value
11161116+finished setting value
11171117+setting value
11181118+finished setting value
11191119+setting value
11201120+finished setting value
11211121+setting value
11221122+finished setting value
11231123+setting value
11241124+finished setting value
11251125+setting value
11261126+finished setting value
11271127+setting value
11281128+finished setting value
11291129+setting value
11301130+finished setting value
11311131+setting value
11321132+finished setting value
11331133+setting value
11341134+finished setting value
11351135+setting value
11361136+finished setting value
11371137+setting value
11381138+finished setting value
11391139+setting value
11401140+finished setting value
11411141+setting value
11421142+finished setting value
11431143+setting value
11441144+finished setting value
11451145+setting value
11461146+finished setting value
11471147+setting value
11481148+finished setting value
11491149+setting value
11501150+finished setting value
11511151+setting value
11521152+finished setting value
11531153+setting value
11541154+finished setting value
11551155+setting value
11561156+finished setting value
11571157+setting value
11581158+finished setting value
11591159+setting value
11601160+finished setting value
11611161+setting value
11621162+finished setting value
11631163+setting value
11641164+finished setting value
11651165+setting value
11661166+finished setting value
11671167+setting value
11681168+finished setting value
11691169+setting value
11701170+finished setting value
11711171+setting value
11721172+finished setting value
11731173+setting value
11741174+finished setting value
11751175+setting value
11761176+finished setting value
11771177+setting value
11781178+finished setting value
11791179+setting value
11801180+finished setting value
11811181+setting value
11821182+finished setting value
11831183+setting value
11841184+finished setting value
11851185+setting value
11861186+finished setting value
11871187+setting value
11881188+finished setting value
11891189+setting value
11901190+finished setting value
11911191+setting value
11921192+finished setting value
11931193+setting value
11941194+finished setting value
11951195+setting value
11961196+finished setting value
11971197+setting value
11981198+finished setting value
11991199+setting value
12001200+finished setting value
12011201+setting value
12021202+finished setting value
12031203+setting value
12041204+finished setting value
12051205+setting value
12061206+finished setting value
12071207+setting value
12081208+finished setting value
12091209+setting value
12101210+finished setting value
12111211+setting value
12121212+finished setting value
12131213+setting value
12141214+finished setting value
12151215+setting value
12161216+finished setting value
12171217+setting value
12181218+finished setting value
12191219+setting value
12201220+setting value
12211221+finished setting value
12221222+finished setting value
12231223+setting value
12241224+finished setting value
12251225+setting value
12261226+finished setting value
12271227+setting value
12281228+finished setting value
12291229+setting value
12301230+finished setting value
12311231+setting value
12321232+finished setting value
12331233+setting value
12341234+finished setting value
12351235+setting value
12361236+finished setting value
12371237+setting value
12381238+finished setting value
12391239+setting value
12401240+finished setting value
12411241+setting value
12421242+finished setting value
12431243+setting value
12441244+finished setting value
12451245+setting value
12461246+finished setting value
12471247+setting value
12481248+finished setting value
12491249+setting value
12501250+finished setting value
12511251+setting value
12521252+finished setting value
12531253+setting value
12541254+finished setting value
12551255+setting value
12561256+finished setting value
12571257+setting value
12581258+finished setting value
12591259+setting value
12601260+finished setting value
12611261+setting value
12621262+finished setting value
12631263+setting value
12641264+finished setting value
12651265+setting value
12661266+finished setting value
12671267+setting value
12681268+finished setting value
12691269+setting value
12701270+finished setting value
12711271+setting value
12721272+finished setting value
12731273+setting value
12741274+finished setting value
12751275+setting value
12761276+finished setting value
12771277+setting value
12781278+finished setting value
12791279+setting value
12801280+finished setting value
12811281+setting value
12821282+finished setting value
12831283+setting value
12841284+finished setting value
12851285+setting value
12861286+finished setting value
12871287+setting value
12881288+finished setting value
12891289+setting value
12901290+finished setting value
12911291+setting value
12921292+finished setting value
12931293+setting value
12941294+finished setting value
12951295+setting value
12961296+finished setting value
12971297+setting value
12981298+finished setting value
12991299+setting value
13001300+finished setting value
13011301+setting value
13021302+finished setting value
13031303+setting value
13041304+finished setting value
13051305+setting value
13061306+finished setting value
13071307+setting value
13081308+finished setting value
13091309+setting value
13101310+finished setting value
13111311+setting value
13121312+finished setting value
13131313+setting value
13141314+finished setting value
13151315+setting value
13161316+finished setting value
13171317+setting value
13181318+finished setting value
13191319+setting value
13201320+finished setting value
13211321+setting value
13221322+finished setting value
13231323+setting value
13241324+finished setting value
13251325+setting value
13261326+finished setting value
13271327+setting value
13281328+finished setting value
13291329+setting value
13301330+finished setting value
13311331+setting value
13321332+finished setting value
13331333+setting value
13341334+finished setting value
13351335+setting value
13361336+finished setting value
13371337+setting value
13381338+finished setting value
13391339+setting value
13401340+finished setting value
13411341+setting value
13421342+finished setting value
13431343+setting value
13441344+finished setting value
13451345+setting value
13461346+finished setting value
13471347+setting value
13481348+finished setting value
13491349+setting value
13501350+finished setting value
13511351+setting value
13521352+finished setting value
13531353+setting value
13541354+finished setting value
13551355+setting value
13561356+finished setting value
13571357+setting value
13581358+finished setting value
13591359+setting value
13601360+finished setting value
13611361+setting value
13621362+finished setting value
13631363+setting value
13641364+finished setting value
13651365+setting value
13661366+finished setting value
13671367+setting value
13681368+finished setting value
13691369+setting value
13701370+finished setting value
13711371+setting value
13721372+finished setting value
13731373+setting value
13741374+finished setting value
13751375+setting value
13761376+finished setting value
13771377+setting value
13781378+finished setting value
13791379+setting value
13801380+finished setting value
13811381+setting value
13821382+finished setting value
13831383+setting value
13841384+finished setting value
13851385+setting value
13861386+finished setting value
13871387+setting value
13881388+finished setting value
13891389+setting value
13901390+finished setting value
13911391+setting value
13921392+finished setting value
13931393+setting value
13941394+finished setting value
13951395+setting value
13961396+finished setting value
13971397+setting value
13981398+finished setting value
13991399+setting value
14001400+finished setting value
14011401+setting value
14021402+finished setting value
14031403+setting value
14041404+finished setting value
14051405+setting value
14061406+finished setting value
14071407+setting value
14081408+finished setting value
14091409+setting value
14101410+finished setting value
14111411+setting value
14121412+finished setting value
14131413+setting value
14141414+finished setting value
14151415+setting value
14161416+finished setting value
14171417+setting value
14181418+finished setting value
14191419+setting value
14201420+finished setting value
14211421+setting value
14221422+finished setting value
14231423+setting value
14241424+finished setting value
14251425+setting value
14261426+finished setting value
14271427+setting value
14281428+finished setting value
14291429+setting value
14301430+finished setting value
14311431+setting value
14321432+finished setting value
14331433+setting value
14341434+finished setting value
14351435+setting value
14361436+finished setting value
14371437+setting value
14381438+finished setting value
14391439+setting value
14401440+finished setting value
14411441+setting value
14421442+finished setting value
14431443+setting value
14441444+finished setting value
14451445+setting value
14461446+finished setting value
14471447+setting value
14481448+finished setting value
14491449+setting value
14501450+finished setting value
14511451+setting value
14521452+finished setting value
14531453+setting value
14541454+finished setting value
14551455+setting value
14561456+finished setting value
14571457+setting value
14581458+finished setting value
14591459+setting value
14601460+finished setting value
14611461+setting value
14621462+finished setting value
14631463+setting value
14641464+finished setting value
14651465+setting value
14661466+finished setting value
14671467+setting value
14681468+finished setting value
14691469+setting value
14701470+finished setting value
14711471+setting value
14721472+finished setting value
14731473+setting value
14741474+finished setting value
14751475+setting value
14761476+finished setting value
14771477+setting value
14781478+finished setting value
14791479+setting value
14801480+finished setting value
14811481+setting value
14821482+finished setting value
14831483+setting value
14841484+finished setting value
14851485+setting value
14861486+finished setting value
14871487+setting value
14881488+finished setting value
14891489+setting value
14901490+finished setting value
14911491+setting value
14921492+finished setting value
14931493+setting value
14941494+finished setting value
14951495+setting value
14961496+finished setting value
14971497+setting value
14981498+finished setting value
14991499+setting value
15001500+finished setting value
15011501+setting value
15021502+finished setting value
15031503+setting value
15041504+finished setting value
15051505+setting value
15061506+finished setting value
15071507+setting value
15081508+finished setting value
15091509+setting value
15101510+finished setting value
15111511+setting value
15121512+finished setting value
15131513+setting value
15141514+finished setting value
15151515+setting value
15161516+finished setting value
15171517+setting value
15181518+finished setting value
15191519+setting value
15201520+finished setting value
15211521+setting value
15221522+finished setting value
15231523+setting value
15241524+finished setting value
15251525+setting value
15261526+finished setting value
15271527+setting value
15281528+finished setting value
15291529+setting value
15301530+finished setting value
15311531+setting value
15321532+finished setting value
15331533+setting value
15341534+finished setting value
15351535+setting value
15361536+finished setting value
15371537+setting value
15381538+finished setting value
15391539+setting value
15401540+finished setting value
15411541+setting value
15421542+finished setting value
15431543+setting value
15441544+finished setting value
15451545+setting value
15461546+finished setting value
15471547+setting value
15481548+finished setting value
15491549+setting value
15501550+finished setting value
15511551+setting value
15521552+finished setting value
15531553+setting value
15541554+finished setting value
15551555+setting value
15561556+finished setting value
15571557+setting value
15581558+finished setting value
15591559+setting value
15601560+finished setting value
15611561+setting value
15621562+finished setting value
15631563+setting value
15641564+finished setting value
15651565+setting value
15661566+finished setting value
15671567+setting value
15681568+finished setting value
15691569+setting value
15701570+finished setting value
15711571+setting value
15721572+finished setting value
15731573+setting value
15741574+finished setting value
15751575+setting value
15761576+finished setting value
15771577+setting value
15781578+finished setting value
15791579+setting value
15801580+finished setting value
15811581+setting value
15821582+finished setting value
15831583+setting value
15841584+finished setting value
15851585+setting value
15861586+finished setting value
15871587+setting value
15881588+finished setting value
15891589+setting value
15901590+finished setting value
15911591+setting value
15921592+finished setting value
15931593+setting value
15941594+finished setting value
15951595+setting value
15961596+finished setting value
15971597+setting value
15981598+finished setting value
15991599+setting value
16001600+finished setting value
16011601+setting value
16021602+finished setting value
16031603+setting value
16041604+finished setting value
16051605+setting value
16061606+finished setting value
16071607+setting value
16081608+finished setting value
16091609+setting value
16101610+finished setting value
16111611+setting value
16121612+finished setting value
16131613+setting value
16141614+finished setting value
16151615+setting value
16161616+finished setting value
16171617+setting value
16181618+finished setting value
16191619+setting value
16201620+finished setting value
16211621+setting value
16221622+finished setting value
16231623+setting value
16241624+finished setting value
16251625+setting value
16261626+finished setting value
16271627+setting value
16281628+finished setting value
16291629+setting value
16301630+finished setting value
16311631+setting value
16321632+finished setting value
16331633+setting value
16341634+finished setting value
16351635+setting value
16361636+finished setting value
16371637+setting value
16381638+finished setting value
16391639+setting value
16401640+finished setting value
16411641+setting value
16421642+finished setting value
16431643+setting value
16441644+finished setting value
16451645+setting value
16461646+finished setting value
16471647+setting value
16481648+finished setting value
16491649+setting value
16501650+finished setting value
16511651+setting value
16521652+finished setting value
16531653+setting value
16541654+finished setting value
16551655+setting value
16561656+finished setting value
16571657+setting value
16581658+finished setting value
16591659+setting value
16601660+finished setting value
16611661+setting value
16621662+finished setting value
16631663+setting value
16641664+finished setting value
16651665+setting value
16661666+finished setting value
16671667+setting value
16681668+finished setting value
16691669+setting value
16701670+finished setting value
16711671+setting value
16721672+finished setting value
16731673+setting value
16741674+finished setting value
16751675+setting value
16761676+finished setting value
16771677+setting value
16781678+finished setting value
16791679+setting value
16801680+finished setting value
16811681+setting value
16821682+finished setting value
16831683+setting value
16841684+finished setting value
16851685+setting value
16861686+finished setting value
16871687+setting value
16881688+finished setting value
16891689+setting value
16901690+finished setting value
16911691+setting value
16921692+finished setting value
16931693+setting value
16941694+finished setting value
16951695+setting value
16961696+finished setting value
16971697+setting value
16981698+finished setting value
16991699+setting value
17001700+finished setting value
17011701+setting value
17021702+finished setting value
17031703+setting value
17041704+finished setting value
17051705+setting value
17061706+finished setting value
17071707+setting value
17081708+finished setting value
17091709+setting value
17101710+finished setting value
17111711+setting value
17121712+finished setting value
17131713+setting value
17141714+finished setting value
17151715+setting value
17161716+finished setting value
17171717+setting value
17181718+finished setting value
17191719+setting value
17201720+finished setting value
17211721+setting value
17221722+finished setting value
17231723+setting value
17241724+finished setting value
17251725+setting value
17261726+finished setting value
17271727+setting value
17281728+finished setting value
17291729+setting value
17301730+finished setting value
17311731+setting value
17321732+finished setting value
17331733+setting value
17341734+finished setting value
17351735+setting value
17361736+finished setting value
17371737+setting value
17381738+finished setting value
17391739+setting value
17401740+finished setting value
17411741+setting value
17421742+finished setting value
17431743+setting value
17441744+finished setting value
17451745+setting value
17461746+finished setting value
17471747+setting value
17481748+finished setting value
17491749+setting value
17501750+finished setting value
17511751+setting value
17521752+finished setting value
17531753+setting value
17541754+finished setting value
17551755+setting value
17561756+finished setting value
17571757+setting value
17581758+finished setting value
17591759+setting value
17601760+finished setting value
17611761+setting value
17621762+finished setting value
17631763+setting value
17641764+finished setting value
17651765+setting value
17661766+finished setting value
17671767+setting value
17681768+finished setting value
17691769+setting value
17701770+finished setting value
17711771+setting value
17721772+finished setting value
17731773+setting value
17741774+finished setting value
17751775+setting value
17761776+finished setting value
17771777+setting value
17781778+finished setting value
17791779+setting value
17801780+finished setting value
17811781+setting value
17821782+finished setting value
17831783+setting value
17841784+finished setting value
17851785+setting value
17861786+finished setting value
17871787+setting value
17881788+finished setting value
17891789+setting value
17901790+finished setting value
17911791+setting value
17921792+finished setting value
17931793+setting value
17941794+finished setting value
17951795+setting value
17961796+finished setting value
17971797+setting value
17981798+finished setting value
17991799+setting value
18001800+finished setting value
18011801+setting value
18021802+finished setting value
18031803+setting value
18041804+finished setting value
18051805+setting value
18061806+finished setting value
18071807+setting value
18081808+finished setting value
18091809+setting value
18101810+finished setting value
18111811+setting value
18121812+finished setting value
18131813+setting value
18141814+finished setting value
18151815+setting value
18161816+finished setting value
18171817+setting value
18181818+finished setting value
18191819+setting value
18201820+finished setting value
18211821+setting value
18221822+finished setting value
18231823+setting value
18241824+finished setting value
18251825+setting value
18261826+finished setting value
18271827+setting value
18281828+finished setting value
18291829+setting value
18301830+finished setting value
18311831+setting value
18321832+finished setting value
18331833+setting value
18341834+finished setting value
18351835+setting value
18361836+finished setting value
18371837+setting value
18381838+finished setting value
18391839+setting value
18401840+finished setting value
18411841+setting value
18421842+finished setting value
18431843+setting value
18441844+finished setting value
18451845+setting value
18461846+finished setting value
18471847+setting value
18481848+finished setting value
18491849+setting value
18501850+finished setting value
18511851+setting value
18521852+finished setting value
18531853+setting value
18541854+finished setting value
18551855+setting value
18561856+finished setting value
18571857+setting value
18581858+finished setting value
18591859+setting value
18601860+finished setting value
18611861+setting value
18621862+finished setting value
18631863+setting value
18641864+finished setting value
18651865+setting value
18661866+finished setting value
18671867+setting value
18681868+finished setting value
18691869+setting value
18701870+finished setting value
18711871+setting value
18721872+finished setting value
18731873+setting value
18741874+finished setting value
18751875+setting value
18761876+finished setting value
18771877+setting value
18781878+finished setting value
18791879+setting value
18801880+finished setting value
18811881+setting value
18821882+finished setting value
18831883+setting value
18841884+finished setting value
18851885+setting value
18861886+finished setting value
18871887+setting value
18881888+finished setting value
18891889+setting value
18901890+finished setting value
18911891+setting value
18921892+finished setting value
18931893+setting value
18941894+finished setting value
18951895+setting value
18961896+finished setting value
18971897+setting value
18981898+finished setting value
18991899+setting value
19001900+finished setting value
19011901+setting value
19021902+finished setting value
19031903+setting value
19041904+finished setting value
19051905+setting value
19061906+finished setting value
19071907+setting value
19081908+finished setting value
19091909+setting value
19101910+finished setting value
19111911+setting value
19121912+finished setting value
19131913+setting value
19141914+finished setting value
19151915+setting value
19161916+finished setting value
19171917+setting value
19181918+finished setting value
19191919+setting value
19201920+finished setting value
19211921+setting value
19221922+finished setting value
19231923+setting value
19241924+finished setting value
19251925+setting value
19261926+finished setting value
19271927+setting value
19281928+finished setting value
19291929+setting value
19301930+finished setting value
19311931+setting value
19321932+finished setting value
19331933+setting value
19341934+finished setting value
19351935+setting value
19361936+finished setting value
19371937+setting value
19381938+finished setting value
19391939+setting value
19401940+finished setting value
19411941+setting value
19421942+finished setting value
19431943+setting value
19441944+finished setting value
19451945+setting value
19461946+finished setting value
19471947+setting value
19481948+finished setting value
19491949+setting value
19501950+finished setting value
19511951+setting value
19521952+finished setting value
19531953+setting value
19541954+finished setting value
19551955+setting value
19561956+finished setting value
19571957+setting value
19581958+finished setting value
19591959+setting value
19601960+finished setting value
19611961+setting value
19621962+finished setting value
19631963+setting value
19641964+finished setting value
19651965+setting value
19661966+finished setting value
19671967+setting value
19681968+finished setting value
19691969+setting value
19701970+finished setting value
19711971+setting value
19721972+finished setting value
19731973+setting value
19741974+finished setting value
19751975+setting value
19761976+finished setting value
19771977+setting value
19781978+finished setting value
19791979+setting value
19801980+finished setting value
19811981+setting value
19821982+finished setting value
19831983+setting value
19841984+finished setting value
19851985+setting value
19861986+finished setting value
19871987+setting value
19881988+finished setting value
19891989+setting value
19901990+finished setting value
19911991+setting value
19921992+finished setting value
19931993+setting value
19941994+finished setting value
19951995+setting value
19961996+finished setting value
19971997+setting value
19981998+finished setting value
19991999+setting value
20002000+finished setting value
20012001+setting value
20022002+finished setting value
20032003+setting value
20042004+finished setting value
20052005+setting value
20062006+finished setting value
20072007+setting value
20082008+finished setting value
20092009+setting value
20102010+finished setting value
20112011+setting value
20122012+finished setting value
20132013+setting value
20142014+finished setting value
20152015+setting value
20162016+finished setting value
20172017+setting value
20182018+finished setting value
20192019+setting value
20202020+finished setting value
20212021+setting value
20222022+finished setting value
20232023+setting value
20242024+finished setting value
20252025+setting value
20262026+finished setting value
20272027+setting value
20282028+finished setting value
20292029+setting value
20302030+finished setting value
20312031+setting value
20322032+finished setting value
20332033+setting value
20342034+finished setting value
20352035+setting value
20362036+finished setting value
20372037+setting value
20382038+finished setting value
20392039+setting value
20402040+finished setting value
20412041+setting value
20422042+finished setting value
20432043+setting value
20442044+finished setting value
20452045+setting value
20462046+finished setting value
20472047+setting value
20482048+finished setting value
20492049+setting value
20502050+finished setting value
20512051+setting value
20522052+finished setting value
20532053+setting value
20542054+finished setting value
20552055+setting value
20562056+finished setting value
20572057+setting value
20582058+finished setting value
20592059+setting value
20602060+finished setting value
20612061+setting value
20622062+finished setting value
20632063+setting value
20642064+finished setting value
20652065+setting value
20662066+finished setting value
20672067+setting value
20682068+finished setting value
20692069+setting value
20702070+finished setting value
20712071+setting value
20722072+finished setting value
20732073+setting value
20742074+finished setting value
20752075+setting value
20762076+finished setting value
20772077+setting value
20782078+finished setting value
20792079+setting value
20802080+finished setting value
20812081+setting value
20822082+finished setting value
20832083+setting value
20842084+finished setting value
20852085+setting value
20862086+finished setting value
20872087+setting value
20882088+finished setting value
20892089+setting value
20902090+finished setting value
20912091+setting value
20922092+finished setting value
20932093+setting value
20942094+finished setting value
20952095+setting value
20962096+finished setting value
20972097+setting value
20982098+finished setting value
20992099+setting value
21002100+finished setting value
21012101+setting value
21022102+finished setting value
21032103+setting value
21042104+finished setting value
21052105+setting value
21062106+finished setting value
21072107+setting value
21082108+finished setting value
21092109+setting value
21102110+finished setting value
21112111+setting value
21122112+finished setting value
21132113+setting value
21142114+finished setting value
21152115+setting value
21162116+finished setting value
21172117+setting value
21182118+finished setting value
21192119+setting value
21202120+finished setting value
21212121+setting value
21222122+finished setting value
21232123+setting value
21242124+finished setting value
21252125+setting value
21262126+finished setting value
21272127+setting value
21282128+finished setting value
21292129+setting value
21302130+finished setting value
21312131+setting value
21322132+finished setting value
21332133+setting value
21342134+finished setting value
21352135+setting value
21362136+finished setting value
21372137+setting value
21382138+finished setting value
21392139+setting value
21402140+finished setting value
21412141+setting value
21422142+finished setting value
21432143+setting value
21442144+finished setting value
21452145+setting value
21462146+finished setting value
21472147+setting value
21482148+finished setting value
21492149+setting value
21502150+finished setting value
21512151+setting value
21522152+finished setting value
21532153+setting value
21542154+finished setting value
21552155+setting value
21562156+finished setting value
21572157+setting value
21582158+finished setting value
21592159+setting value
21602160+finished setting value
21612161+setting value
21622162+finished setting value
21632163+setting value
21642164+finished setting value
21652165+setting value
21662166+finished setting value
21672167+setting value
21682168+finished setting value
21692169+setting value
21702170+finished setting value
21712171+setting value
21722172+finished setting value
21732173+setting value
21742174+finished setting value
21752175+setting value
21762176+finished setting value
21772177+setting value
21782178+finished setting value
21792179+setting value
21802180+finished setting value
21812181+setting value
21822182+finished setting value
21832183+setting value
21842184+finished setting value
21852185+setting value
21862186+finished setting value
21872187+setting value
21882188+finished setting value
21892189+setting value
21902190+finished setting value
21912191+setting value
21922192+finished setting value
21932193+setting value
21942194+finished setting value
21952195+setting value
21962196+finished setting value
21972197+setting value
21982198+finished setting value
21992199+setting value
22002200+finished setting value
22012201+setting value
22022202+finished setting value
22032203+setting value
22042204+finished setting value
22052205+setting value
22062206+finished setting value
22072207+setting value
22082208+finished setting value
22092209+setting value
22102210+finished setting value
22112211+setting value
22122212+finished setting value
22132213+setting value
22142214+finished setting value
22152215+setting value
22162216+finished setting value
22172217+setting value
22182218+finished setting value
22192219+setting value
22202220+finished setting value
22212221+setting value
22222222+finished setting value
22232223+setting value
22242224+setting value
22252225+finished setting value
22262226+finished setting value
22272227+setting value
22282228+finished setting value
22292229+setting value
22302230+finished setting value
22312231+setting value
22322232+finished setting value
22332233+setting value
22342234+finished setting value
22352235+setting value
22362236+finished setting value
22372237+setting value
22382238+finished setting value
22392239+setting value
22402240+finished setting value
22412241+setting value
22422242+finished setting value
22432243+setting value
22442244+finished setting value
22452245+setting value
22462246+finished setting value
22472247+setting value
22482248+finished setting value
22492249+setting value
22502250+finished setting value
22512251+setting value
22522252+finished setting value
22532253+setting value
22542254+finished setting value
22552255+setting value
22562256+finished setting value
22572257+setting value
22582258+finished setting value
22592259+setting value
22602260+finished setting value
22612261+setting value
22622262+finished setting value
22632263+setting value
22642264+finished setting value
22652265+setting value
22662266+finished setting value
22672267+setting value
22682268+finished setting value
22692269+setting value
22702270+finished setting value
22712271+setting value
22722272+finished setting value
22732273+setting value
22742274+finished setting value
22752275+setting value
22762276+finished setting value
22772277+setting value
22782278+finished setting value
22792279+setting value
22802280+finished setting value
22812281+setting value
22822282+finished setting value