Commit 9a519751 authored by Dmytro Stechenko's avatar Dmytro Stechenko Committed by Facebook GitHub Bot

Add subset to superset badge lifting

Summary:
Conversion for cases when we have a `folly::any_badge<A, B>` and want to call some function that accepts `folly::any_badge<A, B, C>`.
```
void call_superset(folly::any_badge<A, B, C>);
void call_subset(folly::any_badge<A, B> badges) { call_superset(badges); }

// somewhere in A class
call_subset(folly::badge<A>{});

// somewhere in B class
call_subset(folly::badge<B>{});
```

Also establish bidirectional conversions between `folly::badge<A>` and `folly::any_badge<A>`.

Reviewed By: yfeldblum

Differential Revision: D32697212

fbshipit-source-id: 2f55d0b5015e133166fcdd6d9c25a0e396c2a151
parent 4faac360
......@@ -22,6 +22,9 @@
namespace folly {
template <typename... Holders>
class any_badge;
/**
* Badge pattern allows us to abstract over friend classes and make friend
* feature more scoped. Using this simple technique we can specify a badge tag
......@@ -50,13 +53,19 @@ namespace folly {
*/
template <typename Holder>
class badge {
public:
friend Holder;
badge() noexcept {}
/* implicit */ badge(any_badge<Holder>) noexcept {}
private:
/* implicit */ badge() noexcept {}
};
/**
* For cases when multiple badge holders need to call a function we can
* use folly::any_badge over each individual holder allowed.
* We allow subsets of badges to lift into supersets:
* folly::any_badge<A, B> lifts into folly::any_badge<A, B, C>.
*
* Example:
* class ProtectedClass: {
......@@ -76,8 +85,14 @@ class any_badge {
public:
template <
typename Holder,
std::enable_if_t<folly::IsOneOf<Holder, Holders...>::value, int> = 0>
typename = std::enable_if_t<folly::IsOneOf<Holder, Holders...>::value>>
/* implicit */ any_badge(badge<Holder>) noexcept {}
template <
typename... OtherHolders,
typename = std::enable_if_t<folly::StrictConjunction<
folly::IsOneOf<OtherHolders, Holders...>...>::value>>
/* implicit */ any_badge(any_badge<OtherHolders...>) noexcept {}
};
} // namespace folly
......@@ -23,26 +23,38 @@ namespace {
class FriendClass;
class OtherFriendClass;
class DummyClass;
using SingleBadge = folly::badge<FriendClass>;
using OtherSingleBadge = folly::badge<OtherFriendClass>;
using MultipleBadges = folly::any_badge<FriendClass, OtherFriendClass>;
using SubsetBadges = folly::any_badge<FriendClass, OtherFriendClass>;
using SupersetBadges =
folly::any_badge<FriendClass, OtherFriendClass, DummyClass>;
class ProtectedClass {
public:
static void single(SingleBadge) {}
static void multiple(MultipleBadges) {}
static void subset(SubsetBadges badges) { superset(badges); }
static void superset(SupersetBadges) {}
};
class FriendClass {
public:
static void single() { ProtectedClass::single({}); }
static void single() {
ProtectedClass::single({});
folly::any_badge<FriendClass> badge = SingleBadge{};
ProtectedClass::single(badge);
}
static void multiple() { ProtectedClass::multiple(SingleBadge{}); }
static void subset() { ProtectedClass::subset(SingleBadge{}); }
};
class OtherFriendClass {
public:
static void multiple() { ProtectedClass::multiple(OtherSingleBadge{}); }
static void subset() { ProtectedClass::subset(OtherSingleBadge{}); }
};
} // namespace
......@@ -65,3 +77,13 @@ TEST(BadgeTest, test_multiple_badges) {
FriendClass::multiple();
OtherFriendClass::multiple();
}
TEST(BadgeTest, test_subset_badges) {
// check a badge cannot be constructed outside of the context
EXPECT_FALSE(std::is_default_constructible_v<SubsetBadges>);
EXPECT_FALSE(std::is_default_constructible_v<SupersetBadges>);
// check a badge subset can be converted to superset anywhere
FriendClass::subset();
OtherFriendClass::subset();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment