implement lambda call stack

This commit is contained in:
falsycat 2022-07-20 18:25:24 +09:00
parent 3ad18e3f0e
commit b443e71b46
7 changed files with 128 additions and 60 deletions

View File

@ -2,6 +2,8 @@
#include <memory>
#include "nf7.hh"
#include "common/value.hh"
@ -9,7 +11,11 @@ namespace nf7 {
class Lambda {
public:
Lambda() = default;
class Owner;
Lambda() = delete;
Lambda(const std::shared_ptr<Owner>& owner) noexcept : owner_(owner) {
}
virtual ~Lambda() = default;
Lambda(const Lambda&) = delete;
Lambda(Lambda&&) = delete;
@ -17,6 +23,42 @@ class Lambda {
Lambda& operator=(Lambda&&) = delete;
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_; }
private:
nf7::File::Path path_;
std::string desc_;
size_t depth_;
std::shared_ptr<Owner> parent_;
};
} // namespace nf7

View File

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

View File

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

View File

@ -79,7 +79,8 @@ class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
std::vector<std::string>(input_), std::vector<std::string>(output_));
}
std::shared_ptr<nf7::Lambda> CreateLambda() noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
void Handle(const Event&) noexcept override;
void Update() noexcept override;
@ -177,10 +178,10 @@ class Node::FetchTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>
class Node::Lambda final : public nf7::Context, public nf7::Lambda,
public std::enable_shared_from_this<Node::Lambda> {
public:
Lambda(Node& owner) noexcept :
Context(owner),
owner_(&owner), owner_id_(owner.id()),
log_(owner.log_), handler_(owner.FetchHandler()) {
Lambda(Node& f, const std::shared_ptr<Owner>& owner) noexcept :
Context(f), nf7::Lambda(owner),
owner_(&f), owner_id_(f.id()),
log_(f.log_), handler_(f.FetchHandler()) {
}
void Handle(size_t idx, nf7::Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
@ -259,7 +260,7 @@ class Node::Lambda final : public nf7::Context, public nf7::Lambda,
}
void PushCaller(lua_State* L, const std::shared_ptr<nf7::Lambda>& caller) noexcept {
constexpr auto kTypeName = "nf7::File/LuaJIT/Node::Caller";
constexpr auto kTypeName = "nf7::File/LuaJIT/Node::Owner";
struct D final {
std::weak_ptr<nf7::Lambda> self;
std::shared_ptr<nf7::Lambda> caller;
@ -291,8 +292,9 @@ class Node::Lambda final : public nf7::Context, public nf7::Lambda,
};
std::shared_ptr<nf7::Lambda> Node::CreateLambda() noexcept {
return std::make_shared<Node::Lambda>(*this);
std::shared_ptr<nf7::Lambda> Node::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
return std::make_shared<Node::Lambda>(*this, owner);
}
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Node::FetchHandler() noexcept {
if (handler_) return handler_;

View File

@ -68,7 +68,8 @@ class Imm final : public nf7::File, public nf7::DirItem, public nf7::Node {
return std::make_unique<Imm>(env, data.type, nf7::Value{data.value});
}
std::shared_ptr<nf7::Lambda> CreateLambda() noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
void UpdateNode(Node::Editor&) noexcept override;
@ -110,7 +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& owner) noexcept : value_(owner.mem_.data().value) {
Lambda(Imm& f, const std::shared_ptr<Owner>& owner) noexcept :
nf7::Lambda(owner), value_(f.mem_.data().value) {
}
void Handle(size_t, nf7::Value&&, const std::shared_ptr<nf7::Lambda>& recv) noexcept override {
@ -120,8 +122,9 @@ class Imm::Lambda final : public nf7::Lambda,
private:
nf7::Value value_;
};
std::shared_ptr<nf7::Lambda> Imm::CreateLambda() noexcept {
return std::make_shared<Imm::Lambda>(*this);
std::shared_ptr<nf7::Lambda> Imm::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
return std::make_shared<Imm::Lambda>(*this, owner);
}

View File

@ -115,7 +115,8 @@ class Network final : public nf7::File,
void UpdateNode(Node::Editor&) noexcept override;
void Handle(const Event& ev) noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda() noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
File::Interface* interface(const std::type_info& t) noexcept override {
return InterfaceSelector<nf7::DirItem, nf7::Node>(t).Select(this);
@ -186,7 +187,8 @@ class Network final : public nf7::File,
class Network::InternalNode : public nf7::File::Interface {
public:
virtual std::shared_ptr<nf7::Lambda> CreateInitiator() noexcept = 0;
virtual std::shared_ptr<nf7::Lambda> CreateInitiator(
const std::shared_ptr<nf7::Lambda::Owner>&) noexcept = 0;
};
class Network::ChildNode : public nf7::File {
@ -310,18 +312,20 @@ class Network::Item::Watcher final : public nf7::Env::Watcher {
class Network::Lambda : public nf7::Context, public nf7::Lambda,
public std::enable_shared_from_this<Lambda> {
public:
Lambda(Network& owner, bool root = false) noexcept :
Context(owner), root_(root) {
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(owner.items_.size());
for (const auto& item : owner.items_) {
conns_.reserve(f.items_.size());
for (const auto& item : f.items_) {
if (auto inode = item->inode()) {
if (auto lambda = inode->CreateInitiator()) {
if (auto lambda = inode->CreateInitiator(self)) {
initiators_.push_back(std::move(lambda));
}
}
if (auto lambda = item->node().CreateLambda()) {
if (auto lambda = item->node().CreateLambda(self)) {
conns_[lambda.get()] = {};
nmap_[&item->node()] = lambda;
idmap[item->id()] = lambda;
@ -329,14 +333,14 @@ class Network::Lambda : public nf7::Context, public nf7::Lambda,
}
// build connection map
for (const auto& lk : owner.links_.items()) {
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 = owner.GetItem(lk.src_id).node().output(lk.src_name);
const auto dst_index = owner.GetItem(lk.dst_id).node().input(lk.dst_name);
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&) {
}
@ -350,7 +354,7 @@ class Network::Lambda : public nf7::Context, public nf7::Lambda,
auto task = [this, self = shared_from_this(), idx, v = std::move(v), caller]() {
if(abort_) return;
if (!root_ && outer_ == nullptr) {
if (owner() && outer_ == nullptr) {
outer_ = caller;
}
@ -401,8 +405,6 @@ class Network::Lambda : public nf7::Context, public nf7::Lambda,
size_t dst_idx;
};
bool root_;
std::shared_ptr<nf7::Lambda> outer_;
std::atomic<bool> abort_ = false;
@ -418,7 +420,7 @@ class Network::Editor final : public nf7::Node::Editor {
void Emit(Node& node, size_t idx, nf7::Value&& v) noexcept override {
if (!owner_->exec_) {
owner_->exec_ = std::make_shared<Network::Lambda>(*owner_, true);
owner_->exec_ = std::make_shared<Network::Lambda>(*owner_);
}
const auto& exec = owner_->exec_;
@ -660,12 +662,13 @@ class Network::Initiator final : public Network::ChildNode,
return std::make_unique<Initiator>(env, enable_auto_);
}
std::shared_ptr<nf7::Lambda> CreateInitiator() noexcept override {
std::shared_ptr<nf7::Lambda> CreateInitiator(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override {
if (!enable_auto_) return nullptr;
class Emitter final : public nf7::Lambda,
public std::enable_shared_from_this<Emitter> {
public:
Emitter() = default;
using Lambda::Lambda;
void Handle(size_t, Value&&, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
if (!std::exchange(done_, true)) {
caller->Handle(0, nf7::Value::Pulse {}, shared_from_this());
@ -674,18 +677,21 @@ class Network::Initiator final : public Network::ChildNode,
private:
bool done_ = false;
};
return std::make_shared<Emitter>();
return std::make_shared<Emitter>(owner);
}
std::shared_ptr<nf7::Lambda> CreateLambda() noexcept override {
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() = default;
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>();
return std::make_shared<Emitter>(owner);
}
void UpdateNode(Editor& ed) noexcept override {
@ -795,12 +801,14 @@ class Network::Input final : public Network::InputOrOutput,
return std::make_unique<Input>(env, mem_.data());
}
std::shared_ptr<nf7::Lambda> CreateInitiator() noexcept override
std::shared_ptr<nf7::Lambda> CreateInitiator(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override
try {
class Emitter final : public nf7::Lambda,
public std::enable_shared_from_this<Emitter> {
public:
Emitter(size_t idx) noexcept : idx_(idx) {
Emitter(size_t idx, const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept :
Lambda(owner), idx_(idx) {
}
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& recv) noexcept override {
if (idx != idx_) return;
@ -809,11 +817,12 @@ class Network::Input final : public Network::InputOrOutput,
private:
size_t idx_;
};
return std::make_unique<Emitter>(owner().input(mem_.data()));
return std::make_unique<Emitter>(InputOrOutput::owner().input(mem_.data()), owner);
} catch (Exception&) {
return nullptr;
}
std::shared_ptr<nf7::Lambda> CreateLambda() noexcept override {
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;
@ -855,11 +864,13 @@ class Network::Output final : public Network::InputOrOutput,
return std::make_unique<Output>(env, mem_.data());
}
std::shared_ptr<nf7::Lambda> CreateLambda() noexcept override
std::shared_ptr<nf7::Lambda> CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept override
try {
class Emitter final : public nf7::Lambda {
public:
Emitter(size_t idx) noexcept : idx_(idx) {
Emitter(size_t idx, const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept :
Lambda(owner), idx_(idx) {
}
void Handle(size_t idx, Value&& v, const std::shared_ptr<nf7::Lambda>& caller) noexcept override {
if (idx != 0) return;
@ -874,7 +885,7 @@ class Network::Output final : public Network::InputOrOutput,
private:
size_t idx_;
};
return std::make_unique<Emitter>(owner().output(mem_.data()));
return std::make_unique<Emitter>(InputOrOutput::owner().output(mem_.data()), owner);
} catch (Exception&) {
return nullptr;
}
@ -945,8 +956,9 @@ try {
} catch (Exception&) {
return nullptr;
}
std::shared_ptr<nf7::Lambda> Network::CreateLambda() noexcept {
return std::make_shared<Network::Lambda>(*this);
std::shared_ptr<nf7::Lambda> Network::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept {
return std::make_shared<Network::Lambda>(*this, owner);
}
void Network::Handle(const Event& ev) noexcept {
switch (ev.type) {

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() noexcept override;
std::shared_ptr<nf7::Lambda> CreateLambda(const std::shared_ptr<nf7::Lambda::Owner>&) noexcept override;
void Handle(const Event& ev) noexcept {
const auto& d = mem_.data();
@ -155,13 +155,15 @@ 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& owner, std::shared_ptr<nf7::Lambda>&& base) :
base_(std::move(base)), log_(owner.log_) {
auto& n = owner.target();
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_) {
auto& n = f.target();
// ref input index -> target input index
inmap_.reserve(owner.input_.size());
for (const auto& name : owner.input()) {
inmap_.reserve(f.input_.size());
for (const auto& name : f.input()) {
try {
inmap_.push_back(n.input(name));
} catch (nf7::Exception&){
@ -170,10 +172,10 @@ class Ref::Lambda final : public nf7::Lambda,
}
// target output index -> ref output index
outmap_.reserve(owner.output_.size());
outmap_.reserve(f.output_.size());
for (const auto& name : n.output()) {
try {
outmap_.push_back(owner.output(name));
outmap_.push_back(f.output(name));
} catch (nf7::Exception&){
outmap_.push_back(std::nullopt);
}
@ -211,9 +213,12 @@ class Ref::Lambda final : public nf7::Lambda,
}
};
std::shared_ptr<nf7::Lambda> Ref::CreateLambda() noexcept
std::shared_ptr<nf7::Lambda> Ref::CreateLambda(
const std::shared_ptr<nf7::Lambda::Owner>& owner) noexcept
try {
return std::make_shared<Ref::Lambda>(*this, target().CreateLambda());
auto self = std::make_shared<nf7::Lambda::Owner>(
abspath(), "call through reference", owner);
return std::make_shared<Ref::Lambda>(*this, target().CreateLambda(self), owner);
} catch (nf7::Exception& e) {
log_->Error("failed to create lambda: "+e.msg());
return nullptr;