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 &param)
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 &params, 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 &params, 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 &params, 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 &params, 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 &params, 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 &params, 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 &params, 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       &params,
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 &params, 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