init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
// 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_ADDRESSOF_HPP
#define RANGES_V3_UTILITY_ADDRESSOF_HPP
#include <memory>
#include <type_traits>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/config.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
#ifdef __cpp_lib_addressof_constexpr
using std::addressof;
#else
namespace check_addressof
{
inline ignore_t operator&(ignore_t)
{
return {};
}
template<typename T>
auto addressof(T & t)
{
return &t;
}
} // namespace check_addressof
template<typename T>
constexpr bool has_bad_addressof()
{
return !std::is_scalar<T>::value &&
!RANGES_IS_SAME(decltype(check_addressof::addressof(*(T *)nullptr)),
ignore_t);
}
template(typename T)(
requires(has_bad_addressof<T>()))
T * addressof(T & arg) noexcept
{
return std::addressof(arg);
}
template(typename T)(
requires (!has_bad_addressof<T>()))
constexpr T * addressof(T & arg) noexcept
{
return &arg;
}
template<typename T>
T const * addressof(T const &&) = delete;
#endif
} // namespace detail
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,234 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2015-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_ANY_HPP
#define RANGES_V3_UTILITY_ANY_HPP
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/swap.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
namespace ranges
{
struct bad_any_cast : std::bad_cast
{
virtual const char * what() const noexcept override
{
return "bad any_cast";
}
};
struct RANGES_DEPRECATED(
"ranges::any will be going away in the not-too-distant future. "
"We suggest you use std::any or boost::any instead (or simply steal "
"this header and maintain it yourself).") any;
template<typename T>
meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &);
template<typename T>
meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const &);
template<typename T>
meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &&);
template<typename T>
T * any_cast(any *) noexcept;
template<typename T>
T const * any_cast(any const *) noexcept;
struct any
{
private:
template<typename T>
friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(any &);
template<typename T>
friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
any const &);
template<typename T>
friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
any &&);
template<typename T>
friend T * any_cast(any *) noexcept;
template<typename T>
friend T const * any_cast(any const *) noexcept;
struct interface
{
virtual ~interface()
{}
virtual interface * clone() const = 0;
virtual std::type_info const & type() const noexcept = 0;
};
template<typename T>
struct impl final : interface
{
private:
T obj;
public:
impl() = default;
impl(T o)
: obj(std::move(o))
{}
T & get()
{
return obj;
}
T const & get() const
{
return obj;
}
impl * clone() const override
{
return new impl{obj};
}
std::type_info const & type() const noexcept override
{
return typeid(T);
}
};
std::unique_ptr<interface> ptr_;
public:
any() noexcept = default;
template(typename TRef, typename T = detail::decay_t<TRef>)(
requires copyable<T> AND (!same_as<T, any>)) //
any(TRef && t)
: ptr_(new impl<T>(static_cast<TRef &&>(t)))
{}
any(any &&) noexcept = default;
any(any const & that)
: ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
{}
any & operator=(any &&) noexcept = default;
any & operator=(any const & that)
{
ptr_.reset(that.ptr_ ? that.ptr_->clone() : nullptr);
return *this;
}
template(typename TRef, typename T = detail::decay_t<TRef>)(
requires copyable<T> AND (!same_as<T, any>)) //
any & operator=(TRef && t)
{
any{static_cast<TRef &&>(t)}.swap(*this);
return *this;
}
void clear() noexcept
{
ptr_.reset();
}
bool empty() const noexcept
{
return !ptr_;
}
std::type_info const & type() const noexcept
{
return ptr_ ? ptr_->type() : typeid(void);
}
void swap(any & that) noexcept
{
ptr_.swap(that.ptr_);
}
#if !RANGES_BROKEN_CPO_LOOKUP
friend void swap(any & x, any & y) noexcept
{
x.swap(y);
}
#endif
};
#if RANGES_BROKEN_CPO_LOOKUP
namespace _any_
{
inline void swap(any & x, any & y) noexcept
{
x.swap(y);
}
} // namespace _any_
#endif
/// \throw bad_any_cast
template<typename T>
meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any & x)
{
if(x.type() != typeid(detail::decay_t<T>))
throw bad_any_cast{};
return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
}
/// \overload
template<typename T>
meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const & x)
{
if(x.type() != typeid(detail::decay_t<T>))
throw bad_any_cast{};
return static_cast<any::impl<detail::decay_t<T>> const *>(x.ptr_.get())->get();
}
/// \overload
template<typename T>
meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any && x)
{
if(x.type() != typeid(detail::decay_t<T>))
throw bad_any_cast{};
return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
}
/// \overload
template<typename T>
T * any_cast(any * p) noexcept
{
if(p && p->ptr_)
if(any::impl<T> * q = dynamic_cast<any::impl<T> *>(p->ptr_.get()))
return &q->get();
return nullptr;
}
/// \overload
template<typename T>
T const * any_cast(any const * p) noexcept
{
if(p && p->ptr_)
if(any::impl<T> const * q = dynamic_cast<any::impl<T> const *>(p->ptr_.get()))
return &q->get();
return nullptr;
}
} // namespace ranges
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,23 @@
// Range v3 library
//
// Copyright Eric Niebler 2013-2014, 2016
// 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_ASSOCIATED_TYPES_HPP
#define RANGES_V3_UTILITY_ASSOCIATED_TYPES_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/iterator/traits.hpp> instead.")
#include <range/v3/iterator/traits.hpp>
#endif

View File

@@ -0,0 +1,23 @@
// Range v3 library
//
// Copyright Eric Niebler 2014-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_BASIC_ITERATOR_HPP
#define RANGES_V3_UTILITY_BASIC_ITERATOR_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/iterator/basic_iterator.hpp> "
"instead.")
#include <range/v3/iterator/basic_iterator.hpp>
#endif

View File

@@ -0,0 +1,370 @@
/// \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>
#include <range/v3/detail/prologue.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::bool_<!detail::is_final_v<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{}
{}
#if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E>)
constexpr explicit(!convertible_to<E, Element>) box(E && e)
noexcept(std::is_nothrow_constructible<Element, E>::value) //
: value(static_cast<E &&>(e))
{}
#else
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E> AND
convertible_to<E, Element>)
constexpr box(E && e)
noexcept(std::is_nothrow_constructible<Element, E>::value)
: value(static_cast<E &&>(e))
{}
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E> AND
(!convertible_to<E, Element>))
constexpr explicit box(E && e)
noexcept(std::is_nothrow_constructible<Element, E>::value) //
: value(static_cast<E &&>(e))
{}
#endif
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{}
{}
#if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E>)
constexpr explicit(!convertible_to<E, Element>) box(E && e)
noexcept(std::is_nothrow_constructible<Element, E>::value) //
: Element(static_cast<E &&>(e))
{}
#else
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E> AND
convertible_to<E, Element>)
constexpr box(E && e)
noexcept(std::is_nothrow_constructible<Element, E>::value) //
: Element(static_cast<E &&>(e))
{}
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E> AND
(!convertible_to<E, Element>))
constexpr explicit box(E && e)
noexcept(std::is_nothrow_constructible<Element, E>::value) //
: Element(static_cast<E &&>(e))
{}
#endif
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;
#if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E>)
constexpr explicit(!convertible_to<E, Element>) box(E &&) noexcept
{}
#else
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E> AND
convertible_to<E, Element>)
constexpr box(E &&) noexcept
{}
template(typename E)(
requires (!same_as<box, detail::decay_t<E>>) AND
constructible_from<Element, E> AND
(!convertible_to<E, Element>))
constexpr explicit box(E &&) noexcept
{}
#endif
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
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,23 @@
// Range v3 library
//
// Copyright Eric Niebler 2014-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_COMMON_ITERATOR_HPP
#define RANGES_V3_UTILITY_COMMON_ITERATOR_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/iterator/common_iterator.hpp> "
"instead.")
#include <range/v3/iterator/common_iterator.hpp>
#endif

View File

