Free memory with dbus_free instead of free. Account for NULL signatures.
[dbus-cxx-async.git] / include / dbus-c++ / util.h
blob3740eea4999e0d56073e25435673ae9940431691
1 /*
3 * D-Bus++ - C++ bindings for D-Bus
5 * Copyright (C) 2005-2009 Paolo Durante <shackan@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifndef __DBUSXX_UTIL_H
26 #define __DBUSXX_UTIL_H
28 #include <pthread.h>
30 #ifdef __QNXNTO__
31 #include <atomic.h>
32 #else
33 #include <ext/atomicity.h>
34 #endif
36 #include <set>
37 #include "api.h"
38 #include "debug.h"
40 namespace DBus {
43 // Platform independent atomic support
45 #ifdef __QNXNTO__
47 class AtomicCounter
49 public:
50 typedef unsigned tAtomicCnt;
52 AtomicCounter(tAtomicCnt init_val):
53 _counter(init_val)
56 operator tAtomicCnt()
58 return atomic_add_value(&_counter, 0U);
61 void inc()
63 atomic_add(&_counter, 1);
66 void dec()
68 atomic_sub(&_counter, 1);
71 protected:
72 volatile tAtomicCnt _counter;
75 #elif defined(__GNUC__)
77 class AtomicCounter
79 public:
80 typedef _Atomic_word tAtomicCnt;
82 AtomicCounter(tAtomicCnt init_val):
83 _counter(init_val)
86 operator tAtomicCnt()
88 return __gnu_cxx::__exchange_and_add(&_counter, 0);
91 void inc()
93 __gnu_cxx::__atomic_add(&_counter, +1);
96 void dec()
98 __gnu_cxx::__atomic_add(&_counter, -1);
101 protected:
102 volatile tAtomicCnt _counter;
105 #else
106 #error Atomic operations are not defined for this OS and/or compiler
107 #endif
110 * Very simple reference counting
113 class DBUSXXAPI RefCnt
115 public:
117 RefCnt()
119 __ref = new AtomicCounter(1);
122 RefCnt(const RefCnt &rc)
124 __ref = rc.__ref;
125 ref();
128 virtual ~RefCnt()
130 unref();
133 RefCnt &operator = (const RefCnt &ref)
135 if (&ref != this)
137 ref.ref();
138 unref();
139 __ref = ref.__ref;
141 return *this;
144 bool noref() const
146 return (*__ref) == 0;
149 bool one() const
151 return (*__ref) == 1;
154 private:
156 DBUSXXAPILOCAL void ref() const
158 __ref->inc();
161 DBUSXXAPILOCAL void unref()
163 __ref->dec();
165 if ((*__ref) < 0)
167 debug_log("%p: refcount dropped below zero!", __ref);
170 if (noref())
172 delete __ref;
173 __ref = 0;
177 private:
179 AtomicCounter* __ref;
183 * Pthreads-based mutual exclusion
185 class Synchronized
187 protected:
189 struct Guard
191 Guard(const Synchronized *s) : _s(s)
193 _s->lock();
195 ~Guard()
197 _s->unlock();
199 const Synchronized *_s;
202 void lock() const
204 pthread_mutex_lock(&__mtx);
207 void unlock() const
209 pthread_mutex_unlock(&__mtx);
212 protected:
214 Synchronized()
216 pthread_mutex_init(&__mtx, NULL);
219 public:
221 ~Synchronized()
223 pthread_mutex_destroy(&__mtx);
226 private:
228 // Not supported - unimplemented
229 Synchronized(const Synchronized& lhs);
230 Synchronized& operator=(const Synchronized& ref);
232 mutable pthread_mutex_t __mtx;
236 * Reference counting pointers (emulate boost::shared_ptr)
239 class RefPtrVoid
241 public:
243 RefPtrVoid(void *ptr)
244 : __ptr(ptr)
245 , __cnt()
248 RefPtrVoid(const RefPtrVoid& lhs)
249 : __ptr(0)
250 , __cnt()
253 virtual ~RefPtrVoid()
256 bool operator == (const RefPtrVoid &ref) const
258 return __ptr == ref.__ptr;
261 protected:
263 void *__ptr;
264 RefCnt __cnt;
267 template <class T>
268 class RefPtrI : public RefPtrVoid // RefPtr to incomplete type
270 public:
272 RefPtrI(T *ptr = 0);
274 RefPtrI(const RefPtrI<T>& lhs);
276 ~RefPtrI();
278 RefPtrI<T>& operator = (const RefPtrI<T> &ref);
280 T &operator *() const
282 return *get();
285 T *operator ->() const
287 return get();
290 T *get() const
292 return static_cast<T *>(__ptr);
296 template <class T>
297 class RefPtr : public RefPtrVoid
299 public:
301 RefPtr(T *ptr = 0)
302 : RefPtrVoid(ptr)
305 RefPtr(const RefPtr<T>& lhs)
306 : RefPtrVoid(0)
308 operator=(lhs);
311 ~RefPtr()
313 if (__cnt.one()) delete get();
316 RefPtr<T>& operator = (const RefPtr<T>& ref)
318 if (this != &ref)
320 // If there is only a single reference (that's us) then ...
321 if (__cnt.one())
323 delete get();
324 __ptr = 0;
326 __ptr = ref.__ptr;
327 __cnt = ref.__cnt;
329 return *this;
332 T &operator *() const
334 return *get();
337 T *operator ->() const
339 return get();
342 T *get() const
344 return static_cast<T *>(__ptr);
349 * Typed callback template
353 // Forward Declarations
355 class CallbackEmitter;
356 class CallbackTarget;
358 class CallbackEmitter : protected Synchronized
360 public:
361 CallbackEmitter();
362 virtual ~CallbackEmitter();
364 protected:
365 void connect(CallbackTarget* tgt);
367 void disconnect();
369 bool isConnected() const;
371 private:
372 CallbackTarget* target;
373 friend class CallbackTarget;
376 class CallbackTarget : protected Synchronized
378 public:
379 CallbackTarget();
380 virtual ~CallbackTarget();
382 private:
383 void disconnect_emitter(CallbackEmitter* cbEmitter);
384 void connect_emitter(CallbackEmitter* cbEmitter);
386 typedef std::set<CallbackEmitter*> EmitterCollection;
387 EmitterCollection emitters;
388 friend class CallbackEmitter;
392 // CallbackTarget Implementation
394 inline CallbackTarget::CallbackTarget()
395 : Synchronized()
396 , emitters()
398 debug_log("CallbackTarget(%p)::Constructed");
401 inline CallbackTarget::~CallbackTarget()
403 Guard g(this);
404 EmitterCollection::const_iterator it;
405 // Tell all the callback emitters that this target is
406 // being disconnected.
407 debug_log("CallbackTarget(%p)::# Emitters to disconnect: %u",
408 this, emitters.size());
410 for ( it = emitters.begin(); it != emitters.end(); ++it )
412 debug_log("CallbackTarget(%p)::Disconnect emitter: %p", this, *it);
413 (*it)->disconnect();
415 emitters.clear();
416 debug_log("CallbackTarget(%p)::Destroyed", this);
419 inline void CallbackTarget::disconnect_emitter(CallbackEmitter* cbEmitter)
421 Guard g(this);
422 debug_log("CallbackTarget(%p)::Erasing emitter: %p", this, cbEmitter);
423 emitters.erase(cbEmitter);
426 inline void CallbackTarget::connect_emitter(CallbackEmitter* cbEmitter)
428 Guard g(this);
429 debug_log("CallbackTarget(%p)::Inserting emitter: %p", this, cbEmitter);
430 emitters.insert(cbEmitter);
434 // CallbackEmitter Implementation
437 inline CallbackEmitter::CallbackEmitter()
438 : Synchronized()
439 , target(0)
441 debug_log("CallbackEmitter(%p)::Constructed", this);
444 inline CallbackEmitter::~CallbackEmitter()
446 Guard g(this);
448 if ( target )
450 debug_log("CallbackEmitter(%p)::Disconnecting from target: %p", this, target);
451 target->disconnect_emitter(this);
454 debug_log("CallbackEmitter(%p)::Destroyed", this);
457 inline void CallbackEmitter::connect(CallbackTarget* tgt)
459 Guard g(this);
461 if ( target && (target != tgt) )
463 // Unregister from the (old) target first
464 debug_log("CallbackEmitter(%p)::Unregistering emitter from target: %p", this, target);
465 target->disconnect_emitter(this);
468 target = tgt;
469 if ( target )
471 debug_log("CallbackEmitter(%p)::Connecting to target: %p", this, target);
472 target->connect_emitter(this);
476 inline void CallbackEmitter::disconnect()
478 Guard g(this);
479 debug_log("CallbackEmitter(%p)::Disconnecting target: %p", this, target);
480 target = 0;
483 inline bool CallbackEmitter::isConnected() const
485 return 0 != target;
489 template <class R, class P>
490 class Callback_Base : public CallbackEmitter
492 public:
493 Callback_Base() : CallbackEmitter() {}
495 virtual R call(P param) const = 0;
497 virtual ~Callback_Base()
501 template <class R, class P>
502 class Slot
504 public:
506 Slot &operator = (Callback_Base<R,P>* s)
508 _cb = s;
510 return *this;
513 R operator()(P param) const
515 /*if (_cb.get())*/ return _cb->call(param);
518 R call(P param) const
520 /*if (_cb.get())*/ return _cb->call(param);
523 bool empty()
525 return _cb.get() == 0;
528 private:
530 RefPtr< Callback_Base<R,P> > _cb;
534 template <class C, class P>
535 class CallbackNoReturn : public Callback_Base<void,P>
537 public:
539 typedef void (C::*M)(P);
541 CallbackNoReturn(C *c, M m)
542 : _c(c), _m(m)
544 debug_log("CallbackNoReturn(%p)::Ctor - connect to target: %p", this, c);
545 CallbackEmitter::connect(c);
548 virtual ~CallbackNoReturn()
550 debug_log("CallbackNoReturn(%p)::Destroyed", this);
553 void call(P param) const
555 Synchronized::Guard g(this);
557 if ( CallbackEmitter::isConnected() )
559 (_c->*_m)(param);
561 return;
564 private:
566 C *_c; M _m;
569 template <class C, class R, class P>
570 class Callback : public Callback_Base<R,P>
572 public:
574 typedef R (C::*M)(P);
576 Callback(C *c, M m, const R& def)
577 : _c(c), _m(m), _d(def)
579 debug_log("Callback(%p)::Ctor - connect to target: %p", this, c);
580 CallbackEmitter::connect(c);
583 virtual ~Callback()
585 debug_log("Callback(%p)::Destroyed", this);
588 R call(P param) const
590 Synchronized::Guard g(this);
592 if ( CallbackEmitter::isConnected() )
594 return (_c->*_m)(param);
596 return _d;
599 private:
601 C *_c; M _m; R _d;
604 } /* namespace DBus */
606 #endif//__DBUSXX_UTIL_H