1 //------------------------------------------------------------------------------
2 // emModel.h
3 //
4 // Copyright (C) 2005-2008,2010,2016 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #ifndef emModel_h
22 #define emModel_h
23
24 #ifndef emRef_h
25 #include <emCore/emRef.h>
26 #endif
27
28 #ifndef emContext_h
29 #include <emCore/emContext.h>
30 #endif
31
32
33 //==============================================================================
34 //================================== emModel ===================================
35 //==============================================================================
36
37 class emModel : public emEngine {
38
39 public:
40
41 // emModel is a base class for shared data and logics.
42 //
43 // Model references
44 // ----------------
45 // Models must be referred through instances of the template class
46 // emRef. A model deletes itself automatically as soon as there are no
47 // remaining references. It is even possible to have weak references
48 // by making use of emCrossPtr.
49 //
50 // Model context
51 // -------------
52 // Each model exists within a context (see emContext, emRootContext and
53 // emView). Contexts are used for grouping and refinding models. They
54 // are making up a tree. Models in a root context are something like
55 // "global variables".
56 //
57 // Common models
58 // -------------
59 // Models can be registered within their context so that they can be
60 // refound. Registered models are called common models. The identity of
61 // a common model must be unique and consists of:
62 // - The final class of the model (determined through the RTTI
63 // function typeid).
64 // - The context of the model.
65 // - The name of the model.
66 // The name is a character string whose meaning is defined by derived
67 // model classes. It may even be generated from model specific
68 // arguments.
69 //
70 // Hint: a typedef does not change the result of typeid() and therefore
71 // it has no effect on the identity of a model. This should not be
72 // forgotten when doing something like:
73 // typedef emVarModel<int> MyIntModel;
74 // Best is not to typedef models. Make derivatives instead.
75 //
76 // Private models
77 // --------------
78 // Models which are not registered for refinding, are called private
79 // models. They do not need to have a unique identification and they are
80 // referring a context just for convenience.
81 //
82 // Lifetime of common models
83 // -------------------------
84 // Common models can live longer than their user references. The method
85 // SetMinCommonLifetime allows to set a minimum time for which the
86 // context should hold the model after all other references have gone.
87 // Thereby, models can easily be designed for being caches, resources,
88 // configurations and so on.
89 //
90 // Get or create a model: the Acquire function
91 // -------------------------------------------
92 // Each derived model class which is not just a base class must have a
93 // static method named Acquire. That function returns a reference to an
94 // existing or newly created model. Constructors and destructors of
95 // models are never to be called by users and should always be
96 // protected.
97
98 static emRef<emModel> Acquire(
99 emContext & context, const emString & name, bool common=true
100 );
101 // This is an example for the Acquire function (it does not make
102 // sense here because this is just a base class). The behavior
103 // should always be: If common==true, search for an already
104 // registered model of the same class, context and name, and if
105 // it is found, return a reference to that model. Otherwise
106 // create a new model, register it if common==true, and return a
107 // reference to it.
108 // Arguments:
109 // context - The context of the model
110 // name - The name of the model.
111 // common - true for refinding or creating a common model,
112 // false for creating a private model.
113 // Returns: A reference to the found or created model.
114
115 // The following two macros can be used to implement Acquire functions.
116 // The first macro is for the general case, and the second is for
117 // classes of models which are always common.
118 # define EM_IMPL_ACQUIRE(CLASS, CONTEXT, NAME, COMMON) \
119 CLASS * m; \
120 if (!COMMON) m=new CLASS(CONTEXT,NAME); \
121 else { \
122 m=(CLASS*)CONTEXT.Lookup(typeid(CLASS),NAME); \
123 if (!m) { m=new CLASS(CONTEXT,NAME); m->Register(); } \
124 } \
125 return emRef<CLASS >(m);
126 # define EM_IMPL_ACQUIRE_COMMON(CLASS, CONTEXT, NAME) \
127 CLASS * m; \
128 m=(CLASS*)CONTEXT.Lookup(typeid(CLASS),NAME); \
129 if (!m) { m=new CLASS(CONTEXT,NAME); m->Register(); } \
130 return emRef<CLASS >(m);
131
132 emRootContext & GetRootContext() const;
133 // Get the root context.
134
135 emContext & GetContext() const;
136 // Get the context of this model.
137
138 const emString & GetName() const;
139 // Get the name of this model.
140
141 bool IsCommon() const;
142 // Ask whether this is a common model.
143
144 bool IsRegistered() const;
145 // Just a synonym for IsCommon().
146
147 unsigned GetMinCommonLifetime() const;
148 void SetMinCommonLifetime(unsigned seconds);
149 // Minimum lifetime after the common model is no longer in use.
150 // Zero means this model is deleted immediately when there are
151 // no other references than the context. Everything greater
152 // UINT_MAX/2 (or (int)seconds<0) means infinite (lifetime of
153 // context). The default is zero. For private models, this
154 // parameter has no meaning. Normally, SetMinCommonLifetime
155 // should be called only by model constructors, not by model
156 // users. Or lets say user should not shorten the lifetime.
157
158 void Alloc();
159 void Free();
160 // Increment or decrement the reference counter. Free() deletes
161 // this model if the reference counter gets zero. These methods
162 // are usually only to be called by emRef and emContext.
163
164 void LinkCrossPtr(emCrossPtrPrivate & crossPtr);
165 // This means emCrossPtr<emModel> is possible.
166
167 protected:
168
169 emModel(emContext & context, const emString & name);
170 // Constructor.
171 // Arguments:
172 // context - The context for this model
173 // name - The name for this model.
174
175 virtual ~emModel();
176 // Destructor.
177
178 void Register();
179 void Unregister();
180 // Register or unregister this model in its context.
181 // IMPORTANT:
182 // - These methods must never be called from constructors or
183 // destructors of the model (directly or indirectly), because
184 // the final class is part of the registration identity, and
185 // typeid(this) does not return the final class while
186 // constructing or destructing a base class.
187 // - There must not be more than one registered model of the
188 // same class, context and name.
189 // - Usually, Register() should only be called by the Acquire
190 // functions, and Unregister() should never be called by any
191 // derivatives.
192
193 virtual bool Cycle();
194 // emModel has been derived from emEngine for convenience. This
195 // default implementation does nothing and returns false.
196
197 private: friend class emContext;
198
199 emContext & Context;
200 // The context of this model.
201
202 emString Name;
203 // The name of this model.
204
205 emCrossPtrList CrossPtrList;
206 // List of cross pointers to this model.
207
208 emAvlNode AvlNode;
209 // Node for this model in the AVL tree of common models of the
210 // context.
211
212 int AvlHashCode;
213 // Hash index for this model in the AVL tree of the context.
214 // Or zero if this is not a common model.
215
216 int RefCount;
217 // Number of references to this model (including the context
218 // when this is a common model).
219
220 unsigned MinCommonLifetime;
221 // If this is a common model: Number of seconds the context
222 // should keep this model alive when there are no other
223 // references. (int)MinCommonLifetime<0 means infinite.
224
225 unsigned TimeOfDeath;
226 // If this is a common model which is only referred by the
227 // context: Planed time of death (in units of
228 // Context.SharedTiming->SecsCounter)
229 };
230
GetRootContext()231 inline emRootContext & emModel::GetRootContext() const
232 {
233 return Context.RootContext;
234 }
235
GetContext()236 inline emContext & emModel::GetContext() const
237 {
238 return Context;
239 }
240
GetName()241 inline const emString & emModel::GetName() const
242 {
243 return Name;
244 }
245
IsCommon()246 inline bool emModel::IsCommon() const
247 {
248 return AvlHashCode!=0;
249 }
250
IsRegistered()251 inline bool emModel::IsRegistered() const
252 {
253 return AvlHashCode!=0;
254 }
255
GetMinCommonLifetime()256 inline unsigned emModel::GetMinCommonLifetime() const
257 {
258 return MinCommonLifetime;
259 }
260
Alloc()261 inline void emModel::Alloc()
262 {
263 RefCount++;
264 }
265
LinkCrossPtr(emCrossPtrPrivate & crossPtr)266 inline void emModel::LinkCrossPtr(emCrossPtrPrivate & crossPtr)
267 {
268 CrossPtrList.LinkCrossPtr(crossPtr);
269 }
270
Register()271 inline void emModel::Register()
272 {
273 Context.RegisterModel(this);
274 }
275
Unregister()276 inline void emModel::Unregister()
277 {
278 Context.UnregisterModel(this);
279 }
280
281
282 #endif
283