Use std::string_view for property keys (#8844)

* string_view props API

* wip

* fix leak

* add string_view to swig

* fix comment

* add backwards incompatibilty note

* fix rebase issue

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>
This commit is contained in:
Ricardo Rodriguez
2025-10-09 16:14:48 +02:00
committed by GitHub
parent ad1fcb5b7b
commit 7d1e662bc7
10 changed files with 158 additions and 138 deletions

View File

@@ -28,8 +28,9 @@
#include "list_indexing_suite.hpp"
#include <RDGeneral/BoostEndInclude.h>
#include <vector>
#include <list>
#include <string_view>
#include <vector>
#include <RDGeneral/Exceptions.h>
namespace python = boost::python;
@@ -322,47 +323,6 @@ struct iterable_converter {
}
};
/// Simple Boost.Python custom converter from pathlib.Path to std::string
template <typename T = std::string>
struct path_converter {
path_converter() {
python::converter::registry::push_back(&path_converter::convertible,
&path_converter::construct,
boost::python::type_id<T>());
}
/// Check PyObject is a pathlib.Path
static void *convertible(PyObject *object) {
// paranoia
if (object == nullptr) {
return nullptr;
}
python::object boost_object(python::handle<>(python::borrowed(object)));
std::string object_classname = boost::python::extract<std::string>(
boost_object.attr("__class__").attr("__name__"));
// pathlib.Path is always specialized to the below derived classes
if (object_classname == "WindowsPath" || object_classname == "PosixPath") {
return object;
}
return nullptr;
}
/// Construct a std::string from pathlib.Path using its own __str__ attribute
static void construct(
PyObject *object,
boost::python::converter::rvalue_from_python_stage1_data *data) {
void *storage =
((boost::python::converter::rvalue_from_python_storage<T> *)data)
->storage.bytes;
python::object boost_object{python::handle<>{python::borrowed(object)}};
new (storage)
T{boost::python::extract<std::string>{boost_object.attr("__str__")()}};
data->convertible = storage;
}
};
//
// allows rdkit objects to be pickled.
struct rdkit_pickle_suite : python::pickle_suite {

View File

@@ -234,6 +234,81 @@ struct python_ostream_wrapper {
};
void seedRNG(unsigned int seed) { std::srand(seed); }
/// Simple Boost.Python custom converter from pathlib.Path to std::string
template <typename T = std::string>
struct path_converter {
path_converter() {
python::converter::registry::push_back(&path_converter::convertible,
&path_converter::construct,
boost::python::type_id<T>());
}
/// Check PyObject is a pathlib.Path
static void *convertible(PyObject *object) {
// paranoia
if (object == nullptr) {
return nullptr;
}
python::object boost_object(python::handle<>(python::borrowed(object)));
std::string object_classname = boost::python::extract<std::string>(
boost_object.attr("__class__").attr("__name__"));
// pathlib.Path is always specialized to the below derived classes
if (object_classname == "WindowsPath" || object_classname == "PosixPath") {
return object;
}
return nullptr;
}
/// Construct a std::string from pathlib.Path using its own __str__ attribute
static void construct(
PyObject *object,
boost::python::converter::rvalue_from_python_stage1_data *data) {
void *storage =
((boost::python::converter::rvalue_from_python_storage<T> *)data)
->storage.bytes;
python::object boost_object{python::handle<>{python::borrowed(object)}};
new (storage)
T{boost::python::extract<std::string>{boost_object.attr("__str__")()}};
data->convertible = storage;
}
};
/// Convert a Python str to a std::string_view
template <typename T = std::string_view>
struct string_view_converter {
string_view_converter() {
python::converter::registry::push_back(&string_view_converter::convertible,
&string_view_converter::construct,
boost::python::type_id<T>());
}
/// Check PyObject is a str
static void *convertible(PyObject *object) {
if (object != nullptr && PyUnicode_Check(object)) {
return object;
}
return nullptr;
}
/// Construct a std::string_view from the internal string of the PyObject.
/// This shouldn´t fail, as we block the Python thread until the C++ code
/// returns, so the PyObject and the internal string should remain valid.
static void construct(
PyObject *object,
boost::python::converter::rvalue_from_python_stage1_data *data) {
const char *tmp = PyUnicode_AsUTF8(object);
void *storage =
((boost::python::converter::rvalue_from_python_storage<T> *)data)
->storage.bytes;
new (storage) T{tmp};
data->convertible = storage;
}
};
} // namespace
BOOST_PYTHON_MODULE(rdBase) {
@@ -256,6 +331,7 @@ BOOST_PYTHON_MODULE(rdBase) {
RegisterVectorConverter<std::pair<int, int>>("MatchTypeVect");
path_converter();
string_view_converter();
RegisterListConverter<int>();
RegisterListConverter<std::vector<int>>();