diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index 517bc61..d02a4ea 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -143,16 +143,17 @@ template using bool_constant = constant; template using size_constant = constant; template -auto constant_of(std::integral_constant /*value*/ = {}) { +constexpr auto constant_of(std::integral_constant /*value*/ = {}) { return constant{}; } template -auto size_constant_of( - std::integral_constant /*value*/ = {}) { +constexpr auto +size_constant_of(std::integral_constant /*value*/ = {}) { return size_constant{}; } template -auto bool_constant_of(std::integral_constant /*value*/ = {}) { +constexpr auto +bool_constant_of(std::integral_constant /*value*/ = {}) { return bool_constant{}; } @@ -177,24 +178,26 @@ template struct is_identity : std::false_type {}; template struct is_identity> : std::true_type {}; -template identity> identity_of(T const& /*type*/) { +template +identity> constexpr identity_of(T const& /*type*/) noexcept { return {}; } template -identity identity_of(identity /*type*/) { +constexpr identity identity_of(identity /*type*/) noexcept { return {}; } -template auto identity_of() { +template constexpr auto identity_of() noexcept { return std::conditional_t>::value, T, identity>>{}; } -template auto get(identity) { +template +constexpr auto get(identity) noexcept { return identity_of>(); } /// Helper to trick compilers about that a parameter pack is used -template void unused(T&&... args) { +template constexpr void unused(T&&... args) { auto use = [](auto&& type) mutable { (void)type; return 0; @@ -225,63 +228,69 @@ struct is_valid_impl {}; template -void static_if_impl(std::true_type, Type&& type, TrueCallback&& trueCallback) { +constexpr void static_if_impl(std::true_type, Type&& type, + TrueCallback&& trueCallback) { std::forward(trueCallback)(std::forward(type)); } template -void static_if_impl(std::false_type, Type&& /*type*/, - TrueCallback&& /*trueCallback*/) {} +constexpr void static_if_impl(std::false_type, Type&& /*type*/, + TrueCallback&& /*trueCallback*/) {} template -auto static_if_impl(std::true_type, Type&& type, TrueCallback&& trueCallback, - FalseCallback&& /*falseCallback*/) { +constexpr auto static_if_impl(std::true_type, Type&& type, + TrueCallback&& trueCallback, + FalseCallback&& /*falseCallback*/) { return std::forward(trueCallback)(std::forward(type)); } template -auto static_if_impl(std::false_type, Type&& type, - TrueCallback&& /*trueCallback*/, - FalseCallback&& falseCallback) { +constexpr auto static_if_impl(std::false_type, Type&& type, + TrueCallback&& /*trueCallback*/, + FalseCallback&& falseCallback) { return std::forward(falseCallback)(std::forward(type)); } } // end namespace detail /// Returns the pack size of the given type -template auto pack_size_of(identity>) { +template +constexpr auto pack_size_of(identity>) noexcept { return size_of_t{}; } /// Returns the pack size of the given type template -auto pack_size_of(identity>) { +constexpr auto pack_size_of(identity>) noexcept { return size_of_t{}; } /// Returns the pack size of the given type -template auto pack_size_of(identity) { +template +constexpr auto pack_size_of(identity) noexcept { return size_of_t{}; } /// Returns an index sequence of the given type -template auto sequenceOf(T&& sequenceable) { - auto size = pack_size_of(std::forward(sequenceable)); - (void)size; - return std::make_index_sequence(); +template constexpr auto sequenceOf(T&& /*sequenceable*/) noexcept { + return std::make_index_sequence()))::value>(); } /// Returns a check which returns a true type if the current value /// is below the -template auto isLessThen(size_constant end) { +template +constexpr auto isLessThen(size_constant end) noexcept { return [=](auto current) { return end > current; }; } /// Compile-time check for validating a certain expression template -auto is_valid(T&& /*type*/, Check&& /*check*/) { +constexpr auto is_valid(T&& /*type*/, Check&& /*check*/) noexcept { return typename detail::is_valid_impl::type{}; } /// Creates a static functional validator object. -template auto validatorOf(Check&& check) { +template +constexpr auto validatorOf(Check&& check) noexcept( + std::is_nothrow_move_constructible>::value) { return [check = std::forward(check)](auto&& matchable) { return is_valid(std::forward(matchable), check); }; @@ -289,7 +298,8 @@ template auto validatorOf(Check&& check) { /// Invokes the callback only if the given type matches the check template -void static_if(Type&& type, Check&& check, TrueCallback&& trueCallback) { +constexpr void static_if(Type&& type, Check&& check, + TrueCallback&& trueCallback) { detail::static_if_impl(std::forward(check)(type), std::forward(type), std::forward(trueCallback)); @@ -298,8 +308,9 @@ void static_if(Type&& type, Check&& check, TrueCallback&& trueCallback) { /// Invokes the callback only if the given type matches the check template -auto static_if(Type&& type, Check&& check, TrueCallback&& trueCallback, - FalseCallback&& falseCallback) { +constexpr auto static_if(Type&& type, Check&& check, + TrueCallback&& trueCallback, + FalseCallback&& falseCallback) { return detail::static_if_impl(std::forward(check)(type), std::forward(type), std::forward(trueCallback), @@ -309,7 +320,8 @@ auto static_if(Type&& type, Check&& check, TrueCallback&& trueCallback, /// A compile-time while loop, which loops as long the value matches /// the predicate. The handler shall return the next value. template -auto static_while(Value&& value, Predicate&& predicate, Handler&& handler) { +constexpr auto static_while(Value&& value, Predicate&& predicate, + Handler&& handler) { return static_if(std::forward(value), predicate, [&](auto&& result) mutable { return static_while( @@ -323,7 +335,7 @@ auto static_while(Value&& value, Predicate&& predicate, Handler&& handler) { } /// Returns a validator which checks whether the given sequenceable is empty -inline auto is_empty() { +inline auto is_empty() noexcept { return [](auto const& checkable) { return pack_size_of(checkable) == size_constant_of<0>(); }; @@ -331,14 +343,14 @@ inline auto is_empty() { /// Calls the given unpacker with the content of the given sequence template -auto unpack(std::integer_sequence, U&& unpacker) { +constexpr auto unpack(std::integer_sequence, U&& unpacker) { return std::forward(unpacker)(size_constant_of()...); } /// Calls the given unpacker with the content of the given sequenceable template -auto unpack(F&& firstSequenceable, U&& unpacker, - std::integer_sequence) { +constexpr auto unpack(F&& firstSequenceable, U&& unpacker, + std::integer_sequence) { using std::get; (void)firstSequenceable; return std::forward(unpacker)( @@ -347,9 +359,9 @@ auto unpack(F&& firstSequenceable, U&& unpacker, /// Calls the given unpacker with the content of the given sequenceable template -auto unpack(F&& firstSequenceable, S&& secondSequenceable, U&& unpacker, - std::integer_sequence, - std::integer_sequence) { +constexpr auto unpack(F&& firstSequenceable, S&& secondSequenceable, + U&& unpacker, std::integer_sequence, + std::integer_sequence) { using std::get; (void)firstSequenceable; (void)secondSequenceable; @@ -365,7 +377,8 @@ auto unpack(F&& firstSequenceable, U&& unpacker) { } /// Calls the given unpacker with the content of the given sequenceables template -auto unpack(F&& firstSequenceable, S&& secondSequenceable, U&& unpacker) { +constexpr auto unpack(F&& firstSequenceable, S&& secondSequenceable, + U&& unpacker) { return unpack(std::forward(firstSequenceable), std::forward(secondSequenceable), std::forward(unpacker), sequenceOf(identity_of(firstSequenceable)), @@ -374,7 +387,8 @@ auto unpack(F&& firstSequenceable, S&& secondSequenceable, U&& unpacker) { /// Applies the handler function to each element contained in the sequenceable template -void static_for_each_in(Sequenceable&& sequenceable, Handler&& handler) { +constexpr void static_for_each_in(Sequenceable&& sequenceable, + Handler&& handler) { unpack( std::forward(sequenceable), [&](auto&&... entries) mutable { auto consume = [&](auto&& entry) mutable { @@ -390,7 +404,7 @@ void static_for_each_in(Sequenceable&& sequenceable, Handler&& handler) { /// Adds the given type at the back of the left sequenceable template -auto push(Left&& left, Element&& element) { +constexpr auto push(Left&& left, Element&& element) { return unpack(std::forward(left), [&](auto&&... leftArgs) { return std::make_tuple(std::forward(leftArgs)..., std::forward(element)); @@ -399,44 +413,45 @@ auto push(Left&& left, Element&& element) { /// Adds the element to the back of the identity template -auto push(identity, identity) { +constexpr auto push(identity, identity) noexcept { return identity{}; } /// Removes the first element from the identity template -auto pop_first(identity) { +constexpr auto pop_first(identity) noexcept { return identity{}; } /// Returns the merged sequence -template auto merge(Left&& left) { +template constexpr auto merge(Left&& left) { return std::forward(left); } /// Merges the left sequenceable with the right ones template -auto merge(Left&& left, Right&& right, Rest&&... rest) { - // Merge the left with the right sequenceable - auto merged = - unpack(std::forward(left), std::forward(right), - [&](auto&&... args) { - // Maybe use: template class T, - // typename... Args> - return std::make_tuple(std::forward(args)...); - }); - // And merge it with the rest - return merge(std::move(merged), std::forward(rest)...); +constexpr auto merge(Left&& left, Right&& right, Rest&&... rest) { + // Merge the left with the right sequenceable and + // merge the result with the rest. + return merge(unpack(std::forward(left), std::forward(right), + [&](auto&&... args) { + // Maybe use: template class T, + // typename... Args> + return std::make_tuple( + std::forward(args)...); + }), + std::forward(rest)...); } /// Merges the left identity with the right ones template -auto merge(identity /*left*/, identity /*right*/, - Rest&&... rest) { +constexpr auto merge(identity /*left*/, + identity /*right*/, Rest&&... rest) { return merge(identity{}, std::forward(rest)...); } /// Combines the given arguments with the given folding function -template auto fold(F&& /*folder*/, First&& first) { +template +constexpr auto fold(F&& /*folder*/, First&& first) { return std::forward(first); } /// Combines the given arguments with the given folding function @@ -448,21 +463,21 @@ auto fold(F&& folder, First&& first, Second&& second, Rest&&... rest) { } /// Returns a folding function using operator `&&`. -inline auto and_folding() { +inline auto and_folding() noexcept { return [](auto&& left, auto&& right) { return std::forward(left) && std::forward(right); }; } /// Returns a folding function using operator `||`. -inline auto or_folding() { +inline auto or_folding() noexcept { return [](auto&& left, auto&& right) { return std::forward(left) || std::forward(right); }; } /// Returns a folding function using operator `>>`. -inline auto seq_folding() { +inline auto seq_folding() noexcept { return [](auto&& left, auto&& right) { return std::forward(left) >> std::forward(right); @@ -583,18 +598,18 @@ auto partial_invoke(T&& callable, Args&&... args) { // Class for making child classes non copyable struct non_copyable { - non_copyable() = default; + constexpr non_copyable() = default; non_copyable(non_copyable const&) = delete; - non_copyable(non_copyable&&) = default; + constexpr non_copyable(non_copyable&&) = default; non_copyable& operator=(non_copyable const&) = delete; non_copyable& operator=(non_copyable&&) = default; }; // Class for making child classes non copyable and movable struct non_movable { - non_movable() = default; + constexpr non_movable() = default; non_movable(non_movable const&) = delete; - non_movable(non_movable&&) = delete; + constexpr non_movable(non_movable&&) = delete; non_movable& operator=(non_movable const&) = delete; non_movable& operator=(non_movable&&) = delete; }; @@ -604,9 +619,9 @@ struct non_movable { /// is moved to another instance. class ownership { public: - ownership() = default; - explicit ownership(bool isOwning_) : is_owning(isOwning_) {} - ownership(ownership const&) = default; + constexpr ownership() = default; + constexpr explicit ownership(bool isOwning_) : is_owning(isOwning_) {} + constexpr ownership(ownership const&) = default; ownership(ownership&& right) noexcept : is_owning(std::exchange(right.is_owning, false)){}; ownership& operator=(ownership const&) = default; @@ -619,7 +634,7 @@ public: return ownership(has_ownership() && right.has_ownership()); } - bool has_ownership() const noexcept { return is_owning; } + constexpr bool has_ownership() const noexcept { return is_owning; } void invalidate() noexcept { is_owning = false; } private: @@ -654,15 +669,15 @@ struct this_thread_executor_tag {}; /// -> void namespace base { /// Returns the signature hint of the given continuable -template auto hint_of(util::identity) { +template constexpr auto hint_of(util::identity) { static_assert(util::fail::value, "Expected a continuation with an existing signature hint!"); return util::identity_of(); } /// Returns the signature hint of the given continuable template -auto hint_of( - util::identity>>) { +constexpr auto +hint_of(util::identity>>) { return signature_hint_tag{}; } @@ -726,18 +741,18 @@ public: using T::operator(); /// Returns the underlaying signature hint - Hint hint() const noexcept { return {}; } + constexpr Hint hint() const noexcept { return {}; } }; template -auto make_invoker(T&& invoke, signature_hint_tag) { +constexpr auto make_invoker(T&& invoke, signature_hint_tag) { return invoker, signature_hint_tag>( std::forward(invoke)); } /// - continuable -> result(nextCallback); template -auto invokerOf(util::identity>) { +constexpr auto invokerOf(util::identity>) { /// Get the hint of the unwrapped returned continuable using Type = decltype(attorney::materialize( std::declval>())); @@ -796,14 +811,14 @@ inline auto sequencedUnpackInvoker() { // - std::pair -> nextCallback(?, ?) template -auto invokerOf(util::identity>) { +constexpr auto invokerOf(util::identity>) { return make_invoker(sequencedUnpackInvoker(), util::identity{}); } // - std::tuple -> nextCallback(?...) template -auto invokerOf(util::identity>) { +constexpr auto invokerOf(util::identity>) { return make_invoker(sequencedUnpackInvoker(), util::identity{}); } } // end namespace decoration @@ -890,8 +905,8 @@ void invoke_proxy(signature_hint_tag, Continuation&& continuation, /// Returns the next hint when the callback is invoked with the given hint template -auto next_hint_of(util::identity /*callback*/, - signature_hint_tag /*current*/) { +constexpr auto next_hint_of(util::identity /*callback*/, + signature_hint_tag /*current*/) { auto result = util::identity_of()(std::declval()...))>(); @@ -989,12 +1004,12 @@ template <> struct is_strategy : std::true_type {}; namespace annotating { namespace detail { /// Void hints are equal to an empty signature -inline auto make_hint_of(util::identity) { +constexpr auto make_hint_of(util::identity) noexcept { return signature_hint_tag<>{}; } /// All other hints are the obvious hints... template -auto make_hint_of(util::identity args) { +constexpr auto make_hint_of(util::identity args) noexcept { return args; // Identity is equal to signature_hint_tag } } // end namespace detail @@ -1015,7 +1030,8 @@ auto make_hint_of(util::identity args) { /// - absent_signature_hint_tag /// template -auto extract(util::identity /*type*/, util::identity hint) { +constexpr auto extract(util::identity /*type*/, + util::identity hint) { return util::static_if(hint, util::is_empty(), [=](auto /*hint*/) { /// When the arguments are the hint is absent @@ -1030,7 +1046,7 @@ auto extract(util::identity /*type*/, util::identity hint) { namespace detail { template -void assign(util::size_constant /*pos*/, T& /*storage*/) { +constexpr void assign(util::size_constant /*pos*/, T& /*storage*/) { // ... } template @@ -1251,11 +1267,11 @@ auto make_any_result_submitter(Callback&& callback) { } template -T first_of(util::identity) noexcept; +constexpr T first_of(util::identity) noexcept; template -auto common_result_of(Signature signature, signature_hint_tag<>, - Args... /*args*/) { +constexpr auto common_result_of(Signature signature, signature_hint_tag<>, + Args... /*args*/) { /// Assert that the other signatures are empty too which means all signatures /// had the same size. util::static_for_each_in(util::identity{}, [&](auto rest) { @@ -1271,7 +1287,8 @@ auto common_result_of(Signature signature, signature_hint_tag<>, /// c1 with `void(int)` and c22 with `void(float)`, the common result shared /// between both continuations is `void(int)`. template -auto common_result_of(Signature signature, First first, Args... args) { +constexpr auto common_result_of(Signature signature, First first, + Args... args) { auto common = util::identity>{}; @@ -1366,9 +1383,9 @@ class promise_callback> typename future_trait::promise_t promise_; public: - promise_callback() = default; + constexpr promise_callback() = default; promise_callback(promise_callback const&) = delete; - promise_callback(promise_callback&&) = default; + constexpr promise_callback(promise_callback&&) = default; promise_callback& operator=(promise_callback const&) = delete; promise_callback& operator=(promise_callback&&) = delete;