Skip to content

Commit b4d154d

Browse files
committed
A few small performance enhancements
1 parent 706ea1f commit b4d154d

File tree

14 files changed

+149
-38
lines changed

14 files changed

+149
-38
lines changed

cpp/include/hgraph/types/ref.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ namespace hgraph
7979
using BaseTimeSeriesOutput::BaseTimeSeriesOutput;
8080

8181
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
82+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Reference | TimeSeriesKind::Output; }
8283

8384
const TimeSeriesReference &value() const; // Throws if no value
8485

@@ -143,8 +144,10 @@ namespace hgraph
143144
using BaseTimeSeriesInput::BaseTimeSeriesInput;
144145

145146
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override {
146-
return dynamic_cast<const TimeSeriesReferenceInput *>(other) != nullptr;
147+
// Single comparison checks both type (Reference) and direction (Input)
148+
return other->kind() == kind();
147149
}
150+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Reference | TimeSeriesKind::Input; }
148151

149152
void start();
150153

cpp/include/hgraph/types/time_series_type.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,65 @@
99

1010
namespace hgraph
1111
{
12+
/**
13+
* @brief Type tag enum for fast runtime type identification without RTTI.
14+
*
15+
* Used to avoid dynamic_cast overhead in hot paths like is_same_type() and copy operations.
16+
* Each concrete time series type has a unique kind value.
17+
*/
18+
/**
19+
* @brief Type tag using bit flags for fast runtime type identification.
20+
*
21+
* Each flag represents a type trait that can be combined:
22+
* - Direction: Output, Input
23+
* - Base types: Value, Bundle, List, Dict, Set, Reference, Window
24+
* - Modifiers: Indexed, Signal, etc.
25+
*
26+
* Examples:
27+
* - ListOutput: List | Output
28+
* - ListInput: List | Input
29+
* - IndexedListOutput: Indexed | List | Output
30+
*/
31+
enum class TimeSeriesKind : uint32_t {
32+
None = 0,
33+
34+
// Direction flags (mutually exclusive)
35+
Output = 1 << 0,
36+
Input = 1 << 1,
37+
38+
// Base type flags
39+
Value = 1 << 2,
40+
Bundle = 1 << 3,
41+
List = 1 << 4,
42+
Dict = 1 << 5,
43+
Set = 1 << 6,
44+
Reference = 1 << 7,
45+
Window = 1 << 8,
46+
47+
// Modifier flags (can be combined with base types)
48+
Indexed = 1 << 9,
49+
Signal = 1 << 10,
50+
FixedWindow = 1 << 11,
51+
TimeWindow = 1 << 12,
52+
};
53+
54+
// Bitwise operators for combining flags
55+
constexpr TimeSeriesKind operator|(TimeSeriesKind a, TimeSeriesKind b) {
56+
return static_cast<TimeSeriesKind>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
57+
}
58+
59+
constexpr TimeSeriesKind operator&(TimeSeriesKind a, TimeSeriesKind b) {
60+
return static_cast<TimeSeriesKind>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
61+
}
62+
63+
constexpr bool operator!(TimeSeriesKind k) {
64+
return static_cast<uint32_t>(k) == 0;
65+
}
66+
67+
// Helper to check if all flags in 'required' are present in 'kind'
68+
constexpr bool has_flags(TimeSeriesKind kind, TimeSeriesKind required) {
69+
return (kind & required) == required;
70+
}
1271

1372
struct TimeSeriesVisitor;
1473

@@ -105,6 +164,14 @@ namespace hgraph
105164
[[nodiscard]] virtual bool is_reference() const = 0;
106165
[[nodiscard]] virtual bool has_reference() const = 0;
107166

167+
/**
168+
* @brief Returns the runtime type tag for this time series.
169+
*
170+
* Used for fast type identification without RTTI overhead.
171+
* Default implementation returns None; concrete classes override with their specific kind.
172+
*/
173+
[[nodiscard]] virtual TimeSeriesKind kind() const { return TimeSeriesKind::None; }
174+
108175
static inline time_series_type_s_ptr null_ptr{};
109176
};
110177

