1 /************************************************************************
2  *
3  * Copyright 2011 Jakob Leben (jakob.leben@gmail.com)
4  *
5  * This file is part of SuperCollider Qt GUI.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  ************************************************************************/
21 
22 #pragma once
23 
24 #include "Common.h"
25 
26 #include <QApplication>
27 #include <QAtomicPointer>
28 #include <QAtomicInt>
29 #include <QMutex>
30 
31 namespace QtCollider {
32 
33 template <typename T> class SafePtr {
34 public:
SafePtr()35     SafePtr(): d(0) {}
36 
SafePtr(const SafePtr & other)37     SafePtr(const SafePtr& other): d(other.d) { ref(); }
38 
SafePtr(T * ptr)39     SafePtr(T* ptr): d(new Data(ptr)) {}
40 
operator =(const SafePtr & other)41     SafePtr& operator=(const SafePtr& other) {
42         deref();
43         d = other.d;
44         ref();
45         return *this;
46     }
47 
~SafePtr()48     ~SafePtr() { deref(); }
49 
operator ->() const50     T* operator->() const { return d->ptr.load(); }
51 
operator *() const52     T& operator*() const { return *d->ptr.load(); }
53 
operator T*() const54     operator T*() const { return (d ? d->ptr.load() : 0); }
55 
ptr() const56     T* ptr() const { return (d ? d->ptr.load() : 0); }
57 
id() const58     void* id() const { return (void*)d; } // useful for checking internal pointer identity
59 
invalidate()60     void invalidate() {
61         qcDebugMsg(2, "SafePtr: invalidating");
62         if (d)
63             d->ptr = 0;
64     }
65 
66 private:
67     struct Data {
DataQtCollider::SafePtr::Data68         Data(T* ptr_): ptr(ptr_), refCount(1) {}
69         QAtomicPointer<T> ptr;
70         QAtomicInt refCount;
71     };
72 
ref()73     void ref() {
74         if (d) {
75             d->refCount.ref();
76             qcDebugMsg(2, QString("SafePtr: +refcount = %1").arg(d->refCount.load()));
77         }
78     }
deref()79     void deref() {
80         if (d) {
81             bool ref = d->refCount.deref();
82             qcDebugMsg(2, QString("SafePtr: -refcount = %1").arg(d->refCount.load()));
83             if (!ref) {
84                 qcDebugMsg(2, "SafePtr: unreferenced!");
85                 delete d;
86             }
87         }
88     }
89 
90     Data* d;
91 };
92 
93 } // namespace QtCollider
94