IMP logo
IMP Reference Guide  2.5.0
The Integrative Modeling Platform
Decorator.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Decorator.h \brief The base class for decorators.
3  *
4  * Copyright 2007-2015 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_DECORATOR_H
9 #define IMPKERNEL_DECORATOR_H
10 
11 #include <IMP/kernel_config.h>
12 #include "base_types.h"
13 #include <IMP/Object.h>
14 #include <IMP/WeakPointer.h>
15 #include "Model.h"
16 #include "Particle.h"
17 #include "utility.h"
18 #include "Constraint.h"
19 #include "internal/utility.h"
20 #include <IMP/utility_macros.h>
21 #include <IMP/Vector.h>
22 #include <IMP/Value.h>
23 
24 IMPKERNEL_BEGIN_NAMESPACE
25 class ParticleAdaptor;
26 
27 /**
28 Representation of the structure in \imp is via a collection of
29 Particle objects. However, since particles are general purpose, they
30 provide a basic set of tools for managing the data (e.g.
31 IMP::Model::add_attribute(), IMP::Model::get_value()
32 etc). Decorators wrap (or \quote{decorate}) particles to provide a much
33 richer interface. For example, most particles have Cartesian
34 coordinates. The class IMP::core::XYZ decorates such a particle to
35 provide functions to get and set the Cartesian coordinates as well as
36 compute distances between particles.
37 \code
38 d0= IMP.core.XYZ(p0)
39 d1= IMP.core.XYZ(p1)
40 print IMP.core.distance(d0,d1)
41 print d0.get_coordinates()
42 \endcode
43 
44 \par Decorator basics
45 
46 \note The `get_is_setup()` and `setup_particle()` functions mentioned below
47 can take any of either an IMP::Model* and IMP::ParticleIndex
48 pair, an IMP::Paricle* or another decorator to identify the particle.
49 We use various of those below.
50 
51 Dealing with decorators and particles has two main parts
52 -# setting up the particle to be used with that decorator
53 -# decorating the particle.
54 
55 To set up a particle to be used with the IMP::core::XYZ decorator we do
56 \code
57 d0= IMP.core.XYZ.setup_particle(m, pi, IMP.algebra.Vector3D(0,2,3))
58 \endcode
59 The method calls also decorates the particle and returns the decorator
60 which can now be used to manipulate the particle. For example we can
61 access the coordinates \c (0,2,3) by doing
62 \code
63 print d0.get_coordinates()
64 \endcode
65 We now say the particle is an XYZ particle. If that particle is
66 encountered later when we do not have the existing decorator available,
67 we can decorate it again (since it is already set up) by doing
68 \code
69 d1= IMP.core.XYZ(m, pi)
70 \endcode
71 
72 If you do not know if \c p has been set up for the XYZ decorator, you can
73 ask with
74 \code
75 if IMP.core.XYZ.get_is_setup(m, pi):
76 \endcode
77 
78 More abstractly, decorators can be used to
79 - maintain invariants: e.g. an IMP::atom::Bond particle always connects
80  two other particles, both of which are IMP::atom::Bonded particles.
81 - add functionality: e.g. you can get the coordinates as an
82  IMP::algebra::Vector3D
83 - provide uniform names for attributes: so you do not use \quote{x} some places
84 and \quote{X} other places
85 
86 To see a list of all available decorators and to see what functions
87 all decorators have, look at the list of classes which inherit from
88 IMP::Decorator, below.
89 
90 See the IMP::example::ExampleDecorator %example for how to implement a
91 simple decorator.
92 
93 \note Decorator objects are ordered based on the address of the wrapped
94 particle. Like pointers, they are logical values so can be in \c if
95 statements.
96 
97 \implementation{Decorator, IMP_DECORATOR, IMP::example::ExampleDecorator}
98 \n\n For efficiency reasons attribute keys should always be created
99 lazily (at the time of the first use), and not be created as static
100 variables. The reason for this is that initialized attribute keys result
101 in space being allocated in decorators, even before they are used.\n\n
102 Implementors should consult IMP::example::ExampleDecorator,
103 IMP_DECORATOR_METHODS(), IMP_DECORATOR_WITH_TRAITS_METHODS(),
104 IMP_DECORATOR_GET().
105 
106 A decorator can be cast to a IMP::Particle* in C++. You have to
107 use the Decorator::get_particle() function in Python.
108 
109 \note It is undefined behavior to use a decorator constructed on
110 a particle that is no longer part of a model. Since constructing
111 decorators is very cheap, you probably should not store decorators,
112 and then would not have this problem.
113 
114 See example::ExampleDecorator to see what a minimal decorator looks like.
115 */
116 class IMPKERNELEXPORT Decorator : public Value {
117  private:
118  WeakPointer<Model> model_;
119  ParticleIndex pi_;
120  bool is_valid_; // false if constructed with default constructor
121  int compare(Object* o) const {
122  if (o < get_particle())
123  return -1;
124  else if (o > get_particle())
125  return 1;
126  else
127  return 0;
128  }
129 
130  protected:
132  : model_(m), pi_(pi), is_valid_(true) {}
133  Decorator() : is_valid_(false) {}
134 
135 #ifndef IMP_DOXYGEN
136  public:
137 #endif
138  explicit Decorator(ParticleAdaptor p);
139 
140  public:
141 #ifdef _MSC_VER
142  typedef Particle* ParticleP;
143 #endif
144 #ifndef IMP_DOXYGEN
145  bool __eq__(Object* o) const { return operator==(o); }
146  bool __ne__(Object* o) const { return operator!=(o); }
147  bool __lt__(Object* o) const { return operator<(o); }
148  bool __gt__(Object* o) const { return operator>(o); }
149  bool __ge__(Object* o) const { return operator>=(o); }
150  bool __le__(Object* o) const { return operator<=(o); }
151 #ifndef SWIG
152  bool operator==(Object* o) const { return (compare(o) == 0); }
153  bool operator!=(Object* o) const { return (compare(o) != 0); }
154  bool operator<(Object* o) const { return (compare(o) < 0); }
155  bool operator>(Object* o) const { return (compare(o) > 0); }
156  bool operator>=(Object* o) const { return !(compare(o) < 0); }
157  bool operator<=(Object* o) const { return !(compare(o) > 0); }
158 
159  bool operator==(Particle* o) const { return (compare(o) == 0); }
160  bool operator!=(Particle* o) const { return (compare(o) != 0); }
161  bool operator<(Particle* o) const { return (compare(o) < 0); }
162  bool operator>(Particle* o) const { return (compare(o) > 0); }
163  bool operator>=(Particle* o) const { return !(compare(o) < 0); }
164  bool operator<=(Particle* o) const { return !(compare(o) > 0); }
165 #endif
166 #endif
167 
168  //! Returns the particle decorated by this decorator.
170  if (!model_)
171  return nullptr;
172  else {
173  IMP_USAGE_CHECK(model_->get_particle(pi_),
174  "Particle " << pi_ << " is no longer part of the model.");
175  return model_->get_particle(pi_);
176  }
177  }
178 
179 #if !defined(SWIG)
180  operator Particle*() const { return get_particle(); }
181  Particle* operator->() const { return get_particle(); }
182  operator ParticleIndex() const { return get_particle_index(); }
183 #endif
184 
185  //! Returns the particle index decorated by this decorator.
186  ParticleIndex get_particle_index() const { return pi_; }
187 
188  //! Returns the Model containing the particle.
189  Model* get_model() const { return model_; }
190 
191  /** Returns true if the decorator was constructued with a non-default
192  constructor.
193 
194  @note It is guaranteed that this is a very fast method.
195  However, this method might return false if the particle itself
196  was invalidated after construction - use check_particle()
197  in that case.
198  */
199  bool get_is_valid() const { return is_valid_; }
200 
201  IMP_HASHABLE_INLINE(Decorator, return boost::hash_value(get_particle()););
202 
203 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
204  typedef boost::false_type DecoratorHasTraits;
205 #endif
206 };
207 
208 #ifndef IMP_DOXYGEN
209 /** Check that the particle satisfies invariants registered by decorators.
210  */
211 IMPKERNELEXPORT void check_particle(Model *m, ParticleIndex pi);
212 
213 IMPKERNEL_DEPRECATED_FUNCTION_DECL(2.5)
214 inline void check_particle(Particle* p) {
215  IMPKERNEL_DEPRECATED_FUNCTION_DEF(2.5, "Use the index version instead");
216  check_particle(p->get_model(), p->get_index());
217 }
218 #endif
219 
220 IMPKERNEL_END_NAMESPACE
221 
222 #endif /* IMPKERNEL_DECORATOR_H */
ParticleIndex get_particle_index() const
Returns the particle index decorated by this decorator.
Definition: Decorator.h:186
Smart pointer to Object-derived classes that does not refcount.
Definition: WeakPointer.h:76
#define IMP_HASHABLE_INLINE(name, hashret)
Definition: hash_macros.h:18
Model * get_model() const
Returns the Model containing the particle.
Definition: Decorator.h:189
Storage of a model, its restraints, constraints and particles.
Index< ParticleIndexTag > ParticleIndex
Definition: base_types.h:154
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:72
Base for a simple primitive-like type.
Definition: Value.h:21
Common base class for heavy weight IMP objects.
Definition: Object.h:106
int compare(const VectorD< D > &a, const VectorD< D > &b)
lexicographic comparison of two vectors
Definition: VectorD.h:179
Various general useful macros for IMP.
A nullptr-initialized pointer to an Object.
A class for storing lists of IMP items.
For backwards compatibility.
bool get_is_valid() const
Definition: Decorator.h:199
Particle * get_particle() const
Returns the particle decorated by this decorator.
Definition: Decorator.h:169
Classes to handle individual model particles. (Note that implementation of inline functions is in int...
A shared base class to help in debugging and things.
Basic types used by IMP.
Class to handle individual model particles.
Definition: Particle.h:37
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168