RDKit
Open-source cheminformatics and machine learning.
Dict.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2003-2021 Greg Landrum and other RDKit contributors
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() {}
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(Dict &&other) noexcept = default;
64 
65  ~Dict() {
66  reset(); // to clear pointers if necessary
67  }
68 
69  void update(const Dict &other, bool preserveExisting = false) {
70  if (!preserveExisting) {
71  *this = other;
72  } else {
73  if (other._hasNonPodData) {
74  _hasNonPodData = true;
75  }
76  for (size_t i = 0; i < other._data.size(); ++i) {
77  const Pair &pair = other._data[i];
78  Pair *target = nullptr;
79  for (size_t i = 0; i < _data.size(); ++i) {
80  if (_data[i].key == pair.key) {
81  target = &_data[i];
82  break;
83  }
84  }
85 
86  if (!target) {
87  // need to create blank entry and copy
88  _data.push_back(Pair(pair.key));
89  copy_rdvalue(_data.back().val, pair.val);
90  } else {
91  // just copy
92  copy_rdvalue(target->val, pair.val);
93  }
94  }
95  }
96  }
97 
98  Dict &operator=(const Dict &other) {
99  if (this == &other) {
100  return *this;
101  }
102  if (_hasNonPodData) {
103  reset();
104  }
105 
106  if (other._hasNonPodData) {
107  std::vector<Pair> data(other._data.size());
108  _data.swap(data);
109  for (size_t i = 0; i < _data.size(); ++i) {
110  _data[i].key = other._data[i].key;
111  copy_rdvalue(_data[i].val, other._data[i].val);
112  }
113  } else {
114  _data = other._data;
115  }
116  _hasNonPodData = other._hasNonPodData;
117  return *this;
118  }
119 
120  Dict &operator=(Dict &&other) noexcept {
121  if (this == &other) {
122  return *this;
123  }
124  if (_hasNonPodData) {
125  reset();
126  }
127  _hasNonPodData = other._hasNonPodData;
128  other._hasNonPodData = false;
129  _data = std::move(other._data);
130  return *this;
131  }
132 
133  //----------------------------------------------------------
134  //! \brief Access to the underlying non-POD containment flag
135  //! This is meant to be used only in bulk updates of _data.
136  bool &getNonPODStatus() { return _hasNonPodData; }
137 
138  //----------------------------------------------------------
139  //! \brief Access to the underlying data.
140  const DataType &getData() const { return _data; }
141  DataType &getData() { return _data; }
142 
143  //----------------------------------------------------------
144 
145  //! \brief Returns whether or not the dictionary contains a particular
146  //! key.
147  bool hasVal(const std::string &what) const {
148  for (const auto &data : _data) {
149  if (data.key == what) {
150  return true;
151  }
152  }
153  return false;
154  }
155 
156  //----------------------------------------------------------
157  //! Returns the set of keys in the dictionary
158  /*!
159  \return a \c STR_VECT
160  */
161  STR_VECT keys() const {
162  STR_VECT res;
163  res.reserve(_data.size());
164  for (const auto &item : _data) {
165  res.push_back(item.key);
166  }
167  return res;
168  }
169 
170  //----------------------------------------------------------
171  //! \brief Gets the value associated with a particular key
172  /*!
173  \param what the key to lookup
174  \param res a reference used to return the result
175 
176  <B>Notes:</b>
177  - If \c res is a \c std::string, every effort will be made
178  to convert the specified element to a string using the
179  \c boost::lexical_cast machinery.
180  - If the dictionary does not contain the key \c what,
181  a KeyErrorException will be thrown.
182  */
183  template <typename T>
184  void getVal(const std::string &what, T &res) const {
185  res = getVal<T>(what);
186  }
187 
188  //! \overload
189  template <typename T>
190  T getVal(const std::string &what) const {
191  for (auto &data : _data) {
192  if (data.key == what) {
193  return from_rdvalue<T>(data.val);
194  }
195  }
196  throw KeyErrorException(what);
197  }
198 
199  //! \overload
200  void getVal(const std::string &what, std::string &res) const {
201  for (const auto &i : _data) {
202  if (i.key == what) {
203  rdvalue_tostring(i.val, res);
204  return;
205  }
206  }
207  throw KeyErrorException(what);
208  }
209 
210  //----------------------------------------------------------
211  //! \brief Potentially gets the value associated with a particular key
212  //! returns true on success/false on failure.
213  /*!
214  \param what the key to lookup
215  \param res a reference used to return the result
216 
217  <B>Notes:</b>
218  - If \c res is a \c std::string, every effort will be made
219  to convert the specified element to a string using the
220  \c boost::lexical_cast machinery.
221  - If the dictionary does not contain the key \c what,
222  a KeyErrorException will be thrown.
223  */
224  template <typename T>
225  bool getValIfPresent(const std::string &what, T &res) const {
226  for (const auto &data : _data) {
227  if (data.key == what) {
228  res = from_rdvalue<T>(data.val);
229  return true;
230  }
231  }
232  return false;
233  }
234 
235  //! \overload
236  bool getValIfPresent(const std::string &what, std::string &res) const {
237  for (const auto &i : _data) {
238  if (i.key == what) {
239  rdvalue_tostring(i.val, res);
240  return true;
241  }
242  }
243  return false;
244  }
245 
246  //----------------------------------------------------------
247  //! \brief Sets the value associated with a key
248  /*!
249 
250  \param what the key to set
251  \param val the value to store
252 
253  <b>Notes:</b>
254  - If \c val is a <tt>const char *</tt>, it will be converted
255  to a \c std::string for storage.
256  - If the dictionary already contains the key \c what,
257  the value will be replaced.
258  */
259  template <typename T>
260  void setVal(const std::string &what, T &val) {
261  static_assert(!std::is_same_v<T, std::string_view>,
262  "T cannot be string_view");
263  _hasNonPodData = true;
264  for (auto &&data : _data) {
265  if (data.key == what) {
266  RDValue::cleanup_rdvalue(data.val);
267  data.val = val;
268  return;
269  }
270  }
271  _data.push_back(Pair(what, val));
272  }
273 
274  template <typename T>
275  void setPODVal(const std::string &what, T val) {
276  static_assert(!std::is_same_v<T, std::string_view>,
277  "T cannot be string_view");
278  // don't change the hasNonPodData status
279  for (auto &&data : _data) {
280  if (data.key == what) {
281  RDValue::cleanup_rdvalue(data.val);
282  data.val = val;
283  return;
284  }
285  }
286  _data.push_back(Pair(what, val));
287  }
288 
289  void setVal(const std::string &what, bool val) { setPODVal(what, val); }
290 
291  void setVal(const std::string &what, double val) { setPODVal(what, val); }
292 
293  void setVal(const std::string &what, float val) { setPODVal(what, val); }
294 
295  void setVal(const std::string &what, int val) { setPODVal(what, val); }
296 
297  void setVal(const std::string &what, unsigned int val) {
298  setPODVal(what, val);
299  }
300 
301  //! \overload
302  void setVal(const std::string &what, const char *val) {
303  std::string h(val);
304  setVal(what, h);
305  }
306 
307  //----------------------------------------------------------
308  //! \brief Clears the value associated with a particular key,
309  //! removing the key from the dictionary.
310  /*!
311 
312  \param what the key to clear
313 
314  */
315  void clearVal(const std::string &what) {
316  for (DataType::iterator it = _data.begin(); it < _data.end(); ++it) {
317  if (it->key == what) {
318  if (_hasNonPodData) {
319  RDValue::cleanup_rdvalue(it->val);
320  }
321  _data.erase(it);
322  return;
323  }
324  }
325  }
326 
327  //----------------------------------------------------------
328  //! \brief Clears all keys (and values) from the dictionary.
329  //!
330  void reset() {
331  if (_hasNonPodData) {
332  for (auto &&data : _data) {
333  RDValue::cleanup_rdvalue(data.val);
334  }
335  }
336  DataType data;
337  _data.swap(data);
338  }
339 
340  private:
341  DataType _data{}; //!< the actual dictionary
342  bool _hasNonPodData{false}; // if true, need a deep copy
343  // (copy_rdvalue)
344 };
345 
346 template <>
347 inline std::string Dict::getVal<std::string>(const std::string &what) const {
348  std::string res;
349  getVal(what, res);
350  return res;
351 }
352 
353 } // namespace RDKit
354 #endif
Class to allow us to throw a KeyError from C++ and have it make it back to Python.
Definition: Exceptions.h:56
The Dict class can be used to store objects of arbitrary type keyed by strings.
Definition: Dict.h:36
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:302
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:190
Dict(Dict &&other) noexcept=default
void reset()
Clears all keys (and values) from the dictionary.
Definition: Dict.h:330
void setPODVal(const std::string &what, T val)
Definition: Dict.h:275
STR_VECT keys() const
Returns the set of keys in the dictionary.
Definition: Dict.h:161
void setVal(const std::string &what, float val)
Definition: Dict.h:293
void setVal(const std::string &what, double val)
Definition: Dict.h:291
bool hasVal(const std::string &what) const
Returns whether or not the dictionary contains a particular key.
Definition: Dict.h:147
void setVal(const std::string &what, bool val)
Definition: Dict.h:289
Dict & operator=(Dict &&other) noexcept
Definition: Dict.h:120
void setVal(const std::string &what, unsigned int val)
Definition: Dict.h:297
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:200
~Dict()
Definition: Dict.h:65
Dict & operator=(const Dict &other)
Definition: Dict.h:98
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:136
std::vector< Pair > DataType
Definition: Dict.h:47
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:225
void update(const Dict &other, bool preserveExisting=false)
Definition: Dict.h:69
void getVal(const std::string &what, T &res) const
Gets the value associated with a particular key.
Definition: Dict.h:184
const DataType & getData() const
Access to the underlying data.
Definition: Dict.h:140
DataType & getData()
Definition: Dict.h:141
Dict()
Definition: Dict.h:49
Dict(const Dict &other)
Definition: Dict.h:51
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:236
void setVal(const std::string &what, int val)
Definition: Dict.h:295
void clearVal(const std::string &what)
Clears the value associated with a particular key, removing the key from the dictionary.
Definition: Dict.h:315
void setVal(const std::string &what, T &val)
Sets the value associated with a key.
Definition: Dict.h:260
#define RDKIT_RDGENERAL_EXPORT
Definition: export.h:369
Std stuff.
Definition: Abbreviations.h:19
std::vector< std::string > STR_VECT
Definition: Dict.h:29
bool rdvalue_tostring(RDValue_cast_t val, std::string &res)
Definition: RDValue.h:187
void copy_rdvalue(RDValue &dest, const RDValue &src)
Pair(std::string s)
Definition: Dict.h:43
std::string key
Definition: Dict.h:39
Pair(std::string s, const RDValue &v)
Definition: Dict.h:44
RDValue val
Definition: Dict.h:40
static void cleanup_rdvalue(RDValue v)