|
- /// \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 <cstdlib>
- #include <type_traits>
- #include <utility>
-
- #include <meta/meta.hpp>
-
- #include <concepts/concepts.hpp>
-
- #include <range/v3/range_fwd.hpp>
-
- #include <range/v3/utility/get.hpp>
-
- RANGES_DIAGNOSTIC_PUSH
- RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
-
- namespace ranges
- {
- /// \addtogroup group-utility Utility
- /// @{
- ///
-
- /// \cond
- template<typename T>
- 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<T>::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<typename T, T v>
- 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<typename Fn>
- using could_be_lambda = meta::bool_<!std::is_default_constructible<Fn>::value &&
- !std::is_copy_assignable<Fn>::value>;
-
- template<typename>
- constexpr box_compress box_compression_(...)
- {
- return box_compress::none;
- }
- template<typename T, typename = meta::if_<meta::strict_and<
- std::is_empty<T>,
- meta::not_<detail::is_final<T>>
- #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_<could_be_lambda<T>>
- #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<typename T,
- typename =
- meta::if_<meta::strict_and<std::is_empty<T>, detail::is_trivial<T>>>>
- constexpr box_compress box_compression_(int)
- {
- return box_compress::coalesce;
- }
- #endif
- template<typename T>
- constexpr box_compress box_compression()
- {
- return box_compression_<T>(0);
- }
- } // namespace detail
- /// \endcond
-
- template<typename Element, typename Tag = void,
- detail::box_compress = detail::box_compression<Element>()>
- class box
- {
- Element value;
-
- public:
- CPP_member
- constexpr CPP_ctor(box)()( //
- noexcept(std::is_nothrow_default_constructible<Element>::value) //
- requires std::is_default_constructible<Element>::value)
- : value{}
- {}
- template<typename E>
- constexpr CPP_ctor(box)(E && e)( //
- noexcept(std::is_nothrow_constructible<Element, E>::value) //
- requires(!defer::same_as<box, detail::decay_t<E>>) &&
- defer::constructible_from<Element, E> && defer::convertible_to<E, Element>)
- : value(static_cast<E &&>(e))
- {}
- template<typename E>
- constexpr explicit CPP_ctor(box)(E && e)( //
- noexcept(std::is_nothrow_constructible<Element, E>::value) //
- requires(!defer::same_as<box, detail::decay_t<E>>) &&
- defer::constructible_from<Element, E> && (!defer::convertible_to<E, Element>))
- : value(static_cast<E &&>(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<typename Element, typename Tag>
- class box<Element, Tag, detail::box_compress::ebo> : Element
- {
- public:
- CPP_member
- constexpr CPP_ctor(box)()( //
- noexcept(std::is_nothrow_default_constructible<Element>::value) //
- requires std::is_default_constructible<Element>::value)
- : Element{}
- {}
- template<typename E>
- constexpr CPP_ctor(box)(E && e)( //
- noexcept(std::is_nothrow_constructible<Element, E>::value) //
- requires(!defer::same_as<box, detail::decay_t<E>>) &&
- defer::constructible_from<Element, E> && defer::convertible_to<E, Element>)
- : Element(static_cast<E &&>(e))
- {}
- template<typename E>
- constexpr explicit CPP_ctor(box)(E && e)( //
- noexcept(std::is_nothrow_constructible<Element, E>::value) //
- requires(!defer::same_as<box, detail::decay_t<E>>) &&
- defer::constructible_from<Element, E> && (!defer::convertible_to<E, Element>))
- : Element(static_cast<E &&>(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<typename Element, typename Tag>
- class box<Element, Tag, detail::box_compress::coalesce>
- {
- static Element value;
-
- public:
- constexpr box() noexcept = default;
- template<typename E>
- constexpr CPP_ctor(box)(E &&)( //
- noexcept(true) //
- requires(!defer::same_as<box, detail::decay_t<E>>) &&
- defer::constructible_from<Element, E> && defer::convertible_to<E, Element>)
- {}
- template<typename E>
- constexpr explicit CPP_ctor(box)(E &&)( //
- noexcept(true) //
- requires(!defer::same_as<box, detail::decay_t<E>>) &&
- defer::constructible_from<Element, E> && (!defer::convertible_to<E, Element>))
- {}
-
- 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<typename Element, typename Tag>
- Element box<Element, Tag, detail::box_compress::coalesce>::value{};
-
- /// \cond
- namespace _get_
- {
- /// \endcond
- // Get by tag type
- template<typename Tag, typename Element, detail::box_compress BC>
- constexpr Element & get(box<Element, Tag, BC> & b) noexcept
- {
- return b.get();
- }
- template<typename Tag, typename Element, detail::box_compress BC>
- constexpr Element const & get(box<Element, Tag, BC> const & b) noexcept
- {
- return b.get();
- }
- template<typename Tag, typename Element, detail::box_compress BC>
- constexpr Element && get(box<Element, Tag, BC> && b) noexcept
- {
- return detail::move(b).get();
- }
- // Get by index
- template<std::size_t I, typename Element, detail::box_compress BC>
- constexpr Element & get(box<Element, meta::size_t<I>, BC> & b) noexcept
- {
- return b.get();
- }
- template<std::size_t I, typename Element, detail::box_compress BC>
- constexpr Element const & get(
- box<Element, meta::size_t<I>, BC> const & b) noexcept
- {
- return b.get();
- }
- template<std::size_t I, typename Element, detail::box_compress BC>
- constexpr Element && get(box<Element, meta::size_t<I>, BC> && b) noexcept
- {
- return detail::move(b).get();
- }
- /// \cond
- } // namespace _get_
- /// \endcond
- /// @}
- } // namespace ranges
-
- RANGES_DIAGNOSTIC_POP
-
- #endif
|