IMP logo
IMP Reference Guide  develop.27926d84dc,2024/04/16
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-2022 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  boost::scoped_array<char> quoted_name_;
114 
115  static unsigned int live_objects_;
116  mutable int count_;
117 
118 #if IMP_HAS_LOG != IMP_NONE
119  LogLevel log_level_;
120 #endif
121 
122 #if IMP_HAS_CHECKS >= IMP_USAGE
123  CheckLevel check_level_;
124  mutable bool was_owned_;
125  double check_value_;
126 #endif
127 
128 #if IMP_HAS_CHECKS >= IMP_INTERNAL
129  static void add_live_object(Object* o);
130  static void remove_live_object(Object* o);
131 #endif
132 
133  friend class cereal::access;
134 
135  template<class Archive> void serialize(Archive &ar) {
136  ar(name_);
137 #if IMP_HAS_LOG != IMP_NONE
138  ar(log_level_);
139 #endif
140 #if IMP_HAS_CHECKS >= IMP_USAGE
141  ar(check_level_, was_owned_, check_value_);
142 #endif
143  if (std::is_base_of<cereal::detail::InputArchiveBase, Archive>::value) {
144  // set quoted_name from name
145  set_name_internal(name_);
146  }
147  }
148 
149  void set_name_internal(std::string name);
150 
151  void initialize(std::string name);
152 
153  int compare(const Object& o) const {
154  if (&o < this)
155  return 1;
156  else if (&o > this)
157  return -1;
158  else
159  return 0;
160  }
161 
162  typedef std::function<void(Object *, cereal::BinaryOutputArchive &)> SaveFunc;
163  typedef std::function<Object*(cereal::BinaryInputArchive &)> LoadFunc;
164  struct OutputSerializer {
165  std::string class_name;
166  SaveFunc save_func;
167  };
168 
169  static std::map<std::string, OutputSerializer> &get_output_serializers();
170  static std::map<std::string, LoadFunc> &get_input_serializers();
171 
172  protected:
173  //! Construct an object with the given name
174  /** An instance of "%1%" in the string will be replaced by a unique
175  index.
176  */
177  Object(std::string name);
178 
179  public:
180  virtual ~Object();
181  // needed for Python to make sure all wrapper objects are equivalent
182  IMP_HASHABLE_INLINE(Object, return boost::hash_value(this););
183 
184  //! Set the logging level used in this object
185  /** Each object can be assigned a different log level in order to,
186  for example, suppress messages for verbose and uninteresting
187  objects. If set to DEFAULT, the global level as returned by
188  IMP::get_log_level() is used, otherwise
189  the local one is used. Methods in classes inheriting from
190  Object should start with IMP_OBJECT_LOG to change the log
191  level to the local one for this object and increase
192  the current indent.
193 
194  \see IMP::set_log_level()
195  \see IMP::get_log_level()
196  */
197  void set_log_level(LogLevel l);
198 
199  /** Each object can be assigned a different check level too.
200  */
201  void set_check_level(CheckLevel l);
202  LogLevel get_log_level() const;
203  CheckLevel get_check_level() const;
204 
205  //! Get information about the module and version of the object
206  virtual VersionInfo get_version_info() const {
207  return VersionInfo("none", "none");
208  }
209 
210  /** @name Names
211  All objects have names to aid in debugging and inspection
212  of the state of the system. These names are not necessarily unique
213  and should not be used to store data or as keys into a table. Use
214  the address of the object instead since objects cannot be copied.
215  @{
216  */
217  const std::string& get_name() const { return name_; }
218  void set_name(std::string name);
219  virtual std::string get_type_name() const { return "unknown object type"; }
220  /* @} */
221 
222  /** \imp provides warnings when objects are never used before they are
223  destroyed. Examples of use include adding an IMP::Restraint to an
224  IMP::Model. If an object is not properly marked as used, or your
225  code is the one using it, call set_was_used(true) on the object.
226  */
227  void set_was_used(bool tf) const;
228 
229  IMP_SHOWABLE(Object);
230 
231 #ifndef IMP_DOXYGEN
232  //! Return a string version of the object, can be used in the debugger
233  std::string get_string() const {
234  std::ostringstream oss;
235  show(oss);
236  return oss.str();
237  }
238 
239 #ifndef SWIG
240  void ref() const { ++count_; }
241  void unref() const;
242  void release() const;
243  const char* get_quoted_name_c_string() const { return quoted_name_.get(); }
244 
245  /** \see IMP_OBJECT_SERIALIZE_DECL */
246  static bool register_serialize(const std::type_info &t, std::string name,
247  SaveFunc save_func, LoadFunc load_func);
248 
249  //! Save the most-derived Object subclass to the given binary archive
250  void poly_serialize(cereal::BinaryOutputArchive &ar);
251 
252  //! Create most-derived Object subclass from the given binary archive
253  static Object *poly_unserialize(cereal::BinaryInputArchive &ar);
254 #endif
255 
256  void _on_destruction();
257 
258  //! Return whether the object already been freed
259  bool get_is_valid() const;
260 
261  unsigned int get_ref_count() const { return count_; }
262 
263  static unsigned int get_number_of_live_objects() { return live_objects_; }
264  bool get_is_shared() const { return count_ > 1; }
265 #endif // IMP_DOXYGEN
266 
267  /** Objects can have internal caches. This method resets them returning
268  the object to its just-initialized state.
269  */
270  virtual void clear_caches() {}
271 
272  protected:
273  /** Override this method to take action on destruction. */
274  virtual void do_destroy() {}
275 };
276 
277 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
278 inline void Object::set_check_level(CheckLevel l) {
279  IMP_CHECK_VARIABLE(l);
280 #if IMP_HAS_CHECKS != IMP_NONE
281  check_level_ = l;
282 #endif
283 }
284 
285 inline LogLevel Object::get_log_level() const {
286 #if IMP_HAS_LOG == IMP_SILENT
287  return SILENT;
288 #else
289  return log_level_;
290 #endif
291 }
292 inline CheckLevel Object::get_check_level() const {
293 #if IMP_HAS_CHECKS == IMP_NONE
294  return NONE;
295 #else
296  return check_level_;
297 #endif
298 }
299 
300 inline void Object::set_was_used(bool tf) const {
301  IMP_CHECK_VARIABLE(tf);
302 #if IMP_HAS_CHECKS >= IMP_USAGE
303  was_owned_ = tf;
304 #endif
305 }
306 
307 inline bool Object::get_is_valid() const {
308 #if IMP_HAS_CHECKS == IMP_NONE
309  return true;
310 #else
311  return static_cast<int>(check_value_) == 111111111;
312 #endif
313 }
314 #endif
315 
316 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
317 /** Send the whole show output to a stream*/
318 class ShowFull {
319  std::string showed_;
320 
321  public:
322  ShowFull(Object* o) {
323  std::ostringstream oss;
324  o->show(oss);
325  showed_ = oss.str();
326  }
327  const std::string& get_string() const { return showed_; }
328 };
329 inline std::ostream& operator<<(std::ostream& o, const ShowFull& sf) {
330  o << sf.get_string();
331  return o;
332 }
333 #endif
334 IMPKERNEL_END_NAMESPACE
335 
336 #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:270
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:274
Common base class for heavy weight IMP objects.
Definition: Object.h:111
Macros to control compiler warnings.
int compare(const VectorD< D > &a, const VectorD< D > &b)
lexicographic comparison of two vectors
Definition: VectorD.h:166
Helper macros for implementing hashable classes.
Various general useful macros for IMP.
Version and module information for Objects.
Definition: VersionInfo.h:29
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:206
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