diff --git a/Framework/Core/include/Framework/ServiceRegistry.h b/Framework/Core/include/Framework/ServiceRegistry.h index f85b4e32458c6..56d63e83b9242 100644 --- a/Framework/Core/include/Framework/ServiceRegistry.h +++ b/Framework/Core/include/Framework/ServiceRegistry.h @@ -7,26 +7,41 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef FRAMEWORK_SERVICEREGISTRY_H -#define FRAMEWORK_SERVICEREGISTRY_H +#ifndef O2_FRAMEWORK_SERVICEREGISTRY_H_ +#define O2_FRAMEWORK_SERVICEREGISTRY_H_ +#include "Framework/CompilerBuiltins.h" + +#include +#include #include #include #include #include #include -#include -namespace o2 -{ -namespace framework +namespace o2::framework { /// Service registry to hold generic, singleton like, interfaces and retrieve /// them by type. class ServiceRegistry { + using ServicePtr = void*; + using ConstServicePtr = void const*; + /// The maximum distance a entry can be from the optimal slot. + constexpr static int MAX_DISTANCE = 8; + /// The number of slots in the hashmap. + constexpr static int MAX_SERVICES = 256; + /// The mask to use to calculate the initial slot id. + constexpr static int MAX_SERVICES_MASK = MAX_SERVICES - 1; + public: + ServiceRegistry() + { + mServices.fill(std::make_pair(0L, nullptr)); + mConstServices.fill(std::make_pair(0L, nullptr)); + } // Register a service for the given interface T // with actual implementation C, i.e. C is derived from T. // Only one instance of type C can be registered per type T. @@ -42,7 +57,16 @@ class ServiceRegistry // advance static_assert(std::is_base_of::value == true, "Registered service is not derived from declared interface"); - mServices[typeid(I)] = reinterpret_cast(service); + auto typeHash = typeid(I).hash_code() >> 4; + auto serviceId = typeHash & MAX_SERVICES_MASK; + for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { + if (mServices[i + serviceId].second == nullptr) { + mServices[i + serviceId].first = typeHash; + mServices[i + serviceId].second = reinterpret_cast(service); + return; + } + } + O2_BUILTIN_UNREACHABLE(); } template @@ -53,7 +77,16 @@ class ServiceRegistry // advance static_assert(std::is_base_of::value == true, "Registered service is not derived from declared interface"); - mConstServices[typeid(I)] = reinterpret_cast(service); + auto typeHash = typeid(I).hash_code() >> 4; + auto serviceId = typeHash & MAX_SERVICES_MASK; + for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { + if (mConstServices[i + serviceId].second == nullptr) { + mConstServices[i + serviceId].first = typeHash; + mConstServices[i + serviceId].second = reinterpret_cast(service); + return; + } + } + O2_BUILTIN_UNREACHABLE(); } /// Get a service for the given interface T. The returned reference exposed to @@ -62,13 +95,16 @@ class ServiceRegistry template std::enable_if_t == false, T&> get() const { - auto service = mServices.find(typeid(T)); - if (service == mServices.end()) { - throw std::runtime_error(std::string("Unable to find service of kind ") + - typeid(T).name() + - " did you register one as non-const reference?"); + auto typeHash = typeid(T).hash_code() >> 4; + auto serviceId = typeHash & MAX_SERVICES_MASK; + for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { + if (mServices[i + serviceId].first == typeHash) { + return *reinterpret_cast(mServices[i + serviceId].second); + } } - return *reinterpret_cast(service->second); + throw std::runtime_error(std::string("Unable to find service of kind ") + + typeid(T).name() + + " did you register one as non-const reference?"); } /// Get a service for the given interface T. The returned reference exposed to /// the user is actually of the last concrete type C registered, however this @@ -76,35 +112,23 @@ class ServiceRegistry template std::enable_if_t, T&> get() const { - auto service = mConstServices.find(typeid(T)); - if (service == mConstServices.end()) { - throw std::runtime_error(std::string("Unable to find service of kind ") + typeid(T).name() + ". Is it non-const?"); + auto typeHash = typeid(T).hash_code() >> 4; + auto serviceId = typeHash & MAX_SERVICES_MASK; + for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { + if (mConstServices[i + serviceId].first == typeHash) { + return *reinterpret_cast(mConstServices[i + serviceId].second); + } } - return *reinterpret_cast(service->second); + throw std::runtime_error(std::string("Unable to find service of kind ") + + typeid(T).name() + + " did you register one as const reference?"); } private: - using TypeInfoRef = std::reference_wrapper; - using ServicePtr = void*; - using ConstServicePtr = void const*; - struct Hasher { - std::size_t operator()(TypeInfoRef code) const - { - return code.get().hash_code(); - } - }; - struct EqualTo { - bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const - { - return lhs.get() == rhs.get(); - } - }; - std::unordered_map mServices; - // Services which we want to expose as read only - std::unordered_map mConstServices; + std::array, MAX_SERVICES + MAX_DISTANCE> mServices; + std::array, MAX_SERVICES + MAX_DISTANCE> mConstServices; }; -} // namespace framework -} // namespace o2 +} // namespace o2::framework -#endif //FRAMEWORK_SERVICEREGISTRY_H +#endif // O2_FRAMEWORK_SERVICEREGISTRY_H_