IMP  2.0.1
The Integrative Modeling Platform
kernel/decorator_macros.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kernel/decorator_macros.h
3  * \brief Various general useful macros for IMP.
4  *
5  * Copyright 2007-2013 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_DECORATOR_MACROS_H
10 #define IMPKERNEL_DECORATOR_MACROS_H
11 #include <IMP/kernel/kernel_config.h>
12 #include <IMP/base/check_macros.h>
13 #include <IMP/base/log_macros.h>
16 
17 /** \name Macros to aid with implementing decorators
18 
19  These macros are here to aid in implementation of IMP::Decorator
20  objects. The first two declare/define the expected methods. The
21  remainder help implement basic functions.
22 
23  @{
24 */
25 
26 //! Define the basic things needed by a Decorator.
27 /** The macro defines the following methods
28  - a default constructor Decorator::Decorator()
29 
30  It also declares:
31  - IMP::Decorator::show()
32  - IMP::Decorator::decorate_particle()
33  - IMP::Decorator::Decorator()
34 
35  Finally, it expects methods corresponding to
36  - IMP::Decorator::particle_is_instance()
37  - IMP::Decorator::setup_particle()
38 
39  You also implement static methods \c get_x_key() to return each of the
40  keys used. These static methods, which must be defined in the \c .cpp
41  file, should declare the key itself as a \c static member variable to
42  avoid initializing the key if the decorator is not used.
43 
44  See IMP::Decorator for a more detailed description
45  of decorators.
46 
47  \param[in] Name is the name of the decorator, such as XYZR
48  \param[in] Parent The class name for the parent of this class,
49  typically Decorator
50 
51  \see IMP_DECORATOR_WITH_TRAITS()
52 */
53 #define IMP_DECORATOR(Name, Parent) \
54  public: \
55  /* Should be private but SWIG accesses it through the comparison
56  macros*/ \
57 IMP_NO_DOXYGEN(typedef Parent ParentDecorator); \
58 Name(): Parent(){} \
59 Name(Model *m, ParticleIndex id): Parent(m, id) { \
60  IMP_INTERNAL_CHECK(particle_is_instance(m->get_particle(id)), \
61  "Particle " << m->get_particle(id)->get_name() \
62  << " missing required attributes for decorator " \
63  << #Name << "\n" \
64  << base::ShowFull(m->get_particle(id))); \
65 } \
66 explicit Name(::IMP::kernel::Particle *p): Parent(p) { \
67  IMP_INTERNAL_CHECK(particle_is_instance(p), \
68  "Particle " << p->get_name() \
69  << " missing required attributes for decorator " \
70  << #Name << "\n" << base::ShowFull(p)); \
71 } \
72 static Name decorate_particle(::IMP::kernel::Particle *p) { \
73  IMP_CHECK_OBJECT(p); \
74  if (!particle_is_instance(p)) { \
75  return Name(); \
76  } \
77  return Name(p); \
78 } \
79 IMP_SHOWABLE(Name)
80 
81 
82 //! Define the basic things needed by a Decorator which has a traits object.
83 /** This macro is the same as IMP_DECORATOR() except that an extra object
84  of type TraitsType is passed after the particle to
85  - IMP::Decorator::particle_is_instance()
86  - IMP::Decorator::setup_particle()
87  As in the IMP::core::XYZR or IMP::core::Hierarchy,
88  this object can be used to parameterize the Decorator. The traits
89  object is stored in the decorator and made accessible through
90  the get_traits() method.
91 */
92 #define IMP_DECORATOR_WITH_TRAITS(Name, Parent, TraitsType, traits_name, \
93  default_traits) \
94  private: \
95  TraitsType traits_; \
96 public: \
97  IMP_NO_DOXYGEN(typedef Parent ParentDecorator); \
98  Name(){} \
99  Name(Model *m, ParticleIndex id, const TraitsType &tr): Parent(m, id), \
100  traits_(tr) { \
101  IMP_INTERNAL_CHECK(particle_is_instance(m->get_particle(id), tr), \
102  "Particle " << m->get_particle(id)->get_name() \
103  << " missing required attributes for decorator " \
104  << #Name << "\n" << Showable(m->get_particle(id))); \
105 } \
106  Name(const TraitsType &tr): \
107  traits_(tr) {} \
108  explicit Name(::IMP::kernel::Particle *p, \
109  const TraitsType &tr=default_traits): \
110  Parent(p), traits_(tr) { \
111  IMP_INTERNAL_CHECK(particle_is_instance(p, tr), \
112  "Particle " << p->get_name() \
113  << " missing required attributes " \
114  << " for decorator " \
115  << #Name << "\n" << Showable(p)); \
116  } \
117  static Name decorate_particle(::IMP::kernel::Particle *p, \
118  const TraitsType &tr=default_traits) { \
119  if (!particle_is_instance(p, tr)) return Name(); \
120  else return Name(p, tr); \
121  } \
122  IMP_SHOWABLE(Name); \
123  const TraitsType &get_##traits_name() const { \
124  return get_decorator_traits(); \
125  } \
126  typedef Parent DecoratorTraitsBase; \
127  typedef TraitsType DecoratorTraits; \
128  const DecoratorTraits& get_decorator_traits() const {return traits_;} \
129  static const DecoratorTraits& get_default_decorator_traits() { \
130  static TraitsType dt= default_traits; \
131  return dt; \
132  } \
133  IMP_NO_DOXYGEN(typedef boost::true_type DecoratorHasTraits)
134 
135 
136 //! Perform actions dependent on whether a particle has an attribute.
137 /** A common pattern is to check if a particle has a particular attribute,
138  do one thing if it does and another if it does not. This macro implements
139  that pattern. It requires that the method get_particle() return the
140  particle being used.
141 
142  \param[in] AttributeKey The key for the attribute
143  \param[in] Type The type for the attribute ("Int", "Float", "String")
144  \param[in] has_action The action to take if the Particle has the attribute.
145  The attribute value is stored in the variable VALUE.
146  \param[in] not_has_action The action to take if the Particle does not have
147  the attribute.
148  \see IMP_DECORATOR_GET()
149  \see IMP_DECORATOR_GET_SET()
150 
151 */
152 #define IMP_DECORATOR_GET(AttributeKey, Type, has_action, not_has_action) \
153  do { \
154  if (get_model()->get_has_attribute(AttributeKey, get_particle_index())) { \
155  Type VALUE = get_model()->get_attribute(AttributeKey, \
156  get_particle_index()); \
157  has_action; \
158  } else { \
159  not_has_action; \
160  } \
161  } while (false)
162 
163 
164 
165 //! Set an attribute, creating it if it does not already exist.
166 /** Another common pattern is to have an assumed value if the attribute
167  is not there. Then, you sometimes need to set the value whether it
168  is there or not.
169  \see IMP_DECORATOR_GET()
170  \see IMP_DECORATOR_GET_SET()
171 */
172 #define IMP_DECORATOR_SET(AttributeKey, value) \
173  do { \
174  if (get_model()->get_has_attribute(AttributeKey, \
175  get_particle_index())) { \
176  get_model()->set_attribute(AttributeKey, \
177  get_particle_index(), \
178  value); \
179  } else { \
180  get_model()->add_attribute(AttributeKey, \
181  get_particle_index(), \
182  value); \
183  } \
184  } while (false)
185 
186 
187 //! Define methods for getting and setting a particular simple field
188 /** This macro defines methods to get and set a particular attribute.
189 
190  \param[in] name The lower case name of the attribute
191  \param[in] AttributeKey The AttributeKey object controlling
192  the attribute.
193  \param[in] Type The type of the attribute (upper case).
194  \param[in] ReturnType The type to return from the get.
195  \see IMP_DECORATOR_GET()
196  \see IMP_DECORATOR_SET()
197 */
198 #define IMP_DECORATOR_GET_SET(name, AttributeKey, Type, ReturnType) \
199  ReturnType get_##name() const { \
200  return static_cast<ReturnType>(get_model() \
201  ->get_attribute(AttributeKey, \
202  get_particle_index())); \
203  } \
204  void set_##name(ReturnType t) { \
205  get_model()->set_attribute(AttributeKey, get_particle_index(), t); \
206  } \
207  IMP_REQUIRE_SEMICOLON_CLASS(getset##name)
208 
209 
210 //! Define methods for getting and setting an optional simple field.
211 /** See IMP_DECORATOR_GET_SET(). The difference is that here you can provide
212  a default value to use if the decorator does not have the attribute.
213 
214  \param[in] name The lower case name of the attribute
215  \param[in] AttributeKey The expression to get the required attribute key.
216  \param[in] Type The type of the attribute (upper case).
217  \param[in] ReturnType The type to return from the get.
218  \param[in] default_value The value returned if the attribute is missing.
219 */
220 #define IMP_DECORATOR_GET_SET_OPT(name, AttributeKey, Type, \
221  ReturnType, default_value) \
222  ReturnType get_##name() const { \
223  IMP_DECORATOR_GET(AttributeKey, Type, \
224  return static_cast<ReturnType>(VALUE), \
225  return default_value); \
226  } \
227  void set_##name(ReturnType t) { \
228  IMP_DECORATOR_SET(AttributeKey, t); \
229  } \
230  IMP_REQUIRE_SEMICOLON_CLASS(getset_##name)
231 
232 
233 #ifdef IMP_DOXYGEN
234 #define IMP_DECORATORS_DECL(Name, PluralName)
235 #define IMP_DECORATORS_DEF(Name, PluralName)
236 
237 
238 //! Define the types for storing sets of decorators
239 /** The macro defines the types PluralName and PluralNameTemp.
240  */
241 #define IMP_DECORATORS(Name, PluralName, Parent)
242 
243 #else
244 #define IMP_DECORATORS_DECL(Name, PluralName) \
245  class Name; \
246  typedef IMP::base::Vector<Name> PluralName
247 
248 #define IMP_DECORATORS_DEF(Name, PluralName) \
249  /* needed so there is no ambiguity with operator->*/ \
250  inline std::ostream &operator<<(std::ostream &out, Name n) { \
251  n.show(out); \
252  return out; \
253  } \
254 
255 
256 #define IMP_DECORATORS(Name, PluralName, Parent) \
257  IMP_DECORATORS_DECL(Name, PluralName); \
258  IMP_DECORATORS_DEF(Name, PluralName)
259 
260 #endif
261 
262 #ifdef IMP_DOXYGEN
263 //! Define the types for storing sets of decorators
264 /** The macro defines the types PluralName and PluralNameTemp.
265  */
266 #define IMP_DECORATORS_WITH_TRAITS(Name, PluralName, Parent)
267 
268 #else
269 #define IMP_DECORATORS_WITH_TRAITS(Name, PluralName, Parent) \
270  /* needed so there is no ambiguity with operator->*/ \
271  inline std::ostream &operator<<(std::ostream &out, Name n) { \
272  n.show(out); \
273  return out; \
274  } \
275  typedef IMP::base::Vector<Name> PluralName
276 
277 #endif
278 
279 //! Create a decorator that computes some sort of summary info on a set
280 /** Examples include a centroid or a cover for a set of particles.
281 
282  \param[in] Name The name for the decorator
283  \param[in] Parent the parent decorator type
284  \param[in] Members the way to pass a set of particles in
285 */
286 #define IMP_SUMMARY_DECORATOR_DECL(Name, Parent, Members) \
287  class IMPCOREEXPORT Name: public Parent { \
288  IMP_CONSTRAINT_DECORATOR_DECL(Name); \
289  public: \
290  IMP_DECORATOR(Name, Parent); \
291  static Name setup_particle(Particle *p, \
292  const Members &members); \
293  static Name setup_particle(Particle *p, \
294  Refiner *ref); \
295  ~Name(); \
296  static bool particle_is_instance(Particle *p) { \
297  return p->has_attribute(get_constraint_key()); \
298  } \
299  IMP_NO_DOXYGEN(typedef boost::false_type DecoratorHasTraits); \
300  private: \
301  /* hide set methods*/ \
302  void set_coordinates() {}; \
303  void set_coordinates_are_optimized()const{} \
304  void set_coordinate() const {} \
305  void set_radius()const{} \
306  }; \
307  IMP_DECORATORS(Name, Name##s, Parent##s)
308 
309 
310 /** See IMP_SUMMARY_DECORATOR_DECL()
311  \param[in] Name The name for the decorator
312  \param[in] Parent the parent decorator type
313  \param[in] Members the way to pass a set of particles in
314  \param[in] create_modifier the statements to create the modifier
315  which computes the summary info. It should be called mod.
316 */
317 #define IMP_SUMMARY_DECORATOR_DEF(Name, Parent, Members, create_modifier) \
318  Name Name::setup_particle(Particle *p, const Members &ps) { \
319  Refiner *ref=new FixedRefiner(ps); \
320  create_modifier; \
321  if (!Parent::particle_is_instance(p)) Parent::setup_particle(p); \
322  set_constraint(mod, new DerivativesToRefined(ref), p); \
323  return Name(p); \
324  } \
325  Name Name::setup_particle(Particle *p, Refiner *ref) { \
326  create_modifier; \
327  if (!Parent::particle_is_instance(p)) Parent::setup_particle(p); \
328  set_constraint(mod, new DerivativesToRefined(ref), p); \
329  return Name(p); \
330  } \
331  Name::~Name(){} \
332  IMP_NO_DOXYGEN(void Name::show(std::ostream &out) const { \
333  out << #Name << " at " << static_cast<Parent>(*this); \
334  }) \
335  IMP_CONSTRAINT_DECORATOR_DEF(Name)
336 
337 
338 #endif /* IMPKERNEL_DECORATOR_MACROS_H */