comparison qt/d2/qt/Signal.d @ 276:501128ac7a2c

signals cleaned up correctly on receiver destruction
author maxter
date Tue, 29 Sep 2009 12:00:45 +0000
parents cf6a4cd0e3f2
children 5df570e79cfc
comparison
equal deleted inserted replaced
275:bb0f228c27cd 276:501128ac7a2c
33 a = (cast(T*)crealloc(a.ptr, length * T.sizeof))[0..length]; 33 a = (cast(T*)crealloc(a.ptr, length * T.sizeof))[0..length];
34 if (!a.ptr) 34 if (!a.ptr)
35 new OutOfMemoryError(__FILE__, __LINE__); 35 new OutOfMemoryError(__FILE__, __LINE__);
36 } 36 }
37 37
38 unittest 38
39 { 39 void append(T)(ref T[] a, T element)
40 int[] a; 40 {
41 realloc(a, 16); 41 auto newLen = a.length + 1;
42 assert(a.length == 16); 42 a = (cast(T*)crealloc(a.ptr, newLen * T.sizeof))[0..newLen];
43 foreach (i, ref e; a) 43 if (!a.ptr)
44 e = i; 44 new OutOfMemoryError(__FILE__, __LINE__);
45 realloc(a, 4096); 45 a[newLen - 1] = element;
46 assert(a.length == 4096); 46 }
47 foreach (i, e; a[0..16]) 47
48 assert(e == i); 48 void move(T)(ref T[] a, size_t src, size_t dest, size_t length)
49 cfree(a.ptr); 49 {
50 } 50 if (a.length > 1)
51 51 memmove(a.ptr + dest, a.ptr + src, length * T.sizeof);
52 }
53
54 // COMPILER BUG: Though this is private cannot name it 'remove' because of conflicts
55 // with Array.remove
56 void erase(T)(ref T[] a, size_t i)
57 {
58 auto newLen = a.length - 1;
59 move(a, i + 1, i, newLen);
60 realloc(a, newLen);
61 }
62
63 version (QtdUnittest)
64 {
65 unittest
66 {
67 int[] a;
68 realloc(a, 16);
69 assert(a.length == 16);
70 foreach (i, ref e; a)
71 e = i;
72 realloc(a, 4096);
73 assert(a.length == 4096);
74 foreach (i, e; a[0..16])
75 assert(e == i);
76 cfree(a.ptr);
77 }
78 }
52 79
53 //TODO: should be in the standard library 80 //TODO: should be in the standard library
54 struct STuple(A...) 81 struct STuple(A...)
55 { 82 {
56 static string genSTuple() 83 static string genSTuple()
61 return r; 88 return r;
62 } 89 }
63 90
64 mixin (genSTuple); 91 mixin (genSTuple);
65 template at(size_t i) { mixin("alias _" ~ ToString!(i) ~ " at;"); }; 92 template at(size_t i) { mixin("alias _" ~ ToString!(i) ~ " at;"); };
66 }
67
68 void move(T)(ref T[] a, size_t src, size_t dest, size_t length)
69 {
70 if (a.length > 1)
71 memmove(a.ptr + dest, a.ptr + src, length * T.sizeof);
72 } 93 }
73 94
74 enum SignalEventId 95 enum SignalEventId
75 { 96 {
76 firstSlotConnected, 97 firstSlotConnected,
150 { 171 {
151 alias R Receiver; 172 alias R Receiver;
152 173
153 Receiver receiver; 174 Receiver receiver;
154 Dg invoker; 175 Dg invoker;
155 176 ConnectionFlags flags;
177
156 static if (is(Receiver == Dg)) 178 static if (is(Receiver == Dg))
157 { 179 {
158 static const isDelegate = true; 180 static const isDelegate = true;
159 181
160 void onReceiverDisposed(Object o)
161 {
162 assert (lock !is null);
163 synchronized(lock)
164 {
165 receiver.context = null;
166 receiver.funcptr = null;
167 }
168 }
169
170 // null if receiver doesn't point to a disposable object
171 Object lock;
172
173 bool isDisposed() 182 bool isDisposed()
174 { 183 {
175 return !receiver.funcptr; 184 return !receiver.funcptr;
176 } 185 }
186
187 void dispose()
188 {
189 receiver.funcptr = null;
190 receiver.context = null;
191 }
177 192
178 Object getObject() 193 Object getObject()
179 { 194 {
180 return lock ? _d_toObject(receiver.context) : null; 195 return flags & ConnectionFlags.NoObject || !receiver.context
196 ? null : _d_toObject(receiver.context);
181 } 197 }
182 } 198 }
183 else 199 else
184 static const isDelegate = false; 200 static const isDelegate = false;
185 } 201 }
256 s.changed.emit; // bar is called. 272 s.changed.emit; // bar is called.
257 s.changed.disconnect(&bar); // must be explicitly disconnected. 273 s.changed.disconnect(&bar); // must be explicitly disconnected.
258 } 274 }
259 ---- 275 ----
260 */ 276 */
261 public enum ConnectionFlags 277 public enum ConnectionFlags : ubyte
262 { 278 {
263 /// 279 ///
264 None, 280 None,
265 /** 281 /**
266 The receiver will be stored as weak reference (implied if ConnectionFlags.NoObject is not specified). 282 The receiver will be stored as weak reference (implied if ConnectionFlags.NoObject is not specified).
321 return data.length; 337 return data.length;
322 } 338 }
323 339
324 void free() 340 void free()
325 { 341 {
326 static if (SlotType.isDelegate)
327 {
328 foreach (ref slot; data)
329 {
330 if (auto obj = slot.getObject)
331 rt_detachDisposeEvent(obj, &slot.onReceiverDisposed);
332 }
333 }
334 static if (!strong) 342 static if (!strong)
335 cfree(data.ptr); 343 cfree(data.ptr);
336 } 344 }
337 } 345 }
338 346
339 public alias void delegate(int signalId, SignalEventId event) SignalEvent; 347 public alias void delegate(int signalId, SignalEventId event) SignalEvent;
348
349 struct Receivers
350 {
351 struct Data
352 {
353 Object object;
354 int refs;
355 }
356
357 Data[] data;
358 void add(Object receiver, DEvent disposeEvent)
359 {
360 foreach (ref d; data)
361 {
362 if (d.object is receiver)
363 {
364 d.refs++;
365 return;
366 }
367 }
368
369 append(data, Data(receiver, 1));
370 rt_attachDisposeEvent(receiver, disposeEvent);
371 }
372
373 void remove(Object receiver, DEvent disposeEvent)
374 {
375 foreach (i, ref d; data)
376 {
377 if (d.object is receiver)
378 {
379 assert (d.refs);
380 d.refs--;
381 if (!d.refs)
382 {
383 .erase(data, i);
384 rt_detachDisposeEvent(receiver, disposeEvent);
385 }
386 return;
387 }
388 }
389
390 assert (false);
391 }
392
393 // remove all refarences for receiver, receiver has been disposed
394 void removeAll(Object receiver)
395 {
396 foreach (i, ref d; data)
397 {
398 if (d.object is receiver)
399 {
400 .erase(data, i);
401 return;
402 }
403 }
404 }
405
406 // remove all references for all receivers, detaching dispose events
407 void free(DEvent disposeEvent)
408 {
409 foreach (i, ref d; data)
410 rt_detachDisposeEvent(d.object, disposeEvent);
411 cfree(data.ptr);
412 data = null;
413 }
414 }
340 415
341 struct SignalConnections 416 struct SignalConnections
342 { 417 {
343 bool isInUse; 418 bool isInUse;
344 419
406 { 481 {
407 foreach(i, e; slotLists.tupleof) 482 foreach(i, e; slotLists.tupleof)
408 { 483 {
409 static if (is(typeof(slotLists.at!(i).free))) 484 static if (is(typeof(slotLists.at!(i).free)))
410 slotLists.at!(i).free; 485 slotLists.at!(i).free;
486 }
487 }
488
489 void onReceiverDisposed(Object receiver)
490 {
491 foreach (i, e; slotLists.tupleof)
492 {
493 static if (slotLists.at!(i).SlotType.isDelegate)
494 {
495 foreach (ref slot; slotLists.at!(i).data)
496 {
497 if (slot.getObject is receiver)
498 slot.dispose;
499 }
500 }
411 } 501 }
412 } 502 }
413 503
414 template SlotListType(int slotListId) 504 template SlotListType(int slotListId)
415 { 505 {
438 */ 528 */
439 public Object signalSender() { 529 public Object signalSender() {
440 return signalSender_; 530 return signalSender_;
441 } 531 }
442 532
443 public class SignalHandler 533 public final class SignalHandler
444 { 534 {
445 SignalConnections[] connections; 535 SignalConnections[] connections;
536 Receivers receivers;
446 Object owner; 537 Object owner;
447 int blocked; 538 int blocked;
448 539
449 SignalEvent signalEvent; 540 SignalEvent signalEvent;
450 541
461 return &connections[signalId]; 552 return &connections[signalId];
462 return null; 553 return null;
463 } 554 }
464 555
465 private SlotType!(slotListId)* addSlot(int slotListId)(int signalId, ReceiverType!(slotListId) receiver, 556 private SlotType!(slotListId)* addSlot(int slotListId)(int signalId, ReceiverType!(slotListId) receiver,
466 Dg invoker) 557 Dg invoker, ConnectionFlags flags)
467 { 558 {
468 if (signalId >= connections.length) 559 if (signalId >= connections.length)
469 connections.length = signalId + 1; 560 connections.length = signalId + 1;
470 auto slot = connections[signalId].addSlot!(slotListId)(SlotType!(slotListId)(receiver, invoker)); 561 auto slot = connections[signalId].addSlot!(slotListId)(SlotType!(slotListId)(receiver, invoker));
471 562
472 if (signalEvent && connections[signalId].slotCount == 1) 563 static if (slot.isDelegate)
564 {
565 if (!(flags & ConnectionFlags.NoObject))
566 receivers.add(_d_toObject(receiver.context), &onReceiverDisposed);
567 }
568
569 if (signalEvent && connections[signalId].slotCount == 1)
473 signalEvent(signalId, SignalEventId.firstSlotConnected); 570 signalEvent(signalId, SignalEventId.firstSlotConnected);
474 571
475 return slot; 572 return slot;
476 } 573 }
574
575 void onReceiverDisposed(Object receiver)
576 {
577 synchronized(this)
578 {
579 foreach(ref c; connections)
580 c.onReceiverDisposed(receiver);
581 receivers.removeAll(receiver);
582 }
583 }
477 584
478 private void removeSlot(int slotListId)(int signalId, int slotId) 585 private void removeSlot(int slotListId)(int signalId, int slotId)
479 { 586 {
587 auto slot = connections[signalId].getSlotList!(slotListId).get(slotId);
588 static if (slot.isDelegate)
589 {
590 if (auto obj = slot.getObject)
591 receivers.remove(obj, &onReceiverDisposed);
592 }
593
480 connections[signalId].removeSlot!(slotListId)(slotId); 594 connections[signalId].removeSlot!(slotListId)(slotId);
481 595
482 if (signalEvent && !connections[signalId].slotCount) 596 if (signalEvent && !connections[signalId].slotCount)
483 signalEvent(signalId, SignalEventId.lastSlotDisconnected); 597 signalEvent(signalId, SignalEventId.lastSlotDisconnected);
484 }
485
486 private SlotType!(slotListId)* addObjectSlot(int slotListId)(size_t signalId, Object obj, Dg receiver,
487 Dg invoker)
488 {
489 auto slot = addSlot!(slotListId)(signalId, receiver, invoker);
490 slot.lock = this;
491 rt_attachDisposeEvent(obj, &slot.onReceiverDisposed);
492 return slot;
493 } 598 }
494 599
495 size_t slotCount(int signalId) 600 size_t slotCount(int signalId)
496 { 601 {
497 synchronized(this) 602 synchronized(this)
501 return con.slotCount; 606 return con.slotCount;
502 return 0; 607 return 0;
503 } 608 }
504 } 609 }
505 610
506 void connect(Receiver)(size_t signalId, Receiver receiver, 611 void connect(Receiver)(int signalId, Receiver receiver,
507 Dg invoker, ConnectionFlags flags) 612 Dg invoker, ConnectionFlags flags)
508 { 613 {
509 synchronized(this) 614 synchronized(this)
510 { 615 {
511 static if (is(typeof(receiver.context))) 616 static if (is(typeof(receiver.context)))
512 { 617 {
513 Object obj; 618 Object obj;
514 if ((flags & ConnectionFlags.NoObject) || (obj = _d_toObject(receiver.context)) is null) 619 if ((flags & ConnectionFlags.NoObject))
515 { 620 {
516 // strong by default 621 // strong by default
517 if (flags & ConnectionFlags.Weak) 622 if (flags & ConnectionFlags.Weak)
518 addSlot!(SlotListId.Weak)(signalId, receiver, invoker); 623 addSlot!(SlotListId.Weak)(signalId, receiver, invoker, flags);
519 else 624 else
520 addSlot!(SlotListId.Strong)(signalId, receiver, invoker); 625 addSlot!(SlotListId.Strong)(signalId, receiver, invoker, flags);
521 } 626 }
522 else 627 else
523 { 628 {
524 // weak by default 629 // weak by default
525 if (flags & ConnectionFlags.Strong) 630 if (flags & ConnectionFlags.Strong)
526 addObjectSlot!(SlotListId.Strong)(signalId, obj, receiver, invoker); 631 addSlot!(SlotListId.Strong)(signalId, receiver, invoker, flags);
527 else 632 else
528 addObjectSlot!(SlotListId.Weak)(signalId, obj, receiver, invoker); 633 addSlot!(SlotListId.Weak)(signalId, receiver, invoker, flags);
529 } 634 }
530 } 635 }
531 else 636 else
532 addSlot!(SlotListId.Func)(signalId, receiver, invoker); 637 addSlot!(SlotListId.Func)(signalId, receiver, invoker, flags);
533 } 638 }
534 } 639 }
535 640
536 void disconnect(Receiver)(int signalId, Receiver receiver) 641 void disconnect(Receiver)(int signalId, Receiver receiver)
537 { 642 {
568 } 673 }
569 } 674 }
570 675
571 if (slot.receiver == receiver) 676 if (slot.receiver == receiver)
572 { 677 {
573 static if (slot.isDelegate)
574 {
575 if (auto obj = slot.getObject)
576 rt_detachDisposeEvent(obj, &slot.onReceiverDisposed);
577 }
578 removeSlot!(slotListId)(signalId, slotId); 678 removeSlot!(slotListId)(signalId, slotId);
579 break TOP; 679 break TOP;
580 } 680 }
581 681
582 slotId++; 682 slotId++;
671 } 771 }
672 } 772 }
673 773
674 ~this() 774 ~this()
675 { 775 {
776 receivers.free(&onReceiverDisposed);
676 foreach(ref c; connections) 777 foreach(ref c; connections)
677 c.free; 778 c.free;
678 } 779 }
679 } 780 }
680 781