@@ -0,0 +1,792 @@
/// \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_COMMON_TUPLE_HPP
#define RANGES_V3_UTILITY_COMMON_TUPLE_HPP
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/adl_get.hpp>
#include <range/v3/functional/bind.hpp>
#include <range/v3/functional/reference_wrapper.hpp>
#include <range/v3/utility/common_type.hpp>
#include <range/v3/utility/tuple_algorithm.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename... Us, typename Tup, std::size_t... Is>
std::tuple<Us...> to_std_tuple(Tup && tup, meta::index_sequence<Is...>)
{
return std::tuple<Us...>{adl_get<Is>(static_cast<Tup &&>(tup))...};
}
#ifdef RANGES_WORKAROUND_MSVC_786312
template<std::size_t, typename...>
struct args_;
template<typename, typename>
inline constexpr bool argstructible = false;
template<std::size_t N, typename... Ts, typename... Us>
inline constexpr bool argstructible<args_<N, Ts...>, args_<N, Us...>> =
(META_IS_CONSTRUCTIBLE(Ts, Us) && ...);
template<typename, typename>
inline constexpr bool argsignable = false;
template<std::size_t N, typename... Ts, typename... Us>
inline constexpr bool argsignable<args_<N, Ts...>, args_<N, Us...>> =
(std::is_assignable_v<Ts &, Us> && ...);
#endif // RANGES_WORKAROUND_MSVC_786312
template<std::size_t N, typename... Ts>
struct args_
{
template<typename... Us>
args_(args_<N, Us...>, meta::if_c<
#ifdef RANGES_WORKAROUND_MSVC_786312
argstructible<args_, args_<N, Us...>>
#else // ^^^ workaround / no workaround vvv
meta::and_c<META_IS_CONSTRUCTIBLE(Ts,
Us)...>::value
#endif // RANGES_WORKAROUND_MSVC_786312
> * = nullptr)
{}
template<typename... Us>
meta::if_c<
#ifdef RANGES_WORKAROUND_MSVC_786312
argsignable<args_, args_<N, Us...>>,
#else // ^^^ workaround / no workaround vvv
meta::and_c<std::is_assignable<Ts &, Us>::value...>::value,
#endif // RANGES_WORKAROUND_MSVC_786312
args_ &>
operator=(args_<N, Us...>)
{
return *this;
}
};
template<typename... Ts>
using args = args_<sizeof...(Ts), Ts...>;
template<typename... Ts>
using rargs = args_<sizeof...(Ts), Ts &...>;
} // namespace detail
/// \endcond
template<typename... Ts>
struct common_tuple : _tuple_wrapper_::forward_tuple_interface<std::tuple<Ts...>>
{
private:
template<typename That, std::size_t... Is>
common_tuple(That && that, meta::index_sequence<Is...>)
: common_tuple::forward_tuple_interface{
detail::adl_get<Is>(static_cast<That &&>(that))...}
{}
struct element_assign_
{
template<typename T, typename U>
int operator()(T & t, U && u) const
{
t = static_cast<U &&>(u);
return 0;
}
};
public:
// Construction
CPP_member
CPP_ctor(common_tuple)()( //
noexcept( //
meta::and_c<std::is_nothrow_default_constructible<Ts>::value...>::value)
requires default_constructible<std::tuple<Ts...>>)
: common_tuple::forward_tuple_interface{}
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::args<Us...>>)
explicit common_tuple(Us &&... us) //
noexcept(meta::and_c<std::is_nothrow_constructible<Ts, Us>::value...>::value)
: common_tuple::forward_tuple_interface{static_cast<Us &&>(us)...}
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::rargs<Us...>>)
common_tuple(std::tuple<Us...> & that) //
noexcept(
meta::and_c<std::is_nothrow_constructible<Ts, Us &>::value...>::value) //
: common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::rargs<Us const...>>)
common_tuple(std::tuple<Us...> const & that) //
noexcept(meta::and_c<
std::is_nothrow_constructible<Ts, Us const &>::value...>::value) //
: common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::args<Us...>>)
common_tuple(std::tuple<Us...> && that) //
noexcept(
meta::and_c<std::is_nothrow_constructible<Ts, Us>::value...>::value) //
: common_tuple(std::move(that), meta::make_index_sequence<sizeof...(Ts)>{})
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::rargs<Us...>>)
common_tuple(common_tuple<Us...> & that) //
noexcept(
meta::and_c<std::is_nothrow_constructible<Ts, Us &>::value...>::value) //
: common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::rargs<Us const...>>)
common_tuple(common_tuple<Us...> const & that) //
noexcept(meta::and_c<
std::is_nothrow_constructible<Ts, Us const &>::value...>::value) //
: common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
{}
template(typename... Us)(
requires constructible_from<detail::args<Ts...>, detail::args<Us...>>)
common_tuple(common_tuple<Us...> && that) //
noexcept(
meta::and_c<std::is_nothrow_constructible<Ts, Us>::value...>::value) //
: common_tuple(std::move(that), meta::make_index_sequence<sizeof...(Ts)>{})
{}
std::tuple<Ts...> & base() noexcept
{
return *this;
}
std::tuple<Ts...> const & base() const noexcept
{
return *this;
}
// Assignment
template(typename... Us)(
requires std::is_assignable<detail::args<Ts...> &,
detail::rargs<Us...>>::value) //
common_tuple & operator=(std::tuple<Us...> & that) noexcept(
meta::and_c<std::is_nothrow_assignable<Ts &, Us &>::value...>::value)
{
(void)tuple_transform(base(), that, element_assign_{});
return *this;
}
template(typename... Us)(
requires std::is_assignable<detail::args<Ts...> &,
detail::rargs<Us const...>>::value) //
common_tuple & operator=(std::tuple<Us...> const & that) noexcept(
meta::and_c<std::is_nothrow_assignable<Ts &, Us const &>::value...>::value)
{
(void)tuple_transform(base(), that, element_assign_{});
return *this;
}
template(typename... Us)(
requires std::is_assignable<detail::args<Ts...> &,
detail::args<Us...>>::value) //
common_tuple & operator=(std::tuple<Us...> && that) noexcept(
meta::and_c<std::is_nothrow_assignable<Ts &, Us>::value...>::value)
{
(void)tuple_transform(base(), std::move(that), element_assign_{});
return *this;
}
template(typename... Us)(
requires std::is_assignable<detail::args<Ts const...> &,
detail::rargs<Us...>>::value)
common_tuple const & operator=(std::tuple<Us...> & that) const noexcept(
meta::and_c<std::is_nothrow_assignable<Ts const &, Us &>::value...>::value)
{
(void)tuple_transform(base(), that, element_assign_{});
return *this;
}
template(typename... Us)(
requires std::is_assignable<detail::args<Ts const...> &,
detail::rargs<Us const...>>::value)
common_tuple const & operator=(std::tuple<Us...> const & that) const
noexcept(meta::and_c<
std::is_nothrow_assignable<Ts const &, Us const &>::value...>::value)
{
(void)tuple_transform(base(), that, element_assign_{});
return *this;
}
template(typename... Us)(
requires std::is_assignable<detail::args<Ts const...> &,
detail::args<Us...>>::value)
common_tuple const & operator=(std::tuple<Us...> && that) const noexcept(
meta::and_c<std::is_nothrow_assignable<Ts const &, Us &&>::value...>::value)
{
(void)tuple_transform(base(), std::move(that), element_assign_{});
return *this;
}
// Conversion
template(typename... Us)(
requires constructible_from<detail::args<Us...>, detail::rargs<Ts...>>)
operator std::tuple<Us...>() & noexcept(
meta::and_c<std::is_nothrow_constructible<Us, Ts &>::value...>::value)
{
return detail::to_std_tuple<Us...>(
*this, meta::make_index_sequence<sizeof...(Ts)>{});
}
template(typename... Us)(
requires constructible_from<detail::args<Us...>,
detail::rargs<Ts const...>>)
operator std::tuple<Us...>() const & noexcept(
meta::and_c<std::is_nothrow_constructible<Us, Ts const &>::value...>::value)
{
return detail::to_std_tuple<Us...>(
*this, meta::make_index_sequence<sizeof...(Ts)>{});
}
template(typename... Us)(
requires constructible_from<detail::args<Us...>, detail::args<Ts...>>)
operator std::tuple<Us...>() &&
noexcept(meta::and_c<std::is_nothrow_constructible<Us, Ts>::value...>::value)
{
return detail::to_std_tuple<Us...>(
std::move(*this), meta::make_index_sequence<sizeof...(Ts)>{});
}
};
// Logical operators
#define LOGICAL_OP(OP, CONCEPT) \
template(typename... Ts, typename... Us)( \
requires and_v<CONCEPT<Ts, Us>...>) \
bool operator OP(common_tuple<Ts...> const & a, common_tuple<Us...> const & b) \
{ \
return a.base() OP b.base(); \
} \
template(typename... Ts, typename... Us)( \
requires and_v<CONCEPT<Ts, Us>...>) \
bool operator OP(std::tuple<Ts...> const & a, common_tuple<Us...> const & b) \
{ \
return a OP b.base(); \
} \
template(typename... Ts, typename... Us)( \
requires and_v<CONCEPT<Ts, Us>...>) \
bool operator OP(common_tuple<Ts...> const & a, std::tuple<Us...> const & b) \
{ \
return a.base() OP b; \
} \
/**/
LOGICAL_OP(==, equality_comparable_with)
LOGICAL_OP(!=, equality_comparable_with)
LOGICAL_OP(<, totally_ordered_with)
LOGICAL_OP(<=, totally_ordered_with)
LOGICAL_OP(>, totally_ordered_with)
LOGICAL_OP(>=, totally_ordered_with)
#undef LOGICAL_OP
struct make_common_tuple_fn
{
template<typename... Args>
common_tuple<bind_element_t<Args>...> operator()(Args &&... args) const noexcept(
meta::and_c<std::is_nothrow_constructible<
bind_element_t<Args>, unwrap_reference_t<Args>>::value...>::value)
{
return common_tuple<bind_element_t<Args>...>{
unwrap_reference(static_cast<Args &&>(args))...};
}
};
/// \ingroup group-utility
/// \sa `make_common_tuple_fn`
RANGES_INLINE_VARIABLE(make_common_tuple_fn, make_common_tuple)
template<typename F, typename S>
struct common_pair : std::pair<F, S>
{
private:
std::pair<F, S> const & base() const noexcept
{
return *this;
}
public:
// Construction
CPP_member
CPP_ctor(common_pair)()( //
noexcept(std::is_nothrow_default_constructible<F>::value && //
std::is_nothrow_default_constructible<S>::value) //
requires default_constructible<F> && default_constructible<S>)
: std::pair<F, S>{}
{}
template(typename F2, typename S2)(
requires constructible_from<F, F2> AND constructible_from<S, S2>)
common_pair(F2 && f2, S2 && s2) //
noexcept(std::is_nothrow_constructible<F, F2>::value &&
std::is_nothrow_constructible<S, S2>::value) //
: std::pair<F, S>{static_cast<F2 &&>(f2), static_cast<S2 &&>(s2)}
{}
template(typename F2, typename S2)(
requires constructible_from<F, F2 &> AND constructible_from<S, S2 &>)
common_pair(std::pair<F2, S2> & that) //
noexcept(std::is_nothrow_constructible<F, F2 &>::value &&
std::is_nothrow_constructible<S, S2 &>::value) //
: std::pair<F, S>{that.first, that.second}
{}
template(typename F2, typename S2)(
requires constructible_from<F, F2 const &> AND
constructible_from<S, S2 const &>)
common_pair(std::pair<F2, S2> const & that) //
noexcept(std::is_nothrow_constructible<F, F2 const &>::value &&
std::is_nothrow_constructible<S, S2 const &>::value) //
: std::pair<F, S>{that.first, that.second}
{}
template(typename F2, typename S2)(
requires constructible_from<F, F2> AND constructible_from<S, S2>)
common_pair(std::pair<F2, S2> && that) //
noexcept(std::is_nothrow_constructible<F, F2>::value &&
std::is_nothrow_constructible<S, S2>::value) //
: std::pair<F, S>{std::forward<F2>(that.first), std::forward<S2>(that.second)}
{}
// Conversion
template(typename F2, typename S2)(
requires constructible_from<F2, F &> AND constructible_from<S2, S &>)
operator std::pair<F2, S2>() & //
noexcept(std::is_nothrow_constructible<F2, F &>::value &&
std::is_nothrow_constructible<S2, S &>::value)
{
return {this->first, this->second};
}
template(typename F2, typename S2)(
requires constructible_from<F2, F const &> AND
constructible_from<S2, S const &>)
operator std::pair<F2, S2>() const & //
noexcept(std::is_nothrow_constructible<F2, F const &>::value &&
std::is_nothrow_constructible<S2, S const &>::value)
{
return {this->first, this->second};
}
template(typename F2, typename S2)(
requires constructible_from<F2, F> AND constructible_from<S2, S>)
operator std::pair<F2, S2>() &&
noexcept(std::is_nothrow_constructible<F2, F>::value &&
std::is_nothrow_constructible<S2, S>::value)
{
return {std::forward<F>(this->first), std::forward<S>(this->second)};
}
// Assignment
template(typename F2, typename S2)(
requires assignable_from<F &, F2 &> AND assignable_from<S &, S2 &>)
common_pair & operator=(std::pair<F2, S2> & that) //
noexcept(std::is_nothrow_assignable<F &, F2 &>::value &&
std::is_nothrow_assignable<S &, S2 &>::value)
{
this->first = that.first;
this->second = that.second;
return *this;
}
template(typename F2, typename S2)(
requires assignable_from<F &, F2 const &> AND
assignable_from<S &, S2 const &>)
common_pair & operator=(std::pair<F2, S2> const & that) //
noexcept(std::is_nothrow_assignable<F &, F2 const &>::value &&
std::is_nothrow_assignable<S &, S2 const &>::value)
{
this->first = that.first;
this->second = that.second;
return *this;
}
template(typename F2, typename S2)(
requires assignable_from<F &, F2> AND assignable_from<S &, S2>)
common_pair & operator=(std::pair<F2, S2> && that) //
noexcept(std::is_nothrow_assignable<F &, F2>::value &&
std::is_nothrow_assignable<S &, S2>::value)
{
this->first = static_cast<F2 &&>(that.first);
this->second = static_cast<S2 &&>(that.second);
return *this;
}
template(typename F2, typename S2)(
requires assignable_from<F const &, F2 &> AND
assignable_from<S const &, S2 &>)
common_pair const & operator=(std::pair<F2, S2> & that) const //
noexcept(std::is_nothrow_assignable<F const &, F2 &>::value &&
std::is_nothrow_assignable<S const &, S2 &>::value)
{
this->first = that.first;
this->second = that.second;
return *this;
}
template(typename F2, typename S2)(
requires assignable_from<F const &, F2 const &> AND
assignable_from<S const &, S2 const &>)
common_pair const & operator=(std::pair<F2, S2> const & that) const //
noexcept(std::is_nothrow_assignable<F const &, F2 const &>::value &&
std::is_nothrow_assignable<S const &, S2 const &>::value)
{
this->first = that.first;
this->second = that.second;
return *this;
}
template(typename F2, typename S2)(
requires assignable_from<F const &, F2> AND assignable_from<S const &, S2>)
common_pair const & operator=(std::pair<F2, S2> && that) const //
noexcept(std::is_nothrow_assignable<F const &, F2 &&>::value &&
std::is_nothrow_assignable<S const &, S2 &&>::value)
{
this->first = static_cast<F2 &&>(that.first);
this->second = static_cast<S2 &&>(that.second);
return *this;
}
};
// Logical operators
template(typename F1, typename S1, typename F2, typename S2)(
requires equality_comparable_with<F1, F2> AND equality_comparable_with<S1, S2>)
bool operator==(common_pair<F1, S1> const & a, common_pair<F2, S2> const & b)
{
return a.first == b.first && a.second == b.second;
}
template(typename F1, typename S1, typename F2, typename S2)(
requires equality_comparable_with<F1, F2> AND equality_comparable_with<S1, S2>)
bool operator==(common_pair<F1, S1> const & a, std::pair<F2, S2> const & b)
{
return a.first == b.first && a.second == b.second;
}
template(typename F1, typename S1, typename F2, typename S2)(
requires equality_comparable_with<F1, F2> AND equality_comparable_with<S1, S2>)
bool operator==(std::pair<F1, S1> const & a, common_pair<F2, S2> const & b)
{
return a.first == b.first && a.second == b.second;
}
template(typename F1, typename S1, typename F2, typename S2)(
requires totally_ordered_with<F1, F2> AND totally_ordered_with<S1, S2>)
bool operator<(common_pair<F1, S1> const & a, common_pair<F2, S2> const & b)
{
return a.first < b.first || (!(b.first < a.first) && a.second < b.second);
}
template(typename F1, typename S1, typename F2, typename S2)(
requires totally_ordered_with<F1, F2> AND totally_ordered_with<S1, S2>)
bool operator<(std::pair<F1, S1> const & a, common_pair<F2, S2> const & b)
{
return a.first < b.first || (!(b.first < a.first) && a.second < b.second);
}
template(typename F1, typename S1, typename F2, typename S2)(
requires totally_ordered_with<F1, F2> AND totally_ordered_with<S1, S2>)
bool operator<(common_pair<F1, S1> const & a, std::pair<F2, S2> const & b)
{
return a.first < b.first || (!(b.first < a.first) && a.second < b.second);
}
#define LOGICAL_OP(OP, CONCEPT, RET) \
template(typename F1, typename S1, typename F2, typename S2)( \
requires CONCEPT<F1, F2> AND CONCEPT<S1, S2>) \
bool operator OP(common_pair<F1, S1> const & a, common_pair<F2, S2> const & b) \
{ \
return RET; \
} \
template(typename F1, typename S1, typename F2, typename S2)( \
requires CONCEPT<F1, F2> AND CONCEPT<S1, S2>) \
bool operator OP(std::pair<F1, S1> const & a, common_pair<F2, S2> const & b) \
{ \
return RET; \
} \
template(typename F1, typename S1, typename F2, typename S2)( \
requires CONCEPT<F1, F2> AND CONCEPT<S1, S2>) \
bool operator OP(common_pair<F1, S1> const & a, std::pair<F2, S2> const & b) \
{ \
return RET; \
} \
/**/
LOGICAL_OP(!=, equality_comparable_with, !(a == b))
LOGICAL_OP(<=, totally_ordered_with, !(b < a))
LOGICAL_OP(>, totally_ordered_with, (b < a))
LOGICAL_OP(>=, totally_ordered_with, !(a < b))
#undef LOGICAL_OP
struct make_common_pair_fn
{
template<typename First, typename Second, typename F = bind_element_t<First>,
typename S = bind_element_t<Second>>
common_pair<F, S> operator()(First && f, Second && s) const //
noexcept(std::is_nothrow_constructible<F, unwrap_reference_t<First>>::value &&
std::is_nothrow_constructible<F, unwrap_reference_t<Second>>::value)
{
return {unwrap_reference(static_cast<First &&>(f)),
unwrap_reference(static_cast<Second &&>(s))};
}
};
/// \ingroup group-utility
/// \sa `make_common_pair_fn`
RANGES_INLINE_VARIABLE(make_common_pair_fn, make_common_pair)
/// \cond
namespace detail
{
template<typename, typename, typename, typename = void>
struct common_type_tuple_like
{};
template<template<typename...> class T0, typename... Ts,
template<typename...> class T1, typename... Us, typename TupleLike>
struct common_type_tuple_like<T0<Ts...>, T1<Us...>, TupleLike,
meta::if_c<sizeof...(Ts) == sizeof...(Us)>>
: meta::lazy::let<
meta::lazy::invoke<TupleLike, meta::lazy::_t<common_type<Ts, Us>>...>>
{};
template<typename, typename, typename, typename = void>
struct common_ref_tuple_like
{};
template<template<typename...> class T0, typename... Ts,
template<typename...> class T1, typename... Us, typename TupleLike>
struct common_ref_tuple_like<T0<Ts...>, T1<Us...>, TupleLike,
meta::if_c<sizeof...(Ts) == sizeof...(Us)>>
: meta::lazy::let<meta::lazy::invoke<
TupleLike, meta::lazy::_t<common_reference<Ts, Us>>...>>
{};
} // namespace detail
/// \endcond
} // namespace ranges
/// \cond
namespace concepts
{
// common_type for pairs
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<std::pair<F1, S1>, ranges::common_pair<F2, S2>>
: ranges::detail::common_type_tuple_like<
std::pair<F1, S1>, ranges::common_pair<F2, S2>,
meta::quote<ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<ranges::common_pair<F1, S1>, std::pair<F2, S2>>
: ranges::detail::common_type_tuple_like<
ranges::common_pair<F1, S1>, std::pair<F2, S2>,
meta::quote<ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<ranges::common_pair<F1, S1>, ranges::common_pair<F2, S2>>
: ranges::detail::common_type_tuple_like<ranges::common_pair<F1, S1>,
ranges::common_pair<F2, S2>,
meta::quote<ranges::common_pair>>
{};
// common_type for tuples
template<typename... Ts, typename... Us>
struct common_type<ranges::common_tuple<Ts...>, std::tuple<Us...>>
: ranges::detail::common_type_tuple_like<
ranges::common_tuple<Ts...>, std::tuple<Us...>,
meta::quote<ranges::common_tuple>>
{};
template<typename... Ts, typename... Us>
struct common_type<std::tuple<Ts...>, ranges::common_tuple<Us...>>
: ranges::detail::common_type_tuple_like<
std::tuple<Ts...>, ranges::common_tuple<Us...>,
meta::quote<ranges::common_tuple>>
{};
template<typename... Ts, typename... Us>
struct common_type<ranges::common_tuple<Ts...>, ranges::common_tuple<Us...>>
: ranges::detail::common_type_tuple_like<ranges::common_tuple<Ts...>,
ranges::common_tuple<Us...>,
meta::quote<ranges::common_tuple>>
{};
// common reference for pairs
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<ranges::common_pair<F1, S1>, std::pair<F2, S2>, Qual1,
Qual2>
: ranges::detail::common_ref_tuple_like<
ranges::common_pair<Qual1<F1>, Qual1<S1>>, std::pair<Qual2<F2>, Qual2<S2>>,
meta::quote<ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<std::pair<F1, S1>, ranges::common_pair<F2, S2>, Qual1,
Qual2>
: ranges::detail::common_ref_tuple_like<
std::pair<Qual1<F1>, Qual1<S1>>, ranges::common_pair<Qual2<F2>, Qual2<S2>>,
meta::quote<ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<ranges::common_pair<F1, S1>,
ranges::common_pair<F2, S2>, Qual1, Qual2>
: ranges::detail::common_ref_tuple_like<ranges::common_pair<Qual1<F1>, Qual1<S1>>,
ranges::common_pair<Qual2<F2>, Qual2<S2>>,
meta::quote<ranges::common_pair>>
{};
// common reference for tuples
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<ranges::common_tuple<Ts...>, std::tuple<Us...>, Qual1,
Qual2>
: ranges::detail::common_ref_tuple_like<
ranges::common_tuple<Qual1<Ts>...>, std::tuple<Qual2<Us>...>,
meta::quote<ranges::common_tuple>>
{};
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<std::tuple<Ts...>, ranges::common_tuple<Us...>, Qual1,
Qual2>
: ranges::detail::common_ref_tuple_like<
std::tuple<Qual1<Ts>...>, ranges::common_tuple<Qual2<Us>...>,
meta::quote<ranges::common_tuple>>
{};
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<ranges::common_tuple<Ts...>,
ranges::common_tuple<Us...>, Qual1, Qual2>
: ranges::detail::common_ref_tuple_like<ranges::common_tuple<Qual1<Ts>...>,
ranges::common_tuple<Qual2<Us>...>,
meta::quote<ranges::common_tuple>>
{};
} // namespace concepts
/// \endcond
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
RANGES_BEGIN_NAMESPACE_STD
template<typename First, typename Second>
struct tuple_size<::ranges::common_pair<First, Second>>
: std::integral_constant<size_t, 2>
{};
template<typename First, typename Second>
struct tuple_element<0, ::ranges::common_pair<First, Second>>
{
using type = First;
};
template<typename First, typename Second>
struct tuple_element<1, ::ranges::common_pair<First, Second>>
{
using type = Second;
};
template<typename... Ts>
struct tuple_size<::ranges::common_tuple<Ts...>>
: std::integral_constant<size_t, sizeof...(Ts)>
{};
template<size_t N, typename... Ts>
struct tuple_element<N, ::ranges::common_tuple<Ts...>>
: tuple_element<N, tuple<Ts...>>
{};
#if RANGES_CXX_VER > RANGES_CXX_STD_17
RANGES_BEGIN_NAMESPACE_VERSION
template<typename...>
struct common_type;
// common_type for pairs
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<std::pair<F1, S1>, ::ranges::common_pair<F2, S2>>
: ::ranges::detail::common_type_tuple_like<
std::pair<F1, S1>, ::ranges::common_pair<F2, S2>,
::meta::quote<::ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<::ranges::common_pair<F1, S1>, std::pair<F2, S2>>
: ::ranges::detail::common_type_tuple_like<
::ranges::common_pair<F1, S1>, std::pair<F2, S2>,
::meta::quote<::ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<::ranges::common_pair<F1, S1>, ::ranges::common_pair<F2, S2>>
: ::ranges::detail::common_type_tuple_like<::ranges::common_pair<F1, S1>,
::ranges::common_pair<F2, S2>,
::meta::quote<::ranges::common_pair>>
{};
// common_type for tuples
template<typename... Ts, typename... Us>
struct common_type<::ranges::common_tuple<Ts...>, std::tuple<Us...>>
: ::ranges::detail::common_type_tuple_like<
::ranges::common_tuple<Ts...>, std::tuple<Us...>,
::meta::quote<::ranges::common_tuple>>
{};
template<typename... Ts, typename... Us>
struct common_type<std::tuple<Ts...>, ::ranges::common_tuple<Us...>>
: ::ranges::detail::common_type_tuple_like<
std::tuple<Ts...>, ::ranges::common_tuple<Us...>,
::meta::quote<::ranges::common_tuple>>
{};
template<typename... Ts, typename... Us>
struct common_type<::ranges::common_tuple<Ts...>, ::ranges::common_tuple<Us...>>
: ::ranges::detail::common_type_tuple_like<::ranges::common_tuple<Ts...>,
::ranges::common_tuple<Us...>,
::meta::quote<::ranges::common_tuple>>
{};
template<typename, typename, template<typename> class, template<typename> class>
struct basic_common_reference;
// common reference for pairs
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<::ranges::common_pair<F1, S1>, std::pair<F2, S2>, Qual1,
Qual2>
: ::ranges::detail::common_ref_tuple_like<
::ranges::common_pair<Qual1<F1>, Qual1<S1>>, std::pair<Qual2<F2>, Qual2<S2>>,
::meta::quote<::ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<std::pair<F1, S1>, ::ranges::common_pair<F2, S2>, Qual1,
Qual2>
: ::ranges::detail::common_ref_tuple_like<
std::pair<Qual1<F1>, Qual1<S1>>, ::ranges::common_pair<Qual2<F2>, Qual2<S2>>,
::meta::quote<::ranges::common_pair>>
{};
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<::ranges::common_pair<F1, S1>,
::ranges::common_pair<F2, S2>, Qual1, Qual2>
: ::ranges::detail::common_ref_tuple_like<::ranges::common_pair<Qual1<F1>, Qual1<S1>>,
::ranges::common_pair<Qual2<F2>, Qual2<S2>>,
::meta::quote<::ranges::common_pair>>
{};
// common reference for tuples
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<::ranges::common_tuple<Ts...>, std::tuple<Us...>, Qual1,
Qual2>
: ::ranges::detail::common_ref_tuple_like<
::ranges::common_tuple<Qual1<Ts>...>, std::tuple<Qual2<Us>...>,
::meta::quote<::ranges::common_tuple>>
{};
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<std::tuple<Ts...>, ::ranges::common_tuple<Us...>, Qual1,
Qual2>
: ::ranges::detail::common_ref_tuple_like<
std::tuple<Qual1<Ts>...>, ::ranges::common_tuple<Qual2<Us>...>,
::meta::quote<::ranges::common_tuple>>
{};
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<::ranges::common_tuple<Ts...>,
::ranges::common_tuple<Us...>, Qual1, Qual2>
: ::ranges::detail::common_ref_tuple_like<::ranges::common_tuple<Qual1<Ts>...>,
::ranges::common_tuple<Qual2<Us>...>,
::meta::quote<::ranges::common_tuple>>
{};
RANGES_END_NAMESPACE_VERSION
#endif // RANGES_CXX_VER > RANGES_CXX_STD_17
RANGES_END_NAMESPACE_STD
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,175 @@
/// \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_COMMON_TYPE_HPP
#define RANGES_V3_UTILITY_COMMON_TYPE_HPP
#include <tuple>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/type_traits.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/prologue.hpp>
// Sadly, this is necessary because of:
// - std::common_type is !SFINAE-friendly, and
// - The specification of std::common_type makes it impossibly
// difficult to specialize on user-defined types without spamming
// out a bajillion copies to handle all combinations of cv and ref
// qualifiers.
namespace ranges
{
template<typename... Ts>
using common_type = concepts::common_type<Ts...>;
template<typename... Ts>
using common_type_t = concepts::common_type_t<Ts...>;
template<typename... Ts>
using common_reference = concepts::common_reference<Ts...>;
template<typename... Ts>
using common_reference_t = concepts::common_reference_t<Ts...>;
/// \cond
template<typename F, typename S>
struct common_pair;
template<typename... Ts>
struct common_tuple;
/// \endcond
} // namespace ranges
/// \cond
// Specializations for pair and tuple
namespace concepts
{
// common_type for std::pairs
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<std::pair<F1, S1>, ::ranges::common_pair<F2, S2>>;
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<::ranges::common_pair<F1, S1>, std::pair<F2, S2>>;
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<::ranges::common_pair<F1, S1>, ::ranges::common_pair<F2, S2>>;
// common_type for std::tuples
template<typename... Ts, typename... Us>
struct common_type<::ranges::common_tuple<Ts...>, std::tuple<Us...>>;
template<typename... Ts, typename... Us>
struct common_type<std::tuple<Ts...>, ::ranges::common_tuple<Us...>>;
template<typename... Ts, typename... Us>
struct common_type<::ranges::common_tuple<Ts...>, ::ranges::common_tuple<Us...>>;
// A common reference for std::pairs
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<::ranges::common_pair<F1, S1>, std::pair<F2, S2>, Qual1, Qual2>;
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<std::pair<F1, S1>, ::ranges::common_pair<F2, S2>, Qual1, Qual2>;
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<::ranges::common_pair<F1, S1>, ::ranges::common_pair<F2, S2>, Qual1, Qual2>;
// A common reference for std::tuples
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<::ranges::common_tuple<Ts...>, std::tuple<Us...>, Qual1, Qual2>;
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<std::tuple<Ts...>, ::ranges::common_tuple<Us...>, Qual1, Qual2>;
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<::ranges::common_tuple<Ts...>, ::ranges::common_tuple<Us...>, Qual1, Qual2>;
} // namespace concepts
#if RANGES_CXX_VER > RANGES_CXX_STD_17
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
RANGES_BEGIN_NAMESPACE_STD
RANGES_BEGIN_NAMESPACE_VERSION
template<typename...>
struct common_type;
// common_type for std::pairs
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<std::pair<F1, S1>, ::ranges::common_pair<F2, S2>>;
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<::ranges::common_pair<F1, S1>, std::pair<F2, S2>>;
template<typename F1, typename S1, typename F2, typename S2>
struct common_type<::ranges::common_pair<F1, S1>, ::ranges::common_pair<F2, S2>>;
// common_type for std::tuples
template<typename... Ts, typename... Us>
struct common_type<::ranges::common_tuple<Ts...>, std::tuple<Us...>>;
template<typename... Ts, typename... Us>
struct common_type<std::tuple<Ts...>, ::ranges::common_tuple<Us...>>;
template<typename... Ts, typename... Us>
struct common_type<::ranges::common_tuple<Ts...>, ::ranges::common_tuple<Us...>>;
template<typename, typename, template<typename> class, template<typename> class>
struct basic_common_reference;
// A common reference for std::pairs
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<::ranges::common_pair<F1, S1>, std::pair<F2, S2>, Qual1, Qual2>;
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<std::pair<F1, S1>, ::ranges::common_pair<F2, S2>, Qual1, Qual2>;
template<typename F1, typename S1, typename F2, typename S2,
template<typename> class Qual1, template<typename> class Qual2>
struct basic_common_reference<::ranges::common_pair<F1, S1>, ::ranges::common_pair<F2, S2>, Qual1, Qual2>;
// A common reference for std::tuples
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<::ranges::common_tuple<Ts...>, std::tuple<Us...>, Qual1, Qual2>;
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<std::tuple<Ts...>, ::ranges::common_tuple<Us...>, Qual1, Qual2>;
template<typename... Ts, typename... Us, template<typename> class Qual1,
template<typename> class Qual2>
struct basic_common_reference<::ranges::common_tuple<Ts...>, ::ranges::common_tuple<Us...>, Qual1, Qual2>;
RANGES_END_NAMESPACE_VERSION
RANGES_END_NAMESPACE_STD
RANGES_DIAGNOSTIC_POP
#endif // RANGES_CXX_VER > RANGES_CXX_STD_17
/// \endcond
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,230 @@
/// \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_COMPRESSED_PAIR_HPP
#define RANGES_V3_UTILITY_COMPRESSED_PAIR_HPP
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace compressed_tuple_detail
{
// tagging individual elements with the complete type list disambiguates
// base classes when composing compressed_tuples recursively.
template<typename T, std::size_t I, typename... Ts>
using storage = box<T, meta::list<meta::size_t<I>, Ts...>>;
template<typename List, typename Indices>
struct compressed_tuple_;
template<typename... Ts, std::size_t... Is>
struct RANGES_EMPTY_BASES
compressed_tuple_<meta::list<Ts...>, meta::index_sequence<Is...>>
: storage<Ts, Is, Ts...>...
{
static_assert(same_as<meta::index_sequence<Is...>,
meta::make_index_sequence<sizeof...(Is)>>,
"What madness is this?!?");
compressed_tuple_() = default;
template<typename... Args,
meta::if_<meta::and_c<META_IS_CONSTRUCTIBLE(Ts, Args)...>, int> = 0>
constexpr compressed_tuple_(Args &&... args) noexcept(
meta::strict_and<std::is_nothrow_constructible<storage<Ts, Is, Ts...>,
Args>...>::value)
: storage<Ts, Is, Ts...>{static_cast<Args &&>(args)}...
{}
template<
typename... Us,
meta::if_<meta::and_c<META_IS_CONSTRUCTIBLE(Us, Ts const &)...>, int> = 0>
constexpr operator std::tuple<Us...>() const noexcept(
meta::strict_and<std::is_nothrow_constructible<Us, Ts const &>...>::value)
{
return std::tuple<Us...>{get<Is>(*this)...};
}
template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
friend constexpr T & get(compressed_tuple_ & tuple) noexcept
{
return static_cast<storage<T, I, Ts...> &>(tuple).get();
}
template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
friend constexpr T const & get(compressed_tuple_ const & tuple) noexcept
{
return static_cast<storage<T, I, Ts...> const &>(tuple).get();
}
template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
friend constexpr T && get(compressed_tuple_ && tuple) noexcept
{
return static_cast<storage<T, I, Ts...> &&>(tuple).get();
}
template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
friend constexpr T const && get(compressed_tuple_ const && tuple) noexcept
{
return static_cast<storage<T, I, Ts...> const &&>(tuple).get();
}
};
template<typename... Ts>
using compressed_tuple RANGES_DEPRECATED(
"ranges::compressed_tuple is deprecated.") =
compressed_tuple_<meta::list<Ts...>,
meta::make_index_sequence<sizeof...(Ts)>>;
} // namespace compressed_tuple_detail
/// \endcond
using compressed_tuple_detail::compressed_tuple;
struct make_compressed_tuple_fn
{
// clang-format off
template<typename... Args>
constexpr auto CPP_auto_fun(operator())(Args &&... args) (const)
(
return compressed_tuple<bind_element_t<Args>...>{
static_cast<Args &&>(args)...}
)
// clang-format on
};
/// \ingroup group-utility
/// \sa `make_compressed_tuple_fn`
RANGES_INLINE_VARIABLE(make_compressed_tuple_fn, make_compressed_tuple)
template<typename First, typename Second>
struct RANGES_EMPTY_BASES compressed_pair
: box<First, meta::size_t<0>>
, box<Second, meta::size_t<1>>
{
using first_type = First;
using second_type = Second;
compressed_pair() = default;
template(typename U, typename V)(
requires constructible_from<First, U> AND constructible_from<Second, V>)
constexpr compressed_pair(U && u, V && v) //
noexcept(noexcept(First((U &&) u)) && noexcept(Second((V &&) v)))
: box<First, meta::size_t<0>>{(U &&) u}
, box<Second, meta::size_t<1>>{(V &&) v}
{}
constexpr First & first() &
{
return this->box<First, meta::size_t<0>>::get();
}
constexpr First const & first() const &
{
return this->box<First, meta::size_t<0>>::get();
}
constexpr First && first() &&
{
return static_cast<First &&>(this->box<First, meta::size_t<0>>::get());
}
constexpr Second & second() &
{
return this->box<Second, meta::size_t<1>>::get();
}
constexpr Second const & second() const &
{
return this->box<Second, meta::size_t<1>>::get();
}
constexpr Second && second() &&
{
return static_cast<Second &&>(this->box<Second, meta::size_t<1>>::get());
}
template(typename F, typename S)(
requires convertible_to<First const &, F> AND
convertible_to<Second const &, S>)
constexpr
operator std::pair<F, S>() const
{
return std::pair<F, S>{first(), second()};
}
};
struct make_compressed_pair_fn
{
// clang-format off
template<typename First, typename Second>
constexpr auto CPP_auto_fun(operator())(First &&f, Second &&s) (const)
(
return compressed_pair<bind_element_t<First>, bind_element_t<Second>>{
static_cast<First &&>(f), static_cast<Second &&>(s)
}
)
// clang-format on
};
/// \ingroup group-utility
/// \sa `make_compressed_pair_fn`
RANGES_INLINE_VARIABLE(make_compressed_pair_fn, make_compressed_pair)
} // namespace ranges
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename... Ts, size_t... Is>
struct tuple_size<::ranges::compressed_tuple_detail::compressed_tuple_<
::meta::list<Ts...>, ::meta::index_sequence<Is...>>>
: integral_constant<size_t, sizeof...(Ts)>
{};
template<size_t I, typename... Ts, size_t... Is>
struct tuple_element<I, ::ranges::compressed_tuple_detail::compressed_tuple_<
::meta::list<Ts...>, ::meta::index_sequence<Is...>>>
{
using type = ::meta::at_c<::meta::list<Ts...>, I>;
};
template<typename First, typename Second>
struct tuple_size<::ranges::compressed_pair<First, Second>>
: integral_constant<size_t, 2>
{};
template<typename First, typename Second>
struct tuple_element<0, ::ranges::compressed_pair<First, Second>>
{
using type = First;
};
template<typename First, typename Second>
struct tuple_element<1, ::ranges::compressed_pair<First, Second>>
{
using type = Second;
};
} // namespace std
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,27 @@
// 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_CONCEPTS_HPP
#define RANGES_V3_UTILITY_CONCEPTS_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <concepts/concepts.hpp> instead.")
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/common_type.hpp>
#include <range/v3/utility/swap.hpp>
#endif

