diff --git a/Framework/Core/include/Framework/ContextRegistry.h b/Framework/Core/include/Framework/ContextRegistry.h index a6274ff897aee..34ce1f8dd2a78 100644 --- a/Framework/Core/include/Framework/ContextRegistry.h +++ b/Framework/Core/include/Framework/ContextRegistry.h @@ -8,11 +8,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef O2_FRAMEWORK_CONTEXTREGISTRY_H_ -#define O2_FRAMEWORK_CONTEXTREGISTRY_H_ - -#include "Framework/TypeIdHelpers.h" -#include "Framework/CompilerBuiltins.h" +#ifndef FRAMEWORK_CONTEXTREGISTRY_H +#define FRAMEWORK_CONTEXTREGISTRY_H #include #include @@ -23,7 +20,9 @@ #include #include -namespace o2::framework +namespace o2 +{ +namespace framework { /// @class ContextRegistry @@ -31,16 +30,9 @@ namespace o2::framework /// Decouples getting the various contextes from the actual type /// of context, so that the DataAllocator does not need to know /// about the various serialization methods. +/// class ContextRegistry { - using ContextElementPtr = void*; - /// 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_CONTEXT_ELEMENTS = 256; - /// The mask to use to calculate the initial slot id. - constexpr static int MAX_ELEMENTS_MASK = MAX_CONTEXT_ELEMENTS - 1; - public: ContextRegistry(); @@ -50,22 +42,16 @@ class ContextRegistry set(std::forward(instances)...); } - /// 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 - /// should not be a problem. template T* get() const { - constexpr auto typeHash = TypeIdHelpers::uniqueId>(); - constexpr auto elementId = typeHash & MAX_ELEMENTS_MASK; - for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { - if (mElements[i + elementId].first == typeHash) { - return reinterpret_cast(mElements[i + elementId].second); + void* instance = nullptr; + for (size_t i = 0; i < mRegistryCount; ++i) { + if (mRegistryKey[i] == typeid(T*).hash_code()) { + return reinterpret_cast(mRegistryValue[i]); } } - throw std::runtime_error(std::string("Unable to find context element of kind ") + - typeid(T).name() + - " did you register one?"); + throw std::out_of_range(std::string("Unsupported backend, no registered context '") + typeid(T).name() + "'"); } template @@ -75,31 +61,31 @@ class ContextRegistry set(std::forward(more)...); } - // 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. - // The fact we use a bare pointer indicates that the ownership - // of the service still belongs to whatever created it, and is - // not passed to the registry. It's therefore responsibility of - // the creator of the service to properly dispose it. template - void set(T* element) + void set(T* instance) { static_assert(std::is_void::value == false, "can not register a void object"); - constexpr auto typeHash = TypeIdHelpers::uniqueId>(); - constexpr auto elementId = typeHash & MAX_ELEMENTS_MASK; - for (uint8_t i = 0; i < MAX_DISTANCE; ++i) { - if (mElements[i + elementId].second == nullptr) { - mElements[i + elementId].first = typeHash; - mElements[i + elementId].second = reinterpret_cast(element); + size_t i = 0; + for (i = 0; i < mRegistryCount; ++i) { + if (typeid(T*).hash_code() == mRegistryKey[i]) { return; } } - O2_BUILTIN_UNREACHABLE(); + if (i == MAX_REGISTRY_SIZE) { + throw std::runtime_error("Too many entries in ContextRegistry"); + } + mRegistryCount = i + 1; + mRegistryKey[i] = typeid(T*).hash_code(); + mRegistryValue[i] = instance; } + private: - std::array, MAX_CONTEXT_ELEMENTS + MAX_DISTANCE> mElements; + static constexpr size_t MAX_REGISTRY_SIZE = 8; + size_t mRegistryCount = 0; + std::array mRegistryKey; + std::array mRegistryValue; }; -} // namespace o2::framework -#endif // O2_FRAMEWORK_CONTEXTREGISTRY_H_ +} // namespace framework +} // namespace o2 +#endif // FRAMEWORK_CONTEXTREGISTRY_H diff --git a/Framework/Core/include/Framework/ServiceRegistry.h b/Framework/Core/include/Framework/ServiceRegistry.h index 5d136513796ad..72db44056181a 100644 --- a/Framework/Core/include/Framework/ServiceRegistry.h +++ b/Framework/Core/include/Framework/ServiceRegistry.h @@ -126,8 +126,8 @@ class ServiceRegistry } private: - std::array, MAX_SERVICES + MAX_DISTANCE> mServices; - std::array, MAX_SERVICES + MAX_DISTANCE> mConstServices; + std::array, MAX_SERVICES + MAX_DISTANCE> mServices; + std::array, MAX_SERVICES + MAX_DISTANCE> mConstServices; }; } // namespace o2::framework diff --git a/Framework/Foundation/include/Framework/TypeIdHelpers.h b/Framework/Foundation/include/Framework/TypeIdHelpers.h index 7b9d96f2fdfd7..8d32bd3a1a97a 100644 --- a/Framework/Foundation/include/Framework/TypeIdHelpers.h +++ b/Framework/Foundation/include/Framework/TypeIdHelpers.h @@ -11,60 +11,20 @@ #ifndef O2_FRAMEWORK_TYPEIDHELPERS_H_ #define O2_FRAMEWORK_TYPEIDHELPERS_H_ -#include -#include +#include "Framework/StringHelpers.h" namespace o2::framework { -/// helper to get constexpr unique string and typeid from a given type -/// Adapted from https://github.com/Manu343726/ctti -struct TypeIdHelpers { - // From https://github.com/foonathan/string_id. As usually, thanks Jonathan. - - using hash_t = uint64_t; - - // See http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - constexpr static hash_t fnv_basis = 14695981039346656037ull; - constexpr static hash_t fnv_prime = 1099511628211ull; - - // FNV-1a 64 bit hash - constexpr static hash_t fnv1a_hash(size_t n, const char* str, hash_t hash = fnv_basis) - { - return n > 0 ? fnv1a_hash(n - 1, str + 1, (hash ^ *str) * fnv_prime) : hash; - } - template - constexpr static hash_t fnv1a_hash(const char (&array)[N]) - { - return fnv1a_hash(N - 1, &array[0]); - } - - struct cstring { - template - constexpr cstring(const char (&str)[N]) : str{&str[0]}, - length{N - 1} - { - } - - constexpr hash_t hash() const - { - return TypeIdHelpers::fnv1a_hash(length, str); - } - - const char* str; - size_t length; - }; +struct TypeIdHelpers { + /// Return a unique id for a given type + /// This works just fine with GCC and CLANG, + /// C++20 will allow us to use: + /// std::experimental::source_location::current().function_name(); template - constexpr static cstring typeName() - { - return {__PRETTY_FUNCTION__}; - } - - template - constexpr static size_t uniqueId() + constexpr static uint32_t uniqueId() { - constexpr auto h = typeName().hash(); - return h; + return compile_time_hash(__PRETTY_FUNCTION__); } };