Skip to content

Commit 7d1f99a

Browse files
committed
Fix another issue, with Dereferencing SIGNAL output bound to input.
1 parent 5cb0e40 commit 7d1f99a

File tree

5 files changed

+99
-11
lines changed

5 files changed

+99
-11
lines changed

cpp/include/hgraph/builders/time_series_types/time_series_signal_input_builder.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ namespace hgraph {
1212

1313
struct HGRAPH_EXPORT TimeSeriesSignalInputBuilder : InputBuilder {
1414
using ptr = nb::ref<TimeSeriesSignalInputBuilder>;
15-
using InputBuilder::InputBuilder;
15+
16+
// Constructor for signal without impl (basic signal)
17+
TimeSeriesSignalInputBuilder() = default;
18+
19+
// Constructor for signal with impl (signal bound to a dereferenced type)
20+
explicit TimeSeriesSignalInputBuilder(InputBuilder::ptr impl_builder);
1621

1722
time_series_input_s_ptr make_instance(node_ptr owning_node) const override;
1823

@@ -27,7 +32,10 @@ namespace hgraph {
2732
[[nodiscard]] size_t type_alignment() const override;
2833

2934
static void register_with_nanobind(nb::module_ &m);
35+
36+
private:
37+
InputBuilder::ptr impl_builder_{nullptr};
3038
};
3139
} // namespace hgraph
3240

33-
#endif // TIME_SERIES_SIGNAL_INPUT_BUILDER_H
41+
#endif // TIME_SERIES_SIGNAL_INPUT_BUILDER_H

cpp/include/hgraph/types/ts_signal.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,22 @@ namespace hgraph {
3636

3737
void make_passive() override;
3838

39+
// Override to delegate to impl or propagate to children
40+
bool bind_output(time_series_output_s_ptr output) override;
41+
42+
void un_bind_output(bool unbind_refs) override;
43+
3944
void do_un_bind_output(bool unbind_refs) override;
4045

46+
[[nodiscard]] bool bound() const override;
47+
4148
VISITOR_SUPPORT()
4249

4350
private:
4451
friend TimeSeriesSignalInputBuilder;
52+
TimeSeriesInput::s_ptr _impl; // Delegate input for when bound to dereferenced type
4553
mutable std::vector<TimeSeriesInput::s_ptr> _ts_values; // Lazily created child signals
4654
};
4755
}
4856

49-
#endif //TS_SIGNAL_H
57+
#endif //TS_SIGNAL_H

cpp/src/cpp/builders/time_series_types/time_series_signal_input_builder.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,27 @@
44
#include <hgraph/util/arena_enable_shared_from_this.h>
55

66
namespace hgraph {
7+
TimeSeriesSignalInputBuilder::TimeSeriesSignalInputBuilder(InputBuilder::ptr impl_builder)
8+
: impl_builder_{std::move(impl_builder)} {}
9+
710
time_series_input_s_ptr TimeSeriesSignalInputBuilder::make_instance(node_ptr owning_node) const {
8-
return arena_make_shared_as<TimeSeriesSignalInput, TimeSeriesInput>(owning_node);
11+
auto sig = arena_make_shared_as<TimeSeriesSignalInput, TimeSeriesInput>(owning_node);
12+
if (impl_builder_) {
13+
// Create the impl input with the signal as its parent, matching Python behavior
14+
auto signal_ptr = static_cast<TimeSeriesSignalInput*>(sig.get());
15+
signal_ptr->_impl = impl_builder_->make_instance(signal_ptr);
16+
}
17+
return sig;
918
}
1019

1120
time_series_input_s_ptr TimeSeriesSignalInputBuilder::make_instance(time_series_input_ptr owning_input) const {
12-
return arena_make_shared_as<TimeSeriesSignalInput, TimeSeriesInput>(owning_input);
21+
auto sig = arena_make_shared_as<TimeSeriesSignalInput, TimeSeriesInput>(owning_input);
22+
if (impl_builder_) {
23+
// Create the impl input with the signal as its parent, matching Python behavior
24+
auto signal_ptr = static_cast<TimeSeriesSignalInput*>(sig.get());
25+
signal_ptr->_impl = impl_builder_->make_instance(signal_ptr);
26+
}
27+
return sig;
1328
}
1429

1530
void TimeSeriesSignalInputBuilder::release_instance(time_series_input_ptr item) const {
@@ -21,19 +36,30 @@ namespace hgraph {
2136
throw std::runtime_error("TimeSeriesSignalInputBuilder::release_instance: expected TimeSeriesSignalInput but got different type");
2237
}
2338
InputBuilder::release_instance(signal_input);
39+
// Release impl if present
40+
if (signal_input->_impl && impl_builder_) {
41+
impl_builder_->release_instance(signal_input->_impl.get());
42+
}
2443
if (signal_input->_ts_values.empty()) { return; }
2544
for (auto &ts_value: signal_input->_ts_values) { release_instance(ts_value.get()); }
2645
}
2746

2847
size_t TimeSeriesSignalInputBuilder::memory_size() const {
29-
return add_canary_size(sizeof(TimeSeriesSignalInput));
48+
size_t total = add_canary_size(sizeof(TimeSeriesSignalInput));
49+
if (impl_builder_) {
50+
total = align_size(total, impl_builder_->type_alignment());
51+
total += impl_builder_->memory_size();
52+
}
53+
return total;
3054
}
3155

3256
size_t TimeSeriesSignalInputBuilder::type_alignment() const {
3357
return alignof(TimeSeriesSignalInput);
3458
}
3559

3660
void TimeSeriesSignalInputBuilder::register_with_nanobind(nb::module_ &m) {
37-
nb::class_<TimeSeriesSignalInputBuilder, InputBuilder>(m, "InputBuilder_TS_Signal").def(nb::init<>());
61+
nb::class_<TimeSeriesSignalInputBuilder, InputBuilder>(m, "InputBuilder_TS_Signal")
62+
.def(nb::init<>())
63+
.def(nb::init<InputBuilder::ptr>(), "impl_builder"_a);
3864
}
3965
} // namespace hgraph

