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 @@ ...@@ -22,6 +22,9 @@
namespace folly { namespace folly {
template <typename... Holders>
class any_badge;
/** /**
* Badge pattern allows us to abstract over friend classes and make friend * 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 * feature more scoped. Using this simple technique we can specify a badge tag
...@@ -50,13 +53,19 @@ namespace folly { ...@@ -50,13 +53,19 @@ namespace folly {
*/ */
template <typename Holder> template <typename Holder>
class badge { class badge {
public:
friend Holder; 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 * For cases when multiple badge holders need to call a function we can
* use folly::any_badge over each individual holder allowed. * 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: * Example:
* class ProtectedClass: { * class ProtectedClass: {
...@@ -76,8 +85,14 @@ class any_badge { ...@@ -76,8 +85,14 @@ class any_badge {
public: public:
template < template <
typename Holder, 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 {} /* 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 } // namespace folly
...@@ -23,26 +23,38 @@ namespace { ...@@ -23,26 +23,38 @@ namespace {
class FriendClass; class FriendClass;
class OtherFriendClass; class OtherFriendClass;
class DummyClass;
using SingleBadge = folly::badge<FriendClass>; using SingleBadge = folly::badge<FriendClass>;
using OtherSingleBadge = folly::badge<OtherFriendClass>; using OtherSingleBadge = folly::badge<OtherFriendClass>;
using MultipleBadges = folly::any_badge<FriendClass, 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 { class ProtectedClass {
public: public:
static void single(SingleBadge) {} static void single(SingleBadge) {}
static void multiple(MultipleBadges) {} static void multiple(MultipleBadges) {}
static void subset(SubsetBadges badges) { superset(badges); }
static void superset(SupersetBadges) {}
}; };
class FriendClass { class FriendClass {
public: 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 multiple() { ProtectedClass::multiple(SingleBadge{}); }
static void subset() { ProtectedClass::subset(SingleBadge{}); }
}; };
class OtherFriendClass { class OtherFriendClass {
public: public:
static void multiple() { ProtectedClass::multiple(OtherSingleBadge{}); } static void multiple() { ProtectedClass::multiple(OtherSingleBadge{}); }
static void subset() { ProtectedClass::subset(OtherSingleBadge{}); }
}; };
} // namespace } // namespace
...@@ -65,3 +77,13 @@ TEST(BadgeTest, test_multiple_badges) { ...@@ -65,3 +77,13 @@ TEST(BadgeTest, test_multiple_badges) {
FriendClass::multiple(); FriendClass::multiple();
OtherFriendClass::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