2 #include <ossia/dataflow/fx_node.hpp>
3 #include <ossia/dataflow/graph_node.hpp>
4 #include <ossia/dataflow/node_process.hpp>
5 #include <ossia/dataflow/port.hpp>
6 #include <ossia/dataflow/safe_nodes/node.hpp>
7 #include <ossia/dataflow/safe_nodes/tick_policies.hpp>
9 #include <ossia/detail/apply_type.hpp>
10 #include <ossia/detail/for_each_in_tuple.hpp>
11 #include <ossia/detail/lockfree_queue.hpp>
18 template <
typename T, std::
size_t N>
22 constexpr T& operator[](std::size_t i) noexcept {
return arr[i]; }
23 constexpr
const T& operator[](std::size_t i)
const noexcept {
return arr[i]; }
26 struct ebo_array<T, 0>
31 template <
typename T, std::
size_t N>
32 constexpr
const T* begin(
const ebo_array<T, N>& e)
36 template <
typename T, std::
size_t N>
37 constexpr
const T* end(
const ebo_array<T, N>& e)
41 template <
typename T, std::
size_t N>
42 constexpr T* begin(ebo_array<T, N>& e)
46 template <
typename T, std::
size_t N>
47 constexpr T* end(ebo_array<T, N>& e)
52 namespace ossia::safe_nodes
55 template <
typename T,
typename =
void>
56 struct has_event_policy : std::false_type
60 struct has_event_policy<T, std::void_t<typename T::event_policy>> : std::true_type
64 template <
typename T,
typename =
void>
65 struct has_audio_policy : std::false_type
69 struct has_audio_policy<T, std::void_t<typename T::audio_policy>> : std::true_type
73 template <
typename T,
typename =
void>
74 struct has_control_policy : std::false_type
78 struct has_control_policy<T, std::void_t<typename T::control_policy>> : std::true_type
82 template <
typename info, std::
size_t N>
83 static constexpr
auto& get_inlet_accessor(
const ossia::inlets& inl) noexcept
85 constexpr
auto cat = info::categorize_inlet(N);
86 if constexpr(cat == ossia::safe_nodes::inlet_kind::audio_in)
87 return *inl[N]->target<ossia::audio_port>();
88 else if constexpr(cat == ossia::safe_nodes::inlet_kind::midi_in)
89 return *inl[N]->target<ossia::midi_port>();
90 else if constexpr(cat == ossia::safe_nodes::inlet_kind::value_in)
91 return *inl[N]->target<ossia::value_port>();
92 else if constexpr(cat == ossia::safe_nodes::inlet_kind::address_in)
93 return inl[N]->address;
98 template <
typename info, std::
size_t N>
99 static constexpr
auto& get_outlet_accessor(
const ossia::outlets& outl) noexcept
101 constexpr
auto cat = info::categorize_outlet(N);
102 if constexpr(cat == ossia::safe_nodes::outlet_kind::audio_out)
103 return *outl[N]->target<ossia::audio_port>();
104 else if constexpr(cat == ossia::safe_nodes::outlet_kind::midi_out)
105 return *outl[N]->target<ossia::midi_port>();
106 else if constexpr(cat == ossia::safe_nodes::outlet_kind::value_out)
107 return *outl[N]->target<ossia::value_port>();
112 template <
typename Node_T>
113 class safe_node final
114 :
public ossia::nonowning_graph_node
115 ,
public get_state<Node_T>::type
118 using info = info_functions<Node_T>;
119 static const constexpr
bool has_state = has_state_t<Node_T>::value;
120 using state_type =
typename get_state<Node_T>::type;
122 using controls_changed_list = std::bitset<info_functions<Node_T>::control_count>;
123 using controls_type =
typename info_functions<Node_T>::controls_type;
124 using controls_values_type =
typename info_functions<Node_T>::controls_values_type;
125 using control_tuple_t =
126 typename ossia::apply_type<controls_values_type, timed_vec>::type;
129 controls_values_type controls;
132 controls_changed_list controls_changed;
135 ossia::spsc_queue<controls_values_type> cqueue;
138 control_tuple_t control_tuple;
140 using control_outs_changed_list
141 = std::bitset<info_functions<Node_T>::control_out_count>;
142 using control_outs_type =
typename info_functions<Node_T>::control_outs_type;
143 using control_outs_values_type =
144 typename info_functions<Node_T>::control_outs_values_type;
145 using control_out_tuple_t =
146 typename ossia::apply_type<control_outs_values_type, timed_vec>::type;
148 control_outs_values_type control_outs;
149 control_outs_changed_list control_outs_changed;
150 ossia::spsc_queue<control_outs_values_type> control_outs_queue;
151 control_out_tuple_t control_outs_tuple;
153 ebo_array<ossia::audio_inlet, info::audio_in_count> audio_in_ports;
154 ebo_array<ossia::midi_inlet, info::midi_in_count> midi_in_ports;
155 ebo_array<ossia::value_inlet, info::value_in_count> value_in_ports;
156 ebo_array<ossia::value_inlet, info::address_in_count> address_in_ports;
157 ebo_array<ossia::value_inlet, info::control_count> control_in_ports;
159 ebo_array<ossia::audio_outlet, info::audio_out_count> audio_out_ports;
160 ebo_array<ossia::midi_outlet, info::midi_out_count> midi_out_ports;
161 ebo_array<ossia::value_outlet, info::value_out_count> value_out_ports;
162 ebo_array<ossia::value_outlet, info::control_out_count> control_out_ports;
166 m_inlets.reserve(info_functions<Node_T>::inlet_size);
167 m_outlets.reserve(info_functions<Node_T>::outlet_size);
168 if constexpr(info::audio_in_count > 0)
169 for(auto& port : this->audio_in_ports)
170 m_inlets.push_back(std::addressof(port));
172 if constexpr(info::midi_in_count > 0)
173 for(auto& port : this->midi_in_ports)
174 m_inlets.push_back(std::addressof(port));
176 if constexpr(info::value_in_count > 0)
177 for(std::
size_t i = 0; i < info::value_in_count; i++)
179 (*value_in_ports[i]).is_event = Node_T::Metadata::value_ins[i].is_event;
180 m_inlets.push_back(std::addressof(value_in_ports[i]));
183 if constexpr(info::address_in_count > 0)
184 for(auto& port : this->address_in_ports)
185 m_inlets.push_back(std::addressof(port));
187 if constexpr(info::control_count > 0)
189 for(
auto& port : this->control_in_ports)
191 (*port).is_event =
true;
192 m_inlets.push_back(std::addressof(port));
197 for_each_in_tuple(Node_T::Metadata::controls, [&](
auto& ctrl_info) {
198 ctrl_info.setup_exec(this->control_in_ports[ctrl_i]);
204 if constexpr(info::audio_out_count > 0)
205 for(auto& port : this->audio_out_ports)
206 m_outlets.push_back(std::addressof(port));
208 if constexpr(info::midi_out_count > 0)
209 for(auto& port : this->midi_out_ports)
210 m_outlets.push_back(std::addressof(port));
212 if constexpr(info::value_out_count > 0)
213 for(std::
size_t i = 0; i < info::value_out_count; i++)
215 auto& port = value_out_ports[i];
216 if(
auto& type = Node_T::Metadata::value_outs[i].type; !type.empty())
220 m_outlets.push_back(std::addressof(port));
223 if constexpr(info::control_out_count > 0)
224 for(auto& port : this->control_out_ports)
225 m_outlets.push_back(std::addressof(port));
228 template <std::
size_t N>
229 constexpr const auto& get_control_accessor(const
ossia::inlets& inl) noexcept
231 constexpr
const auto idx = info::control_start + N;
232 static_assert(info::control_count > 0);
233 static_assert(N < info::control_count);
236 typename std::tuple_element<N, decltype(Node_T::Metadata::controls)>::type;
237 using val_type =
typename control_type::type;
239 ossia::timed_vec<val_type>& vec = get<N>(this->control_tuple);
242 const auto& vp =
static_cast<ossia::value_inlet*
>(inl[idx])->data.get_data();
243 vec.reserve(vp.size() + 1);
246 vec.insert(std::make_pair(int64_t{0}, get<N>(this->controls)));
249 apply_control<control_type::must_validate, N>(vec, vp);
252 get<N>(this->controls) = vec.rbegin()->second;
256 template <std::
size_t N>
257 constexpr
auto& get_control_outlet_accessor(
const ossia::outlets& outl) noexcept
259 static_assert(info::control_out_count > 0);
260 static_assert(N < info::control_out_count);
262 return get<N>(this->control_outs_tuple);
265 template <
bool Val
idate, std::
size_t N,
typename Vec,
typename Vp>
266 void apply_control(Vec& vec,
const Vp& vp) noexcept
268 constexpr
const auto ctrl = get<N>(Node_T::Metadata::controls);
269 if constexpr(Validate)
273 if(
auto res = ctrl.fromValue(v.value))
275 vec[int64_t{v.timestamp}] = *std::move(res);
276 this->controls_changed.set(N);
284 vec[int64_t{v.timestamp}] = ctrl.fromValue(v.value);
285 this->controls_changed.set(N);
291 template <std::size_t... I, std::size_t... CI, std::size_t... O, std::size_t... CO>
293 const std::index_sequence<I...>&,
const std::index_sequence<CI...>&,
294 const std::index_sequence<O...>&,
const std::index_sequence<CO...>&,
295 ossia::token_request tk, ossia::exec_state_facade st) noexcept
297 ossia::inlets& inlets = this->root_inputs();
298 ossia::outlets& outlets = this->root_outputs();
300 if constexpr(has_state)
302 if constexpr(info::control_count > 0)
304 using policy =
typename Node_T::control_policy;
306 [&](
const ossia::token_request& sub_tk,
auto&&... ctls) {
308 get_inlet_accessor<info, I>(inlets)...,
309 std::forward<decltype(ctls)>(ctls)...,
310 get_outlet_accessor<info, O>(outlets)...,
311 get_control_outlet_accessor<CO>(outlets)..., sub_tk, st,
312 static_cast<state_type&
>(*
this));
314 tk, get_control_accessor<CI>(inlets)...);
319 get_inlet_accessor<info, I>(inlets)...,
320 get_outlet_accessor<info, O>(outlets)...,
321 get_control_outlet_accessor<CO>(outlets)..., tk, st,
322 static_cast<state_type&
>(*
this));
327 if constexpr(info::control_count > 0)
329 using policy =
typename Node_T::control_policy;
331 [&](
const ossia::token_request& sub_tk,
auto&&... ctls) {
333 get_inlet_accessor<info, I>(inlets)...,
334 std::forward<decltype(ctls)>(ctls)...,
335 get_outlet_accessor<info, O>(outlets)...,
336 get_control_outlet_accessor<CO>(outlets)..., sub_tk, st);
338 tk, get_control_accessor<CI>(inlets)...);
343 get_inlet_accessor<info, I>(inlets)...,
344 get_outlet_accessor<info, O>(outlets)...,
345 get_control_outlet_accessor<CO>(outlets)..., tk, st);
350 void run(
const ossia::token_request& tk, ossia::exec_state_facade st) noexcept
override
352 using inlets_indices = std::make_index_sequence<info::control_start>;
353 using controls_indices = std::make_index_sequence<info::control_count>;
354 using outlets_indices = std::make_index_sequence<info::control_out_start>;
355 using control_outs_indices = std::make_index_sequence<info::control_out_count>;
358 inlets_indices{}, controls_indices{}, outlets_indices{}, control_outs_indices{},
361 if constexpr(info::control_count > 0)
363 if(cqueue.size_approx() < 1 && controls_changed.any())
365 cqueue.try_enqueue(controls);
366 controls_changed.reset();
370 if constexpr(info::control_out_count > 0)
374 ossia::for_each_in_tuples_ref(
375 this->control_outs_tuple, this->control_outs,
376 [&](
auto&& current_ctrls,
auto&& control_out) {
377 if(!current_ctrls.empty())
380 control_out = std::move(current_ctrls.tree().get_sequence_cref().back().second);
381 current_ctrls.clear();
389 this->control_outs_queue.enqueue(this->control_outs);
394 void all_notes_off() noexcept
override
396 if constexpr(info::midi_in_count > 0)
402 [[nodiscard]] std::string label() const noexcept
override {
return "Control"; }
405 template <
typename T>
406 struct controls_feedback_type
412 struct controls_feedback_type<std::string>
414 using type = std::string_view;
416 template <
typename T>
417 using controls_feedback_type_t =
typename controls_feedback_type<T>::type;
419 template <
typename Node_T>
420 requires std::is_same_v<typename Node_T::control_policy, ossia::safe_nodes::last_tick>
421 class safe_node<Node_T> final
422 :
public ossia::nonowning_graph_node
423 ,
public get_state<Node_T>::type
426 using info = info_functions<Node_T>;
427 static const constexpr
bool has_state = has_state_t<Node_T>::value;
428 using state_type =
typename get_state<Node_T>::type;
430 using controls_changed_list = std::bitset<info_functions<Node_T>::control_count>;
431 using controls_type =
typename info_functions<Node_T>::controls_type;
432 using controls_values_type =
typename info_functions<Node_T>::controls_values_type;
433 using controls_values_feedback = boost::mp11::mp_transform<
434 controls_feedback_type_t,
typename info_functions<Node_T>::controls_values_type>;
437 controls_values_type controls;
440 controls_changed_list controls_changed;
443 ossia::spsc_queue<controls_values_feedback> cqueue;
445 using control_outs_changed_list
446 = std::bitset<info_functions<Node_T>::control_out_count>;
447 using control_outs_type =
typename info_functions<Node_T>::control_outs_type;
448 using control_outs_values_type =
449 typename info_functions<Node_T>::control_outs_values_type;
451 control_outs_values_type control_outs;
452 control_outs_changed_list control_outs_changed;
453 ossia::spsc_queue<control_outs_values_type> control_outs_queue;
455 ebo_array<ossia::audio_inlet, info::audio_in_count> audio_in_ports;
456 ebo_array<ossia::midi_inlet, info::midi_in_count> midi_in_ports;
457 ebo_array<ossia::value_inlet, info::value_in_count> value_in_ports;
458 ebo_array<ossia::value_inlet, info::address_in_count> address_in_ports;
459 ebo_array<ossia::value_inlet, info::control_count> control_in_ports;
461 ebo_array<ossia::audio_outlet, info::audio_out_count> audio_out_ports;
462 ebo_array<ossia::midi_outlet, info::midi_out_count> midi_out_ports;
463 ebo_array<ossia::value_outlet, info::value_out_count> value_out_ports;
464 ebo_array<ossia::value_outlet, info::control_out_count> control_out_ports;
468 m_inlets.reserve(info_functions<Node_T>::inlet_size);
469 m_outlets.reserve(info_functions<Node_T>::outlet_size);
470 if constexpr(info::audio_in_count > 0)
471 for(auto& port : this->audio_in_ports)
472 m_inlets.push_back(std::addressof(port));
474 if constexpr(info::midi_in_count > 0)
475 for(auto& port : this->midi_in_ports)
476 m_inlets.push_back(std::addressof(port));
478 if constexpr(info::value_in_count > 0)
479 for(std::
size_t i = 0; i < info::value_in_count; i++)
481 (*value_in_ports[i]).is_event = Node_T::Metadata::value_ins[i].is_event;
482 m_inlets.push_back(std::addressof(value_in_ports[i]));
485 if constexpr(info::address_in_count > 0)
486 for(auto& port : this->address_in_ports)
487 m_inlets.push_back(std::addressof(port));
489 if constexpr(info::control_count > 0)
491 for(
auto& port : this->control_in_ports)
493 (*port).is_event =
true;
494 m_inlets.push_back(std::addressof(port));
499 for_each_in_tuple(Node_T::Metadata::controls, [&](
auto& ctrl_info) {
500 ctrl_info.setup_exec(this->control_in_ports[ctrl_i]);
506 if constexpr(info::audio_out_count > 0)
507 for(auto& port : this->audio_out_ports)
508 m_outlets.push_back(std::addressof(port));
510 if constexpr(info::midi_out_count > 0)
511 for(auto& port : this->midi_out_ports)
512 m_outlets.push_back(std::addressof(port));
514 if constexpr(info::value_out_count > 0)
515 for(std::
size_t i = 0; i < info::value_out_count; i++)
517 auto& port = value_out_ports[i];
518 if(
auto& type = Node_T::Metadata::value_outs[i].type; !type.empty())
522 m_outlets.push_back(std::addressof(port));
525 if constexpr(info::control_out_count > 0)
526 for(auto& port : this->control_out_ports)
527 m_outlets.push_back(std::addressof(port));
530 template <std::
size_t N>
531 constexpr const auto& get_control_accessor(const
ossia::inlets& inl) noexcept
533 constexpr
const auto idx = info::control_start + N;
534 static_assert(info::control_count > 0);
535 static_assert(N < info::control_count);
538 typename std::tuple_element<N, decltype(Node_T::Metadata::controls)>::type;
540 const auto& vp =
static_cast<ossia::value_inlet*
>(inl[idx])->data.get_data();
545 apply_control<control_type::must_validate, N>(
546 get<N>(this->controls), vp.back().value);
548 return get<N>(this->controls);
551 template <std::
size_t N>
552 constexpr
auto& get_control_outlet_accessor(
const ossia::outlets& outl) noexcept
554 static_assert(info::control_out_count > 0);
555 static_assert(N < info::control_out_count);
557 return get<N>(this->control_outs_tuple);
560 template <
bool Val
idate, std::
size_t N,
typename Ctl>
561 void apply_control(Ctl& ctl,
const ossia::value& v) noexcept
563 constexpr
const auto ctrl = get<N>(Node_T::Metadata::controls);
564 if constexpr(Validate)
566 if(
auto res = ctrl.fromValue(v))
568 ctl = *std::move(res);
569 this->controls_changed.set(N);
574 ctl = ctrl.fromValue(v);
575 this->controls_changed.set(N);
580 controls_values_feedback controls_feedback(
const controls_values_type& t)
582 return tuplet::apply(
583 []<
typename... Args>(
const Args&... args) {
584 return controls_values_feedback{args...};
589 template <std::size_t... I, std::size_t... CI, std::size_t... O, std::size_t... CO>
591 const std::index_sequence<I...>&,
const std::index_sequence<CI...>&,
592 const std::index_sequence<O...>&,
const std::index_sequence<CO...>&,
593 ossia::token_request tk, ossia::exec_state_facade st) noexcept
595 ossia::inlets& inlets = this->root_inputs();
596 ossia::outlets& outlets = this->root_outputs();
598 if constexpr(has_state)
600 if constexpr(info::control_count > 0)
602 using policy = last_tick_values;
604 [&](
const ossia::token_request& sub_tk,
auto&&... ctls) {
606 get_inlet_accessor<info, I>(inlets)...,
607 std::forward<decltype(ctls)>(ctls)...,
608 get_outlet_accessor<info, O>(outlets)...,
609 get_control_outlet_accessor<CO>(outlets)..., sub_tk, st,
610 static_cast<state_type&
>(*
this));
612 tk, get_control_accessor<CI>(inlets)...);
617 get_inlet_accessor<info, I>(inlets)...,
618 get_outlet_accessor<info, O>(outlets)...,
619 get_control_outlet_accessor<CO>(outlets)..., tk, st,
620 static_cast<state_type&
>(*
this));
625 if constexpr(info::control_count > 0)
627 using policy = last_tick_values;
629 [&](
const ossia::token_request& sub_tk,
auto&&... ctls) {
631 get_inlet_accessor<info, I>(inlets)...,
632 std::forward<decltype(ctls)>(ctls)...,
633 get_outlet_accessor<info, O>(outlets)...,
634 get_control_outlet_accessor<CO>(outlets)..., sub_tk, st);
636 tk, get_control_accessor<CI>(inlets)...);
641 get_inlet_accessor<info, I>(inlets)...,
642 get_outlet_accessor<info, O>(outlets)...,
643 get_control_outlet_accessor<CO>(outlets)..., tk, st);
648 void run(
const ossia::token_request& tk, ossia::exec_state_facade st) noexcept
override
650 using inlets_indices = std::make_index_sequence<info::control_start>;
651 using controls_indices = std::make_index_sequence<info::control_count>;
652 using outlets_indices = std::make_index_sequence<info::control_out_start>;
653 using control_outs_indices = std::make_index_sequence<info::control_out_count>;
656 inlets_indices{}, controls_indices{}, outlets_indices{}, control_outs_indices{},
659 if constexpr(info::control_count > 0)
661 if(cqueue.size_approx() < 1 && controls_changed.any())
663 cqueue.try_enqueue(controls_feedback(controls));
664 controls_changed.reset();
668 if constexpr(info::control_out_count > 0)
672 ossia::for_each_in_tuples_ref(
673 this->control_outs_tuple, this->control_outs,
674 [&](
auto&& current_ctrls,
auto&& control_out) {
675 if(!current_ctrls.empty())
678 control_out = std::move(current_ctrls.container.back().second);
679 current_ctrls.clear();
687 this->control_outs_queue.enqueue(this->control_outs);
692 void all_notes_off() noexcept
override
694 if constexpr(info::midi_in_count > 0)
700 [[nodiscard]] std::string label() const noexcept
override {
return "Control"; }
702 template <
typename Node_T>
703 requires std::is_same_v<
704 typename Node_T::control_policy, ossia::safe_nodes::default_tick>
705 class safe_node<Node_T> final
706 :
public ossia::nonowning_graph_node
707 ,
public get_state<Node_T>::type
710 using info = info_functions<Node_T>;
711 static_assert(info::control_count == 0);
712 static_assert(info::control_out_count == 0);
713 static const constexpr
bool has_state = has_state_t<Node_T>::value;
714 using state_type =
typename get_state<Node_T>::type;
716 ebo_array<ossia::audio_inlet, info::audio_in_count> audio_in_ports;
717 ebo_array<ossia::midi_inlet, info::midi_in_count> midi_in_ports;
718 ebo_array<ossia::value_inlet, info::value_in_count> value_in_ports;
719 ebo_array<ossia::value_inlet, info::address_in_count> address_in_ports;
721 ebo_array<ossia::audio_outlet, info::audio_out_count> audio_out_ports;
722 ebo_array<ossia::midi_outlet, info::midi_out_count> midi_out_ports;
723 ebo_array<ossia::value_outlet, info::value_out_count> value_out_ports;
727 m_inlets.reserve(info_functions<Node_T>::inlet_size);
728 m_outlets.reserve(info_functions<Node_T>::outlet_size);
729 if constexpr(info::audio_in_count > 0)
730 for(auto& port : this->audio_in_ports)
731 m_inlets.push_back(std::addressof(port));
733 if constexpr(info::midi_in_count > 0)
734 for(auto& port : this->midi_in_ports)
735 m_inlets.push_back(std::addressof(port));
737 if constexpr(info::value_in_count > 0)
738 for(std::
size_t i = 0; i < info::value_in_count; i++)
740 (*value_in_ports[i]).is_event = Node_T::Metadata::value_ins[i].is_event;
741 m_inlets.push_back(std::addressof(value_in_ports[i]));
744 if constexpr(info::address_in_count > 0)
745 for(auto& port : this->address_in_ports)
746 m_inlets.push_back(std::addressof(port));
748 if constexpr(info::audio_out_count > 0)
749 for(auto& port : this->audio_out_ports)
750 m_outlets.push_back(std::addressof(port));
752 if constexpr(info::midi_out_count > 0)
753 for(auto& port : this->midi_out_ports)
754 m_outlets.push_back(std::addressof(port));
756 if constexpr(info::value_out_count > 0)
757 for(std::
size_t i = 0; i < info::value_out_count; i++)
759 auto& port = value_out_ports[i];
760 if(
auto& type = Node_T::Metadata::value_outs[i].type; !type.empty())
764 m_outlets.push_back(std::addressof(port));
768 template <std::size_t... I, std::size_t... O>
770 const std::index_sequence<I...>&,
const std::index_sequence<O...>&,
771 ossia::token_request tk, ossia::exec_state_facade st) noexcept
773 ossia::inlets& inlets = this->root_inputs();
774 ossia::outlets& outlets = this->root_outputs();
776 if constexpr(has_state)
779 get_inlet_accessor<info, I>(inlets)...,
780 get_outlet_accessor<info, O>(outlets)..., tk, st,
781 static_cast<state_type&
>(*
this));
786 get_inlet_accessor<info, I>(inlets)...,
787 get_outlet_accessor<info, O>(outlets)..., tk, st);
791 void run(
const ossia::token_request& tk, ossia::exec_state_facade st) noexcept
override
793 using inlets_indices = std::make_index_sequence<info::control_start>;
794 using outlets_indices = std::make_index_sequence<info::control_out_start>;
796 apply_all_impl(inlets_indices{}, outlets_indices{}, tk, st);
799 void all_notes_off() noexcept
override
801 if constexpr(info::midi_in_count > 0)
807 [[nodiscard]] std::string label() const noexcept
override {
return "Control"; }
812 ossia::value_port& port;
817 port.write_value(std::move(v), 0);
821 template <
typename T>
822 struct control_updater
826 void operator()() { control = std::move(v); }
The value class.
Definition: value.hpp:173
val_type
Enum to represent the types that a value can take.
Definition: parameter_properties.hpp:16
unit_t parse_dataspace(std::string_view text)
parse_dataspace
Definition: dataspace_visitors.cpp:89