IMP logo
IMP Reference Guide  2.15.0
The Integrative Modeling Platform
Key.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Key.h \brief Keys to cache lookup of attribute strings.
3  *
4  * Copyright 2007-2021 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_KEY_H
9 #define IMPKERNEL_KEY_H
10 
11 #include "utility.h"
12 #include "internal/key_helpers.h"
13 #include <IMP/check_macros.h>
14 #include <IMP/comparison_macros.h>
15 #include <IMP/hash_macros.h>
16 #include <IMP/log_macros.h>
17 #include <IMP/thread_macros.h>
18 #include <IMP/Value.h>
19 #include <vector>
20 
21 IMPKERNEL_BEGIN_NAMESPACE
22 
23 //! A base class for Keys
24 /** This class does internal caching of the strings to accelerate the
25  name lookup. It is better to create a Key and reuse it
26  rather than recreate it many times from strings.
27 
28  If you use this with a new type, you must add a new definition of
29  attribute_table_index. Yes, this is an evil hack, but I couldn't
30  get linking to work with static members of the template class.
31 
32  The keys in \imp maintain a cached mapping between strings and indexes.
33  This mapping is global--that is all \imp Models and Particles in the
34  same program use the same mapping for each type of key. The type of
35  the key is determined by an integer which should be unique for
36  each type. If the integer is not unique, everything works, just
37  more memory is wasted and types are interconvertible.
38 
39  Keys used for storing attributes in particles should never be statically
40  initialized. While this is annoying, statically initializing them is bad,
41  as unused attribute keys can result in wasted memory in each particle.
42  */
43 template <unsigned int ID>
44 class Key : public Value {
45  private:
46 
47  //! returns a static structure with mapping between
48  //! key int identifiers and strings
49  static internal::KeyData& get_key_data() {
50 #ifndef IMPKERNEL_INTERNAL_OLD_COMPILER
51  static internal::KeyData static_key_data_(ID);
52  return static_key_data_;
53 #else
54  return IMP::internal::get_key_data(ID);
55 #endif
56  }
57 
58  private:
59  int str_;
60  static const internal::KeyData::Map& get_map() {
61  return get_key_data().get_map();
62  }
63  static const internal::KeyData::RMap& get_rmap() {
64  IMP::internal::KeyData const& kd=get_key_data();
65  IMP::internal::KeyData::RMap const& ret=kd.get_rmap();
66  return ret;
67  }
68 
69  //! returns the index of sc, adds it if it's not there
70  static unsigned int find_or_add_index(std::string const& sc) {
71  IMP_USAGE_CHECK(!sc.empty(), "Can't create a key with an empty name");
72  unsigned int val;
73  IMP_OMP_PRAGMA(critical(imp_key)) {
74  if (get_map().find(sc) == get_map().end()) {
75  val = get_key_data().add_key(sc);
76  } else {
77  val = get_map().find(sc)->second;
78  }
79  }
80  return val;
81  }
82 
83 
84  static unsigned int find_index(std::string const& sc) {
85  IMP_USAGE_CHECK(!sc.empty(), "Can't create a key with an empty name");
86  unsigned int val;
87  IMP_OMP_PRAGMA(critical(imp_key)) {
88  IMP_USAGE_CHECK( get_key_exists(sc), "Key<" << ID << ">::find_index():"
89  << " You must explicitly create the type first: "
90  << sc);
91  val = get_map().find(sc)->second;
92  }
93  return val;
94  }
95 
96  private:
97  bool is_default() const;
98 
99  public:
100 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
101  static unsigned int get_ID() { return ID; }
102 
103  static const std::string get_string(int i) {
104  std::string val;
105  IMP_OMP_PRAGMA(critical(imp_key)) {
106  if (static_cast<unsigned int>(i) < get_rmap().size()) {
107  val = get_rmap()[i];
108  }
109  }
110  if (val.empty()) {
111  IMP_FAILURE("Corrupted Key Table asking for key "
112  << i << " with a table of size " << get_rmap().size());
113  }
114  return val;
115  }
116 
117 #endif
118  //! make a default key in a well-defined null state
119  Key() : str_(-1) {}
120 
121  //! Generate a key object from the given string
122  /**
123  Generate a key object from the given string.
124 
125  @param c key string representation
126  @param is_implicit_add_permitted If true, a key for c can be created even if it hasn't
127  been created earlier. If false, than it is assumed that a key for c
128  has already been instantiated by e.g., a previous
129  call to Key(c, true) or using Key::add_key().
130  Formally, it is assumed that get_has_key(c) is true.
131 
132  @note This operation can be expensive, so please cache the result.
133  */
134  explicit Key(std::string const& c, bool is_implicit_add_permitted=true)
135  : str_(is_implicit_add_permitted ? find_or_add_index(c) : find_index(c))
136  {}
137 
138 #if !defined(IMP_DOXYGEN)
139  //! this is a fast and lean constructor that should be used
140  //! whenever performence is of the essence
141  explicit Key(unsigned int i) : str_(i) {
142  IMP_INTERNAL_CHECK(str_ >= 0, "Invalid initializer " << i);
143  // cannot check here as we need a past end iterator
144  }
145 #endif
146 
147  static unsigned int add_key(std::string sc) {
148  IMP_USAGE_CHECK(!sc.empty(), "Can't create a key with an empty name");
149  unsigned int val;
150  IMP_OMP_PRAGMA(critical(imp_key))
151  IMP_LOG_PROGRESS("Key::add_key " << sc << " ID " << ID << std::endl);
152  val = get_key_data().add_key(sc);
153  return val;
154  }
155 
156  //! Return true if there already is a key with that string
157  static bool get_key_exists(std::string sc) {
158  bool val;
159  IMP_OMP_PRAGMA(critical(imp_key))
160  val = get_map().find(sc) != get_map().end();
161  return val;
162  }
163 
164  //! Turn a key into a pretty string
165  const std::string get_string() const {
166  if (is_default()) return std::string("nullptr");
167  std::string val;
168  val = get_string(str_);
169  return val;
170  }
171 
172  IMP_COMPARISONS_1(Key, str_);
173 
174  IMP_HASHABLE_INLINE(Key, return str_;)
175 
176  IMP_SHOWABLE_INLINE(Key, out << "\"" << get_string() << "\"";);
177 
178  //! Make new_name an alias for old_key
179  /** Afterwards
180  \code
181  Key<ID>(old_key.get_string()) == Key<ID>(new_name)
182  \endcode
183  */
184  static Key<ID> add_alias(Key<ID> old_key,
185  std::string new_name) {
186  IMP_INTERNAL_CHECK( get_map().find(new_name) == get_map().end(),
187  "The name is already taken with an existing key or alias");
188  get_key_data().add_alias(new_name, old_key.get_index());
189  return Key<ID>(new_name.c_str());
190  }
191 
192  static unsigned int get_number_of_keys() {
193  return get_rmap().size();
194  }
195 
196 #ifndef DOXYGEN
197  unsigned int get_index() const {
198  IMP_INTERNAL_CHECK(!is_default(),
199  "Cannot get index on defaultly constructed Key");
200  return str_;
201  }
202 #endif
203 
204  //! Show all the keys of this type
205  static void show_all(std::ostream& out);
206 
207  //! Get a list of all of the keys of this type
208  /**
209  This can be used to check for typos and similar keys.
210  */
211  static Vector<std::string> get_all_strings();
212 
213  //! Get the total number of keys of this type
214  /**
215  This is mostly for debugging to make sure that there are no extra
216  keys created.
217  */
218  static unsigned int get_number_unique() { return get_rmap().size(); }
219 
220 #ifndef SWIG
221  /** \todo These should be protected, I'll try to work how
222  */
224  ++str_;
225  return *this;
226  }
227  Key& operator--() {
228  --str_;
229  return *this;
230  }
231  Key operator+(int o) const {
232  Key c = *this;
233  c.str_ += o;
234  return c;
235  }
236 #endif
237 };
238 
239 #ifndef IMP_DOXYGEN
240 
241 
242 template <unsigned int ID>
243 inline std::ostream& operator<<(std::ostream& out, Key<ID> k) {
244  k.show(out);
245  return out;
246 }
247 
248 template <unsigned int ID>
249 inline bool Key<ID>::is_default() const {
250  return str_ == -1;
251 }
252 
253 template <unsigned int ID>
254  inline void Key<ID>::show_all(std::ostream& out) {
255  IMP_OMP_PRAGMA(critical(imp_key))
256  get_key_data().show(out);
257 }
258 
259 template <unsigned int ID>
260 Vector<std::string> Key<ID>::get_all_strings() {
261  Vector<std::string> str;
262  IMP_OMP_PRAGMA(critical(imp_key))
263  for (internal::KeyData::Map::const_iterator it = get_map().begin();
264  it != get_map().end(); ++it) {
265  str.push_back(it->first);
266  }
267  return str;
268 }
269 #endif
270 
271 IMPKERNEL_END_NAMESPACE
272 
273 #endif /* IMPKERNEL_KEY_H */
274 
Key & operator++()
Definition: Key.h:223
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
Helper macros for implementing comparisons of IMP objects.
#define IMP_FAILURE(message)
A runtime failure for IMP.
Definition: check_macros.h:72
#define IMP_HASHABLE_INLINE(name, hashret)
Definition: hash_macros.h:18
Key()
make a default key in a well-defined null state
Definition: Key.h:119
#define IMP_LOG_PROGRESS(expr)
Definition: log_macros.h:94
const std::string get_string() const
Turn a key into a pretty string.
Definition: Key.h:165
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
Definition: check_macros.h:139
Base class for a simple primitive-like type.
Definition: Value.h:23
static unsigned int get_number_unique()
Get the total number of keys of this type.
Definition: Key.h:218
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
Helper macros for implementing hashable classes.
Logging and error reporting support.
A base class for Keys.
Definition: Key.h:44
For backwards compatibility.
std::ostream & show(Hierarchy h, std::ostream &out=std::cout)
Print the hierarchy using a given decorator to display each node.
Helper macros for throwing and handling exceptions.
Base class for a simple primitive-like type.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
static Key< ID > add_alias(Key< ID > old_key, std::string new_name)
Make new_name an alias for old_key.
Definition: Key.h:184
#define IMP_COMPARISONS_1(Name, field)
Implement comparison in a class using field as the variable to compare.
Key(std::string const &c, bool is_implicit_add_permitted=true)
Generate a key object from the given string.
Definition: Key.h:134
Control for OpenMP.
#define IMP_OMP_PRAGMA(x)
Definition: thread_macros.h:35