Add bt node result interception & re-throw node

This commit is contained in:
Nikita Lisitsa 2022-11-18 12:18:05 +03:00
parent a1a1dbd56e
commit 0a42a015eb
2 changed files with 150 additions and 0 deletions

View file

@ -0,0 +1,25 @@
#pragma once
#include <psemek/bt/node.hpp>
#include <psemek/bt/sequence.hpp>
#include <psemek/bt/success.hpp>
#include <psemek/bt/trampoline.hpp>
namespace psemek::bt
{
template <typename Tree>
node_ptr<Tree> finally(node_ptr<Tree> child, node_ptr<Tree> finalizator)
{
trampoline<Tree> t;
return
t.rethrow(
bt::sequence(
bt::success(t.intercept(std::move(child))),
std::move(finalizator)
)
);
}
}

View file

@ -0,0 +1,125 @@
#pragma once
#include <psemek/bt/node.hpp>
#include <optional>
namespace psemek::bt
{
namespace detail
{
template <typename Tree>
struct trampoline_state
{
std::optional<typename bt::node<Tree>::status> cached_status;
};
}
template <typename Tree>
struct trampoline_intercept_node;
template <typename Tree>
struct trampoline_rethrow_node;
template <typename Time, typename Event, typename ... Args>
struct trampoline_intercept_node<tree<Time, Event, Args...>>
: node<tree<Time, Event, Args...>>
{
using tree_type = tree<Time, Event, Args...>;
using node_type = node<tree_type>;
using typename node_type::finished;
using typename node_type::status;
trampoline_intercept_node(node_ptr<tree_type> child, std::shared_ptr<detail::trampoline_state<tree<Time, Event, Args...>>> state)
: child_(std::move(child))
, state_(std::move(state))
{}
void start(Args ... args) override
{
child_->start(args...);
}
status update(Time dt, Args ... args) override
{
auto result = child_->update(dt, args...);
if (auto f = std::get_if<finished>(&result))
state_->cached_status = *f;
return result;
}
bool event(Event const & event, Args ... args) override
{
return child_->event(event, args...);
}
private:
node_ptr<tree<Time, Event, Args...>> child_;
std::shared_ptr<detail::trampoline_state<tree<Time, Event, Args...>>> state_;
};
template <typename Time, typename Event, typename ... Args>
struct trampoline_rethrow_node<tree<Time, Event, Args...>>
: node<tree<Time, Event, Args...>>
{
using tree_type = tree<Time, Event, Args...>;
using node_type = node<tree_type>;
using typename node_type::finished;
using typename node_type::status;
trampoline_rethrow_node(node_ptr<tree_type> child, std::shared_ptr<detail::trampoline_state<tree<Time, Event, Args...>>> state)
: child_(std::move(child))
, state_(std::move(state))
{}
void start(Args ... args) override
{
child_->start(args...);
}
status update(Time dt, Args ... args) override
{
auto result = child_->update(dt, args...);
if (std::get_if<finished>(&result) && state_->cached_status)
{
result = *state_->cached_status;
state_->cached_status = std::nullopt;
}
return result;
}
bool event(Event const & event, Args ... args) override
{
return child_->event(event, args...);
}
private:
node_ptr<tree<Time, Event, Args...>> child_;
std::shared_ptr<detail::trampoline_state<tree<Time, Event, Args...>>> state_;
};
template <typename Tree>
struct trampoline
{
trampoline()
: state_(std::make_shared<detail::trampoline_state<Tree>>())
{}
node_ptr<Tree> intercept(node_ptr<Tree> child)
{
return std::make_unique<trampoline_intercept_node<Tree>>(std::move(child), state_);
}
node_ptr<Tree> rethrow(node_ptr<Tree> child)
{
return std::make_unique<trampoline_rethrow_node<Tree>>(std::move(child), state_);
}
private:
std::shared_ptr<detail::trampoline_state<Tree>> state_;
};
}