cpp/src/cpp/types/ts_signal.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ namespace hgraph {
77
nb::object TimeSeriesSignalInput::py_delta_value() const { return py_value(); }
88

99
TimeSeriesInput::s_ptr TimeSeriesSignalInput::get_input(size_t index) {
10+
// If we have an impl, delegate to it
11+
if (_impl) {
12+
return _impl->get_input(index);
13+
}
1014
// This signal has been bound to a free bundle or a TSL so will be bound item-wise
1115
// Create child signals on demand, similar to Python implementation
1216
while (index >= _ts_values.size()) {
@@ -19,20 +23,29 @@ namespace hgraph {
1923
}
2024

2125
bool TimeSeriesSignalInput::valid() const {
26+
if (_impl) {
27+
return _impl->valid();
28+
}
2229
if (!_ts_values.empty()) {
2330
return std::ranges::any_of(_ts_values, [](const auto &item) { return item->valid(); });
2431
}
2532
return BaseTimeSeriesInput::valid();
2633
}
2734

2835
bool TimeSeriesSignalInput::modified() const {
36+
if (_impl) {
37+
return _impl->modified();
38+
}
2939
if (!_ts_values.empty()) {
3040
return std::ranges::any_of(_ts_values, [](const auto &item) { return item->modified(); });
3141
}
3242
return BaseTimeSeriesInput::modified();
3343
}
3444

3545
engine_time_t TimeSeriesSignalInput::last_modified_time() const {
46+
if (_impl) {
47+
return _impl->last_modified_time();
48+
}
3649
if (!_ts_values.empty()) {
3750
engine_time_t max_time = MIN_DT;
3851
for (const auto &item: _ts_values) { max_time = std::max(max_time, item->last_modified_time()); }
@@ -44,23 +57,53 @@ namespace hgraph {
4457
void TimeSeriesSignalInput::make_active() {
4558
if (active()) { return; }
4659
BaseTimeSeriesInput::make_active();
47-
if (!_ts_values.empty()) {
60+
if (_impl) {
61+
_impl->make_active();
62+
} else if (!_ts_values.empty()) {
4863
for (auto &item: _ts_values) { item->make_active(); }
4964
}
5065
}
5166

5267
void TimeSeriesSignalInput::make_passive() {
5368
if (!active()) { return; }
5469
BaseTimeSeriesInput::make_passive();
55-
if (!_ts_values.empty()) {
70+
if (_impl) {
71+
_impl->make_passive();
72+
} else if (!_ts_values.empty()) {
5673
for (auto &item: _ts_values) { item->make_passive(); }
5774
}
5875
}
5976

77+
bool TimeSeriesSignalInput::bind_output(time_series_output_s_ptr output) {
78+
if (_impl) {
79+
return _impl->bind_output(output);
80+
}
81+
return BaseTimeSeriesInput::bind_output(output);
82+
}
83+
84+
void TimeSeriesSignalInput::un_bind_output(bool unbind_refs) {
85+
if (_impl) {
86+
_impl->un_bind_output(unbind_refs);
87+
} else {
88+
BaseTimeSeriesInput::un_bind_output(unbind_refs);
89+
}
90+
}
91+
6092
void TimeSeriesSignalInput::do_un_bind_output(bool unbind_refs) {
93+
if (_impl) {
94+
_impl->un_bind_output(unbind_refs);
95+
}
6196
if (!_ts_values.empty()) {
6297
for (auto &item: _ts_values) { item->un_bind_output(unbind_refs); }
98+
_ts_values.clear();
99+
}
100+
}
101+
102+
bool TimeSeriesSignalInput::bound() const {
103+
if (_impl) {
104+
return _impl->bound();
63105
}
106+
return BaseTimeSeriesInput::bound() || !_ts_values.empty();
64107
}
65108

66-
} // namespace hgraph
109+
} // namespace hgraph

hgraph/_use_cpp_runtime.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ def _make_tsw_input_builder(self, value_tp):
9393

9494
def make_input_builder(self, value_tp):
9595
return {
96-
hgraph.HgSignalMetaData: lambda: _hgraph.InputBuilder_TS_Signal(),
96+
hgraph.HgSignalMetaData: lambda: (
97+
_hgraph.InputBuilder_TS_Signal(self.make_input_builder(value_tp.value_tp))
98+
if value_tp.value_tp else _hgraph.InputBuilder_TS_Signal()
99+
),
97100
hgraph.HgTSTypeMetaData: lambda: _ts_input_builder_type_for(value_tp.value_scalar_tp)(),
98101
hgraph.HgTSWTypeMetaData: lambda: self._make_tsw_input_builder(value_tp),
99102
hgraph.HgTSLTypeMetaData: lambda: _hgraph.InputBuilder_TSL(

0 commit comments

Comments
 (0)