IMP  2.2.0
The Integrative Modeling Platform
kernel/Key.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kernel/Key.h \brief Keys to cache lookup of attribute strings.
3  *
4  * Copyright 2007-2014 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/base/check_macros.h>
15 #include <IMP/base/hash_macros.h>
16 #include <IMP/base/thread_macros.h>
17 #include <IMP/base/Value.h>
18 #include <vector>
19 
20 IMPKERNEL_BEGIN_NAMESPACE
21 
22 //! A base class for Keys
23 /** This class does internal caching of the strings to accelerate the
24  name lookup. It is better to create a Key and reuse it
25  rather than recreate it many times from strings.
26 
27  If you use this with a new type, you must add a new definition of
28  attribute_table_index. Yes, this is an evil hack, but I couldn't
29  get linking to work with static members of the template class.
30 
31  The keys in \imp maintain a cached mapping between strings and indexes.
32  This mapping is global--that is all \imp Models and Particles in the
33  same program use the same mapping for each type of key. The type of
34  the key is determined by an integer which should be unique for
35  each type. If the integer is not unique, everything works, just
36  more memory is wasted and types are interconvertible.
37 
38  Keys used for storing attributes in particles should never be statically
39  initialized. While this is annoying, statically initializing them is bad,
40  as unused attribute keys can result in wasted memory in each particle.
41 
42  If LazyAdd is true, keys created with a new string will be added,
43  otherwise this is an error.
44  */
45 template <unsigned int ID, bool LazyAdd>
46 class Key : public base::Value {
47  int str_;
48 
49  static const internal::KeyData::Map& get_map() {
50  return IMP::kernel::internal::get_key_data(ID).get_map();
51  }
52  static const internal::KeyData::RMap& get_rmap() {
53  return IMP::kernel::internal::get_key_data(ID).get_rmap();
54  }
55 
56  static unsigned int find_index(std::string sc) {
57  IMP_USAGE_CHECK(!sc.empty(), "Can't create a key with an empty name");
58  unsigned int val;
59  IMP_OMP_PRAGMA(critical(imp_key)) {
60  if (get_map().find(sc) == get_map().end()) {
61  IMP_INTERNAL_CHECK(LazyAdd, "You must explicitly create the type"
62  << " first: " << sc);
63  val = IMP::kernel::internal::get_key_data(ID).add_key(sc);
64  } else {
65  val = get_map().find(sc)->second;
66  }
67  }
68  return val;
69  }
70 
71  private:
72  bool is_default() const;
73 
74  public:
75 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
76  static unsigned int get_ID() { return ID; }
77 
78  static const std::string get_string(int i) {
79  std::string val;
80  IMP_OMP_PRAGMA(critical(imp_key)) {
81  if (static_cast<unsigned int>(i) < get_rmap().size()) {
82  val = get_rmap()[i];
83  }
84  }
85  if (val.empty()) {
86  IMP_FAILURE("Corrupted Key Table asking for key "
87  << i << " with a table of size " << get_rmap().size());
88  }
89  return val;
90  }
91 
92 #endif
93  //! make a default key in a well-defined null state
94  Key() : str_(-1) {}
95 
96  //! Generate a key from the given string
97  /** This operation can be expensive, so please cache the result.*/
98  explicit Key(std::string c) : str_(find_index(c)) {}
99 
100 #if !defined(IMP_DOXYGEN)
101  explicit Key(unsigned int i) : str_(i) {
102  IMP_INTERNAL_CHECK(str_ >= 0, "Invalid initializer " << i);
103  // cannot check here as we need a past end iterator
104  }
105 #endif
106 
107  static unsigned int add_key(std::string sc) {
108  IMP_USAGE_CHECK(!sc.empty(), "Can't create a key with an empty name");
109  unsigned int val;
110  IMP_OMP_PRAGMA(critical(imp_key))
111  val = IMP::kernel::internal::get_key_data(ID).add_key(sc);
112  return val;
113  }
114 
115  //! Return true if there already is a key with that string
116  static bool get_key_exists(std::string sc) {
117  bool val;
118  IMP_OMP_PRAGMA(critical(imp_key))
119  val = get_map().find(sc) != get_map().end();
120  return val;
121  }
122 
123  //! Turn a key into a pretty string
124  const std::string get_string() const {
125  if (is_default()) return std::string("nullptr");
126  std::string val;
127  val = get_string(str_);
128  return val;
129  }
130 
131  IMP_COMPARISONS_1(Key, str_);
132 
133  IMP_HASHABLE_INLINE(Key, return str_;)
134 
135  IMP_SHOWABLE_INLINE(Key, out << "\"" << get_string() << "\"";);
136 
137  //! Make new_name an alias for old_key
138  /** Afterwards
139  \code
140  Key<ID>(old_key.get_string()) == Key<ID>(new_name)
141  \endcode
142  */
144  std::string new_name) {
146  get_map().find(new_name) == get_map().end(),
147  "The name is already taken with an existing key or alias");
148  IMP::kernel::internal::get_key_data(ID)
149  .add_alias(new_name, old_key.get_index());
150  return Key<ID, LazyAdd>(new_name.c_str());
151  }
152 
153 #ifndef DOXYGEN
154  unsigned int get_index() const {
155  IMP_INTERNAL_CHECK(!is_default(),
156  "Cannot get index on defaultly constructed Key");
157  return str_;
158  }
159 #endif
160 
161  //! Show all the keys of this type
162  static void show_all(std::ostream& out);
163 
164  //! Get a list of all of the keys of this type
165  /**
166  This can be used to check for typos and similar keys.
167  */
168  static base::Vector<std::string> get_all_strings();
169 
170  //! Get the total number of keys of this type
171  /**
172  This is mostly for debugging to make sure that there are no extra
173  keys created.
174  */
175  static unsigned int get_number_unique() { return get_rmap().size(); }
176 
177 #ifndef SWIG
178  /** \todo These should be protected, I'll try to work how
179  */
181  ++str_;
182  return *this;
183  }
184  Key& operator--() {
185  --str_;
186  return *this;
187  }
188  Key operator+(int o) const {
189  Key c = *this;
190  c.str_ += o;
191  return c;
192  }
193 #endif
194 };
195 
196 #ifndef IMP_DOXYGEN
197 
198 template <unsigned int ID, bool LA>
199 inline std::ostream& operator<<(std::ostream& out, Key<ID, LA> k) {
200  k.show(out);
201  return out;
202 }
203 
204 template <unsigned int ID, bool LA>
205 inline bool Key<ID, LA>::is_default() const {
206  return str_ == -1;
207 }
208 
209 template <unsigned int ID, bool LA>
210 inline void Key<ID, LA>::show_all(std::ostream& out) {
211  IMP_OMP_PRAGMA(critical(imp_key))
212  internal::get_key_data(ID).show(out);
213 }
214 
215 template <unsigned int ID, bool LA>
216 base::Vector<std::string> Key<ID, LA>::get_all_strings() {
217  base::Vector<std::string> str;
218  IMP_OMP_PRAGMA(critical(imp_key))
219  for (internal::KeyData::Map::const_iterator it = get_map().begin();
220  it != get_map().end(); ++it) {
221  str.push_back(it->first);
222  }
223  return str;
224 }
225 #endif
226 
227 IMPKERNEL_END_NAMESPACE
228 
229 #endif /* IMPKERNEL_KEY_H */
Key & operator++()
Definition: kernel/Key.h:180
Key(std::string c)
Generate a key from the given string.
Definition: kernel/Key.h:98
A base class for Keys.
Definition: kernel/Key.h:46
Various general useful macros for IMP.
Ints get_index(const kernel::ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
static unsigned int get_number_unique()
Get the total number of keys of this type.
Definition: kernel/Key.h:175
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
Various general useful macros for IMP.
#define IMP_HASHABLE_INLINE(name, hashret)
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Basic types used by IMP.
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
#define IMP_OMP_PRAGMA(x)
#define IMP_COMPARISONS_1(Name, field)
Implement comparison in a class using field as the variable to compare.
Key()
make a default key in a well-defined null state
Definition: kernel/Key.h:94
void show(Hierarchy h, std::ostream &out=std::cout)
Print out a molecular hierarchy.
const std::string get_string() const
Turn a key into a pretty string.
Definition: kernel/Key.h:124
For backwards compatibility.
Exception definitions and assertions.
#define IMP_FAILURE(message)
A runtime failure for IMP.
static Key< ID, LazyAdd > add_alias(Key< ID, LazyAdd > old_key, std::string new_name)
Make new_name an alias for old_key.
Definition: kernel/Key.h:143
Control for OpenMP.