cpp/include/hgraph/types/ts.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ namespace hgraph {
5656
void copy_from_output(const TimeSeriesOutput& output) override;
5757
void copy_from_input(const TimeSeriesInput& input) override;
5858
[[nodiscard]] bool is_same_type(const TimeSeriesType* other) const override;
59+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Value | TimeSeriesKind::Output; }
5960
void reset_value();
6061

6162
VISITOR_SUPPORT()
@@ -90,6 +91,7 @@ namespace hgraph {
9091
[[nodiscard]] const value::TypeMeta* schema() const;
9192

9293
[[nodiscard]] bool is_same_type(const TimeSeriesType* other) const override;
94+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Value | TimeSeriesKind::Input; }
9395

9496
VISITOR_SUPPORT()
9597
};

cpp/include/hgraph/types/ts_signal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ namespace hgraph {
2020

2121
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override { return true; }
2222

23+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Signal | TimeSeriesKind::Input; }
24+
2325
[[nodiscard]] TimeSeriesInput::s_ptr get_input(size_t index) override;
2426

2527
// Override to aggregate from children like Python implementation

cpp/include/hgraph/types/tsb.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ namespace hgraph {
152152

153153
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
154154

155+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Indexed | TimeSeriesKind::Bundle | TimeSeriesKind::Output; }
156+
155157
VISITOR_SUPPORT()
156158

157159
protected:
@@ -166,6 +168,8 @@ namespace hgraph {
166168

167169
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
168170

171+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Indexed | TimeSeriesKind::Bundle | TimeSeriesKind::Input; }
172+
169173
// This is used by the nested graph infra to rewrite the stub inputs when we build the nested graphs.
170174
// The general pattern in python was copy_with(node, ts=...)
171175
// To keep the code in sync for now, will keep this, but there is probably a better way to implement this going forward.

cpp/include/hgraph/types/tsd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ namespace hgraph
209209

210210
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
211211

212+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Dict | TimeSeriesKind::Output; }
213+
212214
[[nodiscard]] value_type get_or_create(const value::ConstValueView &key);
213215

214216
[[nodiscard]] bool has_reference() const override;
@@ -346,6 +348,8 @@ namespace hgraph
346348

347349
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
348350

351+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Dict | TimeSeriesKind::Input; }
352+
349353
[[nodiscard]] bool has_reference() const override;
350354

351355
void make_active() override;

cpp/include/hgraph/types/tsl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ namespace hgraph {
7272

7373
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
7474

75+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Indexed | TimeSeriesKind::List | TimeSeriesKind::Output; }
76+
7577
void py_set_value(const nb::object& value) override;
7678

7779
VISITOR_SUPPORT()
@@ -87,6 +89,8 @@ namespace hgraph {
8789

8890
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override;
8991

92+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Indexed | TimeSeriesKind::List | TimeSeriesKind::Input; }
93+
9094
VISITOR_SUPPORT()
9195

9296
protected:

cpp/include/hgraph/types/tss.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,15 @@ namespace hgraph {
160160
[[nodiscard]] bool empty() const override { return _storage.empty(); }
161161

162162
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override {
163-
if (auto* other_tss = dynamic_cast<const TimeSeriesSetOutput*>(other)) {
164-
return _element_type == other_tss->_element_type;
165-
}
166-
return false;
163+
// Single comparison checks both type (Set) and direction (Output)
164+
if (other->kind() != kind()) { return false; }
165+
// Kind matches exactly, safe to use static_cast
166+
auto* other_tss = static_cast<const TimeSeriesSetOutput*>(other);
167+
return _element_type == other_tss->_element_type;
167168
}
168169

170+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Set | TimeSeriesKind::Output; }
171+
169172
void _reset_value();
170173

