// Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Implementation details of absl/types/variant.h, pulled into a // separate file to avoid cluttering the top of the API header with // implementation details. #ifndef ABSL_TYPES_variant_internal_H_ #define ABSL_TYPES_variant_internal_H_ #include <cassert> #include <cstddef> #include <cstdlib> #include <memory> #include <stdexcept> #include <tuple> #include <type_traits> #include "absl/base/config.h" #include "absl/base/internal/identity.h" #include "absl/base/internal/inline_variable.h" #include "absl/base/internal/invoke.h" #include "absl/base/macros.h" #include "absl/base/optimization.h" #include "absl/meta/type_traits.h" #include "absl/types/bad_variant_access.h" #include "absl/utility/utility.h" #if !defined(ABSL_USES_STD_VARIANT) namespace absl { ABSL_NAMESPACE_BEGIN template <class... Types> class variant; ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1)); template <class T> struct variant_size; template <std::size_t I, class T> struct variant_alternative; namespace variant_internal { // NOTE: See specializations below for details. template <std::size_t I, class T> struct VariantAlternativeSfinae {}; // Requires: I < variant_size_v<T>. // // Value: The Ith type of Types... template <std::size_t I, class T0, class... Tn> struct VariantAlternativeSfinae<I, variant<T0, Tn...>> : VariantAlternativeSfinae<I - 1, variant<Tn...>> {}; // Value: T0 template <class T0, class... Ts> struct VariantAlternativeSfinae<0, variant<T0, Ts...>> { using type = T0; }; template <std::size_t I, class T> using VariantAlternativeSfinaeT = typename VariantAlternativeSfinae<I, T>::type; // NOTE: Requires T to be a reference type. template <class T, class U> struct GiveQualsTo; template <class T, class U> struct GiveQualsTo<T&, U> { using type = U&; }; template <class T, class U> struct GiveQualsTo<T&&, U> { using type = U&&; }; template <class T, class U> struct GiveQualsTo<const T&, U> { using type = const U&; }; template <class T, class U> struct GiveQualsTo<const T&&, U> { using type = const U&&; }; template <class T, class U> struct GiveQualsTo<volatile T&, U> { using type = volatile U&; }; template <class T, class U> struct GiveQualsTo<volatile T&&, U> { using type = volatile U&&; }; template <class T, class U> struct GiveQualsTo<volatile const T&, U> { using type = volatile const U&; }; template <class T, class U> struct GiveQualsTo<volatile const T&&, U> { using type = volatile const U&&; }; template <class T, class U> using GiveQualsToT = typename GiveQualsTo<T, U>::type; // Convenience alias, since size_t integral_constant is used a lot in this file. template <std::size_t I> using SizeT = std::integral_constant<std::size_t, I>; using NPos = SizeT<variant_npos>; template <class Variant, class T, class = void> struct IndexOfConstructedType {}; template <std::size_t I, class Variant> struct VariantAccessResultImpl; template <std::size_t I, template <class...> class Variantemplate, class... T> struct VariantAccessResultImpl<I, Variantemplate<T...>&> { using type = typename absl::variant_alternative<I, variant<T...>>::type&; }; template <std::size_t I, template <class...> class Variantemplate, class... T> struct VariantAccessResultImpl<I, const Variantemplate<T...>&> { using type = const typename absl::variant_alternative<I, variant<T...>>::type&; }; template <std::size_t I, template <class...> class Variantemplate, class... T> struct VariantAccessResultImpl<I, Variantemplate<T...>&&> { using type = typename absl::variant_alternative<I, variant<T...>>::type&&; }; template <std::size_t I, template <class...> class Variantemplate, class... T> struct VariantAccessResultImpl<I, const Variantemplate<T...>&&> { using type = const typename absl::variant_alternative<I, variant<T...>>::type&&; }; template <std::size_t I, class Variant> using VariantAccessResult = typename VariantAccessResultImpl<I, Variant&&>::type; // NOTE: This is used instead of std::array to reduce instantiation overhead. template <class T, std::size_t Size> struct SimpleArray { static_assert(Size != 0, ""); T value[Size]; }; template <class T> struct AccessedType { using type = T; }; template <class T> using AccessedTypeT = typename AccessedType<T>::type; template <class T, std::size_t Size> struct AccessedType<SimpleArray<T, Size>> { using type = AccessedTypeT<T>; }; template <class T> constexpr T AccessSimpleArray(const T& value) { return value; } template <class T, std::size_t Size, class... SizeT> constexpr AccessedTypeT<T> AccessSimpleArray(const SimpleArray<T, Size>& table, std::size_t head_index, SizeT... tail_indices) { return AccessSimpleArray(table.value[head_index], tail_indices...); } // Note: Intentionally is an alias. template <class T> using AlwaysZero = SizeT<0>; template <class Op, class... Vs> struct VisitIndicesResultImpl { using type = absl::result_of_t<Op(AlwaysZero<Vs>...)>; }; template <class Op, class... Vs> using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type; template <class ReturnType, class FunctionObject, class EndIndices, class BoundIndices> struct MakeVisitationMatrix; template <class ReturnType, class FunctionObject, std::size_t... Indices> constexpr ReturnType call_with_indices(FunctionObject&& function) { static_assert( std::is_same<ReturnType, decltype(std::declval<FunctionObject>()( SizeT<Indices>()...))>::value, "Not all visitation overloads have the same return type."); return absl::forward<FunctionObject>(function)(SizeT<Indices>()...); } template <class ReturnType, class FunctionObject, std::size_t... BoundIndices> struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>, index_sequence<BoundIndices...>> { using ResultType = ReturnType (*)(FunctionObject&&); static constexpr ResultType Run() { return &call_with_indices<ReturnType, FunctionObject, (BoundIndices - 1)...>; } }; template <typename Is, std::size_t J> struct AppendToIndexSequence; template <typename Is, std::size_t J> using AppendToIndexSequenceT = typename AppendToIndexSequence<Is, J>::type; template <std::size_t... Is, std::size_t J> struct AppendToIndexSequence<index_sequence<Is...>, J> { using type = index_sequence<Is..., J>; }; template <class ReturnType, class FunctionObject, class EndIndices, class CurrIndices, class BoundIndices> struct MakeVisitationMatrixImpl; template <class ReturnType, class FunctionObject, class EndIndices, std::size_t... CurrIndices, class BoundIndices> struct MakeVisitationMatrixImpl<ReturnType, FunctionObject, EndIndices, index_sequence<CurrIndices...>, BoundIndices> { using ResultType = SimpleArray< typename MakeVisitationMatrix<ReturnType, FunctionObject, EndIndices, index_sequence<>>::ResultType, sizeof...(CurrIndices)>; static constexpr ResultType Run() { return {{MakeVisitationMatrix< ReturnType, FunctionObject, EndIndices, AppendToIndexSequenceT<BoundIndices, CurrIndices>>::Run()...}}; } }; template <class ReturnType, class FunctionObject, std::size_t HeadEndIndex, std::size_t... TailEndIndices, std::size_t... BoundIndices> struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<HeadEndIndex, TailEndIndices...>, index_sequence<BoundIndices...>> : MakeVisitationMatrixImpl<ReturnType, FunctionObject, index_sequence<TailEndIndices...>, absl::make_index_sequence<HeadEndIndex>, index_sequence<BoundIndices...>> {}; struct UnreachableSwitchCase { template <class Op> [[noreturn]] static VisitIndicesResultT<Op, std::size_t> Run( Op&& /*ignored*/) { #if ABSL_HAVE_BUILTIN(__builtin_unreachable) || \ (defined(__GNUC__) && !defined(__clang__)) __builtin_unreachable(); #elif defined(_MSC_VER) __assume(false); #else // Try to use assert of false being identified as an unreachable intrinsic. // NOTE: We use assert directly to increase chances of exploiting an assume // intrinsic. assert(false); // NOLINT // Hack to silence potential no return warning -- cause an infinite loop. return Run(absl::forward<Op>(op)); #endif // Checks for __builtin_unreachable } }; template <class Op, std::size_t I> struct ReachableSwitchCase { static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) { return absl::base_internal::invoke(absl::forward<Op>(op), SizeT<I>()); } }; // The number 33 is just a guess at a reasonable maximum to our switch. It is // not based on any analysis. The reason it is a power of 2 plus 1 instead of a // power of 2 is because the number was picked to correspond to a power of 2 // amount of "normal" alternatives, plus one for the possibility of the user // providing "monostate" in addition to the more natural alternatives. ABSL_INTERNAL_INLINE_CONSTEXPR(std::size_t, MaxUnrolledVisitCases, 33); // Note: The default-definition is for unreachable cases. template <bool IsReachable> struct PickCaseImpl { template <class Op, std::size_t I> using Apply = UnreachableSwitchCase; }; template <> struct PickCaseImpl</*IsReachable =*/true> { template <class Op, std::size_t I> using Apply = ReachableSwitchCase<Op, I>; }; // Note: This form of dance with template aliases is to make sure that we // instantiate a number of templates proportional to the number of variant // alternatives rather than a number of templates proportional to our // maximum unrolled amount of visitation cases (aliases are effectively // "free" whereas other template instantiations are costly). template <class Op, std::size_t I, std::size_t EndIndex> using PickCase = typename PickCaseImpl<(I < EndIndex)>::template Apply<Op, I>; template <class ReturnType> [[noreturn]] ReturnType TypedThrowBadVariantAccess() { absl::variant_internal::ThrowBadVariantAccess(); } // Given N variant sizes, determine the number of cases there would need to be // in a single switch-statement that would cover every possibility in the // corresponding N-ary visit operation. template <std::size_t... NumAlternatives> struct NumCasesOfSwitch; template <std::size_t HeadNumAlternatives, std::size_t... TailNumAlternatives> struct NumCasesOfSwitch<HeadNumAlternatives, TailNumAlternatives...> { static constexpr std::size_t value = (HeadNumAlternatives + 1) * NumCasesOfSwitch<TailNumAlternatives...>::value; }; template <> struct NumCasesOfSwitch<> { static constexpr std::size_t value = 1; }; // A switch statement optimizes better than the table of function pointers. template <std::size_t EndIndex> struct VisitIndicesSwitch { static_assert(EndIndex <= MaxUnrolledVisitCases, "Maximum unrolled switch size exceeded."); template <class Op> static VisitIndicesResultT<Op, std::size_t> Run(Op&& op, std::size_t i) { switch (i) { case 0: return PickCase<Op, 0, EndIndex>::Run(absl::forward<Op>(op)); case 1: return PickCase<Op, 1, EndIndex>::Run(absl::forward<Op>(op)); case 2: return PickCase<Op, 2, EndIndex>::Run(absl::forward<Op>(op)); case 3: return PickCase<Op, 3, EndIndex>::Run(absl::forward<Op>(op)); case 4: return PickCase<Op, 4, EndIndex>::Run(absl::forward<Op>(op)); case 5: return PickCase<Op, 5, EndIndex>::Run(absl::forward<Op>(op)); case 6: return PickCase<Op, 6, EndIndex>::Run(absl::forward<Op>(op)); case 7: return PickCase<Op, 7, EndIndex>::Run(absl::forward<Op>(op)); case 8: return PickCase<Op, 8, EndIndex>::Run(absl::forward<Op>(op)); case 9: return PickCase<Op, 9, EndIndex>::Run(absl::forward<Op>(op)); case 10: return PickCase<Op, 10, EndIndex>::Run(absl::forward<Op>(op)); case 11: return PickCase<Op, 11, EndIndex>::Run(absl::forward<Op>(op)); case 12: return PickCase<Op, 12, EndIndex>::Run(absl::forward<Op>(op)); case 13: return PickCase<Op, 13, EndIndex>::Run(absl::forward<Op>(op)); case 14: return PickCase<Op, 14, EndIndex>::Run(absl::forward<Op>(op)); case 15: return PickCase<Op, 15, EndIndex>::Run(absl::forward<Op>(op)); case 16: return PickCase<Op, 16, EndIndex>::Run(absl::forward<Op>(op)); case 17: return PickCase<Op, 17, EndIndex>::Run(absl::forward<Op>(op)); case 18: return PickCase<Op, 18, EndIndex>::Run(absl::forward<Op>(op)); case 19: return PickCase<Op, 19, EndIndex>::Run(absl::forward<Op>(op)); case 20: return PickCase<Op, 20, EndIndex>::Run(absl::forward<Op>(op)); case 21: return PickCase<Op, 21, EndIndex>::Run(absl::forward<Op>(op)); case 22: return PickCase<Op, 22, EndIndex>::Run(absl::forward<Op>(op)); case 23: return PickCase<Op, 23, EndIndex>::Run(absl::forward<Op>(op)); case 24: return PickCase<Op, 24, EndIndex>::Run(absl::forward<Op>(op)); case 25: return PickCase<Op, 25, EndIndex>::Run(absl::forward<Op>(op)); case 26: return PickCase<Op, 26, EndIndex>::Run(absl::forward<Op>(op)); case 27: return PickCase<Op, 27, EndIndex>::Run(absl::forward<Op>(op)); case 28: return PickCase<Op, 28, EndIndex>::Run(absl::forward<Op>(op)); case 29: return PickCase<Op, 29, EndIndex>::Run(absl::forward<Op>(op)); case 30: return PickCase<Op, 30, EndIndex>::Run(absl::forward<Op>(op)); case 31: return PickCase<Op, 31, EndIndex>::Run(absl::forward<Op>(op)); case 32: return PickCase<Op, 32, EndIndex>::Run(absl::forward<Op>(op)); default: ABSL_ASSERT(i == variant_npos); return absl::base_internal::invoke(absl::forward<Op>(op), NPos()); } } }; template <std::size_t... EndIndices> struct VisitIndicesFallback { template <class Op, class... SizeT> static VisitIndicesResultT<Op, SizeT...> Run(Op&& op, SizeT... indices) { return AccessSimpleArray( MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op, index_sequence<(EndIndices + 1)...>, index_sequence<>>::Run(), (indices + 1)...)(absl::forward<Op>(op)); } }; // Take an N-dimensional series of indices and convert them into a single index // without loss of information. The purpose of this is to be able to convert an // N-ary visit operation into a single switch statement. template <std::size_t...> struct FlattenIndices; template <std::size_t HeadSize, std::size_t... TailSize> struct FlattenIndices<HeadSize, TailSize...> { template<class... SizeType> static constexpr std::size_t Run(std::size_t head, SizeType... tail) { return head + HeadSize * FlattenIndices<TailSize...>::Run(tail...); } }; template <> struct FlattenIndices<> { static constexpr std::size_t Run() { return 0; } }; // Take a single "flattened" index (flattened by FlattenIndices) and determine // the value of the index of one of the logically represented dimensions. template <std::size_t I, std::size_t IndexToGet, std::size_t HeadSize, std::size_t... TailSize> struct UnflattenIndex { static constexpr std::size_t value = UnflattenIndex<I / HeadSize, IndexToGet - 1, TailSize...>::value; }; template <std::size_t I, std::size_t HeadSize, std::size_t... TailSize> struct UnflattenIndex<I, 0, HeadSize, TailSize...> { static constexpr std::size_t value = (I % HeadSize); }; // The backend for converting an N-ary visit operation into a unary visit. template <class IndexSequence, std::size_t... EndIndices> struct VisitIndicesVariadicImpl; template <std::size_t... N, std::size_t... EndIndices> struct VisitIndicesVariadicImpl<absl::index_sequence<N...>, EndIndices...> { // A type that can take an N-ary function object and converts it to a unary // function object that takes a single, flattened index, and "unflattens" it // into its individual dimensions when forwarding to the wrapped object. template <class Op> struct FlattenedOp { template <std::size_t I> VisitIndicesResultT<Op, decltype(EndIndices)...> operator()( SizeT<I> /*index*/) && { return base_internal::invoke( absl::forward<Op>(op), SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value - std::size_t{1}>()...); } Op&& op; }; template <class Op, class... SizeType> static VisitIndicesResultT<Op, decltype(EndIndices)...> Run( Op&& op, SizeType... i) { return VisitIndicesSwitch<NumCasesOfSwitch<EndIndices...>::value>::Run( FlattenedOp<Op>{absl::forward<Op>(op)}, FlattenIndices<(EndIndices + std::size_t{1})...>::Run( (i + std::size_t{1})...)); } }; template <std::size_t... EndIndices> struct VisitIndicesVariadic : VisitIndicesVariadicImpl<absl::make_index_sequence<sizeof...(EndIndices)>, EndIndices...> {}; // This implementation will flatten N-ary visit operations into a single switch // statement when the number of cases would be less than our maximum specified // switch-statement size. // TODO(calabrese) // Based on benchmarks, determine whether the function table approach actually // does optimize better than a chain of switch statements and possibly update // the implementation accordingly. Also consider increasing the maximum switch // size. template <std::size_t... EndIndices> struct VisitIndices : absl::conditional_t<(NumCasesOfSwitch<EndIndices...>::value <= MaxUnrolledVisitCases), VisitIndicesVariadic<EndIndices...>, VisitIndicesFallback<EndIndices...>> {}; template <std::size_t EndIndex> struct VisitIndices<EndIndex> : absl::conditional_t<(EndIndex <= MaxUnrolledVisitCases), VisitIndicesSwitch<EndIndex>, VisitIndicesFallback<EndIndex>> {}; // Suppress bogus warning on MSVC: MSVC complains that the `reinterpret_cast` // below is returning the address of a temporary or local object. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4172) #endif // _MSC_VER // TODO(calabrese) std::launder // TODO(calabrese) constexpr // NOTE: DO NOT REMOVE the `inline` keyword as it is necessary to work around a // MSVC bug. See https://github.com/abseil/abseil-cpp/issues/129 for details. template <class Self, std::size_t I> inline VariantAccessResult<I, Self> AccessUnion(Self&& self, SizeT<I> /*i*/) { return reinterpret_cast<VariantAccessResult<I, Self>>(self); } #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER template <class T> void DeducedDestroy(T& self) { // NOLINT self.~T(); } // NOTE: This type exists as a single entity for variant and its bases to // befriend. It contains helper functionality that manipulates the state of the // variant, such as the implementation of things like assignment and emplace // operations. struct VariantCoreAccess { template <class VariantType> static typename VariantType::Variant& Derived(VariantType& self) { // NOLINT return static_cast<typename VariantType::Variant&>(self); } template <class VariantType> static const typename VariantType::Variant& Derived( const VariantType& self) { // NOLINT return static_cast<const typename VariantType::Variant&>(self); } template <class VariantType> static void Destroy(VariantType& self) { // NOLINT Derived(self).destroy(); self.index_ = absl::variant_npos; } template <class Variant> static void SetIndex(Variant& self, std::size_t i) { // NOLINT self.index_ = i; } template <class Variant> static void InitFrom(Variant& self, Variant&& other) { // NOLINT VisitIndices<absl::variant_size<Variant>::value>::Run( InitFromVisitor<Variant, Variant&&>{&self, std::forward<Variant>(other)}, other.index()); self.index_ = other.index(); } // Access a variant alternative, assuming the index is correct. template <std::size_t I, class Variant> static VariantAccessResult<I, Variant> Access(Variant&& self) { // This cast instead of invocation of AccessUnion with an rvalue is a // workaround for msvc. Without this there is a runtime failure when dealing // with rvalues. // TODO(calabrese) Reduce test case and find a simpler workaround. return static_cast<VariantAccessResult<I, Variant>>( variant_internal::AccessUnion(self.state_, SizeT<I>())); } // Access a variant alternative, throwing if the index is incorrect. template <std::size_t I, class Variant> static VariantAccessResult<I, Variant> CheckedAccess(Variant&& self) { if (ABSL_PREDICT_FALSE(self.index_ != I)) { TypedThrowBadVariantAccess<VariantAccessResult<I, Variant>>(); } return Access<I>(absl::forward<Variant>(self)); } // The implementation of the move-assignment operation for a variant. template <class VType> struct MoveAssignVisitor { using DerivedType = typename VType::Variant; template <std::size_t NewIndex> void operator()(SizeT<NewIndex> /*new_i*/) const { if (left->index_ == NewIndex) { Access<NewIndex>(*left) = std::move(Access<NewIndex>(*right)); } else { Derived(*left).template emplace<NewIndex>( std::move(Access<NewIndex>(*right))); } } void operator()(SizeT<absl::variant_npos> /*new_i*/) const { Destroy(*left); } VType* left; VType* right; }; template <class VType> static MoveAssignVisitor<VType> MakeMoveAssignVisitor(VType* left, VType* other) { return {left, other}; } // The implementation of the assignment operation for a variant. template <class VType> struct CopyAssignVisitor { using DerivedType = typename VType::Variant; template <std::size_t NewIndex> void operator()(SizeT<NewIndex> /*new_i*/) const { using New = typename absl::variant_alternative<NewIndex, DerivedType>::type; if (left->index_ == NewIndex) { Access<NewIndex>(*left) = Access<NewIndex>(*right); } else if (std::is_nothrow_copy_constructible<New>::value || !std::is_nothrow_move_constructible<New>::value) { Derived(*left).template emplace<NewIndex>(Access<NewIndex>(*right)); } else { Derived(*left) = DerivedType(Derived(*right)); } } void operator()(SizeT<absl::variant_npos> /*new_i*/) const { Destroy(*left); } VType* left; const VType* right; }; template <class VType> static CopyAssignVisitor<VType> MakeCopyAssignVisitor(VType* left, const VType& other) { return {left, &other}; } // The implementation of conversion-assignment operations for variant. template <class Left, class QualifiedNew> struct ConversionAssignVisitor { using NewIndex = variant_internal::IndexOfConstructedType<Left, QualifiedNew>; void operator()(SizeT<NewIndex::value> /*old_i*/ ) const { Access<NewIndex::value>(*left) = absl::forward<QualifiedNew>(other); } template <std::size_t OldIndex> void operator()(SizeT<OldIndex> /*old_i*/ ) const { using New = typename absl::variant_alternative<NewIndex::value, Left>::type; if (std::is_nothrow_constructible<New, QualifiedNew>::value || !std::is_nothrow_move_constructible<New>::value) { left->template emplace<NewIndex::value>( absl::forward<QualifiedNew>(other)); } else { // the standard says "equivalent to // operator=(variant(std::forward<T>(t)))", but we use `emplace` here // because the variant's move assignment operator could be deleted. left->template emplace<NewIndex::value>( New(absl::forward<QualifiedNew>(other))); } } Left* left; QualifiedNew&& other; }; template <class Left, class QualifiedNew> static ConversionAssignVisitor<Left, QualifiedNew> MakeConversionAssignVisitor(Left* left, QualifiedNew&& qual) { return {left, absl::forward<QualifiedNew>(qual)}; } // Backend for operations for `emplace()` which destructs `*self` then // construct a new alternative with `Args...`. template <std::size_t NewIndex, class Self, class... Args> static typename absl::variant_alternative<NewIndex, Self>::type& Replace( Self* self, Args&&... args) { Destroy(*self); using New = typename absl::variant_alternative<NewIndex, Self>::type; New* const result = ::new (static_cast<void*>(&self->state_)) New(absl::forward<Args>(args)...); self->index_ = NewIndex; return *result; } template <class LeftVariant, class QualifiedRightVariant> struct InitFromVisitor { template <std::size_t NewIndex> void operator()(SizeT<NewIndex> /*new_i*/) const { using Alternative = typename variant_alternative<NewIndex, LeftVariant>::type; ::new (static_cast<void*>(&left->state_)) Alternative( Access<NewIndex>(std::forward<QualifiedRightVariant>(right))); } void operator()(SizeT<absl::variant_npos> /*new_i*/) const { // This space intentionally left blank. } LeftVariant* left; QualifiedRightVariant&& right; }; }; template <class Expected, class... T> struct IndexOfImpl; template <class Expected> struct IndexOfImpl<Expected> { using IndexFromEnd = SizeT<0>; using MatchedIndexFromEnd = IndexFromEnd; using MultipleMatches = std::false_type; }; template <class Expected, class Head, class... Tail> struct IndexOfImpl<Expected, Head, Tail...> : IndexOfImpl<Expected, Tail...> { using IndexFromEnd = SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>; }; template <class Expected, class... Tail> struct IndexOfImpl<Expected, Expected, Tail...> : IndexOfImpl<Expected, Tail...> { using IndexFromEnd = SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>; using MatchedIndexFromEnd = IndexFromEnd; using MultipleMatches = std::integral_constant< bool, IndexOfImpl<Expected, Tail...>::MatchedIndexFromEnd::value != 0>; }; template <class Expected, class... Types> struct IndexOfMeta { using Results = IndexOfImpl<Expected, Types...>; static_assert(!Results::MultipleMatches::value, "Attempted to access a variant by specifying a type that " "matches more than one alternative."); static_assert(Results::MatchedIndexFromEnd::value != 0, "Attempted to access a variant by specifying a type that does " "not match any alternative."); using type = SizeT<sizeof...(Types) - Results::MatchedIndexFromEnd::value>; }; template <class Expected, class... Types> using IndexOf = typename IndexOfMeta<Expected, Types...>::type; template <class Variant, class T, std::size_t CurrIndex> struct UnambiguousIndexOfImpl; // Terminating case encountered once we've checked all of the alternatives template <class T, std::size_t CurrIndex> struct UnambiguousIndexOfImpl<variant<>, T, CurrIndex> : SizeT<CurrIndex> {}; // Case where T is not Head template <class Head, class... Tail, class T, std::size_t CurrIndex> struct UnambiguousIndexOfImpl<variant<Head, Tail...>, T, CurrIndex> : UnambiguousIndexOfImpl<variant<Tail...>, T, CurrIndex + 1>::type {}; // Case where T is Head template <class Head, class... Tail, std::size_t CurrIndex> struct UnambiguousIndexOfImpl<variant<Head, Tail...>, Head, CurrIndex> : SizeT<UnambiguousIndexOfImpl<variant<Tail...>, Head, 0>::value == sizeof...(Tail) ? CurrIndex : CurrIndex + sizeof...(Tail) + 1> {}; template <class Variant, class T> struct UnambiguousIndexOf; struct NoMatch { struct type {}; }; template <class... Alts, class T> struct UnambiguousIndexOf<variant<Alts...>, T> : std::conditional<UnambiguousIndexOfImpl<variant<Alts...>, T, 0>::value != sizeof...(Alts), UnambiguousIndexOfImpl<variant<Alts...>, T, 0>, NoMatch>::type::type {}; template <class T, std::size_t /*Dummy*/> using UnambiguousTypeOfImpl = T; template <class Variant, class T> using UnambiguousTypeOfT = UnambiguousTypeOfImpl<T, UnambiguousIndexOf<Variant, T>::value>; template <class H, class... T> class VariantStateBase; // This is an implementation of the "imaginary function" that is described in // [variant.ctor] // It is used in order to determine which alternative to construct during // initialization from some type T. template <class Variant, std::size_t I = 0> struct ImaginaryFun; template <std::size_t I> struct ImaginaryFun<variant<>, I> { static void Run() = delete; }; template <class H, class... T, std::size_t I> struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> { using ImaginaryFun<variant<T...>, I + 1>::Run; // NOTE: const& and && are used instead of by-value due to lack of guaranteed // move elision of C++17. This may have other minor differences, but tests // pass. static SizeT<I> Run(const H&, SizeT<I>); static SizeT<I> Run(H&&, SizeT<I>); }; // The following metafunctions are used in constructor and assignment // constraints. template <class Self, class T> struct IsNeitherSelfNorInPlace : std::true_type {}; template <class Self> struct IsNeitherSelfNorInPlace<Self, Self> : std::false_type {}; template <class Self, class T> struct IsNeitherSelfNorInPlace<Self, in_place_type_t<T>> : std::false_type {}; template <class Self, std::size_t I> struct IsNeitherSelfNorInPlace<Self, in_place_index_t<I>> : std::false_type {}; template <class Variant, class T, class = void> struct ConversionIsPossibleImpl : std::false_type {}; template <class Variant, class T> struct ConversionIsPossibleImpl< Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>> : std::true_type {}; template <class Variant, class T> struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::type {}; template <class Variant, class T> struct IndexOfConstructedType< Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>> : decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {})) {}; template <std::size_t... Is> struct ContainsVariantNPos : absl::negation<std::is_same< // NOLINT absl::integer_sequence<bool, 0 <= Is...>, absl::integer_sequence<bool, Is != absl::variant_npos...>>> {}; template <class Op, class... QualifiedVariants> using RawVisitResult = absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>; // NOTE: The spec requires that all return-paths yield the same type and is not // SFINAE-friendly, so we can deduce the return type by examining the first // result. If it's not callable, then we get an error, but are compliant and // fast to compile. // TODO(calabrese) Possibly rewrite in a way that yields better compile errors // at the cost of longer compile-times. template <class Op, class... QualifiedVariants> struct VisitResultImpl { using type = absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>; }; // Done in two steps intentionally so that we don't cause substitution to fail. template <class Op, class... QualifiedVariants> using VisitResult = typename VisitResultImpl<Op, QualifiedVariants...>::type; template <class Op, class... QualifiedVariants> struct PerformVisitation { using ReturnType = VisitResult<Op, QualifiedVariants...>; template <std::size_t... Is> constexpr ReturnType operator()(SizeT<Is>... indices) const { return Run(typename ContainsVariantNPos<Is...>::type{}, absl::index_sequence_for<QualifiedVariants...>(), indices...); } template <std::size_t... TupIs, std::size_t... Is> constexpr ReturnType Run(std::false_type /*has_valueless*/, index_sequence<TupIs...>, SizeT<Is>...) const { static_assert( std::is_same<ReturnType, absl::result_of_t<Op(VariantAccessResult< Is, QualifiedVariants>...)>>::value, "All visitation overloads must have the same return type."); return absl::base_internal::invoke( absl::forward<Op>(op), VariantCoreAccess::Access<Is>( absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...); } template <std::size_t... TupIs, std::size_t... Is> [[noreturn]] ReturnType Run(std::true_type /*has_valueless*/, index_sequence<TupIs...>, SizeT<Is>...) const { absl::variant_internal::ThrowBadVariantAccess(); } // TODO(calabrese) Avoid using a tuple, which causes lots of instantiations // Attempts using lambda variadic captures fail on current GCC. std::tuple<QualifiedVariants&&...> variant_tup; Op&& op; }; template <class... T> union Union; // We want to allow for variant<> to be trivial. For that, we need the default // constructor to be trivial, which means we can't define it ourselves. // Instead, we use a non-default constructor that takes NoopConstructorTag // that doesn't affect the triviality of the types. struct NoopConstructorTag {}; template <std::size_t I> struct EmplaceTag {}; template <> union Union<> { constexpr explicit Union(NoopConstructorTag) noexcept {} }; // Suppress bogus warning on MSVC: MSVC complains that Union<T...> has a defined // deleted destructor from the `std::is_destructible` check below. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4624) #endif // _MSC_VER template <class Head, class... Tail> union Union<Head, Tail...> { using TailUnion = Union<Tail...>; explicit constexpr Union(NoopConstructorTag /*tag*/) noexcept : tail(NoopConstructorTag()) {} template <class... P> explicit constexpr Union(EmplaceTag<0>, P&&... args) : head(absl::forward<P>(args)...) {} template <std::size_t I, class... P> explicit constexpr Union(EmplaceTag<I>, P&&... args) : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {} Head head; TailUnion tail; }; #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER // TODO(calabrese) Just contain a Union in this union (certain configs fail). template <class... T> union DestructibleUnionImpl; template <> union DestructibleUnionImpl<> { constexpr explicit DestructibleUnionImpl(NoopConstructorTag) noexcept {} }; template <class Head, class... Tail> union DestructibleUnionImpl<Head, Tail...> { using TailUnion = DestructibleUnionImpl<Tail...>; explicit constexpr DestructibleUnionImpl(NoopConstructorTag /*tag*/) noexcept : tail(NoopConstructorTag()) {} template <class... P> explicit constexpr DestructibleUnionImpl(EmplaceTag<0>, P&&... args) : head(absl::forward<P>(args)...) {} template <std::size_t I, class... P> explicit constexpr DestructibleUnionImpl(EmplaceTag<I>, P&&... args) : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {} ~DestructibleUnionImpl() {} Head head; TailUnion tail; }; // This union type is destructible even if one or more T are not trivially // destructible. In the case that all T are trivially destructible, then so is // this resultant type. template <class... T> using DestructibleUnion = absl::conditional_t<std::is_destructible<Union<T...>>::value, Union<T...>, DestructibleUnionImpl<T...>>; // Deepest base, containing the actual union and the discriminator template <class H, class... T> class VariantStateBase { protected: using Variant = variant<H, T...>; template <class LazyH = H, class ConstructibleH = absl::enable_if_t< std::is_default_constructible<LazyH>::value, LazyH>> constexpr VariantStateBase() noexcept( std::is_nothrow_default_constructible<ConstructibleH>::value) : state_(EmplaceTag<0>()), index_(0) {} template <std::size_t I, class... P> explicit constexpr VariantStateBase(EmplaceTag<I> tag, P&&... args) : state_(tag, absl::forward<P>(args)...), index_(I) {} explicit constexpr VariantStateBase(NoopConstructorTag) : state_(NoopConstructorTag()), index_(variant_npos) {} void destroy() {} // Does nothing (shadowed in child if non-trivial) DestructibleUnion<H, T...> state_; std::size_t index_; }; using absl::internal::identity; // OverloadSet::Overload() is a unary function which is overloaded to // take any of the element types of the variant, by reference-to-const. // The return type of the overload on T is identity<T>, so that you // can statically determine which overload was called. // // Overload() is not defined, so it can only be called in unevaluated // contexts. template <typename... Ts> struct OverloadSet; template <typename T, typename... Ts> struct OverloadSet<T, Ts...> : OverloadSet<Ts...> { using Base = OverloadSet<Ts...>; static identity<T> Overload(const T&); using Base::Overload; }; template <> struct OverloadSet<> { // For any case not handled above. static void Overload(...); }; template <class T> using LessThanResult = decltype(std::declval<T>() < std::declval<T>()); template <class T> using GreaterThanResult = decltype(std::declval<T>() > std::declval<T>()); template <class T> using LessThanOrEqualResult = decltype(std::declval<T>() <= std::declval<T>()); template <class T> using GreaterThanOrEqualResult = decltype(std::declval<T>() >= std::declval<T>()); template <class T> using EqualResult = decltype(std::declval<T>() == std::declval<T>()); template <class T> using NotEqualResult = decltype(std::declval<T>() != std::declval<T>()); using type_traits_internal::is_detected_convertible; template <class... T> using RequireAllHaveEqualT = absl::enable_if_t< absl::conjunction<is_detected_convertible<bool, EqualResult, T>...>::value, bool>; template <class... T> using RequireAllHaveNotEqualT = absl::enable_if_t<absl::conjunction<is_detected_convertible< bool, NotEqualResult, T>...>::value, bool>; template <class... T> using RequireAllHaveLessThanT = absl::enable_if_t<absl::conjunction<is_detected_convertible< bool, LessThanResult, T>...>::value, bool>; template <class... T> using RequireAllHaveLessThanOrEqualT = absl::enable_if_t<absl::conjunction<is_detected_convertible< bool, LessThanOrEqualResult, T>...>::value, bool>; template <class... T> using RequireAllHaveGreaterThanOrEqualT = absl::enable_if_t<absl::conjunction<is_detected_convertible< bool, GreaterThanOrEqualResult, T>...>::value, bool>; template <class... T> using RequireAllHaveGreaterThanT = absl::enable_if_t<absl::conjunction<is_detected_convertible< bool, GreaterThanResult, T>...>::value, bool>; // Helper template containing implementations details of variant that can't go // in the private section. For convenience, this takes the variant type as a // single template parameter. template <typename T> struct VariantHelper; template <typename... Ts> struct VariantHelper<variant<Ts...>> { // Type metafunction which returns the element type selected if // OverloadSet::Overload() is well-formed when called with argument type U. template <typename U> using BestMatch = decltype( variant_internal::OverloadSet<Ts...>::Overload(std::declval<U>())); // Type metafunction which returns true if OverloadSet::Overload() is // well-formed when called with argument type U. // CanAccept can't be just an alias because there is a MSVC bug on parameter // pack expansion involving decltype. template <typename U> struct CanAccept : std::integral_constant<bool, !std::is_void<BestMatch<U>>::value> {}; // Type metafunction which returns true if Other is an instantiation of // variant, and variants's converting constructor from Other will be // well-formed. We will use this to remove constructors that would be // ill-formed from the overload set. template <typename Other> struct CanConvertFrom; template <typename... Us> struct CanConvertFrom<variant<Us...>> : public absl::conjunction<CanAccept<Us>...> {}; }; // A type with nontrivial copy ctor and trivial move ctor. struct TrivialMoveOnly { TrivialMoveOnly(TrivialMoveOnly&&) = default; }; // Trait class to detect whether a type is trivially move constructible. // A union's defaulted copy/move constructor is deleted if any variant member's // copy/move constructor is nontrivial. template <typename T> struct IsTriviallyMoveConstructible: std::is_move_constructible<Union<T, TrivialMoveOnly>> {}; // To guarantee triviality of all special-member functions that can be trivial, // we use a chain of conditional bases for each one. // The order of inheritance of bases from child to base are logically: // // variant // VariantCopyAssignBase // VariantMoveAssignBase // VariantCopyBase // VariantMoveBase // VariantStateBaseDestructor // VariantStateBase // // Note that there is a separate branch at each base that is dependent on // whether or not that corresponding special-member-function can be trivial in // the resultant variant type. template <class... T> class VariantStateBaseDestructorNontrivial; template <class... T> class VariantMoveBaseNontrivial; template <class... T> class VariantCopyBaseNontrivial; template <class... T> class VariantMoveAssignBaseNontrivial; template <class... T> class VariantCopyAssignBaseNontrivial; // Base that is dependent on whether or not the destructor can be trivial. template <class... T> using VariantStateBaseDestructor = absl::conditional_t<std::is_destructible<Union<T...>>::value, VariantStateBase<T...>, VariantStateBaseDestructorNontrivial<T...>>; // Base that is dependent on whether or not the move-constructor can be // implicitly generated by the compiler (trivial or deleted). // Previously we were using `std::is_move_constructible<Union<T...>>` to check // whether all Ts have trivial move constructor, but it ran into a GCC bug: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84866 // So we have to use a different approach (i.e. `HasTrivialMoveConstructor`) to // work around the bug. template <class... T> using VariantMoveBase = absl::conditional_t< absl::disjunction< absl::negation<absl::conjunction<std::is_move_constructible<T>...>>, absl::conjunction<IsTriviallyMoveConstructible<T>...>>::value, VariantStateBaseDestructor<T...>, VariantMoveBaseNontrivial<T...>>; // Base that is dependent on whether or not the copy-constructor can be trivial. template <class... T> using VariantCopyBase = absl::conditional_t< absl::disjunction< absl::negation<absl::conjunction<std::is_copy_constructible<T>...>>, std::is_copy_constructible<Union<T...>>>::value, VariantMoveBase<T...>, VariantCopyBaseNontrivial<T...>>; // Base that is dependent on whether or not the move-assign can be trivial. template <class... T> using VariantMoveAssignBase = absl::conditional_t< absl::disjunction< absl::conjunction<absl::is_move_assignable<Union<T...>>, std::is_move_constructible<Union<T...>>, std::is_destructible<Union<T...>>>, absl::negation<absl::conjunction<std::is_move_constructible<T>..., // Note: We're not qualifying this with // absl:: because it doesn't compile // under MSVC. is_move_assignable<T>...>>>::value, VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>; // Base that is dependent on whether or not the copy-assign can be trivial. template <class... T> using VariantCopyAssignBase = absl::conditional_t< absl::disjunction< absl::conjunction<absl::is_copy_assignable<Union<T...>>, std::is_copy_constructible<Union<T...>>, std::is_destructible<Union<T...>>>, absl::negation<absl::conjunction<std::is_copy_constructible<T>..., // Note: We're not qualifying this with // absl:: because it doesn't compile // under MSVC. is_copy_assignable<T>...>>>::value, VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>; template <class... T> using VariantBase = VariantCopyAssignBase<T...>; template <class... T> class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> { private: using Base = VariantStateBase<T...>; protected: using Base::Base; VariantStateBaseDestructorNontrivial() = default; VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) = default; VariantStateBaseDestructorNontrivial( const VariantStateBaseDestructorNontrivial&) = default; VariantStateBaseDestructorNontrivial& operator=( VariantStateBaseDestructorNontrivial&&) = default; VariantStateBaseDestructorNontrivial& operator=( const VariantStateBaseDestructorNontrivial&) = default; struct Destroyer { template <std::size_t I> void operator()(SizeT<I> i) const { using Alternative = typename absl::variant_alternative<I, variant<T...>>::type; variant_internal::AccessUnion(self->state_, i).~Alternative(); } void operator()(SizeT<absl::variant_npos> /*i*/) const { // This space intentionally left blank } VariantStateBaseDestructorNontrivial* self; }; void destroy() { VisitIndices<sizeof...(T)>::Run(Destroyer{this}, index_); } ~VariantStateBaseDestructorNontrivial() { destroy(); } protected: using Base::index_; using Base::state_; }; template <class... T> class VariantMoveBaseNontrivial : protected VariantStateBaseDestructor<T...> { private: using Base = VariantStateBaseDestructor<T...>; protected: using Base::Base; struct Construct { template <std::size_t I> void operator()(SizeT<I> i) const { using Alternative = typename absl::variant_alternative<I, variant<T...>>::type; ::new (static_cast<void*>(&self->state_)) Alternative( variant_internal::AccessUnion(absl::move(other->state_), i)); } void operator()(SizeT<absl::variant_npos> /*i*/) const {} VariantMoveBaseNontrivial* self; VariantMoveBaseNontrivial* other; }; VariantMoveBaseNontrivial() = default; VariantMoveBaseNontrivial(VariantMoveBaseNontrivial&& other) noexcept( absl::conjunction<std::is_nothrow_move_constructible<T>...>::value) : Base(NoopConstructorTag()) { VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_); index_ = other.index_; } VariantMoveBaseNontrivial(VariantMoveBaseNontrivial const&) = default; VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial&&) = default; VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial const&) = default; protected: using Base::index_; using Base::state_; }; template <class... T> class VariantCopyBaseNontrivial : protected VariantMoveBase<T...> { private: using Base = VariantMoveBase<T...>; protected: using Base::Base; VariantCopyBaseNontrivial() = default; VariantCopyBaseNontrivial(VariantCopyBaseNontrivial&&) = default; struct Construct { template <std::size_t I> void operator()(SizeT<I> i) const { using Alternative = typename absl::variant_alternative<I, variant<T...>>::type; ::new (static_cast<void*>(&self->state_)) Alternative(variant_internal::AccessUnion(other->state_, i)); } void operator()(SizeT<absl::variant_npos> /*i*/) const {} VariantCopyBaseNontrivial* self; const VariantCopyBaseNontrivial* other; }; VariantCopyBaseNontrivial(VariantCopyBaseNontrivial const& other) : Base(NoopConstructorTag()) { VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_); index_ = other.index_; } VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial&&) = default; VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial const&) = default; protected: using Base::index_; using Base::state_; }; template <class... T> class VariantMoveAssignBaseNontrivial : protected VariantCopyBase<T...> { friend struct VariantCoreAccess; private: using Base = VariantCopyBase<T...>; protected: using Base::Base; VariantMoveAssignBaseNontrivial() = default; VariantMoveAssignBaseNontrivial(VariantMoveAssignBaseNontrivial&&) = default; VariantMoveAssignBaseNontrivial(const VariantMoveAssignBaseNontrivial&) = default; VariantMoveAssignBaseNontrivial& operator=( VariantMoveAssignBaseNontrivial const&) = default; VariantMoveAssignBaseNontrivial& operator=(VariantMoveAssignBaseNontrivial&& other) noexcept( absl::conjunction<std::is_nothrow_move_constructible<T>..., std::is_nothrow_move_assignable<T>...>::value) { VisitIndices<sizeof...(T)>::Run( VariantCoreAccess::MakeMoveAssignVisitor(this, &other), other.index_); return *this; } protected: using Base::index_; using Base::state_; }; template <class... T> class VariantCopyAssignBaseNontrivial : protected VariantMoveAssignBase<T...> { friend struct VariantCoreAccess; private: using Base = VariantMoveAssignBase<T...>; protected: using Base::Base; VariantCopyAssignBaseNontrivial() = default; VariantCopyAssignBaseNontrivial(VariantCopyAssignBaseNontrivial&&) = default; VariantCopyAssignBaseNontrivial(const VariantCopyAssignBaseNontrivial&) = default; VariantCopyAssignBaseNontrivial& operator=( VariantCopyAssignBaseNontrivial&&) = default; VariantCopyAssignBaseNontrivial& operator=( const VariantCopyAssignBaseNontrivial& other) { VisitIndices<sizeof...(T)>::Run( VariantCoreAccess::MakeCopyAssignVisitor(this, other), other.index_); return *this; } protected: using Base::index_; using Base::state_; }; //////////////////////////////////////// // Visitors for Comparison Operations // //////////////////////////////////////// template <class... Types> struct EqualsOp { const variant<Types...>* v; const variant<Types...>* w; constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { return true; } template <std::size_t I> constexpr bool operator()(SizeT<I> /*v_i*/) const { return VariantCoreAccess::Access<I>(*v) == VariantCoreAccess::Access<I>(*w); } }; template <class... Types> struct NotEqualsOp { const variant<Types...>* v; const variant<Types...>* w; constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { return false; } template <std::size_t I> constexpr bool operator()(SizeT<I> /*v_i*/) const { return VariantCoreAccess::Access<I>(*v) != VariantCoreAccess::Access<I>(*w); } }; template <class... Types> struct LessThanOp { const variant<Types...>* v; const variant<Types...>* w; constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { return false; } template <std::size_t I> constexpr bool operator()(SizeT<I> /*v_i*/) const { return VariantCoreAccess::Access<I>(*v) < VariantCoreAccess::Access<I>(*w); } }; template <class... Types> struct GreaterThanOp { const variant<Types...>* v; const variant<Types...>* w; constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { return false; } template <std::size_t I> constexpr bool operator()(SizeT<I> /*v_i*/) const { return VariantCoreAccess::Access<I>(*v) > VariantCoreAccess::Access<I>(*w); } }; template <class... Types> struct LessThanOrEqualsOp { const variant<Types...>* v; const variant<Types...>* w; constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { return true; } template <std::size_t I> constexpr bool operator()(SizeT<I> /*v_i*/) const { return VariantCoreAccess::Access<I>(*v) <= VariantCoreAccess::Access<I>(*w); } }; template <class... Types> struct GreaterThanOrEqualsOp { const variant<Types...>* v; const variant<Types...>* w; constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { return true; } template <std::size_t I> constexpr bool operator()(SizeT<I> /*v_i*/) const { return VariantCoreAccess::Access<I>(*v) >= VariantCoreAccess::Access<I>(*w); } }; // Precondition: v.index() == w.index(); template <class... Types> struct SwapSameIndex { variant<Types...>* v; variant<Types...>* w; template <std::size_t I> void operator()(SizeT<I>) const { type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w)); } void operator()(SizeT<variant_npos>) const {} }; // TODO(calabrese) do this from a different namespace for proper adl usage template <class... Types> struct Swap { variant<Types...>* v; variant<Types...>* w; void generic_swap() const { variant<Types...> tmp(std::move(*w)); VariantCoreAccess::Destroy(*w); VariantCoreAccess::InitFrom(*w, std::move(*v)); VariantCoreAccess::Destroy(*v); VariantCoreAccess::InitFrom(*v, std::move(tmp)); } void operator()(SizeT<absl::variant_npos> /*w_i*/) const { if (!v->valueless_by_exception()) { generic_swap(); } } template <std::size_t Wi> void operator()(SizeT<Wi> /*w_i*/) { if (v->index() == Wi) { VisitIndices<sizeof...(Types)>::Run(SwapSameIndex<Types...>{v, w}, Wi); } else { generic_swap(); } } }; template <typename Variant, typename = void, typename... Ts> struct VariantHashBase { VariantHashBase() = delete; VariantHashBase(const VariantHashBase&) = delete; VariantHashBase(VariantHashBase&&) = delete; VariantHashBase& operator=(const VariantHashBase&) = delete; VariantHashBase& operator=(VariantHashBase&&) = delete; }; struct VariantHashVisitor { template <typename T> size_t operator()(const T& t) { return std::hash<T>{}(t); } }; template <typename Variant, typename... Ts> struct VariantHashBase<Variant, absl::enable_if_t<absl::conjunction< type_traits_internal::IsHashable<Ts>...>::value>, Ts...> { using argument_type = Variant; using result_type = size_t; size_t operator()(const Variant& var) const { type_traits_internal::AssertHashEnabled<Ts...>(); if (var.valueless_by_exception()) { return 239799884; } size_t result = VisitIndices<variant_size<Variant>::value>::Run( PerformVisitation<VariantHashVisitor, const Variant&>{ std::forward_as_tuple(var), VariantHashVisitor{}}, var.index()); // Combine the index and the hash result in order to distinguish // std::variant<int, int> holding the same value as different alternative. return result ^ var.index(); } }; } // namespace variant_internal ABSL_NAMESPACE_END } // namespace absl #endif // !defined(ABSL_USES_STD_VARIANT) #endif // ABSL_TYPES_variant_internal_H_