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