Loading...
Searching...
No Matches
Dict.h
Go to the documentation of this file.
//
// Copyright (C) 2003-2026 Greg Landrum and other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
/*! \file Dict.h
\brief Defines the Dict class
*/
#include <RDGeneral/export.h>
#ifndef RD_DICT_H_012020
#define RD_DICT_H_012020
#include <string>
#include <string_view>
#include <vector>
#include "RDValue.h"
#include "Exceptions.h"
#include <RDGeneral/BoostStartInclude.h>
#include <boost/lexical_cast.hpp>
#include <RDGeneral/BoostEndInclude.h>
namespace RDKit {
typedef std::vector<std::string> STR_VECT;
//! \brief The \c Dict class can be used to store objects of arbitrary
//! type keyed by \c strings.
//!
//! The actual storage is done using \c RDValue objects.
//!
class RDKIT_RDGENERAL_EXPORT Dict {
public:
struct Pair {
std::string key;
RDValue val;
Pair() : key(), val() {}
explicit Pair(std::string s) : key(std::move(s)), val() {}
explicit Pair(std::string_view s) : key(std::string(s)), val() {}
Pair(std::string s, const RDValue &v) : key(std::move(s)), val(v) {}
Pair(std::string_view s, const RDValue &v) : key(std::string(s)), val(v) {}
// In the case you are holding onto an rdvalue outside of a dictionary
// or other container, you kust call cleanup to release non POD memory.
void cleanup() { RDValue::cleanup_rdvalue(val); }
};
typedef std::vector<Pair> DataType;
Dict() {}
Dict(const Dict &other) : _data(other._data) {
_hasNonPodData = other._hasNonPodData;
if (other._hasNonPodData) { // other has non pod data, need to copy
std::vector<Pair> data(other._data.size());
_data.swap(data);
for (size_t i = 0; i < _data.size(); ++i) {
_data[i].key = other._data[i].key;
copy_rdvalue(_data[i].val, other._data[i].val);
}
}
}
Dict(Dict &&other) noexcept = default;
~Dict() {
reset(); // to clear pointers if necessary
}
void update(const Dict &other, bool preserveExisting = false) {
if (!preserveExisting) {
*this = other;
} else {
if (other._hasNonPodData) {
_hasNonPodData = true;
}
for (const auto &opair : other._data) {
Pair *target = nullptr;
for (auto &dpair : _data) {
if (dpair.key == opair.key) {
target = &dpair;
break;
}
}
if (!target) {
// need to create blank entry and copy
_data.push_back(Pair(opair.key));
copy_rdvalue(_data.back().val, opair.val);
} else {
// just copy
copy_rdvalue(target->val, opair.val);
}
}
}
}
Dict &operator=(const Dict &other) {
if (this == &other) {
return *this;
}
if (_hasNonPodData) {
reset();
}
if (other._hasNonPodData) {
std::vector<Pair> data(other._data.size());
_data.swap(data);
for (size_t i = 0; i < _data.size(); ++i) {
_data[i].key = other._data[i].key;
copy_rdvalue(_data[i].val, other._data[i].val);
}
} else {
_data = other._data;
}
_hasNonPodData = other._hasNonPodData;
return *this;
}
Dict &operator=(Dict &&other) noexcept {
if (this == &other) {
return *this;
}
if (_hasNonPodData) {
reset();
}
_hasNonPodData = other._hasNonPodData;
other._hasNonPodData = false;
_data = std::move(other._data);
return *this;
}
//----------------------------------------------------------
//! \brief Returns the number of entries in the dictionary
std::size_t size() const { return _data.size(); }
//! \brief Returns whether the dictionary is empty
bool empty() const { return _data.empty(); }
using const_iterator = DataType::const_iterator;
const_iterator begin() const { return _data.begin(); }
const_iterator end() const { return _data.end(); }
//! \brief Appends a populated Pair to the dictionary.
void insert(Pair &&pair) {
_hasNonPodData |= pair.val.needsCleanup();
_data.push_back(std::move(pair));
}
//! \brief Bulk-appends a vector of Pairs, moving them into the dictionary.
void extend(std::vector<Pair> &&pairs) {
for (auto &p : pairs) {
_hasNonPodData |= p.val.needsCleanup();
}
_data.insert(_data.end(), std::make_move_iterator(pairs.begin()),
std::make_move_iterator(pairs.end()));
}
//! \brief Returns a const reference to the RDValue for a key.
//! Throws KeyErrorException if the key is not found.
const RDValue &getRDValue(const std::string_view what) const {
for (const auto &data : _data) {
if (data.key == what) {
return data.val;
}
}
throw KeyErrorException(what);
}
//----------------------------------------------------------
//! \brief Returns whether or not the dictionary contains a particular
//! key.
bool hasVal(const std::string_view what) const {
for (const auto &data : _data) {
if (data.key == what) {
return true;
}
}
return false;
}
//----------------------------------------------------------
//! Returns the set of keys in the dictionary
/*!
\return a \c STR_VECT
*/
STR_VECT keys() const {
STR_VECT res;
res.reserve(_data.size());
for (const auto &item : _data) {
res.push_back(item.key);
}
return res;
}
//----------------------------------------------------------
//! \brief Gets the value associated with a particular key
/*!
\param what the key to lookup
\param res a reference used to return the result
<b>Notes:</b>
- If \c res is a \c std::string, every effort will be made
to convert the specified element to a string using the
\c boost::lexical_cast machinery.
- If the dictionary does not contain the key \c what,
a KeyErrorException will be thrown.
*/
template <typename T>
void getVal(const std::string_view what, T &res) const {
res = getVal<T>(what);
}
//! \overload
template <typename T>
T getVal(const std::string_view what) const {
for (auto &data : _data) {
if (data.key == what) {
return from_rdvalue<T>(data.val);
}
}
throw KeyErrorException(what);
}
//! \overload
void getVal(const std::string_view what, std::string &res) const {
for (const auto &i : _data) {
if (i.key == what) {
rdvalue_tostring(i.val, res);
return;
}
}
throw KeyErrorException(what);
}
//----------------------------------------------------------
//! \brief Potentially gets the value associated with a particular key
//! returns true on success/false on failure.
/*!
\param what the key to lookup
\param res a reference used to return the result
<b>Notes:</b>
- If \c res is a \c std::string, every effort will be made
to convert the specified element to a string using the
\c boost::lexical_cast machinery.
- If the dictionary does not contain the key \c what,
a KeyErrorException will be thrown.
*/
template <typename T>
bool getValIfPresent(const std::string_view what, T &res) const {
for (const auto &data : _data) {
if (data.key == what) {
res = from_rdvalue<T>(data.val);
return true;
}
}
return false;
}
//! \overload
bool getValIfPresent(const std::string_view what, std::string &res) const {
for (const auto &i : _data) {
if (i.key == what) {
rdvalue_tostring(i.val, res);
return true;
}
}
return false;
}
//----------------------------------------------------------
//! \brief Sets the value associated with a key
/*!
\param what the key to set
\param val the value to store
<b>Notes:</b>
- If \c val is a <tt>const char *</tt>, it will be converted
to a \c std::string for storage.
- If the dictionary already contains the key \c what,
the value will be replaced.
*/
template <typename T>
void setVal(const std::string_view what, T &val) {
static_assert(!std::is_same_v<T, std::string_view>,
"T cannot be string_view");
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
_hasNonPodData = true;
for (auto &&data : _data) {
if (data.key == what) {
RDValue::cleanup_rdvalue(data.val);
data.val = val;
return;
}
}
_data.push_back(Pair(what, val));
}
template <typename T>
void setPODVal(const std::string_view what, T val) {
static_assert(!std::is_same_v<T, std::string_view>,
"T cannot be string_view");
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
// don't change the hasNonPodData status
for (auto &&data : _data) {
if (data.key == what) {
RDValue::cleanup_rdvalue(data.val);
data.val = val;
return;
}
}
_data.push_back(Pair(what, val));
}
void setVal(const std::string_view what, bool val) {
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
setPODVal(what, val);
}
void setVal(const std::string_view what, double val) {
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
setPODVal(what, val);
}
void setVal(const std::string_view what, float val) {
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
setPODVal(what, val);
}
void setVal(const std::string_view what, int val) {
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
setPODVal(what, val);
}
void setVal(const std::string_view what, unsigned int val) {
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
setPODVal(what, val);
}
//! \overload
void setVal(const std::string_view what, const char *val) {
if (what.empty()) {
throw ValueErrorException("Cannot set value with empty key");
}
std::string h(val);
setVal(what, h);
}
//----------------------------------------------------------
//! \brief Clears the value associated with a particular key,
//! removing the key from the dictionary.
/*!
\param what the key to clear
*/
void clearVal(const std::string_view what) {
for (auto it = _data.begin(); it < _data.end(); ++it) {
if (it->key == what) {
if (_hasNonPodData) {
RDValue::cleanup_rdvalue(it->val);
}
_data.erase(it);
return;
}
}
}
//----------------------------------------------------------
//! \brief Clears all keys (and values) from the dictionary.
//!
void reset() {
if (_hasNonPodData) {
for (auto &&data : _data) {
RDValue::cleanup_rdvalue(data.val);
}
}
DataType data;
_data.swap(data);
}
private:
DataType _data{}; //!< the actual dictionary
bool _hasNonPodData{false}; // if true, need a deep copy
// (copy_rdvalue)
};
template <>
inline std::string Dict::getVal<std::string>(
const std::string_view what) const {
std::string res;
getVal(what, res);
return res;
}
// Utility class for holding a Dict::Pair
// Dict::Pairs require containers for memory management
// This utility class covers cleanup and copying
class PairHolder : public Dict::Pair {
public:
PairHolder() : Pair() {}
explicit PairHolder(const PairHolder &p) : Pair(p.key) {
copy_rdvalue(this->val, p.val);
}
explicit PairHolder(PairHolder &&p) : Pair(p.key) {
this->val = p.val;
p.val.type = RDTypeTag::EmptyTag;
}
explicit PairHolder(Dict::Pair &&p) : Pair(p.key) {
this->val = p.val;
p.val.type = RDTypeTag::EmptyTag;
}
~PairHolder() { RDValue::cleanup_rdvalue(this->val); }
};
} // namespace RDKit
#endif
BoostEndInclude.h
BoostStartInclude.h
Exceptions.h
RDValue.h
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::setVal
void setVal(const std::string_view what, float val)
Definition Dict.h:340
RDKit::Dict::setVal
void setVal(const std::string_view what, int val)
Definition Dict.h:346
RDKit::Dict::const_iterator
DataType::const_iterator const_iterator
Definition Dict.h:144
RDKit::Dict::Dict
Dict(Dict &&other) noexcept=default
RDKit::Dict::getVal
T getVal(const std::string_view what) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Dict.h:221
RDKit::Dict::extend
void extend(std::vector< Pair > &&pairs)
Bulk-appends a vector of Pairs, moving them into the dictionary.
Definition Dict.h:155
RDKit::Dict::setPODVal
void setPODVal(const std::string_view what, T val)
Definition Dict.h:309
RDKit::Dict::reset
void reset()
Clears all keys (and values) from the dictionary.
Definition Dict.h:392
RDKit::Dict::operator=
Dict & operator=(const Dict &other)
Definition Dict.h:102
RDKit::Dict::keys
STR_VECT keys() const
Returns the set of keys in the dictionary.
Definition Dict.h:192
RDKit::Dict::insert
void insert(Pair &&pair)
Appends a populated Pair to the dictionary.
Definition Dict.h:149
RDKit::Dict::end
const_iterator end() const
Definition Dict.h:146
RDKit::Dict::setVal
void setVal(const std::string_view what, T &val)
Sets the value associated with a key.
Definition Dict.h:291
RDKit::Dict::hasVal
bool hasVal(const std::string_view what) const
Returns whether or not the dictionary contains a particular key.
Definition Dict.h:178
RDKit::Dict::getValIfPresent
bool getValIfPresent(const std::string_view what, std::string &res) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Dict.h:267
RDKit::Dict::begin
const_iterator begin() const
Definition Dict.h:145
RDKit::Dict::clearVal
void clearVal(const std::string_view what)
Clears the value associated with a particular key, removing the key from the dictionary.
Definition Dict.h:377
RDKit::Dict::setVal
void setVal(const std::string_view what, const char *val)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Dict.h:361
RDKit::Dict::getRDValue
const RDValue & getRDValue(const std::string_view what) const
Returns a const reference to the RDValue for a key. Throws KeyErrorException if the key is not found.
Definition Dict.h:165
RDKit::Dict::~Dict
~Dict()
Definition Dict.h:70
RDKit::Dict::setVal
void setVal(const std::string_view what, bool val)
Definition Dict.h:326
RDKit::Dict::getVal
void getVal(const std::string_view what, std::string &res) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Dict.h:231
RDKit::Dict::DataType
std::vector< Pair > DataType
Definition Dict.h:52
RDKit::Dict::setVal
void setVal(const std::string_view what, double val)
Definition Dict.h:333
RDKit::Dict::operator=
Dict & operator=(Dict &&other) noexcept
Definition Dict.h:124
RDKit::Dict::update
void update(const Dict &other, bool preserveExisting=false)
Definition Dict.h:74
RDKit::Dict::setVal
void setVal(const std::string_view what, unsigned int val)
Definition Dict.h:353
RDKit::Dict::getVal
void getVal(const std::string_view what, T &res) const
Gets the value associated with a particular key.
Definition Dict.h:215
RDKit::Dict::empty
bool empty() const
Returns whether the dictionary is empty.
Definition Dict.h:142
RDKit::Dict::Dict
Dict()
Definition Dict.h:54
RDKit::Dict::Dict
Dict(const Dict &other)
Definition Dict.h:56
RDKit::Dict::getValIfPresent
bool getValIfPresent(const std::string_view what, T &res) const
Potentially gets the value associated with a particular key returns true on success/false on failure.
Definition Dict.h:256
RDKit::Dict::size
std::size_t size() const
Returns the number of entries in the dictionary.
Definition Dict.h:139
RDKit::PairHolder::PairHolder
PairHolder()
Definition Dict.h:421
RDKit::PairHolder::PairHolder
PairHolder(PairHolder &&p)
Definition Dict.h:427
RDKit::PairHolder::~PairHolder
~PairHolder()
Definition Dict.h:437
RDKit::PairHolder::PairHolder
PairHolder(Dict::Pair &&p)
Definition Dict.h:432
RDKit::PairHolder::PairHolder
PairHolder(const PairHolder &p)
Definition Dict.h:423
ValueErrorException
Class to allow us to throw a ValueError from C++ and have it make it back to Python.
Definition Exceptions.h:41
export.h
RDKIT_RDGENERAL_EXPORT
#define RDKIT_RDGENERAL_EXPORT
Definition export.h:449
RDKit::RDTypeTag::EmptyTag
const short EmptyTag
Definition RDValue-taggedunion.h:83
RDKit
Std stuff.
Definition Abbreviations.h:19
RDKit::STR_VECT
std::vector< std::string > STR_VECT
Definition Dict.h:29
RDKit::rdvalue_tostring
bool rdvalue_tostring(RDValue_cast_t val, std::string &res)
Definition RDValue.h:192
RDKit::copy_rdvalue
void copy_rdvalue(RDValue &dest, const RDValue &src)
Definition RDValue-doublemagic.h:339
RDKit::from_rdvalue
boost::enable_if< boost::is_arithmetic< T >, T >::type from_rdvalue(RDValue_cast_t arg)
Definition RDValue.h:270
RDKit::Dict::Pair
Definition Dict.h:38
RDKit::Dict::Pair::Pair
Pair(std::string s)
Definition Dict.h:43
RDKit::Dict::Pair::key
std::string key
Definition Dict.h:39
RDKit::Dict::Pair::cleanup
void cleanup()
Definition Dict.h:49
RDKit::Dict::Pair::Pair
Pair(std::string s, const RDValue &v)
Definition Dict.h:45
RDKit::Dict::Pair::Pair
Pair(std::string_view s)
Definition Dict.h:44
RDKit::Dict::Pair::Pair
Pair()
Definition Dict.h:42
RDKit::Dict::Pair::val
RDValue val
Definition Dict.h:40
RDKit::Dict::Pair::Pair
Pair(std::string_view s, const RDValue &v)
Definition Dict.h:46
RDKit::RDValue
Definition RDValue-doublemagic.h:166
RDKit::RDValue::cleanup_rdvalue
static void cleanup_rdvalue(RDValue v)
Definition RDValue-doublemagic.h:331