16#ifndef YASMIN__BLACKBOARD_KEY_INFO_PY_HPP_
17#define YASMIN__BLACKBOARD_KEY_INFO_PY_HPP_
19#include <pybind11/pybind11.h>
20#include <pybind11/stl.h>
26#include <unordered_map>
33namespace py = pybind11;
44using StringDict = std::unordered_map<std::string, std::string>;
45using IntDict = std::unordered_map<std::string, std::int64_t>;
46using FloatDict = std::unordered_map<std::string, double>;
47using BoolDict = std::unordered_map<std::string, bool>;
53 if (PyBytes_Check(value.ptr()) != 0) {
54 if (PyBytes_AsStringAndSize(value.ptr(), &data, &size) != 0) {
55 throw py::error_already_set();
57 }
else if (PyByteArray_Check(value.ptr()) != 0) {
58 data = PyByteArray_AsString(value.ptr());
59 size = PyByteArray_Size(value.ptr());
61 throw std::runtime_error(
"Expected bytes or bytearray object");
64 return std::vector<uint8_t>(
reinterpret_cast<uint8_t *
>(data),
65 reinterpret_cast<uint8_t *
>(data) + size);
68template <
typename ByteT>
70 return py::bytes(
reinterpret_cast<const char *
>(value.data()),
71 static_cast<py::ssize_t
>(value.size()));
75 return PyBytes_Check(value.ptr()) != 0 || PyByteArray_Check(value.ptr()) != 0;
79 return py::isinstance<py::int_>(value) && !py::isinstance<py::bool_>(value);
83 return py::isinstance<py::float_>(value);
91 return py::isinstance<py::list>(value) || py::isinstance<py::tuple>(value);
94template <
typename Predicate>
96 for (
auto item : seq) {
106 std::vector<T> result;
107 result.reserve(
static_cast<std::size_t
>(py::len(seq)));
109 for (
auto item : seq) {
110 result.push_back(py::cast<T>(item));
117 for (
auto item : dict) {
118 if (!py::isinstance<py::str>(item.first)) {
125template <
typename Predicate>
127 for (
auto item : dict) {
128 if (!pred(item.second)) {
136inline std::unordered_map<std::string, T>
138 std::unordered_map<std::string, T> result;
139 result.reserve(
static_cast<std::size_t
>(py::len(dict)));
141 for (
auto item : dict) {
142 result.emplace(py::cast<std::string>(item.first), py::cast<T>(item.second));
161inline BlackboardKeyInfo
166 if (py::isinstance<py::bool_>(value)) {
170 if (is_python_int_like(value)) {
174 if (py::isinstance<py::float_>(value)) {
178 if (is_python_bytes_like(value)) {
182 if (py::isinstance<py::str>(value)) {
186 if (is_python_sequence_like(value)) {
187 py::sequence seq = value.cast<py::sequence>();
189 if (py::len(seq) == 0) {
193 auto stored = std::make_shared<py::object>(value);
196 py::gil_scoped_acquire gil;
197 bb.
set<py::object>(key, *stored);
202 if (sequence_matches(seq, [](
const py::handle &item) {
203 return py::isinstance<py::bool_>(item);
208 if (sequence_matches(seq, [](
const py::handle &item) {
209 return is_python_int_like(item);
212 sequence_to_vector<std::int64_t>(seq));
215 if (sequence_matches(seq, [](
const py::handle &item) {
216 return is_python_number_like(item);
221 if (sequence_matches(seq, [](
const py::handle &item) {
222 return py::isinstance<py::str>(item);
225 sequence_to_vector<std::string>(seq));
229 if (py::isinstance<py::dict>(value)) {
230 py::dict dict = value.cast<py::dict>();
232 if (py::len(dict) != 0 && dict_has_only_string_keys(dict)) {
233 if (dict_values_match(dict, [](
const py::handle &item) {
234 return py::isinstance<py::bool_>(item);
237 dict_to_unordered_map<bool>(dict));
240 if (dict_values_match(dict, [](
const py::handle &item) {
241 return is_python_int_like(item);
244 dict_to_unordered_map<std::int64_t>(dict));
247 if (dict_values_match(dict, [](
const py::handle &item) {
248 return is_python_number_like(item);
251 dict_to_unordered_map<double>(dict));
254 if (dict_values_match(dict, [](
const py::handle &item) {
255 return py::isinstance<py::str>(item);
258 dict_to_unordered_map<std::string>(dict));
267 auto stored = std::make_shared<py::object>(value);
270 py::gil_scoped_acquire gil;
271 bb.
set<py::object>(key, *stored);
293 if (is_exact_cpp_type<std::vector<uint8_t>>(type)) {
294 return byte_vector_to_py_bytes(
297 if (is_exact_cpp_type<std::vector<unsigned char>>(type)) {
298 return byte_vector_to_py_bytes(
301 if (is_exact_cpp_type<std::vector<char>>(type)) {
305 if (is_exact_cpp_type<StringVector>(type)) {
308 if (is_exact_cpp_type<IntVector>(type) ||
309 is_exact_cpp_type<std::vector<int>>(type) ||
310 is_exact_cpp_type<std::vector<long>>(type) ||
311 is_exact_cpp_type<std::vector<long long>>(type)) {
312 if (is_exact_cpp_type<IntVector>(type)) {
315 if (is_exact_cpp_type<std::vector<int>>(type)) {
318 if (is_exact_cpp_type<std::vector<long>>(type)) {
323 if (is_exact_cpp_type<FloatVector>(type) ||
324 is_exact_cpp_type<std::vector<float>>(type)) {
325 if (is_exact_cpp_type<FloatVector>(type)) {
330 if (is_exact_cpp_type<BoolVector>(type)) {
334 if (is_exact_cpp_type<StringDict>(type)) {
337 if (is_exact_cpp_type<IntDict>(type) ||
338 is_exact_cpp_type<std::unordered_map<std::string, int>>(type) ||
339 is_exact_cpp_type<std::unordered_map<std::string, long>>(type) ||
340 is_exact_cpp_type<std::unordered_map<std::string, long long>>(type)) {
341 if (is_exact_cpp_type<IntDict>(type)) {
344 if (is_exact_cpp_type<std::unordered_map<std::string, int>>(type)) {
348 if (is_exact_cpp_type<std::unordered_map<std::string, long>>(type)) {
355 if (is_exact_cpp_type<FloatDict>(type) ||
356 is_exact_cpp_type<std::unordered_map<std::string, float>>(type)) {
357 if (is_exact_cpp_type<FloatDict>(type)) {
363 if (is_exact_cpp_type<BoolDict>(type)) {
367 if (is_exact_cpp_type<std::string>(type)) {
370 if (is_exact_cpp_type<std::int64_t>(type)) {
373 if (is_exact_cpp_type<int>(type)) {
376 if (is_exact_cpp_type<long>(type)) {
379 if (is_exact_cpp_type<long long>(type)) {
382 if (is_exact_cpp_type<float>(type)) {
385 if (is_exact_cpp_type<double>(type)) {
388 if (is_exact_cpp_type<bool>(type)) {
391 if (type ==
"py::object") {
395 throw std::runtime_error(
"Unsupported BlackboardKeyInfo default value type "
396 "for Python conversion: " +
A thread-safe storage for key-value pairs of varying types.
Definition blackboard.hpp:67
void set(const std::string &name, T value)
Set a value in the blackboard.
Definition blackboard.hpp:122
Definition blackboard_key_info_py.hpp:37
bool is_python_sequence_like(const py::handle &value)
Definition blackboard_key_info_py.hpp:90
bool is_python_number_like(const py::handle &value)
Definition blackboard_key_info_py.hpp:86
std::vector< std::string > StringVector
Definition blackboard_key_info_py.hpp:39
std::vector< bool > BoolVector
Definition blackboard_key_info_py.hpp:42
std::vector< T > sequence_to_vector(const py::sequence &seq)
Definition blackboard_key_info_py.hpp:105
bool dict_has_only_string_keys(const py::dict &dict)
Definition blackboard_key_info_py.hpp:116
bool sequence_matches(const py::sequence &seq, Predicate pred)
Definition blackboard_key_info_py.hpp:95
std::vector< double > FloatVector
Definition blackboard_key_info_py.hpp:41
bool is_python_float_like(const py::handle &value)
Definition blackboard_key_info_py.hpp:82
std::unordered_map< std::string, std::int64_t > IntDict
Definition blackboard_key_info_py.hpp:45
std::unordered_map< std::string, double > FloatDict
Definition blackboard_key_info_py.hpp:46
bool is_exact_cpp_type(const std::string &type)
Definition blackboard_key_info_py.hpp:148
std::vector< std::int64_t > IntVector
Definition blackboard_key_info_py.hpp:40
bool dict_values_match(const py::dict &dict, Predicate pred)
Definition blackboard_key_info_py.hpp:126
bool is_python_int_like(const py::handle &value)
Definition blackboard_key_info_py.hpp:78
bool is_python_bytes_like(const py::handle &value)
Definition blackboard_key_info_py.hpp:74
py::bytes byte_vector_to_py_bytes(const std::vector< ByteT > &value)
Definition blackboard_key_info_py.hpp:69
std::vector< uint8_t > py_buffer_to_vector(const py::handle &value)
Definition blackboard_key_info_py.hpp:49
std::unordered_map< std::string, T > dict_to_unordered_map(const py::dict &dict)
Definition blackboard_key_info_py.hpp:137
std::unordered_map< std::string, bool > BoolDict
Definition blackboard_key_info_py.hpp:47
std::unordered_map< std::string, std::string > StringDict
Definition blackboard_key_info_py.hpp:44
Definition blackboard.hpp:34
py::object blackboard_key_info_get_py_default(const BlackboardKeyInfo &info)
Convert a BlackboardKeyInfo default value back to a Python object.
Definition blackboard_key_info_py.hpp:284
std::string demangle_type(const std::string &mangled_name)
Demangle a C++ type name to a human-readable format.
Definition blackboard.hpp:41
BlackboardKeyInfo blackboard_key_info_from_pyobject(const std::string &key_name, py::object value)
Create a BlackboardKeyInfo from a Python object default value.
Definition blackboard_key_info_py.hpp:162
Extension methods for BlackboardKeyInfo. Added via ADL-friendly free functions used by the pybind cod...
Definition blackboard_key_info_py.hpp:408
static py::object get_py_default_value(const BlackboardKeyInfo &info)
Definition blackboard_key_info_py.hpp:414
static BlackboardKeyInfo from_pyobject(const std::string &key_name, py::object value)
Definition blackboard_key_info_py.hpp:409
Information about a blackboard key including name and optional default value.
Definition blackboard_key_info.hpp:35
bool has_default
Whether this key has a default value.
Definition blackboard_key_info.hpp:41
T get_default_value() const
Retrieve the default value as the given type.
Definition blackboard_key_info.hpp:113
std::function< void(Blackboard &, const std::string &)> inject_default
Function to inject the default value into a blackboard at the given key.
Definition blackboard_key_info.hpp:48
std::string default_value_type
The type name of the default value.
Definition blackboard_key_info.hpp:46
std::shared_ptr< void > default_value
Definition blackboard_key_info.hpp:44