Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 29 additions & 43 deletions Framework/Core/include/Framework/ContextRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typeinfo>
#include <typeindex>
Expand All @@ -23,24 +20,19 @@
#include <utility>
#include <array>

namespace o2::framework
namespace o2
{
namespace framework
{

/// @class ContextRegistry
/// Instances are registered by pointer and are not owned by the registry
/// 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();

Expand All @@ -50,22 +42,16 @@ class ContextRegistry
set(std::forward<Types*>(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 <typename T>
T* get() const
{
constexpr auto typeHash = TypeIdHelpers::uniqueId<std::decay_t<T>>();
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<T*>(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<T*>(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 <typename T, typename... Types>
Expand All @@ -75,31 +61,31 @@ class ContextRegistry
set(std::forward<Types*>(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 <typename T>
void set(T* element)
void set(T* instance)
{
static_assert(std::is_void<T>::value == false, "can not register a void object");
constexpr auto typeHash = TypeIdHelpers::uniqueId<std::decay_t<T>>();
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<ContextElementPtr>(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<std::pair<size_t, ContextElementPtr>, MAX_CONTEXT_ELEMENTS + MAX_DISTANCE> mElements;
static constexpr size_t MAX_REGISTRY_SIZE = 8;
size_t mRegistryCount = 0;
std::array<size_t, MAX_REGISTRY_SIZE> mRegistryKey;
std::array<void*, MAX_REGISTRY_SIZE> mRegistryValue;
};

} // namespace o2::framework
#endif // O2_FRAMEWORK_CONTEXTREGISTRY_H_
} // namespace framework
} // namespace o2
#endif // FRAMEWORK_CONTEXTREGISTRY_H
4 changes: 2 additions & 2 deletions Framework/Core/include/Framework/ServiceRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ class ServiceRegistry
}

private:
std::array<std::pair<size_t, ServicePtr>, MAX_SERVICES + MAX_DISTANCE> mServices;
std::array<std::pair<size_t, ConstServicePtr>, MAX_SERVICES + MAX_DISTANCE> mConstServices;
std::array<std::pair<uint32_t, ServicePtr>, MAX_SERVICES + MAX_DISTANCE> mServices;
std::array<std::pair<uint32_t, ConstServicePtr>, MAX_SERVICES + MAX_DISTANCE> mConstServices;
};

} // namespace o2::framework
Expand Down
56 changes: 8 additions & 48 deletions Framework/Foundation/include/Framework/TypeIdHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,20 @@
#ifndef O2_FRAMEWORK_TYPEIDHELPERS_H_
#define O2_FRAMEWORK_TYPEIDHELPERS_H_

#include <cstddef>
#include <cstdint>
#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 <size_t N>
constexpr static hash_t fnv1a_hash(const char (&array)[N])
{
return fnv1a_hash(N - 1, &array[0]);
}

struct cstring {
template <size_t N>
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 <typename T>
constexpr static cstring typeName()
{
return {__PRETTY_FUNCTION__};
}

template <typename TYPE>
constexpr static size_t uniqueId()
constexpr static uint32_t uniqueId()
{
constexpr auto h = typeName<TYPE>().hash();
return h;
return compile_time_hash(__PRETTY_FUNCTION__);
}
};

Expand Down