View File

@@ -0,0 +1,60 @@
/// \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_COPY_HPP
#define RANGES_V3_UTILITY_COPY_HPP
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-utility
/// @{
namespace aux
{
struct copy_fn : copy_tag
{
template(typename T)(
requires constructible_from<detail::decay_t<T>, T>)
constexpr auto operator()(T && t) const -> detail::decay_t<T>
{
return static_cast<T &&>(t);
}
/// \ingroup group-utility
/// \sa `copy_fn`
template<typename T>
friend constexpr auto operator|(T && t, copy_fn)
-> CPP_broken_friend_ret(detail::decay_t<T>)(
requires constructible_from<detail::decay_t<T>, T>)
{
return static_cast<T &&>(t);
}
};
/// \ingroup group-utility
/// \sa `copy_fn`
RANGES_INLINE_VARIABLE(copy_fn, copy)
} // namespace aux
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,22 @@
// Range v3 library
//
// Copyright Eric Niebler 2014-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_COUNTED_ITERATOR_HPP
#define RANGES_V3_UTILITY_COUNTED_ITERATOR_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/iterator/counted_iterator.hpp> "
"instead.")
#include <range/v3/iterator/counted_iterator.hpp>
#endif

View File

@@ -0,0 +1,22 @@
// 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_DANGLING_HPP
#define RANGES_V3_UTILITY_DANGLING_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/range/dangling.hpp> instead.")
#include <range/v3/range/dangling.hpp>
#endif

