/** * Copyright 2015-2016 Denis Blank * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* #include #include #include namespace detail { template struct Identity { }; template struct IdentityInheritenceWrapper : Identity, IdentityInheritenceWrapper { }; enum class NamedParameterId { NAMED_PARAMATER_CALLBACK, NAMED_PARAMATER_REJECTOR }; template struct NamedParameter : std::integral_constant, std::common_type { }; template using GetNamedParameterOrDefault = void; template class ContinuableBase; template struct ReturnTypeToContinuableConverter; template struct template class ContinuableBase, CallbackType> { CallbackType callback_; public: explicit ContinuableBase(CallbackType&& callback) : callback_(std::move(callback)) { } void via() { } template auto then(C&& continuation) { // The type the callback will evaluate to using EvaluatedTo = decltype(std::declval()(std::declval()...)); return EvaluatedTo{ }; } }; } // namespace detail using namespace detail; // template // using Continuable = detail::ContinuableBase>; template struct Callback { void operator() (Args... ) { } }; template auto make_continuable(Args&&...) { return Continuable<> { }; } auto http_request(std::string url) { return make_continuable([url](auto& callback) { callback("
hi
"); }); } template auto appendHandlerToContinuation(Continuation&& cont, Handler&& handler) { return [cont = std::forward(cont), handler = std::forward(handler)](auto&& continuation) { using T = decltype(continuation); return [continuation = std::forward(continuation)](auto&&... arg) { continuation(std::forward(arg)...); }; current([continuation = std::forward(continuation)](auto&&... arg) { continuation(std::forward(arg)...); }); }; } */ #include #include #include #include struct SelfDispatcher { template void operator() (T&& callable) const { std::forward(callable)(); } }; template class ContinuableBase; static auto createEmptyContinuation() { return [](auto&& callback) { callback(); }; } static auto createEmptyCallback() { return [](auto&&...) { }; } template auto applyTuple(std::integer_sequence, T&& tuple, F&& function) { return std::forward(function)(std::get(std::forward(tuple))...); } class Ownership { public: Ownership() { } Ownership(Ownership const&) = default; explicit Ownership(Ownership&& right) noexcept : isOwningThis(takeOverFrom(std::move(right))) { }; Ownership& operator = (Ownership const&) = default; Ownership& operator = (Ownership&& right) noexcept { isOwningThis = takeOverFrom(std::move(right)); return *this; } bool IsOwning() const noexcept { return isOwningThis; } private: bool static takeOverFrom(Ownership&& right) { bool value = right.isOwningThis; right.isOwningThis = false; return value; } bool isOwningThis{ true }; }; /// Decorates none template struct CallbackResultDecorator { template static auto decorate(Callback&& callback) { return std::forward(callback); } }; /// Decorates void as return type template<> struct CallbackResultDecorator { template static auto decorate(Callback&& callback) { return [callback = std::forward(callback)](auto&&... args) { callback(std::forward(args)...); return createEmptyContinuation(); }; } }; // Decorates tuples as return type template struct CallbackResultDecorator> { template static auto decorate(Callback&& callback) { return [callback = std::forward(callback)](auto&&... args) { // Receive the tuple from the callback auto result = callback(std::forward(args)...); return [result = std::move(result)] (auto&& next) mutable { // Generate a sequence for tag dispatching auto constexpr const sequence = std::make_integer_sequence{}; // Invoke the callback with the tuple returned // from the previous callback. applyTuple(sequence, std::move(result), std::forward(next)); }; }; } }; /// Create the proxy callback that is responsible for invoking /// the real callback and passing the next continuation into /// to the result of the callback. template auto createProxyCallback(Callback&& callback, Next&& next) { return [callback = std::forward(callback), next = std::forward(next)] (auto&&... args) mutable { // Callbacks shall always return a continuation, // if not, we need to decorate it. using Result = decltype(callback(std::forward(args)...)); using Decorator = CallbackResultDecorator; Decorator::decorate(std::move(callback)) (std::forward(args)...)(std::move(next)); }; } template auto appendHandlerToContinuation(Continuation&& continuation, Callback&& callback) { return [continuation = std::forward(continuation), callback = std::forward(callback)](auto&& next) mutable { // Invoke the next invocation handler std::move(continuation)(createProxyCallback( std::move(callback), std::forward(next))); }; } template void invokeContinuation(Continuation&& continuation) { // Pass an empty callback to the continuation to invoke it std::forward(continuation)(createEmptyCallback()); } template struct ContinuableConfig { using Continuation = ContinuationType; using Dispatcher = DispatcherType; template using ChangeContinuationTo = ContinuableConfig< NewType, Dispatcher >; template using ChangeDispatcherTo = ContinuableConfig< Continuation, NewType >; }; template auto make_continuable(Continuation&& continuation, Dispatcher&& dispatcher = SelfDispatcher{}) noexcept { using Config = ContinuableConfig< std::decay_t, std::decay_t >; return ContinuableBase { std::forward(continuation), std::forward(dispatcher) }; } template class ContinuableBase { template friend class ContinuableBase; ContinuableBase(typename Config::Continuation continuation_, Ownership ownership_, typename Config::Dispatcher dispatcher_) noexcept : continuation(std::move(continuation_)), dispatcher(std::move(dispatcher_)), ownership(std::move(ownership_)) { } public: ContinuableBase(typename Config::Continuation continuation_, typename Config::Dispatcher dispatcher_) noexcept : continuation(std::move(continuation_)), dispatcher(std::move(dispatcher_)) { } ~ContinuableBase() { if (ownership.IsOwning()) { invokeContinuation(std::move(continuation)); } } ContinuableBase(ContinuableBase&&) = default; ContinuableBase(ContinuableBase const&) = default; template auto then(Callback&& callback)&& { auto next = appendHandlerToContinuation(std::move(continuation), std::forward(callback)); using Transformed = ContinuableBase< typename Config::template ChangeContinuationTo >; return Transformed { std::move(next), std::move(ownership), std::move(dispatcher) }; } template auto then(Callback&& callback) const& { auto next = appendHandlerToContinuation(continuation, std::forward(callback)); using Transformed = ContinuableBase< typename Config::template ChangeContinuationTo >; return Transformed { std::move(next), ownership, dispatcher }; } template auto post(NewDispatcher&& newDispatcher)&& { using Transformed = ContinuableBase< typename Config::template ChangeDispatcherTo> >; return Transformed { std::move(continuation), std::move(ownership), std::forward(newDispatcher) }; } template auto post(NewDispatcher&& newDispatcher) const& { using Transformed = ContinuableBase< typename Config::template ChangeDispatcherTo> >; return Transformed { continuation, ownership, std::forward(newDispatcher) }; } private: typename Config::Continuation continuation; typename Config::Dispatcher dispatcher; Ownership ownership; }; static auto makeTestContinuation() { return make_continuable([](auto&& callback) { callback("
hi
"); }); } int main(int, char**) { auto dispatcher = SelfDispatcher{}; int res = 0; makeTestContinuation() .post(dispatcher) .then([](std::string) { return std::make_tuple(47, 46, 45); }) .then([&](int val1, int val2, int val3) { res += val1 + val2 + val3; int i = 0; }); return res; }