/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // Copyright Casey Carter 2016 // // 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_BOX_HPP #define RANGES_V3_UTILITY_BOX_HPP #include #include #include #include #include #include #include RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS namespace ranges { /// \addtogroup group-utility Utility /// @{ /// /// \cond template struct RANGES_DEPRECATED("The ranges::mutable_ class template is deprecated") mutable_ { mutable T value; CPP_member constexpr CPP_ctor(mutable_)()( // requires std::is_default_constructible::value) : value{} {} constexpr explicit mutable_(T const & t) : value(t) {} constexpr explicit mutable_(T && t) : value(detail::move(t)) {} mutable_ const & operator=(T const & t) const { value = t; return *this; } mutable_ const & operator=(T && t) const { value = detail::move(t); return *this; } constexpr operator T &() const & { return value; } }; template struct RANGES_DEPRECATED("The ranges::constant class template is deprecated") constant { constant() = default; constexpr explicit constant(T const &) {} constant & operator=(T const &) { return *this; } constant const & operator=(T const &) const { return *this; } constexpr operator T() const { return v; } constexpr T exchange(T const &) const { return v; } }; /// \endcond /// \cond namespace detail { // "box" has three different implementations that store a T differently: enum class box_compress { none, // Nothing special: get() returns a reference to a T member subobject ebo, // Apply Empty Base Optimization: get() returns a reference to a T base // subobject coalesce // Coalesce all Ts into one T: get() returns a reference to a static // T singleton }; // Per N4582, lambda closures are *not*: // - aggregates ([expr.prim.lambda]/4) // - default constructible_from ([expr.prim.lambda]/p21) // - copy assignable ([expr.prim.lambda]/p21) template using could_be_lambda = meta::bool_::value && !std::is_copy_assignable::value>; template constexpr box_compress box_compression_(...) { return box_compress::none; } template, meta::not_> #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 6 && __GNUC_MINOR__ < 2 // GCC 6.0 & 6.1 find empty lambdas' implicit conversion // to function pointer when doing overload resolution // for function calls. That causes hard errors. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71117 , meta::not_> #endif >>> constexpr box_compress box_compression_(long) { return box_compress::ebo; } #ifndef RANGES_WORKAROUND_MSVC_249830 // MSVC pukes passing non-constant-expression objects to constexpr // functions, so do not coalesce. template, detail::is_trivial>>> constexpr box_compress box_compression_(int) { return box_compress::coalesce; } #endif template constexpr box_compress box_compression() { return box_compression_(0); } } // namespace detail /// \endcond template()> class box { Element value; public: CPP_member constexpr CPP_ctor(box)()( // noexcept(std::is_nothrow_default_constructible::value) // requires std::is_default_constructible::value) : value{} {} template constexpr CPP_ctor(box)(E && e)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as>) && defer::constructible_from && defer::convertible_to) : value(static_cast(e)) {} template constexpr explicit CPP_ctor(box)(E && e)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as>) && defer::constructible_from && (!defer::convertible_to)) : value(static_cast(e)) {} constexpr Element & get() & noexcept { return value; } constexpr Element const & get() const & noexcept { return value; } constexpr Element && get() && noexcept { return detail::move(value); } constexpr Element const && get() const && noexcept { return detail::move(value); } }; template class box : Element { public: CPP_member constexpr CPP_ctor(box)()( // noexcept(std::is_nothrow_default_constructible::value) // requires std::is_default_constructible::value) : Element{} {} template constexpr CPP_ctor(box)(E && e)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as>) && defer::constructible_from && defer::convertible_to) : Element(static_cast(e)) {} template constexpr explicit CPP_ctor(box)(E && e)( // noexcept(std::is_nothrow_constructible::value) // requires(!defer::same_as>) && defer::constructible_from && (!defer::convertible_to)) : Element(static_cast(e)) {} constexpr Element & get() & noexcept { return *this; } constexpr Element const & get() const & noexcept { return *this; } constexpr Element && get() && noexcept { return detail::move(*this); } constexpr Element const && get() const && noexcept { return detail::move(*this); } }; template class box { static Element value; public: constexpr box() noexcept = default; template constexpr CPP_ctor(box)(E &&)( // noexcept(true) // requires(!defer::same_as>) && defer::constructible_from && defer::convertible_to) {} template constexpr explicit CPP_ctor(box)(E &&)( // noexcept(true) // requires(!defer::same_as>) && defer::constructible_from && (!defer::convertible_to)) {} constexpr Element & get() & noexcept { return value; } constexpr Element const & get() const & noexcept { return value; } constexpr Element && get() && noexcept { return detail::move(value); } constexpr Element const && get() const && noexcept { return detail::move(value); } }; template Element box::value{}; /// \cond namespace _get_ { /// \endcond // Get by tag type template constexpr Element & get(box & b) noexcept { return b.get(); } template constexpr Element const & get(box const & b) noexcept { return b.get(); } template constexpr Element && get(box && b) noexcept { return detail::move(b).get(); } // Get by index template constexpr Element & get(box, BC> & b) noexcept { return b.get(); } template constexpr Element const & get( box, BC> const & b) noexcept { return b.get(); } template constexpr Element && get(box, BC> && b) noexcept { return detail::move(b).get(); } /// \cond } // namespace _get_ /// \endcond /// @} } // namespace ranges RANGES_DIAGNOSTIC_POP #endif