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