зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1338389 - Index-based Variant::is<N>, as<N>, and extract<N> - r=froydnj
MozReview-Commit-ID: C5iga0Eb1tH --HG-- extra : rebase_source : d88cf614318cc8544d7ab52315e015a7ca4e5efd
This commit is contained in:
Родитель
fd1e018417
Коммит
6015fbb5ac
|
@ -25,6 +25,22 @@ class Variant;
|
|||
|
||||
namespace detail {
|
||||
|
||||
// Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
|
||||
template<size_t N, typename... Ts>
|
||||
struct Nth;
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
struct Nth<0, T, Ts...>
|
||||
{
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
template<size_t N, typename T, typename... Ts>
|
||||
struct Nth<N, T, Ts...>
|
||||
{
|
||||
using Type = typename Nth<N - 1, Ts...>::Type;
|
||||
};
|
||||
|
||||
template <typename...>
|
||||
struct FirstTypeIsInRest;
|
||||
|
||||
|
@ -180,31 +196,31 @@ struct VariantImplementation<Tag, N, T>
|
|||
|
||||
template<typename Variant>
|
||||
static void copyConstruct(void* aLhs, const Variant& aRhs) {
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template as<T>());
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
|
||||
}
|
||||
|
||||
template<typename Variant>
|
||||
static void moveConstruct(void* aLhs, Variant&& aRhs) {
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template extract<T>());
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
|
||||
}
|
||||
|
||||
template<typename Variant>
|
||||
static void destroy(Variant& aV) {
|
||||
aV.template as<T>().~T();
|
||||
aV.template as<N>().~T();
|
||||
}
|
||||
|
||||
template<typename Variant>
|
||||
static bool
|
||||
equal(const Variant& aLhs, const Variant& aRhs) {
|
||||
return aLhs.template as<T>() == aRhs.template as<T>();
|
||||
return aLhs.template as<N>() == aRhs.template as<N>();
|
||||
}
|
||||
|
||||
template<typename Matcher, typename ConcreteVariant>
|
||||
static auto
|
||||
match(Matcher&& aMatcher, ConcreteVariant& aV)
|
||||
-> decltype(aMatcher.match(aV.template as<T>()))
|
||||
-> decltype(aMatcher.match(aV.template as<N>()))
|
||||
{
|
||||
return aMatcher.match(aV.template as<T>());
|
||||
return aMatcher.match(aV.template as<N>());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -222,8 +238,8 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
|
||||
template<typename Variant>
|
||||
static void copyConstruct(void* aLhs, const Variant& aRhs) {
|
||||
if (aRhs.template is<T>()) {
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template as<T>());
|
||||
if (aRhs.template is<N>()) {
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
|
||||
} else {
|
||||
Next::copyConstruct(aLhs, aRhs);
|
||||
}
|
||||
|
@ -231,8 +247,8 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
|
||||
template<typename Variant>
|
||||
static void moveConstruct(void* aLhs, Variant&& aRhs) {
|
||||
if (aRhs.template is<T>()) {
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template extract<T>());
|
||||
if (aRhs.template is<N>()) {
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
|
||||
} else {
|
||||
Next::moveConstruct(aLhs, Move(aRhs));
|
||||
}
|
||||
|
@ -240,8 +256,8 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
|
||||
template<typename Variant>
|
||||
static void destroy(Variant& aV) {
|
||||
if (aV.template is<T>()) {
|
||||
aV.template as<T>().~T();
|
||||
if (aV.template is<N>()) {
|
||||
aV.template as<N>().~T();
|
||||
} else {
|
||||
Next::destroy(aV);
|
||||
}
|
||||
|
@ -249,9 +265,9 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
|
||||
template<typename Variant>
|
||||
static bool equal(const Variant& aLhs, const Variant& aRhs) {
|
||||
if (aLhs.template is<T>()) {
|
||||
MOZ_ASSERT(aRhs.template is<T>());
|
||||
return aLhs.template as<T>() == aRhs.template as<T>();
|
||||
if (aLhs.template is<N>()) {
|
||||
MOZ_ASSERT(aRhs.template is<N>());
|
||||
return aLhs.template as<N>() == aRhs.template as<N>();
|
||||
} else {
|
||||
return Next::equal(aLhs, aRhs);
|
||||
}
|
||||
|
@ -260,10 +276,10 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
template<typename Matcher, typename ConcreteVariant>
|
||||
static auto
|
||||
match(Matcher&& aMatcher, ConcreteVariant& aV)
|
||||
-> decltype(aMatcher.match(aV.template as<T>()))
|
||||
-> decltype(aMatcher.match(aV.template as<N>()))
|
||||
{
|
||||
if (aV.template is<T>()) {
|
||||
return aMatcher.match(aV.template as<T>());
|
||||
if (aV.template is<N>()) {
|
||||
return aMatcher.match(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
|
||||
|
@ -349,6 +365,7 @@ struct AsVariantTemporary
|
|||
* Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
|
||||
*
|
||||
* All access to the contained value goes through type-safe accessors.
|
||||
* Either the stored type, or the type index may be provided.
|
||||
*
|
||||
* void
|
||||
* Foo(Variant<A, B, C> v)
|
||||
|
@ -356,6 +373,8 @@ struct AsVariantTemporary
|
|||
* if (v.is<A>()) {
|
||||
* A& ref = v.as<A>();
|
||||
* ...
|
||||
* } else (v.is<1>()) { // Same as v.is<B> in this case.
|
||||
* ...
|
||||
* } else {
|
||||
* ...
|
||||
* }
|
||||
|
@ -382,8 +401,8 @@ struct AsVariantTemporary
|
|||
* auto ptr = v.extract<UniquePtr<A>>();
|
||||
*
|
||||
* Finally, you can exhaustively match on the contained variant and branch into
|
||||
* different code paths depending which type is contained. This is preferred to
|
||||
* manually checking every variant type T with is<T>() because it provides
|
||||
* different code paths depending on which type is contained. This is preferred
|
||||
* to manually checking every variant type T with is<T>() because it provides
|
||||
* compile-time checking that you handled every type, rather than runtime
|
||||
* assertion failures.
|
||||
*
|
||||
|
@ -533,7 +552,7 @@ public:
|
|||
}
|
||||
|
||||
/** Move assignment from AsVariant(). */
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
|
||||
{
|
||||
this->~Variant();
|
||||
|
@ -554,6 +573,14 @@ public:
|
|||
return Impl::template tag<T>() == tag;
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
bool is() const
|
||||
{
|
||||
static_assert(N < sizeof...(Ts),
|
||||
"provided an index outside of this Variant's type list");
|
||||
return N == size_t(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator == overload that defers to the variant type's operator==
|
||||
* implementation if the rhs is tagged as the same type as this one.
|
||||
|
@ -582,6 +609,15 @@ public:
|
|||
return *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 *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
|
||||
}
|
||||
|
||||
/** Immutable const reference. */
|
||||
template<typename T>
|
||||
const T& as() const {
|
||||
|
@ -591,6 +627,15 @@ public:
|
|||
return *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 *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
|
||||
|
@ -605,6 +650,15 @@ public:
|
|||
return T(Move(as<T>()));
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
typename detail::Nth<N, Ts...>::Type extract()
|
||||
{
|
||||
static_assert(N < sizeof...(Ts),
|
||||
"provided an index outside of this Variant's type list");
|
||||
MOZ_RELEASE_ASSERT(is<N>());
|
||||
return typename detail::Nth<N, Ts...>::Type(Move(as<N>()));
|
||||
}
|
||||
|
||||
// Exhaustive matching of all variant types on the contained value.
|
||||
|
||||
/** Match on an immutable const reference. */
|
||||
|
|
|
@ -28,6 +28,12 @@ testSimple()
|
|||
MOZ_RELEASE_ASSERT(v.is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(!v.is<uint32_t>());
|
||||
MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);
|
||||
|
||||
MOZ_RELEASE_ASSERT(v.is<1>());
|
||||
MOZ_RELEASE_ASSERT(!v.is<0>());
|
||||
static_assert(mozilla::IsSame<decltype(v.as<1>()), uint64_t&>::value,
|
||||
"as<1>() should return a uint64_t");
|
||||
MOZ_RELEASE_ASSERT(v.as<1>() == 1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Загрузка…
Ссылка в новой задаче