IMP logo
IMP Reference Guide  develop.d36d3deffb,2026/11/09
The Integrative Modeling Platform
Object.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Object.h
3  * \brief A shared base class to help in debugging and things.
4  *
5  * Copyright 2007-2026 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_OBJECT_H
10 #define IMPKERNEL_OBJECT_H
11 
12 #include <IMP/kernel_config.h>
13 #include <IMP/kernel_config.h>
14 #include "exception.h"
15 #include "utility_macros.h"
16 #include "NonCopyable.h"
17 #include "ref_counted_macros.h"
18 #include "enums.h"
19 #include "hash_macros.h"
20 #include "warning_macros.h"
21 #include "showable_macros.h"
22 #include "VersionInfo.h"
23 #include "utility_macros.h"
24 #include <IMP/hash.h>
25 #include "hash.h"
26 #include <boost/scoped_array.hpp>
27 #include <cereal/access.hpp>
28 
29 // Make sure that binary archives are registered with cereal
30 // before any Object subclass that uses CEREAL_REGISTER_TYPE
31 #include <cereal/archives/binary.hpp>
32 
33 #if !defined(IMP_HAS_CHECKS)
34 #error "IMP_HAS_CHECKS not defined, something is broken"
35 #endif
36 #if !defined(IMP_NONE)
37 #error "IMP_NONE not defined, something is broken"
38 #endif
39 #if !defined(IMP_HAS_LOG)
40 #error "IMP_HAS_LOG not defined, something is broken"
41 #endif
42 #if !defined(IMP_SILENT)
43 #error "IMP_SILENT not defined, something is broken"
44 #endif
45 
46 IMPKERNEL_BEGIN_NAMESPACE
47 
48 //! Common base class for heavy weight \imp objects.
49 /**
50 The base class for non \ref introduction_values "value-type classes" in
51 \imp. Anything inheriting from Object has the following properties:
52 
53 - has embedded information about the module and version which can
54 be accessed using Object::get_version_info(). This information can
55 be used to log what version of software is used to compute a
56 result.
57 
58 - it has a local logging level which can override the global one
59 allowing fine grained logging control.
60 
61 - in Python, there is a method Class::get_from(Object *o) that
62 attempts to cast o to an object of type Class and throws an
63 exception if it fails.
64 
65 - the object keeps track of whether it has been been used. See the
66 Object::set_was_used() method for an explanation.
67 
68 - It is reference counted
69 
70 Types inheriting from Object should always be created using \c new
71 in C++ and passed using pointers and stored using Pointer
72 objects. Note that you have to be careful of cycles and so must
73 use WeakPointer objects to break cycles. IMP_NEW() can help shorten
74 creating a ref counted pointer. See Pointer for more
75 information.
76 
77 See example::ExampleObject for a simple example.
78 
79 Reference counting is a technique for managing memory and
80 automatically freeing memory (destroying objects) when it is no
81 longer needed. In reference counting, each object has a reference
82 count, which tracks how many different places are using the
83 object. When this count goes to 0, the object is freed.
84 
85 Python internally reference counts everything. C++, on the other
86 hand, requires extra steps be taken to ensure that objects are
87 reference counted properly.
88 
89 In \imp, reference counting is done through the Pointer,
90 PointerMember and Object classes. The former should be used
91 instead of a raw C++ pointer when storing a pointer to any object
92 inheriting from Object.
93 
94 Any time one is using reference
95 counting, one needs to be aware of cycles, since if, for example,
96 object A contains an IMP::Pointer to object B and object B
97 contains an Pointer to object A, their reference counts will never
98 go to 0 even if both A and B are no longer used. To avoid this,
99 use an WeakPointer in one of A or B.
100 
101 Functions that create new objects should follow the following pattern
102 
103  ObjectType *create_object(arguments) {
104  IMP_NEW(ObjectType, ret, (args));
105  do_stuff;
106  return ret.release();
107  }
108 
109 using Pointer::release() to safely return the new object without freeing it.
110 */
111 class IMPKERNELEXPORT Object : public NonCopyable {
112  std::string name_;
113 #if IMP_KERNEL_HAS_LOG4CXX
114  boost::scoped_array<char> quoted_name_;
115 #endif
116 
117  static unsigned int live_objects_;
118  mutable int count_;
119 
120 #if IMP_HAS_LOG != IMP_NONE
121  LogLevel log_level_;
122 #endif
123 
124 #if IMP_HAS_CHECKS >= IMP_USAGE
125  CheckLevel check_level_;
126  mutable bool was_owned_;
127  double check_value_;
128 #endif
129 
130 #if IMP_HAS_CHECKS >= IMP_INTERNAL
131  static void add_live_object(Object* o);
132  static void remove_live_object(Object* o);
133 #endif
134 
135  friend class cereal::access;
136 
137  template<class Archive> void serialize(Archive &ar) {
138  ar(name_);
139 #if IMP_HAS_LOG != IMP_NONE
140  ar(log_level_);
141 #endif
142 #if IMP_HAS_CHECKS >= IMP_USAGE
143  ar(check_level_, was_owned_, check_value_);
144 #endif
145  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
146  // set quoted_name from name
147  set_name_internal(name_);
148  }
149  }
150 
151  void set_name_internal(std::string name);
152 
153  void initialize(std::string name);
154 
155  int compare(const Object& o) const {
156  if (&o < this)
157  return 1;
158  else if (&o > this)
159  return -1;
160  else
161  return 0;
162  }
163 
164  typedef std::function<void(Object *, cereal::BinaryOutputArchive &)> SaveFunc;
165  typedef std::function<Object*(cereal::BinaryInputArchive &)> LoadFunc;
166  struct OutputSerializer {
167  std::string class_name;
168  SaveFunc save_func;
169  };
170 
171  static std::map<std::string, OutputSerializer> &get_output_serializers();
172  static std::map<std::string, LoadFunc> &get_input_serializers();
173 
174  protected:
175  //! Construct an object with the given name
176  /** An instance of "%1%" in the string will be replaced by a unique
177  index.
178  */
179  Object(std::string name);
180 
181  public:
182  virtual ~Object();
183  // needed for Python to make sure all wrapper objects are equivalent
184  IMP_HASHABLE_INLINE(Object, return boost::hash_value(this););
185 
186  //! Set the logging level used in this object
187  /** Each object can be assigned a different log level in order to,
188  for example, suppress messages for verbose and uninteresting
189  objects. If set to DEFAULT, the global level as returned by
190  IMP::get_log_level() is used, otherwise
191  the local one is used. Methods in classes inheriting from
192  Object should start with IMP_OBJECT_LOG to change the log
193  level to the local one for this object and increase
194  the current indent.
195 
196  \see IMP::set_log_level()
197  \see IMP::get_log_level()
198  */
199  void set_log_level(LogLevel l);
200 
201  /** Each object can be assigned a different check level too.
202  */
203  void set_check_level(CheckLevel l);
204  LogLevel get_log_level() const;
205  CheckLevel get_check_level() const;
206 
207  //! Get information about the module and version of the object
208  virtual VersionInfo get_version_info() const {
209  return VersionInfo("none", "none");
210  }
211 
212  /** @name Names
213  All objects have names to aid in debugging and inspection
214  of the state of the system. These names are not necessarily unique
215  and should not be used to store data or as keys into a table. Use
216  the address of the object instead since objects cannot be copied.
217  @{
218  */
219  const std::string& get_name() const { return name_; }
220  void set_name(std::string name);
221  virtual std::string get_type_name() const { return "unknown object type"; }
222  /* @} */
223 
224  /** \imp provides warnings when objects are never used before they are
225  destroyed. Examples of use include adding an IMP::Restraint to an
226  IMP::ScoringFunction. If an object is not properly marked as used, or
227  your code is the one using it, call set_was_used(true) on the object.
228  */
229  void set_was_used(bool tf) const;
230 
231  IMP_SHOWABLE(Object);
232 
233 #ifndef IMP_DOXYGEN
234  //! Return a string version of the object, can be used in the debugger
235  std::string get_string() const {
236  std::ostringstream oss;
237  show(oss);
238  return oss.str();
239  }
240 
241 #ifndef SWIG
242  void ref() const { ++count_; }
243  void unref() const;
244  void release() const;
245 #if IMP_KERNEL_HAS_LOG4CXX
246  const char* get_quoted_name_c_string() const { return quoted_name_.get(); }
247 #endif
248 
249  /** \see IMP_OBJECT_SERIALIZE_DECL */
250  static bool register_serialize(const std::type_info &t, std::string name,
251  SaveFunc save_func, LoadFunc load_func);
252 
253  //! Save the most-derived Object subclass to the given binary archive
254  void poly_serialize(cereal::BinaryOutputArchive &ar);
255 
256  //! Create most-derived Object subclass from the given binary archive
257  static Object *poly_unserialize(cereal::BinaryInputArchive &ar);
258 #endif
259 
260  void _on_destruction();
261 
262  //! Return whether the object already been freed
263  bool get_is_valid() const;
264 
265  unsigned int get_ref_count() const { return count_; }
266 
267  static unsigned int get_number_of_live_objects() { return live_objects_; }
268  bool get_is_shared() const { return count_ > 1; }
269 #endif // IMP_DOXYGEN
270 
271  /** Objects can have internal caches. This method resets them returning
272  the object to its just-initialized state.
273  */
274  virtual void clear_caches() {}
275 
276  protected:
277  /** Override this method to take action on destruction. */
278  virtual void do_destroy() {}
279 };
280 
281 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
282 inline void Object::set_check_level(CheckLevel l) {
283  IMP_CHECK_VARIABLE(l);
284 #if IMP_HAS_CHECKS != IMP_NONE
285  check_level_ = l;
286 #endif
287 }
288 
289 inline LogLevel Object::get_log_level() const {
290 #if IMP_HAS_LOG == IMP_SILENT
291  return SILENT;
292 #else
293  return log_level_;
294 #endif
295 }
296 inline CheckLevel Object::get_check_level() const {
297 #if IMP_HAS_CHECKS == IMP_NONE
298  return NONE;
299 #else
300  return check_level_;
301 #endif
302 }
303 
304 inline void Object::set_was_used(bool tf) const {
305  IMP_CHECK_VARIABLE(tf);
306 #if IMP_HAS_CHECKS >= IMP_USAGE
307  was_owned_ = tf;
308 #endif
309 }
310 
311 inline bool Object::get_is_valid() const {
312 #if IMP_HAS_CHECKS == IMP_NONE
313  return true;
314 #else
315  return static_cast<int>(check_value_) == 111111111;
316 #endif
317 }
318 #endif
319 
320 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
321 /** Send the whole show output to a stream*/
322 class ShowFull {
323  std::string showed_;
324 
325  public:
326  ShowFull(Object* o) {
327  std::ostringstream oss;
328  o->show(oss);
329  showed_ = oss.str();
330  }
331  const std::string& get_string() const { return showed_; }
332 };
333 inline std::ostream& operator<<(std::ostream& o, const ShowFull& sf) {
334  o << sf.get_string();
335  return o;
336 }
337 #endif
338 IMPKERNEL_END_NAMESPACE
339 
340 #endif /* IMPKERNEL_OBJECT_H */
Macros to help with reference counting.
CheckLevel get_check_level()
Get the current audit mode.
Definition: exception.h:80
Base class for all objects that cannot be copied.
#define IMP_HASHABLE_INLINE(name, hashret)
Definition: hash_macros.h:18
Helper functions for implementing hashes.
LogLevel
The log levels supported by IMP.
Definition: enums.h:19
#define IMP_SHOWABLE(Name)
virtual void clear_caches()
Definition: Object.h:274
Exception definitions and assertions.
LogLevel get_log_level()
Get the currently active global log level.
Definition: log.h:92
Do not output any text.
Definition: enums.h:24
Base class for all objects that cannot be copied.
Definition: NonCopyable.h:22
virtual void do_destroy()
Definition: Object.h:278
Common base class for heavy weight IMP objects.
Definition: Object.h:111
Macros to control compiler warnings.
Helper macros for implementing hashable classes.
Various general useful macros for IMP.
Version and module information for Objects.
Definition: VersionInfo.h:29
int compare(const VectorD< D > &a, const VectorD< D > &b)
lexicographic comparison of two vectors
Definition: VectorD.h:165
Basic enumeration types used by IMP.
std::ostream & show(Hierarchy h, std::ostream &out=std::cout)
Print the hierarchy using a given decorator to display each node.
void set_log_level(LogLevel l)
Set the current global log level.
CheckLevel
Specify the level of runtime checks performed.
Definition: enums.h:51
virtual VersionInfo get_version_info() const
Get information about the module and version of the object.
Definition: Object.h:208
Version and authorship of IMP objects.
Macros to help with objects that can be printed to a stream.
void set_check_level(CheckLevel tf)
Control runtime checks in the code.
Definition: exception.h:72