1 // Written in the D programming language.
2 
3 /**
4  * Signals and Slots are an implementation of the $(LINK2 http://en.wikipedia.org/wiki/Observer_pattern, Observer pattern)$(BR)
5  * Essentially, when a Signal is emitted, a list of connected Observers
6  * (called slots) are called.
7  *
8  * They were first introduced in the
9  * $(LINK2 http://en.wikipedia.org/wiki/Qt_%28framework%29, Qt GUI toolkit), alternate implementations are
10  * $(LINK2 http://libsigc.sourceforge.net, libsig++) or
11  * $(LINK2 http://www.boost.org/doc/libs/1_55_0/doc/html/signals2.html, Boost.Signals2)
12  * similar concepts are implemented in other languages than C++ too.
13  *
14  * Copyright: Copyright Robert Klotzner 2012 - 2014.
15  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
16  * Authors:   Robert Klotzner
17  */
18 
19 /*          Copyright Robert Klotzner 2012 - 2014.
20  * Distributed under the Boost Software License, Version 1.0.
21  *    (See accompanying file LICENSE_1_0.txt or copy at
22  *          http://www.boost.org/LICENSE_1_0.txt)
23  *
24  * Based on the original implementation written by Walter Bright. (std.signals)
25  * I shamelessly stole some ideas of: http://forum.dlang.org/thread/jjote0$1cql$1@digitalmars.com
26  * written by Alex Rønne Petersen.
27  *
28  * Also thanks to Denis Shelomovskij who made me aware of some
29  * deficiencies in the concurrent part of WeakRef.
30  */
31 module phobosx.signal;
32 
33 import core.atomic;
34 import core.memory;
35 import std.functional : toDelegate;
36 
37 
38 // Hook into the GC to get informed about object deletions.
39 private alias void delegate(Object) DisposeEvt;
40 private extern (C) void  rt_attachDisposeEvent( Object obj, DisposeEvt evt );
41 private extern (C) void  rt_detachDisposeEvent( Object obj, DisposeEvt evt );
42 
43 /**
44  * Full signal implementation.
45  *
46  * It implements the emit function, for all other functionality it has
47  * this aliased to RestrictedSignal.
48  *
49  * A signal is a way to couple components together in a very loose
50  * way. The receiver does not need to know anything about the sender
51  * and the sender does not need to know anything about the
52  * receivers. The sender will just call emit when something happens,
53  * the signal takes care of notifying all interested parties. By using
54  * wrapper delegates/functions, not even the function signature of
55  * sender/receiver need to match.
56  *
57  * Another consequence of this very loose coupling is, that a
58  * connected object will be freed by the GC if all references to it
59  * are dropped, even if it was still connected to a signal. The
60  * connection will simply be removed. This way the developer is freed of
61  * manually keeping track of connections.
62  *
63  * If in your application the connections made by a signal are not
64  * that loose you can use strongConnect(), in this case the GC won't
65  * free your object until it was disconnected from the signal or the
66  * signal got itself destroyed.
67  *
68  * This struct is not thread-safe in general, it just handles the
69  * concurrent parts of the GC.
70  *
71  * Bugs: The code probably won't compile with -profile because of bug:
72  *       $(LINK2 http://d.puremagic.com/issues/show_bug.cgi?id=10260, 10260)
73  *
74  * Example:
75  ---
76  import std.signal;
77  import std.stdio;
78  import std.functional;
79 
80  class MyObject
81  {
82      // Public accessor method returning a RestrictedSignal, thus restricting
83      // the use of emit to this module. See the signal() string mixin below
84      // for a simpler way.
85      ref RestrictedSignal!(string, int) valueChanged() { return _valueChanged;}
86      private Signal!(string, int) _valueChanged;
87 
88      int value() @property { return _value; }
89      int value(int v) @property
90      {
91         if (v != _value)
92         {
93             _value = v;
94             // call all the connected slots with the two parameters
95             _valueChanged.emit("setting new value", v);
96         }
97         return v;
98      }
99  private:
100      int _value;
101  }
102 
103  class Observer
104  {   // our slot
105      void watch(string msg, int i)
106      {
107          writefln("Observed msg '%s' and value %s", msg, i);
108      }
109  }
110  void watch(string msg, int i)
111  {
112      writefln("Globally observed msg '%s' and value %s", msg, i);
113  }
114  void main()
115  {
116      auto a = new MyObject;
117      Observer o = new Observer;
118 
119      a.value = 3;                // should not call o.watch()
120      a.valueChanged.connect!"watch"(o);        // o.watch is the slot
121      a.value = 4;                // should call o.watch()
122      a.valueChanged.disconnect!"watch"(o);     // o.watch is no longer a slot
123      a.value = 5;                // should not call o.watch()
124      a.valueChanged.connect!"watch"(o);        // connect again
125      // Do some fancy stuff:
126      a.valueChanged.connect!Observer(o, (obj, msg, i) =>  obj.watch("Some other text I made up", i+1));
127      a.valueChanged.connect(&watch);
128      a.value = 6;                // should call o.watch()
129      destroy(o);                 // destroying o should automatically disconnect it
130      a.value = 7;                // should not call o.watch()
131  }
132 ---
133  * which should print:
134  * <pre>
135  * Observed msg 'setting new value' and value 4
136  * Observed msg 'setting new value' and value 6
137  * Observed msg 'Some other text I made up' and value 7
138  * Globally observed msg 'setting new value' and value 6
139  * Globally observed msg 'setting new value' and value 7
140  * </pre>
141  */
142 struct Signal(Args...)
143 {
144     alias restricted this;
145 
146     /**
147      * Emit the signal.
148      *
149      * All connected slots which are still alive will be called.  If
150      * any of the slots throws an exception, the other slots will
151      * still be called. You'll receive a chained exception with all
152      * exceptions that were thrown. Thus slots won't influence each
153      * others execution.
154      *
155      * The slots are called in the same sequence as they were registered.
156      *
157      * emit also takes care of actually removing dead connections. For
158      * concurrency reasons they are just set to an invalid state by the GC.
159      *
160      * If you remove a slot during emit() it won't be called in the
161      * current run if it was not already.
162      *
163      * If you add a slot during emit() it will be called in the
164      * current emit() run. Note however, Signal is not thread-safe, "called
165      * during emit" basically means called from within a slot.
166      */
167     void emit( Args args ) @trusted
168     {
169         _restricted._impl.emit(args);
170     }
171 
172     /**
173      * Get access to the rest of the signals functionality.
174      *
175      * By only granting your users access to the returned RestrictedSignal
176      * reference, you are preventing your users from calling emit on their
177      * own.
178      */
179     ref RestrictedSignal!(Args) restricted() @property @trusted
180     {
181         return _restricted;
182     }
183 
184     private:
185     RestrictedSignal!(Args) _restricted;
186 }
187 
188 /**
189  * The signal implementation, not providing an emit method.
190  *
191  * A RestrictedSignal reference is returned by Signal.restricted,
192  * it can safely be passed to users of your API, without
193  * allowing them to call emit().
194  */
195 struct RestrictedSignal(Args...)
196 {
197     /**
198      * Direct connection to an object.
199      *
200      * Use this method if you want to connect directly to an object's
201      * method matching the signature of this signal.  The connection
202      * will have weak reference semantics, meaning if you drop all
203      * references to the object the garbage collector will collect it
204      * and this connection will be removed.
205      *
206      * Preconditions: obj must not be null. mixin("&obj."~method)
207      * must be valid and compatible.
208      * Params:
209      *     obj = Some object of a class implementing a method
210      *     compatible with this signal.
211      */
212     void connect(string method, ClassType)(ClassType obj) @trusted
213         if (is(ClassType == class) && __traits(compiles, {void delegate(Args) dg = mixin("&obj."~method);}))
214     in
215     {
216         assert(obj);
217     }
218     body
219     {
220         _impl.addSlot(obj, cast(void delegate())mixin("&obj."~method));
221     }
222     /**
223      * Indirect connection to an object.
224      *
225      * Use this overload if you want to connect to an objects method
226      * which does not match the signal's signature.  You can provide
227      * any delegate to do the parameter adaption, but make sure your
228      * delegates' context does not contain a reference to the target
229      * object, instead use the provided obj parameter, where the
230      * object passed to connect will be passed to your delegate.
231      * This is to make weak ref semantics possible, if your delegate
232      * contains a ref to obj, the object won't be freed as long as
233      * the connection remains.
234      *
235      * Preconditions: obj and dg must not be null.
236      * dg's context must not be equal to obj.
237      *
238      * Params:
239      *     obj = The object to connect to. It will be passed to the
240      *     delegate when the signal is emitted.
241      *
242      *     dg = A wrapper delegate which takes care of calling some
243      *     method of obj. It can do any kind of parameter adjustments
244      *     necessary.
245      */
246     void connect(ClassType)(ClassType obj, void delegate(ClassType obj, Args) dg) @trusted
247         if (is(ClassType == class))
248     in
249     {
250         assert(obj);
251         assert(dg);
252         assert(cast(void*)obj !is dg.ptr);
253     }
254     body
255     {
256         _impl.addSlot(obj, cast(void delegate()) dg);
257     }
258 
259     /**
260      * Connect a free function to this signal.
261      *
262      * Preconditions: fn must not be null. 
263      * 
264      * Params:
265      *     fn = The free function to be connected.
266      */
267     void connect(void function(Args) fn) @trusted
268     in
269     {
270         assert(fn);
271     }
272     body
273     {
274         strongConnect(toDelegate(fn));
275     }
276 
277     /**
278      * Connect with strong ref semantics.
279      *
280      * Use this overload if you either want strong ref
281      * semantics for some reason or because you want to connect some
282      * non-class method delegate. Whatever the delegates' context
283      * references will stay in memory as long as the signals'
284      * connection is not removed and the signal gets not destroyed
285      * itself.
286      *
287      * Preconditions: dg must not be null.
288      *
289      * Params:
290      *     dg = The delegate to be connected.
291      */
292     void strongConnect(void delegate(Args) dg) @trusted
293     in
294     {
295         assert(dg);
296     }
297     body
298     {
299         _impl.addSlot(null, cast(void delegate()) dg);
300     }
301 
302 
303     /**
304      * Disconnect a direct connection.
305      *
306      * After issuing this call, the connection to method of obj is lost
307      * and obj.method() will no longer be called on emit.
308      * Preconditions: Same as for direct connect.
309      */
310     void disconnect(string method, ClassType)(ClassType obj) @trusted
311         if (is(ClassType == class) && __traits(compiles, {void delegate(Args) dg = mixin("&obj."~method);}))
312     in
313     {
314         assert(obj);
315     }
316     body
317     {
318         void delegate(Args) dg = mixin("&obj."~method);
319         _impl.removeSlot(obj, cast(void delegate()) dg);
320     }
321 
322     /**
323      * Disconnect an indirect connection.
324      *
325      * For this to work properly, dg has to be exactly the same as
326      * the one passed to connect. So if you used a lamda you have to
327      * keep a reference to it somewhere if you want to disconnect
328      * the connection later on.  If you want to remove all
329      * connections to a particular object, use the overload which only
330      * takes an object parameter.
331      */
332     void disconnect(ClassType)(ClassType obj, void delegate(ClassType, T1) dg) @trusted
333         if (is(ClassType == class))
334     in
335     {
336         assert(obj);
337         assert(dg);
338     }
339     body
340     {
341         _impl.removeSlot(obj, cast(void delegate())dg);
342     }
343 
344     /**
345      * Disconnect all connections to obj.
346      *
347      * All connections to obj made with calls to connect are removed.
348      */
349     void disconnect(ClassType)(ClassType obj) @trusted if (is(ClassType == class))
350     in
351     {
352         assert(obj);
353     }
354     body
355     {
356         _impl.removeSlot(obj);
357     }
358 
359     /**
360      * Disconnect a free function.
361      *
362      * Preconditions: fn must not be null. 
363      * 
364      * Params:
365      *    fn = The function to be disconnected.
366      */
367     void disconnect(void function(Args) fn) @trusted
368     in
369     {
370         assert(fn);
371     }
372     body
373     {
374         strongDisconnect(toDelegate(fn));
375     }
376     
377     /**
378      * Disconnect a connection made with strongConnect.
379      *
380      * Disconnects all connections to dg.
381      */
382     void strongDisconnect(void delegate(Args) dg) @trusted
383     in
384     {
385         assert(dg);
386     }
387     body
388     {
389         _impl.removeSlot(null, cast(void delegate()) dg);
390     }
391     private:
392     SignalImpl _impl;
393 }
394 
395 /**
396  * string mixin for creating a signal.
397  *
398  * If you found the above:
399 ---
400      ref RestrictedSignal!(string, int) valueChanged() { return _valueChanged;}
401      private Signal!(string, int) _valueChanged;
402 ---
403    a bit tedious, but still want to restrict the use of emit, you can use this
404    string mixin. The following would result in exactly the same code:
405 ---
406      mixin(signal!(string, int)("valueChanged"));
407 ---
408  * Additional flexibility is provided by the protection parameter,
409  * where you can change the protection of _valueChanged to protected
410  * for example.
411  *
412  * Bugs:
413  *     This mixin generator does not work with templated types right now because of:
414  *     $(LINK2 http://d.puremagic.com/issues/show_bug.cgi?id=10502, 10502)$(BR)
415  *     You might want to use the Signal struct directly in this
416  *     case. Ideally you write the code, the mixin would generate, manually
417  *     to ensure an easy upgrade path when the above bug gets fixed:
418  ---
419  *     ref RestrictedSignal!(SomeTemplate!int) mysig() { return _mysig;}
420  *     private Signal!(SomeTemplate!int) _mysig;
421  ---
422  *
423  * Params:
424  *   name = How the signal should be named. The ref returning function
425  *   will be named like this, the actual struct instance will have an
426  *   underscore prefixed.
427  *
428  *   protection = Specifies how the full functionality (emit) of the
429  *   signal should be protected. Default is private. If
430  *   Protection.none is given, private is used for the Signal member
431  *   variable and the ref returning accessor method will return a
432  *   Signal instead of a RestrictedSignal. The protection of the
433  *   accessor method is specified by the surrounding protection scope:
434  ---
435  *     public: // Everyone can access mysig now:
436  *     // Result of mixin(signal!int("mysig", Protection.none))
437  *     ref Signal!int mysig() { return _mysig;}
438  *     private Signal!int _mysig;
439  ---
440  */
441 string signal(Args...)(string name, Protection protection=Protection.private_) @trusted // trusted necessary because of to!string
442 {
443     import std.conv;
444     string argList="(";
445     import std.traits : fullyQualifiedName;
446     foreach (arg; Args)
447     {
448         argList~=fullyQualifiedName!(arg)~", ";
449     }
450     if (argList.length>"(".length)
451         argList = argList[0 .. $-2];
452     argList ~= ")";
453 
454     string output = (protection == Protection.none ? "private" : to!string(protection)[0..$-1]) ~
455         " Signal!" ~ argList ~ " _" ~ name ~ ";\n";
456     string rType = protection == Protection.none ? "Signal!" : "RestrictedSignal!";
457     output ~= "ref " ~ rType ~ argList ~ " " ~ name ~ "() { return _" ~ name ~ ";}\n";
458     return output;
459 }
460 
461 /**
462  * Protection to use for the signal string mixin.
463  */
464 enum Protection
465 {
466     none, /// No protection at all, the wrapping function will return a ref Signal instead of a ref RestrictedSignal
467     private_, /// The Signal member variable will be private.
468     protected_, /// The signal member variable will be protected.
469     package_ /// The signal member variable will have package protection.
470 }
471 
472 
473 private struct SignalImpl
474 {
475     /**
476      * Forbid copying.
477      * Unlike the old implementations, it would now be theoretically
478      * possible to copy a signal. Even different semantics are
479      * possible. But none of the possible semantics are what the user
480      * intended in all cases, so I believe it is still the safer
481      * choice to simply disallow copying.
482      */
483     @disable this(this);
484     /// Forbid copying
485     @disable void opAssign(SignalImpl other);
486 
487     void emit(Args...)( Args args )
488     {
489         int emptyCount = 0;
490         if (!_slots.emitInProgress)
491         {
492             _slots.emitInProgress = true;
493             scope (exit) _slots.emitInProgress = false;
494         }
495         else
496             emptyCount = -1;
497         doEmit(0, emptyCount, args);
498         if (emptyCount > 0)
499         {
500             _slots.slots = _slots.slots[0 .. $-emptyCount];
501             _slots.slots.assumeSafeAppend();
502         }
503     }
504 
505     void addSlot(Object obj, void delegate() dg)
506     {
507         auto oldSlots = _slots.slots;
508         if (oldSlots.capacity <= oldSlots.length)
509         {
510             auto buf = new SlotImpl[oldSlots.length+1]; // TODO: This growing strategy might be inefficient.
511             foreach (i, ref slot ; oldSlots)
512                 buf[i].moveFrom(slot);
513             oldSlots = buf;
514         }
515         else
516             oldSlots.length = oldSlots.length + 1;
517 
518         oldSlots[$-1].construct(obj, dg);
519         _slots.slots = oldSlots;
520     }
521     void removeSlot(Object obj, void delegate() dg)
522     {
523         removeSlot((ref SlotImpl item) => item.wasConstructedFrom(obj, dg));
524     }
525     void removeSlot(Object obj)
526     {
527         removeSlot((ref SlotImpl item) => item.obj is obj);
528     }
529 
530     ~this()
531     {
532         foreach (ref slot; _slots.slots)
533         {
534             debug (signal) { import std.stdio; stderr.writefln("Destruction, removing some slot(%s, weakref: %s), signal: ", &slot, &slot._obj, &this); }
535             slot.reset(); // This is needed because ATM the GC won't trigger struct
536                         // destructors to be run when within a GC managed array.
537         }
538     }
539 
540 /// Little helper functions:
541 
542     /**
543      * Find and make invalid any slot for which isRemoved returns true.
544      */
545     void removeSlot(bool delegate(ref SlotImpl) isRemoved)
546     {
547         if (_slots.emitInProgress)
548         {
549             foreach (ref slot; _slots.slots)
550                 if (isRemoved(slot))
551                     slot.reset();
552         }
553         else // It is save to do immediate cleanup:
554         {
555             int emptyCount = 0;
556             auto mslots = _slots.slots;
557             foreach (int i, ref slot; mslots)
558             {
559             // We are retrieving obj twice which is quite expensive because of GC lock:
560                 if (!slot.isValid || isRemoved(slot))
561                 {
562                     emptyCount++;
563                     slot.reset();
564                 }
565                 else if (emptyCount)
566                     mslots[i-emptyCount].moveFrom(slot);
567             }
568 
569             if (emptyCount > 0)
570             {
571                 mslots = mslots[0..$-emptyCount];
572                 mslots.assumeSafeAppend();
573                 _slots.slots = mslots;
574             }
575         }
576     }
577 
578     /**
579      * Helper method to allow all slots being called even in case of an exception.
580      * All exceptions that occur will be chained.
581      * Any invalid slots (GC collected or removed) will be dropped.
582      */
583     void doEmit(Args...)(int offset, ref int emptyCount, Args args )
584     {
585         int i=offset;
586         auto myslots = _slots.slots;
587         scope (exit) if (i+1<myslots.length) doEmit(i+1, emptyCount, args); // Carry on.
588         if (emptyCount == -1)
589         {
590             for (; i<myslots.length; i++)
591             {
592                 myslots[i](args);
593                 myslots = _slots.slots; // Refresh because addSlot might have been called.
594             }
595         }
596         else
597         {
598             for (; i<myslots.length; i++)
599             {
600                 bool result = myslots[i](args);
601                 myslots = _slots.slots; // Refresh because addSlot might have been called.
602                 if (!result)
603                     emptyCount++;
604                 else if (emptyCount>0)
605                 {
606                     myslots[i-emptyCount].reset();
607                     myslots[i-emptyCount].moveFrom(myslots[i]);
608                 }
609             }
610         }
611     }
612 
613     SlotArray _slots;
614 }
615 
616 
617 // Simple convenience struct for signal implementation.
618 // Its is inherently unsafe. It is not a template so SignalImpl does
619 // not need to be one.
620 private struct SlotImpl
621 {
622     @disable this(this);
623     @disable void opAssign(SlotImpl other);
624 
625     /// Pass null for o if you have a strong ref delegate.
626     /// dg.funcptr must not point to heap memory.
627     void construct(Object o, void delegate() dg)
628     in { assert(this is SlotImpl.init); }
629     body
630     {
631         _obj.construct(o);
632         _dataPtr = dg.ptr;
633         _funcPtr = dg.funcptr;
634         assert(GC.addrOf(_funcPtr) is null, "Your function is implemented on the heap? Such dirty tricks are not supported with std.signal!");
635         assert(!hasObject, "Function has it's MSB set - we got a problem here!");
636         if (o)
637         {
638             if (_dataPtr is cast(void*) o)
639                 _dataPtr = directPtrFlag;
640             hasObject = true;
641         }
642     }
643 
644     /**
645      * Check whether this slot was constructed from object o and delegate dg.
646      */
647     bool wasConstructedFrom(Object o, void delegate() dg)
648     {
649         if ( o && dg.ptr is cast(void*) o)
650             return obj is o && _dataPtr is directPtrFlag && funcPtr is dg.funcptr;
651         else
652             return obj is o && _dataPtr is dg.ptr && funcPtr is dg.funcptr;
653     }
654     /**
655      * Implement proper explicit move.
656      */
657     void moveFrom(ref SlotImpl other)
658     in { assert(this is SlotImpl.init); }
659     body
660     {
661         auto o = other.obj;
662         _obj.construct(o);
663         _dataPtr = other._dataPtr;
664         _funcPtr = other._funcPtr;
665         other.reset(); // Destroy original!
666     }
667 
668     @property Object obj()
669     {
670         return _obj.obj;
671     }
672 
673     /**
674      * Whether or not _obj should contain a valid object. (We have a weak connection)
675      */
676     bool hasObject() @property const
677     {
678         return (cast(ptrdiff_t) _funcPtr & hasObjectBit) != 0;
679     }
680 
681     /**
682      * Check whether this is a valid slot.
683      *
684      * Meaning opCall will call something and return true;
685      */
686     bool isValid() @property
687     {
688         return funcPtr && (!hasObject || obj !is null);
689     }
690     /**
691      * Call the slot.
692      *
693      * Returns: True if the call was successful (the slot was valid).
694      */
695     bool opCall(Args...)(Args args)
696     {
697         auto o = obj;
698         void* o_addr = cast(void*)(o);
699 
700         if (!funcPtr || (hasObject && !o_addr))
701             return false;
702         if (_dataPtr is directPtrFlag || !hasObject)
703         {
704             void delegate(Args) mdg;
705             mdg.funcptr=cast(void function(Args)) funcPtr;
706             debug (signal) { import std.stdio; writefln("hasObject: %s, o_addr: %s, dataPtr: %s", hasObject, o_addr, _dataPtr);}
707             assert((hasObject && _dataPtr is directPtrFlag) || (!hasObject && _dataPtr !is directPtrFlag));
708             if (hasObject)
709                 mdg.ptr = o_addr;
710             else
711                 mdg.ptr = _dataPtr;
712             mdg(args);
713         }
714         else
715         {
716             void delegate(Object, Args) mdg;
717             mdg.ptr = _dataPtr;
718             mdg.funcptr = cast(void function(Object, Args)) funcPtr;
719             mdg(o, args);
720         }
721         return true;
722     }
723     /**
724      * Reset this instance to its initial value.
725      */
726     void reset() {
727         _funcPtr = SlotImpl.init._funcPtr;
728         _dataPtr = SlotImpl.init._dataPtr;
729         _obj.reset();
730     }
731 private:
732     void* funcPtr() @property const
733     {
734         return cast(void*)( cast(ptrdiff_t)_funcPtr & ~cast(ptrdiff_t)hasObjectBit);
735     }
736     void hasObject(bool yes) @property
737     {
738         if (yes)
739             _funcPtr = cast(void*)(cast(ptrdiff_t) _funcPtr | hasObjectBit);
740         else
741             _funcPtr = cast(void*)(cast(ptrdiff_t) _funcPtr & ~cast(ptrdiff_t)hasObjectBit);
742     }
743     void* _funcPtr;
744     void* _dataPtr;
745     WeakRef _obj;
746 
747 
748     enum directPtrFlag = cast(void*)(~0);
749     enum hasObjectBit = 1L << (ptrdiff_t.sizeof * 8 - 1);
750 }
751 
752 
753 // Provides a way of holding a reference to an object, without the GC seeing it.
754 private struct WeakRef
755 {
756     /**
757      * As struct must be relocatable, it is not even possible to
758      * provide proper copy support for WeakRef.  rt_attachDisposeEvent
759      * is used for registering unhook. D's move semantics assume
760      * relocatable objects, which results in this(this) being called
761      * for one instance and the destructor for another, thus the wrong
762      * handlers are deregistered.  D's assumption of relocatable
763      * objects is not matched, so move() for example will still simply
764      * swap contents of two structs, resulting in the wrong unhook
765      * delegates being unregistered.
766 
767      * Unfortunately the runtime still blindly copies WeakRefs if they
768      * are in a dynamic array and reallocation is needed. This case
769      * has to be handled separately.
770      */
771     @disable this(this);
772     @disable void opAssign(WeakRef other);
773     void construct(Object o)
774     in { assert(this is WeakRef.init); }
775     body
776     {
777         debug (signal) createdThis=&this;
778         debug (signal) { import std.stdio; writefln("WeakRef.construct for %s and object: %s", &this, o); }
779         if (!o)
780             return;
781         _obj.construct(cast(void*)o);
782         rt_attachDisposeEvent(o, &unhook);
783     }
784     Object obj() @property
785     {
786         return cast(Object) _obj.address;
787     }
788     /**
789      * Reset this instance to its intial value.
790      */
791     void reset()
792     {
793         auto o = obj;
794         debug (signal) { import std.stdio; writefln("WeakRef.reset for %s and object: %s", &this, o); }
795         if (o)
796             rt_detachDisposeEvent(o, &unhook);
797         unhook(o); // unhook has to be done unconditionally, because in case the GC
798         //kicked in during toggleVisibility(), obj would contain -1
799         //so the assertion of SlotImpl.moveFrom would fail.
800         debug (signal) createdThis = null;
801     }
802 
803     ~this()
804     {
805         reset();
806     }
807     private:
808     debug (signal)
809     {
810         invariant()
811         {
812             import std.conv : text;
813             assert(createdThis is null || &this is createdThis,
814                    text("We changed address! This should really not happen! Orig address: ",
815                     cast(void*)createdThis, " new address: ", cast(void*)&this));
816         }
817 
818         WeakRef* createdThis;
819     }
820 
821     void unhook(Object o)
822     {
823         _obj.reset();
824     }
825 
826     shared(InvisibleAddress) _obj;
827 }
828 
829 // Do all the dirty stuff, WeakRef is only a thin wrapper completing
830 // the functionality by means of rt_ hooks.
831 private shared struct InvisibleAddress
832 {
833     /// Initialize with o, state is set to invisible immediately.
834     /// No precautions regarding thread safety are necessary because
835     /// obviously a live reference exists.
836     void construct(void* o)
837     {
838         auto tmp = cast(ptrdiff_t) o;
839         _addr = makeInvisible(cast(ptrdiff_t) o);
840     }
841     void reset()
842     {
843         atomicStore(_addr, 0L);
844     }
845     void* address() @property
846     {
847         makeVisible();
848         scope (exit) makeInvisible();
849         GC.addrOf(cast(void*)atomicLoad(_addr)); // Just a dummy call to the GC
850                                  // in order to wait for any possible running
851                                  // collection to complete (have unhook called).
852         auto buf = atomicLoad(_addr);
853         if ( isNull(buf) )
854             return null;
855         assert(isVisible(buf));
856         return cast(void*) buf;
857     }
858     debug(signal)        string toString()
859     {
860         import std.conv : text;
861         return text(address);
862     }
863 private:
864 
865     long _addr;
866 
867     void makeVisible()
868     {
869         long buf, wbuf;
870         do
871         {
872             buf = atomicLoad(_addr);
873             wbuf = makeVisible(buf);
874         }
875         while(!cas(&_addr, buf, wbuf));
876     }
877     void makeInvisible()
878     {
879         long buf, wbuf;
880         do
881         {
882             buf = atomicLoad(_addr);
883             wbuf = makeInvisible(buf);
884         }
885         while(!cas(&_addr, buf, wbuf));
886     }
887     version(D_LP64)
888     {
889         static long makeVisible(long addr)
890         {
891             return ~addr;
892         }
893 
894         static long makeInvisible(long addr)
895         {
896             return ~addr;
897         }
898         static bool isVisible(long addr)
899         {
900             return !(addr & (1L << (ptrdiff_t.sizeof*8-1)));
901         }
902         static bool isNull(long addr)
903         {
904             return ( addr == 0 || addr == (~0) );
905         }
906     }
907     else
908     {
909         static long makeVisible(long addr)
910         {
911             auto addrHigh = (addr >> 32) & 0xffff;
912             auto addrLow = addr & 0xffff;
913             return addrHigh << 16 | addrLow;
914         }
915 
916         static long makeInvisible(long addr)
917         {
918             auto addrHigh = ((addr >> 16) & 0x0000ffff) | 0xffff0000;
919             auto addrLow = (addr & 0x0000ffff) | 0xffff0000;
920             return (cast(long)addrHigh << 32) | addrLow;
921         }
922         static bool isVisible(long addr)
923         {
924             return !((addr >> 32) & 0xffffffff);
925         }
926         static bool isNull(long addr)
927         {
928             return ( addr == 0 || addr == ((0xffff0000L << 32) | 0xffff0000) );
929         }
930     }
931 }
932 
933 /**
934  * Provides a way of storing flags in unused parts of a typical D array.
935  *
936  * By unused I mean the highest bits of the length.
937  * (We don't need to support 4 billion slots per signal with int
938  * or 10^19 if length gets changed to 64 bits.)
939  */
940 private struct SlotArray {
941     // Choose int for now, this saves 4 bytes on 64 bits.
942     alias int lengthType;
943     import std.bitmanip : bitfields;
944     enum reservedBitsCount = 3;
945     enum maxSlotCount = lengthType.max >> reservedBitsCount;
946     SlotImpl[] slots() @property
947     {
948         return _ptr[0 .. length];
949     }
950     void slots(SlotImpl[] newSlots) @property
951     {
952         _ptr = newSlots.ptr;
953         version(assert)
954         {
955             import std.conv : text;
956             assert(newSlots.length <= maxSlotCount, text("Maximum slots per signal exceeded: ", newSlots.length, "/", maxSlotCount));
957         }
958         _blength.length &= ~maxSlotCount;
959         _blength.length |= newSlots.length;
960     }
961     size_t length() @property
962     {
963         return _blength.length & maxSlotCount;
964     }
965 
966     bool emitInProgress() @property
967     {
968         return _blength.emitInProgress;
969     }
970     void emitInProgress(bool val) @property
971     {
972         _blength.emitInProgress = val;
973     }
974 private:
975     SlotImpl* _ptr;
976     union BitsLength {
977         mixin(bitfields!(
978                   bool, "", lengthType.sizeof*8-1,
979                   bool, "emitInProgress", 1
980                   ));
981         lengthType length;
982     }
983     BitsLength _blength;
984 }
985 unittest {
986     SlotArray arr;
987     auto tmp = new SlotImpl[10];
988     arr.slots = tmp;
989     assert(arr.length == 10);
990     assert(!arr.emitInProgress);
991     arr.emitInProgress = true;
992     assert(arr.emitInProgress);
993     assert(arr.length == 10);
994     assert(arr.slots is tmp);
995     arr.slots = tmp;
996     assert(arr.emitInProgress);
997     assert(arr.length == 10);
998     assert(arr.slots is tmp);
999     debug (signal){ import std.stdio;
1000         writeln("Slot array tests passed!");
1001     }
1002 }
1003 
1004 unittest
1005 { // Check that above example really works ...
1006     import std.functional;
1007     debug (signal) import std.stdio;
1008     class MyObject
1009     {
1010         mixin(signal!(string, int)("valueChanged"));
1011 
1012         int value() @property { return _value; }
1013         int value(int v) @property
1014         {
1015             if (v != _value)
1016             {
1017                 _value = v;
1018                 // call all the connected slots with the two parameters
1019                 _valueChanged.emit("setting new value", v);
1020             }
1021             return v;
1022         }
1023     private:
1024         int _value;
1025     }
1026 
1027     class Observer
1028     {   // our slot
1029         void watch(string msg, int i)
1030         {
1031             debug (signal) writefln("Observed msg '%s' and value %s", msg, i);
1032         }
1033     }
1034 
1035     static void watch(string msg, int i)
1036     {
1037         debug (signal) writefln("Globally observed msg '%s' and value %s", msg, i);
1038     }
1039 
1040     auto a = new MyObject;
1041     Observer o = new Observer;
1042 
1043     a.value = 3;                // should not call o.watch()
1044     a.valueChanged.connect!"watch"(o);        // o.watch is the slot
1045     a.value = 4;                // should call o.watch()
1046     a.valueChanged.disconnect!"watch"(o);     // o.watch is no longer a slot
1047     a.value = 5;                // so should not call o.watch()
1048     a.valueChanged.connect!"watch"(o);        // connect again
1049     // Do some fancy stuff:
1050     a.valueChanged.connect!Observer(o, (obj, msg, i) =>  obj.watch("Some other text I made up", i+1));
1051     a.valueChanged.connect(&watch);
1052     a.value = 6;                // should call o.watch()
1053     destroy(o);                 // destroying o should automatically disconnect it
1054     a.value = 7;                // should not call o.watch()
1055 }
1056 
1057 unittest
1058 {
1059     debug (signal) import std.stdio;
1060     class Observer
1061     {
1062         void watch(string msg, int i)
1063         {
1064             //writefln("Observed msg '%s' and value %s", msg, i);
1065             captured_value = i;
1066             captured_msg   = msg;
1067         }
1068 
1069 
1070         int    captured_value;
1071         string captured_msg;
1072     }
1073 
1074     class SimpleObserver
1075     {
1076         void watchOnlyInt(int i) {
1077             captured_value = i;
1078         }
1079         int captured_value;
1080     }
1081 
1082     class Foo
1083     {
1084         @property int value() { return _value; }
1085 
1086         @property int value(int v)
1087         {
1088             if (v != _value)
1089             {   _value = v;
1090                 _extendedSig.emit("setting new value", v);
1091                 //_simpleSig.emit(v);
1092             }
1093             return v;
1094         }
1095 
1096         mixin(signal!(string, int)("extendedSig"));
1097         //Signal!(int) simpleSig;
1098 
1099         private:
1100         int _value;
1101     }
1102 
1103     Foo a = new Foo;
1104     Observer o = new Observer;
1105     SimpleObserver so = new SimpleObserver;
1106     // check initial condition
1107     assert(o.captured_value == 0);
1108     assert(o.captured_msg == "");
1109 
1110     // set a value while no observation is in place
1111     a.value = 3;
1112     assert(o.captured_value == 0);
1113     assert(o.captured_msg == "");
1114 
1115     // connect the watcher and trigger it
1116     a.extendedSig.connect!"watch"(o);
1117     a.value = 4;
1118     assert(o.captured_value == 4);
1119     assert(o.captured_msg == "setting new value");
1120 
1121     // disconnect the watcher and make sure it doesn't trigger
1122     a.extendedSig.disconnect!"watch"(o);
1123     a.value = 5;
1124     assert(o.captured_value == 4);
1125     assert(o.captured_msg == "setting new value");
1126     //a.extendedSig.connect!Observer(o, (obj, msg, i) { obj.watch("Hahah", i); });
1127     a.extendedSig.connect!Observer(o, (obj, msg, i) => obj.watch("Hahah", i) );
1128 
1129     a.value = 7;
1130     debug (signal) stderr.writeln("After asignment!");
1131     assert(o.captured_value == 7);
1132     assert(o.captured_msg == "Hahah");
1133     a.extendedSig.disconnect(o); // Simply disconnect o, otherwise we would have to store the lamda somewhere if we want to disconnect later on.
1134     // reconnect the watcher and make sure it triggers
1135     a.extendedSig.connect!"watch"(o);
1136     a.value = 6;
1137     assert(o.captured_value == 6);
1138     assert(o.captured_msg == "setting new value");
1139 
1140     // destroy the underlying object and make sure it doesn't cause
1141     // a crash or other problems
1142     debug (signal) stderr.writefln("Disposing");
1143     destroy(o);
1144     debug (signal) stderr.writefln("Disposed");
1145     a.value = 7;
1146 }
1147 
1148 unittest {
1149     class Observer
1150     {
1151         int    i;
1152         long   l;
1153         string str;
1154 
1155         void watchInt(string str, int i)
1156         {
1157             this.str = str;
1158             this.i = i;
1159         }
1160 
1161         void watchLong(string str, long l)
1162         {
1163             this.str = str;
1164             this.l = l;
1165         }
1166     }
1167 
1168     class Bar
1169     {
1170         @property void value1(int v)  { _s1.emit("str1", v); }
1171         @property void value2(int v)  { _s2.emit("str2", v); }
1172         @property void value3(long v) { _s3.emit("str3", v); }
1173 
1174         mixin(signal!(string, int) ("s1"));
1175         mixin(signal!(string, int) ("s2"));
1176         mixin(signal!(string, long)("s3"));
1177     }
1178 
1179     void test(T)(T a)
1180     {
1181         auto o1 = new Observer;
1182         auto o2 = new Observer;
1183         auto o3 = new Observer;
1184 
1185         // connect the watcher and trigger it
1186         a.s1.connect!"watchInt"(o1);
1187         a.s2.connect!"watchInt"(o2);
1188         a.s3.connect!"watchLong"(o3);
1189 
1190         assert(!o1.i && !o1.l && !o1.str);
1191         assert(!o2.i && !o2.l && !o2.str);
1192         assert(!o3.i && !o3.l && !o3.str);
1193 
1194         a.value1 = 11;
1195         assert(o1.i == 11 && !o1.l && o1.str == "str1");
1196         assert(!o2.i && !o2.l && !o2.str);
1197         assert(!o3.i && !o3.l && !o3.str);
1198         o1.i = -11; o1.str = "x1";
1199 
1200         a.value2 = 12;
1201         assert(o1.i == -11 && !o1.l && o1.str == "x1");
1202         assert(o2.i == 12 && !o2.l && o2.str == "str2");
1203         assert(!o3.i && !o3.l && !o3.str);
1204         o2.i = -12; o2.str = "x2";
1205 
1206         a.value3 = 13;
1207         assert(o1.i == -11 && !o1.l && o1.str == "x1");
1208         assert(o2.i == -12 && !o1.l && o2.str == "x2");
1209         assert(!o3.i && o3.l == 13 && o3.str == "str3");
1210         o3.l = -13; o3.str = "x3";
1211 
1212         // disconnect the watchers and make sure it doesn't trigger
1213         a.s1.disconnect!"watchInt"(o1);
1214         a.s2.disconnect!"watchInt"(o2);
1215         a.s3.disconnect!"watchLong"(o3);
1216 
1217         a.value1 = 21;
1218         a.value2 = 22;
1219         a.value3 = 23;
1220         assert(o1.i == -11 && !o1.l && o1.str == "x1");
1221         assert(o2.i == -12 && !o1.l && o2.str == "x2");
1222         assert(!o3.i && o3.l == -13 && o3.str == "x3");
1223 
1224         // reconnect the watcher and make sure it triggers
1225         a.s1.connect!"watchInt"(o1);
1226         a.s2.connect!"watchInt"(o2);
1227         a.s3.connect!"watchLong"(o3);
1228 
1229         a.value1 = 31;
1230         a.value2 = 32;
1231         a.value3 = 33;
1232         assert(o1.i == 31 && !o1.l && o1.str == "str1");
1233         assert(o2.i == 32 && !o1.l && o2.str == "str2");
1234         assert(!o3.i && o3.l == 33 && o3.str == "str3");
1235 
1236         // destroy observers
1237         destroy(o1);
1238         destroy(o2);
1239         destroy(o3);
1240         a.value1 = 41;
1241         a.value2 = 42;
1242         a.value3 = 43;
1243     }
1244 
1245     test(new Bar);
1246 
1247     class BarDerived: Bar
1248     {
1249         @property void value4(int v)  { _s4.emit("str4", v); }
1250         @property void value5(int v)  { _s5.emit("str5", v); }
1251         @property void value6(long v) { _s6.emit("str6", v); }
1252 
1253         mixin(signal!(string, int) ("s4"));
1254         mixin(signal!(string, int) ("s5"));
1255         mixin(signal!(string, long)("s6"));
1256     }
1257 
1258     auto a = new BarDerived;
1259 
1260     test!Bar(a);
1261     test!BarDerived(a);
1262 
1263     auto o4 = new Observer;
1264     auto o5 = new Observer;
1265     auto o6 = new Observer;
1266 
1267     // connect the watcher and trigger it
1268     a.s4.connect!"watchInt"(o4);
1269     a.s5.connect!"watchInt"(o5);
1270     a.s6.connect!"watchLong"(o6);
1271 
1272     assert(!o4.i && !o4.l && !o4.str);
1273     assert(!o5.i && !o5.l && !o5.str);
1274     assert(!o6.i && !o6.l && !o6.str);
1275 
1276     a.value4 = 44;
1277     assert(o4.i == 44 && !o4.l && o4.str == "str4");
1278     assert(!o5.i && !o5.l && !o5.str);
1279     assert(!o6.i && !o6.l && !o6.str);
1280     o4.i = -44; o4.str = "x4";
1281 
1282     a.value5 = 45;
1283     assert(o4.i == -44 && !o4.l && o4.str == "x4");
1284     assert(o5.i == 45 && !o5.l && o5.str == "str5");
1285     assert(!o6.i && !o6.l && !o6.str);
1286     o5.i = -45; o5.str = "x5";
1287 
1288     a.value6 = 46;
1289     assert(o4.i == -44 && !o4.l && o4.str == "x4");
1290     assert(o5.i == -45 && !o4.l && o5.str == "x5");
1291     assert(!o6.i && o6.l == 46 && o6.str == "str6");
1292     o6.l = -46; o6.str = "x6";
1293 
1294     // disconnect the watchers and make sure it doesn't trigger
1295     a.s4.disconnect!"watchInt"(o4);
1296     a.s5.disconnect!"watchInt"(o5);
1297     a.s6.disconnect!"watchLong"(o6);
1298 
1299     a.value4 = 54;
1300     a.value5 = 55;
1301     a.value6 = 56;
1302     assert(o4.i == -44 && !o4.l && o4.str == "x4");
1303     assert(o5.i == -45 && !o4.l && o5.str == "x5");
1304     assert(!o6.i && o6.l == -46 && o6.str == "x6");
1305 
1306     // reconnect the watcher and make sure it triggers
1307     a.s4.connect!"watchInt"(o4);
1308     a.s5.connect!"watchInt"(o5);
1309     a.s6.connect!"watchLong"(o6);
1310 
1311     a.value4 = 64;
1312     a.value5 = 65;
1313     a.value6 = 66;
1314     assert(o4.i == 64 && !o4.l && o4.str == "str4");
1315     assert(o5.i == 65 && !o4.l && o5.str == "str5");
1316     assert(!o6.i && o6.l == 66 && o6.str == "str6");
1317 
1318     // destroy observers
1319     destroy(o4);
1320     destroy(o5);
1321     destroy(o6);
1322     a.value4 = 44;
1323     a.value5 = 45;
1324     a.value6 = 46;
1325 }
1326 
1327 unittest
1328 {
1329     import std.stdio;
1330 
1331     struct Property
1332     {
1333         alias value this;
1334         mixin(signal!(int)("signal"));
1335         @property int value()
1336         {
1337             return value_;
1338         }
1339         ref Property opAssign(int val)
1340         {
1341             debug (signal) writeln("Assigning int to property with signal: ", &this);
1342             value_ = val;
1343             _signal.emit(val);
1344             return this;
1345         }
1346         private:
1347         int value_;
1348     }
1349 
1350     void observe(int val)
1351     {
1352         debug (signal) writefln("observe: Wow! The value changed: %s", val);
1353     }
1354 
1355     class Observer
1356     {
1357         void observe(int val)
1358         {
1359             debug (signal) writefln("Observer: Wow! The value changed: %s", val);
1360             debug (signal) writefln("Really! I must know I am an observer (old value was: %s)!", observed);
1361             observed = val;
1362             count++;
1363         }
1364         int observed;
1365         int count;
1366     }
1367     Property prop;
1368     void delegate(int) dg = (val) => observe(val);
1369     prop.signal.strongConnect(dg);
1370     assert(prop.signal._impl._slots.length==1);
1371     Observer o=new Observer;
1372     prop.signal.connect!"observe"(o);
1373     assert(prop.signal._impl._slots.length==2);
1374     debug (signal) writeln("Triggering on original property with value 8 ...");
1375     prop=8;
1376     assert(o.count==1);
1377     assert(o.observed==prop);
1378 }
1379 
1380 unittest
1381 {
1382     debug (signal) import std.stdio;
1383     import std.conv;
1384     Signal!() s1;
1385     void testfunc(int id)
1386     {
1387         throw new Exception(to!string(id));
1388     }
1389     s1.strongConnect(() => testfunc(0));
1390     s1.strongConnect(() => testfunc(1));
1391     s1.strongConnect(() => testfunc(2));
1392     try s1.emit();
1393     catch(Exception e)
1394     {
1395         Throwable t=e;
1396         int i=0;
1397         while (t)
1398         {
1399             debug (signal) stderr.writefln("Caught exception (this is fine)");
1400             assert(to!int(t.msg)==i);
1401             t=t.next;
1402             i++;
1403         }
1404         assert(i==3);
1405     }
1406 }
1407 unittest
1408 {
1409     class A
1410     {
1411         mixin(signal!(string, int)("s1"));
1412     }
1413 
1414     class B : A
1415     {
1416         mixin(signal!(string, int)("s2"));
1417     }
1418 }
1419 
1420 unittest
1421 {
1422     struct Test
1423     {
1424         mixin(signal!int("a", Protection.package_));
1425         mixin(signal!int("ap", Protection.private_));
1426         mixin(signal!int("app", Protection.protected_));
1427         mixin(signal!int("an", Protection.none));
1428     }
1429 
1430     static assert(signal!int("a", Protection.package_)=="package Signal!(int) _a;\nref RestrictedSignal!(int) a() { return _a;}\n");
1431     static assert(signal!int("a", Protection.protected_)=="protected Signal!(int) _a;\nref RestrictedSignal!(int) a() { return _a;}\n");
1432     static assert(signal!int("a", Protection.private_)=="private Signal!(int) _a;\nref RestrictedSignal!(int) a() { return _a;}\n");
1433     static assert(signal!int("a", Protection.none)=="private Signal!(int) _a;\nref Signal!(int) a() { return _a;}\n");
1434 
1435     debug (signal)
1436     {
1437         pragma(msg, signal!int("a", Protection.package_));
1438         pragma(msg, signal!(int, string, int[int])("a", Protection.private_));
1439         pragma(msg, signal!(int, string, int[int], float, double)("a", Protection.protected_));
1440         pragma(msg, signal!(int, string, int[int], float, double, long)("a", Protection.none));
1441     }
1442 }
1443 
1444 unittest // Test nested emit/removal/addition ...
1445 {
1446     Signal!() sig;
1447     bool doEmit = true;
1448     int counter = 0;
1449     int slot3called = 0;
1450     int slot3shouldcalled = 0;
1451     void slot1()
1452     {
1453         doEmit = !doEmit;
1454         if (!doEmit)
1455             sig.emit();
1456     }
1457     void slot3()
1458     {
1459         slot3called++;
1460     }
1461     void slot2()
1462     {
1463         debug (signal) { import std.stdio; writefln("\nCALLED: %s, should called: %s", slot3called, slot3shouldcalled);}
1464         assert (slot3called == slot3shouldcalled);
1465         if ( ++counter < 100)
1466             slot3shouldcalled += counter;
1467         if ( counter < 100 )
1468             sig.strongConnect(&slot3);
1469     }
1470     void slot4()
1471     {
1472         if ( counter == 100 )
1473             sig.strongDisconnect(&slot3); // All connections dropped
1474     }
1475     sig.strongConnect(&slot1);
1476     sig.strongConnect(&slot2);
1477     sig.strongConnect(&slot4);
1478     for (int i=0; i<1000; i++)
1479         sig.emit();
1480     debug (signal)
1481     {
1482         import std.stdio;
1483         writeln("slot3called: ", slot3called);
1484     }
1485 }
1486 /* vim: set ts=4 sw=4 expandtab : */