improve Lambda interface

also implemet lazy loading in Node/Network
This commit is contained in:
falsycat 2022-08-05 13:35:29 +09:00
parent 3e8ffb0f72
commit 03c1199175
10 changed files with 206 additions and 230 deletions

View File

@ -9,12 +9,16 @@
namespace nf7 {
class Lambda {
class Lambda : public nf7::Context {
public:
class Owner;
Lambda() = delete;
Lambda(const std::shared_ptr<Owner>& owner) noexcept : owner_(owner) {
Lambda(nf7::File& f, const std::shared_ptr<nf7::Lambda>& parent) noexcept :
Lambda(f.env(), f.id(), parent) {
}
Lambda(Env& env, File::Id id, const std::shared_ptr<nf7::Lambda>& parent) noexcept :
Context(env, id), depth_(parent? parent->depth()+1: 0), parent_(parent) {
}
virtual ~Lambda() = default;
Lambda(const Lambda&) = delete;
@ -24,41 +28,13 @@ class Lambda {
virtual void Handle(size_t, Value&&, const std::shared_ptr<Lambda>&) noexcept { }
const std::shared_ptr<Owner>& owner() const noexcept { return owner_; }
private:
std::shared_ptr<Owner> owner_;
};
class Lambda::Owner final {
public:
Owner() = delete;
Owner(nf7::File::Path&& path,
std::string_view desc,
const std::shared_ptr<Owner>& parent = nullptr) noexcept :
path_(std::move(path)),
desc_(desc),
depth_(parent? parent->depth()+1: 0),
parent_(parent) {
}
Owner(const Owner&) = delete;
Owner(Owner&&) = delete;
Owner& operator=(const Owner&) = delete;
Owner& operator=(Owner&&) = delete;
const nf7::File::Path& path() const noexcept { return path_; }
const std::string& desc() const noexcept { return desc_; }
size_t depth() const noexcept { return depth_; }
const std::shared_ptr<Owner>& parent() const noexcept { return parent_; }
const std::weak_ptr<Lambda>& parent() const noexcept { return parent_; }
private:
nf7::File::Path path_;
std::string desc_;
size_t depth_;
std::shared_ptr<Owner> parent_;
std::weak_ptr<Lambda> parent_;
};
} // namespace nf7

View File

@ -14,7 +14,6 @@
#include "nf7.hh"
#include "common/future.hh"
#include "common/lambda.hh"
#include "common/logger_ref.hh"
#include "common/luajit.hh"
#include "common/luajit_ref.hh"
@ -54,9 +53,8 @@ class Thread final : public std::enable_shared_from_this<Thread> {
Thread() = delete;
Thread(const std::shared_ptr<nf7::Context>& ctx,
const std::shared_ptr<nf7::luajit::Queue>& ljq,
const std::shared_ptr<nf7::Lambda::Owner>& la_owner,
Handler&& handler) noexcept :
ctx_(ctx), ljq_(ljq), la_owner_(la_owner), handler_(std::move(handler)) {
ctx_(ctx), ljq_(ljq), handler_(std::move(handler)) {
}
Thread(const Thread&) = delete;
Thread(Thread&&) = delete;
@ -115,7 +113,6 @@ class Thread final : public std::enable_shared_from_this<Thread> {
nf7::Env& env() noexcept { return ctx_->env(); }
const std::shared_ptr<nf7::Context>& ctx() const noexcept { return ctx_; }
const std::shared_ptr<nf7::luajit::Queue>& ljq() const noexcept { return ljq_; }
const std::shared_ptr<nf7::Lambda::Owner>& lambdaOwner() const noexcept { return la_owner_; }
const std::shared_ptr<nf7::LoggerRef>& logger() const noexcept { return logger_; }
State state() const noexcept { return state_; }
@ -125,7 +122,6 @@ class Thread final : public std::enable_shared_from_this<Thread> {
std::shared_ptr<nf7::Context> ctx_;
std::shared_ptr<nf7::luajit::Queue> ljq_;
std::shared_ptr<nf7::Lambda::Owner> la_owner_;
Handler handler_;
std::atomic<State> state_ = kInitial;

View File

@ -82,8 +82,9 @@ class Thread::Lambda::Receiver final : public nf7::Lambda,
static constexpr size_t kMaxQueue = 1024;
Receiver() = delete;
Receiver(const std::shared_ptr<const Thread::Lambda::ImmData>& imm) noexcept :
nf7::Lambda(nullptr), imm_(imm) {
Receiver(nf7::Env& env, nf7::File::Id id,
const std::shared_ptr<const Thread::Lambda::ImmData>& imm) noexcept :
nf7::Lambda(env, id, nullptr), imm_(imm) {
}
void Handle(size_t idx, nf7::Value&& v, const std::shared_ptr<nf7::Lambda>&) noexcept override {
@ -124,8 +125,8 @@ class Thread::Lambda::Receiver final : public nf7::Lambda,
Thread::Lambda::Lambda(const std::shared_ptr<Thread>& th, nf7::Node& n) noexcept :
th_(th),
imm_(new ImmData {n.input(), n.output()}),
recv_(new Receiver {imm_}),
la_(n.CreateLambda(th->lambdaOwner())) {
recv_(new Receiver {th->env(), th->ctx()->initiator(), imm_}),
la_(n.CreateLambda(recv_)) {
}
void Thread::Lambda::PushMeta(lua_State* L) noexcept {
if (luaL_newmetatable(L, kTypeName)) {

View File

@ -33,7 +33,7 @@ class Node : public File::Interface {
Node& operator=(Node&&) = default;
virtual std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept = 0;
const std::shared_ptr<nf7::Lambda>&) noexcept = 0;
virtual void UpdateNode(Editor&) noexcept { }
virtual void UpdateMenu(Editor&) noexcept { }

View File

@ -71,7 +71,7 @@ class Device final : public nf7::File, public nf7::DirItem, public nf7::Node {
return std::make_unique<Device>(env, Selector {selector_}, cfg_);
}
std::shared_ptr<nf7::Lambda> CreateLambda(const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(const std::shared_ptr<nf7::Lambda>&) noexcept override;
void Handle(const Event&) noexcept override;
void Update() noexcept override;
@ -295,8 +295,8 @@ class Device::PlaybackLambda final : public nf7::Lambda,
};
PlaybackLambda() = delete;
PlaybackLambda(Device& f, const std::shared_ptr<Owner>& owner) noexcept :
Lambda(owner), data_(f.data_), info_(f.infoTuple()) {
PlaybackLambda(Device& f, const std::shared_ptr<nf7::Lambda>& parent) noexcept :
Lambda(f, parent), data_(f.data_), info_(f.infoTuple()) {
}
void Handle(size_t idx, nf7::Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override
@ -344,8 +344,8 @@ class Device::CaptureLambda final : public nf7::Lambda,
};
CaptureLambda() = delete;
CaptureLambda(Device& f, const std::shared_ptr<Owner>& owner) noexcept :
Lambda(owner), data_(f.data_), info_(f.infoTuple()) {
CaptureLambda(Device& f, const std::shared_ptr<nf7::Lambda>& parent) noexcept :
Lambda(f, parent), data_(f.data_), info_(f.infoTuple()) {
}
void Handle(size_t idx, nf7::Value&&, const std::shared_ptr<nf7::Lambda>& caller) noexcept override
@ -377,12 +377,12 @@ class Device::CaptureLambda final : public nf7::Lambda,
std::optional<uint64_t> time_;
};
std::shared_ptr<nf7::Lambda> Device::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
const std::shared_ptr<nf7::Lambda>& parent) noexcept {
switch (cfg_.deviceType) {
case ma_device_type_playback:
return std::make_shared<Device::PlaybackLambda>(*this, owner);
return std::make_shared<Device::PlaybackLambda>(*this, parent);
case ma_device_type_capture:
return std::make_shared<Device::CaptureLambda>(*this, owner);
return std::make_shared<Device::CaptureLambda>(*this, parent);
default:
std::abort();
}

View File

@ -80,7 +80,7 @@ class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
}
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
const std::shared_ptr<nf7::Lambda>&) noexcept override;
void Handle(const Event&) noexcept override;
void Update() noexcept override;
@ -170,17 +170,17 @@ class Node::FetchTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>
}
} catch (Exception& e) {
log_->Error("fetch failure: "+e.msg());
throw;
}
}
};
class Node::Lambda final : public nf7::Context, public nf7::Lambda,
class Node::Lambda final : public nf7::Lambda,
public std::enable_shared_from_this<Node::Lambda> {
public:
Lambda(Node& f, const std::shared_ptr<Owner>& owner) noexcept :
Context(f), nf7::Lambda(owner),
file_(&f), file_id_(f.id()),
log_(f.log_), handler_(f.FetchHandler()) {
Lambda(Node& f, const std::shared_ptr<nf7::Lambda>& parent) noexcept :
nf7::Lambda(f, parent),
file_(&f), log_(f.log_), handler_(f.FetchHandler()) {
}
void Handle(size_t idx, nf7::Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
@ -199,7 +199,6 @@ class Node::Lambda final : public nf7::Context, public nf7::Lambda,
private:
Node* const file_;
File::Id file_id_;
std::shared_ptr<nf7::LoggerRef> log_;
@ -222,9 +221,9 @@ class Node::Lambda final : public nf7::Context, public nf7::Lambda,
auto handler = handler_.value();
ljq_ = handler->ljq();
env().GetFileOrThrow(file_id_); // check if the owner is alive
env().GetFileOrThrow(initiator()); // check if the owner is alive
auto th = std::make_shared<nf7::luajit::Thread>(
self, ljq_, owner(),
self, ljq_,
[self](auto& th, auto L) { self->HandleThread(th, L); });
th->Install(log_);
th_.emplace_back(th);
@ -309,8 +308,8 @@ class Node::Lambda final : public nf7::Context, public nf7::Lambda,
std::shared_ptr<nf7::Lambda> Node::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
return std::make_shared<Node::Lambda>(*this, owner);
const std::shared_ptr<nf7::Lambda>& parent) noexcept {
return std::make_shared<Node::Lambda>(*this, parent);
}
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Node::FetchHandler() noexcept {
if (handler_) return handler_;

View File

@ -180,10 +180,7 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
}
// queue task to trigger the thread
auto la_owner = std::make_shared<nf7::Lambda::Owner>(
target_->abspath(), "building Lua object", nullptr);
auto th = std::make_shared<nf7::luajit::Thread>(
self(), ljq, la_owner, std::move(handler));
auto th = std::make_shared<nf7::luajit::Thread>(self(), ljq, std::move(handler));
th->Install(log_);
ljq->Push(self(), [&](auto L) {
try {

View File

@ -69,7 +69,7 @@ class Imm final : public nf7::File, public nf7::DirItem, public nf7::Node {
}
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
const std::shared_ptr<nf7::Lambda>&) noexcept override;
void UpdateNode(Node::Editor&) noexcept override;
@ -111,8 +111,8 @@ class Imm final : public nf7::File, public nf7::DirItem, public nf7::Node {
class Imm::Lambda final : public nf7::Lambda,
public std::enable_shared_from_this<Imm::Lambda> {
public:
Lambda(Imm& f, const std::shared_ptr<Owner>& owner) noexcept :
nf7::Lambda(owner), value_(f.mem_.data().value) {
Lambda(Imm& f, const std::shared_ptr<nf7::Lambda>& parent) noexcept :
nf7::Lambda(f, parent), value_(f.mem_.data().value) {
}
void Handle(size_t, nf7::Value&&, const std::shared_ptr<nf7::Lambda>& recv) noexcept override {
@ -123,8 +123,8 @@ class Imm::Lambda final : public nf7::Lambda,
nf7::Value value_;
};
std::shared_ptr<nf7::Lambda> Imm::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
return std::make_shared<Imm::Lambda>(*this, owner);
const std::shared_ptr<nf7::Lambda>& parent) noexcept {
return std::make_shared<Imm::Lambda>(*this, parent);
}

View File

@ -116,7 +116,7 @@ class Network final : public nf7::File,
void Handle(const Event& ev) noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
const std::shared_ptr<nf7::Lambda>&) noexcept override;
File::Interface* interface(const std::type_info& t) noexcept override {
return InterfaceSelector<nf7::DirItem, nf7::Node>(t).Select(this);
@ -188,12 +188,27 @@ class Network final : public nf7::File,
}
};
// InternalNode is an interface which can create an initiator lambda,
// Network lambda passes its input to all initiator lambdas.
// InternalNode is an interface which provides additional parameters.
class Network::InternalNode : public nf7::File::Interface {
public:
virtual std::shared_ptr<nf7::Lambda> CreateInitiator(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept = 0;
enum Flag : uint8_t {
kNone = 0,
kInputHandler = 1 << 0, // receives all input from outer
kOutputEmitter = 1 << 1, // all output is transmitted to outer
};
using Flags = uint8_t;
InternalNode(Flags flags) noexcept : flags_(flags) {
}
InternalNode(const InternalNode&) = delete;
InternalNode(InternalNode&&) = delete;
InternalNode& operator=(const InternalNode&) = delete;
InternalNode& operator=(InternalNode&&) = delete;
Flags flags() const noexcept { return flags_; }
private:
const Flags flags_;
};
// ChildNode is a File where it can be supposed that owner is Node/Network.
@ -270,7 +285,9 @@ class Network::Item final {
nf7::Env& env() const noexcept { return file_->env(); }
nf7::File& file() const noexcept { return *file_; }
nf7::Node& node() const noexcept { return *node_; }
InternalNode* inode() const noexcept { return inode_; }
InternalNode::Flags iflags() const noexcept { return inode_? inode_->flags(): 0; }
private:
ItemId id_;
@ -320,70 +337,88 @@ class Network::Item::Watcher final : public nf7::Env::Watcher {
// Builds and holds network information independently from Node/Network.
// When it receives an input from outside or an output from Nodes in the network,
// propagates it to appropriate Nodes.
class Network::Lambda : public nf7::Context, public nf7::Lambda,
class Network::Lambda : public nf7::Lambda,
public std::enable_shared_from_this<Lambda> {
public:
Lambda(Network& f, const std::shared_ptr<nf7::Lambda::Owner>& owner = nullptr) noexcept :
Context(f), nf7::Lambda(owner) {
auto self = std::make_shared<nf7::Lambda::Owner>(f.abspath(), "network lambda", owner);
// create sub lambdas
std::unordered_map<ItemId, std::shared_ptr<nf7::Lambda>> idmap;
conns_.reserve(f.items_.size());
for (const auto& item : f.items_) {
auto lambda = item->node().CreateLambda(self);
if (auto inode = item->inode()) {
assert(!lambda && "it's not allowed to have both initiator and normal lambda");
lambda = inode->CreateInitiator(self);
initiators_.push_back(lambda);
}
assert(lambda);
conns_[lambda.get()] = {};
nmap_[&item->node()] = lambda;
idmap[item->id()] = lambda;
}
// build connection map
for (const auto& lk : f.links_.items()) {
try {
const auto& src_lambda = idmap[lk.src_id];
const auto& dst_lambda = idmap[lk.dst_id];
if (!src_lambda || !dst_lambda) continue;
const auto src_index = f.GetItem(lk.src_id).node().output(lk.src_name);
const auto dst_index = f.GetItem(lk.dst_id).node().input(lk.dst_name);
conns_[src_lambda.get()].emplace_back(src_index, dst_lambda, dst_index);
} catch (Exception&) {
}
}
Lambda(Network& f, const std::shared_ptr<nf7::Lambda>& parent = nullptr) noexcept :
nf7::Lambda(f, parent), net_(&f), root_(parent == nullptr) {
}
// The first caller is remembered as an outer context. After that all callers
// are treated as a sub lambda.
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
if(abort_) return;
auto task = [this, self = shared_from_this(), idx, v = std::move(v), caller]() {
if(abort_) return;
if (owner() && outer_ == nullptr) {
outer_ = caller;
env().ExecSub(shared_from_this(), [this, idx, v = std::move(v), caller]() {
if (abort_) return;
if (!env().GetFile(initiator())) {
return; // net_ is expired
}
auto parent = this->parent().lock();
if (caller == outer_) {
for (auto init : initiators_) {
init->Handle(0, nf7::Value{v}, shared_from_this());
}
} else {
auto itr = conns_.find(caller.get());
if (itr == conns_.end()) return;
for (const auto& conn : itr->second) {
if (idx == conn.src_idx) {
conn.dst->Handle(conn.dst_idx, nf7::Value {v}, shared_from_this());
// send input from outer to input handlers
if (caller == parent) {
for (auto& item : net_->items_) {
if (item->iflags() & InternalNode::kInputHandler) {
auto la = FindOrCreateLambda(item->id());
la->Handle(idx, nf7::Value {v}, shared_from_this());
}
}
return;
}
};
env().ExecSub(shared_from_this(), std::move(task));
// send an output from children as input to children
try {
auto itr = idmap_.find(caller.get());
if (itr == idmap_.end()) {
throw nf7::Exception {"called by unknown lambda"};
}
const auto src_id = itr->second;
const auto& src_item = net_->GetItem(src_id);
const auto src_name = src_item.node().output(idx);
if (parent && src_item.iflags() & InternalNode::kOutputEmitter) {
parent->Handle(idx, nf7::Value {v}, shared_from_this());
}
for (auto& lk : net_->links_.items()) {
if (lk.src_id == src_id && lk.src_name == src_name) {
try {
const auto& dst_item = net_->GetItem(lk.dst_id);
const auto dst_idx = dst_item.node().input(lk.dst_name);
const auto dst_la = FindOrCreateLambda(lk.dst_id);
dst_la->Handle(dst_idx, nf7::Value {v}, shared_from_this());
} catch (nf7::Exception&) {
// ignore missing socket
}
}
}
} catch (nf7::Exception&) {
}
});
}
// Ensure that net_ is alive before calling
std::shared_ptr<nf7::Lambda> FindOrCreateLambda(ItemId id) noexcept
try {
return FindLambda(id);
} catch (nf7::Exception&) {
return CreateLambda(net_->GetItem(id));
}
std::shared_ptr<nf7::Lambda> FindOrCreateLambda(const Item& item) noexcept
try {
return FindLambda(item.id());
} catch (nf7::Exception&) {
return CreateLambda(item);
}
const std::shared_ptr<nf7::Lambda>& CreateLambda(const Item& item) noexcept {
auto la = item.node().CreateLambda(shared_from_this());
idmap_[la.get()] = item.id();
auto [itr, added] = lamap_.emplace(item.id(), std::move(la));
return itr->second;
}
const std::shared_ptr<nf7::Lambda>& FindLambda(ItemId id) {
auto itr = lamap_.find(id);
if (itr == lamap_.end()) {
throw nf7::Exception {"lambda is not registered"};
}
return itr->second;
}
void CleanUp() noexcept override {
@ -398,33 +433,19 @@ class Network::Lambda : public nf7::Context, public nf7::Lambda,
return "executing Node/Network";
}
const std::shared_ptr<nf7::Lambda>& outer() const noexcept { return outer_; }
const std::shared_ptr<nf7::Lambda>& sub(nf7::Node& node) const noexcept {
auto itr = nmap_.find(&node);
assert(itr != nmap_.end());
return itr->second;
}
bool isRoot() const noexcept { return root_; }
private:
struct Conn {
public:
Conn(size_t srci, const std::shared_ptr<nf7::Lambda>& dstp, size_t dsti) noexcept :
src_idx(srci), dst(dstp), dst_idx(dsti) {
}
size_t src_idx;
std::shared_ptr<nf7::Lambda> dst;
size_t dst_idx;
};
Network* const net_;
bool root_;
std::unordered_map<ItemId, std::shared_ptr<nf7::Lambda>> lamap_;
std::unordered_map<nf7::Lambda*, ItemId> idmap_;
std::shared_ptr<nf7::Lambda> outer_;
std::atomic<bool> abort_ = false;
std::vector<std::shared_ptr<nf7::Lambda>> initiators_;
std::unordered_map<Node*, std::shared_ptr<nf7::Lambda>> nmap_;
std::unordered_map<nf7::Lambda*, std::vector<Conn>> conns_;
};
void Network::DetachLambda() noexcept {
if (lambda_ && !lambda_->owner()) {
if (lambda_ && lambda_->isRoot()) {
lambda_->Abort();
}
lambda_ = nullptr;
@ -440,14 +461,16 @@ class Network::Editor final : public nf7::Node::Editor {
if (!owner_->lambda_) {
owner_->lambda_ = std::make_shared<Network::Lambda>(*owner_);
}
const auto& exec = owner_->lambda_;
const auto& lam = exec->sub(node);
assert(lam);
owner_->env().ExecSub(
exec, [exec, lam, idx, v = std::move(v)]() mutable {
lam->Handle(idx, std::move(v), exec);
});
try {
const auto& exec = owner_->lambda_;
const auto& la = exec->FindOrCreateLambda(owner_->GetItem(node));
assert(la);
owner_->env().ExecSub(
exec, [exec, la, idx, v = std::move(v)]() mutable {
la->Handle(idx, std::move(v), exec);
});
} catch (nf7::Exception&) {
}
}
void AddLink(Node& src_node, std::string_view src_name,
@ -674,7 +697,8 @@ class Network::Initiator final : public Network::ChildNode,
static constexpr size_t kManualIndex = 777;
Initiator(Env& env, bool enable_auto = false) noexcept :
ChildNode(kType, env), enable_auto_(enable_auto) {
ChildNode(kType, env), InternalNode(InternalNode::kInputHandler),
enable_auto_(enable_auto) {
output_ = {"out"};
}
@ -688,9 +712,9 @@ class Network::Initiator final : public Network::ChildNode,
return std::make_unique<Initiator>(env, enable_auto_);
}
std::shared_ptr<nf7::Lambda> CreateInitiator(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override {
if (!enable_auto_) return nullptr;
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda>& parent) noexcept override {
// TODO: use enable_auto_ value
class Emitter final : public nf7::Lambda,
public std::enable_shared_from_this<Emitter> {
public:
@ -703,21 +727,7 @@ class Network::Initiator final : public Network::ChildNode,
private:
bool done_ = false;
};
return std::make_shared<Emitter>(owner);
}
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override {
class Emitter final : public nf7::Lambda,
public std::enable_shared_from_this<Emitter> {
public:
Emitter(const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept :
Lambda(owner) {
}
void Handle(size_t, Value&&, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
caller->Handle(0, nf7::Value::Pulse {}, shared_from_this());
}
};
return std::make_shared<Emitter>(owner);
return std::make_shared<Emitter>(*this, parent);
}
void UpdateNode(Editor& ed) noexcept override {
@ -816,7 +826,8 @@ class Network::Input final : public Network::InputOrOutput,
static inline const GenericTypeInfo<Input> kType = {"Node/Network/Input", {}};
Input(Env& env, std::string_view name) noexcept :
InputOrOutput(kType, env, name, Socket::kInput) {
InputOrOutput(kType, env, name, Socket::kInput),
InternalNode(InternalNode::kInputHandler) {
output_ = {"out"};
}
@ -830,31 +841,22 @@ class Network::Input final : public Network::InputOrOutput,
return std::make_unique<Input>(env, mem_.data());
}
std::shared_ptr<nf7::Lambda> CreateInitiator(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override
try {
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda>& parent) noexcept override {
class Emitter final : public nf7::Lambda,
public std::enable_shared_from_this<Emitter> {
public:
Emitter(size_t idx, const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept :
Lambda(owner), idx_(idx) {
Emitter(Input& f, const std::shared_ptr<nf7::Lambda>& parent, size_t idx) noexcept :
nf7::Lambda(f, parent), idx_(idx) {
}
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& recv) noexcept override {
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
if (idx != idx_) return;
recv->Handle(0, std::move(v), shared_from_this());
caller->Handle(0, std::move(v), shared_from_this());
}
private:
size_t idx_;
};
return std::make_unique<Emitter>(InputOrOutput::owner().input(mem_.data()), owner);
} catch (Exception&) {
return nullptr;
}
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override {
// returning nullptr is allowed because it's guaranteed that
// parent is Node/Network, which can handle nullptr safely
return nullptr;
return std::make_unique<Emitter>(*this, parent, owner().input(mem_.data()));
}
void UpdateNode(Editor&) noexcept override {
@ -876,12 +878,13 @@ class Network::Input final : public Network::InputOrOutput,
// An implementation of ChildNode that passes an input to a caller of Node/Network's lambda.
class Network::Output final : public Network::InputOrOutput,
public nf7::Node {
public nf7::Node, public Network::InternalNode {
public:
static inline const GenericTypeInfo<Output> kType = {"Node/Network/Output", {}};
Output(Env& env, std::string_view name) noexcept :
InputOrOutput(kType, env, name, Socket::kOutput) {
InputOrOutput(kType, env, name, Socket::kOutput),
InternalNode(InternalNode::kOutputEmitter) {
input_ = {"in"};
}
@ -896,27 +899,26 @@ class Network::Output final : public Network::InputOrOutput,
}
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override
const std::shared_ptr<nf7::Lambda>& parent) noexcept override
try {
class Emitter final : public nf7::Lambda {
class Emitter final : public nf7::Lambda,
public std::enable_shared_from_this<Emitter> {
public:
Emitter(size_t idx, const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept :
Lambda(owner), idx_(idx) {
Emitter(Output& f, const std::shared_ptr<Network::Lambda>& parent, size_t idx) noexcept :
Lambda(f, parent), idx_(idx) {
assert(parent);
}
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
if (idx != 0) return;
auto exec = std::dynamic_pointer_cast<Network::Lambda>(caller);
assert(exec);
auto outer = exec->outer();
assert(outer);
outer->Handle(idx, std::move(v), exec);
caller->Handle(idx_, std::move(v), shared_from_this());
}
private:
size_t idx_;
};
return std::make_unique<Emitter>(InputOrOutput::owner().output(mem_.data()), owner);
return std::make_shared<Emitter>(
*this,
std::dynamic_pointer_cast<Network::Lambda>(parent),
owner().output(mem_.data()));
} catch (Exception&) {
return nullptr;
}
@ -985,8 +987,8 @@ try {
return nullptr;
}
std::shared_ptr<nf7::Lambda> Network::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
auto ret = std::make_shared<Network::Lambda>(*this, owner);
const std::shared_ptr<nf7::Lambda>& parent) noexcept {
auto ret = std::make_shared<Network::Lambda>(*this, parent);
lambdas_running_.emplace_back(ret);
return ret;
}
@ -1324,7 +1326,7 @@ void Network::Update() noexcept {
// ---- editor window / toolbar / attached lambda combo
const auto current_lambda =
!lambda_? "(unselected)"s:
!lambda_->owner()? "(isolated)"s:
lambda_->isRoot()? "(isolated)"s:
std::to_string(reinterpret_cast<uintptr_t>(lambda_.get()));
if (ImGui::BeginCombo("##lambda", current_lambda.c_str())) {
if (lambda_) {
@ -1346,9 +1348,12 @@ void Network::Update() noexcept {
ImGui::BeginTooltip();
ImGui::TextUnformatted("call stack:");
ImGui::Indent();
for (auto owner = ptr->owner(); owner; owner = owner->parent()) {
ImGui::TextUnformatted(owner->path().Stringify().c_str());
ImGui::TextDisabled("%s", owner->desc().c_str());
for (auto p = ptr->parent().lock(); p; p = p->parent().lock()) {
auto f = env().GetFile(p->initiator());
const auto path = f? f->abspath().Stringify(): "[missing file]";
ImGui::TextUnformatted(path.c_str());
ImGui::TextDisabled("%s", p->GetDescription().c_str());
}
ImGui::Unindent();
ImGui::EndTooltip();

View File

@ -60,7 +60,7 @@ class Ref final : public nf7::File, public nf7::Node {
std::vector<std::string>{input_}, std::vector<std::string>{output_});
}
std::shared_ptr<nf7::Lambda> CreateLambda(const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(const std::shared_ptr<nf7::Lambda>&) noexcept override;
void Handle(const Event& ev) noexcept {
const auto& d = mem_.data();
@ -155,10 +155,8 @@ class Ref final : public nf7::File, public nf7::Node {
class Ref::Lambda final : public nf7::Lambda,
public std::enable_shared_from_this<Ref::Lambda> {
public:
Lambda(Ref& f,
std::shared_ptr<nf7::Lambda>&& base,
const std::shared_ptr<nf7::Lambda::Owner>& owner) :
nf7::Lambda(owner), base_(std::move(base)), log_(f.log_) {
Lambda(Ref& f, const std::shared_ptr<nf7::Lambda>& parent) :
nf7::Lambda(f, parent), ref_(&f), log_(f.log_) {
auto& n = f.target();
// ref input index -> target input index
@ -184,12 +182,18 @@ class Ref::Lambda final : public nf7::Lambda,
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override
try {
auto parent = parent_.lock();
if (parent && caller == base_) {
if (!env().GetFile(initiator())) return;
auto parent = this->parent().lock();
if (!parent) return;
if (caller == base_) {
parent->Handle(GetIndex(outmap_, idx), std::move(v), shared_from_this());
} else {
assert(!parent || parent == caller);
parent_ = caller;
}
if (caller == parent) {
if (!base_) {
base_ = ref_->target().CreateLambda(shared_from_this());
}
base_->Handle(GetIndex(inmap_, idx), std::move(v), shared_from_this());
}
} catch (nf7::Exception&) {
@ -197,10 +201,10 @@ class Ref::Lambda final : public nf7::Lambda,
}
private:
std::shared_ptr<nf7::Lambda> base_;
Ref* const ref_;
std::shared_ptr<nf7::LoggerRef> log_;
std::weak_ptr<nf7::Lambda> parent_;
std::shared_ptr<nf7::Lambda> base_;
std::vector<std::optional<size_t>> inmap_, outmap_;
@ -214,11 +218,9 @@ class Ref::Lambda final : public nf7::Lambda,
};
std::shared_ptr<nf7::Lambda> Ref::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept
const std::shared_ptr<nf7::Lambda>& parent) noexcept
try {
auto self = std::make_shared<nf7::Lambda::Owner>(
abspath(), "call through reference", owner);
return std::make_shared<Ref::Lambda>(*this, target().CreateLambda(self), owner);
return std::make_shared<Ref::Lambda>(*this, parent);
} catch (nf7::Exception& e) {
log_->Error("failed to create lambda: "+e.msg());
return nullptr;