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