// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_DETAIL_VARIANT_HPP #define BOOST_BEAST_DETAIL_VARIANT_HPP #include #include #include namespace boost { namespace beast { namespace detail { // This simple variant gets the job done without // causing too much trouble with template depth: // // * Always allows an empty state I==0 // * emplace() and get() support 1-based indexes only // * Basic exception guarantee // * Max 255 types // template class variant { detail::aligned_union_t<1, TN...> buf_; unsigned char i_ = 0; struct destroy { variant& self; void operator()(mp11::mp_size_t<0>) { } template void operator()(I) noexcept { using T = mp11::mp_at_c; detail::launder_cast(&self.buf_)->~T(); } }; struct copy { variant& self; variant const& other; void operator()(mp11::mp_size_t<0>) { } template void operator()(I) { using T = mp11::mp_at_c; ::new(&self.buf_) T( *detail::launder_cast(&other.buf_)); self.i_ = I::value; } }; struct move { variant& self; variant& other; void operator()(mp11::mp_size_t<0>) { } template void operator()(I) { using T = mp11::mp_at_c; ::new(&self.buf_) T(std::move( *detail::launder_cast(&other.buf_))); detail::launder_cast(&other.buf_)->~T(); self.i_ = I::value; } }; struct equals { variant const& self; variant const& other; bool operator()(mp11::mp_size_t<0>) { return true; } template bool operator()(I) { using T = mp11::mp_at_c; return *detail::launder_cast(&self.buf_) == *detail::launder_cast(&other.buf_); } }; void destruct() { mp11::mp_with_index< sizeof...(TN) + 1>( i_, destroy{*this}); i_ = 0; } void copy_construct(variant const& other) { mp11::mp_with_index< sizeof...(TN) + 1>( other.i_, copy{*this, other}); } void move_construct(variant& other) { mp11::mp_with_index< sizeof...(TN) + 1>( other.i_, move{*this, other}); other.i_ = 0; } public: variant() = default; ~variant() { destruct(); } bool operator==(variant const& other) const { if(i_ != other.i_) return false; return mp11::mp_with_index< sizeof...(TN) + 1>( i_, equals{*this, other}); } // 0 = empty unsigned char index() const { return i_; } // moved-from object becomes empty variant(variant&& other) noexcept { move_construct(other); } variant(variant const& other) { copy_construct(other); } // moved-from object becomes empty variant& operator=(variant&& other) { if(this != &other) { destruct(); move_construct(other); } return *this; } variant& operator=(variant const& other) { if(this != &other) { destruct(); copy_construct(other); } return *this; } template void emplace(Args&&... args) noexcept { destruct(); ::new(&buf_) mp11::mp_at_c( std::forward(args)...); i_ = I; } template mp11::mp_at_c& get() { BOOST_ASSERT(i_ == I); return *detail::launder_cast< mp11::mp_at_c*>(&buf_); } template mp11::mp_at_c const& get() const { BOOST_ASSERT(i_ == I); return *detail::launder_cast< mp11::mp_at_c const*>(&buf_); } void reset() { destruct(); } }; } // detail } // beast } // boost #endif