Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
driven_table_test.cc
Go to the documentation of this file.
1
10#include <gtest/gtest.h>
11#include <driven_table.H>
12#include <string>
13
14using namespace std;
15
16// =============================================================================
17// Helper Functions for Legacy Events (void* interface)
18// =============================================================================
19
20// Simple event that returns a string
21void* event_hello(void* data) {
22 static string msg = "Hello";
23 return &msg;
24}
25
26// Event that increments a counter passed as data
27void* event_increment(void* data) {
28 int* counter = static_cast<int*>(data);
29 if (counter) {
30 (*counter)++;
31 }
32 return counter;
33}
34
35// Event that returns the input data directly
36void* event_echo(void* data) {
37 return data;
38}
39
40// =============================================================================
41// Legacy Static_Event_Table Tests (void* interface)
42// =============================================================================
43
48
51
52 // Register at specific index
54
55 // Execute
56 void* result = table.execute_event(0);
57 string* msg = static_cast<string*>(result);
58 EXPECT_EQ(*msg, "Hello");
59}
60
63
64 // Note: register_event(fct) appends to the END of the table.
65 // For Static_Event_Table, this means writing to index size().
66 // But Static_Event_Table has fixed size, so writing to size() is out of bounds!
67 //
68 // Wait, let's check the implementation of append_event_to_table:
69 // void append_event_to_table(Event_Fct fct) { write_table(size(), fct); }
70 //
71 // And Static_Event_Table::write_table checks: if (i >= size_table) error.
72 //
73 // So register_event(fct) on a Static_Event_Table will ALWAYS fail
74 // because it tries to append beyond the fixed size.
75 // This seems to be a design limitation or intended behavior for dynamic tables only.
76 // Let's verify this behavior.
77
78 EXPECT_THROW(table.register_event(event_hello), std::range_error);
79}
80
84
85 int counter = 0;
86 table.execute_event(2, &counter);
87 EXPECT_EQ(counter, 1);
88
89 table.execute_event(2, &counter);
90 EXPECT_EQ(counter, 2);
91}
92
96
97 EXPECT_TRUE(table.check(1, event_hello));
98
99 table.unregister_event(1);
100
101 // Should be nullptr now
102 EXPECT_FALSE(table.check(1, event_hello));
103
104 // Executing unregistered event should throw
105 EXPECT_THROW(table.execute_event(1), std::range_error);
106}
107
110
111 EXPECT_THROW(table.register_event(5, event_hello), std::range_error);
112 EXPECT_THROW(table.execute_event(5), std::range_error); // read_table checks range first
113}
114
121
126
129 table1.register_event(0, event_hello);
130
131 // Move constructor
133 EXPECT_EQ(table2.size(), 5u);
134 EXPECT_EQ(table1.size(), 0u); // Moved from
135
136 void* result = table2.execute_event(0);
137 EXPECT_EQ(*static_cast<string*>(result), "Hello");
138
139 // Move assignment
141 table3 = std::move(table2);
142 EXPECT_EQ(table3.size(), 5u);
143 EXPECT_EQ(table2.size(), 0u);
144
145 result = table3.execute_event(0);
146 EXPECT_EQ(*static_cast<string*>(result), "Hello");
147}
148
149// =============================================================================
150// Dynamic_Event_Table Tests
151// =============================================================================
152
157
159 Legacy_Dynamic_Event_Table table; // Empty
160
161 // Auto-append
162 size_t id1 = table.register_event(event_hello);
163 EXPECT_EQ(id1, 0u);
164 EXPECT_EQ(table.size(), 1u);
165
166 size_t id2 = table.register_event(event_echo);
167 EXPECT_EQ(id2, 1u);
168 EXPECT_EQ(table.size(), 2u);
169
170 // Execute
171 void* result = table.execute_event(id1);
172 EXPECT_EQ(*static_cast<string*>(result), "Hello");
173
174 int data = 42;
175 result = table.execute_event(id2, &data);
176 EXPECT_EQ(*static_cast<int*>(result), 42);
177}
178
180 Legacy_Dynamic_Event_Table table(10); // Pre-allocate
181
182 table.register_event(5, event_hello);
183 EXPECT_TRUE(table.check(5, event_hello));
184
185 // Should grow if we write beyond the current size?
186 // The base class register_event(index, fct) checks: index >= size() -> range_error
187 // So we cannot register at arbitrary index beyond size using register_event(index, fct).
188 // We must use register_event(fct) to append.
189
190 EXPECT_THROW(table.register_event(20, event_hello), std::range_error);
191}
192
196 size_t id1 = table.register_event(event_echo);
197
198 EXPECT_EQ(table.size(), 2u);
199
200 // Unregister last event: slot is cleared but table does not shrink
201 // (size stays the same because the base class only shrinks when
202 // index == size(), which is unreachable after the range check).
203 table.unregister_event(id1);
204 EXPECT_EQ(table.size(), 2u);
206
207 // Verify event at id0 was not corrupted by unregistering id1
208 EXPECT_TRUE(table.check(0, event_hello));
209 void* result = table.execute_event(0);
210 EXPECT_EQ(*static_cast<string*>(result), "Hello");
211
212 // The cleared slot can be reused via register_event(index, fct)
215}
216
219 table.register_event(0, event_hello);
220 table.unregister_event(0);
221
222 // Now slot 0 is free
223 table.register_event(0, event_echo);
224 EXPECT_TRUE(table.check(0, event_echo));
225}
226
227// =============================================================================
228// Modern Type-Safe Event Table Tests (with lambdas and templates)
229// =============================================================================
230
231// Test void(int) signature
233 Static_Event_Table<void(int)> table(5);
234 EXPECT_EQ(table.size(), 5u);
235
236 int counter = 0;
237 table.register_event(0, [&counter](int x) { counter += x; });
238
239 table.execute_event(0, 10);
240 EXPECT_EQ(counter, 10);
241
242 table.execute_event(0, 5);
243 EXPECT_EQ(counter, 15);
244}
245
246// Test int(int, int) signature with return value
248 Static_Event_Table<int(int, int)> table(3);
249
250 // Lambda that adds two numbers
251 table.register_event(0, [](int a, int b) { return a + b; });
252
253 // Lambda that multiplies
254 table.register_event(1, [](int a, int b) { return a * b; });
255
256 EXPECT_EQ(table.execute_event(0, 3, 4), 7);
257 EXPECT_EQ(table.execute_event(1, 3, 4), 12);
258}
259
260// Test string(string) with complex objects
262 Static_Event_Table<string(const string&)> table(2);
263
264 table.register_event(0, [](const string& s) { return "Hello, " + s; });
265 table.register_event(1, [](const string& s) {
266 string upper = s;
267 for (auto& c : upper) c = toupper(c);
268 return upper;
269 });
270
271 EXPECT_EQ(table.execute_event(0, "World"), "Hello, World");
272 EXPECT_EQ(table.execute_event(1, "test"), "TEST");
273}
274
275// Test Dynamic_Event_Table with lambdas
277 Dynamic_Event_Table<int(int)> table;
278
279 auto id1 = table.register_event([](int x) { return x * 2; });
280 auto id2 = table.register_event([](int x) { return x * 3; });
281 auto id3 = table.register_event([](int x) { return x * 5; });
282
283 EXPECT_EQ(table.size(), 3u);
284
285 EXPECT_EQ(table.execute_event(id1, 10), 20);
286 EXPECT_EQ(table.execute_event(id2, 10), 30);
287 EXPECT_EQ(table.execute_event(id3, 10), 50);
288}
289
290// Test with stateful lambdas (captures)
292 Dynamic_Event_Table<void(int)> table;
293
294 int total = 0;
295 int count = 0;
296
297 // Lambda capturing by reference
298 auto avg_id = table.register_event([&](int value) {
299 total += value;
300 count++;
301 });
302
303 table.execute_event(avg_id, 10);
304 table.execute_event(avg_id, 20);
305 table.execute_event(avg_id, 30);
306
307 EXPECT_EQ(total, 60);
308 EXPECT_EQ(count, 3);
309}
310
311// Test std::function directly
313 Dynamic_Event_Table<double(double)> table;
314
315 std::function<double(double)> square = [](double x) { return x * x; };
316 std::function<double(double)> cube = [](double x) { return x * x * x; };
317
318 auto square_id = table.register_event(square);
319 auto cube_id = table.register_event(cube);
320
321 EXPECT_DOUBLE_EQ(table.execute_event(square_id, 5.0), 25.0);
322 EXPECT_DOUBLE_EQ(table.execute_event(cube_id, 3.0), 27.0);
323}
324
325// Test is_registered
327 Dynamic_Event_Table<void()> table;
328
329 auto id1 = table.register_event([]() {});
330 auto id2 = table.register_event([]() {});
331
334 EXPECT_FALSE(table.is_registered(999));
335
336 table.unregister_event(id1);
339}
340
341// Test move semantics
344 table1.register_event(0, [](int x) { return x * 10; });
345
346 // Move constructor
347 Static_Event_Table<int(int)> table2(std::move(table1));
348 EXPECT_EQ(table2.size(), 3u);
349 EXPECT_EQ(table1.size(), 0u);
350
351 EXPECT_EQ(table2.execute_event(0, 5), 50);
352
353 // Move assignment
355 table3 = std::move(table2);
356 EXPECT_EQ(table3.size(), 3u);
357 EXPECT_EQ(table2.size(), 0u);
358
359 EXPECT_EQ(table3.execute_event(0, 5), 50);
360}
361
362// =============================================================================
363// Main
364// =============================================================================
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Dynamic (growable) event table implementation.
size_t size() const override
Get the current table size (implements Event_Table virtual method)
bool is_registered(const size_t index) const
Check if an event is registered at the given index.
void register_event(const size_t index, Callable &&fct)
Register an event at a specific index.
void unregister_event(const size_t index)
Unregister an event at the given index.
bool check(const size_t, F) const
Legacy check method (for backward compatibility).
auto execute_event(const size_t index, Args &&... args) const
Execute the event at the given index with type-safe arguments.
Fixed-size event table implementation.
size_t size() const override
Get table size (implements Event_Table virtual method)
#define TEST(name)
Event-driven table abstraction for event-driven simulations.
void * event_echo(void *data)
void * event_hello(void *data)
void * event_increment(void *data)
std::string toupper(const char *str)
Convert a C std::string to upper-case.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.