boost shared pointer debugging, from an idea by carl hetherington
[ardour.git] / libs / pbd / pbd / shiva.h
1 /*
2     Copyright (C) 2000-2007 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __pbd_shiva_h__
21 #define __pbd_shiva_h__
22
23 #include <sigc++/sigc++.h>
24
25 namespace PBD {
26
27 /* named after the Hindu god Shiva, The Destroyer */
28
29 template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
30 class Shiva : public sigc::trackable 
31 {
32   public:
33         Shiva (ObjectWithGoingAway& emitter, ObjectToBeDestroyed& receiver) {
34
35                 /* if the emitter goes away, destroy the receiver */
36
37                 _connection = emitter.GoingAway.connect 
38                         (sigc::bind (sigc::mem_fun 
39                                      (*this, &Shiva<ObjectWithGoingAway,ObjectToBeDestroyed>::destroy),
40                                      &receiver));
41         }
42
43         ~Shiva() { 
44                 forget ();
45         }
46
47   private:
48         sigc::connection _connection;
49
50         void destroy (ObjectToBeDestroyed* obj) {
51                 delete obj;
52                 forget ();
53         }
54
55         void forget () {
56                 _connection.disconnect ();
57         }
58                         
59 };
60
61 template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
62 class ProxyShiva : public sigc::trackable 
63 {
64   public:
65         ProxyShiva (ObjectWithGoingAway& emitter, ObjectToBeDestroyed& receiver, void (*callback)(ObjectToBeDestroyed*, ObjectWithGoingAway*)) {
66                 
67                 /* if the emitter goes away, destroy the receiver */
68
69                 _callback = callback;
70                 _callback_argument = &emitter;
71
72                 _connection = emitter.GoingAway.connect 
73                         (sigc::bind (sigc::mem_fun 
74                                      (*this, &ProxyShiva<ObjectWithGoingAway,ObjectToBeDestroyed>::destroy),
75                                      &receiver));
76         }
77
78         ~ProxyShiva () {
79                 forget ();
80         }
81
82   private:
83         sigc::connection _connection;
84         void (*_callback) (ObjectToBeDestroyed*, ObjectWithGoingAway*);
85         ObjectWithGoingAway* _callback_argument;
86
87         void destroy (ObjectToBeDestroyed* obj) {
88                 /* callback must destroy obj if appropriate, not done here */
89                 _callback (obj, _callback_argument);
90                 forget ();
91         }
92
93         void forget () {
94                 _connection.disconnect ();
95         }
96 };
97
98 template<typename ObjectWithGoingAway, typename ObjectToBeDestroyed>
99 class PairedShiva : public sigc::trackable 
100 {
101   public:
102         PairedShiva (ObjectWithGoingAway& emitter, ObjectToBeDestroyed& receiver) {
103
104                 /* if the emitter goes away, destroy the receiver */
105
106                 _connection1 = emitter.GoingAway.connect 
107                         (sigc::bind (sigc::mem_fun 
108                                      (*this, &PairedShiva<ObjectWithGoingAway,ObjectToBeDestroyed>::destroy),
109                                      &receiver));
110
111                 /* if the receiver goes away, forget all this nonsense */
112
113                 _connection2 = receiver.GoingAway.connect 
114                         (sigc::mem_fun (*this, &PairedShiva<ObjectWithGoingAway,ObjectToBeDestroyed>::forget));
115         }
116
117         ~PairedShiva() { 
118                 forget ();
119         }
120
121   private:
122         sigc::connection _connection1;
123         sigc::connection _connection2;
124
125         void destroy (ObjectToBeDestroyed* obj) {
126                 delete obj;
127                 forget ();
128         }
129
130         void forget () {
131                 _connection1.disconnect ();
132                 _connection2.disconnect ();
133         }
134                         
135 };
136
137 }
138
139 #endif /* __pbd_shiva_h__ */