diff --git a/include/rice/rice.hpp b/include/rice/rice.hpp index 15567da2..13fb2c89 100644 --- a/include/rice/rice.hpp +++ b/include/rice/rice.hpp @@ -1075,6 +1075,7 @@ namespace Rice::detail #include #include +#include namespace Rice::detail @@ -1093,8 +1094,8 @@ namespace Rice::detail Return_T lookup(VALUE klass, ID method_id); private: - std::pair key(VALUE klass, ID method_id); - std::map, std::any> natives_ = {}; + size_t key(VALUE klass, ID method_id); + std::unordered_multimap> natives_ = {}; }; } @@ -1112,20 +1113,32 @@ namespace Rice::detail { // Effective Java (2nd edition) // https://stackoverflow.com/a/2634715 - inline std::pair NativeRegistry::key(VALUE klass, ID id) + inline size_t NativeRegistry::key(VALUE klass, ID id) + { + uint32_t prime = 53; + return (prime + klass) * prime + id; + } + + inline void NativeRegistry::add(VALUE klass, ID method_id, std::any callable) { if (rb_type(klass) == T_ICLASS) { klass = detail::protect(rb_class_of, klass); } - return std::make_pair(klass, id); - } + auto range = this->natives_.equal_range(key(klass, method_id)); + for (auto it = range.first; it != range.second; ++it) + { + const auto [k, m, d] = it->second; - inline void NativeRegistry::add(VALUE klass, ID method_id, std::any callable) - { - // Now store data about it - this->natives_[key(klass, method_id)] = callable; + if (k == klass && m == method_id) + { + std::get<2>(it->second) = callable; + return; + } + } + + this->natives_.emplace(std::make_pair(key(klass, method_id), std::make_tuple(klass, method_id, callable))); } template @@ -1144,14 +1157,23 @@ namespace Rice::detail template inline Return_T NativeRegistry::lookup(VALUE klass, ID method_id) { - auto iter = this->natives_.find(key(klass, method_id)); - if (iter == this->natives_.end()) + if (rb_type(klass) == T_ICLASS) + { + klass = detail::protect(rb_class_of, klass); + } + + auto range = this->natives_.equal_range(key(klass, method_id)); + for (auto it = range.first; it != range.second; ++it) { - rb_raise(rb_eRuntimeError, "Could not find data for klass and method id"); + const auto [k, m, d] = it->second; + + if (k == klass && m == method_id) + { + return std::any_cast(d); + } } - std::any data = iter->second; - return std::any_cast(data); + rb_raise(rb_eRuntimeError, "Could not find data for klass and method id"); } } diff --git a/rice/detail/NativeRegistry.hpp b/rice/detail/NativeRegistry.hpp index a89d3757..3c7b9575 100644 --- a/rice/detail/NativeRegistry.hpp +++ b/rice/detail/NativeRegistry.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "ruby.hpp" @@ -22,8 +23,8 @@ namespace Rice::detail Return_T lookup(VALUE klass, ID method_id); private: - std::pair key(VALUE klass, ID method_id); - std::map, std::any> natives_ = {}; + size_t key(VALUE klass, ID method_id); + std::unordered_multimap> natives_ = {}; }; } #include "NativeRegistry.ipp" diff --git a/rice/detail/NativeRegistry.ipp b/rice/detail/NativeRegistry.ipp index ec4e1e31..d325f81b 100644 --- a/rice/detail/NativeRegistry.ipp +++ b/rice/detail/NativeRegistry.ipp @@ -12,20 +12,32 @@ namespace Rice::detail { // Effective Java (2nd edition) // https://stackoverflow.com/a/2634715 - inline std::pair NativeRegistry::key(VALUE klass, ID id) + inline size_t NativeRegistry::key(VALUE klass, ID id) + { + uint32_t prime = 53; + return (prime + klass) * prime + id; + } + + inline void NativeRegistry::add(VALUE klass, ID method_id, std::any callable) { if (rb_type(klass) == T_ICLASS) { klass = detail::protect(rb_class_of, klass); } - return std::make_pair(klass, id); - } + auto range = this->natives_.equal_range(key(klass, method_id)); + for (auto it = range.first; it != range.second; ++it) + { + const auto [k, m, d] = it->second; - inline void NativeRegistry::add(VALUE klass, ID method_id, std::any callable) - { - // Now store data about it - this->natives_[key(klass, method_id)] = callable; + if (k == klass && m == method_id) + { + std::get<2>(it->second) = callable; + return; + } + } + + this->natives_.emplace(std::make_pair(key(klass, method_id), std::make_tuple(klass, method_id, callable))); } template @@ -44,13 +56,22 @@ namespace Rice::detail template inline Return_T NativeRegistry::lookup(VALUE klass, ID method_id) { - auto iter = this->natives_.find(key(klass, method_id)); - if (iter == this->natives_.end()) + if (rb_type(klass) == T_ICLASS) + { + klass = detail::protect(rb_class_of, klass); + } + + auto range = this->natives_.equal_range(key(klass, method_id)); + for (auto it = range.first; it != range.second; ++it) { - rb_raise(rb_eRuntimeError, "Could not find data for klass and method id"); + const auto [k, m, d] = it->second; + + if (k == klass && m == method_id) + { + return std::any_cast(d); + } } - std::any data = iter->second; - return std::any_cast(data); + rb_raise(rb_eRuntimeError, "Could not find data for klass and method id"); } }