RDKit
Open-source cheminformatics and machine learning.
Dict.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2003-2020 Greg Landrum and Rational Discovery LLC
3 //
4 // @@ All Rights Reserved @@
5 // This file is part of the RDKit.
6 // The contents are covered by the terms of the BSD license
7 // which is included in the file license.txt, found at the root
8 // of the RDKit source tree.
9 //
10 /*! \file Dict.h
11 
12  \brief Defines the Dict class
13 
14 */
15 #include <RDGeneral/export.h>
16 #ifndef RD_DICT_H_012020
17 #define RD_DICT_H_012020
18 
19 #include <map>
20 #include <string>
21 #include <vector>
22 #include "RDValue.h"
23 #include "Exceptions.h"
25 #include <boost/lexical_cast.hpp>
27 
28 namespace RDKit {
29 typedef std::vector<std::string> STR_VECT;
30 
31 //! \brief The \c Dict class can be used to store objects of arbitrary
32 //! type keyed by \c strings.
33 //!
34 //! The actual storage is done using \c RDValue objects.
35 //!
37  public:
38  struct Pair {
39  std::string key;
41 
42  Pair() : key(), val() {}
43  explicit Pair(std::string s) : key(std::move(s)), val() {}
44  Pair(std::string s, const RDValue &v) : key(std::move(s)), val(v) {}
45  };
46 
47  typedef std::vector<Pair> DataType;
48 
49  Dict() : _data(), _hasNonPodData(false) {}
50 
51  Dict(const Dict &other) : _data(other._data) {
52  _hasNonPodData = other._hasNonPodData;
53  if (other._hasNonPodData) { // other has non pod data, need to copy
54  std::vector<Pair> data(other._data.size());
55  _data.swap(data);
56  for (size_t i = 0; i < _data.size(); ++i) {
57  _data[i].key = other._data[i].key;
58  copy_rdvalue(_data[i].val, other._data[i].val);
59  }
60  }
61  }
62 
63  ~Dict() {
64  reset(); // to clear pointers if necessary
65  }
66 
67  void update(const Dict &other, bool preserveExisting = false) {
68  if (!preserveExisting) {
69  *this = other;
70  } else {
71  if (other._hasNonPodData) _hasNonPodData = true;
72  for (size_t i = 0; i < other._data.size(); ++i) {
73  const Pair &pair = other._data[i];
74  Pair *target = 0;
75  for (size_t i = 0; i < _data.size(); ++i) {
76  if (_data[i].key == pair.key) {
77  target = &_data[i];
78  break;
79  }
80  }
81 
82  if (!target) {
83  // need to create blank entry and copy
84  _data.push_back(Pair(pair.key));
85  copy_rdvalue(_data.back().val, pair.val);
86  } else {
87  // just copy
88  copy_rdvalue(target->val, pair.val);
89  }
90  }
91  }
92  }
93 
94  Dict &operator=(const Dict &other) {
95  if (this == &other) return *this;
96  if (_hasNonPodData) reset();
97 
98  if (other._hasNonPodData) {
99  std::vector<Pair> data(other._data.size());
100  _data.swap(data);
101  for (size_t i = 0; i < _data.size(); ++i) {
102  _data[i].key = other._data[i].key;
103  copy_rdvalue(_data[i].val, other._data[i].val);
104  }
105  } else {
106  _data = other._data;
107  }
108  _hasNonPodData = other._hasNonPodData;
109  return *this;
110  }
111 
112  //----------------------------------------------------------
113  //! \brief Access to the underlying non-POD containment flag
114  //! This is meant to be used only in bulk updates of _data.
115  bool &getNonPODStatus() { return _hasNonPodData; }
116 
117  //----------------------------------------------------------
118  //! \brief Access to the underlying data.
119  const DataType &getData() const { return _data; }
120  DataType &getData() { return _data; }
121 
122  //----------------------------------------------------------
123 
124  //! \brief Returns whether or not the dictionary contains a particular
125  //! key.
126  bool hasVal(const std::string &what) const {
127  for (const auto &data : _data) {
128  if (data.key == what) return true;
129  }
130  return false;
131  }
132 
133  //----------------------------------------------------------
134  //! Returns the set of keys in the dictionary
135  /*!
136  \return a \c STR_VECT
137  */
138  STR_VECT keys() const {
139  STR_VECT res;
140  res.reserve(_data.size());
141  for (const auto &item : _data) {
142  res.push_back(item.key);
143  }
144  return res;
145  }
146 
147  //----------------------------------------------------------
148  //! \brief Gets the value associated with a particular key
149  /*!
150  \param what the key to lookup
151  \param res a reference used to return the result
152 
153  <B>Notes:</b>
154  - If \c res is a \c std::string, every effort will be made
155  to convert the specified element to a string using the
156  \c boost::lexical_cast machinery.
157  - If the dictionary does not contain the key \c what,
158  a KeyErrorException will be thrown.
159  */
160  template <typename T>
161  void getVal(const std::string &what, T &res) const {
162  res = getVal<T>(what);
163  }
164 
165  //! \overload
166  template <typename T>
167  T getVal(const std::string &what) const {
168  for (auto &data : _data) {
169  if (data.key == what) {
170  return from_rdvalue<T>(data.val);
171  }
172  }
173  throw KeyErrorException(what);
174  }
175 
176  //! \overload
177  void getVal(const std::string &what, std::string &res) const {
178  for (const auto &i : _data) {
179  if (i.key == what) {
180  rdvalue_tostring(i.val, res);
181  return;
182  }
183  }
184  throw KeyErrorException(what);
185  }
186 
187  //----------------------------------------------------------
188  //! \brief Potentially gets the value associated with a particular key
189  //! returns true on success/false on failure.
190  /*!
191  \param what the key to lookup
192  \param res a reference used to return the result
193 
194  <B>Notes:</b>
195  - If \c res is a \c std::string, every effort will be made
196  to convert the specified element to a string using the
197  \c boost::lexical_cast machinery.
198  - If the dictionary does not contain the key \c what,
199  a KeyErrorException will be thrown.
200  */
201  template <typename T>
202  bool getValIfPresent(const std::string &what, T &res) const {
203  for (const auto &data : _data) {
204  if (data.key == what) {
205  res = from_rdvalue<T>(data.val);
206  return true;
207  }
208  }
209  return false;
210  }
211 
212  //! \overload
213  bool getValIfPresent(const std::string &what, std::string &res) const {
214  for (const auto &i : _data) {
215  if (i.key == what) {
216  rdvalue_tostring(i.val, res);
217  return true;
218  }
219  }
220  return false;
221  }
222 
223  //----------------------------------------------------------
224  //! \brief Sets the value associated with a key
225  /*!
226 
227  \param what the key to set
228  \param val the value to store
229 
230  <b>Notes:</b>
231  - If \c val is a <tt>const char *</tt>, it will be converted
232  to a \c std::string for storage.
233  - If the dictionary already contains the key \c what,
234  the value will be replaced.
235  */
236  template <typename T>
237  void setVal(const std::string &what, T &val) {
238  _hasNonPodData = true;
239  for (auto &&data : _data) {
240  if (data.key == what) {
241  RDValue::cleanup_rdvalue(data.val);
242  data.val = val;
243  return;
244  }
245  }
246  _data.push_back(Pair(what, val));
247  }
248 
249  template <typename T>
250  void setPODVal(const std::string &what, T val) {
251  // don't change the hasNonPodData status
252  for (auto &&data : _data) {
253  if (data.key == what) {
254  RDValue::cleanup_rdvalue(data.val);
255  data.val = val;
256  return;
257  }
258  }
259  _data.push_back(Pair(what, val));
260  }
261 
262  void setVal(const std::string &what, bool val) { setPODVal(what, val); }
263 
264  void setVal(const std::string &what, double val) { setPODVal(what, val); }
265 
266  void setVal(const std::string &what, float val) { setPODVal(what, val); }
267 
268  void setVal(const std::string &what, int val) { setPODVal(what, val); }
269 
270  void setVal(const std::string &what, unsigned int val) {
271  setPODVal(what, val);
272  }
273 
274  //! \overload
275  void setVal(const std::string &what, const char *val) {
276  std::string h(val);
277  setVal(what, h);
278  }
279 
280  //----------------------------------------------------------
281  //! \brief Clears the value associated with a particular key,
282  //! removing the key from the dictionary.
283  /*!
284 
285  \param what the key to clear
286 
287  */
288  void clearVal(const std::string &what) {
289  for (DataType::iterator it = _data.begin(); it < _data.end(); ++it) {
290  if (it->key == what) {
291  if (_hasNonPodData) {
292  RDValue::cleanup_rdvalue(it->val);
293  }
294  _data.erase(it);
295  return;
296  }
297  }
298  }
299 
300  //----------------------------------------------------------
301  //! \brief Clears all keys (and values) from the dictionary.
302  //!
303  void reset() {
304  if (_hasNonPodData) {
305  for (auto &&data : _data) {
306  RDValue::cleanup_rdvalue(data.val);
307  }
308  }
309  DataType data;
310  _data.swap(data);
311  }
312 
313  private:
314  DataType _data; //!< the actual dictionary
315  bool _hasNonPodData; // if true, need a deep copy
316  // (copy_rdvalue)
317 };
318 
319 template <>
320 inline std::string Dict::getVal<std::string>(const std::string &what) const {
321  std::string res;
322  getVal(what, res);
323  return res;
324 }
325 
326 } // namespace RDKit
327 #endif
RDKit::Dict::setVal
void setVal(const std::string &what, bool val)
Definition: Dict.h:262
RDKit::Dict
The Dict class can be used to store objects of arbitrary type keyed by strings.
Definition: Dict.h:36
RDKit::Dict::update
void update(const Dict &other, bool preserveExisting=false)
Definition: Dict.h:67
RDKit::Dict::setVal
void setVal(const std::string &what, unsigned int val)
Definition: Dict.h:270
RDKit::Dict::Pair::key
std::string key
Definition: Dict.h:39
RDKit::Dict::setVal
void setVal(const std::string &what, double val)
Definition: Dict.h:264
RDKit::Dict::DataType
std::vector< Pair > DataType
Definition: Dict.h:47
RDKit::Dict::setVal
void setVal(const std::string &what, const char *val)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: Dict.h:275
BoostStartInclude.h
RDKit::Dict::Dict
Dict(const Dict &other)
Definition: Dict.h:51
RDKit::RDValue
Definition: RDValue-doublemagic.h:167
RDKit::Dict::setVal
void setVal(const std::string &what, float val)
Definition: Dict.h:266
RDKit::Dict::~Dict
~Dict()
Definition: Dict.h:63
KeyErrorException
Class to allow us to throw a KeyError from C++ and have it make it back to Python.
Definition: Exceptions.h:57
RDKit::Dict::getNonPODStatus
bool & getNonPODStatus()
Access to the underlying non-POD containment flag This is meant to be used only in bulk updates of _d...
Definition: Dict.h:115
RDKit::Dict::hasVal
bool hasVal(const std::string &what) const
Returns whether or not the dictionary contains a particular key.
Definition: Dict.h:126
RDKit::STR_VECT
std::vector< std::string > STR_VECT
Definition: Dict.h:29
RDKit::RDValue::cleanup_rdvalue
static void cleanup_rdvalue(RDValue v)
Definition: RDValue-doublemagic.h:331
RDKit::Dict::getValIfPresent
bool getValIfPresent(const std::string &what, T &res) const
Potentially gets the value associated with a particular key returns true on success/false on failure.
Definition: Dict.h:202
BoostEndInclude.h
RDKit::Dict::Pair::val
RDValue val
Definition: Dict.h:40
RDKit::Dict::getVal
void getVal(const std::string &what, std::string &res) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: Dict.h:177
RDKit::Dict::setVal
void setVal(const std::string &what, T &val)
Sets the value associated with a key.
Definition: Dict.h:237
RDKit::Dict::getVal
void getVal(const std::string &what, T &res) const
Gets the value associated with a particular key.
Definition: Dict.h:161
RDKit::Dict::Pair::Pair
Pair()
Definition: Dict.h:42
RDKit::Dict::clearVal
void clearVal(const std::string &what)
Clears the value associated with a particular key, removing the key from the dictionary.
Definition: Dict.h:288
RDKit::Dict::reset
void reset()
Clears all keys (and values) from the dictionary.
Definition: Dict.h:303
RDKit::Dict::setPODVal
void setPODVal(const std::string &what, T val)
Definition: Dict.h:250
RDKit::Dict::Pair::Pair
Pair(std::string s, const RDValue &v)
Definition: Dict.h:44
RDKit::Dict::keys
STR_VECT keys() const
Returns the set of keys in the dictionary.
Definition: Dict.h:138
RDKit::Dict::Dict
Dict()
Definition: Dict.h:49
RDKit::Dict::operator=
Dict & operator=(const Dict &other)
Definition: Dict.h:94
RDKit::Dict::Pair::Pair
Pair(std::string s)
Definition: Dict.h:43
RDKit
Std stuff.
Definition: Atom.h:30
RDKit::rdvalue_tostring
bool rdvalue_tostring(RDValue_cast_t val, std::string &res)
Definition: RDValue.h:171
RDKit::Dict::getVal
T getVal(const std::string &what) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: Dict.h:167
RDKit::Dict::getValIfPresent
bool getValIfPresent(const std::string &what, std::string &res) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: Dict.h:213
RDValue.h
RDKit::Dict::Pair
Definition: Dict.h:38
RDKIT_RDGENERAL_EXPORT
#define RDKIT_RDGENERAL_EXPORT
Definition: export.h:502
RDKit::Dict::getData
const DataType & getData() const
Access to the underlying data.
Definition: Dict.h:119
RDKit::Dict::getData
DataType & getData()
Definition: Dict.h:120
RDKit::copy_rdvalue
void copy_rdvalue(RDValue &dest, const RDValue &src)
Definition: RDValue-doublemagic.h:339
RDKit::Dict::setVal
void setVal(const std::string &what, int val)
Definition: Dict.h:268
Exceptions.h
export.h