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
28namespace RDKit {
29typedef 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
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) {
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
346template <>
347inline 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
const DataType & getData() const
Access to the underlying data.
Definition: Dict.h:140
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
Dict & operator=(const Dict &other)
Definition: Dict.h:98
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
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
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
Dict & operator=(Dict &&other) noexcept
Definition: Dict.h:120
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
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)