View File

@@ -0,0 +1,42 @@
// 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_FUNCTIONAL_HPP
#define RANGES_V3_UTILITY_FUNCTIONAL_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header has been deprecated. Please find what you are looking for in the "
"range/v3/functional/ directory.")
#include <range/v3/detail/with_braced_init_args.hpp>
#include <range/v3/functional/arithmetic.hpp>
#include <range/v3/functional/bind.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/comparisons.hpp>
#include <range/v3/functional/compose.hpp>
#include <range/v3/functional/concepts.hpp>
#include <range/v3/functional/identity.hpp>
#include <range/v3/functional/indirect.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/functional/not_fn.hpp>
#include <range/v3/functional/on.hpp>
#include <range/v3/functional/overload.hpp>
#include <range/v3/functional/pipeable.hpp>
#include <range/v3/functional/reference_wrapper.hpp>
namespace ranges
{
using detail::with_braced_init_args;
} // namespace ranges
#endif

View File

@@ -0,0 +1,73 @@
/// \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_GET_HPP
#define RANGES_V3_UTILITY_GET_HPP
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/detail/adl_get.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-utility Utility
/// @{
///
/// \cond
namespace _get_
{
/// \endcond
// clang-format off
template<std::size_t I, typename TupleLike>
constexpr auto CPP_auto_fun(get)(TupleLike &&t)
(
return detail::adl_get<I>(static_cast<TupleLike &&>(t))
)
template<typename T, typename TupleLike>
constexpr auto CPP_auto_fun(get)(TupleLike &&t)
(
return detail::adl_get<T>(static_cast<TupleLike &&>(t))
)
// clang-format on
template<typename T>
T & get(meta::id_t<T> & value) noexcept
{
return value;
}
template<typename T>
T const & get(meta::id_t<T> const & value) noexcept
{
return value;
}
template<typename T>
T && get(meta::id_t<T> && value) noexcept
{
return static_cast<T &&>(value);
}
/// \cond
} // namespace _get_
using namespace _get_;
/// \endcond
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,33 @@
/// \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_IN_PLACE_HPP
#define RANGES_V3_UTILITY_IN_PLACE_HPP
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \ingroup group-utility
struct in_place_t
{};
RANGES_INLINE_VARIABLE(in_place_t, in_place)
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,71 @@
// Range v3 library
//
// Copyright Eric Niebler 2014-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_INFINITY_HPP
#define RANGES_V3_UTILITY_INFINITY_HPP
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated and will be removed from a future version of range-v3.")
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
struct infinity
{
friend constexpr bool operator==(infinity, infinity)
{
return true;
}
friend constexpr bool operator!=(infinity, infinity)
{
return false;
}
template<typename Integer>
friend constexpr auto operator==(Integer, infinity) noexcept
-> CPP_broken_friend_ret(bool)(
requires integral<Integer>)
{
return false;
}
template<typename Integer>
friend constexpr auto operator==(infinity, Integer) noexcept
-> CPP_broken_friend_ret(bool)(
requires integral<Integer>)
{
return false;
}
template<typename Integer>
friend constexpr auto operator!=(Integer, infinity) noexcept
-> CPP_broken_friend_ret(bool)(
requires integral<Integer>)
{
return true;
}
template<typename Integer>
friend constexpr auto operator!=(infinity, Integer) noexcept
-> CPP_broken_friend_ret(bool)(
requires integral<Integer>)
{
return true;
}
};
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,23 @@
// 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_INVOKE_HPP
#define RANGES_V3_UTILITY_INVOKE_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This file has been deprecated. Please #include <range/v3/functional/invoke.hpp> "
"instead.")
#include <range/v3/functional/invoke.hpp>
#endif

View File

@@ -0,0 +1,31 @@
// 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_ITERATOR_HPP
#define RANGES_V3_UTILITY_ITERATOR_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
R"(This header is deprecated. Please include one of the following depending on your need:
<range/v3/iterator/operations.hpp>,
<range/v3/iterator/insert_iterators.hpp>,
<range/v3/iterator/move_iterators.hpp>,
<range/v3/iterator/reverse_iterator.hpp>,
<range/v3/iterator/stream_iterators.hpp>)")
#include <range/v3/iterator/insert_iterators.hpp>
#include <range/v3/iterator/move_iterators.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/reverse_iterator.hpp>
#include <range/v3/iterator/stream_iterators.hpp>
#endif

View File

@@ -0,0 +1,23 @@
// 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_ITERATOR_CONCEPTS_HPP
#define RANGES_V3_UTILITY_ITERATOR_CONCEPTS_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/iterator/concepts.hpp> "
"instead.")
#include <range/v3/iterator/concepts.hpp>
#endif // RANGES_V3_UTILITY_ITERATOR_CONCEPTS_HPP

View File

@@ -0,0 +1,22 @@
// 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_ITERATOR_TRAITS_HPP
#define RANGES_V3_UTILITY_ITERATOR_TRAITS_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/iterator/traits.hpp> instead.")
#include <range/v3/iterator/traits.hpp>
#endif // RANGES_V3_UTILITY_ITERATOR_TRAITS_HPP

View File

