236 lines
4.8 KiB
C++
236 lines
4.8 KiB
C++
//
|
|
// 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 <boost/beast/core/detail/type_traits.hpp>
|
|
#include <boost/assert.hpp>
|
|
#include <boost/mp11/algorithm.hpp>
|
|
|
|
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... TN>
|
|
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<class I>
|
|
void operator()(I) noexcept
|
|
{
|
|
using T =
|
|
mp11::mp_at_c<variant, I::value - 1>;
|
|
detail::launder_cast<T*>(&self.buf_)->~T();
|
|
}
|
|
};
|
|
|
|
struct copy
|
|
{
|
|
variant& self;
|
|
variant const& other;
|
|
|
|
void operator()(mp11::mp_size_t<0>)
|
|
{
|
|
}
|
|
|
|
template<class I>
|
|
void operator()(I)
|
|
{
|
|
using T =
|
|
mp11::mp_at_c<variant, I::value - 1>;
|
|
::new(&self.buf_) T(
|
|
*detail::launder_cast<T const*>(&other.buf_));
|
|
self.i_ = I::value;
|
|
}
|
|
};
|
|
|
|
struct move
|
|
{
|
|
variant& self;
|
|
variant& other;
|
|
|
|
void operator()(mp11::mp_size_t<0>)
|
|
{
|
|
}
|
|
|
|
template<class I>
|
|
void operator()(I)
|
|
{
|
|
using T =
|
|
mp11::mp_at_c<variant, I::value - 1>;
|
|
::new(&self.buf_) T(std::move(
|
|
*detail::launder_cast<T*>(&other.buf_)));
|
|
detail::launder_cast<T*>(&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<class I>
|
|
bool operator()(I)
|
|
{
|
|
using T =
|
|
mp11::mp_at_c<variant, I::value - 1>;
|
|
return
|
|
*detail::launder_cast<T const*>(&self.buf_) ==
|
|
*detail::launder_cast<T const*>(&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<std::size_t I, class... Args>
|
|
void
|
|
emplace(Args&&... args) noexcept
|
|
{
|
|
destruct();
|
|
::new(&buf_) mp11::mp_at_c<variant, I - 1>(
|
|
std::forward<Args>(args)...);
|
|
i_ = I;
|
|
}
|
|
|
|
template<std::size_t I>
|
|
mp11::mp_at_c<variant, I - 1>&
|
|
get()
|
|
{
|
|
BOOST_ASSERT(i_ == I);
|
|
return *detail::launder_cast<
|
|
mp11::mp_at_c<variant, I - 1>*>(&buf_);
|
|
}
|
|
|
|
template<std::size_t I>
|
|
mp11::mp_at_c<variant, I - 1> const&
|
|
get() const
|
|
{
|
|
BOOST_ASSERT(i_ == I);
|
|
return *detail::launder_cast<
|
|
mp11::mp_at_c<variant, I - 1> const*>(&buf_);
|
|
}
|
|
|
|
void
|
|
reset()
|
|
{
|
|
destruct();
|
|
}
|
|
};
|
|
|
|
} // detail
|
|
} // beast
|
|
} // boost
|
|
|
|
#endif
|