171174
VISITOR_SUPPORT()
@@ -280,12 +283,15 @@ namespace hgraph {
280283
[[nodiscard]] bool empty() const override;
281284

282285
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override {
283-
if (auto* other_tss = dynamic_cast<const TimeSeriesSetInput*>(other)) {
284-
return element_type() == other_tss->element_type();
285-
}
286-
return false;
286+
// Single comparison checks both type (Set) and direction (Input)
287+
if (other->kind() != kind()) { return false; }
288+
// Kind matches exactly, safe to use static_cast
289+
auto* other_tss = static_cast<const TimeSeriesSetInput*>(other);
290+
return element_type() == other_tss->element_type();
287291
}
288292

293+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Set | TimeSeriesKind::Input; }
294+
289295
VISITOR_SUPPORT()
290296

291297
protected:

cpp/include/hgraph/types/tsw.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ namespace hgraph {
6060
void copy_from_input(const TimeSeriesInput &input) override;
6161

6262
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override {
63-
if (auto* other_tsw = dynamic_cast<const TimeSeriesFixedWindowOutput*>(other)) {
64-
return _element_type == other_tsw->_element_type;
65-
}
66-
return false;
63+
if (other->kind() != kind()) { return false; }
64+
auto* other_tsw = static_cast<const TimeSeriesFixedWindowOutput*>(other);
65+
return _element_type == other_tsw->_element_type;
6766
}
6867

68+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Window | TimeSeriesKind::FixedWindow | TimeSeriesKind::Output; }
69+
6970
// Extra API to mirror Python TSW
7071
[[nodiscard]] size_t size() const { return _size; }
7172
[[nodiscard]] size_t min_size() const { return _min_size; }
@@ -131,12 +132,13 @@ namespace hgraph {
131132
void copy_from_input(const TimeSeriesInput &input) override;
132133

133134
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override {
134-
if (auto* other_tsw = dynamic_cast<const TimeSeriesTimeWindowOutput*>(other)) {
135-
return _element_type == other_tsw->_element_type;
136-
}
137-
return false;
135+
if (other->kind() != kind()) { return false; }
136+
auto* other_tsw = static_cast<const TimeSeriesTimeWindowOutput*>(other);
137+
return _element_type == other_tsw->_element_type;
138138
}
139139

140+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Window | TimeSeriesKind::TimeWindow | TimeSeriesKind::Output; }
141+
140142
// Extra API to mirror Python TSW
141143
[[nodiscard]] engine_time_delta_t size() const { return _size; }
142144
[[nodiscard]] engine_time_delta_t min_size() const { return _min_size; }
@@ -208,12 +210,13 @@ namespace hgraph {
208210
[[nodiscard]] size_t len() const;
209211

210212
[[nodiscard]] bool is_same_type(const TimeSeriesType *other) const override {
211-
if (auto* other_input = dynamic_cast<const TimeSeriesWindowInput*>(other)) {
212-
return element_type() == other_input->element_type();
213-
}
214-
return false;
213+
if (other->kind() != kind()) { return false; }
214+
auto* other_input = static_cast<const TimeSeriesWindowInput*>(other);
215+
return element_type() == other_input->element_type();
215216
}
216217

218+
[[nodiscard]] TimeSeriesKind kind() const override { return TimeSeriesKind::Window | TimeSeriesKind::Input; }
219+
217220
VISITOR_SUPPORT()
218221

219222
private:

cpp/src/cpp/types/ref.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ namespace hgraph
231231
// ============================================================
232232

233233
bool TimeSeriesReferenceOutput::is_same_type(const TimeSeriesType *other) const {
234-
return dynamic_cast<const TimeSeriesReferenceOutput *>(other) != nullptr;
234+
// Single comparison checks both type (Reference) and direction (Output)
235+
return other->kind() == kind();
235236
}
236237

237238
const TimeSeriesReference &TimeSeriesReferenceOutput::value() const {

0 commit comments

Comments
 (0)