@@ -0,0 +1,256 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014-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
//
//===-------------------------- algorithm ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef RANGES_V3_UTILITY_MEMORY_HPP
#define RANGES_V3_UTILITY_MEMORY_HPP
#include <cstdint>
#include <memory>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/detail/config.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/traits.hpp>
#include <range/v3/utility/polymorphic_cast.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename T>
std::pair<T *, std::ptrdiff_t> get_temporary_buffer_impl(std::size_t n) noexcept
{
if(n > PTRDIFF_MAX / sizeof(T))
n = PTRDIFF_MAX / sizeof(T);
void * ptr = nullptr;
for(; ptr == nullptr && n > 0; n /= 2)
{
#if RANGES_CXX_ALIGNED_NEW < RANGES_CXX_ALIGNED_NEW_17
static_assert(alignof(T) <= alignof(std::max_align_t),
"Sorry: over-aligned types are supported only with C++17.");
#else // RANGES_CXX_ALIGNED_NEW
if(RANGES_CONSTEXPR_IF(alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__))
ptr = ::operator new(
sizeof(T) * n, std::align_val_t{alignof(T)}, std::nothrow);
else
#endif // RANGES_CXX_ALIGNED_NEW
ptr = ::operator new(sizeof(T) * n, std::nothrow);
}
return {static_cast<T *>(ptr), static_cast<std::ptrdiff_t>(n)};
}
template<typename T, typename D>
std::pair<T *, std::ptrdiff_t> get_temporary_buffer(D count) noexcept
{
RANGES_EXPECT(count >= 0);
return detail::get_temporary_buffer_impl<T>(static_cast<std::size_t>(count));
}
struct return_temporary_buffer
{
template<typename T>
void operator()(T * p) const
{
#if RANGES_CXX_ALIGNED_NEW < RANGES_CXX_ALIGNED_NEW_17
static_assert(alignof(T) <= alignof(std::max_align_t),
"Sorry: over-aligned types are supported only with C++17.");
#else // RANGES_CXX_ALIGNED_NEW
if(RANGES_CONSTEXPR_IF(alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__))
::operator delete(p, std::align_val_t{alignof(T)});
else
#endif // RANGES_CXX_ALIGNED_NEW
::operator delete(p);
}
};
template(typename T, typename... Args)(
requires (!std::is_array<T>::value)) //
std::unique_ptr<T> make_unique(Args &&... args)
{
return std::unique_ptr<T>{new T(static_cast<Args &&>(args)...)};
}
} // namespace detail
/// \endcond
/// \addtogroup group-utility
/// @{
template<typename O, typename Val>
struct raw_storage_iterator
{
private:
CPP_assert(output_iterator<O, Val>);
CPP_assert(std::is_lvalue_reference<iter_reference_t<O>>());
O out_;
public:
using difference_type = iter_difference_t<O>;
raw_storage_iterator() = default;
explicit raw_storage_iterator(O out)
: out_(std::move(out))
{}
raw_storage_iterator & operator*() noexcept
{
return *this;
}
CPP_member
auto operator=(Val const & val) //
-> CPP_ret(raw_storage_iterator &)(
requires copy_constructible<Val>)
{
::new((void *)std::addressof(*out_)) Val(val);
return *this;
}
CPP_member
auto operator=(Val && val) //
-> CPP_ret(raw_storage_iterator &)(
requires move_constructible<Val>)
{
::new((void *)std::addressof(*out_)) Val(std::move(val));
return *this;
}
raw_storage_iterator & operator++()
{
++out_;
return *this;
}
CPP_member
auto operator++(int) //
-> CPP_ret(void)(
requires (!forward_iterator<O>))
{
++out_;
}
CPP_member
auto operator++(int) //
-> CPP_ret(raw_storage_iterator)(
requires forward_iterator<O>)
{
auto tmp = *this;
++out_;
return tmp;
}
O base() const
{
return out_;
}
};
template<typename I>
struct iterator_wrapper
{
private:
CPP_assert(input_or_output_iterator<I>);
mutable I * i_ = nullptr;
public:
using difference_type = iter_difference_t<I>;
iterator_wrapper() = default;
iterator_wrapper(iterator_wrapper const & that)
: i_(that.i_)
{
that.i_ = nullptr;
}
iterator_wrapper & operator=(iterator_wrapper const & that)
{
i_ = that.i_;
that.i_ = nullptr;
return *this;
}
iterator_wrapper(I & i)
: i_(std::addressof(i))
{}
// clang-format off
auto CPP_auto_fun(operator*)()(const)
(
return **i_
)
// clang-format on
iterator_wrapper &
operator++()
{
++*i_;
return *this;
}
void operator++(int)
{
++*i_;
}
I base() const
{
return *i_;
}
};
template(typename I)(
requires input_or_output_iterator<I>)
iterator_wrapper<I> iter_ref(I & i)
{
return i;
}
template<typename I>
struct indirectly_readable_traits<iterator_wrapper<I>>
: meta::if_c<(bool)input_iterator<I>, indirectly_readable_traits<I>, meta::nil_>
{};
template<typename Val>
struct raw_buffer
{
private:
Val * begin_;
raw_storage_iterator<Val *, Val> rsi_;
public:
explicit raw_buffer(Val * first)
: begin_(first)
, rsi_(first)
{}
raw_buffer(raw_buffer &&) = default;
raw_buffer(raw_buffer const &) = delete;
~raw_buffer()
{
for(; begin_ != rsi_.base(); ++begin_)
begin_->~Val();
}
iterator_wrapper<raw_storage_iterator<Val *, Val>> begin()
{
return ranges::iter_ref(rsi_);
}
};
template<typename Val>
raw_buffer<Val> make_raw_buffer(Val * val)
{
return raw_buffer<Val>(val);
}
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,65 @@
/// \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_MOVE_HPP
#define RANGES_V3_UTILITY_MOVE_HPP
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
namespace aux
{
/// \ingroup group-utility
struct move_fn : move_tag
{
template<typename T>
constexpr meta::_t<std::remove_reference<T>> && operator()(T && t) const //
noexcept
{
return static_cast<meta::_t<std::remove_reference<T>> &&>(t);
}
/// \ingroup group-utility
/// \sa `move_fn`
template<typename T>
friend constexpr decltype(auto) operator|(T && t, move_fn move) noexcept
{
return move(t);
}
};
/// \ingroup group-utility
/// \sa `move_fn`
RANGES_INLINE_VARIABLE(move_fn, move)
/// \ingroup group-utility
/// \sa `move_fn`
template<typename R>
using move_t =
meta::if_c<std::is_reference<R>::value, meta::_t<std::remove_reference<R>> &&,
detail::decay_t<R>>;
} // namespace aux
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,40 @@
// Range v3 library
//
// Copyright Eric Niebler 2013,2014.
//
// 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_NULLPTR_V_HPP
#define RANGES_V3_UTILITY_NULLPTR_V_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated and will be removed from a future version of range-v3.")
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \ingroup group-utility
template<typename T>
constexpr T * _nullptr_v()
{
return nullptr;
}
#if RANGES_CXX_VARIABLE_TEMPLATES
/// \ingroup group-utility
template<typename T>
constexpr T * nullptr_v = nullptr;
#endif
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,996 @@
/// \file
// Range v3 library
//
// Copyright Casey Carter 2017
//
// 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_OPTIONAL_HPP
#define RANGES_V3_UTILITY_OPTIONAL_HPP
#include <exception>
#include <initializer_list>
#include <memory>
#include <new>
#include <concepts/concepts.hpp>
#include <range/v3/detail/config.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/utility/in_place.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/utility/swap.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
template<typename>
struct optional;
struct bad_optional_access : std::exception
{
virtual const char * what() const noexcept override
{
return "bad optional access";
}
};
struct nullopt_t
{
struct tag
{};
constexpr explicit nullopt_t(tag) noexcept
{}
};
#if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
inline constexpr nullopt_t nullopt{nullopt_t::tag{}};
#else
/// \cond
namespace detail
{
template<typename>
struct nullopt_holder
{
static constexpr nullopt_t nullopt{nullopt_t::tag{}};
};
template<typename T>
constexpr nullopt_t nullopt_holder<T>::nullopt;
} // namespace detail
/// \endcond
namespace
{
constexpr auto & nullopt = detail::nullopt_holder<void>::nullopt;
}
#endif
/// \cond
namespace detail
{
template<typename = void>
[[noreturn]] bool throw_bad_optional_access()
{
throw bad_optional_access{};
}
namespace optional_adl
{
template<typename T, bool = std::is_trivially_destructible<T>::value>
struct optional_storage
{
union
{
char dummy_;
meta::_t<std::remove_cv<T>> data_;
};
bool engaged_;
constexpr optional_storage() noexcept
: optional_storage(
tag{},
meta::bool_<detail::is_trivially_default_constructible_v<T> &&
detail::is_trivially_copyable_v<T>>{})
{}
template(typename... Args)(
requires constructible_from<T, Args...>)
constexpr explicit optional_storage(in_place_t,
Args &&... args) //
noexcept(std::is_nothrow_constructible<T, Args...>::value)
: data_(static_cast<Args &&>(args)...)
, engaged_{true}
{}
constexpr void reset() noexcept
{
engaged_ = false;
}
private:
struct tag
{};
constexpr optional_storage(tag, std::false_type) noexcept
: dummy_{}
, engaged_{false}
{}
constexpr optional_storage(tag, std::true_type) noexcept
: data_{}
, engaged_{false}
{}
};
template<typename T>
struct optional_storage<T, false>
{
union
{
char dummy_;
meta::_t<std::remove_cv<T>> data_;
};
bool engaged_;
~optional_storage()
{
reset();
}
constexpr optional_storage() noexcept
: dummy_{}
, engaged_{false}
{}
template(typename... Args)(
requires constructible_from<T, Args...>)
constexpr explicit optional_storage(in_place_t,
Args &&... args) //
noexcept(std::is_nothrow_constructible<T, Args...>::value)
: data_(static_cast<Args &&>(args)...)
, engaged_{true}
{}
optional_storage(optional_storage const &) = default;
optional_storage(optional_storage &&) = default;
optional_storage & operator=(optional_storage const &) = default;
optional_storage & operator=(optional_storage &&) = default;
void reset() noexcept
{
if(engaged_)
{
data_.~T();
engaged_ = false;
}
}
};
template<typename T>
struct optional_base : private optional_storage<T>
{
using optional_storage<T>::optional_storage;
using optional_storage<T>::reset;
constexpr bool has_value() const noexcept
{
return engaged_;
}
constexpr T & operator*() & noexcept
{
return RANGES_EXPECT(engaged_), data_;
}
constexpr T const & operator*() const & noexcept
{
return RANGES_EXPECT(engaged_), data_;
}
constexpr T && operator*() && noexcept
{
return RANGES_EXPECT(engaged_), detail::move(data_);
}
constexpr T const && operator*() const && noexcept
{
return RANGES_EXPECT(engaged_), detail::move(data_);
}
constexpr T * operator->() noexcept
{
return RANGES_EXPECT(engaged_), detail::addressof(data_);
}
constexpr T const * operator->() const noexcept
{
return RANGES_EXPECT(engaged_), detail::addressof(data_);
}
CPP_member
constexpr auto swap(optional_base & that) //
noexcept(std::is_nothrow_move_constructible<T>::value &&
is_nothrow_swappable<T>::value) //
-> CPP_ret(void)(
requires move_constructible<T> && swappable<T>)
{
constexpr bool can_swap_trivially =
!::concepts::adl_swap_detail::is_adl_swappable_v<T> &&
detail::is_trivially_move_constructible_v<T> &&
detail::is_trivially_move_assignable_v<T>;
swap_(meta::bool_<can_swap_trivially>{}, that);
}
protected:
template(typename... Args)(
requires constructible_from<T, Args...>)
T & construct_from(Args &&... args)
noexcept(std::is_nothrow_constructible<T, Args...>::value)
{
RANGES_EXPECT(!engaged_);
auto const address = static_cast<void *>(std::addressof(data_));
::new(address) T(static_cast<Args &&>(args)...);
engaged_ = true;
return data_;
}
template(typename I)(
requires constructible_from<T, decltype(*std::declval<const I &>())>)
T & construct_from_deref(const I & it)
{
RANGES_EXPECT(!engaged_);
auto const address = static_cast<void *>(std::addressof(data_));
::new(address) T(*it);
engaged_ = true;
return data_;
}
template<typename U>
constexpr void assign_from(U && that) noexcept(
std::is_nothrow_constructible<T, decltype(*static_cast<U &&>(that))>::
value && std::is_nothrow_assignable<
T &, decltype(*static_cast<U &&>(that))>::value)
{
if(!that.has_value())
reset();
else if(engaged_)
data_ = *static_cast<U &&>(that);
else
{
auto const address =
static_cast<void *>(detail::addressof(data_));
::new(address) T(*static_cast<U &&>(that));
engaged_ = true;
}
}
private:
constexpr void swap_(std::true_type, optional_base & that) noexcept
{
ranges::swap(static_cast<optional_storage<T> &>(*this),
static_cast<optional_storage<T> &>(that));
}
constexpr void swap_(std::false_type, optional_base & that) noexcept(
std::is_nothrow_move_constructible<T>::value &&
is_nothrow_swappable<T>::value)
{
if(that.engaged_ == engaged_)
{
if(engaged_)
ranges::swap(data_, that.data_);
}
else
{
auto & src = engaged_ ? *this : that;
auto & dst = engaged_ ? that : *this;
dst.construct_from(detail::move(src.data_));
src.reset();
}
}
using optional_storage<T>::engaged_;
using optional_storage<T>::data_;
};
template<typename T>
struct optional_base<T &>
{
optional_base() = default;
template(typename Arg)(
requires constructible_from<T &, Arg>)
constexpr explicit optional_base(in_place_t, Arg && arg) noexcept //
: ptr_(detail::addressof(arg))
{}
constexpr bool has_value() const noexcept
{
return ptr_;
}
constexpr T & operator*() const noexcept
{
return RANGES_EXPECT(ptr_), *ptr_;
}
constexpr T * operator->() const noexcept
{
return RANGES_EXPECT(ptr_), ptr_;
}
constexpr void reset() noexcept
{
ptr_ = nullptr;
}
CPP_member
constexpr auto swap(optional_base & that) //
noexcept(is_nothrow_swappable<T>::value) //
-> CPP_ret(void)(
requires swappable<T>)
{
if(ptr_ && that.ptr_)
ranges::swap(*ptr_, *that.ptr_);
else
ranges::swap(ptr_, that.ptr_);
}
protected:
template(typename U)(
requires convertible_to<U &, T &>)
constexpr T & construct_from(U && ref) noexcept
{
RANGES_EXPECT(!ptr_);
ptr_ = detail::addressof(ref);
return *ptr_;
}
template<typename U>
constexpr void assign_from(U && that)
{
if(ptr_ && that.ptr_)
*ptr_ = *that.ptr_;
else
ptr_ = that.ptr_;
}
private:
T * ptr_ = nullptr;
};
template<typename T>
struct optional_copy : optional_base<T>
{
optional_copy() = default;
optional_copy(optional_copy const & that) noexcept(
std::is_nothrow_copy_constructible<T>::value)
{
if(that.has_value())
this->construct_from(*that);
}
optional_copy(optional_copy &&) = default;
optional_copy & operator=(optional_copy const &) = default;
optional_copy & operator=(optional_copy &&) = default;
using optional_base<T>::optional_base;
};
template<typename T>
using copy_construct_layer =
meta::if_c<std::is_copy_constructible<T>::value &&
!detail::is_trivially_copy_constructible_v<T>,
optional_copy<T>, optional_base<T>>;
template<typename T>
struct optional_move : copy_construct_layer<T>
{
optional_move() = default;
optional_move(optional_move const &) = default;
optional_move(optional_move && that) noexcept(
std::is_nothrow_move_constructible<T>::value)
{
if(that.has_value())
this->construct_from(std::move(*that));
}
optional_move & operator=(optional_move const &) = default;
optional_move & operator=(optional_move &&) = default;
using copy_construct_layer<T>::copy_construct_layer;
};
template<typename T>
using move_construct_layer =
meta::if_c<std::is_move_constructible<T>::value &&
!detail::is_trivially_move_constructible_v<T>,
optional_move<T>, copy_construct_layer<T>>;
template<typename T>
struct optional_copy_assign : move_construct_layer<T>
{
optional_copy_assign() = default;
optional_copy_assign(optional_copy_assign const &) = default;
optional_copy_assign(optional_copy_assign &&) = default;
optional_copy_assign & operator=(optional_copy_assign const & that) //
noexcept(std::is_nothrow_copy_constructible<T>::value &&
std::is_nothrow_copy_assignable<T>::value)
{
this->assign_from(that);
return *this;
}
optional_copy_assign & operator=(optional_copy_assign &&) = default;
using move_construct_layer<T>::move_construct_layer;
};
template<typename T>
struct deleted_copy_assign : move_construct_layer<T>
{
deleted_copy_assign() = default;
deleted_copy_assign(deleted_copy_assign const &) = default;
deleted_copy_assign(deleted_copy_assign &&) = default;
deleted_copy_assign & operator=(deleted_copy_assign const &) = delete;
deleted_copy_assign & operator=(deleted_copy_assign &&) = default;
using move_construct_layer<T>::move_construct_layer;
};
template<typename T>
using copy_assign_layer = meta::if_c<
std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
meta::if_c<std::is_reference<T>::value ||
!(detail::is_trivially_copy_constructible_v<T> &&
detail::is_trivially_copy_assignable_v<T>),
optional_copy_assign<T>, move_construct_layer<T>>,
deleted_copy_assign<T>>;
template<typename T>
struct optional_move_assign : copy_assign_layer<T>
{
optional_move_assign() = default;
optional_move_assign(optional_move_assign const &) = default;
optional_move_assign(optional_move_assign &&) = default;
optional_move_assign & operator=(optional_move_assign const &) = default;
optional_move_assign & operator=(optional_move_assign && that) noexcept(
std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value)
{
this->assign_from(std::move(that));
return *this;
}
using copy_assign_layer<T>::copy_assign_layer;
};
template<typename T>
struct deleted_move_assign : copy_assign_layer<T>
{
deleted_move_assign() = default;
deleted_move_assign(deleted_move_assign const &) = default;
deleted_move_assign(deleted_move_assign &&) = default;
deleted_move_assign & operator=(deleted_move_assign const &) = default;
deleted_move_assign & operator=(deleted_move_assign &&) = delete;
using copy_assign_layer<T>::copy_assign_layer;
};
template<typename T>
using move_assign_layer = meta::if_c<
std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,
meta::if_c<std::is_reference<T>::value ||
!(detail::is_trivially_move_constructible_v<T> &&
detail::is_trivially_move_assignable_v<T>),
optional_move_assign<T>, copy_assign_layer<T>>,
deleted_move_assign<T>>;
} // namespace optional_adl
} // namespace detail
/// \endcond
// clang-format off
/// \concept optional_should_convert
/// \brief The \c optional_should_convert concept
template<typename U, typename T>
CPP_concept optional_should_convert =
!(
constructible_from<T, optional<U> & > ||
constructible_from<T, optional<U> && > ||
constructible_from<T, optional<U> const & > ||
constructible_from<T, optional<U> const &&> ||
convertible_to<optional<U> &, T> ||
convertible_to<optional<U> &&, T> ||
convertible_to<optional<U> const &, T> ||
convertible_to<optional<U> const &&, T>
);
/// \concept optional_should_convert_assign
/// \brief The \c optional_should_convert_assign concept
template<typename U, typename T>
CPP_concept optional_should_convert_assign =
optional_should_convert<U, T> &&
!(assignable_from<T &, optional<U> &> ||
assignable_from<T &, optional<U> &&> ||
assignable_from<T &, optional<U> const &> ||
assignable_from<T &, optional<U> const &&>);
// clang-format on
template<typename T>
struct optional : detail::optional_adl::move_assign_layer<T>
{
private:
using base_t = detail::optional_adl::move_assign_layer<T>;
public:
CPP_assert(destructible<T>);
static_assert(std::is_object<T>::value || std::is_lvalue_reference<T>::value, "");
static_assert((bool)!same_as<nullopt_t, uncvref_t<T>>, "");
static_assert((bool)!same_as<in_place_t, uncvref_t<T>>, "");
using value_type = meta::_t<std::remove_cv<T>>;
constexpr optional() noexcept
{}
constexpr optional(nullopt_t) noexcept
: optional{}
{}
optional(optional const &) = default;
optional(optional &&) = default;
using base_t::base_t;
template(typename E, typename... Args)(
requires constructible_from<T, std::initializer_list<E> &, Args...>)
constexpr explicit optional(in_place_t, std::initializer_list<E> il,
Args &&... args) //
noexcept(std::is_nothrow_constructible<T, std::initializer_list<E> &,
Args...>::value)
: base_t(in_place, il, static_cast<Args &&>(args)...)
{}
#if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
template(typename U = T)(
requires (!same_as<detail::decay_t<U>, in_place_t>) AND
(!same_as<detail::decay_t<U>, optional>) AND
constructible_from<T, U>)
constexpr explicit(!convertible_to<U, T>) optional(U && v)
: base_t(in_place, static_cast<U &&>(v))
{}
template(typename U)(
requires optional_should_convert<U, T> AND
constructible_from<T, U const &>)
explicit(!convertible_to<U const &, T>) optional(optional<U> const & that)
{
if(that.has_value())
base_t::construct_from(*that);
}
#else
template(typename U = T)(
requires (!same_as<detail::decay_t<U>, in_place_t>) AND
(!same_as<detail::decay_t<U>, optional>) AND
constructible_from<T, U> AND
convertible_to<U, T>)
constexpr optional(U && v)
: base_t(in_place, static_cast<U &&>(v))
{}
template(typename U = T)(
requires (!same_as<detail::decay_t<U>, in_place_t>) AND
(!same_as<detail::decay_t<U>, optional>) AND
constructible_from<T, U> AND
(!convertible_to<U, T>))
constexpr explicit optional(U && v)
: base_t(in_place, static_cast<U &&>(v))
{}
template(typename U)(
requires optional_should_convert<U, T> AND
constructible_from<T, U const &> AND
convertible_to<U const &, T>)
optional(optional<U> const & that)
{
if(that.has_value())
base_t::construct_from(*that);
}
template(typename U)(
requires optional_should_convert<U, T> AND
constructible_from<T, U const &> AND
(!convertible_to<U const &, T>))
explicit optional(optional<U> const & that)
{
if(that.has_value())
base_t::construct_from(*that);
}
#endif
template(typename U)(
requires optional_should_convert<U, T> AND constructible_from<T, U> AND
convertible_to<U, T>)
optional(optional<U> && that)
{
if(that.has_value())
base_t::construct_from(detail::move(*that));
}
template(typename U)(
requires optional_should_convert<U, T> AND constructible_from<T, U> AND
(!convertible_to<U, T>)) //
explicit optional(optional<U> && that)
{
if(that.has_value())
base_t::construct_from(detail::move(*that));
}
constexpr optional & operator=(nullopt_t) noexcept
{
reset();
return *this;
}
optional & operator=(optional const &) = default;
optional & operator=(optional &&) = default;
template(typename U = T)(
requires (!same_as<optional, detail::decay_t<U>>) AND
(!(satisfies<T, std::is_scalar> && same_as<T, detail::decay_t<U>>)) AND
constructible_from<T, U> AND
assignable_from<T &, U>)
constexpr optional & operator=(U && u) noexcept(
std::is_nothrow_constructible<T, U>::value &&
std::is_nothrow_assignable<T &, U>::value)
{
if(has_value())
**this = static_cast<U &&>(u);
else
base_t::construct_from(static_cast<U &&>(u));
return *this;
}
template(typename U)(
requires optional_should_convert_assign<U, T> AND
constructible_from<T, const U &> AND
assignable_from<T &, const U &>)
constexpr optional & operator=(optional<U> const & that)
{
base_t::assign_from(that);
return *this;
}
template(typename U)(
requires optional_should_convert_assign<U, T> AND
constructible_from<T, U> AND
assignable_from<T &, U>)
constexpr optional & operator=(optional<U> && that)
{
base_t::assign_from(std::move(that));
return *this;
}
template(typename I)(
requires constructible_from<T, decltype(*std::declval<const I &>())>)
T & emplace_deref(const I & it)
{
reset();
return base_t::construct_from_deref(it);
}
template(typename... Args)(
requires constructible_from<T, Args...>)
T & emplace(Args &&... args) noexcept(
std::is_nothrow_constructible<T, Args...>::value)
{
reset();
return base_t::construct_from(static_cast<Args &&>(args)...);
}
template(typename E, typename... Args)(
requires constructible_from<T, std::initializer_list<E> &, Args...>)
T & emplace(std::initializer_list<E> il, Args &&... args) noexcept(
std::is_nothrow_constructible<T, std::initializer_list<E> &, Args...>::value)
{
reset();
return base_t::construct_from(il, static_cast<Args &&>(args)...);
}
using base_t::swap;
using base_t::operator->;
using base_t::operator*;
constexpr explicit operator bool() const noexcept
{
return has_value();
}
using base_t::has_value;
constexpr T const & value() const &
{
return (has_value() || detail::throw_bad_optional_access()), **this;
}
constexpr T & value() &
{
return (has_value() || detail::throw_bad_optional_access()), **this;
}
constexpr T const && value() const &&
{
return (has_value() || detail::throw_bad_optional_access()),
detail::move(**this);
}
constexpr T && value() &&
{
return (has_value() || detail::throw_bad_optional_access()),
detail::move(**this);
}
template(typename U)(
requires copy_constructible<T> AND convertible_to<U, T>)
constexpr T value_or(U && u) const &
{
return has_value() ? **this : static_cast<T>((U &&) u);
}
template(typename U)(
requires move_constructible<T> AND convertible_to<U, T>)
constexpr T value_or(U && u) &&
{
return has_value() ? detail::move(**this) : static_cast<T>((U &&) u);
}
using base_t::reset;
};
/// \cond
namespace detail
{
namespace optional_adl
{
constexpr bool convert_bool(bool b) noexcept
{
return b;
}
// Relational operators [optional.relops]
template<typename T, typename U>
constexpr auto operator==(optional<T> const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(*x == *y)))
-> decltype(convert_bool(*x == *y))
{
return x.has_value() == y.has_value() && (!x || convert_bool(*x == *y));
}
template<typename T, typename U>
constexpr auto operator!=(optional<T> const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(*x != *y)))
-> decltype(convert_bool(*x != *y))
{
return x.has_value() != y.has_value() || (x && convert_bool(*x != *y));
}
template<typename T, typename U>
constexpr auto operator<(optional<T> const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(*x < *y)))
-> decltype(convert_bool(*x < *y))
{
return y && (!x || convert_bool(*x < *y));
}
template<typename T, typename U>
constexpr auto operator>(optional<T> const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(*x > *y)))
-> decltype(convert_bool(*x > *y))
{
return x && (!y || convert_bool(*x > *y));
}
template<typename T, typename U>
constexpr auto operator<=(optional<T> const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(*x <= *y)))
-> decltype(convert_bool(*x <= *y))
{
return !x || (y && convert_bool(*x <= *y));
}
template<typename T, typename U>
constexpr auto operator>=(optional<T> const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(*x >= *y)))
-> decltype(convert_bool(*x >= *y))
{
return !y || (x && convert_bool(*x >= *y));
}
// Comparisons with nullopt [optional.nullops]
template<typename T>
constexpr bool operator==(optional<T> const & x, nullopt_t) noexcept
{
return !x;
}
template<typename T>
constexpr bool operator==(nullopt_t, optional<T> const & x) noexcept
{
return !x;
}
template<typename T>
constexpr bool operator!=(optional<T> const & x, nullopt_t) noexcept
{
return !!x;
}
template<typename T>
constexpr bool operator!=(nullopt_t, optional<T> const & x) noexcept
{
return !!x;
}
template<typename T>
constexpr bool operator<(optional<T> const &, nullopt_t) noexcept
{
return false;
}
template<typename T>
constexpr bool operator<(nullopt_t, optional<T> const & x) noexcept
{
return !!x;
}
template<typename T>
constexpr bool operator>(optional<T> const & x, nullopt_t) noexcept
{
return !!x;
}
template<typename T>
constexpr bool operator>(nullopt_t, optional<T> const &) noexcept
{
return false;
}
template<typename T>
constexpr bool operator<=(optional<T> const & x, nullopt_t) noexcept
{
return !x;
}
template<typename T>
constexpr bool operator<=(nullopt_t, optional<T> const &) noexcept
{
return true;
}
template<typename T>
constexpr bool operator>=(optional<T> const &, nullopt_t) noexcept
{
return true;
}
template<typename T>
constexpr bool operator>=(nullopt_t, optional<T> const & x) noexcept
{
return !x;
}
// Comparisons with T [optional.comp_with_t]
template<typename T, typename U>
constexpr auto operator==(optional<T> const & x, U const & y) //
noexcept(noexcept(convert_bool(*x == y))) //
-> decltype(convert_bool(*x == y))
{
return x && convert_bool(*x == y);
}
template<typename T, typename U>
constexpr auto operator==(T const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(x == *y))) //
-> decltype(convert_bool(x == *y))
{
return y && convert_bool(x == *y);
}
template<typename T, typename U>
constexpr auto operator!=(optional<T> const & x, U const & y) //
noexcept(noexcept(convert_bool(*x != y))) //
-> decltype(convert_bool(*x != y))
{
return !x || convert_bool(*x != y);
}
template<typename T, typename U>
constexpr auto operator!=(T const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(x != *y))) //
-> decltype(convert_bool(x != *y))
{
return !y || convert_bool(x != *y);
}
template<typename T, typename U>
constexpr auto operator<(optional<T> const & x, U const & y) //
noexcept(noexcept(convert_bool(*x < y))) //
-> decltype(convert_bool(*x < y))
{
return !x || convert_bool(*x < y);
}
template<typename T, typename U>
constexpr auto operator<(T const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(x < *y))) //
-> decltype(convert_bool(x < *y))
{
return y && convert_bool(x < *y);
}
template<typename T, typename U>
constexpr auto operator>(optional<T> const & x, U const & y) //
noexcept(noexcept(convert_bool(*x > y))) -> decltype(convert_bool(*x > y))
{
return x && convert_bool(*x > y);
}
template<typename T, typename U>
constexpr auto operator>(T const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(x > *y))) //
-> decltype(convert_bool(x > *y))
{
return !y || convert_bool(x > *y);
}
template<typename T, typename U>
constexpr auto operator<=(optional<T> const & x, U const & y) //
noexcept(noexcept(convert_bool(*x <= y))) //
-> decltype(convert_bool(*x <= y))
{
return !x || convert_bool(*x <= y);
}
template<typename T, typename U>
constexpr auto operator<=(T const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(x <= *y))) //
-> decltype(convert_bool(x <= *y))
{
return y && convert_bool(x <= *y);
}
template<typename T, typename U>
constexpr auto operator>=(optional<T> const & x, U const & y) //
noexcept(noexcept(convert_bool(*x >= y))) //
-> decltype(convert_bool(*x >= y))
{
return x && convert_bool(*x >= y);
}
template<typename T, typename U>
constexpr auto operator>=(T const & x, optional<U> const & y) //
noexcept(noexcept(convert_bool(x >= *y))) //
-> decltype(convert_bool(x >= *y))
{
return !y || convert_bool(x >= *y);
}
// clang-format off
template<typename T>
auto CPP_auto_fun(swap)(optional<T> &x, optional<T> &y)
(
return x.swap(y)
)
// clang-format on
} // namespace optional_adl
} // namespace detail
/// \endcond
// clang-format off
template<typename T>
constexpr auto CPP_auto_fun(make_optional)(T &&t)
(
return optional<detail::decay_t<T>>{static_cast<T &&>(t)}
)
template<typename T, typename... Args>
constexpr auto CPP_auto_fun(make_optional)(Args &&... args)
(
return optional<T>{in_place, static_cast<Args &&>(args)...}
)
template<typename T, typename U, typename... Args>
constexpr auto CPP_auto_fun(make_optional)(std::initializer_list<U> il,
Args &&... args)
(
return optional<T>{in_place, il, static_cast<Args &&>(args)...}
)
// clang-format on
/// \cond
namespace detail
{
template<typename T, typename Tag = void, bool Enable = true>
struct non_propagating_cache : optional<T>
{
non_propagating_cache() = default;
constexpr non_propagating_cache(nullopt_t) noexcept
{}
constexpr non_propagating_cache(non_propagating_cache const &) noexcept
: optional<T>{}
{}
constexpr non_propagating_cache(non_propagating_cache && that) noexcept
: optional<T>{}
{
that.optional<T>::reset();
}
constexpr non_propagating_cache & operator=(
non_propagating_cache const &) noexcept
{
optional<T>::reset();
return *this;
}
constexpr non_propagating_cache & operator=(
non_propagating_cache && that) noexcept
{
that.optional<T>::reset();
optional<T>::reset();
return *this;
}
using optional<T>::operator=;
template<class I>
constexpr T & emplace_deref(const I & i)
{
return optional<T>::emplace(*i);
}
};
template<typename T, typename Tag>
struct non_propagating_cache<T, Tag, false>
{};
} // namespace detail
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,46 @@
// (C) Copyright Kevlin Henney and Dave Abrahams 1999.
// 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)
#ifndef RANGES_V3_UTILITY_POLYMORPHIC_CAST_HPP
#define RANGES_V3_UTILITY_POLYMORPHIC_CAST_HPP
#include <memory>
#include <type_traits>
#include <meta/meta.hpp>
#include <range/v3/detail/config.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
template<typename Target, typename Source>
auto polymorphic_downcast(Source * x) noexcept
-> meta::if_<std::is_pointer<Target>,
decltype((static_cast<Target>(x), dynamic_cast<Target>(x)))>
{
auto result = static_cast<Target>(x);
RANGES_ASSERT(dynamic_cast<Target>(x) == result);
return result;
}
template<typename Target, typename Source>
auto polymorphic_downcast(Source && x) noexcept
-> meta::if_<std::is_reference<Target>,
decltype((static_cast<Target>(std::declval<Source>()),
dynamic_cast<Target>(std::declval<Source>())))>
{
auto && result = static_cast<Target>(static_cast<Source &&>(x));
#ifndef NDEBUG
auto && dresult = dynamic_cast<Target>(static_cast<Source &&>(x));
RANGES_ASSERT(std::addressof(dresult) == std::addressof(result));
#endif
return static_cast<Target>(result);
}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif // RANGES_V3_UTILITY_POLYMORPHIC_CAST_HPP

