Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add maybe concept and maybe_view #1659

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions include/range/v3/range/maybe.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/// \file
// Range v3 library
//
// Copyright Hui Xie 2021
//
// 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_RANGE_MAYBE_HPP
#define RANGES_V3_RANGE_MAYBE_HPP

#include <concepts/concepts.hpp>

#include <range/v3/detail/config.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/utility/static_const.hpp>

#include <range/v3/detail/prologue.hpp>

namespace ranges
{
namespace _is_just_
{
// clang-format off
template<typename T>
CPP_requires(has_non_member_is_just_,
requires(T const& t) //
(
static_cast<bool>(is_just(t))
));
template<typename T>
CPP_concept has_non_member_is_just =
CPP_requires_ref(_is_just_::has_non_member_is_just_, T);
// clang-format on

struct fn
{
template(typename M)(
/// \pre
requires has_non_member_is_just<M>) //
constexpr bool
operator()(M && m) const //
noexcept(noexcept(is_just(m)))
{
return is_just(m);
}

template(typename M)(
/// \pre
requires(!has_non_member_is_just<M>)
AND concepts::explicitly_convertible_to<M, bool>) //
constexpr bool
operator()(M && m) const //
noexcept(noexcept(static_cast<bool>(m)))
{
return static_cast<bool>(m);
}
};
} // namespace _is_just_

RANGES_DEFINE_CPO(_is_just_::fn, is_just)

namespace _get_just_
{

// clang-format off
template<typename T>
CPP_requires(has_non_member_get_just_,
requires(T&& t) //
(
get_just(static_cast<T&&>(t))
));
template<typename T>
CPP_concept has_non_member_get_just =
CPP_requires_ref(_get_just_::has_non_member_get_just_, T);
// clang-format on

struct fn
{
private:
struct _non_member_result_
{
template<typename M>
using invoke = decltype(get_just(declval(M &)));
};

struct _operator_result_
{
template<typename M>
using invoke = decltype(*(declval(M &)));
};

template<typename M>
using _result_t =
meta::invoke<meta::conditional_t<has_non_member_get_just<M>,
_non_member_result_, _operator_result_>,
M>;

public:
template(typename M)(
/// \pre
requires has_non_member_get_just<M>) //
constexpr _result_t<M>
operator()(M && m) const //
noexcept(noexcept(get_just(static_cast<M &&>(m))))
{
return get_just(static_cast<M &&>(m));
}

template(typename M)(
/// \pre
requires(!has_non_member_get_just<M>) AND detail::dereferenceable_<M>) //
constexpr _result_t<M>
operator()(M && m) const //
noexcept(noexcept(*(static_cast<M &&>(m))))
{
return *(static_cast<M &&>(m));
}
};
} // namespace _get_just_

RANGES_DEFINE_CPO(_get_just_::fn, get_just)

// clang-format off
template<typename T>
CPP_requires(_maybe_,
requires(T & t) //
(
ranges::is_just(static_cast<const T&>(t)),
ranges::get_just(t)
));
template<typename T>
CPP_concept maybe =
CPP_requires_ref(ranges::_maybe_, T);
// clang-format on

} // namespace ranges

#include <range/v3/detail/epilogue.hpp>

#endif
8 changes: 8 additions & 0 deletions include/range/v3/range_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,14 @@ namespace ranges
struct partial_sum_fn;
}

template<typename T>
struct maybe_view;

namespace views
{
struct maybe_fn;
}

template<typename Rng>
struct move_view;

Expand Down
1 change: 1 addition & 0 deletions include/range/v3/view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <range/v3/view/join.hpp>
#include <range/v3/view/linear_distribute.hpp>
#include <range/v3/view/map.hpp>
#include <range/v3/view/maybe.hpp>
#include <range/v3/view/move.hpp>
#include <range/v3/view/partial_sum.hpp>
#include <range/v3/view/ref.hpp>
Expand Down
134 changes: 134 additions & 0 deletions include/range/v3/view/maybe.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/// \file
// Range v3 library
//
// Copyright Hui Xie 2021
//
// 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_RANGE_VIEW_MAYBE_HPP
#define RANGES_V3_RANGE_VIEW_MAYBE_HPP

#include <type_traits>

#include <range/v3/range_fwd.hpp>

#include <range/v3/range/maybe.hpp>
#include <range/v3/utility/addressof.hpp>
#include <range/v3/utility/in_place.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/view/interface.hpp>

#include <range/v3/detail/prologue.hpp>

namespace ranges
{

/// \addtogroup group-views
/// @{
template<typename Maybe>
struct maybe_view : view_interface<maybe_view<Maybe>, (cardinality)1>
{
private:
CPP_assert(copy_constructible<Maybe>);
static_assert(ranges::maybe<Maybe>,
"The template parameter of maybe_view must satisfy `maybe`");
using T = std::decay_t<decltype(ranges::get_just(declval(Maybe &)))>;

semiregular_box_t<Maybe> value_;
template<typename... Args>
constexpr maybe_view(in_place_t, std::true_type, Args &&... args)
: value_{static_cast<Args &&>(args)...}
{}
template<typename... Args>
constexpr maybe_view(in_place_t, std::false_type, Args &&... args)
: value_{in_place, static_cast<Args &&>(args)...}
{}

public:
maybe_view() = default;
constexpr explicit maybe_view(Maybe const & t)
: value_(t)
{}
constexpr explicit maybe_view(Maybe && t)
: value_(std::move(t))
{}
template(class... Args)(
/// \pre
requires constructible_from<Maybe,
Args...>) constexpr maybe_view(in_place_t,
Args &&... args)
: maybe_view{in_place,
meta::bool_<(bool)semiregular<Maybe>>{},
static_cast<Args &&>(args)...}
{}
constexpr T * begin() noexcept
{
return data();
}
constexpr T const * begin() const noexcept
{
return data();
}
constexpr T * end() noexcept
{
return data() + size();
}
constexpr T const * end() const noexcept
{
return data() + size();
}
constexpr std::size_t size() const noexcept
{
return ranges::is_just(static_cast<Maybe const &>(value_)) ? 1u : 0u;
}
constexpr T * data() noexcept
{
auto & m = static_cast<Maybe &>(value_);
return ranges::is_just(m) ? detail::addressof(ranges::get_just(m)) : nullptr;
}
constexpr T const * data() const noexcept
{
const auto & m = static_cast<Maybe const &>(value_);
return ranges::is_just(m) ? detail::addressof(ranges::get_just(m)) : nullptr;
}
};

#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template<class T>
explicit maybe_view(T &&) //
->maybe_view<detail::decay_t<T>>;
#endif

namespace views
{
struct maybe_fn
{
template(typename Val)(
/// \pre
requires copy_constructible<Val> AND ranges::maybe<Val>) //
maybe_view<Val>
operator()(Val value) const
{
return maybe_view<Val>{std::move(value)};
}
};

/// \relates maybe_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(maybe_fn, maybe)
} // namespace views

/// @}
} // namespace ranges

#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::maybe_view)

#endif
1 change: 1 addition & 0 deletions test/range/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ rv3_add_test(test.range.access range.access access.cpp)
rv3_add_test(test.range.conversion range.conversion conversion.cpp)
rv3_add_test(test.range.index range.index index.cpp)
rv3_add_test(test.range.operations range.operations operations.cpp)
rv3_add_test(test.range.maybe range.maybe maybe.cpp)
Loading