/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // // Use, modification and distribution is subject to 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) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_UTILITY_SEMIREGULAR_BOX_HPP #define RANGES_V3_UTILITY_SEMIREGULAR_BOX_HPP #include #include #include #include #include #include namespace ranges { /// \cond template struct semiregular_box; namespace detail { struct semiregular_get { // clang-format off template friend auto CPP_auto_fun(get)(meta::id_t> &t) ( return t.get() ) template friend auto CPP_auto_fun(get)(meta::id_t> const &t) ( return t.get() ) template friend auto CPP_auto_fun(get)(meta::id_t> &&t) ( return detail::move(t).get() ) // clang-format on }; } // namespace detail /// \endcond /// \addtogroup group-utility /// @{ template struct semiregular_box : private detail::semiregular_get { private: struct tag {}; template void construct_from(Args &&... args) { new((void *)std::addressof(data_)) T(static_cast(args)...); engaged_ = true; } void move_assign(T && t, std::true_type) { data_ = detail::move(t); } void move_assign(T && t, std::false_type) { reset(); construct_from(detail::move(t)); } void copy_assign(T const & t, std::true_type) { data_ = t; } void copy_assign(T && t, std::false_type) { reset(); construct_from(t); } constexpr semiregular_box(tag, std::false_type) noexcept {} constexpr semiregular_box(tag, std::true_type) noexcept( std::is_nothrow_default_constructible::value) : data_{} , engaged_(true) {} void reset() { if(engaged_) { data_.~T(); engaged_ = false; } } union { char ch_{}; T data_; }; bool engaged_{false}; public: constexpr semiregular_box() noexcept( std::is_nothrow_default_constructible::value || !std::is_default_constructible::value) : semiregular_box(tag{}, std::is_default_constructible{}) {} semiregular_box(semiregular_box && that) noexcept( std::is_nothrow_move_constructible::value) { if(that.engaged_) this->construct_from(detail::move(that.data_)); } semiregular_box(semiregular_box const & that) noexcept( std::is_nothrow_copy_constructible::value) { if(that.engaged_) this->construct_from(that.data_); } #if defined(__cpp_conditional_explicit) && 0 < __cpp_conditional_explicit template explicit(!convertible_to) constexpr CPP_ctor(semiregular_box)(U && u)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as, semiregular_box>) && defer::constructible_from) : semiregular_box(in_place, static_cast(u)) {} #else template explicit constexpr CPP_ctor(semiregular_box)(U && u)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as, semiregular_box>) && defer::constructible_from && (!defer::convertible_to)) : semiregular_box(in_place, static_cast(u)) {} template constexpr CPP_ctor(semiregular_box)(U && u)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as, semiregular_box>) && defer::constructible_from && defer::convertible_to) : semiregular_box(in_place, static_cast(u)) {} #endif CPP_template(typename... Args)( // requires constructible_from) // constexpr semiregular_box(in_place_t, Args &&... args) // noexcept(std::is_nothrow_constructible::value) : data_(static_cast(args)...) , engaged_(true) {} ~semiregular_box() { reset(); } semiregular_box & operator=(semiregular_box && that) noexcept( std::is_nothrow_move_constructible::value && (!std::is_move_assignable::value || std::is_nothrow_move_assignable::value)) { if(engaged_ && that.engaged_) this->move_assign(detail::move(that.data_), std::is_move_assignable()); else if(that.engaged_) this->construct_from(detail::move(that.data_)); else if(engaged_) this->reset(); return *this; } semiregular_box & operator=(semiregular_box const & that) noexcept( std::is_nothrow_copy_constructible::value && (!std::is_copy_assignable::value || std::is_nothrow_copy_assignable::value)) { if(engaged_ && that.engaged_) this->copy_assign(that.data_, std::is_copy_assignable()); else if(that.engaged_) this->construct_from(that.data_); else if(engaged_) this->reset(); return *this; } semiregular_box & operator=(T t) noexcept( std::is_nothrow_move_constructible::value && (!std::is_move_assignable::value || std::is_nothrow_move_assignable::value)) { if(engaged_) this->move_assign(detail::move(t), std::is_move_assignable()); else this->construct_from(detail::move(t)); return *this; } constexpr T & get() & noexcept { return RANGES_ENSURE(engaged_), data_; } constexpr T const & get() const & noexcept { return RANGES_ENSURE(engaged_), data_; } constexpr T && get() && noexcept { return RANGES_ENSURE(engaged_), detail::move(data_); } T const && get() const && = delete; constexpr operator T &() & noexcept { return get(); } constexpr operator T const &() const & noexcept { return get(); } constexpr operator T &&() && noexcept { return detail::move(get()); } operator T const &&() const && = delete; // clang-format off template constexpr auto CPP_auto_fun(operator())(Args &&... args)(mutable &) ( return data_(static_cast(args)...) ) template constexpr auto CPP_auto_fun(operator())(Args &&... args)(const &) ( return data_(static_cast(args)...) ) #ifdef RANGES_WORKAROUND_MSVC_786376 template constexpr auto CPP_auto_fun(operator())(Args &&... args)(mutable &&) ( return ((U &&) data_)(static_cast(args)...) ) #else // ^^^ workaround / no workaround vvv template constexpr auto CPP_auto_fun(operator())(Args &&... args)(mutable &&) ( return ((T &&) data_)(static_cast(args)...) ) #endif // RANGES_WORKAROUND_MSVC_786376 // clang-format on template void operator()(Args &&...) const && = delete; }; template struct semiregular_box : private ranges::reference_wrapper , private detail::semiregular_get { semiregular_box() = default; template CPP_ctor(semiregular_box)(in_place_t, Arg & arg)( // noexcept(true) // requires constructible_from, Arg &>) : ranges::reference_wrapper(arg) {} using ranges::reference_wrapper::reference_wrapper; using ranges::reference_wrapper::get; using ranges::reference_wrapper::operator T &; using ranges::reference_wrapper::operator(); }; template struct semiregular_box : private ranges::reference_wrapper , private detail::semiregular_get { semiregular_box() = default; template CPP_ctor(semiregular_box)(in_place_t, Arg && arg)( // noexcept(true) // requires constructible_from, Arg>) : ranges::reference_wrapper(static_cast(arg)) {} using ranges::reference_wrapper::reference_wrapper; using ranges::reference_wrapper::get; using ranges::reference_wrapper::operator T &&; using ranges::reference_wrapper::operator(); }; template using semiregular_box_t = meta::if_c<(bool)semiregular, T, semiregular_box>; template using semiregular_box_ref_or_val_t = meta::if_c<(bool)semiregular, meta::if_c>, reference_wrapper const, semiregular_box>>>; /// @} /// \cond template using semiregular_t RANGES_DEPRECATED("Please use semiregular_box_t instead.") = semiregular_box_t; template using semiregular_ref_or_val_t RANGES_DEPRECATED( "Please use semiregular_box_t instead.") = semiregular_box_ref_or_val_t; /// \endcond } // namespace ranges #endif