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