AK: Allow Badge to accept multiple types

This lets public APIs name several authorized classes. Callers no longer
need duplicate overloads for one badge.
This commit is contained in:
Sam Atkins 2026-06-10 12:00:44 +01:00 committed by Jelle Raaijmakers
parent ae04222247
commit ad3d65b834
3 changed files with 165 additions and 2 deletions

View file

@ -11,8 +11,11 @@
namespace AK {
template<typename...>
class Badge;
template<typename T>
class Badge {
class Badge<T> {
AK_MAKE_NONCOPYABLE(Badge);
AK_MAKE_NONMOVABLE(Badge);
@ -24,6 +27,58 @@ private:
constexpr Badge() = default;
};
// FIXME: These overloads are all because compiler support for `friend Ts...;` is limited.
// Once compilers can do that, we should only need a single variadic template.
template<typename T, typename U>
class Badge<T, U> {
AK_MAKE_NONCOPYABLE(Badge);
AK_MAKE_NONMOVABLE(Badge);
private:
friend T;
friend U;
constexpr Badge() = default;
};
template<typename T, typename U, typename V>
class Badge<T, U, V> {
AK_MAKE_NONCOPYABLE(Badge);
AK_MAKE_NONMOVABLE(Badge);
private:
friend T;
friend U;
friend V;
constexpr Badge() = default;
};
template<typename T, typename U, typename V, typename W>
class Badge<T, U, V, W> {
AK_MAKE_NONCOPYABLE(Badge);
AK_MAKE_NONMOVABLE(Badge);
private:
friend T;
friend U;
friend V;
friend W;
constexpr Badge() = default;
};
template<typename T, typename U, typename V, typename W, typename X>
class Badge<T, U, V, W, X> {
AK_MAKE_NONCOPYABLE(Badge);
AK_MAKE_NONMOVABLE(Badge);
private:
friend T;
friend U;
friend V;
friend W;
friend X;
constexpr Badge() = default;
};
}
#if USING_AK_GLOBALLY

View file

@ -112,7 +112,7 @@ class HashMap;
template<typename K, typename V, typename KeyTraits = Traits<K>, typename ValueTraits = Traits<V>>
using OrderedHashMap = HashMap<K, V, KeyTraits, ValueTraits, true>;
template<typename T>
template<typename... Ts>
class Badge;
template<typename T>

View file

@ -8,7 +8,115 @@
#include <AK/Badge.h>
namespace {
struct MultipleBadgeUserA {
static void call_two_argument_badge();
static void call_three_argument_badge();
static void call_four_argument_badge();
static void call_five_argument_badge();
};
struct MultipleBadgeUserB {
static void call_two_argument_badge();
};
struct MultipleBadgeUserC {
static void call_three_argument_badge();
};
struct MultipleBadgeUserD {
static void call_four_argument_badge();
};
struct MultipleBadgeUserE {
static void call_five_argument_badge();
};
struct UnrelatedBadgeUser {
};
static void accepts_two_argument_badge(Badge<MultipleBadgeUserA, MultipleBadgeUserB>)
{
}
static void accepts_three_argument_badge(Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC>)
{
}
static void accepts_four_argument_badge(Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC, MultipleBadgeUserD>)
{
}
static void accepts_five_argument_badge(Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC, MultipleBadgeUserD, MultipleBadgeUserE>)
{
}
void MultipleBadgeUserA::call_two_argument_badge()
{
accepts_two_argument_badge({});
}
void MultipleBadgeUserA::call_three_argument_badge()
{
accepts_three_argument_badge({});
}
void MultipleBadgeUserA::call_four_argument_badge()
{
accepts_four_argument_badge({});
}
void MultipleBadgeUserA::call_five_argument_badge()
{
accepts_five_argument_badge({});
}
void MultipleBadgeUserB::call_two_argument_badge()
{
accepts_two_argument_badge({});
}
void MultipleBadgeUserC::call_three_argument_badge()
{
accepts_three_argument_badge({});
}
void MultipleBadgeUserD::call_four_argument_badge()
{
accepts_four_argument_badge({});
}
void MultipleBadgeUserE::call_five_argument_badge()
{
accepts_five_argument_badge({});
}
}
TEST_CASE(should_provide_underlying_type)
{
static_assert(IsSame<int, Badge<int>::Type>);
}
TEST_CASE(should_allow_multiple_underlying_types)
{
static_assert(!IsConstructible<Badge<MultipleBadgeUserA, MultipleBadgeUserB>>);
static_assert(!IsConstructible<Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC>>);
static_assert(!IsConstructible<Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC, MultipleBadgeUserD>>);
static_assert(!IsConstructible<Badge<MultipleBadgeUserA, MultipleBadgeUserB>, Badge<MultipleBadgeUserA>>);
static_assert(!IsConstructible<Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC, MultipleBadgeUserD, MultipleBadgeUserE>>);
static_assert(!IsConstructible<
Badge<MultipleBadgeUserA, MultipleBadgeUserB, MultipleBadgeUserC, MultipleBadgeUserD, MultipleBadgeUserE>,
Badge<MultipleBadgeUserA> const&>);
static_assert(!IsConstructible<Badge<MultipleBadgeUserA, MultipleBadgeUserB>, Badge<UnrelatedBadgeUser>>);
MultipleBadgeUserA::call_two_argument_badge();
MultipleBadgeUserA::call_three_argument_badge();
MultipleBadgeUserA::call_four_argument_badge();
MultipleBadgeUserA::call_five_argument_badge();
MultipleBadgeUserB::call_two_argument_badge();
MultipleBadgeUserC::call_three_argument_badge();
MultipleBadgeUserD::call_four_argument_badge();
MultipleBadgeUserE::call_five_argument_badge();
}