File indexing completed on 2025-12-14 09:39:52
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <format>
0012 #include <functional>
0013 #include <type_traits>
0014 #include <typeindex>
0015 #include <typeinfo>
0016 #include <unordered_map>
0017 #include <vector>
0018
0019 #include <boost/core/demangle.hpp>
0020
0021 namespace Acts {
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 template <typename base_t, typename signature_t>
0032 class TypeDispatcher;
0033
0034 template <typename base_t, typename return_t, typename... args_t>
0035 class TypeDispatcher<base_t, return_t(args_t...)> {
0036 public:
0037
0038 using base_type = base_t;
0039 using return_type = return_t;
0040 using self_type = TypeDispatcher<base_type, return_type(args_t...)>;
0041
0042 using function_signature = return_t(const base_t&, args_t...);
0043 using function_pointer_type = return_t (*)(args_t...);
0044 using function_type = std::function<function_signature>;
0045
0046
0047 TypeDispatcher() = default;
0048
0049
0050
0051 template <typename... derived_types_t>
0052 explicit TypeDispatcher(return_t (*... funcs)(const derived_types_t&,
0053 args_t...))
0054 requires(std::is_base_of_v<base_t, derived_types_t> && ...)
0055 {
0056 (registerFunction(funcs),
0057 ...);
0058 }
0059
0060
0061
0062
0063 template <typename derived_t>
0064 requires std::is_base_of_v<base_t, derived_t>
0065 self_type& registerFunction(return_t (*func)(const derived_t&, args_t...)) {
0066 std::type_index typeIdx(typeid(derived_t));
0067
0068
0069 if (m_functions.find(typeIdx) != m_functions.end()) {
0070 throw std::runtime_error(
0071 std::format("Function already registered for type: {}",
0072 boost::core::demangle(typeIdx.name())));
0073 }
0074
0075
0076
0077 if constexpr (std::is_default_constructible_v<derived_t>) {
0078 derived_t tempObj{};
0079 for (const auto& [existingTypeIdx, checker] : m_castCheckers) {
0080 if (checker(tempObj)) {
0081 throw std::runtime_error(
0082 std::format("Registration conflict: type {} would be handled by "
0083 "existing function registered for type: {}",
0084 boost::core::demangle(typeIdx.name()),
0085 boost::core::demangle(existingTypeIdx.name())));
0086 }
0087 }
0088 }
0089
0090
0091 m_castCheckers[typeIdx] = [](const base_t& obj) -> bool {
0092 const auto* derived = dynamic_cast<const derived_t*>(&obj);
0093 return derived != nullptr;
0094 };
0095
0096
0097 m_functions[typeIdx] = [func]<typename... Ts>(const base_t& base,
0098 Ts&&... args) -> return_t {
0099 const auto* derived = dynamic_cast<const derived_t*>(&base);
0100 if (derived == nullptr) {
0101 throw std::bad_cast();
0102 }
0103 return func(*derived, std::forward<Ts>(args)...);
0104 };
0105
0106 return *this;
0107 }
0108
0109
0110
0111
0112
0113 template <typename... func_args_t>
0114 return_t operator()(const base_t& obj, func_args_t&&... args) const
0115 requires std::invocable<function_pointer_type, func_args_t...>
0116 {
0117 std::vector<std::type_index> compatibleTypes;
0118
0119
0120 for (const auto& [registeredTypeIdx, checker] : m_castCheckers) {
0121 if (checker(obj)) {
0122 compatibleTypes.push_back(registeredTypeIdx);
0123 }
0124 }
0125
0126 if (compatibleTypes.empty()) {
0127 throw std::runtime_error(
0128 std::format("No function registered for type: {}",
0129 boost::core::demangle(typeid(obj).name())));
0130 }
0131
0132 if (compatibleTypes.size() > 1) {
0133 std::string typeNames;
0134 for (std::size_t i = 0; i < compatibleTypes.size(); ++i) {
0135 if (i > 0) {
0136 typeNames += ", ";
0137 }
0138 typeNames += boost::core::demangle(compatibleTypes[i].name());
0139 }
0140 throw std::runtime_error(
0141 std::format("Ambiguous dispatch for type {}: multiple functions can "
0142 "handle it: {}",
0143 boost::core::demangle(typeid(obj).name()), typeNames));
0144 }
0145
0146
0147 auto funcIt = m_functions.find(compatibleTypes[0]);
0148 if (funcIt != m_functions.end()) {
0149 return funcIt->second(obj, std::forward<func_args_t>(args)...);
0150 }
0151
0152
0153 throw std::runtime_error(
0154 "Internal error: function not found for compatible type");
0155 }
0156
0157
0158
0159
0160 bool hasFunction(const base_t& obj) const {
0161
0162 for (const auto& [registeredTypeIdx, checker] : m_castCheckers) {
0163 if (checker(obj)) {
0164 return true;
0165 }
0166 }
0167 return false;
0168 }
0169
0170
0171
0172
0173 template <typename derived_t>
0174 requires std::is_base_of_v<base_t, derived_t>
0175 bool hasFunction() const {
0176 std::type_index typeIdx(typeid(derived_t));
0177 return m_functions.find(typeIdx) != m_functions.end();
0178 }
0179
0180
0181 void clear() {
0182 m_functions.clear();
0183 m_castCheckers.clear();
0184 }
0185
0186
0187 std::size_t size() const { return m_functions.size(); }
0188
0189 private:
0190 using cast_checker_type = std::function<bool(const base_t&)>;
0191
0192 std::unordered_map<std::type_index, function_type> m_functions;
0193 std::unordered_map<std::type_index, cast_checker_type> m_castCheckers;
0194 };
0195
0196 }