util/Intrusive{List,HashSet}: reimplement hook mode detection with implicit cast

This commit is contained in:
Max Kellermann 2023-08-02 23:25:50 +02:00 committed by Max Kellermann
parent 43d633f560
commit dcd7c6337c
2 changed files with 28 additions and 36 deletions

View File

@ -25,29 +25,26 @@ struct IntrusiveHashSetHook {
}
};
/**
* Detect the hook type.
*/
template<typename U>
struct IntrusiveHashSetHookDetection {
/* TODO can this be simplified somehow, without checking for
all possible enum values? */
using type = std::conditional_t<std::is_base_of_v<IntrusiveHashSetHook<IntrusiveHookMode::NORMAL>, U>,
IntrusiveHashSetHook<IntrusiveHookMode::NORMAL>,
std::conditional_t<std::is_base_of_v<IntrusiveHashSetHook<IntrusiveHookMode::TRACK>, U>,
IntrusiveHashSetHook<IntrusiveHookMode::TRACK>,
std::conditional_t<std::is_base_of_v<IntrusiveHashSetHook<IntrusiveHookMode::AUTO_UNLINK>, U>,
IntrusiveHashSetHook<IntrusiveHookMode::AUTO_UNLINK>,
void>>>;
};
/**
* For classes which embed #IntrusiveHashSetHook as base class.
*/
template<typename T>
struct IntrusiveHashSetBaseHookTraits {
/* a never-called helper function which is used by _Cast() */
template<IntrusiveHookMode mode>
static constexpr IntrusiveHashSetHook<mode> _Identity(const IntrusiveHashSetHook<mode> &) noexcept;
/* another never-called helper function which "calls"
_Identity(), implicitly casting the item to the
IntrusiveHashSetHook specialization; we use this to detect
which IntrusiveHashSetHook specialization is used */
template<typename U>
using Hook = typename IntrusiveHashSetHookDetection<U>::type;
static constexpr auto _Cast(const U &u) noexcept {
return decltype(_Identity(u))();
}
template<typename U>
using Hook = decltype(_Cast(std::declval<U>()));
static constexpr T *Cast(Hook<T> *node) noexcept {
return static_cast<T *>(node);

View File

@ -77,31 +77,26 @@ using SafeLinkIntrusiveListHook =
using AutoUnlinkIntrusiveListHook =
IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>;
/**
* Detect the hook type which is embedded in the given type as a base
* class. This is a template to postpone the type checks, to allow
* forward-declared types.
*/
template<typename U>
struct IntrusiveListHookDetection {
/* TODO can this be simplified somehow, without checking for
all possible enum values? */
using type = std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::NORMAL>, U>,
IntrusiveListHook<IntrusiveHookMode::NORMAL>,
std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::TRACK>, U>,
IntrusiveListHook<IntrusiveHookMode::TRACK>,
std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>, U>,
IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>,
void>>>;
};
/**
* For classes which embed #IntrusiveListHook as base class.
*/
template<typename T>
struct IntrusiveListBaseHookTraits {
/* a never-called helper function which is used by _Cast() */
template<IntrusiveHookMode mode>
static constexpr IntrusiveListHook<mode> _Identity(const IntrusiveListHook<mode> &) noexcept;
/* another never-called helper function which "calls"
_Identity(), implicitly casting the item to the
IntrusiveListHook specialization; we use this to detect
which IntrusiveListHook specialization is used */
template<typename U>
using Hook = typename IntrusiveListHookDetection<U>::type;
static constexpr auto _Cast(const U &u) noexcept {
return decltype(_Identity(u))();
}
template<typename U>
using Hook = decltype(_Cast(std::declval<U>()));
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
auto *hook = &Hook<T>::Cast(*node);