View File

@@ -0,0 +1,497 @@
/// \file
// Range v3 library
//
// 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
//
/*
* Random-Number Utilities (randutil)
* Addresses common issues with C++11 random number generation.
* Makes good seeding easier, and makes using RNGs easy while retaining
* all the power.
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Melissa E. O'Neill
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RANGES_V3_UTILITY_RANDOM_HPP
#define RANGES_V3_UTILITY_RANDOM_HPP
#include <array>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <new>
#include <random>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/copy.hpp>
#include <range/v3/algorithm/generate.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/functional/reference_wrapper.hpp>
#include <range/v3/iterator/concepts.hpp>
#if !RANGES_CXX_THREAD_LOCAL
#include <mutex>
#endif
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT
namespace ranges
{
/// \addtogroup group-numerics
/// @{
// clang-format off
/// \concept uniform_random_bit_generator_
/// \brief The \c uniform_random_bit_generator_ concept
template<typename Gen>
CPP_requires(uniform_random_bit_generator_,
requires() //
(
Gen::min(),
Gen::max()
));
/// \concept uniform_random_bit_generator_
/// \brief The \c uniform_random_bit_generator_ concept
template(typename Gen)(
concept (uniform_random_bit_generator_)(Gen),
unsigned_integral<invoke_result_t<Gen &>> AND
same_as<invoke_result_t<Gen &>, decltype(Gen::min())> AND
same_as<invoke_result_t<Gen &>, decltype(Gen::max())>);
/// \concept uniform_random_bit_generator
/// \brief The \c uniform_random_bit_generator concept
template<typename Gen>
CPP_concept uniform_random_bit_generator =
invocable<Gen &> &&
CPP_requires_ref(ranges::uniform_random_bit_generator_, Gen) &&
CPP_concept_ref(ranges::uniform_random_bit_generator_, Gen);
// clang-format on
/// @}
/// \cond
namespace detail
{
namespace randutils
{
inline std::array<std::uint32_t, 8> get_entropy()
{
std::array<std::uint32_t, 8> seeds;
// Hopefully high-quality entropy from random_device.
#if defined(__GLIBCXX__) && defined(RANGES_WORKAROUND_VALGRIND_RDRAND)
std::random_device rd{"/dev/urandom"};
#else
std::random_device rd;
#endif
std::uniform_int_distribution<std::uint32_t> dist{};
ranges::generate(seeds, [&] { return dist(rd); });
return seeds;
}
template(typename I)(
requires unsigned_integral<I>)
constexpr I fast_exp(I x, I power, I result = I{1})
{
return power == I{0}
? result
: randutils::fast_exp(
x * x, power >> 1, result * (power & I{1} ? x : 1));
}
//////////////////////////////////////////////////////////////////////////////
//
// seed_seq_fe
//
//////////////////////////////////////////////////////////////////////////////
/*
* seed_seq_fe implements a fixed-entropy seed sequence; it conforms to all
* the requirements of a Seed Sequence concept.
*
* seed_seq_fe<N> implements a seed sequence which seeds based on a store of
* N * 32 bits of entropy. Typically, it would be initialized with N or more
* integers.
*
* seed_seq_fe128 and seed_seq_fe256 are provided as convenience typedefs for
* 128- and 256-bit entropy stores respectively. These variants outperform
* std::seed_seq, while being better mixing the bits it is provided as
* entropy. In almost all common use cases, they serve as better drop-in
* replacements for seed_seq.
*
* Technical details
*
* Assuming it constructed with M seed integers as input, it exhibits the
* following properties
*
* * Diffusion/Avalanche: A single-bit change in any of the M inputs has a
* 50% chance of flipping every bit in the bitstream produced by generate.
* Initializing the N-word entropy store with M words requires O(N * M)
* time precisely because of the avalanche requirements. Once constructed,
* calls to generate are linear in the number of words generated.
*
* * Bias freedom/Bijection: If M == N, the state of the entropy store is a
* bijection from the M inputs (i.e., no states occur twice, none are
* omitted). If M > N the number of times each state can occur is the same
* (each state occurs 2**(32*(M-N)) times, where ** is the power function).
* If M < N, some states cannot occur (bias) but no state occurs more
* than once (it's impossible to avoid bias if M < N; ideally N should not
* be chosen so that it is more than M).
*
* Likewise, the generate function has similar properties (with the entropy
* store as the input data). If more outputs are requested than there is
* entropy, some outputs cannot occur. For example, the Mersenne Twister
* will request 624 outputs, to initialize its 19937-bit state, which is
* much larger than a 128-bit or 256-bit entropy pool. But in practice,
* limiting the Mersenne Twister to 2**128 possible initializations gives
* us enough initializations to give a unique initialization to trillions
* of computers for billions of years. If you really have 624 words of
* *real* high-quality entropy you want to use, you probably don't need
* an entropy mixer like this class at all. But if you *really* want to,
* nothing is stopping you from creating a randutils::seed_seq_fe<624>.
*
* * As a consequence of the above properties, if all parts of the provided
* seed data are kept constant except one, and the remaining part is varied
* through K different states, K different output sequences will be
* produced.
*
* * Also, because the amount of entropy stored is fixed, this class never
* performs dynamic allocation and is free of the possibility of generating
* an exception.
*
* Ideas used to implement this code include hashing, a simple PCG generator
* based on an MCG base with an XorShift output function and permutation
* functions on tuples.
*
* More detail at
* http://www.pcg-random.org/posts/developing-a-seed_seq-alternative.html
*/
template<std::size_t count, typename IntRep = std::uint32_t>
struct seed_seq_fe
{
public:
CPP_assert(unsigned_integral<IntRep>);
typedef IntRep result_type;
private:
static constexpr std::size_t mix_rounds = 1 + (count <= 2);
static constexpr std::uint32_t INIT_A = 0x43b0d7e5;
static constexpr std::uint32_t MULT_A = 0x931e8875;
static constexpr std::uint32_t INIT_B = 0x8b51f9dd;
static constexpr std::uint32_t MULT_B = 0x58f38ded;
static constexpr std::uint32_t MIX_MULT_L = 0xca01f9dd;
static constexpr std::uint32_t MIX_MULT_R = 0x4973f715;
static constexpr std::uint32_t XSHIFT = sizeof(IntRep) * 8 / 2;
std::array<IntRep, count> mixer_;
template(typename I, typename S)(
requires input_iterator<I> AND sentinel_for<S, I> AND
convertible_to<iter_reference_t<I>, IntRep>)
void mix_entropy(I first, S last)
{
auto hash_const = INIT_A;
auto hash = [&](IntRep value) RANGES_INTENDED_MODULAR_ARITHMETIC {
value ^= hash_const;
hash_const *= MULT_A;
value *= hash_const;
value ^= value >> XSHIFT;
return value;
};
auto mix = [](IntRep x, IntRep y) RANGES_INTENDED_MODULAR_ARITHMETIC {
IntRep result = MIX_MULT_L * x - MIX_MULT_R * y;
result ^= result >> XSHIFT;
return result;
};
for(auto & elem : mixer_)
{
if(first != last)
{
elem = hash(static_cast<IntRep>(*first));
++first;
}
else
elem = hash(IntRep{0});
}
for(auto & src : mixer_)
for(auto & dest : mixer_)
if(&src != &dest)
dest = mix(dest, hash(src));
for(; first != last; ++first)
for(auto & dest : mixer_)
dest = mix(dest, hash(static_cast<IntRep>(*first)));
}
public:
seed_seq_fe(const seed_seq_fe &) = delete;
void operator=(const seed_seq_fe &) = delete;
template(typename T)(
requires convertible_to<T const &, IntRep>)
seed_seq_fe(std::initializer_list<T> init)
{
seed(init.begin(), init.end());
}
template(typename I, typename S)(
requires input_iterator<I> AND sentinel_for<S, I> AND
convertible_to<iter_reference_t<I>, IntRep>)
seed_seq_fe(I first, S last)
{
seed(first, last);
}
// generating functions
template(typename I, typename S)(
requires random_access_iterator<I> AND sentinel_for<S, I>)
RANGES_INTENDED_MODULAR_ARITHMETIC //
void generate(I first, S const last) const
{
auto src_begin = mixer_.begin();
auto src_end = mixer_.end();
auto src = src_begin;
auto hash_const = INIT_B;
for(; first != last; ++first)
{
auto dataval = *src;
if(++src == src_end)
src = src_begin;
dataval ^= hash_const;
hash_const *= MULT_B;
dataval *= hash_const;
dataval ^= dataval >> XSHIFT;
*first = dataval;
}
}
constexpr std::size_t size() const
{
return count;
}
template(typename O)(
requires weakly_incrementable<O> AND
indirectly_copyable<decltype(mixer_.begin()), O>)
RANGES_INTENDED_MODULAR_ARITHMETIC void param(O dest) const
{
constexpr IntRep INV_A = randutils::fast_exp(MULT_A, IntRep(-1));
constexpr IntRep MIX_INV_L =
randutils::fast_exp(MIX_MULT_L, IntRep(-1));
auto mixer_copy = mixer_;
for(std::size_t round = 0; round < mix_rounds; ++round)
{
// Advance to the final value. We'll backtrack from that.
auto hash_const =
INIT_A * randutils::fast_exp(MULT_A, IntRep(count * count));
for(auto src = mixer_copy.rbegin(); src != mixer_copy.rend();
++src)
for(auto rdest = mixer_copy.rbegin();
rdest != mixer_copy.rend();
++rdest)
if(src != rdest)
{
IntRep revhashed = *src;
auto mult_const = hash_const;
hash_const *= INV_A;
revhashed ^= hash_const;
revhashed *= mult_const;
revhashed ^= revhashed >> XSHIFT;
IntRep unmixed = *rdest;
unmixed ^= unmixed >> XSHIFT;
unmixed += MIX_MULT_R * revhashed;
unmixed *= MIX_INV_L;
*rdest = unmixed;
}
for(auto i = mixer_copy.rbegin(); i != mixer_copy.rend(); ++i)
{
IntRep unhashed = *i;
unhashed ^= unhashed >> XSHIFT;
unhashed *= randutils::fast_exp(hash_const, IntRep(-1));
hash_const *= INV_A;
unhashed ^= hash_const;
*i = unhashed;
}
}
ranges::copy(mixer_copy, dest);
}
template(typename I, typename S)(
requires input_iterator<I> AND sentinel_for<S, I> AND
convertible_to<iter_reference_t<I>, IntRep>)
void seed(I first, S last)
{
mix_entropy(first, last);
// For very small sizes, we do some additional mixing. For normal
// sizes, this loop never performs any iterations.
for(std::size_t i = 1; i < mix_rounds; ++i)
stir();
}
seed_seq_fe & stir()
{
mix_entropy(mixer_.begin(), mixer_.end());
return *this;
}
};
using seed_seq_fe128 = seed_seq_fe<4, std::uint32_t>;
using seed_seq_fe256 = seed_seq_fe<8, std::uint32_t>;
//////////////////////////////////////////////////////////////////////////////
//
// auto_seeded
//
//////////////////////////////////////////////////////////////////////////////
/*
* randutils::auto_seeded
*
* Extends a seed sequence class with a nondeterministic default
* constructor. Uses a variety of local sources of entropy to portably
* initialize any seed sequence to a good default state.
*
* In normal use, it's accessed via one of the following type aliases, which
* use seed_seq_fe128 and seed_seq_fe256 above.
*
* randutils::auto_seed_128
* randutils::auto_seed_256
*
* It's discussed in detail at
* http://www.pcg-random.org/posts/simple-portable-cpp-seed-entropy.html
* and its motivation (why you can't just use std::random_device) here
* http://www.pcg-random.org/posts/cpps-random_device.html
*/
template<typename SeedSeq>
struct auto_seeded : public SeedSeq
{
auto_seeded()
: auto_seeded(randutils::get_entropy())
{}
template<std::size_t N>
auto_seeded(std::array<std::uint32_t, N> const & seeds)
: SeedSeq(seeds.begin(), seeds.end())
{}
using SeedSeq::SeedSeq;
const SeedSeq & base() const
{
return *this;
}
SeedSeq & base()
{
return *this;
}
};
using auto_seed_128 = auto_seeded<seed_seq_fe128>;
using auto_seed_256 = auto_seeded<seed_seq_fe256>;
} // namespace randutils
using default_URNG = meta::if_c<(sizeof(void *) >= sizeof(long long)),
std::mt19937_64, std::mt19937>;
#if !RANGES_CXX_THREAD_LOCAL
template<typename URNG>
class sync_URNG : private URNG
{
mutable std::mutex mtx_;
public:
using URNG::URNG;
sync_URNG() = default;
using typename URNG::result_type;
result_type operator()()
{
std::lock_guard<std::mutex> guard{mtx_};
return static_cast<URNG &>(*this)();
}
using URNG::max;
using URNG::min;
};
using default_random_engine = sync_URNG<default_URNG>;
#else
using default_random_engine = default_URNG;
#endif
template<typename T = void>
default_random_engine & get_random_engine()
{
using Seeder = meta::if_c<(sizeof(default_URNG) > 16),
randutils::auto_seed_256,
randutils::auto_seed_128>;
#if RANGES_CXX_THREAD_LOCAL >= RANGES_CXX_THREAD_LOCAL_11
static thread_local default_random_engine engine{Seeder{}.base()};
#elif RANGES_CXX_THREAD_LOCAL
static __thread bool initialized = false;
static __thread meta::_t<std::aligned_storage<sizeof(default_random_engine),
alignof(default_random_engine)>>
storage;
if(!initialized)
{
::new(static_cast<void *>(&storage))
default_random_engine{Seeder{}.base()};
initialized = true;
}
auto & engine = reinterpret_cast<default_random_engine &>(storage);
#else
static default_random_engine engine{Seeder{}.base()};
#endif // RANGES_CXX_THREAD_LOCAL
return engine;
}
} // namespace detail
/// \endcond
} // namespace ranges
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,97 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2017-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_SCOPE_EXIT_HPP
#define RANGES_V3_UTILITY_SCOPE_EXIT_HPP
#include <functional>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
template<typename Fun>
struct scope_exit
{
private:
using nothrow_move_t = std::is_nothrow_move_constructible<Fun>;
using nothrow_copy_t = std::is_nothrow_copy_constructible<Fun>;
Fun fun_;
bool dismissed_{false};
using ref_t = decltype(std::ref(std::declval<Fun const &>()));
using guard = scope_exit<ref_t>;
scope_exit(Fun const & fun, guard && g)
: fun_(fun)
{
g.dismiss();
}
scope_exit(Fun const & fun, std::false_type)
: scope_exit(fun, guard{std::ref(fun)})
{}
scope_exit(Fun const & fun, std::true_type) noexcept
: fun_(fun)
{}
scope_exit(Fun && fun, std::true_type) noexcept
: fun_(std::move(fun))
{}
public:
explicit scope_exit(Fun const & fun) noexcept(
noexcept(scope_exit(fun, nothrow_copy_t{})))
: scope_exit(fun, nothrow_copy_t{})
{}
explicit scope_exit(Fun && fun) noexcept(noexcept(scope_exit(std::move(fun),
nothrow_move_t{})))
: scope_exit(std::move(fun), nothrow_move_t{})
{}
scope_exit(scope_exit const &) = delete;
scope_exit(scope_exit && that) noexcept(
std::is_nothrow_move_constructible<Fun>::value)
: scope_exit(std::move((that.dismiss(), that)).fun_)
{}
~scope_exit()
{
if(!dismissed_)
fun_();
}
void dismiss() noexcept
{
dismissed_ = true;
}
};
template<typename Fun, typename ScopeExit = scope_exit<meta::_t<std::decay<Fun>>>>
ScopeExit make_scope_exit(Fun && fun) noexcept(
noexcept(ScopeExit(ScopeExit((Fun &&) fun))))
{
return ScopeExit((Fun &&) fun);
}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,24 @@
/// \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_HPP
#define RANGES_V3_UTILITY_SEMIREGULAR_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include <range/v3/utility/semiregular_box.hpp> "
"instead.")
#include <range/v3/utility/semiregular_box.hpp>
#endif

