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