#ifdef SWL_CPP_LIBRARY_VARIANT_HPP // ========================= visit dispatcher template using rtype_visit = decltype( ( std::declval()( std::declval().template unsafe_get<0>()... ) ) ); template using rtype_index_visit = decltype( ( std::declval()( std::declval().template unsafe_get<0>(), std::integral_constant{} ) ) ); inline namespace v1 { #if defined(__GNUC__) || defined( __clang__ ) || defined( __INTEL_COMPILER ) #define DeclareUnreachable() __builtin_unreachable() #elif defined (_MSC_VER) #define DeclareUnreachable() __assume(false) #else #error "Compiler not supported, please file an issue." #endif #define DEC(N) X((N)) X((N) + 1) X((N) + 2) X((N) + 3) X((N) + 4) X((N) + 5) X((N) + 6) X((N) + 7) X((N) + 8) X((N) + 9) #define SEQ30(N) DEC( (N) + 0 ) DEC( (N) + 10 ) DEC( (N) + 20 ) #define SEQ100(N) SEQ30((N) + 0) SEQ30((N) + 30) SEQ30((N) + 60) DEC((N) + 90) #define SEQ200(N) SEQ100((N) + 0) SEQ100((N) + 100) #define SEQ400(N) SEQ200((N) + 0) SEQ200((N) + 200) #define CAT(M, N) M##N #define CAT2(M, N) CAT(M, N) #define INJECTSEQ(N) CAT2(SEQ, N)(0) // single-visitation template constexpr Rtype single_visit_tail(Fn&& fn, V&& v){ constexpr auto RemainingIndex = std::decay_t::size - Offset; #define X(N) case (N + Offset) : \ if constexpr (N < RemainingIndex) { \ return static_cast(fn)( static_cast(v).template unsafe_get() ); \ break; \ } else DeclareUnreachable(); #define SEQSIZE 200 switch( v.index() ){ INJECTSEQ(SEQSIZE) default : if constexpr (SEQSIZE < RemainingIndex) return vimpl::single_visit_tail(static_cast(fn), static_cast(v)); else DeclareUnreachable(); } #undef X #undef SEQSIZE } template constexpr Rtype single_visit_w_index_tail(Fn&& fn, V&& v){ constexpr auto RemainingIndex = std::decay_t::size - Offset; #define X(N) case (N + Offset) : \ if constexpr (N < RemainingIndex) { \ return static_cast(fn)( static_cast(v).template unsafe_get(), std::integral_constant{} ); \ break; \ } else DeclareUnreachable(); #define SEQSIZE 200 switch( v.index() ){ INJECTSEQ(SEQSIZE) default : if constexpr (SEQSIZE < RemainingIndex) return vimpl::single_visit_w_index_tail(static_cast(fn), static_cast(v)); else DeclareUnreachable(); } #undef X #undef SEQSIZE } template constexpr decltype(auto) visit(Fn&& fn, V&& v){ return vimpl::single_visit_tail<0, rtype_visit>(SWL_FWD(fn), SWL_FWD(v)); } // unlike other visit functions, this takes the variant first! // this is confusing, but make the client code easier to read template constexpr decltype(auto) visit_with_index(V&& v, Fn&& fn){ return vimpl::single_visit_w_index_tail<0, rtype_index_visit>(SWL_FWD(fn), SWL_FWD(v)); } template constexpr decltype(auto) multi_visit(Fn&& fn, Head&& head, Tail&&... tail){ // visit them one by one, starting with the last auto vis = [&fn, &head] (auto&&... args) -> decltype(auto) { return vimpl::visit( [&fn, &args...] (auto&& elem) -> decltype(auto) { return SWL_FWD(fn)( SWL_FWD(elem), SWL_FWD(args)... ); }, SWL_FWD(head) ); }; if constexpr (sizeof...(tail) == 0) return SWL_FWD(vis)(); else if constexpr (sizeof...(tail) == 1) return vimpl::visit( SWL_FWD(vis), SWL_FWD(tail)... ); else return vimpl::multi_visit(SWL_FWD(vis), SWL_FWD(tail)...); } #undef DEC #undef SEQ30 #undef SEQ100 #undef SEQ200 #undef SEQ400 #undef DeclareUnreachable #undef CAT #undef CAT2 #undef INJECTSEQ } #endif