Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exposed port<> name, priority, [min,max]_samples as public fields #108

Merged
merged 1 commit into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 2 additions & 219 deletions include/graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,223 +32,6 @@ namespace fair::graph {

using namespace fair::literals;

/**
* Runtime capable wrapper to be used within a block. It's primary purpose is to allow the runtime
* initialisation/connections between blocks that are not in the same compilation unit.
* Ownership is defined by if the strongly-typed port P is either passed
* a) as an lvalue (i.e. P& -> keep reference), or
* b) as an rvalue (P&& -> being moved into dyn_port).
*
* N.B. the intended use is within the node/block interface where there is -- once initialised --
* always a strong-reference between the strongly-typed port and it's dyn_port wrapper. I.e no ports
* are added or removed after the initialisation and the port life-time is coupled to that of it's
* parent block/node.
*/
class dynamic_port {
struct model { // intentionally class-private definition to limit interface exposure and enhance composition
virtual ~model() = default;

[[nodiscard]] virtual supported_type
pmt_type() const noexcept
= 0;

[[nodiscard]] virtual port_type_t
type() const noexcept
= 0;

[[nodiscard]] virtual port_direction_t
direction() const noexcept
= 0;

[[nodiscard]] virtual std::string_view
name() const noexcept
= 0;

[[nodiscard]] virtual connection_result_t
resize_buffer(std::size_t min_size) noexcept
= 0;

[[nodiscard]] virtual connection_result_t
disconnect() noexcept
= 0;

[[nodiscard]] virtual connection_result_t
connect(dynamic_port &dst_port)
= 0;

// internal runtime polymorphism access
[[nodiscard]] virtual bool
update_reader_internal(internal_port_buffers buffer_other) noexcept
= 0;
};

std::unique_ptr<model> _accessor;

template<Port T, bool owning>
class wrapper final : public model {
using PortType = std::decay_t<T>;
std::conditional_t<owning, PortType, PortType &> _value;

[[nodiscard]] internal_port_buffers
writer_handler_internal() noexcept {
return _value.writer_handler_internal();
};

[[nodiscard]] bool
update_reader_internal(internal_port_buffers buffer_other) noexcept override {
if constexpr (T::IS_INPUT) {
return _value.update_reader_internal(buffer_other);
} else {
assert(false && "This works only on input ports");
return false;
}
}

public:
wrapper() = delete;

wrapper(const wrapper &) = delete;

auto &
operator=(const wrapper &)
= delete;

auto &
operator=(wrapper &&)
= delete;

explicit constexpr wrapper(T &arg) noexcept : _value{ arg } {
if constexpr (T::IS_INPUT) {
static_assert(
requires { arg.writer_handler_internal(); }, "'private void* writer_handler_internal()' not implemented");
} else {
static_assert(
requires { arg.update_reader_internal(std::declval<internal_port_buffers>()); }, "'private bool update_reader_internal(void* buffer)' not implemented");
}
}

explicit constexpr wrapper(T &&arg) noexcept : _value{ std::move(arg) } {
if constexpr (T::IS_INPUT) {
static_assert(
requires { arg.writer_handler_internal(); }, "'private void* writer_handler_internal()' not implemented");
} else {
static_assert(
requires { arg.update_reader_internal(std::declval<internal_port_buffers>()); }, "'private bool update_reader_internal(void* buffer)' not implemented");
}
}

~wrapper() override = default;

[[nodiscard]] constexpr supported_type
pmt_type() const noexcept override {
return _value.pmt_type();
}

[[nodiscard]] constexpr port_type_t
type() const noexcept override {
return _value.type();
}

[[nodiscard]] constexpr port_direction_t
direction() const noexcept override {
return _value.direction();
}

[[nodiscard]] constexpr std::string_view
name() const noexcept override {
return _value.name();
}

[[nodiscard]] connection_result_t
resize_buffer(std::size_t min_size) noexcept override {
return _value.resize_buffer(min_size);
}

[[nodiscard]] connection_result_t
disconnect() noexcept override {
return _value.disconnect();
}

[[nodiscard]] connection_result_t
connect(dynamic_port &dst_port) override {
if constexpr (T::IS_OUTPUT) {
auto src_buffer = _value.writer_handler_internal();
return dst_port.update_reader_internal(src_buffer) ? connection_result_t::SUCCESS : connection_result_t::FAILED;
} else {
assert(false && "This works only on input ports");
return connection_result_t::FAILED;
}
}
};

bool
update_reader_internal(internal_port_buffers buffer_other) noexcept {
return _accessor->update_reader_internal(buffer_other);
}

public:
using value_type = void; // a sterile port

constexpr dynamic_port() = delete;

dynamic_port(const dynamic_port &arg) = delete;
dynamic_port &
operator=(const dynamic_port &arg)
= delete;

dynamic_port(dynamic_port &&arg) = default;
dynamic_port &
operator=(dynamic_port &&arg)
= default;

// TODO: Make owning versus non-owning API more explicit
template<Port T>
explicit constexpr dynamic_port(T &arg) noexcept : _accessor{ std::make_unique<wrapper<T, false>>(arg) } {}

template<Port T>
explicit constexpr dynamic_port(T &&arg) noexcept : _accessor{ std::make_unique<wrapper<T, true>>(std::forward<T>(arg)) } {}

[[nodiscard]] supported_type
pmt_type() const noexcept {
return _accessor->pmt_type();
}

[[nodiscard]] port_type_t
type() const noexcept {
return _accessor->type();
}

[[nodiscard]] port_direction_t
direction() const noexcept {
return _accessor->direction();
}

[[nodiscard]] std::string_view
name() const noexcept {
return _accessor->name();
}

[[nodiscard]] connection_result_t
resize_buffer(std::size_t min_size) {
if (direction() == port_direction_t::OUTPUT) {
return _accessor->resize_buffer(min_size);
}
return connection_result_t::FAILED;
}

[[nodiscard]] connection_result_t
disconnect() noexcept {
return _accessor->disconnect();
}

[[nodiscard]] connection_result_t
connect(dynamic_port &dst_port) {
return _accessor->connect(dst_port);
}
};

static_assert(Port<dynamic_port>);

#define ENABLE_PYTHON_INTEGRATION
#ifdef ENABLE_PYTHON_INTEGRATION

Expand Down Expand Up @@ -297,7 +80,7 @@ class dynamic_node {

[[nodiscard]] std::optional<std::size_t>
dynamic_input_port_index(std::string_view name) const {
auto portNameMatches = [name](const auto &port) { return port.name() == name; };
auto portNameMatches = [name](const auto &port) { return port.name == name; };
const auto it = std::find_if(_dynamic_input_ports.cbegin(), _dynamic_input_ports.cend(), portNameMatches);
return it != _dynamic_input_ports.cend() ? std::optional{ std::distance(_dynamic_input_ports.cbegin(), it) } : std::nullopt;
}
Expand All @@ -317,7 +100,7 @@ class dynamic_node {

[[nodiscard]] std::optional<std::size_t>
dynamic_output_port_index(std::string_view name) const {
auto portNameMatches = [name](const auto &port) { return port.name() == name; };
auto portNameMatches = [name](const auto &port) { return port.name == name; };
const auto it = std::find_if(_dynamic_output_ports.cbegin(), _dynamic_output_ports.cend(), portNameMatches);
return it != _dynamic_output_ports.cend() ? std::optional{ std::distance(_dynamic_output_ports.cbegin(), it) } : std::nullopt;
}
Expand Down
Loading