1(*
2    Title:      Weak references
3    Author:     David Matthews
4    Copyright   David Matthews 2008, 2015-16
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License version 2.1 as published by the Free Software Foundation.
9    
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14    
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18*)
19
20(* A weak reference or array contains option values.  The SOME variant of
21   the option must contain a reference.  This restriction is imposed because
22   they require pointer equality.  A weak reference or array behaves just like
23   a normal ref or array with one difference.  The garbage collector may set
24   a weak ref or the field of weak array to NONE if it currently contains
25   SOME r but r is not reachable other than through weak references.  The
26   one proviso is that if r is contained in the executable it is always
27   reachable.
28*)
29
30signature WEAK =
31sig
32    val weak: 'a ref option -> 'a ref option ref
33    val weakArray: int * 'a ref option -> 'a ref option array
34    val weakLock: Thread.Mutex.mutex
35    and weakSignal: Thread.ConditionVar.conditionVar
36    val touch : 'a ref -> unit
37end;
38
39structure Weak: WEAK =
40struct
41    fun weak (v: 'a ref option): 'a ref option ref = RunCall.allocateWordMemory(0w1, 0wx60, v)
42    
43    fun weakArray(n: int, v: 'a ref option): 'a ref option array =
44    let
45        val () = if n < 0 orelse n >= Array.maxLen then raise Size else ()
46        val arr = RunCall.allocateWordMemory(Word.fromInt n, 0wx60, v)
47    in
48        arr
49    end
50
51    val weakLock = Thread.Mutex.mutex()
52    and weakSignal = Thread.ConditionVar.conditionVar()
53
54    (* touch is considered by the compiler as an access to the ref but doesn't
55       actually do anything with it.  The idea is that it ensures that when a ref
56       is used as a token that this will access the ref and avoid the weak
57       reference becoming set to NONE.  It's primarily there for long-term
58       security in the event that the compiler is sufficiently clever to
59       work out that something is no longer referenced. *)
60    fun touch v = v := !v
61end;
62