View File

@@ -0,0 +1,333 @@
/// \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 <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/functional/concepts.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/functional/reference_wrapper.hpp>
#include <range/v3/utility/get.hpp>
#include <range/v3/utility/in_place.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
template<typename T>
struct semiregular_box;
namespace detail
{
struct semiregular_get
{
// clang-format off
template<typename T>
friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> &t)
(
return t.get()
)
template<typename T>
friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> const &t)
(
return t.get()
)
template<typename T>
friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> &&t)
(
return detail::move(t).get()
)
// clang-format on
};
} // namespace detail
/// \endcond
/// \addtogroup group-utility
/// @{
template<typename T>
struct semiregular_box : private detail::semiregular_get
{
private:
struct tag
{};
template<typename... Args>
void construct_from(Args &&... args)
{
new((void *)std::addressof(data_)) T(static_cast<Args &&>(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<T>::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<T>::value ||
!std::is_default_constructible<T>::value)
: semiregular_box(tag{}, std::is_default_constructible<T>{})
{}
semiregular_box(semiregular_box && that) noexcept(
std::is_nothrow_move_constructible<T>::value)
{
if(that.engaged_)
this->construct_from(detail::move(that.data_));
}
semiregular_box(semiregular_box const & that) noexcept(
std::is_nothrow_copy_constructible<T>::value)
{
if(that.engaged_)
this->construct_from(that.data_);
}
#if defined(__cpp_conditional_explicit) && 0 < __cpp_conditional_explicit
template(typename U)(
requires (!same_as<uncvref_t<U>, semiregular_box>) AND
constructible_from<T, U>)
explicit(!convertible_to<U, T>) constexpr semiregular_box(U && u)
noexcept(std::is_nothrow_constructible<T, U>::value)
: semiregular_box(in_place, static_cast<U &&>(u))
{}
#else
template(typename U)(
requires (!same_as<uncvref_t<U>, semiregular_box>) AND
constructible_from<T, U> AND (!convertible_to<U, T>)) //
constexpr explicit semiregular_box(U && u)
noexcept(std::is_nothrow_constructible<T, U>::value)
: semiregular_box(in_place, static_cast<U &&>(u))
{}
template(typename U)(
requires (!same_as<uncvref_t<U>, semiregular_box>) AND
constructible_from<T, U> AND convertible_to<U, T>)
constexpr semiregular_box(U && u)
noexcept(std::is_nothrow_constructible<T, U>::value)
: semiregular_box(in_place, static_cast<U &&>(u))
{}
#endif
template(typename... Args)(
requires constructible_from<T, Args...>)
constexpr semiregular_box(in_place_t, Args &&... args) //
noexcept(std::is_nothrow_constructible<T, Args...>::value)
: data_(static_cast<Args &&>(args)...)
, engaged_(true)
{}
~semiregular_box()
{
reset();
}
semiregular_box & operator=(semiregular_box && that) noexcept(
std::is_nothrow_move_constructible<T>::value &&
(!std::is_move_assignable<T>::value ||
std::is_nothrow_move_assignable<T>::value))
{
if(engaged_ && that.engaged_)
this->move_assign(detail::move(that.data_), std::is_move_assignable<T>());
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<T>::value &&
(!std::is_copy_assignable<T>::value ||
std::is_nothrow_copy_assignable<T>::value))
{
if(engaged_ && that.engaged_)
this->copy_assign(that.data_, std::is_copy_assignable<T>());
else if(that.engaged_)
this->construct_from(that.data_);
else if(engaged_)
this->reset();
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(typename... Args)(
requires invocable<T &, Args...>)
constexpr decltype(auto) operator()(Args &&... args) &
noexcept(is_nothrow_invocable_v<T &, Args...>)
{
return invoke(data_, static_cast<Args &&>(args)...);
}
template(typename... Args)(
requires invocable<T const &, Args...>)
constexpr decltype(auto) operator()(Args &&... args) const &
noexcept(is_nothrow_invocable_v<T const &, Args...>)
{
return invoke(data_, static_cast<Args &&>(args)...);
}
template(typename... Args)(
requires invocable<T, Args...>)
constexpr decltype(auto) operator()(Args &&... args) &&
noexcept(is_nothrow_invocable_v<T, Args...>)
{
return invoke(static_cast<T &&>(data_), static_cast<Args &&>(args)...);
}
template<typename... Args>
void operator()(Args &&...) const && = delete;
// clang-format on
};
template<typename T>
struct semiregular_box<T &>
: private ranges::reference_wrapper<T &>
, private detail::semiregular_get
{
semiregular_box() = default;
template(typename Arg)(
requires constructible_from<ranges::reference_wrapper<T &>, Arg &>)
semiregular_box(in_place_t, Arg & arg) noexcept //
: ranges::reference_wrapper<T &>(arg)
{}
using ranges::reference_wrapper<T &>::get;
using ranges::reference_wrapper<T &>::operator T &;
using ranges::reference_wrapper<T &>::operator();
#if defined(_MSC_VER)
template(typename U)(
requires (!same_as<uncvref_t<U>, semiregular_box>) AND
constructible_from<ranges::reference_wrapper<T &>, U>)
constexpr semiregular_box(U && u) noexcept(
std::is_nothrow_constructible<ranges::reference_wrapper<T &>, U>::value)
: ranges::reference_wrapper<T &>{static_cast<U &&>(u)}
{}
#else
using ranges::reference_wrapper<T &>::reference_wrapper;
#endif
};
template<typename T>
struct semiregular_box<T &&>
: private ranges::reference_wrapper<T &&>
, private detail::semiregular_get
{
semiregular_box() = default;
template(typename Arg)(
requires constructible_from<ranges::reference_wrapper<T &&>, Arg>)
semiregular_box(in_place_t, Arg && arg) noexcept //
: ranges::reference_wrapper<T &&>(static_cast<Arg &&>(arg))
{}
using ranges::reference_wrapper<T &&>::get;
using ranges::reference_wrapper<T &&>::operator T &&;
using ranges::reference_wrapper<T &&>::operator();
#if defined(_MSC_VER)
template(typename U)(
requires (!same_as<uncvref_t<U>, semiregular_box>) AND
constructible_from<ranges::reference_wrapper<T &&>, U>)
constexpr semiregular_box(U && u) noexcept(
std::is_nothrow_constructible<ranges::reference_wrapper<T &&>, U>::value)
: ranges::reference_wrapper<T &&>{static_cast<U &&>(u)}
{}
#else
using ranges::reference_wrapper<T &&>::reference_wrapper;
#endif
};
template<typename T>
using semiregular_box_t = meta::if_c<(bool)semiregular<T>, T, semiregular_box<T>>;
template<typename T, bool IsConst = false>
using semiregular_box_ref_or_val_t = meta::if_c<
(bool)semiregular<T>,
meta::if_c<IsConst || std::is_empty<T>::value, T, reference_wrapper<T>>,
reference_wrapper<
meta::if_c<IsConst, semiregular_box<T> const, semiregular_box<T>>>>;
/// @}
/// \cond
template<typename T>
using semiregular_t RANGES_DEPRECATED("Please use semiregular_box_t instead.") =
semiregular_box_t<T>;
template<typename T, bool IsConst = false>
using semiregular_ref_or_val_t RANGES_DEPRECATED(
"Please use semiregular_box_ref_or_val_t instead.") =
semiregular_box_ref_or_val_t<T, IsConst>;
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,32 @@
// 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_STATIC_CONST_HPP
#define RANGES_V3_UTILITY_STATIC_CONST_HPP
namespace ranges
{
/// \ingroup group-utility
template<typename T>
struct static_const
{
static constexpr T value{};
};
/// \ingroup group-utility
/// \sa `static_const`
template<typename T>
constexpr T static_const<T>::value;
} // namespace ranges
#endif

View File

@@ -0,0 +1,55 @@
/// \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
//
// The implementation of swap (see below) has been adapted from libc++
// (http://libcxx.llvm.org).
#ifndef RANGES_V3_UTILITY_SWAP_HPP
#define RANGES_V3_UTILITY_SWAP_HPP
#include <concepts/swap.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
template<typename T>
using is_swappable = concepts::is_swappable<T>;
template<typename T>
using is_nothrow_swappable = concepts::is_nothrow_swappable<T>;
template<typename T, typename U>
using is_swappable_with = concepts::is_swappable_with<T, U>;
template<typename T, typename U>
using is_nothrow_swappable_with = concepts::is_nothrow_swappable_with<T, U>;
using concepts::exchange;
/// \ingroup group-utility
/// \relates concepts::adl_swap_detail::swap_fn
RANGES_DEFINE_CPO(uncvref_t<decltype(concepts::swap)>, swap)
namespace cpp20
{
using ranges::swap;
}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,228 @@
/// \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_TAGGED_PAIR_HPP
#define RANGES_V3_UTILITY_TAGGED_PAIR_HPP
#include <utility>
#include <meta/meta.hpp>
#include <concepts/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/adl_get.hpp>
#include <range/v3/utility/swap.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
namespace ranges
{
/// \cond
namespace detail
{
template<typename T>
using tag_spec = meta::front<meta::as_list<T>>;
template<typename T>
using tag_elem = meta::back<meta::as_list<T>>;
template<typename Base, std::size_t, typename...>
struct tagged_chain
{
using type = _tuple_wrapper_::forward_tuple_interface<Base>;
};
template<typename Base, std::size_t I, typename First, typename... Rest>
struct tagged_chain<Base, I, First, Rest...>
{
using type = typename First::template getter<
Base, I, meta::_t<tagged_chain<Base, I + 1, Rest...>>>;
};
} // namespace detail
#if RANGES_BROKEN_CPO_LOOKUP
namespace _tagged_
{
struct adl_hook_
{};
} // namespace _tagged_
#endif
/// \endcond
template<typename Base, typename... Tags>
class RANGES_EMPTY_BASES RANGES_DEPRECATED(
"Class template tagged is deprecated.") tagged
: public meta::_t<detail::tagged_chain<Base, 0, Tags...>>
#if RANGES_BROKEN_CPO_LOOKUP
, private _tagged_::adl_hook_
#endif
{
CPP_assert(same_as<Base, uncvref_t<Base>>);
using base_t = meta::_t<detail::tagged_chain<Base, 0, Tags...>>;
template<typename Other>
struct can_convert
: meta::bool_<!RANGES_IS_SAME(Other, Base) &&
detail::is_convertible<Other, Base>::value>
{};
public:
tagged() = default;
using base_t::base_t;
template(typename Other)(
requires can_convert<Other>::value) //
constexpr tagged(tagged<Other, Tags...> && that) //
noexcept(std::is_nothrow_constructible<Base, Other>::value)
: base_t(static_cast<Other &&>(that))
{}
template(typename Other)(
requires can_convert<Other>::value) //
constexpr tagged(tagged<Other, Tags...> const & that) //
noexcept(std::is_nothrow_constructible<Base, Other const &>::value)
: base_t(static_cast<Other const &>(that))
{}
template(typename Other)(
requires can_convert<Other>::value) //
constexpr tagged & operator=(tagged<Other, Tags...> && that) //
noexcept(
noexcept(std::declval<Base &>() = static_cast<Other &&>(that)))
{
static_cast<Base &>(*this) = static_cast<Other &&>(that);
return *this;
}
template(typename Other)(
requires can_convert<Other>::value) //
constexpr tagged & operator=(tagged<Other, Tags...> const & that) //
noexcept(
noexcept(std::declval<Base &>() = static_cast<Other const &>(that)))
{
static_cast<Base &>(*this) = static_cast<Other const &>(that);
return *this;
}
template(typename U)(
requires (!same_as<tagged, detail::decay_t<U>>) AND
satisfies<Base &, std::is_assignable, U>)
constexpr tagged & operator=(U && u) //
noexcept(noexcept(std::declval<Base &>() = static_cast<U &&>(u)))
{
static_cast<Base &>(*this) = static_cast<U &&>(u);
return *this;
}
template(typename B = Base)(
requires is_swappable<B>::value) //
constexpr void swap(tagged & that) noexcept(is_nothrow_swappable<B>::value)
{
ranges::swap(static_cast<Base &>(*this), static_cast<Base &>(that));
}
#if !RANGES_BROKEN_CPO_LOOKUP
template<typename B = Base>
friend constexpr auto swap(tagged & x, tagged & y) //
noexcept(is_nothrow_swappable<B>::value)
-> CPP_broken_friend_ret(void)(
requires is_swappable<B>::value)
{
x.swap(y);
}
#endif
};
#if RANGES_BROKEN_CPO_LOOKUP
namespace _tagged_
{
template(typename Base, typename... Tags)(
requires is_swappable<Base>::value) //
constexpr void swap(tagged<Base, Tags...> & x, tagged<Base, Tags...> & y) //
noexcept(is_nothrow_swappable<Base>::value)
{
x.swap(y);
}
} // namespace _tagged_
#endif
template<typename F, typename S>
using tagged_pair RANGES_DEPRECATED("ranges::tagged_pair is deprecated.") =
tagged<std::pair<detail::tag_elem<F>, detail::tag_elem<S>>, detail::tag_spec<F>,
detail::tag_spec<S>>;
template<typename Tag1, typename Tag2, typename T1, typename T2,
typename R = tagged_pair<Tag1(bind_element_t<T1>), Tag2(bind_element_t<T2>)>>
RANGES_DEPRECATED("ranges::make_tagged_pair is deprecated.")
constexpr R make_tagged_pair(T1 && t1, T2 && t2) noexcept(
std::is_nothrow_constructible<R, T1, T2>::value)
{
return {static_cast<T1 &&>(t1), static_cast<T2 &&>(t2)};
}
} // namespace ranges
#define RANGES_DEFINE_TAG_SPECIFIER(NAME) \
namespace tag \
{ \
struct NAME \
{ \
template<typename Untagged, std::size_t I, typename Next> \
class getter : public Next \
{ \
protected: \
~getter() = default; \
\
public: \
getter() = default; \
getter(getter &&) = default; \
getter(getter const &) = default; \
using Next::Next; \
getter & operator=(getter &&) = default; \
getter & operator=(getter const &) = default; \
constexpr meta::_t<std::tuple_element<I, Untagged>> & NAME() & \
noexcept(noexcept(detail::adl_get<I>(std::declval<Untagged &>()))) \
{ \
return detail::adl_get<I>(static_cast<Untagged &>(*this)); \
} \
constexpr meta::_t<std::tuple_element<I, Untagged>> && NAME() && \
noexcept(noexcept(detail::adl_get<I>(std::declval<Untagged>()))) \
{ \
return detail::adl_get<I>(static_cast<Untagged &&>(*this)); \
} \
constexpr meta::_t<std::tuple_element<I, Untagged>> const & NAME() \
const & noexcept( \
noexcept(detail::adl_get<I>(std::declval<Untagged const &>()))) \
{ \
return detail::adl_get<I>(static_cast<Untagged const &>(*this)); \
} \
}; \
}; \
} \
/**/
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
template<typename Untagged, typename... Tags>
struct tuple_size<::ranges::tagged<Untagged, Tags...>> : tuple_size<Untagged>
{};
template<size_t N, typename Untagged, typename... Tags>
struct tuple_element<N, ::ranges::tagged<Untagged, Tags...>>
: tuple_element<N, Untagged>
{};
} // namespace std
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,45 @@
/// \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_TAGGED_TUPLE_HPP
#define RANGES_V3_UTILITY_TAGGED_TUPLE_HPP
#include <tuple>
#include <range/v3/range_fwd.hpp>
#include <range/v3/utility/tagged_pair.hpp>
#include <range/v3/detail/prologue.hpp>
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
namespace ranges
{
template<typename... Ts>
using tagged_tuple RANGES_DEPRECATED("ranges::tagged_tuple is deprecated.") =
tagged<std::tuple<detail::tag_elem<Ts>...>, detail::tag_spec<Ts>...>;
template<typename... Tags, typename... Ts>
RANGES_DEPRECATED("ranges::make_tagged_tuple is deprecated.")
constexpr tagged_tuple<Tags(bind_element_t<Ts>)...> make_tagged_tuple(Ts &&... ts)
{
return tagged_tuple<Tags(bind_element_t<Ts>)...>{static_cast<Ts &&>(ts)...};
}
} // namespace ranges
RANGES_DIAGNOSTIC_POP
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,196 @@
/// \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_TUPLE_ALGORITHM_HPP
#define RANGES_V3_UTILITY_TUPLE_ALGORITHM_HPP
#include <initializer_list>
#include <tuple>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/detail/adl_get.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \addtogroup group-utility
/// @{
template<typename Tup>
using tuple_indices_t = meta::make_index_sequence<
std::tuple_size<typename std::remove_reference<Tup>::type>::value>;
struct tuple_apply_fn
{
// clang-format off
private:
template<typename Fun, typename Tup, std::size_t... Is>
static constexpr auto //
CPP_auto_fun(impl)(Fun &&fun, Tup &&tup, meta::index_sequence<Is...>)
(
return invoke(static_cast<Fun &&>(fun),
detail::adl_get<Is>(static_cast<Tup &&>(tup))...)
)
public:
template<typename Fun, typename Tup>
constexpr auto CPP_auto_fun(operator())(Fun &&fun, Tup &&tup)(const)
(
return tuple_apply_fn::impl(static_cast<Fun &&>(fun),
static_cast<Tup &&>(tup),
tuple_indices_t<Tup>{})
)
// clang-format on
};
/// \ingroup group-utility
/// \sa `tuple_apply_fn`
RANGES_INLINE_VARIABLE(tuple_apply_fn, tuple_apply)
struct tuple_transform_fn
{
// clang-format off
private:
template<typename Tup, typename Fun, std::size_t... Is>
static constexpr auto //
CPP_auto_fun(impl1)(Tup &&tup, Fun &fun, meta::index_sequence<Is...>)
(
return std::tuple<
decltype(fun(detail::adl_get<Is>(static_cast<Tup &&>(tup))))...>{
fun(detail::adl_get<Is>(static_cast<Tup &&>(
tup)))...}
)
template<typename Tup0, typename Tup1, typename Fun, std::size_t... Is>
static constexpr auto CPP_auto_fun(impl2)(Tup0 &&tup0, Tup1 &&tup1, Fun &fun,
meta::index_sequence<Is...>)
(
return std::tuple<
decltype(fun(detail::adl_get<Is>(static_cast<Tup0 &&>(tup0)),
detail::adl_get<Is>(static_cast<Tup1 &&>(tup1))))...>{
fun(detail::adl_get<Is>(static_cast<Tup0 &&>(tup0)),
detail::adl_get<Is>(static_cast<Tup1 &&>(tup1)))...}
)
public:
template<typename Tup, typename Fun>
constexpr auto CPP_auto_fun(operator())(Tup &&tup, Fun fun)(const)
(
return tuple_transform_fn::impl1(
static_cast<Tup &&>(tup), fun,
tuple_indices_t<Tup>{})
)
template<typename Tup0, typename Tup1, typename Fun>
constexpr auto CPP_auto_fun(operator())(Tup0 &&tup0, Tup1 &&tup1, Fun fun)(const)
(
return tuple_transform_fn::impl2(static_cast<Tup0 &&>(tup0),
static_cast<Tup1 &&>(tup1), fun,
tuple_indices_t<Tup0>{})
)
// clang-format on
};
/// \ingroup group-utility
/// \sa `tuple_transform_fn`
RANGES_INLINE_VARIABLE(tuple_transform_fn, tuple_transform)
struct tuple_foldl_fn
{
private:
template<typename Tup, typename Val, typename Fun>
static constexpr Val impl(Tup &&, Val val, Fun &)
{
return val;
}
// clang-format off
template<std::size_t I0, std::size_t... Is, typename Tup, typename Val,
typename Fun, typename Impl = tuple_foldl_fn>
static constexpr auto CPP_auto_fun(impl)(Tup &&tup, Val val, Fun &fun)
(
return Impl::template impl<Is...>(
static_cast<Tup &&>(tup),
fun(std::move(val), detail::adl_get<I0>(static_cast<Tup &&>(tup))),
fun)
)
template<typename Tup, typename Val, typename Fun, std::size_t... Is>
static constexpr auto CPP_auto_fun(impl2)(Tup &&tup, Val val, Fun &fun,
meta::index_sequence<Is...>)
(
return tuple_foldl_fn::impl<Is...>(static_cast<Tup &&>(tup),
std::move(val),
fun)
)
public:
template<typename Tup, typename Val, typename Fun>
constexpr auto CPP_auto_fun(operator())(Tup &&tup, Val val, Fun fun)(const)
(
return tuple_foldl_fn::impl2(static_cast<Tup &&>(tup),
std::move(val),
fun,
tuple_indices_t<Tup>{})
)
// clang-format on
};
/// \ingroup group-utility
/// \sa `tuple_foldl_fn`
RANGES_INLINE_VARIABLE(tuple_foldl_fn, tuple_foldl)
struct tuple_for_each_fn
{
private:
template<typename Tup, typename Fun, std::size_t... Is>
static constexpr void impl(Tup && tup, Fun & fun, meta::index_sequence<Is...>)
{
(void)std::initializer_list<int>{
((void)fun(detail::adl_get<Is>(static_cast<Tup &&>(tup))), 42)...};
}
public:
template<typename Tup, typename Fun>
constexpr Fun operator()(Tup && tup, Fun fun) const
{
return tuple_for_each_fn::impl(
static_cast<Tup &&>(tup), fun, tuple_indices_t<Tup>{}),
fun;
}
};
/// \ingroup group-utility
/// \sa `tuple_for_each_fn`
RANGES_INLINE_VARIABLE(tuple_for_each_fn, tuple_for_each)
struct make_tuple_fn
{
// clang-format off
template<typename... Ts>
constexpr auto CPP_auto_fun(operator())(Ts &&... ts)(const)
(
return std::make_tuple(static_cast<Ts &&>(ts)...)
)
// clang-format on
};
/// \ingroup group-utility
/// \sa `make_tuple_fn`
RANGES_INLINE_VARIABLE(make_tuple_fn, make_tuple)
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif

View File

@@ -0,0 +1,22 @@
// Range v3 library
//
// Copyright Eric Niebler 2014-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_UNREACHABLE_HPP
#define RANGES_V3_UTILITY_UNREACHABLE_HPP
#include <range/v3/detail/config.hpp>
RANGES_DEPRECATED_HEADER(
"This header is deprecated. Please #include "
"<range/v3/iterator/unreachable_sentinel.hpp> instead.")
#include <range/v3/iterator/unreachable_sentinel.hpp>
#endif

View File

@@ -0,0 +1,134 @@
/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014-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_VARIANT_HPP
#define RANGES_V3_UTILITY_VARIANT_HPP
#include <range/v3/algorithm/copy.hpp>
#include <range/v3/algorithm/move.hpp>
#include <range/v3/detail/variant.hpp>
#include <range/v3/iterator/move_iterators.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
template<typename T, std::size_t N, typename Index>
struct indexed_datum<T[N], Index>
{
private:
union
{
char c;
T data_[N];
};
void fill_default_(T * p, std::true_type)
{
for(; p != ranges::end(data_); ++p)
::new((void *)p) T{};
}
void fill_default_(T * p, std::false_type)
{
RANGES_EXPECT(p == ranges::end(data_));
}
public:
CPP_member
constexpr CPP_ctor(indexed_datum)(meta::nil_ = {})(
requires default_constructible<T>)
: data_{}
{}
CPP_member
CPP_ctor(indexed_datum)(indexed_datum && that)(
requires move_constructible<T>)
{
std::uninitialized_copy_n(make_move_iterator(that.data_), N, data_);
}
CPP_member
CPP_ctor(indexed_datum)(indexed_datum const & that)(
requires copy_constructible<T>)
{
std::uninitialized_copy_n(that.data_, N, data_);
}
// \pre Requires distance(first, last) <= N
// \pre Requires default_constructible<T> || distance(first, last) == N
template(typename I, typename S)(
requires sentinel_for<S, I> AND input_iterator<I> AND
constructible_from<T, iter_reference_t<I>>)
indexed_datum(I first, S last)
{
T * p = detail::uninitialized_copy(first, last, data_);
this->fill_default_(p, meta::bool_<default_constructible<T>>{});
}
// \pre Requires distance(r) <= N
// \pre Requires default_constructible<T> || distance(r) == N
template(typename R)(
requires input_range<R> AND constructible_from<T, range_reference_t<R>>)
explicit indexed_datum(R && r)
: indexed_datum{ranges::begin(r), ranges::end(r)}
{}
CPP_member
auto operator=(indexed_datum && that) //
-> CPP_ret(indexed_datum &)(
requires assignable_from<T &, T>)
{
ranges::move(that.data_, data_);
return *this;
}
CPP_member
auto operator=(indexed_datum const & that) //
-> CPP_ret(indexed_datum &)(
requires assignable_from<T &, T const &>)
{
ranges::copy(that.data_, data_);
return *this;
}
// \pre Requires ranges::distance(r) <= N
template(typename R)(
requires input_range<R> AND assignable_from<T &, range_reference_t<R>>)
indexed_datum & operator=(R && r)
{
ranges::copy(r, data_);
return *this;
}
constexpr auto ref()
{
return indexed_element<T(&)[N], Index::value>{data_};
}
constexpr auto ref() const
{
return indexed_element<T const(&)[N], Index::value>{data_};
}
constexpr T (&get() noexcept)[N]
{
return data_;
}
constexpr T const (&get() const noexcept)[N]
{
return data_;
}
};
} // namespace detail
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif