IMP
2.0.0
The Integrative Modeling Platform
Main Page
Related Pages
Modules
Namespaces
Classes
Files
Examples
File List
File Members
kernel/container_macros.h
Go to the documentation of this file.
1
/**
2
* \file IMP/kernel/container_macros.h
3
* \brief Macros to define containers of objects
4
*
5
* Copyright 2007-2013 IMP Inventors. All rights reserved.
6
*
7
*/
8
9
#ifndef IMPKERNEL_CONTAINER_MACROS_H
10
#define IMPKERNEL_CONTAINER_MACROS_H
11
12
#include <IMP/kernel/kernel_config.h>
13
#include <
IMP/base/check_macros.h
>
14
#include <IMP/base/internal/Vector.h>
15
#include <
IMP/base/SetCheckState.h
>
16
#include <
IMP/base/log_macros.h
>
17
#include <
IMP/base/doxygen_macros.h
>
18
#include <algorithm>
19
20
21
22
23
// Swig doesn't do protection right with protected members
24
#ifdef IMP_SWIG_WRAPPER
25
#define IMP_PROTECTION(protection) public:
26
#else
27
#define IMP_PROTECTION(protection) protection:
28
#endif
29
30
#ifndef SWIG
31
/** Internal use only. */
32
#define IMP_EXPOSE_ITERATORS(ContainerType, container_name, Ucname, Ucnames, \
33
lcname, lcnames) \
34
IMP_SWITCH_DOXYGEN(class Ucname##Iterator; \
35
class Ucname##ConstIterator, \
36
typedef ContainerType::iterator Ucname##Iterator; \
37
typedef ContainerType::const_iterator \
38
Ucname##ConstIterator); \
39
Ucname##Iterator lcnames##_begin() {return container_name.begin();} \
40
Ucname##Iterator lcnames##_end() {return container_name.end();} \
41
Ucname##ConstIterator lcnames##_begin() const { \
42
return container_name.begin(); \
43
} \
44
Ucname##ConstIterator lcnames##_end() const { \
45
return container_name.end();} \
46
47
#else
48
#define IMP_EXPOSE_ITERATORS(ContainerType, container_name, \
49
Ucname, Ucnames,lcname, lcnames)
50
#endif // SWIG
51
52
#ifdef GCC_VISIBILITY
53
# define IMP_FORCE_EXPORT(x) __attribute__ ((visibility("default"))) x
54
#else
55
# define IMP_FORCE_EXPORT(x) x
56
#endif
57
58
59
60
61
/** \brief A macro to provide a uniform interface for storing lists of
62
objects.
63
64
This macro is designed to be used in the body of an object to add
65
a set of methods for manipulating a list of contained objects. It adds
66
methods
67
- get_foo
68
- set_foo
69
- set_foos
70
- foos_begin, foos_end
71
- remove_foo
72
- remove_foos
73
etc. where foo is the lcname provided.
74
75
\param[in] protection The level of protection for the container
76
(public, private).
77
\param[in] Ucname The name of the type of container in uppercase.
78
\param[in] lcname The name of the type of container in lower case.
79
\param[in] Data The type of the data to store.
80
\param[in] PluralData The plural of the data name. This should be a
81
container type.
82
83
An accompanying IMP_LIST_IMPL must go in a \c .cpp file.
84
85
\note This macro should be given an appropriate name and wrapped in a
86
doxygen comment block such as by starting with a C++ comment like
87
\verbatim
88
@name short description
89
longer description
90
@{
91
\endverbatim
92
and ending with one like
93
\verbatim
94
@}
95
\endverbatim
96
*/
97
#define IMP_LIST(protection, Ucname, lcname, Data, PluralData) \
98
IMP_LIST_ACTION(protection, Ucname, Ucname##s, lcname, \
99
lcname##s, Data, PluralData,,,)
100
101
#if defined(SWIG) || defined(IMP_DOXYGEN)
102
103
#define IMP_LIST_ACTION(protection, Ucname, Ucnames, lcname, lcnames, \
104
Data, PluralData,OnAdd, \
105
OnChanged, OnRemoved) \
106
public: \
107
void remove_##lcname(Data d); \
108
void remove_##lcnames(const PluralData& d); \
109
void set_##lcnames(const PluralData& ps); \
110
void set_##lcnames##_order(const PluralData& objs); \
111
unsigned int add_##lcname(Data obj); \
112
void add_##lcnames(const PluralData& objs); \
113
void clear_##lcnames(); \
114
unsigned int get_number_of_##lcnames() const; \
115
bool get_has_##lcnames(); \
116
Data get_##lcname(unsigned int i) const; \
117
PluralData get_##lcnames() const; \
118
void reserve_##lcnames(unsigned int sz)
119
120
121
#else
122
/** A version of IMP_LIST() for types where the spelling of the plural is
123
irregular (eg geometry-> geometries) and where actions can be taken
124
upon addition and removal:
125
\param[in] protection The level of protection for the container
126
(public, private).
127
\param[in] Ucname The name of the type of container in uppercase.
128
\param[in] lcname The name of the type of container in lower case.
129
\param[in] Data The type of the data to store.
130
\param[in] PluralData The plural of the data name. This should be a
131
container type.
132
\param[in] OnAdd Code to modify the passed in object. The object is obj
133
and its index index.
134
\param[in] OnChanged Code to get executed when the container changes.
135
\param[in] OnRemoved Code to get executed when the an object is removed.
136
*/
137
#define IMP_LIST_ACTION(protection, Ucname, Ucnames, lcname, lcnames, \
138
Data, PluralData,OnAdd, \
139
OnChanged, OnRemoved) \
140
IMP_PROTECTION(protection) \
141
/** \brief Remove any occurences of d from the container. */
\
142
void remove_##lcname(Data d) { \
143
IMP_OBJECT_LOG; \
144
bool found=false; \
145
for (Ucname##Iterator it= lcnames##_begin(); \
146
it != lcnames##_end(); ++it) { \
147
if (*it == d) { \
148
lcname##_handle_remove(*it); \
149
found=true; \
150
lcname##_vector_.erase(it); break; \
151
} \
152
} \
153
IMP_UNUSED(found); \
154
IMP_USAGE_CHECK(found, d << " not found in container: " \
155
<< get_as<PluralData>(lcname##_vector_)); \
156
lcname##_handle_change(); \
157
} \
158
/** \brief Remove any occurrences for which f is true */
\
159
template <class F> \
160
void remove_##lcnames##_if(const F &f) { \
161
IMP_OBJECT_LOG; \
162
for (Ucname##Iterator it= lcnames##_begin(); it != lcnames##_end(); \
163
++it) { \
164
if (f(*it)) lcname##_handle_remove(*it); \
165
} \
166
lcname##_vector_.erase(std::remove_if(lcname##_vector_.begin(), \
167
lcname##_vector_.end(), f), \
168
lcname##_vector_.end()); \
169
lcname##_handle_change(); \
170
} \
171
/** \brief Remove any occurences of each item in d. */
\
172
template <class List> \
173
void remove_##lcnames(List d) { \
174
IMP_OBJECT_LOG; \
175
base::Vector<Data> ds(d.begin(), d.end()); \
176
std::sort(ds.begin(), ds.end()); \
177
for (unsigned int i=0; i< ds.size(); ++i) { \
178
lcname##_handle_remove(ds[i]); \
179
} \
180
lcname##_vector_.erase(std::remove_if(lcname##_vector_.begin(), \
181
lcname##_vector_.end(), \
182
::IMP::base::internal \
183
::list_contains(ds)), \
184
lcname##_vector_.end()); \
185
} \
186
/** \brief Set the contents of the container to ps removing all its current
187
contents.
188
*/
\
189
template <class List> \
190
void set_##lcnames(List ps) { \
191
IMP_OBJECT_LOG; \
192
/* Bad things can happen if we use a Temp, as things get unreffed
193
before being reffed if they are in both lists */
\
194
clear_##lcnames(); \
195
add_##lcnames(ps); \
196
} \
197
/** \brief Must be the same set, just in a different order. */
\
198
template <class List> \
199
void set_##lcnames##_order(List ps) { \
200
IMP_OBJECT_LOG; \
201
IMP_USAGE_CHECK(ps.size() == lcname##_vector_.size(), \
202
"Reordered elements don't match."); \
203
lcname##_vector_.clear(); \
204
lcname##_vector_.insert(lcname##_vector_.end(), \
205
ps.begin(), ps.end()); \
206
} \
207
/** \brief add obj to the container
208
\return index of object within the object
209
*/
\
210
unsigned int add_##lcname(Data obj) { \
211
IMP_OBJECT_LOG; \
212
unsigned int index= lcname##_vector_.size(); \
213
lcname##_vector_.push_back(obj); \
214
IMP_UNUSED(index); IMP_UNUSED(obj); \
215
OnAdd; \
216
lcname##_handle_change(); \
217
return index; \
218
} \
219
/** \brief Add several objects to the container. They are not necessarily
220
added at the end.
221
*/
\
222
template <class List> \
223
void add_##lcnames(List objs) { \
224
IMP_OBJECT_LOG; \
225
unsigned int osz= lcname##_vector_.size(); \
226
lcname##_vector_.insert(lcname##_vector_.end(), objs.begin(), \
227
objs.end()); \
228
for (PluralData::size_type i=0; i< objs.size(); ++i) { \
229
Data obj= lcname##_vector_[osz+i]; \
230
unsigned int index(osz+i); \
231
OnAdd; \
232
IMP_UNUSED(obj); IMP_UNUSED(index); \
233
} \
234
lcname##_handle_change(); \
235
} \
236
/** \brief Clear all objects from the container */
\
237
void clear_##lcnames() { \
238
lcname##_vector_.clear(); \
239
lcname##_handle_change(); \
240
} \
241
unsigned int get_number_of_##lcnames() const { \
242
return lcname##_vector_.size();} \
243
/** \brief return true if there are any objects in the container*/
\
244
bool get_has_##lcnames() const { \
245
return !lcname##_vector_.empty();} \
246
/** Get the object refered to by the index
247
\throws IndexException in Python if the index is out of range
248
*/
\
249
Data get_##lcname(unsigned int i) const { \
250
return lcname##_vector_[i]; \
251
} \
252
PluralData get_##lcnames() const { \
253
return get_as<PluralData>(lcname##_vector_); \
254
} \
255
void reserve_##lcnames(unsigned int sz) { \
256
lcname##_vector_.reserve(sz); \
257
} \
258
IMP_EXPOSE_ITERATORS(PluralData, \
259
lcname##_vector_, Ucname, Ucnames, lcname, lcnames); \
260
/** This method allows one to modify the contents of the container without
261
any callbacks being made.*/
\
262
IMP_PROTECTED_METHOD(PluralData &, mutable_access_##lcnames, (), , { \
263
return lcname##_vector_;}); \
264
protected: \
265
IMP_NO_DOXYGEN(const PluralData &access_##lcnames() const { \
266
return lcname##_vector_;}) \
267
private: \
268
void lcname##_handle_remove( Data obj) { \
269
Ucname##DataWrapper::do_handle_remove(obj, this); \
270
} \
271
void lcname##_handle_change() { \
272
OnChanged; \
273
clear_caches(); \
274
} \
275
struct Ucname##DataWrapper: public PluralData { \
276
template <class TT> \
277
static void do_handle_remove( Data obj, TT *container){ \
278
IMP_UNUSED(container); \
279
IMP_UNUSED(obj); \
280
OnRemoved; \
281
} \
282
/* Older GCC (e.g. on Mac OS X 10.4) does not correctly export the
283
symbol for this destructor even when the surrounding class is itself
284
exported, causing lookup failures in DSOs that use the class.
285
Work around this by forcing the symbol to be exported. Ideally, we
286
should have a configure check for this problem... */
\
287
IMP_FORCE_EXPORT(~Ucname##DataWrapper()); \
288
}; \
289
friend struct Ucname##DataWrapper; \
290
IMP_NO_DOXYGEN(Ucname##DataWrapper lcname##_vector_;) \
291
IMP_PROTECTION(protection) \
292
IMP_REQUIRE_SEMICOLON_CLASS(list##lcname)
293
294
#endif
295
296
297
//! This should go in a .cpp file for the respective class.
298
/**
299
This code should go in a .cpp file. One macro for each IMP_CONTAINER.
300
\param[in] Class The name of the class containing this container.
301
\param[in] Ucname The name of the type of container in uppercase.
302
\param[in] lcname The name of the type of container in lower case.
303
\param[in] Data The type of the data to store.
304
\param[in] PluralData The plural of the data name. This should be a
305
container type.
306
307
For all of these the current object is called obj and is of type Data.
308
*/
309
#define IMP_LIST_IMPL(Class, Ucname, lcname, Data, PluralData) \
310
IMP_LIST_ACTION_IMPL(Class, Ucname, Ucname##s, lcname, lcname##s, \
311
Data, PluralData)
312
313
#define IMP_LIST_ACTION_IMPL(Class, Ucname, Ucnames, lcname, lcnames, \
314
Data, PluralData) \
315
Class::Ucname##DataWrapper::~Ucname##DataWrapper() { \
316
for (unsigned int i=0; i< size(); ++i) { \
317
do_handle_remove(operator[](i), static_cast<Class*>(0)); \
318
} \
319
} \
320
IMP_REQUIRE_SEMICOLON_NAMESPACE
321
322
323
324
325
326
#ifndef SWIG
327
/** Report dependencies of the container Name. Add the line
328
deps_(new DependenciesScoreState(this), model) to the constructor
329
initializer list. The input_deps argument should add the input
330
containers to a variable ret.
331
*/
332
#define IMP_CONTAINER_DEPENDENCIES(Name, input_deps) \
333
class DependenciesScoreState: public ScoreState { \
334
Name* back_; \
335
public: \
336
DependenciesScoreState(Name *n): \
337
ScoreState(n->get_name()+" dependencies"), \
338
back_(n){} \
339
ContainersTemp get_input_containers() const{ \
340
ContainersTemp ret; \
341
input_deps \
342
return ret; \
343
} \
344
ContainersTemp get_output_containers() const{ \
345
return ContainersTemp(1, back_); \
346
} \
347
ParticlesTemp get_input_particles() const { \
348
return ParticlesTemp(); \
349
} \
350
ParticlesTemp get_output_particles() const{ \
351
return ParticlesTemp(); \
352
} \
353
void do_before_evaluate() {} \
354
void do_after_evaluate(DerivativeAccumulator *) {} \
355
IMP_OBJECT_METHODS(DependenciesScoreState) \
356
friend class DependenciesScoreState; \
357
ScopedScoreState deps_
358
359
#else
360
#define IMP_CONTAINER_DEPENDENCIES(Name, input_deps)
361
#endif
362
363
#define IMP_CONTAINER_FOREACH_LOOP(ContainerType, container, \
364
operation, tname) \
365
for (unsigned int _2=0; _2< imp_foreach_indexes.size(); ++_2) { \
366
tname ContainerType::ContainedIndexType _1 \
367
= imp_foreach_indexes[_2]; \
368
bool imp_foreach_break=false; \
369
operation; \
370
if (imp_foreach_break) { break;} \
371
} \
372
373
#define IMP_CONTAINER_FOREACH_IMPL(ContainerType, container, \
374
operation, tname) \
375
do { \
376
if (container->get_provides_access()) { \
377
const tname ContainerType::ContainedIndexTypes& \
378
imp_foreach_indexes =container->get_access(); \
379
IMP_CONTAINER_FOREACH_LOOP(ContainerType, container, \
380
operation, tname); \
381
} else { \
382
tname ContainerType::ContainedIndexTypes \
383
imp_foreach_indexes =container->get_indexes(); \
384
IMP_CONTAINER_FOREACH_LOOP(ContainerType, container, \
385
operation, tname); \
386
} \
387
} while (false)
388
389
/** See IMP_CONTAINER_FOREACH().
390
391
This version is for use in a template function. See
392
IMP_FOREACH_INDEX() for another version.
393
*/
394
#define IMP_CONTAINER_FOREACH_TEMPLATE(ContainerType, container, operation) \
395
IMP_CONTAINER_FOREACH_IMPL(ContainerType, container, operation, typename)
396
397
/** These macros avoid various inefficiencies.
398
399
The macros take the name of the container and the operation to
400
peform. In operation, _1 is used to refer to the item using its
401
ContainedIndexType (e.g., IMP::ParticleIndex in SingletonContainer,
402
or IMP::ParticleIndexPair in PairContainer).
403
The location of this item in the container itself is _2.
404
Use it like:
405
\code
406
IMP_CONTAINER_FOREACH(SingletonContainer, sc, std::cout << "Item "
407
<< _2 << " has particle index " << _1 << std::endl);
408
\endcode
409
410
See IMP_CONTAINER_FOREACH_TEMPLATE() if you want to use it in a template
411
function.
412
*/
413
#define IMP_CONTAINER_FOREACH(ContainerType, container, operation) \
414
IMP_CONTAINER_FOREACH_IMPL(ContainerType, container, operation, )
415
416
/** Provide a block that can have efficient, direct access to the contents
417
of the container in the variable imp_indexes.
418
*/
419
#define IMP_CONTAINER_ACCESS(ContainerType, container, operation) \
420
do { \
421
if (container->get_provides_access()) { \
422
const ContainerType::ContainedIndexTypes& \
423
imp_indexes =container->get_access(); \
424
operation; \
425
} else { \
426
ContainerType::ContainedIndexTypes \
427
imp_indexes =container->get_indexes(); \
428
operation; \
429
} \
430
} while (false)
431
432
#endif
/* IMPKERNEL_CONTAINER_MACROS_H */