Skip to content
Merged
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
26 changes: 15 additions & 11 deletions include/fn/choice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ struct choice<Ts...> : sum<Ts...> {
*/
template <typename T>
constexpr choice(T &&v) // NOSONAR cpp:S1709,S6458 implicit arm of the explicit pair; has_type excludes self
noexcept(detail::_nothrow_initializable<::std::remove_cvref_t<T>, decltype(v)>)
requires has_type<::std::remove_cvref_t<T>> && (::std::is_constructible_v<::std::remove_cvref_t<T>, decltype(v)>)
noexcept(::std::is_nothrow_constructible_v<_impl, ::std::in_place_type_t<::std::remove_cvref_t<T>>, decltype(v)>)
requires has_type<::std::remove_cvref_t<T>>
&& (::std::is_constructible_v<_impl, ::std::in_place_type_t<::std::remove_cvref_t<T>>, decltype(v)>)
&& (::std::is_convertible_v<decltype(v), ::std::remove_cvref_t<T>>)
: _impl(::std::in_place_type<::std::remove_cvref_t<T>>, FWD(v))
{
Expand All @@ -101,8 +102,9 @@ struct choice<Ts...> : sum<Ts...> {
*/
template <typename T>
constexpr explicit choice(T &&v) // NOSONAR cpp:S6458 has_type excludes self
noexcept(detail::_nothrow_initializable<::std::remove_cvref_t<T>, decltype(v)>)
requires has_type<::std::remove_cvref_t<T>> && (::std::is_constructible_v<::std::remove_cvref_t<T>, decltype(v)>)
noexcept(::std::is_nothrow_constructible_v<_impl, ::std::in_place_type_t<::std::remove_cvref_t<T>>, decltype(v)>)
requires has_type<::std::remove_cvref_t<T>>
&& (::std::is_constructible_v<_impl, ::std::in_place_type_t<::std::remove_cvref_t<T>>, decltype(v)>)
&& (not ::std::is_convertible_v<decltype(v), ::std::remove_cvref_t<T>>)
: _impl(::std::in_place_type<::std::remove_cvref_t<T>>, FWD(v))
{
Expand All @@ -117,8 +119,8 @@ struct choice<Ts...> : sum<Ts...> {
*/
template <typename T>
constexpr explicit choice(::std::in_place_type_t<T> d, auto &&...args) //
noexcept(detail::_nothrow_initializable<T, decltype(args)...>)
requires has_type<T> && detail::_initializable<T, decltype(args)...>
noexcept(::std::is_nothrow_constructible_v<_impl, ::std::in_place_type_t<T>, decltype(args)...>)
requires has_type<T> && ::std::is_constructible_v<_impl, ::std::in_place_type_t<T>, decltype(args)...>
: _impl(d, FWD(args)...)
{
}
Expand All @@ -131,8 +133,9 @@ struct choice<Ts...> : sum<Ts...> {
*/
template <typename... Tx>
constexpr choice(sum<Tx...> const &v) // NOSONAR cpp:S1709 implicit widening by design
noexcept((... && ::std::is_nothrow_copy_constructible_v<Tx>))
requires detail::is_superset_of<choice, choice<Tx...>> && (... && ::std::is_copy_constructible_v<Tx>)
noexcept(::std::is_nothrow_constructible_v<_impl, ::std::in_place_type_t<sum<Tx...>>, sum<Tx...> const &>)
requires detail::is_superset_of<choice, choice<Tx...>>
&& (::std::is_constructible_v<_impl, ::std::in_place_type_t<sum<Tx...>>, sum<Tx...> const &>)
: _impl(::std::in_place_type<sum<Tx...>>, FWD(v))
{
}
Expand All @@ -145,8 +148,9 @@ struct choice<Ts...> : sum<Ts...> {
*/
template <typename... Tx>
constexpr choice(sum<Tx...> &&v) // NOSONAR cpp:S1709 implicit widening by design
noexcept((... && ::std::is_nothrow_move_constructible_v<Tx>))
requires detail::is_superset_of<choice, choice<Tx...>> && (... && ::std::is_move_constructible_v<Tx>)
noexcept(::std::is_nothrow_constructible_v<_impl, ::std::in_place_type_t<sum<Tx...>>, sum<Tx...>>)
requires detail::is_superset_of<choice, choice<Tx...>>
&& (::std::is_constructible_v<_impl, ::std::in_place_type_t<sum<Tx...>>, sum<Tx...>>)
: _impl(::std::in_place_type<sum<Tx...>>, FWD(v))
{
}
Expand All @@ -159,7 +163,7 @@ struct choice<Ts...> : sum<Ts...> {
*/
template <typename... Tx>
constexpr choice(::std::in_place_type_t<sum<Tx...>>, some_sum auto &&v) //
noexcept((... && ::std::is_nothrow_constructible_v<Tx, apply_const_lvalue_t<decltype(v), Tx &&>>))
noexcept(::std::is_nothrow_constructible_v<_impl, ::std::in_place_type_t<sum<Tx...>>, decltype(v)>)
requires ::std::is_same_v<::std::remove_cvref_t<decltype(v)>, sum<Tx...>>
&& detail::is_superset_of<choice, choice<Tx...>>
: _impl(::std::in_place_type<sum<Tx...>>, FWD(v))
Expand Down
45 changes: 41 additions & 4 deletions include/fn/detail/pack_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,35 @@
// type is reference-related to it, i.e. binds), but gcc reads the braced form as materializing a
// temporary and rejects the bind - while accepting the equivalent declaration. The cast keeps both
// compilers on the binding path.
template <typename T> [[nodiscard]] constexpr auto _make_element(auto &&...args) -> T
template <typename T>
[[nodiscard]] constexpr auto _make_element(auto &&...args) noexcept(_nothrow_initializable<T, decltype(args)...>) -> T
requires _initializable<T, decltype(args)...>
{
if constexpr (::std::is_reference_v<T>)
return T(FWD(args)...); // a single argument, so this is a cast expression: it binds
else
return T{FWD(args)...};
}

// The two questions anyone above may ask about constructing an element, asked OF the function that
// constructs it rather than restated in terms of a trait - the same discipline as `_makeable` beside
// `make_variadic_union`, and for the same reason: a restatement can drift from the deed.
template <typename T, typename... Args>
concept _makeable_element = requires { _make_element<T>(::std::declval<Args>()...); };

Check warning on line 44 in include/fn/detail/pack_impl.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an argument to the requires clause to provide a named value instead.

See more on https://sonarcloud.io/project/issues?id=libfn_functional&issues=AZ9dEDaFb-EF_A0kVCFi&open=AZ9dEDaFb-EF_A0kVCFi&pullRequest=305

template <typename T, typename... Args>
concept _nothrow_makeable_element = requires { requires noexcept(_make_element<T>(::std::declval<Args>()...)); };

Check warning on line 47 in include/fn/detail/pack_impl.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an argument to the requires clause to provide a named value instead.

See more on https://sonarcloud.io/project/issues?id=libfn_functional&issues=AZ9dEDaFb-EF_A0kVCFj&open=AZ9dEDaFb-EF_A0kVCFj&pullRequest=305

// One element's relocation into a new pack: the copy-initialization its holder performs
// ([dcl.init.aggr]/4.3, reached through brace elision), asked of the holder one element at a time -
// `_element<I, T>{src}` elides into the same member copy-initialization. This excludes explicit
// constructors, where `is_[nothrow_]constructible_v` would admit them.
template <typename E, typename Src>
concept _relocatable_element = requires { E{::std::declval<Src>()}; };

Check warning on line 54 in include/fn/detail/pack_impl.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an argument to the requires clause to provide a named value instead.

See more on https://sonarcloud.io/project/issues?id=libfn_functional&issues=AZ9dEDaFb-EF_A0kVCFk&open=AZ9dEDaFb-EF_A0kVCFk&pullRequest=305

template <typename E, typename Src>
concept _nothrow_relocatable_element = requires { requires noexcept(E{::std::declval<Src>()}); };

Check warning on line 57 in include/fn/detail/pack_impl.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an argument to the requires clause to provide a named value instead.

See more on https://sonarcloud.io/project/issues?id=libfn_functional&issues=AZ9dEDaFb-EF_A0kVCFl&open=AZ9dEDaFb-EF_A0kVCFl&pullRequest=305

template <typename, typename... Ts> struct pack_impl;

template <typename... Ts> struct _pack_append;
Expand Down Expand Up @@ -89,6 +110,16 @@
FWD(fn), static_cast<apply_const_lvalue_t<Self, Ts &&>>(FWD(self)._element<Is, Ts>::v)..., FWD(args)...);
}

template <typename Ret, typename Self, typename Fn, typename... Args>
requires(not(... || (_some_pack<Args> || _some_sum<Args>)))
static constexpr auto _invoke_r(Self &&self, Fn &&fn, Args &&...args) //
noexcept(_is_nothrow_invocable_r<Ret, Fn &&, apply_const_lvalue_t<Self, Ts &&>..., Args &&...>::value) -> Ret
requires(_is_invocable_r<Ret, Fn &&, apply_const_lvalue_t<Self, Ts &&>..., Args && ...>::value)
{
return ::fn::detail::_invoke_r<Ret>(
FWD(fn), static_cast<apply_const_lvalue_t<Self, Ts &&>>(FWD(self)._element<Is, Ts>::v)..., FWD(args)...);
}

template <::std::size_t I, typename Self>
static constexpr decltype(auto) _get(Self &&self) noexcept
requires(I < size)
Expand All @@ -101,15 +132,19 @@

// Every existing element is relocated into the new pack, so appending weighs that as well as the
// construction of the element being appended.
template <typename Self>
static constexpr bool _relocatable
= (... && _relocatable_element<_element<Is, Ts>, apply_const_lvalue_t<Self, Ts &&>>);

template <typename Self>
static constexpr bool _nothrow_relocatable
= (... && ::std::is_nothrow_constructible_v<Ts, apply_const_lvalue_t<Self, Ts &&>>);
= (... && _nothrow_relocatable_element<_element<Is, Ts>, apply_const_lvalue_t<Self, Ts &&>>);

template <typename T, typename Self>
static constexpr auto _append(Self &&self, auto &&...args) //
noexcept(_nothrow_relocatable<Self> && _nothrow_initializable<T, decltype(args)...>)
noexcept(_nothrow_relocatable<Self> && _nothrow_makeable_element<T, decltype(args)...>)
-> pack_impl<::std::index_sequence<Is..., size>, Ts..., T>
requires(not _some_sum<T>) && (not _some_pack<T>) && _initializable<T, decltype(args)...>
requires(not _some_sum<T>) && (not _some_pack<T>) && _relocatable<Self> && _makeable_element<T, decltype(args)...>
{
return {static_cast<apply_const_lvalue_t<Self, Ts &&>>(FWD(self)._element<Is, Ts>::v)...,
_make_element<T>(FWD(args)...)};
Expand All @@ -121,6 +156,8 @@
&& ::std::remove_cvref_t<T>::_impl::template _nothrow_relocatable<decltype(other)>) -> //
typename _pack_append<::std::remove_cvref_t<T>, Ts...>::impl
requires _some_pack<T> && (::std::is_same_v<::std::remove_cvref_t<decltype(other)>, ::std::remove_cvref_t<T>>)
&& _relocatable<Self> && ::std::remove_cvref_t<T>::_impl::template
_relocatable<decltype(other)>
{
using type = _pack_append<::std::remove_cvref_t<T>, Ts...>::impl;
return FWD(other)._invoke(FWD(other), [&self](auto &&...args) {
Expand Down
31 changes: 21 additions & 10 deletions include/fn/detail/variadic_union.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,40 +306,51 @@
}

template <typename T, typename U>
[[nodiscard]] constexpr auto make_variadic_union(auto &&...args)
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t0>
[[nodiscard]] constexpr U make_variadic_union(auto &&...args) noexcept(noexcept(T{FWD(args)...}))
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t0> && requires { T{FWD(args)...}; }
{
return U{.v0 = T{FWD(args)...}};
}

template <typename T, typename U>
[[nodiscard]] constexpr auto make_variadic_union(auto &&...args)
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t1>
[[nodiscard]] constexpr U make_variadic_union(auto &&...args) noexcept(noexcept(T{FWD(args)...}))
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t1> && requires { T{FWD(args)...}; }
{
return U{.v1 = T{FWD(args)...}};
}

template <typename T, typename U>
[[nodiscard]] constexpr auto make_variadic_union(auto &&...args)
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t2>
[[nodiscard]] constexpr U make_variadic_union(auto &&...args) noexcept(noexcept(T{FWD(args)...}))
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t2> && requires { T{FWD(args)...}; }
{
return U{.v2 = T{FWD(args)...}};
}

template <typename T, typename U>
[[nodiscard]] constexpr auto make_variadic_union(auto &&...args)
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t3>
[[nodiscard]] constexpr U make_variadic_union(auto &&...args) noexcept(noexcept(T{FWD(args)...}))
requires(U::template has_type<T>) && ::std::is_same_v<T, typename U::t3> && requires { T{FWD(args)...}; }
{
return U{.v3 = T{FWD(args)...}};
}

template <typename T, typename U>
[[nodiscard]] constexpr U make_variadic_union(auto &&...args)
requires(U::template has_type<T>) && (U::more_t::template has_type<T>)
[[nodiscard]] constexpr U make_variadic_union(auto &&...args) noexcept(noexcept(T{FWD(args)...}))
requires(U::template has_type<T>) && (U::more_t::template has_type<T>) && requires { T{FWD(args)...}; }
{
return U{.more = make_variadic_union<T, typename U::more_t>(FWD(args)...)};
}

// The two questions anyone above may ask about storing an alternative, asked OF the function that
// stores it rather than restated in terms of a trait. Restating is how the answer drifts from the
// deed: `make_variadic_union` brace-initializes, and `std::is_[nothrow_]constructible` is a question
// about parentheses - the two can disagree, and where they do the trait is wrong. Nothing here needs
// to know that, and nothing above needs to remember it.
template <typename U, typename T, typename... Args>
concept _makeable = requires { make_variadic_union<T, U>(::std::declval<Args>()...); };

Check warning on line 349 in include/fn/detail/variadic_union.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an argument to the requires clause to provide a named value instead.

See more on https://sonarcloud.io/project/issues?id=libfn_functional&issues=AZ9dEDYkb-EF_A0kVCFg&open=AZ9dEDYkb-EF_A0kVCFg&pullRequest=305

template <typename U, typename T, typename... Args>
concept _nothrow_makeable = requires { requires noexcept(make_variadic_union<T, U>(::std::declval<Args>()...)); };

Check warning on line 352 in include/fn/detail/variadic_union.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an argument to the requires clause to provide a named value instead.

See more on https://sonarcloud.io/project/issues?id=libfn_functional&issues=AZ9dEDYkb-EF_A0kVCFh&open=AZ9dEDYkb-EF_A0kVCFh&pullRequest=305

template <typename R, typename U, typename Fn, typename... Args>
[[nodiscard]] constexpr auto invoke_variadic_union(some_variadic_union auto &&v, ::std::size_t index, Fn &&fn,
Args &&...args)
Expand Down
Loading