/** * 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 #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(std::exchange(right.isOwningThis, false)) { }; Ownership& operator = (Ownership const&) = default; Ownership& operator = (Ownership&& right) noexcept { isOwningThis = std::exchange(right.isOwningThis, false); return *this; } bool hasOwnership() const noexcept { return isOwningThis; } void invalidate() { isOwningThis = false; } private: bool isOwningThis{ true }; }; /// Decorates single values template struct CallbackResultDecorator { template static auto decorate(Callback&& callback) { return [callback = std::forward(callback)](auto&&... args) { Value value = callback(std::forward(args)...); return [value = std::move(value)](auto&& callback) mutable { callback(std::move(value)); }; }; } }; /// No decoration is needed for continuables 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 appendCallback(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(Data data) { // Check whether the ownership is acquired and start the continuation call if (data.ownership.hasOwnership()) { // Pass an empty callback to the continuation to invoke it std::move(data.continuation)(createEmptyCallback()); } } template struct ContinuableConfig { using Continuation = ContinuationType; using Dispatcher = DispatcherType; template using ChangeContinuationTo = ContinuableConfig< NewType, Dispatcher >; template using ChangeDispatcherTo = ContinuableConfig< Continuation, NewType >; }; /// template struct ContinuableData { using Config = ConfigType; ContinuableData(Ownership ownership_, typename Config::Continuation continuation_, typename Config::Dispatcher dispatcher_) noexcept : ownership(std::move(ownership_)), continuation(std::move(continuation_)), dispatcher(std::move(dispatcher_)) { } ContinuableData(typename Config::Continuation continuation_, typename Config::Dispatcher dispatcher_) noexcept : continuation(std::move(continuation_)), dispatcher(std::move(dispatcher_)) { } Ownership ownership; typename Config::Continuation continuation; typename Config::Dispatcher dispatcher; }; /// The DefaultDecoration is a container for already materialized /// ContinuableData which can be accessed instantly. template class DefaultDecoration { public: explicit DefaultDecoration(Data data_) : data(std::move(data_)) { } using Config = typename Data::Config; /// Return a r-value reference to the data Data&& undecorate()&& { return std::move(data); } /// Return a copy of the data Data undecorate() const& { return data; } private: Data data; }; template auto make_continuable(Continuation&& continuation, Dispatcher&& dispatcher = SelfDispatcher{}) noexcept { using Decoration = DefaultDecoration, std::decay_t >>>; return ContinuableBase(Decoration({ std::forward(continuation), std::forward(dispatcher) })); } template auto thenImpl(Data data, Callback&& callback) { auto next = appendCallback(std::move(data.continuation), std::forward(callback)); using Decoration = DefaultDecoration >>; return ContinuableBase(Decoration({ std::move(data.ownership), std::move(next), std::move(data.dispatcher) })); } template auto postImpl(Data&& data ,NewDispatcher&& newDispatcher) { /*->ContinuableBase>> { return{ std::move(continuation), std::move(ownership), std::forward(newDispatcher) }; */ return 0; } template class ContinuableBase { template friend class ContinuableBase; public: explicit ContinuableBase(Decoration decoration_) : decoration(std::move(decoration_)) { } ~ContinuableBase() { // Undecorate/materialize the decoration invokeContinuation(std::move(decoration).undecorate()); } ContinuableBase(ContinuableBase&&) = default; ContinuableBase(ContinuableBase const&) = default; template auto then(Callback&& callback)&& { return thenImpl(std::move(decoration).undecorate(), std::forward(callback)); } template auto then(Callback&& callback) const& { return thenImpl(decoration.undecorate(), std::forward(callback)); } template auto post(NewDispatcher&& newDispatcher)&& { return postImpl(std::move(decoration).undecorate(), std::forward(newDispatcher)); } template auto post(NewDispatcher&& newDispatcher) const& { return postImpl(decoration.undecorate(), std::forward(newDispatcher)); } private: /// The Decoration represents the possible lazy materialized /// data of the continuable. /// The decoration pattern is used to make it possible to allow lazy chaining /// of operators on Continuables like the and expression `&&`. Decoration decoration; }; static auto makeTestContinuation() { return make_continuable([](auto&& callback) { callback("47"); }); } int main(int, char**) { auto dispatcher = SelfDispatcher{}; int res = 0; makeTestContinuation() // .post(dispatcher) .then([](std::string /*str*/) { return std::make_tuple(47, 46, 45); }) .then([](int val1, int val2, int val3) { return val1 + val2 + val3; }) .then([&](int val) { res += val; }); return res; }