1 /*
2 * Medical Image Registration ToolKit (MIRTK)
3 *
4 * Copyright 2013-2016 Imperial College London
5 * Copyright 2013-2016 Andreas Schuh
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifndef MIRTK_Object_H
21 #define MIRTK_Object_H
22
23 #include "mirtk/Array.h"
24 #include "mirtk/Exception.h"
25 #include "mirtk/Pair.h"
26 #include "mirtk/String.h"
27 #include "mirtk/Stream.h"
28
29
30 namespace mirtk {
31
32
33 // =============================================================================
34 // Basic object interface
35 // =============================================================================
36
37 /// Ordered list of parameter name/value pairs
38 typedef Array<Pair<string, string> > ParameterList;
39 typedef ParameterList::iterator ParameterIterator;
40 typedef ParameterList::const_iterator ParameterConstIterator;
41
42
43 /**
44 * Base class for all MIRTK object classes
45 *
46 * \note This base class must be a virtual interface without any own data
47 * members to not change the type size of subclasses! Derive another
48 * intermediate abstract base class from it to add data members shared
49 * by a more specific class of objects.
50 */
51 class Object
52 {
53 public:
54
55 /// Get name of this class type
56 static const char *NameOfType();
57
58 /// Get name of class, which this object is an instance of
59 virtual const char *NameOfClass() const = 0;
60
61 /// Destructor
62 virtual ~Object();
63
64 /// Set parameter value from string
65 ///
66 /// \param[in] name Parameter name.
67 /// \param[in] value Parameter value.
68 ///
69 /// \returns Whether the named parameter is valid and a valid value was
70 /// set from the provided string representation of the value.
71 virtual bool Set(const char *name, const char *value);
72
73 /// Get parameter name/value pairs
74 virtual ParameterList Parameter() const;
75
76 /// Set parameters from name/value pairs
77 bool Parameter(const ParameterList &);
78
79 // ---------------------------------------------------------------------------
80 // Error handling
81 protected:
82
83 /// Raise error in member function
84 ///
85 /// The current implementation prints the error message to STDERR and terminates
86 /// the program with exit code 1. In future releases, when all library code has
87 /// been rewritten to use this function, a suitable runtime exception may be
88 /// thrown instead.
89 ///
90 /// \param[in] err Error type. Unused at the moment, but may be used in
91 /// future releases to throw the appropriate exception type.
92 /// \param[in] cls Name of class that defines the member function.
93 /// \param[in] func Name of member function which is throwing the error (i.e., __func__).
94 /// \param[in] args Error message. The given arguments are converted to strings
95 /// using the ToString template function. These strings are then
96 /// concatenated to produce the complete error message.
97 template <typename... Args>
98 static void ThrowStatic(ErrorType err, const char *cls, const char *func, Args... args);
99
100 /// Raise error in member function
101 ///
102 /// The current implementation prints the error message to STDERR and terminates
103 /// the program with exit code 1. In future releases, when all library code has
104 /// been rewritten to use this function, a suitable runtime exception may be
105 /// thrown instead.
106 ///
107 /// \param[in] err Error type. Unused at the moment, but may be used in
108 /// future releases to throw the appropriate exception type.
109 /// \param[in] func Name of member function which is throwing the error (i.e., __func__).
110 /// \param[in] args Error message. The given arguments are converted to strings
111 /// using the ToString template function. These strings are then
112 /// concatenated to produce the complete error message.
113 template <typename... Args>
114 void Throw(ErrorType err, const char *func, Args... args) const;
115 };
116
117 // =============================================================================
118 // Inline definitions
119 // =============================================================================
120
121 // -----------------------------------------------------------------------------
~Object()122 inline Object::~Object()
123 {
124 }
125
126 // -----------------------------------------------------------------------------
NameOfType()127 inline const char *Object::NameOfType()
128 {
129 return "mirtk::Object";
130 }
131
132 // -----------------------------------------------------------------------------
Set(const char *,const char *)133 inline bool Object::Set(const char *, const char *)
134 {
135 return false;
136 }
137
138 // -----------------------------------------------------------------------------
Parameter()139 inline ParameterList Object::Parameter() const
140 {
141 return ParameterList();
142 }
143
144 // -----------------------------------------------------------------------------
Parameter(const ParameterList & param)145 inline bool Object::Parameter(const ParameterList ¶m)
146 {
147 bool ok = true;
148 for (ParameterConstIterator it = param.begin(); it != param.end(); ++it) {
149 ok = this->Set(it->first.c_str(), it->second.c_str()) && ok;
150 }
151 return ok;
152 }
153
154 // -----------------------------------------------------------------------------
155 template <typename... Args>
ThrowStatic(ErrorType err,const char * cls,const char * func,Args...args)156 void Object::ThrowStatic(ErrorType err, const char *cls, const char *func, Args... args)
157 {
158 string member(cls);
159 member += "::";
160 member += func;
161 mirtk::Throw(err, member.c_str(), args...);
162 }
163
164 // -----------------------------------------------------------------------------
165 template <typename... Args>
Throw(ErrorType err,const char * func,Args...args)166 void Object::Throw(ErrorType err, const char *func, Args... args) const
167 {
168 ThrowStatic(err, this->NameOfClass(), func, args...);
169 }
170
171 // =============================================================================
172 // Auxiliary functions for subclass implementation
173 // =============================================================================
174
175 // -----------------------------------------------------------------------------
176 /// Find parameter in parameters list
Find(const ParameterList & params,string name)177 inline ParameterConstIterator Find(const ParameterList ¶ms, string name)
178 {
179 ParameterConstIterator it = params.begin();
180 while (it != params.end() && it->first != name) ++it;
181 return it;
182 }
183
184 // -----------------------------------------------------------------------------
185 /// Find parameter in parameters list
Find(ParameterList & params,string name)186 inline ParameterIterator Find(ParameterList ¶ms, string name)
187 {
188 ParameterIterator it = params.begin();
189 while (it != params.end() && it->first != name) ++it;
190 return it;
191 }
192
193 // -----------------------------------------------------------------------------
194 /// Whether parameter is in parameters list
Contains(const ParameterList & params,string name)195 inline bool Contains(const ParameterList ¶ms, string name)
196 {
197 return Find(params, name) != params.end();
198 }
199
200 // -----------------------------------------------------------------------------
201 /// Get parameter value from parameters list
Get(const ParameterList & params,string name)202 inline string Get(const ParameterList ¶ms, string name)
203 {
204 ParameterConstIterator pos = Find(params, name);
205 if (pos == params.end()) return string("");
206 return pos->second;
207 }
208
209 // -----------------------------------------------------------------------------
210 /// Insert/replace value into/in parameters list
211 template <class T>
Insert(ParameterList & params,string name,T value)212 inline ParameterList &Insert(ParameterList ¶ms, string name, T value)
213 {
214 ParameterIterator pos = Find(params, name);
215 if (pos == params.end()) {
216 params.push_back(make_pair(name, ToString(value)));
217 } else {
218 pos->second = ToString(value);
219 }
220 return params;
221 }
222
223 // -----------------------------------------------------------------------------
224 /// Insert/replace string value into/in parameters list
225 template <>
Insert(ParameterList & params,string name,const char * value)226 inline ParameterList &Insert(ParameterList ¶ms, string name, const char *value)
227 {
228 ParameterIterator pos = Find(params, name);
229 if (pos == params.end()) {
230 params.push_back(make_pair(name, string(value)));
231 } else {
232 pos->second = value;
233 }
234 return params;
235 }
236
237 // -----------------------------------------------------------------------------
238 /// Insert/replace string value into/in parameters list
239 template <>
Insert(ParameterList & params,string name,string value)240 inline ParameterList &Insert(ParameterList ¶ms, string name, string value)
241 {
242 ParameterIterator pos = Find(params, name);
243 if (pos == params.end()) {
244 params.push_back(make_pair(name, value));
245 } else {
246 pos->second = value;
247 }
248 return params;
249 }
250
251 // -----------------------------------------------------------------------------
252 /// Insert/replace values into/in parameters list
253 inline ParameterList &Insert(ParameterList ¶ms,
254 const ParameterList &other,
255 const char *prefix = NULL)
256 {
257 if (prefix) {
258 string name;
259 for (ParameterConstIterator it = other.begin(); it != other.end(); ++it) {
260 name = it->first;
261 name[0] = ::tolower(name[0]);
262 Insert(params, string(prefix) + " " + name, it->second);
263 }
264 } else {
265 for (ParameterConstIterator it = other.begin(); it != other.end(); ++it) {
266 Insert(params, it->first, it->second);
267 }
268 }
269 return params;
270 }
271
272 // -----------------------------------------------------------------------------
273 /// Remove parameter from parameters list
Remove(ParameterList & params,string name)274 inline ParameterList &Remove(ParameterList ¶ms, string name)
275 {
276 ParameterIterator pos = Find(params, name);
277 if (pos != params.end()) params.erase(pos);
278 return params;
279 }
280
281 // =============================================================================
282 // Auxiliary macros for subclass implementation
283 // =============================================================================
284
285 // -----------------------------------------------------------------------------
286 /// Declare abstract base class derived from Object
287 #define mirtkAbstractMacro(name) \
288 public: \
289 /** Get name of this class type */ \
290 inline static const char *NameOfType() { return #name; } \
291 /** Get name of class, which this object is an instance of */ \
292 virtual const char *NameOfClass() const = 0; \
293 private:
294
295 // -----------------------------------------------------------------------------
296 /// Declare class derived from Object
297 #define mirtkObjectMacro(name) \
298 public: \
299 /** Get name of this class type */ \
300 inline static const char *NameOfType() { return #name; } \
301 /** Get name of class, which this object is an instance of */ \
302 inline virtual const char *NameOfClass() const { return #name; } \
303 private:
304
305 // -----------------------------------------------------------------------------
306 /// Declare class of mutable objects, i.e., ones which define their own
307 /// NameOfClass implementation that returns a different type identifier
308 /// depending on the state of the object.
309 #define mirtkMutableObjectMacro(name) \
310 public: \
311 /** Get name of this class type */ \
312 inline static const char *NameOfType() { return #name; } \
313 /** Get name of class, which this object is an instance of */ \
314 virtual const char *NameOfClass() const; \
315 private:
316
317 // -----------------------------------------------------------------------------
318 /// Define setter for class member variable
319 /// \sa mirtkPublicAttributeMacro
320 #define mirtkSetMacro(name, type) \
321 virtual void Set##name(type arg) { this->_##name = arg; }
322
323 // -----------------------------------------------------------------------------
324 /// Define getter for class member variable
325 /// \sa mirtkPublicAttributeMacro, mirtkReadOnlyAttributeMacro
326 #define mirtkGetMacro(name, type) \
327 type Get##name() const { return this->_##name; }
328
329 // -----------------------------------------------------------------------------
330 /// Define VTK-like On/Off setter for boolean class member variable
331 /// \sa mirtkPublicAttributeMacro
332 #define mirtkOnOffMacro(name) \
333 virtual void name##On() { this->_##name = true; } \
334 virtual void name##Off() { this->_##name = false; }
335
336 // -----------------------------------------------------------------------------
337 /// Define read-only class attribute and corresponding accessors
338 #define mirtkDefineReadOnlyAttributeMacro(typedecl, type, name) \
339 protected: \
340 typedecl _##name; \
341 public: \
342 /** Get value of _##name attribute */ \
343 inline type &name() { return _##name; } \
344 /** Get value of _##name attribute */ \
345 inline const type &name() const { return _##name; } \
346 private:
347
348 // -----------------------------------------------------------------------------
349 /// Define class attribute and corresponding accessors
350 #define mirtkDefineAttributeMacro(access, typedecl, type, name) \
351 protected: \
352 typedecl _##name; \
353 access: \
354 /** Set value of _##name attribute */ \
355 inline virtual void name(type arg) { _##name = arg; } \
356 /** Get value of _##name attribute */ \
357 inline type &name() { return _##name; } \
358 /** Get value of _##name attribute */ \
359 inline const type &name() const { return _##name; } \
360 private:
361
362 // -----------------------------------------------------------------------------
363 /// Define public attribute
364 #define mirtkPublicAttributeMacro(type, name) \
365 mirtkDefineAttributeMacro(public, type, type, name)
366 /// Define public read-only attribute
367 #define mirtkReadOnlyAttributeMacro(type, name) \
368 mirtkDefineReadOnlyAttributeMacro(type, type, name)
369 /// Define public mutable attribute
370 #define mirtkPublicMutableAttributeMacro(type, name) \
371 mirtkDefineAttributeMacro(public, mutable type, type, name)
372
373 // -----------------------------------------------------------------------------
374 /// Define protected attribute
375 #define mirtkAttributeMacro(type, name) \
376 mirtkDefineAttributeMacro(protected, type, type, name)
377 /// Define protected mutable attribute
378 #define mirtkMutableAttributeMacro(type, name) \
379 mirtkDefineAttributeMacro(protected, mutable type, type, name)
380
381 // -----------------------------------------------------------------------------
382 /// Define pointer to aggregate (cf. UML aggregation) and corresponding accessors
383 #define mirtkDefineAggregateMacro(access, type, name) \
384 protected: \
385 type *_##name; \
386 access: \
387 /** Set value of _##name attribute */ \
388 inline virtual void name(type *arg) { _##name = arg; } \
389 /** Get value of _##name attribute */ \
390 inline type *name() const { return _##name; } \
391 private:
392
393 // -----------------------------------------------------------------------------
394 /// Define pointer to aggregate (cf. UML aggregation) and corresponding accessors
395 #define mirtkDefineReadOnlyAggregateMacro(access, type, name) \
396 protected: \
397 type *_##name; \
398 access: \
399 /** Get value of _##name attribute */ \
400 inline type *name() const { return _##name; } \
401 private:
402
403 // -----------------------------------------------------------------------------
404 /// Define public pointer to aggregate (cf. UML aggregation)
405 #define mirtkPublicAggregateMacro(type, name) \
406 mirtkDefineAggregateMacro(public, type, name)
407 /// Define public read-only pointer to aggregate (cf. UML aggregation)
408 #define mirtkReadOnlyAggregateMacro(type, name) \
409 mirtkDefineReadOnlyAggregateMacro(public, type, name)
410
411 // -----------------------------------------------------------------------------
412 /// Define protected pointer to aggregate (cf. UML aggregation)
413 #define mirtkAggregateMacro(type, name) \
414 mirtkDefineAggregateMacro(protected, type, name)
415
416 // -----------------------------------------------------------------------------
417 /// Define pointer to component (cf. UML composition) and corresponding accessors
418 #define mirtkDefineComponentMacro(access, type, name) \
419 protected: \
420 type *_##name; \
421 access: \
422 /** Set pointer to _##name attribute */ \
423 inline virtual void name(type *arg) { delete _##name; _##name = arg; } \
424 /** Get pointer to _##name attribute */ \
425 inline type *name() { return _##name; } \
426 /** Get const pointer to _##name attribute */ \
427 inline const type *name() const { return _##name; } \
428 private:
429
430 // -----------------------------------------------------------------------------
431 /// Define public pointer to component (cf. UML composition)
432 #define mirtkPublicComponentMacro(type, name) \
433 mirtkDefineComponentMacro(public, type, name)
434 /// Define public read-only pointer to component (cf. UML composition)
435 #define mirtkReadOnlyComponentMacro(type, name) \
436 mirtkDefineReadOnlyAggregateMacro(public, type, name)
437
438 // -----------------------------------------------------------------------------
439 /// Define protected pointer to component (cf. UML composition)
440 #define mirtkComponentMacro(type, name) \
441 mirtkDefineComponentMacro(protected, type, name)
442
443 // -----------------------------------------------------------------------------
444 /// Define pointer to component (cf. UML composition) which can also be set to
445 /// an externally managed instance instead using the corresponding accessors
446 ///
447 /// A loose component is a pointer that must never by a nullptr. It must be
448 /// initialized during construction of an instance of the class which this
449 /// component attribute belongs.
450 ///
451 /// Unlike a regular component, a loose component can alternatively be set to an
452 /// externally instantiated object of the component type. In this case, the class
453 /// revokes ownership of the object which must be deleted by the client code.
454 /// When a nullptr is given as argument to the setter of the loose component,
455 /// the current pointer is replaced by a new copy that is owned by this class.
456 /// It can thus be used to release the external object again before destruction
457 /// in cases where the class that the loose component belongs to remains in use.
458 #define mirtkLooseComponentMacro(type, name) \
459 protected: \
460 type *_##name; \
461 bool _##name##Owner; \
462 public: \
463 /** Set pointer to _##name attribute */ \
464 inline virtual void name(type *arg) { \
465 if (_##name##Owner) delete _##name; \
466 if (arg) { \
467 _##name = arg; \
468 _##name##Owner = false; \
469 } else { \
470 _##name = new type(*_##name); \
471 _##name##Owner = true; \
472 } \
473 } \
474 /** Get pointer to _##name attribute */ \
475 inline type *name() { return _##name; } \
476 /** Get const pointer to _##name attribute */ \
477 inline const type *name() const { return _##name; } \
478 private:
479
480
481 } // namespace mirtk
482
483 #endif // MIRTK_Object_H
484