mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Add lazy undecoration
This commit is contained in:
parent
e2ee851100
commit
90a12e10f7
201
NextGen.cpp
201
NextGen.cpp
@ -108,8 +108,10 @@ auto appendHandlerToContinuation(Continuation&& cont, Handler&& handler) {
|
|||||||
};
|
};
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -141,30 +143,42 @@ public:
|
|||||||
Ownership() { }
|
Ownership() { }
|
||||||
Ownership(Ownership const&) = default;
|
Ownership(Ownership const&) = default;
|
||||||
explicit Ownership(Ownership&& right) noexcept
|
explicit Ownership(Ownership&& right) noexcept
|
||||||
: isOwningThis(takeOverFrom(std::move(right))) { };
|
: isOwningThis(std::exchange(right.isOwningThis, false)) { };
|
||||||
Ownership& operator = (Ownership const&) = default;
|
Ownership& operator = (Ownership const&) = default;
|
||||||
Ownership& operator = (Ownership&& right) noexcept {
|
Ownership& operator = (Ownership&& right) noexcept {
|
||||||
isOwningThis = takeOverFrom(std::move(right));
|
isOwningThis = std::exchange(right.isOwningThis, false);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOwning() const noexcept {
|
bool hasOwnership() const noexcept {
|
||||||
return isOwningThis;
|
return isOwningThis;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void invalidate() {
|
||||||
bool static takeOverFrom(Ownership&& right) {
|
isOwningThis = false;
|
||||||
bool value = right.isOwningThis;
|
|
||||||
right.isOwningThis = false;
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
bool isOwningThis{ true };
|
bool isOwningThis{ true };
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Decorates none
|
/// Decorates single values
|
||||||
template<typename Result>
|
template<typename Value>
|
||||||
struct CallbackResultDecorator {
|
struct CallbackResultDecorator {
|
||||||
|
template<typename Callback>
|
||||||
|
static auto decorate(Callback&& callback) {
|
||||||
|
return [callback = std::forward<Callback>(callback)](auto&&... args) {
|
||||||
|
Value value = callback(std::forward<decltype(args)>(args)...);
|
||||||
|
return [value = std::move(value)](auto&& callback) mutable {
|
||||||
|
callback(std::move(value));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// No decoration is needed for continuables
|
||||||
|
template<typename Config>
|
||||||
|
struct CallbackResultDecorator<ContinuableBase<Config>>{
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
static auto decorate(Callback&& callback) {
|
static auto decorate(Callback&& callback) {
|
||||||
return std::forward<Callback>(callback);
|
return std::forward<Callback>(callback);
|
||||||
@ -223,8 +237,7 @@ auto createProxyCallback(Callback&& callback,
|
|||||||
|
|
||||||
template<typename Continuation, typename Callback>
|
template<typename Continuation, typename Callback>
|
||||||
auto appendCallback(Continuation&& continuation,
|
auto appendCallback(Continuation&& continuation,
|
||||||
Callback&& callback) {
|
Callback&& callback) {
|
||||||
|
|
||||||
return [continuation = std::forward<Continuation>(continuation),
|
return [continuation = std::forward<Continuation>(continuation),
|
||||||
callback = std::forward<Callback>(callback)](auto&& next) mutable {
|
callback = std::forward<Callback>(callback)](auto&& next) mutable {
|
||||||
// Invoke the next invocation handler
|
// Invoke the next invocation handler
|
||||||
@ -233,10 +246,13 @@ auto appendCallback(Continuation&& continuation,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Continuation>
|
template<typename Data>
|
||||||
void invokeContinuation(Continuation&& continuation) {
|
void invokeContinuation(Data data) {
|
||||||
// Pass an empty callback to the continuation to invoke it
|
// Check whether the ownership is acquired and start the continuation call
|
||||||
std::forward<Continuation>(continuation)(createEmptyCallback());
|
if (data.ownership.hasOwnership()) {
|
||||||
|
// Pass an empty callback to the continuation to invoke it
|
||||||
|
std::move(data.continuation)(createEmptyCallback());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ContinuationType, typename DispatcherType>
|
template<typename ContinuationType, typename DispatcherType>
|
||||||
@ -255,91 +271,134 @@ struct ContinuableConfig {
|
|||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
template<typename ConfigType>
|
||||||
|
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_)) { }
|
||||||
|
|
||||||
|
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<typename Data>
|
||||||
|
class DefaultDecoration {
|
||||||
|
public:
|
||||||
|
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<typename Continuation, typename Dispatcher = SelfDispatcher>
|
template<typename Continuation, typename Dispatcher = SelfDispatcher>
|
||||||
auto make_continuable(Continuation&& continuation,
|
auto make_continuable(Continuation&& continuation,
|
||||||
Dispatcher&& dispatcher = SelfDispatcher{}) noexcept {
|
Dispatcher&& dispatcher = SelfDispatcher{}) noexcept {
|
||||||
using Config = ContinuableConfig<
|
using Decoration = DefaultDecoration<ContinuableData<ContinuableConfig<
|
||||||
std::decay_t<Continuation>,
|
std::decay_t<Continuation>,
|
||||||
std::decay_t<Dispatcher>
|
std::decay_t<Dispatcher>
|
||||||
>;
|
>>>;
|
||||||
return ContinuableBase<Config> {
|
return ContinuableBase<Decoration> { { {
|
||||||
|
{ },
|
||||||
std::forward<Continuation>(continuation),
|
std::forward<Continuation>(continuation),
|
||||||
std::forward<Dispatcher>(dispatcher)
|
std::forward<Dispatcher>(dispatcher)
|
||||||
};
|
} } };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Config>
|
template<typename Data, typename Callback>
|
||||||
|
auto thenImpl(Data data, Callback&& callback) {
|
||||||
|
auto next = appendCallback(std::move(data.continuation),
|
||||||
|
std::forward<Callback>(callback));
|
||||||
|
using Decoration = DefaultDecoration<ContinuableData<
|
||||||
|
typename Data::Config::template ChangeContinuationTo<decltype(next)>
|
||||||
|
>>;
|
||||||
|
return ContinuableBase<Decoration> { {
|
||||||
|
{ std::move(data.ownership), std::move(next), std::move(data.dispatcher) }
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Data, typename NewDispatcher>
|
||||||
|
auto postImpl(Data&& data ,NewDispatcher&& newDispatcher) {
|
||||||
|
/*->ContinuableBase<typename Config::template
|
||||||
|
ChangeDispatcherTo<std::decay_t<NewDispatcher>>> {
|
||||||
|
return{ std::move(continuation), std::move(ownership),
|
||||||
|
std::forward<NewDispatcher>(newDispatcher) }; */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Decoration>
|
||||||
class ContinuableBase {
|
class ContinuableBase {
|
||||||
template<typename>
|
template<typename>
|
||||||
friend class ContinuableBase;
|
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:
|
public:
|
||||||
ContinuableBase(typename Config::Continuation continuation_,
|
explicit ContinuableBase(Decoration decoration_)
|
||||||
typename Config::Dispatcher dispatcher_) noexcept
|
: decoration(std::move(decoration_)) { }
|
||||||
: continuation(std::move(continuation_)),
|
|
||||||
dispatcher(std::move(dispatcher_)) { }
|
|
||||||
~ContinuableBase() {
|
~ContinuableBase() {
|
||||||
if (ownership.IsOwning()) {
|
// Undecorate/materialize the decoration
|
||||||
invokeContinuation(std::move(continuation));
|
invokeContinuation(std::move(decoration).undecorate());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ContinuableBase(ContinuableBase&&) = default;
|
ContinuableBase(ContinuableBase&&) = default;
|
||||||
ContinuableBase(ContinuableBase const&) = default;
|
ContinuableBase(ContinuableBase const&) = default;
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
auto then(Callback&& callback)&& {
|
auto then(Callback&& callback)&& {
|
||||||
auto next = appendCallback(std::move(continuation),
|
return thenImpl(std::move(decoration).undecorate(),
|
||||||
std::forward<Callback>(callback));
|
std::forward<Callback>(callback));
|
||||||
using Transformed = ContinuableBase<
|
|
||||||
typename Config::template ChangeContinuationTo<decltype(next)>
|
|
||||||
>;
|
|
||||||
return Transformed {
|
|
||||||
std::move(next), std::move(ownership), std::move(dispatcher)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
auto then(Callback&& callback) const& {
|
auto then(Callback&& callback) const& {
|
||||||
auto next = appendCallback(continuation, std::forward<Callback>(callback));
|
return thenImpl(decoration.undecorate(),
|
||||||
using Transformed = ContinuableBase<
|
std::forward<Callback>(callback));
|
||||||
typename Config::template ChangeContinuationTo<decltype(next)>
|
|
||||||
>;
|
|
||||||
return Transformed {
|
|
||||||
std::move(next), ownership, dispatcher
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename NewDispatcher>
|
template<typename NewDispatcher>
|
||||||
auto post(NewDispatcher&& newDispatcher)&&
|
auto post(NewDispatcher&& newDispatcher)&& {
|
||||||
-> ContinuableBase<typename Config::template
|
return postImpl(std::move(decoration).undecorate(),
|
||||||
ChangeDispatcherTo<std::decay_t<NewDispatcher>>> {
|
std::forward<NewDispatcher>(newDispatcher));
|
||||||
return { std::move(continuation), std::move(ownership),
|
|
||||||
std::forward<NewDispatcher>(newDispatcher) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename NewDispatcher>
|
template<typename NewDispatcher>
|
||||||
auto post(NewDispatcher&& newDispatcher) const&
|
auto post(NewDispatcher&& newDispatcher) const& {
|
||||||
-> ContinuableBase<typename Config::template
|
return postImpl(decoration.undecorate(),
|
||||||
ChangeDispatcherTo<std::decay_t<NewDispatcher>>> {
|
std::forward<NewDispatcher>(newDispatcher));
|
||||||
return { continuation, ownership,
|
|
||||||
std::forward<NewDispatcher>(newDispatcher) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typename Config::Continuation continuation;
|
/// The Decoration represents the possible lazy materialized
|
||||||
typename Config::Dispatcher dispatcher;
|
/// data of the continuable.
|
||||||
Ownership ownership;
|
/// 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() {
|
static auto makeTestContinuation() {
|
||||||
return make_continuable([](auto&& callback) {
|
return make_continuable([](auto&& callback) {
|
||||||
callback("<br>hi<br>");
|
callback("47");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,17 +407,15 @@ int main(int, char**) {
|
|||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
makeTestContinuation()
|
makeTestContinuation()
|
||||||
.post(dispatcher)
|
// .post(dispatcher)
|
||||||
.then([](std::string) {
|
.then([](std::string /*str*/) {
|
||||||
|
|
||||||
|
|
||||||
return std::make_tuple(47, 46, 45);
|
return std::make_tuple(47, 46, 45);
|
||||||
})
|
})
|
||||||
.then([&](int val1, int val2, int val3) {
|
.then([](int val1, int val2, int val3) {
|
||||||
|
return val1 + val2 + val3;
|
||||||
|
})
|
||||||
res += val1 + val2 + val3;
|
.then([&](int val) {
|
||||||
int i = 0;
|
res += val;
|
||||||
});
|
});
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user