Program Listing for File blackboard_pywrapper.hpp

Return to documentation for file (include/yasmin/blackboard_pywrapper.hpp)

// Copyright (C) 2025 Miguel Ángel González Santamarta
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef YASMIN__BLACKBOARD_PYWRAPPER_HPP
#define YASMIN__BLACKBOARD_PYWRAPPER_HPP

#include <list>
#include <map>
#include <pybind11/cast.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <vector>

#include "yasmin/blackboard.hpp"

namespace py = pybind11;

namespace yasmin {

// Forward declaration
class BlackboardPyWrapper;

class BlackboardPyWrapper {
private:
  std::shared_ptr<Blackboard> blackboard;

public:
  BlackboardPyWrapper() : blackboard(std::make_shared<Blackboard>()) {}

  BlackboardPyWrapper(Blackboard &&other)
      : blackboard(std::make_shared<Blackboard>(std::move(other))) {}

  explicit BlackboardPyWrapper(std::shared_ptr<Blackboard> bb_ptr)
      : blackboard(bb_ptr) {}

  void set(const std::string &key, py::object value) {
    if (py::isinstance<py::bool_>(value)) {
      this->blackboard->set<bool>(key, value.cast<bool>());
    } else if (py::isinstance<py::int_>(value)) {
      try {
        this->blackboard->set<int>(key, value.cast<int>());
      } catch (...) {
        this->blackboard->set<long>(key, value.cast<long>());
      }
    } else if (py::isinstance<py::float_>(value)) {
      this->blackboard->set<double>(key, value.cast<double>());
    } else if (py::isinstance<py::str>(value)) {
      this->blackboard->set<std::string>(key, value.cast<std::string>());
    } else if (py::isinstance<py::list>(value)) {
      this->blackboard->set<py::object>(key, value);
    } else if (py::isinstance<py::dict>(value)) {
      this->blackboard->set<py::object>(key, value);
    } else if (py::isinstance<py::tuple>(value)) {
      this->blackboard->set<py::object>(key, value);
    } else if (py::isinstance<py::set>(value)) {
      this->blackboard->set<py::object>(key, value);
    } else {
      this->blackboard->set<py::object>(key, value);
    }
  }

  py::object get(const std::string &key) {
    // Get the type of the stored value
    std::string type = this->blackboard->get_type(key);

    // Check if it's a pybind11::object (Python object - includes all Python
    // types)
    if (type.find("pybind11::object") != std::string::npos ||
        type.find("pybind11::int_") != std::string::npos ||
        type.find("pybind11::float_") != std::string::npos ||
        type.find("pybind11::str") != std::string::npos ||
        type.find("pybind11::bool_") != std::string::npos ||
        type.find("pybind11::list") != std::string::npos ||
        type.find("pybind11::dict") != std::string::npos ||
        type.find("pybind11::set") != std::string::npos ||
        type.find("pybind11::tuple") != std::string::npos ||
        type.find("pybind11::bytes") != std::string::npos ||
        type.find("pybind11::none") != std::string::npos) {
      return this->blackboard->get<py::object>(key);
    }
    // Check if it's a std::string (C++ string) - convert to Python str
    else if (type.find("std::string") != std::string::npos ||
             type.find("std::__cxx11::basic_string") != std::string::npos) {
      std::string cpp_value = this->blackboard->get<std::string>(key);
      return py::cast(cpp_value);
    }
    // Check if it's a std::vector (C++ vector) - convert to Python list
    else if (type.find("std::vector") != std::string::npos) {
      return this->blackboard->get<py::object>(key);
    }
    // Check if it's a std::map (C++ map) - convert to Python dict
    else if (type.find("std::map") != std::string::npos ||
             type.find("std::unordered_map") != std::string::npos) {
      return this->blackboard->get<py::object>(key);
    }
    // Check if it's a std::set (C++ set) - convert to Python set
    else if (type.find("std::set") != std::string::npos ||
             type.find("std::unordered_set") != std::string::npos) {
      return this->blackboard->get<py::object>(key);
    }
    // Check if it's a std::list (C++ list) - convert to Python list
    else if (type.find("std::list") != std::string::npos) {
      return this->blackboard->get<py::object>(key);
    }
    // Check if it's a std::tuple (C++ tuple) - convert to Python tuple
    else if (type.find("std::tuple") != std::string::npos) {
      return this->blackboard->get<py::object>(key);
    }
    // Check if it's an int (C++ int) - convert to Python int
    else if (type.find("int") != std::string::npos) {
      int cpp_value = this->blackboard->get<int>(key);
      return py::cast(cpp_value);
    }
    // Check if it's a long (C++ long) - convert to Python int
    else if (type.find("long") != std::string::npos) {
      long cpp_value = this->blackboard->get<long>(key);
      return py::cast(cpp_value);
    }
    // Check if it's a float or double (C++ float/double) - convert to Python
    // float
    else if (type.find("float") != std::string::npos ||
             type.find("double") != std::string::npos) {
      double cpp_value = this->blackboard->get<double>(key);
      return py::cast(cpp_value);
    }
    // Check if it's a bool (C++ bool) - convert to Python bool
    else if (type.find("bool") != std::string::npos) {
      bool cpp_value = this->blackboard->get<bool>(key);
      return py::cast(cpp_value);
    }
    // Default: try to get as py::object
    else {
      return this->blackboard->get<py::object>(key);
    }
  }

  void remove(const std::string &key) { this->blackboard->remove(key); }

  bool contains(const std::string &key) {
    return this->blackboard->contains(key);
  }

  int size() { return this->blackboard->size(); }

  std::string to_string() { return this->blackboard->to_string(); }

  void set_remappings(const std::map<std::string, std::string> &remappings) {
    this->blackboard->set_remappings(remappings);
  }

  std::map<std::string, std::string> get_remappings() {
    return this->blackboard->get_remappings();
  }

  std::shared_ptr<Blackboard> get_cpp_blackboard() { return this->blackboard; }
};

} // namespace yasmin

#endif // YASMIN__BLACKBOARD_PYWRAPPER_HPP