MIRA
FactoryMacros.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_FACTORYMACROS_H_
48 #define _MIRA_FACTORYMACROS_H_
49 
50 #ifndef Q_MOC_RUN
51 #include <boost/mpl/assert.hpp>
52 #endif
53 
54 #include <platform/Typename.h>
55 
57 // class which will be abused as compile time error message
58 template< class T >
59 class ________________________________PLEASE_USE_THE__MIRA_TEMPLATE_CLASS_REGISTER__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________
60 {
61  virtual int FOR_CLASS();
62  virtual ~________________________________PLEASE_USE_THE__MIRA_TEMPLATE_CLASS_REGISTER__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________() {}
63 };
64 
65 // class which will be abused as compile time error message
66 template< class T >
67 class ________________________________PLEASE_USE_THE__MIRA_CLASS_REGISTER__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________
68 {
69  virtual int FOR_CLASS();
70  virtual ~________________________________PLEASE_USE_THE__MIRA_CLASS_REGISTER__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________() {}
71 };
72 
73 // class which will be abused as compile time error message
74 template< class T >
75 class ________________________________PLEASE_USE_THE__MIRA_NO_PUBLIC_DEFAULT_CONSTRUCTOR__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________
76 {
77  virtual int FOR_CLASS();
78  virtual ~________________________________PLEASE_USE_THE__MIRA_NO_PUBLIC_DEFAULT_CONSTRUCTOR__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________() {}
79 };
80 
82 
83 namespace mira {
84 
86 
92 inline std::string mira_stripNameFromIdentifier( std::string const& identifier )
93 {
94  size_t pos = std::string::npos;
95  if ( identifier[identifier.length()-1] == '>' )
96  pos = identifier.rfind('<');
97  std::string tReturn = ( identifier.rfind("::",pos) != std::string::npos ) ?
98  identifier.substr( identifier.rfind("::",pos) + 2 )
99  : identifier;
100  return tReturn;
101 }
102 
104 
105 // *****************************************************************************
106 // *** ClassFactory MACROS (Protected)
107 // *****************************************************************************
108 
113 #define MIRA_OBJECT_BASE( classIdentifier ) \
114  friend class mira::ClassFactory; \
115  \
116  template<typename pCLASS, typename pBASECLASS> \
117  friend struct mira::FactoryRegisterClassHelper; \
118  \
119  template<typename pCLASS> \
120  friend class mira::TClass; \
121 \
122 public: \
123  \
124  mira::TClass<classIdentifier> const& getClass() const { \
125  /* This should do the trick, since all TClasses should be of the same*/\
126  /* structure and size. However, if you get a serious error here, keep*/\
127  /* it private because i will be really really disenchanted otherwise.*/\
128  return \
129  static_cast<mira::TClass<classIdentifier> const&>( internalGetClass() ); \
130  } \
131  \
132  \
133  static mira::TClass<classIdentifier> const& CLASS() { \
134  return _CLASS(); \
135  } \
136 \
137 protected: \
138  \
139  virtual mira::Class& internalGetClass() const { \
140  return _CLASS(); \
141  } \
142  static mira::TClass<classIdentifier>& _staticClassObject( \
143  std::string const& identifier, \
144  std::string const& name, \
145  bool libLoaded);
146 
148 
149 // *****************************************************************************
150 // *** ClassFactory MACROS (Public)
151 // *****************************************************************************
152 
159 #define MIRA_NAMEDOBJECT( classIdentifier, className ) \
160  MIRA_OBJECT_BASE( MIRA_PPARAM( classIdentifier ) ) \
161  \
162  \
163  static mira::TClass<classIdentifier>& _CLASS() { \
164  return _staticClassObject( mira::typeName<classIdentifier>(), \
165  #className, true ); \
166  } \
167 private: \
168  \
169  static void addMetaInfo( std::map<std::string, std::string>& metaMap ) \
170  { \
171  /* No meta info given -> do nothing */ \
172  }
173 
175 
183 #define MIRA_OBJECT( classIdentifier ) \
184  MIRA_OBJECT_BASE( MIRA_PPARAM( classIdentifier ) ) \
185  \
186  \
187  static mira::TClass<classIdentifier>& _CLASS() { \
188  return _staticClassObject( mira::typeName<classIdentifier>(), \
189  mira::mira_stripNameFromIdentifier( \
190  mira::typeName<classIdentifier>() ), true ); \
191  } \
192 private: \
193  \
194  static void addMetaInfo( std::map<std::string, std::string>& metaMap ) \
195  { \
196  /* No meta info given -> do nothing */ \
197  }
198 
200 
208 #define MIRA_META_OBJECT( classIdentifier, MetaInfo ) \
209  MIRA_OBJECT_BASE( MIRA_PPARAM( classIdentifier ) ) \
210  \
211  \
212  static mira::TClass<classIdentifier>& _CLASS() { \
213  return _staticClassObject( mira::typeName<classIdentifier>(), \
214  mira::mira_stripNameFromIdentifier( \
215  mira::typeName<classIdentifier>() ), true ); \
216  } \
217 private: \
218  \
219  static void addMetaInfo( std::map<std::string, std::string>& metaMap ) \
220  { \
221  /* append given meta information to the map */ \
222  boost::assign::insert( metaMap ) MetaInfo; \
223  }
224 
226 
239 #define MIRA_ABSTRACT_OBJECT( classIdentifier ) \
240  MIRA_META_OBJECT( MIRA_PPARAM( classIdentifier ), ("AbstractClass", mira::typeName<classIdentifier>()) )
241 
246 #define MIRA_ABSTRACT_META_OBJECT( classIdentifier, MetaInfo ) \
247  MIRA_META_OBJECT( MIRA_PPARAM( classIdentifier ), ("AbstractClass", mira::typeName<classIdentifier>())MetaInfo )
248 
250 
257 #define MIRA_CLASS_REGISTER( Class, ... ) \
258  /* generate error message if macro is not used in global namespace */ \
259  template <> int \
260  ________________________________PLEASE_USE_THE__MIRA_CLASS_REGISTER__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________ \
261  <Class>::FOR_CLASS() { return 0; } \
262  MIRA_REGISTRAR( MIRA_PPARAM( mira::FactoryRegisterClass<Class, __VA_ARGS__> ) ) \
263  mira::TClass<Class>& Class::_staticClassObject(std::string const& identifier, \
264  std::string const& name, \
265  bool libLoaded) { \
266  static mira::TClass<Class> sClass(identifier, name, libLoaded); \
267  return sClass; \
268  }
269 
274 #define MIRA_NO_PUBLIC_DEFAULT_CONSTRUCTOR(CLASS) \
275  namespace mira { \
276  template<> \
277  class HasPublicDefaultConstructor<CLASS> : public std::false_type {}; \
278  }
279 
280 inline std::string replaceTemplateGeneric( std::string const& genericIdent,
281  std::string const& specialIdent )
282 {
283  size_t tFirstOccGeneric = genericIdent.find('<');
284  size_t tLastOccGeneric = genericIdent.rfind('>');
285  size_t tFirstOccSpecial = specialIdent.find('<');
286  size_t tLastOccSpecial = specialIdent.rfind('>');
287 
288  assert( tFirstOccGeneric != std::string::npos &&
289  tLastOccGeneric != std::string::npos );
290 
291  assert( tFirstOccSpecial != std::string::npos &&
292  tLastOccSpecial != std::string::npos );
293 
294  std::string tReturnValue = genericIdent;
295 
296  return tReturnValue.replace( tFirstOccGeneric, tLastOccGeneric-tFirstOccGeneric,
297  specialIdent.substr( tFirstOccSpecial,
298  tLastOccSpecial - tFirstOccSpecial ) );
299 }
300 
302 
303 #define MIRA_INTERNAL_OPEN_NAMESPACE(r,data,t) \
304  namespace t {
305 
306 #define MIRA_INTERNAL_CLOSE_NAMESPACE(r,data,t) }
307 
310 #define MIRA_VA_NUM_ARGS(...) MIRA_VA_NUM_ARGS_IMPL(__VA_ARGS__,5,4,3,2,1)
311 #define MIRA_VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
312 
313 
314 // see: http://www.mail-archive.com/boost@lists.boost.org/msg03318.html
315 #define MIRA_MAKE_SEQ(size, rel) MIRA_MAKE_SEQ_D(size, rel)
316 #define MIRA_MAKE_SEQ_D(size, rel) \
317  BOOST_PP_CAT( \
318  MIRA_MAKE_SEQ_A_ ## size rel, \
319  0X0 \
320  )() \
321 
322 
323 // size 1
324 #define MIRA_MAKE_SEQ_A_1(a) ((a)) MIRA_MAKE_SEQ_B_1
325 #define MIRA_MAKE_SEQ_B_1(a) ((a)) MIRA_MAKE_SEQ_A_1
326 
327 #define MIRA_MAKE_SEQ_A_10X0()
328 #define MIRA_MAKE_SEQ_B_10X0()
329 
330 // size 2
331 #define MIRA_MAKE_SEQ_A_2(a, b) ((a, b)) MIRA_MAKE_SEQ_B_2
332 #define MIRA_MAKE_SEQ_B_2(a, b) ((a, b)) MIRA_MAKE_SEQ_A_2
333 
334 #define MIRA_MAKE_SEQ_A_20X0()
335 #define MIRA_MAKE_SEQ_B_20X0()
336 
337 // size 3
338 #define MIRA_MAKE_SEQ_A_3(a, b, c) ((a, b, c)) MIRA_MAKE_SEQ_B_3
339 #define MIRA_MAKE_SEQ_B_3(a, b, c) ((a, b, c)) MIRA_MAKE_SEQ_A_3
340 
341 #define MIRA_MAKE_SEQ_A_30X0()
342 #define MIRA_MAKE_SEQ_B_30X0()
343 
344 // size 4
345 #define MIRA_MAKE_SEQ_A_4(a, b, c, d) ((a, b, c, d)) MIRA_MAKE_SEQ_B_4
346 #define MIRA_MAKE_SEQ_B_4(a, b, c, d) ((a, b, c, d)) MIRA_MAKE_SEQ_A_4
347 
348 #define MIRA_INTERNAL_PRINT_TOKEN(TOKEN) #TOKEN
349 
350 #define MIRA_DO_NOTHING(Sequence,StartId)
351 
352 #define MIRA_INTERNAL_NAMESPACE_FOLD(r,data,t) \
353  t::data
354 
355 #define MIRA_INTERNAL_CONC_NAMESPACE_IMPL(Sequence, StartId) \
356  BOOST_PP_SEQ_FOLD_RIGHT(MIRA_INTERNAL_NAMESPACE_FOLD,,BOOST_PP_SEQ_REST_N(StartId,Sequence))
357 
358 #define MIRA_INTERNAL_CONC_NAMESPACE(Sequence,StartId) \
359  /* check if namespace size is greater zero and delay evaluation */ \
360  BOOST_PP_IF( BOOST_PP_SEQ_SIZE( BOOST_PP_SEQ_REST_N( StartId, Sequence) ), \
361  /* length of namespace is greater zero */ \
362  MIRA_INTERNAL_CONC_NAMESPACE_IMPL \
363  /* we do not have a namespace -> do nothing */ \
364  , MIRA_DO_NOTHING )(Sequence, StartId)
365 
366 #define MIRA_INTERNAL_TEMPLATE_CLASS_REGISTER( r, Args, TmplSpec) \
367  /* Args(0) - contains the Class itself */ \
368  /* Args(1) - number of parents k */ \
369  /* Args(2) - number of template parameters */ \
370  /* Args(3) - address n of first namespace token in sequence Args */ \
371  /* Args(4 -- 4+k) - parents */ \
372  /* Args(n -- end) - namespace */ \
373  MIRA_REGISTRAR( MIRA_PPARAM( mira::FactoryRegisterClass< \
374  /* the folding process adds the namespace, if the namesapce sequence*/ \
375  /* length is greater than zero (with delayed evaluation) */ \
376  BOOST_PP_IF( BOOST_PP_SEQ_SIZE( BOOST_PP_SEQ_REST_N( \
377  BOOST_PP_SEQ_ELEM(3,Args),Args) ), \
378  /* length of namespace is greater zero */ \
379  MIRA_INTERNAL_CONC_NAMESPACE_IMPL \
380  /* we do not have a namespace -> do nothing */ \
381  , MIRA_DO_NOTHING )( Args, BOOST_PP_SEQ_ELEM(3,Args) ) \
382  BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR( BOOST_PP_SEQ_ELEM(2,Args), TmplSpec)>, \
383  BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_SUBSEQ(Args,4,BOOST_PP_SEQ_ELEM(1,Args)))> ) ) \
384 
385 
386 #define MIRA_INTERNAL_TEMPLATE_CLASS_STATIC( r, Args, TmplSpec) \
387  /* Args(0) contains the Class itself */ \
388  /* Args(1) contains the number of template parameters */ \
389  template<> mira::TClass<\
390  BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec)> >& \
391  BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec)>::_staticClassObject( \
392  std::string const& identifier, \
393  std::string const& name, \
394  bool libLoaded) { \
395  static mira::TemplateClass<BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec)> > \
396  sClass(identifier, name, libLoaded); \
397  return sClass; \
398  } \
399 
400 
401 #define MIRA_TMPL_SPEC_CONCAT(r, data, i, elem) "," BOOST_PP_STRINGIZE(elem)
402 
403 #define TAIL_NAME( Seq ) \
404  BOOST_PP_SEQ_FOR_EACH_I( MIRA_TMPL_SPEC_CONCAT, , Seq)
405 
406 #define MIRA_INTERNAL_TEMPLATE_IDENTIFIER( r, Args, TmplSpec) \
407  /* Args(0) contains the Class itself */ \
408  /* Args(1) contains the number of template parameters */ \
409  /* Args(2-n) contains the namespace */ \
410  template<> \
411  /* the folding process adds the namespace */ \
412  std::string const& TemplateClass<MIRA_INTERNAL_CONC_NAMESPACE(Args,2) \
413  BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec)> >::getIdentifier() const { \
414  /* we should use a combination of the generic and the specialized */ \
415  /* here since the generic string should include the namespace.*/ \
416  static std::string tIdent = replaceTemplateGeneric( \
417  TClass<MIRA_INTERNAL_CONC_NAMESPACE(Args,2) \
418  BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec)> >::getIdentifier(), \
419  "<" \
420  BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_SEQ_ELEM(1,Args),TmplSpec))) \
421  /* use for_each_i here since recursion of fore_each is not allowed */ \
422  BOOST_PP_SEQ_FOR_EACH_I( MIRA_TMPL_SPEC_CONCAT, , BOOST_PP_SEQ_TAIL(BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec))) \
423  ">" ); \
424  return tIdent; \
425  } \
426  \
427  template<> \
428  /* the folding process adds the namespace */ \
429  std::string const& TemplateClass<MIRA_INTERNAL_CONC_NAMESPACE(Args,2) \
430  BOOST_PP_SEQ_ELEM(0,Args)<BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_SEQ_ELEM(1,Args), TmplSpec)> >::getName() const { \
431  static std::string tName = mira_stripNameFromIdentifier( \
432  getIdentifier() ); \
433  return tName; \
434  } \
435 
436 
450 #define MIRA_TEMPLATE_CLASS_REGISTER( Namespace, Class, TmplSpec, ... ) \
451  MIRA_TEMPLATE_CLASS_REGISTER_IMPL( Namespace, Class, 1, MIRA_MAKE_SEQ(1,TmplSpec), __VA_ARGS__ )
452 
465 #define MIRA_VARTEMPLATE_CLASS_REGISTER( Namespace, Class, NumTmplPrm, TmplSpec, ... ) \
466  MIRA_TEMPLATE_CLASS_REGISTER_IMPL( Namespace, Class, NumTmplPrm, MIRA_MAKE_SEQ(NumTmplPrm,TmplSpec), __VA_ARGS__ )
467 
469 
470 #define MIRA_TMPL_SIG_FROM_SEQ( NumTmplPrm, SeqId, Sequence )\
471  BOOST_PP_TUPLE_REM_CTOR( NumTmplPrm, BOOST_PP_SEQ_ELEM(SeqId,Sequence) )
472 
473 #define MIRA_TEMPLATE_CLASS_REGISTER_IMPL( Namespace, Class, NumTmplPrm, TmplSpec, ... ) \
474  /* generate error message if macro is not used in global namespace */ \
475  template <> int \
476  ________________________________PLEASE_USE_THE__MIRA_TEMPLATE_CLASS_REGISTER__MACRO_IN_GLOBAL_NAMESPACE_ONLY________________________________\
477  <MIRA_INTERNAL_CONC_NAMESPACE(Namespace,0)Class \
478  <MIRA_TMPL_SIG_FROM_SEQ(NumTmplPrm,0,TmplSpec)> >::FOR_CLASS() { return 0; } \
479  /* the following lines build up a sequence for the internal register macro*/\
480  /* structure: (Class)(Number of Parents)(Address of first namespace token */\
481  /* in the sequence)(Parents as sequence)(Namespace as sequence) */ \
482  BOOST_PP_SEQ_FOR_EACH(MIRA_INTERNAL_TEMPLATE_CLASS_REGISTER, \
483  (Class) \
484  (MIRA_VA_NUM_ARGS(__VA_ARGS__))(NumTmplPrm)(BOOST_PP_ADD(MIRA_VA_NUM_ARGS(__VA_ARGS__),4))\
485  BOOST_PP_TUPLE_TO_SEQ(MIRA_VA_NUM_ARGS(__VA_ARGS__),(__VA_ARGS__)) \
486  Namespace,TmplSpec) \
487  \
488  /* we can only specialize the the template in the corresponding namespace */\
489  /* check if length of namespace is greater than zero */ \
490  BOOST_PP_IF( BOOST_PP_SEQ_SIZE( Namespace ), \
491  /* length of namespace is greater zero */ \
492  BOOST_PP_SEQ_FOR_EACH(MIRA_INTERNAL_OPEN_NAMESPACE,~,Namespace) \
493  /* length of namespace is zero -> do nothing */ \
494  , ) \
495  /* we have to combine all parameters in a boost pp sequence in order */ \
496  /* to pass them to the internal macro */ \
497  /* Register the class at the factory */ \
498  BOOST_PP_SEQ_FOR_EACH(MIRA_INTERNAL_TEMPLATE_CLASS_STATIC, \
499  (Class)(NumTmplPrm), TmplSpec) \
500  /* check if length of namespace is greater than zero */ \
501  BOOST_PP_IF( BOOST_PP_SEQ_SIZE( Namespace ), \
502  /* length of namespace is greater zero */ \
503  BOOST_PP_SEQ_FOR_EACH(MIRA_INTERNAL_CLOSE_NAMESPACE,~,Namespace) \
504  /* length of namespace is zero -> do nothing */ \
505  , ) \
506  \
507  namespace mira { \
508  /* Specialize the functions to obtain the template identifiers */ \
509  BOOST_PP_SEQ_FOR_EACH(MIRA_INTERNAL_TEMPLATE_IDENTIFIER, \
510  (Class)(NumTmplPrm)Namespace,TmplSpec) \
511  }
512 
514 
516 
517 } // namespace
518 
519 #endif /* _MIRA_FACTORYMACROS_H_ */
520 
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
Get compiler and platform independent typenames.
std::string mira_stripNameFromIdentifier(std::string const &identifier)
Auxiliary function to extract the class name from the given identifier.
Definition: FactoryMacros.h:92
std::string replaceTemplateGeneric(std::string const &genericIdent, std::string const &specialIdent)
Definition: FactoryMacros.h:280