|
13 | 13 | (* *)
|
14 | 14 | (**************************************************************************)
|
15 | 15 |
|
16 |
| -(* Internals of forcing lazy values. *) |
17 |
| - |
18 |
| -let lazy_tag = 246 |
19 |
| -let forward_tag = 250 |
20 | 16 |
|
| 17 | +(* Internals of forcing lazy values. *) |
21 | 18 | type 'a t = {
|
22 |
| - mutable tag : int ; (* Invariant: name *) |
23 |
| - mutable _0 : 'a |
| 19 | + mutable tag : int [@bs.as "tag"] ; |
| 20 | + (* Invariant: name *) |
| 21 | + mutable value : 'a (* [@bs.as "val"] *) |
| 22 | + (* its type is ['a] or [unit -> 'a ] *) |
24 | 23 | }
|
25 | 24 |
|
26 |
| -external cast_from_lazy : 'a lazy_t -> 'b = "%identity" |
27 |
| -external cast_to_lazy : 'b -> 'a lazy_t = "%identity" |
28 | 25 |
|
29 |
| -(* external new_block : int -> int -> 'a lazy_t = "caml_obj_block" *) |
30 |
| -let set_tag : 'a lazy_t -> int -> unit = fun x tag -> |
31 |
| - (x |. cast_from_lazy).tag<-tag |
32 |
| -let tag : 'a lazy_t -> int = fun x -> |
33 |
| - (x |. cast_from_lazy). tag |
| 26 | +let%private lazy_tag = 246 |
| 27 | +let%private forward_tag = 250 |
| 28 | +external%private magic : 'a -> 'b = "%identity" |
34 | 29 |
|
35 |
| -let set_field (blk : 'arg lazy_t) (result : 'a) : unit = |
36 |
| - (* Obj.set_field (Obj.repr blk) 0 (Obj.repr result) *) |
37 |
| - (blk |. cast_from_lazy)._0<-result |
38 |
| -let get_field (blk : 'arg lazy_t ) : 'a = |
39 |
| - (* Obj.obj (Obj.field (Obj.repr blk) 0) *) |
40 |
| - (blk |. cast_from_lazy)._0 |
| 30 | +let%private lazy_boxed (type a) (l : a ) : bool = |
| 31 | + if Js.testAny l then false |
| 32 | + else |
| 33 | + let t = (magic l : _ t ).tag in |
| 34 | + t = forward_tag || t = lazy_tag |
41 | 35 |
|
42 |
| -let new_block_with_tag tag (value : 'a) : 'arg lazy_t = |
43 |
| - ({tag ; _0 = value} |. cast_to_lazy) |
44 |
| - (* let x = new_block tag 1 in |
45 |
| - set_field x value; |
46 |
| - x *) |
| 36 | +let is_val (type a ) (l : a lazy_t) : bool = |
| 37 | + Js.testAny l || ((magic l : _ t ).tag <> lazy_tag) |
47 | 38 |
|
48 |
| -let from_fun (f : unit -> 'arg ) = |
49 |
| - new_block_with_tag lazy_tag f |
| 39 | +let from_fun (type arg ) (f : unit -> arg ) : arg lazy_t = |
| 40 | + (magic {tag = lazy_tag; value = f} : arg lazy_t) |
50 | 41 |
|
51 | 42 |
|
52 |
| -let from_val (v : 'arg) = |
53 |
| - let t = tag (cast_to_lazy v) in |
54 |
| - if t = forward_tag || t = lazy_tag then begin |
55 |
| - new_block_with_tag forward_tag v |
| 43 | +let from_val (type arg ) (v : arg) : arg lazy_t= |
| 44 | + if lazy_boxed v then begin |
| 45 | + (magic {tag = forward_tag ; value = v} : arg lazy_t ) |
56 | 46 | end else begin
|
57 |
| - (cast_to_lazy v : 'arg lazy_t) |
| 47 | + (magic v : arg lazy_t) |
58 | 48 | end
|
59 | 49 |
|
| 50 | +exception Undefined |
60 | 51 |
|
61 |
| -let forward_with_closure (blk : 'arg lazy_t) closure = |
| 52 | +let%private forward_with_closure (type a ) (blk : a t) (closure : unit -> a) : a = |
62 | 53 | let result = closure () in
|
63 | 54 | (* do set_field BEFORE set_tag *)
|
64 |
| - set_field blk result; |
65 |
| - set_tag blk forward_tag; |
| 55 | + blk.value <- result; |
| 56 | + blk.tag<- forward_tag; |
66 | 57 | result
|
67 | 58 |
|
68 | 59 |
|
69 |
| -exception Undefined |
70 |
| - |
71 |
| -let raise_undefined = (fun () -> raise Undefined) |
| 60 | +let%private raise_undefined = (fun () -> raise Undefined) |
72 | 61 |
|
73 | 62 | (* Assume [blk] is a block with tag lazy *)
|
74 |
| -let force_lazy_block (blk : 'arg lazy_t) = |
75 |
| - let closure : unit -> 'arg = get_field blk in |
76 |
| - set_field blk raise_undefined; |
| 63 | +let%private force_lazy_block (type a ) (blk : a t) : a = |
| 64 | + let closure : unit -> a = magic blk.value in |
| 65 | + blk.value <- magic raise_undefined; |
77 | 66 | try
|
78 | 67 | forward_with_closure blk closure
|
79 | 68 | with e ->
|
80 |
| - set_field blk (fun () -> raise e); |
| 69 | + blk.value <- magic (fun () -> raise e); |
81 | 70 | raise e
|
82 | 71 |
|
83 | 72 |
|
84 | 73 | (* Assume [blk] is a block with tag lazy *)
|
85 |
| -let force_val_lazy_block (blk : 'arg lazy_t) = |
86 |
| - let closure : unit -> 'arg = get_field blk in |
87 |
| - set_field blk raise_undefined; |
| 74 | +let%private force_val_lazy_block (type a ) (blk : a t) : a = |
| 75 | + let closure : unit -> a = magic blk.value in |
| 76 | + blk.value <- magic raise_undefined; |
88 | 77 | forward_with_closure blk closure
|
89 | 78 |
|
90 |
| -(* [force] is not used, since [Lazy.force] is declared as a primitive |
91 |
| - whose code inlines the tag tests of its argument. This function is |
92 |
| - here for the sake of completeness, and for debugging purpose. *) |
93 |
| - |
94 |
| -let force (lzv : 'arg lazy_t) : 'arg = |
95 |
| - let t = tag lzv in |
96 |
| - if t = forward_tag then get_field lzv else |
97 |
| - if t <> lazy_tag then cast_from_lazy lzv |
98 |
| - else force_lazy_block lzv |
99 | 79 |
|
100 | 80 |
|
101 |
| -let force_val (lzv : 'arg lazy_t) : 'arg = |
102 |
| - let t = tag lzv in |
103 |
| - if t = forward_tag then get_field lzv else |
104 |
| - if t <> lazy_tag then cast_from_lazy lzv |
105 |
| - else force_val_lazy_block lzv |
106 |
| - |
| 81 | +let force (type a ) (lzv : a lazy_t) : a = |
| 82 | + if lazy_boxed lzv then |
| 83 | + if is_val lzv then (magic lzv : _ t).value else |
| 84 | + force_lazy_block (magic lzv : _ t) |
| 85 | + else magic lzv |
107 | 86 |
|
108 | 87 |
|
109 | 88 |
|
| 89 | +let force_val (lzv : 'arg lazy_t) : 'arg = |
| 90 | + if lazy_boxed lzv then |
| 91 | + if is_val lzv then (magic lzv : _ t).value else |
| 92 | + force_val_lazy_block (magic lzv : _ t) |
| 93 | + else magic lzv |
110 | 94 |
|
111 |
| -let is_val (l : 'arg lazy_t) = tag l <> lazy_tag |
0 commit comments