Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-26 08:38:45

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Utilities/Any.hpp"
0012 #include "Acts/Utilities/HashedString.hpp"
0013 
0014 #include <concepts>
0015 #include <functional>
0016 #include <unordered_map>
0017 
0018 #include <pybind11/pybind11.h>
0019 
0020 namespace ActsPython {
0021 
0022 /// Concept: pybind11 class must use smart_holder for WhiteBoard ownership.
0023 template <typename... Ts>
0024 concept PyClassWithSmartHolder =
0025     std::same_as<typename pybind11::class_<Ts...>::holder_type,
0026                  pybind11::smart_holder>;
0027 
0028 /// The WhiteBoard is an event-store container that holds arbitrary C++ objects
0029 /// by name. Python algorithms need to read these objects through pybind11, but
0030 /// the WhiteBoard stores them in a type-erased form (`void*`). This registry
0031 /// bridges that gap by mapping Python types to their C++ counterparts and
0032 /// providing a downcast function that converts the stored pointer into a
0033 /// properly reference-managed pybind11 object.
0034 ///
0035 /// Usage:
0036 /// 1. When defining pybind11 bindings for a type T that will be stored on the
0037 ///    WhiteBoard, call `WhiteBoardRegistry::registerClass(pyClass)` or
0038 ///    `WhiteBoardRegistry::registerType<T>(pyType)` immediately after the
0039 ///    py::class_<T> definition.
0040 /// 2. When a Python algorithm creates a `ReadDataHandle` for that type, the
0041 ///    registry is consulted to find the type info and downcast function for
0042 ///    safe retrieval from the `WhiteBoard`.
0043 class WhiteBoardRegistry {
0044  private:
0045   /// Function that converts a type-erased pointer from the WhiteBoard into a
0046   /// Python object.
0047   using ToPythonFunction =
0048       std::function<PyObject*(const Acts::AnyMoveOnly& any, PyObject* wbPy)>;
0049 
0050   /// Function that converts a Python object into a type-erased holder for the
0051   /// WhiteBoard.
0052   using FromPythonFunction =
0053       std::function<std::unique_ptr<Acts::AnyMoveOnly>(PyObject* obj)>;
0054 
0055   template <typename T>
0056   static void registerType() {
0057     namespace py = pybind11;
0058     return registerType<T>(py::type::of<T>());
0059   }
0060 
0061   template <typename T>
0062   static void registerType(const pybind11::object& pyType) {
0063     namespace py = pybind11;
0064 
0065     using type = T;
0066 
0067     instance()[pyType.ptr()] = {
0068         .toPython = [](const Acts::AnyMoveOnly& any,
0069                        PyObject* wbPy) -> PyObject* {
0070           py::object pyWb = py::reinterpret_borrow<py::object>(wbPy);
0071           py::object out =
0072               py::cast(any.as<type>(),
0073                        py::return_value_policy::reference_internal, pyWb);
0074           return out.release().ptr();
0075         },
0076         .fromPython =
0077             [](PyObject* obj) {
0078               py::object pyObj = py::reinterpret_borrow<py::object>(obj);
0079               // This communicates to pybind11's smart_holder that the object is
0080               // consumed in C++
0081               auto up = py::cast<std::unique_ptr<T>>(pyObj);
0082               return std::make_unique<Acts::AnyMoveOnly>(std::move(*up));
0083             },
0084         .typeinfo = &typeid(type),
0085         .typeHash = Acts::typeHash<type>(),
0086     };
0087   }
0088 
0089  public:
0090   /// Register a pybind11-bound type T for WhiteBoard read access.
0091   /// Call this after the `py::class_<T>` definition.
0092   /// @tparam Ts The types to register.
0093   /// @param pyClass The pybind11 class object to register.
0094   template <typename... Ts>
0095   static void registerClass(const pybind11::class_<Ts...>& pyClass)
0096     requires PyClassWithSmartHolder<Ts...>
0097   {
0098     using type = pybind11::class_<Ts...>::type;
0099     registerType<type>(pyClass);
0100   }
0101 
0102   /// Per-type registry entry: downcast function and type metadata for lookups.
0103   struct RegistryEntry {
0104     /// Converts `void*` + `WhiteBoard` -> `py::object`
0105     ToPythonFunction toPython{nullptr};
0106     /// Converts `py::object` -> `void*`
0107     FromPythonFunction fromPython{nullptr};
0108     /// C++ type for type checking
0109     const std::type_info* typeinfo{nullptr};
0110     /// Hash for type verification
0111     std::uint64_t typeHash{0};
0112   };
0113 
0114   /// Look up a registered type by its pybind11 Python type object.
0115   /// @param pyType The pybind11 Python type object to look up.
0116   /// @return Pointer to the `RegistryEntry`, or `nullptr` if not registered
0117   static RegistryEntry* find(const pybind11::object& pyType) {
0118     if (auto it = instance().find(pyType.ptr()); it != instance().end()) {
0119       return &it->second;
0120     }
0121     return nullptr;
0122   }
0123 
0124  private:
0125   WhiteBoardRegistry() = default;
0126 
0127   static std::unordered_map<PyObject*, RegistryEntry>& instance();
0128 };
0129 
0130 }  // namespace ActsPython