Skip to content

Commit

Permalink
Bug 1246841 - Allow construction of Variant values using type inferen…
Browse files Browse the repository at this point in the history
…ce. r=waldo
  • Loading branch information
sethfowler committed Feb 25, 2016
1 parent 5fb5a39 commit 26ee894
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions mfbt/Variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,39 @@ struct VariantImplementation<N, T, Ts...>
}
};

/**
* AsVariantTemporary stores a value of type T to allow construction of a
* Variant value via type inference. Because T is copied and there's no
* guarantee that the copy can be elided, AsVariantTemporary is best used with
* primitive or very small types.
*/
template <typename T>
struct AsVariantTemporary
{
explicit AsVariantTemporary(const T& aValue)
: mValue(aValue)
{}

template<typename U>
explicit AsVariantTemporary(U&& aValue)
: mValue(Forward<U>(aValue))
{}

AsVariantTemporary(const AsVariantTemporary& aOther)
: mValue(aOther.mValue)
{}

AsVariantTemporary(AsVariantTemporary&& aOther)
: mValue(Move(aOther.mValue))
{}

AsVariantTemporary() = delete;
void operator=(const AsVariantTemporary&) = delete;
void operator=(AsVariantTemporary&&) = delete;

typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
};

} // namespace detail

/**
Expand All @@ -270,6 +303,18 @@ struct VariantImplementation<N, T, Ts...>
* Variant<char, uint32_t> v1('a');
* Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
*
* Because specifying the full type of a Variant value is often verbose,
* AsVariant() can be used to construct a Variant value using type inference in
* contexts such as expressions or when returning values from functions. Because
* AsVariant() must copy or move the value into a temporary and this cannot
* necessarily be elided by the compiler, it's mostly appropriate only for use
* with primitive or very small types.
*
*
* Variant<char, uint32_t> Foo() { return AsVariant('x'); }
* // ...
* Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
*
* All access to the contained value goes through type-safe accessors.
*
* void
Expand Down Expand Up @@ -391,6 +436,19 @@ class Variant
new (ptr()) T(Forward<T>(aT));
}

/**
* Constructs this Variant from an AsVariantTemporary<T> such that T can be
* stored in one of the types allowable in this Variant. This is used in the
* implementation of AsVariant().
*/
template<typename RefT,
typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
: tag(Impl::template tag<T>())
{
new (ptr()) T(Move(aValue.mValue));
}

/** Copy construction. */
Variant(const Variant& aRhs)
: tag(aRhs.tag)
Expand Down Expand Up @@ -421,6 +479,15 @@ class Variant
return *this;
}

/** Move assignment from AsVariant(). */
template <typename T>
Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
{
this->~Variant();
new (this) Variant(Move(aValue));
return *this;
}

~Variant()
{
Impl::destroy(*this);
Expand Down Expand Up @@ -502,6 +569,26 @@ class Variant
}
};

/*
* AsVariant() is used to construct a Variant<T,...> value containing the
* provided T value using type inference. It can be used to construct Variant
* values in expressions or return them from functions without specifying the
* entire Variant type.
*
* Because AsVariant() must copy or move the value into a temporary and this
* cannot necessarily be elided by the compiler, it's mostly appropriate only
* for use with primitive or very small types.
*
* AsVariant() returns a AsVariantTemporary value which is implicitly
* convertible to any Variant that can hold a value of type T.
*/
template<typename T>
detail::AsVariantTemporary<T>
AsVariant(T&& aValue)
{
return detail::AsVariantTemporary<T>(Forward<T>(aValue));
}

} // namespace mozilla

#endif /* mozilla_Variant_h */

0 comments on commit 26ee894

Please sign in to comment.