1 #pragma once
2
3 /** @file the_Foundation/object.h Reference-counted object.
4
5 Object is reference-counted and gets deleted only after all references are gone.
6 Object is used as a base class for many of the objects in the_Foundation.
7
8 @authors Copyright (c) 2017 Jaakko Keränen <jaakko.keranen@iki.fi>
9
10 @par License
11
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14
15 1. Redistributions of source code must retain the above copyright notice, this
16 list of conditions and the following disclaimer.
17 2. Redistributions in binary form must reproduce the above copyright notice,
18 this list of conditions and the following disclaimer in the documentation
19 and/or other materials provided with the distribution.
20
21 <small>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</small>
31 */
32
33 #include "defs.h"
34 #include "class.h"
35 #include "atomic.h"
36
37 iBeginPublic
38
39 #define iNew(typeName) ((i##typeName *) new_Object(&Class_##typeName))
40
41 #define iDeclareObjectConstruction(typeName) \
42 i##typeName *new_##typeName(void); \
43 iLocalDef i##typeName *collect_##typeName(i##typeName *d) { \
44 return iCollectDel(d, (iDeleteFunc) deref_Object); \
45 } \
46 void init_##typeName(i##typeName *d); \
47 void deinit_##typeName(i##typeName *d); \
48 iLocalDef const i##typeName##Class *class_##typeName(const i##typeName *d) { \
49 return (const i##typeName##Class *) class_Object(d);\
50 }
51
52 #define iDeclareObjectConstructionArgs(typeName, ...) \
53 i##typeName *new_##typeName(__VA_ARGS__); \
54 iLocalDef i##typeName *collect_##typeName(i##typeName *d) { \
55 return iCollectDel(d, (iDeleteFunc) deref_Object); \
56 } \
57 void init_##typeName(i##typeName *d, __VA_ARGS__); \
58 void deinit_##typeName(i##typeName *d); \
59 iLocalDef const i##typeName##Class *class_##typeName(const i##typeName *d) { \
60 return (const i##typeName##Class *) class_Object(d);\
61 }
62
63 #define iDefineObjectConstruction(typeName) \
64 i##typeName *new_##typeName(void) { \
65 i##typeName *d = iNew(typeName); \
66 init_##typeName(d); \
67 return d; \
68 } \
69
70 #define iDefineObjectConstructionArgs(typeName, newArgs, ...) \
71 i##typeName *new_##typeName newArgs { \
72 i##typeName *d = iNew(typeName); \
73 init_##typeName(d, __VA_ARGS__); \
74 return d; \
75 }
76
77 #define iDeclareObjectSerialization(typeName) \
78 void serialize_##typeName(const i##typeName *, iStream *); \
79 void deserialize_##typeName(i##typeName *, iStream *);
80
81 iDeclareType(Object)
82 iDeclareType(AudienceMember)
83
84 struct Impl_Object {
85 const iClass *classObj;
86 iAtomicInt refCount;
87 iAudienceMember *memberOf;
88 void *user; /* custom user contextual data */
89 uint32_t __sig; /* validity checks in debug builds */
90 };
91
92 typedef void iAnyObject;
93
94 /**
95 * Constructs a new object.
96 *
97 * @param class Object class. Determines how much memory is allocated for the object.
98 */
99 iAnyObject * new_Object (const iAnyClass *);
100
101 void deinit_Object (iAnyObject *);
102
103 iAnyObject * ref_Object (const iAnyObject *);
104 void deref_Object (const iAnyObject *);
105 const iClass * class_Object (const iAnyObject *);
106
isInstance_Object(const iAnyObject * d,const iAnyClass * pClass)107 iLocalDef iBool isInstance_Object(const iAnyObject *d, const iAnyClass *pClass) {
108 return class_Object(d) == pClass || isDerived_Class(class_Object(d), pClass);
109 }
110
111 void setUserData_Object (iAnyObject *, void *user);
112 void * userData_Object (const iAnyObject *);
113
114 iAudienceMember * audienceMember_Object (const iAnyObject *);
115
116 int totalCount_Object (void);
117 void checkSignature_Object (const iAnyObject *);
118
119 #if !defined (NDEBUG)
120 #define iAssertIsObject(d) checkSignature_Object(d)
121 #else
122 #define iAssertIsObject(d)
123 #endif
124
collect_Object(const iAnyObject * d)125 iLocalDef iAnyObject *collect_Object(const iAnyObject *d) {
126 if (d) {
127 iAssertIsObject(d);
128 return collect_Garbage(iConstCast(iAnyObject *, d), (iDeleteFunc) deref_Object);
129 }
130 return NULL;
131 }
132
iRelease(const iAnyObject * d)133 iLocalDef void iRelease(const iAnyObject *d) {
134 deref_Object(d);
135 }
136
137 #define iChangeRef(d, ptr) { iRelease(d); (d) = ref_Object(ptr); }
138
139 #define iReleasePtr(d) { iAssert((d) != NULL); if (d) { deref_Object(*(d)); *(d) = NULL; } }
140
iReleaseLater(const iAnyObject * d)141 iLocalDef iAnyObject *iReleaseLater(const iAnyObject *d) {
142 return collect_Object(d);
143 }
144
145 #define iClob(d) iReleaseLater(d) // clob == collect object
146
147 iEndPublic
148
149 #if defined (__cplusplus)
150 namespace tF {
151
152 template <typename T>
153 class ref {
154 T *_ptr;
155 public:
ref()156 ref() : _ptr(nullptr) {}
ref(const T * p)157 ref(const T *p) : _ptr(static_cast<T *>(ref_Object(p))) {}
ref(const ref & other)158 ref(const ref &other) : _ptr(static_cast<T *>(ref_Object(other._ptr))) {}
ref(ref && moved)159 ref(ref &&moved) : _ptr(moved._ptr) {
160 moved._ptr = nullptr;
161 }
~ref()162 ~ref() { deref_Object(_ptr); }
163 void reset(const T *p = nullptr) {
164 if (_ptr != p) {
165 deref_Object(_ptr);
166 _ptr = static_cast<T *>(ref_Object(p));
167 }
168 }
169 ref &operator=(const ref &other) {
170 reset(other._ptr);
171 return *this;
172 }
173 ref &operator=(ref &&moved) {
174 reset();
175 std::swap(_ptr, moved._ptr);
176 return *this;
177 }
178 explicit operator bool() const { return _ptr != nullptr; }
179 operator T *() const { return _ptr; }
180 operator const T *() const { return _ptr; }
181 T *operator->() const { return _ptr; }
182 T &operator*() const { return *_ptr; }
take(T * p)183 static ref take(T *p) {
184 ref<T> r(p);
185 deref_Object(p);
186 return r;
187 }
188 };
189
make_ref(T * p)190 template <typename T> ref<T> make_ref(T *p) {
191 ref<T> r(p);
192 iRelease(p);
193 return r;
194 }
195
196 } // namespace tF
197 #endif
198