зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1621865 - Variant matchers may optionally take the current index as first parameter - r=froydnj
Depends on D66719 Differential Revision: https://phabricator.services.mozilla.com/D66720 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
9c1f5b9571
Коммит
056a867f22
|
@ -182,12 +182,22 @@ struct VariantImplementation<Tag, N, T> {
|
|||
|
||||
template <typename Matcher, typename ConcreteVariant>
|
||||
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
if constexpr (std::is_invocable_v<Matcher, Tag,
|
||||
decltype(aV.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(Tag(N), aV.template as<N>());
|
||||
} else {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ConcreteVariant, typename Matcher>
|
||||
static decltype(auto) matchN(ConcreteVariant& aV, Matcher&& aMatcher) {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
if constexpr (std::is_invocable_v<Matcher, Tag,
|
||||
decltype(aV.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(Tag(N), aV.template as<N>());
|
||||
} else {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -242,7 +252,12 @@ struct VariantImplementation<Tag, N, T, Ts...> {
|
|||
template <typename Matcher, typename ConcreteVariant>
|
||||
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
|
||||
if (aV.template is<N>()) {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
if constexpr (std::is_invocable_v<Matcher, Tag,
|
||||
decltype(aV.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(Tag(N), aV.template as<N>());
|
||||
} else {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
}
|
||||
} else {
|
||||
// If you're seeing compilation errors here like "no matching
|
||||
// function for call to 'match'" then that means that the
|
||||
|
@ -260,7 +275,12 @@ struct VariantImplementation<Tag, N, T, Ts...> {
|
|||
template <typename ConcreteVariant, typename Mi, typename... Ms>
|
||||
static decltype(auto) matchN(ConcreteVariant& aV, Mi&& aMi, Ms&&... aMs) {
|
||||
if (aV.template is<N>()) {
|
||||
return std::forward<Mi>(aMi)(aV.template as<N>());
|
||||
if constexpr (std::is_invocable_v<Mi, Tag,
|
||||
decltype(aV.template as<N>())>) {
|
||||
return std::forward<Mi>(aMi)(Tag(N), aV.template as<N>());
|
||||
} else {
|
||||
return std::forward<Mi>(aMi)(aV.template as<N>());
|
||||
}
|
||||
} else {
|
||||
// If you're seeing compilation errors here like "no matching
|
||||
// function for call to 'match'" then that means that the
|
||||
|
@ -462,7 +482,7 @@ struct VariantIndex {
|
|||
*
|
||||
* // In some situations, a single generic lambda may also be appropriate:
|
||||
* char* foo(Variant<A, B, C, D>& v) {
|
||||
* return v.match([](auto&){...});
|
||||
* return v.match([](auto&) {...});
|
||||
* }
|
||||
*
|
||||
* // Alternatively, multiple function objects may be provided, each one
|
||||
|
@ -474,6 +494,16 @@ struct VariantIndex {
|
|||
* [](D&) { ... });
|
||||
* }
|
||||
*
|
||||
* // In rare cases, the index of the currently-active alternative is
|
||||
* // needed, it may be obtained by adding a first parameter in the matcner
|
||||
* // callback, which will receive the index in its most compact type (just
|
||||
* // use `size_t` if the exact type is not important), e.g.:
|
||||
* char* foo(Variant<A, B, C, D>& v) {
|
||||
* return v.match([](auto aIndex, auto& aAlternative) {...});
|
||||
* // --OR--
|
||||
* return v.match([](size_t aIndex, auto& aAlternative) {...});
|
||||
* }
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* A tree is either an empty leaf, or a node with a value and two children:
|
||||
|
|
|
@ -550,6 +550,50 @@ static void testMatchingLambda() {
|
|||
MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::bigConst);
|
||||
}
|
||||
|
||||
static void testMatchingLambdaWithIndex() {
|
||||
printf("testMatchingLambdaWithIndex\n");
|
||||
using V = Variant<uint8_t, uint32_t, uint64_t>;
|
||||
|
||||
// Note: Lambdas' call operators are const by default (unless the lambda is
|
||||
// declared `mutable`), hence the use of "...Const" strings below.
|
||||
// There is no need to test mutable lambdas, nor rvalue lambda, because there
|
||||
// would be no way to distinguish how each lambda is actually invoked because
|
||||
// there is only one choice of call operator in each overload set.
|
||||
auto desc = [](auto aIndex, auto& a) {
|
||||
static_assert(sizeof(aIndex) < sizeof(size_t), "Expected small index type");
|
||||
switch (sizeof(a)) {
|
||||
case 1:
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return Describer::littleConst;
|
||||
case 4:
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return Describer::mediumConst;
|
||||
case 8:
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return Describer::bigConst;
|
||||
default:
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
V v1(uint8_t(1));
|
||||
V v2(uint32_t(2));
|
||||
V v3(uint64_t(3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc) == Describer::littleConst);
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc) == Describer::mediumConst);
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc) == Describer::bigConst);
|
||||
|
||||
const V& constRef1 = v1;
|
||||
const V& constRef2 = v2;
|
||||
const V& constRef3 = v3;
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc) == Describer::littleConst);
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc) == Describer::mediumConst);
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::bigConst);
|
||||
}
|
||||
|
||||
static void testMatchingLambdas() {
|
||||
printf("testMatchingLambdas\n");
|
||||
using V = Variant<uint8_t, uint32_t, uint64_t>;
|
||||
|
@ -578,6 +622,43 @@ static void testMatchingLambdas() {
|
|||
Describer::bigConst);
|
||||
}
|
||||
|
||||
static void testMatchingLambdasWithIndex() {
|
||||
printf("testMatchingLambdasWithIndex\n");
|
||||
using V = Variant<uint8_t, uint32_t, uint64_t>;
|
||||
|
||||
auto desc8 = [](size_t aIndex, const uint8_t& a) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return Describer::littleConst;
|
||||
};
|
||||
auto desc32 = [](size_t aIndex, const uint32_t& a) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return Describer::mediumConst;
|
||||
};
|
||||
auto desc64 = [](size_t aIndex, const uint64_t& a) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return Describer::bigConst;
|
||||
};
|
||||
|
||||
V v1(uint8_t(1));
|
||||
V v2(uint32_t(2));
|
||||
V v3(uint64_t(3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) == Describer::littleConst);
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) == Describer::mediumConst);
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) == Describer::bigConst);
|
||||
|
||||
const V& constRef1 = v1;
|
||||
const V& constRef2 = v2;
|
||||
const V& constRef3 = v3;
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
|
||||
Describer::littleConst);
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
|
||||
Describer::mediumConst);
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
|
||||
Describer::bigConst);
|
||||
}
|
||||
|
||||
static void testAddTagToHash() {
|
||||
printf("testAddToHash\n");
|
||||
using V = Variant<uint8_t, uint16_t, uint32_t, uint64_t>;
|
||||
|
@ -623,7 +704,9 @@ int main() {
|
|||
testEquality();
|
||||
testMatching();
|
||||
testMatchingLambda();
|
||||
testMatchingLambdaWithIndex();
|
||||
testMatchingLambdas();
|
||||
testMatchingLambdasWithIndex();
|
||||
testAddTagToHash();
|
||||
|
||||
printf("TestVariant OK!\n");
|
||||
|
|
Загрузка…
Ссылка в новой задаче