зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1500811 - Variant::as()&&, match()&& - r=sg
`as<...>()` on an rvalue variant returns the contained value as rvalue-reference. `match()` on an rvalue variant forwards the contained value as rvalue-reference. So now the contained values can be efficiently moved-from. There are also equivalents for `const&&`, which should be rare. For `match(2+ matchers)`, the static_assert for same return types has been moved to `Impl::matchN`. Also, it doesn't rely on `FunctionTypeTraits` anymore, which has the added benefit of allowing `auto` in individual matchers. Differential Revision: https://phabricator.services.mozilla.com/D98050
This commit is contained in:
Родитель
32c0d65819
Коммит
0e7e45ed66
196
mfbt/Variant.h
196
mfbt/Variant.h
|
@ -10,7 +10,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/FunctionTypeTraits.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
|
@ -179,22 +178,28 @@ struct VariantImplementation<Tag, N, T> {
|
|||
}
|
||||
|
||||
template <typename Matcher, typename ConcreteVariant>
|
||||
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
|
||||
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant&& aV) {
|
||||
if constexpr (std::is_invocable_v<Matcher, Tag,
|
||||
decltype(aV.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(Tag(N), aV.template as<N>());
|
||||
decltype(std::forward<ConcreteVariant>(aV)
|
||||
.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(
|
||||
Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
} else {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
return std::forward<Matcher>(aMatcher)(
|
||||
std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ConcreteVariant, typename Matcher>
|
||||
static decltype(auto) matchN(ConcreteVariant& aV, Matcher&& aMatcher) {
|
||||
static decltype(auto) matchN(ConcreteVariant&& aV, Matcher&& aMatcher) {
|
||||
if constexpr (std::is_invocable_v<Matcher, Tag,
|
||||
decltype(aV.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(Tag(N), aV.template as<N>());
|
||||
decltype(std::forward<ConcreteVariant>(aV)
|
||||
.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(
|
||||
Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
} else {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
return std::forward<Matcher>(aMatcher)(
|
||||
std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -248,13 +253,17 @@ struct VariantImplementation<Tag, N, T, Ts...> {
|
|||
}
|
||||
|
||||
template <typename Matcher, typename ConcreteVariant>
|
||||
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
|
||||
static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant&& aV) {
|
||||
if (aV.template is<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>());
|
||||
decltype(
|
||||
std::forward<ConcreteVariant>(aV)
|
||||
.template as<N>())>) {
|
||||
return std::forward<Matcher>(aMatcher)(
|
||||
Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
} else {
|
||||
return std::forward<Matcher>(aMatcher)(aV.template as<N>());
|
||||
return std::forward<Matcher>(aMatcher)(
|
||||
std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
}
|
||||
} else {
|
||||
// If you're seeing compilation errors here like "no matching
|
||||
|
@ -266,18 +275,38 @@ struct VariantImplementation<Tag, N, T, Ts...> {
|
|||
// return object of type <...> with an rvalue of type <...>" then that
|
||||
// means that the Matcher::operator()(T&) overloads are returning
|
||||
// different types. They must all return the same type.
|
||||
return Next::match(std::forward<Matcher>(aMatcher), aV);
|
||||
return Next::match(std::forward<Matcher>(aMatcher),
|
||||
std::forward<ConcreteVariant>(aV));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ConcreteVariant, typename Mi, typename... Ms>
|
||||
static decltype(auto) matchN(ConcreteVariant& aV, Mi&& aMi, Ms&&... aMs) {
|
||||
static decltype(auto) matchN(ConcreteVariant&& aV, Mi&& aMi, Ms&&... aMs) {
|
||||
if (aV.template is<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>());
|
||||
decltype(
|
||||
std::forward<ConcreteVariant>(aV)
|
||||
.template as<N>())>) {
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(std::forward<Mi>(aMi)(
|
||||
Tag(N),
|
||||
std::forward<ConcreteVariant>(aV).template as<N>())),
|
||||
decltype(Next::matchN(std::forward<ConcreteVariant>(aV),
|
||||
std::forward<Ms>(aMs)...))>,
|
||||
"all matchers must have the same return type");
|
||||
return std::forward<Mi>(aMi)(
|
||||
Tag(N), std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
} else {
|
||||
return std::forward<Mi>(aMi)(aV.template as<N>());
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(std::forward<Mi>(aMi)(
|
||||
std::forward<ConcreteVariant>(aV).template as<N>())),
|
||||
decltype(Next::matchN(std::forward<ConcreteVariant>(aV),
|
||||
std::forward<Ms>(aMs)...))>,
|
||||
"all matchers must have the same return type");
|
||||
return std::forward<Mi>(aMi)(
|
||||
std::forward<ConcreteVariant>(aV).template as<N>());
|
||||
}
|
||||
} else {
|
||||
// If you're seeing compilation errors here like "no matching
|
||||
|
@ -285,7 +314,8 @@ struct VariantImplementation<Tag, N, T, Ts...> {
|
|||
// Matchers don't exhaust all variant types. There must exist a
|
||||
// Matcher (with its operator()(T&)) for every variant type T, in the
|
||||
// exact same order.
|
||||
return Next::matchN(aV, std::forward<Ms>(aMs)...);
|
||||
return Next::matchN(std::forward<ConcreteVariant>(aV),
|
||||
std::forward<Ms>(aMs)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -706,9 +736,9 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
|||
|
||||
// Accessors for working with the contained variant value.
|
||||
|
||||
/** Mutable reference. */
|
||||
/** Mutable lvalue-reference. */
|
||||
template <typename T>
|
||||
T& as() {
|
||||
T& as() & {
|
||||
static_assert(
|
||||
detail::SelectVariantType<T, Ts...>::count == 1,
|
||||
"provided a type not uniquely found in this Variant's type list");
|
||||
|
@ -717,16 +747,16 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
|||
}
|
||||
|
||||
template <size_t N>
|
||||
typename detail::Nth<N, Ts...>::Type& as() {
|
||||
typename detail::Nth<N, Ts...>::Type& as() & {
|
||||
static_assert(N < sizeof...(Ts),
|
||||
"provided an index outside of this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<N>());
|
||||
return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
|
||||
}
|
||||
|
||||
/** Immutable const reference. */
|
||||
/** Immutable const lvalue-reference. */
|
||||
template <typename T>
|
||||
const T& as() const {
|
||||
const T& as() const& {
|
||||
static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
|
||||
"provided a type not found in this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<T>());
|
||||
|
@ -734,13 +764,50 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
|||
}
|
||||
|
||||
template <size_t N>
|
||||
const typename detail::Nth<N, Ts...>::Type& as() const {
|
||||
const typename detail::Nth<N, Ts...>::Type& as() const& {
|
||||
static_assert(N < sizeof...(Ts),
|
||||
"provided an index outside of this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<N>());
|
||||
return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr());
|
||||
}
|
||||
|
||||
/** Mutable rvalue-reference. */
|
||||
template <typename T>
|
||||
T&& as() && {
|
||||
static_assert(
|
||||
detail::SelectVariantType<T, Ts...>::count == 1,
|
||||
"provided a type not uniquely found in this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<T>());
|
||||
return std::move(*static_cast<T*>(ptr()));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
typename detail::Nth<N, Ts...>::Type&& as() && {
|
||||
static_assert(N < sizeof...(Ts),
|
||||
"provided an index outside of this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<N>());
|
||||
return std::move(
|
||||
*static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr()));
|
||||
}
|
||||
|
||||
/** Immutable const rvalue-reference. */
|
||||
template <typename T>
|
||||
const T&& as() const&& {
|
||||
static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
|
||||
"provided a type not found in this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<T>());
|
||||
return std::move(*static_cast<const T*>(ptr()));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
const typename detail::Nth<N, Ts...>::Type&& as() const&& {
|
||||
static_assert(N < sizeof...(Ts),
|
||||
"provided an index outside of this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<N>());
|
||||
return std::move(
|
||||
*static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the contained variant value from this container into a temporary
|
||||
* value. On completion, the value in the variant will be in a
|
||||
|
@ -766,50 +833,52 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
|||
|
||||
// Exhaustive matching of all variant types on the contained value.
|
||||
|
||||
/** Match on an immutable const reference. */
|
||||
/** Match on an immutable const lvalue-reference. */
|
||||
template <typename Matcher>
|
||||
decltype(auto) match(Matcher&& aMatcher) const {
|
||||
decltype(auto) match(Matcher&& aMatcher) const& {
|
||||
return Impl::match(std::forward<Matcher>(aMatcher), *this);
|
||||
}
|
||||
|
||||
template <typename M0, typename M1, typename... Ms>
|
||||
decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const {
|
||||
static_assert(
|
||||
2 + sizeof...(Ms) == sizeof...(Ts),
|
||||
"Variant<T...>::match() takes either one callable argument that "
|
||||
"accepts every type T; or one for each type T, in order");
|
||||
static_assert(
|
||||
tl::And<std::is_same_v<typename FunctionTypeTraits<M0>::ReturnType,
|
||||
typename FunctionTypeTraits<M1>::ReturnType>,
|
||||
std::is_same_v<
|
||||
typename FunctionTypeTraits<M1>::ReturnType,
|
||||
typename FunctionTypeTraits<Ms>::ReturnType>...>::value,
|
||||
"all matchers must have the same return type");
|
||||
return Impl::matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
|
||||
std::forward<Ms>(aMs)...);
|
||||
decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const& {
|
||||
return matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
|
||||
std::forward<Ms>(aMs)...);
|
||||
}
|
||||
|
||||
/** Match on a mutable non-const reference. */
|
||||
/** Match on a mutable non-const lvalue-reference. */
|
||||
template <typename Matcher>
|
||||
decltype(auto) match(Matcher&& aMatcher) {
|
||||
decltype(auto) match(Matcher&& aMatcher) & {
|
||||
return Impl::match(std::forward<Matcher>(aMatcher), *this);
|
||||
}
|
||||
|
||||
template <typename M0, typename M1, typename... Ms>
|
||||
decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) {
|
||||
static_assert(
|
||||
2 + sizeof...(Ms) == sizeof...(Ts),
|
||||
"Variant<T...>::match() takes either one callable argument that "
|
||||
"accepts every type T; or one for each type T, in order");
|
||||
static_assert(
|
||||
tl::And<std::is_same_v<typename FunctionTypeTraits<M0>::ReturnType,
|
||||
typename FunctionTypeTraits<M1>::ReturnType>,
|
||||
std::is_same_v<
|
||||
typename FunctionTypeTraits<M0>::ReturnType,
|
||||
typename FunctionTypeTraits<Ms>::ReturnType>...>::value,
|
||||
"all matchers must have the same return type");
|
||||
return Impl::matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
|
||||
std::forward<Ms>(aMs)...);
|
||||
decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) & {
|
||||
return matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
|
||||
std::forward<Ms>(aMs)...);
|
||||
}
|
||||
|
||||
/** Match on an immutable const rvalue-reference. */
|
||||
template <typename Matcher>
|
||||
decltype(auto) match(Matcher&& aMatcher) const&& {
|
||||
return Impl::match(std::forward<Matcher>(aMatcher), std::move(*this));
|
||||
}
|
||||
|
||||
template <typename M0, typename M1, typename... Ms>
|
||||
decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) const&& {
|
||||
return matchN(std::move(*this), std::forward<M0>(aM0),
|
||||
std::forward<M1>(aM1), std::forward<Ms>(aMs)...);
|
||||
}
|
||||
|
||||
/** Match on a mutable non-const rvalue-reference. */
|
||||
template <typename Matcher>
|
||||
decltype(auto) match(Matcher&& aMatcher) && {
|
||||
return Impl::match(std::forward<Matcher>(aMatcher), std::move(*this));
|
||||
}
|
||||
|
||||
template <typename M0, typename M1, typename... Ms>
|
||||
decltype(auto) match(M0&& aM0, M1&& aM1, Ms&&... aMs) && {
|
||||
return matchN(std::move(*this), std::forward<M0>(aM0),
|
||||
std::forward<M1>(aM1), std::forward<Ms>(aMs)...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -820,6 +889,19 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
|||
mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) const {
|
||||
return mozilla::AddToHash(hashValue, tag);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename ConcreteVariant, typename M0, typename M1, typename... Ms>
|
||||
static decltype(auto) matchN(ConcreteVariant&& aVariant, M0&& aM0, M1&& aM1,
|
||||
Ms&&... aMs) {
|
||||
static_assert(
|
||||
2 + sizeof...(Ms) == sizeof...(Ts),
|
||||
"Variant<T...>::match() takes either one callable argument that "
|
||||
"accepts every type T; or one for each type T, in order");
|
||||
return Impl::matchN(std::forward<ConcreteVariant>(aVariant),
|
||||
std::forward<M0>(aM0), std::forward<M1>(aM1),
|
||||
std::forward<Ms>(aMs)...);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
using mozilla::MakeUnique;
|
||||
using mozilla::UniquePtr;
|
||||
using mozilla::Variant;
|
||||
|
@ -237,7 +239,10 @@ static void testDetails() {
|
|||
|
||||
static void testSimple() {
|
||||
printf("testSimple\n");
|
||||
Variant<uint32_t, uint64_t> v(uint64_t(1));
|
||||
using V = Variant<uint32_t, uint64_t>;
|
||||
|
||||
// Non-const lvalue.
|
||||
V v(uint64_t(1));
|
||||
MOZ_RELEASE_ASSERT(v.is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(!v.is<uint32_t>());
|
||||
MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);
|
||||
|
@ -245,8 +250,44 @@ static void testSimple() {
|
|||
MOZ_RELEASE_ASSERT(v.is<1>());
|
||||
MOZ_RELEASE_ASSERT(!v.is<0>());
|
||||
static_assert(std::is_same_v<decltype(v.as<1>()), uint64_t&>,
|
||||
"as<1>() should return a uint64_t");
|
||||
"v.as<1>() should return a uint64_t&");
|
||||
MOZ_RELEASE_ASSERT(v.as<1>() == 1);
|
||||
|
||||
// Const lvalue.
|
||||
const V& cv = v;
|
||||
MOZ_RELEASE_ASSERT(cv.is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(!cv.is<uint32_t>());
|
||||
MOZ_RELEASE_ASSERT(cv.as<uint64_t>() == 1);
|
||||
|
||||
MOZ_RELEASE_ASSERT(cv.is<1>());
|
||||
MOZ_RELEASE_ASSERT(!cv.is<0>());
|
||||
static_assert(std::is_same_v<decltype(cv.as<1>()), const uint64_t&>,
|
||||
"cv.as<1>() should return a const uint64_t&");
|
||||
MOZ_RELEASE_ASSERT(cv.as<1>() == 1);
|
||||
|
||||
// Non-const rvalue, using a function to create a temporary.
|
||||
auto MakeV = []() { return V(uint64_t(1)); };
|
||||
MOZ_RELEASE_ASSERT(MakeV().is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(!MakeV().is<uint32_t>());
|
||||
MOZ_RELEASE_ASSERT(MakeV().as<uint64_t>() == 1);
|
||||
|
||||
MOZ_RELEASE_ASSERT(MakeV().is<1>());
|
||||
MOZ_RELEASE_ASSERT(!MakeV().is<0>());
|
||||
static_assert(std::is_same_v<decltype(MakeV().as<1>()), uint64_t&&>,
|
||||
"MakeV().as<1>() should return a uint64_t&&");
|
||||
MOZ_RELEASE_ASSERT(MakeV().as<1>() == 1);
|
||||
|
||||
// Const rvalue, using a function to create a temporary.
|
||||
auto MakeCV = []() -> const V { return V(uint64_t(1)); };
|
||||
MOZ_RELEASE_ASSERT(MakeCV().is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(!MakeCV().is<uint32_t>());
|
||||
MOZ_RELEASE_ASSERT(MakeCV().as<uint64_t>() == 1);
|
||||
|
||||
MOZ_RELEASE_ASSERT(MakeCV().is<1>());
|
||||
MOZ_RELEASE_ASSERT(!MakeCV().is<0>());
|
||||
static_assert(std::is_same_v<decltype(MakeCV().as<1>()), const uint64_t&&>,
|
||||
"MakeCV().as<1>() should return a const uint64_t&&");
|
||||
MOZ_RELEASE_ASSERT(MakeCV().as<1>() == 1);
|
||||
}
|
||||
|
||||
static void testDuplicate() {
|
||||
|
@ -432,90 +473,249 @@ static void testEquality() {
|
|||
MOZ_RELEASE_ASSERT(v6 == v6);
|
||||
}
|
||||
|
||||
// Matcher that returns a description of how its call-operator was invoked.
|
||||
struct Describer {
|
||||
static const char* littleNonConst;
|
||||
static const char* mediumNonConst;
|
||||
static const char* bigNonConst;
|
||||
enum class ParameterSize { NA, U8, U32, U64 };
|
||||
enum class ParameterQualifier {
|
||||
NA,
|
||||
ParamLREF,
|
||||
ParamCLREF,
|
||||
ParamRREF,
|
||||
ParamCRREF
|
||||
};
|
||||
enum class ThisQualifier { NA, ThisLREF, ThisCLREF, ThisRREF, ThisCRREF };
|
||||
|
||||
static const char* littleConst;
|
||||
static const char* mediumConst;
|
||||
static const char* bigConst;
|
||||
using Result =
|
||||
std::tuple<ParameterSize, ParameterQualifier, ThisQualifier, uint64_t>;
|
||||
|
||||
static const char* littleRRef;
|
||||
static const char* mediumRRef;
|
||||
static const char* bigRRef;
|
||||
#define RESULT(SIZE, PQUAL, TQUAL, VALUE) \
|
||||
Describer::Result(Describer::ParameterSize::SIZE, \
|
||||
Describer::ParameterQualifier::PQUAL, \
|
||||
Describer::ThisQualifier::TQUAL, VALUE)
|
||||
|
||||
const char* operator()(const uint8_t&) & { return littleNonConst; }
|
||||
const char* operator()(const uint32_t&) & { return mediumNonConst; }
|
||||
const char* operator()(const uint64_t&) & { return bigNonConst; }
|
||||
#define CALL(TYPE, SIZE, PQUAL, TREF, TQUAL) \
|
||||
Result operator()(TYPE aValue) TREF { \
|
||||
return RESULT(SIZE, PQUAL, TQUAL, aValue); \
|
||||
}
|
||||
|
||||
const char* operator()(const uint8_t&) const& { return littleConst; }
|
||||
const char* operator()(const uint32_t&) const& { return mediumConst; }
|
||||
const char* operator()(const uint64_t&) const& { return bigConst; }
|
||||
// All combinations of possible call operators:
|
||||
// Every line, the parameter integer type changes.
|
||||
// Every 3 lines, the parameter type changes constness.
|
||||
// Every 6 lines, the parameter changes reference l/r-valueness.
|
||||
// Every 12 lines, the member function qualifier changes constness.
|
||||
// After 24 lines, the member function qualifier changes ref l/r-valueness.
|
||||
CALL(uint8_t&, U8, ParamLREF, &, ThisLREF)
|
||||
CALL(uint32_t&, U32, ParamLREF, &, ThisLREF)
|
||||
CALL(uint64_t&, U64, ParamLREF, &, ThisLREF)
|
||||
|
||||
const char* operator()(const uint8_t&) && { return littleRRef; }
|
||||
const char* operator()(const uint32_t&) && { return mediumRRef; }
|
||||
const char* operator()(const uint64_t&) && { return bigRRef; }
|
||||
CALL(const uint8_t&, U8, ParamCLREF, &, ThisLREF)
|
||||
CALL(const uint32_t&, U32, ParamCLREF, &, ThisLREF)
|
||||
CALL(const uint64_t&, U64, ParamCLREF, &, ThisLREF)
|
||||
|
||||
CALL(uint8_t&&, U8, ParamRREF, &, ThisLREF)
|
||||
CALL(uint32_t&&, U32, ParamRREF, &, ThisLREF)
|
||||
CALL(uint64_t&&, U64, ParamRREF, &, ThisLREF)
|
||||
|
||||
CALL(const uint8_t&&, U8, ParamCRREF, &, ThisLREF)
|
||||
CALL(const uint32_t&&, U32, ParamCRREF, &, ThisLREF)
|
||||
CALL(const uint64_t&&, U64, ParamCRREF, &, ThisLREF)
|
||||
|
||||
CALL(uint8_t&, U8, ParamLREF, const&, ThisCLREF)
|
||||
CALL(uint32_t&, U32, ParamLREF, const&, ThisCLREF)
|
||||
CALL(uint64_t&, U64, ParamLREF, const&, ThisCLREF)
|
||||
|
||||
CALL(const uint8_t&, U8, ParamCLREF, const&, ThisCLREF)
|
||||
CALL(const uint32_t&, U32, ParamCLREF, const&, ThisCLREF)
|
||||
CALL(const uint64_t&, U64, ParamCLREF, const&, ThisCLREF)
|
||||
|
||||
CALL(uint8_t&&, U8, ParamRREF, const&, ThisCLREF)
|
||||
CALL(uint32_t&&, U32, ParamRREF, const&, ThisCLREF)
|
||||
CALL(uint64_t&&, U64, ParamRREF, const&, ThisCLREF)
|
||||
|
||||
CALL(const uint8_t&&, U8, ParamCRREF, const&, ThisCLREF)
|
||||
CALL(const uint32_t&&, U32, ParamCRREF, const&, ThisCLREF)
|
||||
CALL(const uint64_t&&, U64, ParamCRREF, const&, ThisCLREF)
|
||||
|
||||
CALL(uint8_t&, U8, ParamLREF, &&, ThisRREF)
|
||||
CALL(uint32_t&, U32, ParamLREF, &&, ThisRREF)
|
||||
CALL(uint64_t&, U64, ParamLREF, &&, ThisRREF)
|
||||
|
||||
CALL(const uint8_t&, U8, ParamCLREF, &&, ThisRREF)
|
||||
CALL(const uint32_t&, U32, ParamCLREF, &&, ThisRREF)
|
||||
CALL(const uint64_t&, U64, ParamCLREF, &&, ThisRREF)
|
||||
|
||||
CALL(uint8_t&&, U8, ParamRREF, &&, ThisRREF)
|
||||
CALL(uint32_t&&, U32, ParamRREF, &&, ThisRREF)
|
||||
CALL(uint64_t&&, U64, ParamRREF, &&, ThisRREF)
|
||||
|
||||
CALL(const uint8_t&&, U8, ParamCRREF, &&, ThisRREF)
|
||||
CALL(const uint32_t&&, U32, ParamCRREF, &&, ThisRREF)
|
||||
CALL(const uint64_t&&, U64, ParamCRREF, &&, ThisRREF)
|
||||
|
||||
CALL(uint8_t&, U8, ParamLREF, const&&, ThisCRREF)
|
||||
CALL(uint32_t&, U32, ParamLREF, const&&, ThisCRREF)
|
||||
CALL(uint64_t&, U64, ParamLREF, const&&, ThisCRREF)
|
||||
|
||||
CALL(const uint8_t&, U8, ParamCLREF, const&&, ThisCRREF)
|
||||
CALL(const uint32_t&, U32, ParamCLREF, const&&, ThisCRREF)
|
||||
CALL(const uint64_t&, U64, ParamCLREF, const&&, ThisCRREF)
|
||||
|
||||
CALL(uint8_t&&, U8, ParamRREF, const&&, ThisCRREF)
|
||||
CALL(uint32_t&&, U32, ParamRREF, const&&, ThisCRREF)
|
||||
CALL(uint64_t&&, U64, ParamRREF, const&&, ThisCRREF)
|
||||
|
||||
CALL(const uint8_t&&, U8, ParamCRREF, const&&, ThisCRREF)
|
||||
CALL(const uint32_t&&, U32, ParamCRREF, const&&, ThisCRREF)
|
||||
CALL(const uint64_t&&, U64, ParamCRREF, const&&, ThisCRREF)
|
||||
|
||||
#undef CALL
|
||||
|
||||
// Catch-all, to verify that there is no call with any type other than the
|
||||
// expected ones above.
|
||||
template <typename Other>
|
||||
const char* operator()(const Other&) {
|
||||
Result operator()(const Other&) {
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return "uh?";
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const char* Describer::littleNonConst = "little non-const";
|
||||
const char* Describer::mediumNonConst = "medium non-const";
|
||||
const char* Describer::bigNonConst = "big non-const";
|
||||
|
||||
const char* Describer::littleConst = "little const";
|
||||
const char* Describer::mediumConst = "medium const";
|
||||
const char* Describer::bigConst = "big const";
|
||||
|
||||
const char* Describer::littleRRef = "little rvalue-ref";
|
||||
const char* Describer::mediumRRef = "medium rvalue-ref";
|
||||
const char* Describer::bigRRef = "big rvalue-ref";
|
||||
|
||||
static void testMatching() {
|
||||
printf("testMatching\n");
|
||||
using V = Variant<uint8_t, uint32_t, uint64_t>;
|
||||
|
||||
Describer desc;
|
||||
const Describer descConst;
|
||||
auto MakeDescriber = []() { return Describer(); };
|
||||
auto MakeConstDescriber = []() -> const Describer { return Describer(); };
|
||||
|
||||
V v1(uint8_t(1));
|
||||
V v2(uint32_t(2));
|
||||
V v3(uint64_t(3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc) == Describer::littleNonConst);
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc) == Describer::mediumNonConst);
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc) == Describer::bigNonConst);
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(descConst) == Describer::littleConst);
|
||||
MOZ_RELEASE_ASSERT(v2.match(descConst) == Describer::mediumConst);
|
||||
MOZ_RELEASE_ASSERT(v3.match(descConst) == Describer::bigConst);
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(Describer()) == Describer::littleRRef);
|
||||
MOZ_RELEASE_ASSERT(v2.match(Describer()) == Describer::mediumRRef);
|
||||
MOZ_RELEASE_ASSERT(v3.match(Describer()) == Describer::bigRRef);
|
||||
|
||||
const V& constRef1 = v1;
|
||||
const V& constRef2 = v2;
|
||||
const V& constRef3 = v3;
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc) == Describer::littleNonConst);
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc) == Describer::mediumNonConst);
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::bigNonConst);
|
||||
// Create a temporary variant by returning a copy of one.
|
||||
auto CopyV = [](const V& aV) { return aV; };
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(descConst) == Describer::littleConst);
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(descConst) == Describer::mediumConst);
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(descConst) == Describer::bigConst);
|
||||
// Create a temporary variant by returning a const copy of one.
|
||||
auto CopyConstV = [](const V& aV) -> const V { return aV; };
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(Describer()) == Describer::littleRRef);
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(Describer()) == Describer::mediumRRef);
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(Describer()) == Describer::bigRRef);
|
||||
// All combinations of possible calls:
|
||||
// Every line, the variant integer type changes.
|
||||
// Every 3 lines, the variant type changes constness.
|
||||
// Every 6 lines, the variant changes reference l/r-valueness.
|
||||
// Every 12 lines, the matcher changes constness.
|
||||
// After 24 lines, the matcher changes ref l/r-valueness.
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, ThisLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, ThisLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, ThisLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc) ==
|
||||
RESULT(U8, ParamCLREF, ThisLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc) ==
|
||||
RESULT(U32, ParamCLREF, ThisLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc) ==
|
||||
RESULT(U64, ParamCLREF, ThisLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) ==
|
||||
RESULT(U8, ParamRREF, ThisLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) ==
|
||||
RESULT(U32, ParamRREF, ThisLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) ==
|
||||
RESULT(U64, ParamRREF, ThisLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
|
||||
RESULT(U8, ParamCRREF, ThisLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
|
||||
RESULT(U32, ParamCRREF, ThisLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
|
||||
RESULT(U64, ParamCRREF, ThisLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(descConst) ==
|
||||
RESULT(U8, ParamLREF, ThisCLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(descConst) ==
|
||||
RESULT(U32, ParamLREF, ThisCLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(descConst) ==
|
||||
RESULT(U64, ParamLREF, ThisCLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(descConst) ==
|
||||
RESULT(U8, ParamCLREF, ThisCLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(descConst) ==
|
||||
RESULT(U32, ParamCLREF, ThisCLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(descConst) ==
|
||||
RESULT(U64, ParamCLREF, ThisCLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(descConst) ==
|
||||
RESULT(U8, ParamRREF, ThisCLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(descConst) ==
|
||||
RESULT(U32, ParamRREF, ThisCLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(descConst) ==
|
||||
RESULT(U64, ParamRREF, ThisCLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(descConst) ==
|
||||
RESULT(U8, ParamCRREF, ThisCLREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(descConst) ==
|
||||
RESULT(U32, ParamCRREF, ThisCLREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(descConst) ==
|
||||
RESULT(U64, ParamCRREF, ThisCLREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(MakeDescriber()) ==
|
||||
RESULT(U8, ParamLREF, ThisRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(MakeDescriber()) ==
|
||||
RESULT(U32, ParamLREF, ThisRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(MakeDescriber()) ==
|
||||
RESULT(U64, ParamLREF, ThisRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(MakeDescriber()) ==
|
||||
RESULT(U8, ParamCLREF, ThisRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(MakeDescriber()) ==
|
||||
RESULT(U32, ParamCLREF, ThisRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(MakeDescriber()) ==
|
||||
RESULT(U64, ParamCLREF, ThisRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(MakeDescriber()) ==
|
||||
RESULT(U8, ParamRREF, ThisRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(MakeDescriber()) ==
|
||||
RESULT(U32, ParamRREF, ThisRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(MakeDescriber()) ==
|
||||
RESULT(U64, ParamRREF, ThisRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(MakeDescriber()) ==
|
||||
RESULT(U8, ParamCRREF, ThisRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(MakeDescriber()) ==
|
||||
RESULT(U32, ParamCRREF, ThisRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(MakeDescriber()) ==
|
||||
RESULT(U64, ParamCRREF, ThisRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(MakeConstDescriber()) ==
|
||||
RESULT(U8, ParamLREF, ThisCRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(MakeConstDescriber()) ==
|
||||
RESULT(U32, ParamLREF, ThisCRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(MakeConstDescriber()) ==
|
||||
RESULT(U64, ParamLREF, ThisCRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(MakeConstDescriber()) ==
|
||||
RESULT(U8, ParamCLREF, ThisCRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(MakeConstDescriber()) ==
|
||||
RESULT(U32, ParamCLREF, ThisCRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(MakeConstDescriber()) ==
|
||||
RESULT(U64, ParamCLREF, ThisCRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(MakeConstDescriber()) ==
|
||||
RESULT(U8, ParamRREF, ThisCRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(MakeConstDescriber()) ==
|
||||
RESULT(U32, ParamRREF, ThisCRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(MakeConstDescriber()) ==
|
||||
RESULT(U64, ParamRREF, ThisCRREF, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(MakeConstDescriber()) ==
|
||||
RESULT(U8, ParamCRREF, ThisCRREF, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(MakeConstDescriber()) ==
|
||||
RESULT(U32, ParamCRREF, ThisCRREF, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(MakeConstDescriber()) ==
|
||||
RESULT(U64, ParamCRREF, ThisCRREF, 3));
|
||||
}
|
||||
|
||||
static void testMatchingLambda() {
|
||||
|
@ -523,21 +723,42 @@ static void testMatchingLambda() {
|
|||
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.
|
||||
// declared `mutable`).
|
||||
// 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& a) {
|
||||
switch (sizeof(a)) {
|
||||
case 1:
|
||||
return Describer::littleConst;
|
||||
case 4:
|
||||
return Describer::mediumConst;
|
||||
case 8:
|
||||
return Describer::bigConst;
|
||||
default:
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return "";
|
||||
auto desc = [](auto&& a) {
|
||||
if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
|
||||
return RESULT(U8, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
|
||||
return RESULT(U8, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
|
||||
return RESULT(U8, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
|
||||
return RESULT(U8, ParamCRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
|
||||
return RESULT(U32, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
|
||||
return RESULT(U32, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
|
||||
return RESULT(U32, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
|
||||
return RESULT(U32, ParamCRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
|
||||
return RESULT(U64, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
|
||||
return RESULT(U64, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
|
||||
return RESULT(U64, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
|
||||
return RESULT(U64, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -545,17 +766,34 @@ static void testMatchingLambda() {
|
|||
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);
|
||||
// Create a temporary variant by returning a copy of one.
|
||||
auto CopyV = [](const V& aV) { return aV; };
|
||||
|
||||
// Create a temporary variant by returning a const copy of one.
|
||||
auto CopyConstV = [](const V& aV) -> const V { return aV; };
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc) == RESULT(U8, ParamCLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc) == RESULT(U32, ParamCLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc) == RESULT(U64, ParamCLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) == RESULT(U8, ParamRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) == RESULT(U32, ParamRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) == RESULT(U64, ParamRREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
|
||||
RESULT(U8, ParamCRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
|
||||
RESULT(U32, ParamCRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
|
||||
RESULT(U64, ParamCRREF, NA, 3));
|
||||
}
|
||||
|
||||
static void testMatchingLambdaWithIndex() {
|
||||
|
@ -567,21 +805,51 @@ static void testMatchingLambdaWithIndex() {
|
|||
// 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) {
|
||||
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 "";
|
||||
if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return RESULT(U8, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return RESULT(U8, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return RESULT(U8, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return RESULT(U8, ParamCRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return RESULT(U32, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return RESULT(U32, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return RESULT(U32, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return RESULT(U32, ParamCRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return RESULT(U64, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return RESULT(U64, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return RESULT(U64, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return RESULT(U64, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -589,84 +857,245 @@ static void testMatchingLambdaWithIndex() {
|
|||
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);
|
||||
// Create a temporary variant by returning a copy of one.
|
||||
auto CopyV = [](const V& aV) { return aV; };
|
||||
|
||||
// Create a temporary variant by returning a const copy of one.
|
||||
auto CopyConstV = [](const V& aV) -> const V { return aV; };
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc) == RESULT(U8, ParamCLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc) == RESULT(U32, ParamCLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc) == RESULT(U64, ParamCLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) == RESULT(U8, ParamRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) == RESULT(U32, ParamRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) == RESULT(U64, ParamRREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
|
||||
RESULT(U8, ParamCRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
|
||||
RESULT(U32, ParamCRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
|
||||
RESULT(U64, ParamCRREF, NA, 3));
|
||||
}
|
||||
|
||||
static void testMatchingLambdas() {
|
||||
printf("testMatchingLambdas\n");
|
||||
using V = Variant<uint8_t, uint32_t, uint64_t>;
|
||||
|
||||
auto desc8 = [](const uint8_t& a) { return Describer::littleConst; };
|
||||
auto desc32 = [](const uint32_t& a) { return Describer::mediumConst; };
|
||||
auto desc64 = [](const uint64_t& a) { return Describer::bigConst; };
|
||||
auto desc8 = [](auto&& a) {
|
||||
if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
|
||||
return RESULT(U8, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
|
||||
return RESULT(U8, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
|
||||
return RESULT(U8, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
|
||||
return RESULT(U8, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
auto desc32 = [](auto&& a) {
|
||||
if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
|
||||
return RESULT(U32, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
|
||||
return RESULT(U32, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
|
||||
return RESULT(U32, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
|
||||
return RESULT(U32, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
auto desc64 = [](auto&& a) {
|
||||
if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
|
||||
return RESULT(U64, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
|
||||
return RESULT(U64, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
|
||||
return RESULT(U64, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
|
||||
return RESULT(U64, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// Create a temporary variant by returning a copy of one.
|
||||
auto CopyV = [](const V& aV) { return aV; };
|
||||
|
||||
// Create a temporary variant by returning a const copy of one.
|
||||
auto CopyConstV = [](const V& aV) -> const V { return aV; };
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) ==
|
||||
RESULT(U8, ParamLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) ==
|
||||
RESULT(U32, ParamLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) ==
|
||||
RESULT(U64, ParamLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
|
||||
Describer::littleConst);
|
||||
RESULT(U8, ParamCLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
|
||||
Describer::mediumConst);
|
||||
RESULT(U32, ParamCLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
|
||||
Describer::bigConst);
|
||||
RESULT(U64, ParamCLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(desc8, desc32, desc64) ==
|
||||
RESULT(U8, ParamRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(desc8, desc32, desc64) ==
|
||||
RESULT(U32, ParamRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(desc8, desc32, desc64) ==
|
||||
RESULT(U64, ParamRREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc8, desc32, desc64) ==
|
||||
RESULT(U8, ParamCRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc8, desc32, desc64) ==
|
||||
RESULT(U32, ParamCRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc8, desc32, desc64) ==
|
||||
RESULT(U64, ParamCRREF, NA, 3));
|
||||
}
|
||||
|
||||
static void testMatchingLambdasWithIndex() {
|
||||
printf("testMatchingLambdasWithIndex\n");
|
||||
using V = Variant<uint8_t, uint32_t, uint64_t>;
|
||||
|
||||
auto desc8 = [](size_t aIndex, const uint8_t& a) {
|
||||
auto desc8 = [](size_t aIndex, auto&& a) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 0);
|
||||
return Describer::littleConst;
|
||||
if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
|
||||
return RESULT(U8, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
|
||||
return RESULT(U8, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
|
||||
return RESULT(U8, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
|
||||
return RESULT(U8, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
auto desc32 = [](size_t aIndex, const uint32_t& a) {
|
||||
auto desc32 = [](size_t aIndex, auto&& a) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 1);
|
||||
return Describer::mediumConst;
|
||||
if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
|
||||
return RESULT(U32, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
|
||||
return RESULT(U32, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
|
||||
return RESULT(U32, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
|
||||
return RESULT(U32, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
auto desc64 = [](size_t aIndex, const uint64_t& a) {
|
||||
auto desc64 = [](size_t aIndex, auto&& a) {
|
||||
MOZ_RELEASE_ASSERT(aIndex == 2);
|
||||
return Describer::bigConst;
|
||||
if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
|
||||
return RESULT(U64, ParamLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
|
||||
return RESULT(U64, ParamCLREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
|
||||
return RESULT(U64, ParamRREF, NA, a);
|
||||
} else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
|
||||
return RESULT(U64, ParamCRREF, NA, a);
|
||||
} else {
|
||||
// We don't expect any other type.
|
||||
// Tech note: We can't just do `static_assert(false)` which would always
|
||||
// fail during the initial parsing. So we depend on the templated
|
||||
// parameter to delay computing `false` until actual instantiation.
|
||||
static_assert(sizeof(a) == size_t(-1));
|
||||
return RESULT(NA, NA, NA, 0);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// Create a temporary variant by returning a copy of one.
|
||||
auto CopyV = [](const V& aV) { return aV; };
|
||||
|
||||
// Create a temporary variant by returning a const copy of one.
|
||||
auto CopyConstV = [](const V& aV) -> const V { return aV; };
|
||||
|
||||
MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) ==
|
||||
RESULT(U8, ParamLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) ==
|
||||
RESULT(U32, ParamLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) ==
|
||||
RESULT(U64, ParamLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
|
||||
Describer::littleConst);
|
||||
RESULT(U8, ParamCLREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
|
||||
Describer::mediumConst);
|
||||
RESULT(U32, ParamCLREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
|
||||
Describer::bigConst);
|
||||
RESULT(U64, ParamCLREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyV(v1).match(desc8, desc32, desc64) ==
|
||||
RESULT(U8, ParamRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v2).match(desc8, desc32, desc64) ==
|
||||
RESULT(U32, ParamRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyV(v3).match(desc8, desc32, desc64) ==
|
||||
RESULT(U64, ParamRREF, NA, 3));
|
||||
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc8, desc32, desc64) ==
|
||||
RESULT(U8, ParamCRREF, NA, 1));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc8, desc32, desc64) ==
|
||||
RESULT(U32, ParamCRREF, NA, 2));
|
||||
MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc8, desc32, desc64) ==
|
||||
RESULT(U64, ParamCRREF, NA, 3));
|
||||
}
|
||||
|
||||
#undef RESULT
|
||||
|
||||
static void testAddTagToHash() {
|
||||
printf("testAddToHash\n");
|
||||
using V = Variant<uint8_t, uint16_t, uint32_t, uint64_t>;
|
||||
|
|
Загрузка…
Ссылка в новой задаче