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 (void)data;
23 static string msg = "Hello";
24 return &msg;
25}
26
27// Event that increments a counter passed as data
28void* event_increment(void* data) {
29 int* counter = static_cast<int*>(data);
30 if (counter) {
31 (*counter)++;
32 }
33 return counter;
34}
35
36// Event that returns the input data directly
37void* event_echo(void* data) {
38 return data;
39}
40
41// =============================================================================
42// Legacy Static_Event_Table Tests (void* interface)
43// =============================================================================
44
49
52
53 // Register at specific index
55
56 // Execute
57 void* result = table.execute_event(0);
58 string* msg = static_cast<string*>(result);
59 EXPECT_EQ(*msg, "Hello");
60}
61
64
65 // Note: register_event(fct) appends to the END of the table.
66 // For Static_Event_Table, this means writing to index size().
67 // But Static_Event_Table has fixed size, so writing to size() is out of bounds!
68 //
69 // Wait, let's check the implementation of append_event_to_table:
70 // void append_event_to_table(Event_Fct fct) { write_table(size(), fct); }
71 //
72 // And Static_Event_Table::write_table checks: if (i >= size_table) error.
73 //
74 // So register_event(fct) on a Static_Event_Table will ALWAYS fail
75 // because it tries to append beyond the fixed size.
76 // This seems to be a design limitation or intended behavior for dynamic tables only.
77 // Let's verify this behavior.
78
79 EXPECT_THROW(table.register_event(event_hello), std::range_error);
80}
81
93
97
98 EXPECT_TRUE(table.check(1, event_hello));
99
100 table.unregister_event(1);
101
102 // Should be nullptr now
103 EXPECT_FALSE(table.check(1, event_hello));
104
105 // Executing unregistered event should throw
106 EXPECT_THROW(table.execute_event(1), std::range_error);
107}
108
111
112 EXPECT_THROW(table.register_event(5, event_hello), std::range_error);
113 EXPECT_THROW(table.execute_event(5), std::range_error); // read_table checks range first
114}
115
122
127
130 table1.register_event(0, event_hello);
131
132 // Move constructor
134 EXPECT_EQ(table2.size(), 5u);
135 EXPECT_EQ(table1.size(), 0u); // Moved from
136
137 void* result = table2.execute_event(0);
138 EXPECT_EQ(*static_cast<string*>(result), "Hello");
139
140 // Move assignment
142 table3 = std::move(table2);
143 EXPECT_EQ(table3.size(), 5u);
144 EXPECT_EQ(table2.size(), 0u);
145
146 result = table3.execute_event(0);
147 EXPECT_EQ(*static_cast<string*>(result), "Hello");
148}
149
150// =============================================================================
151// Dynamic_Event_Table Tests
152// =============================================================================
153
158
160 Legacy_Dynamic_Event_Table table; // Empty
161
162 // Auto-append
163 size_t id1 = table.register_event(event_hello);
164 EXPECT_EQ(id1, 0u);
165 EXPECT_EQ(table.size(), 1u);
166
167 size_t id2 = table.register_event(event_echo);
168 EXPECT_EQ(id2, 1u);
169 EXPECT_EQ(table.size(), 2u);
170
171 // Execute
172 void* result = table.execute_event(id1);
173 EXPECT_EQ(*static_cast<string*>(result), "Hello");
174
175 int data = 42;
176 result = table.execute_event(id2, &data);
177 EXPECT_EQ(*static_cast<int*>(result), 42);
178}
179
181 Legacy_Dynamic_Event_Table table(10); // Pre-allocate
182
183 table.register_event(5, event_hello);
184 EXPECT_TRUE(table.check(5, event_hello));
185
186 // Should grow if we write beyond the current size?
187 // The base class register_event(index, fct) checks: index >= size() -> range_error
188 // So we cannot register at arbitrary index beyond size using register_event(index, fct).
189 // We must use register_event(fct) to append.
190
191 EXPECT_THROW(table.register_event(20, event_hello), std::range_error);
192}
193
197 size_t id1 = table.register_event(event_echo);
198
199 EXPECT_EQ(table.size(), 2u);
200
201 // Unregister last event: slot is cleared but table does not shrink
202 // (size stays the same because the base class only shrinks when
203 // index == size(), which is unreachable after the range check).
204 table.unregister_event(id1);
205 EXPECT_EQ(table.size(), 2u);
207
208 // Verify event at id0 was not corrupted by unregistering id1
209 EXPECT_TRUE(table.check(0, event_hello));
210 void* result = table.execute_event(0);
211 EXPECT_EQ(*static_cast<string*>(result), "Hello");
212
213 // The cleared slot can be reused via register_event(index, fct)
216}
217
220 table.register_event(0, event_hello);
221 table.unregister_event(0);
222
223 // Now slot 0 is free
224 table.register_event(0, event_echo);
225 EXPECT_TRUE(table.check(0, event_echo));
226}
227
228// =============================================================================
229// Modern Type-Safe Event Table Tests (with lambdas and templates)
230// =============================================================================
231
232// Test void(int) signature
234 Static_Event_Table<void(int)> table(5);
235 EXPECT_EQ(table.size(), 5u);
236
237 int counter = 0;
238 table.register_event(0, [&counter](int x) { counter += x; });
239
240 table.execute_event(0, 10);
241 EXPECT_EQ(counter, 10);
242
243 table.execute_event(0, 5);
244 EXPECT_EQ(counter, 15);
245}
246
247// Test int(int, int) signature with return value
249 Static_Event_Table<int(int, int)> table(3);
250
251 // Lambda that adds two numbers
252 table.register_event(0, [](int a, int b) { return a + b; });
253
254 // Lambda that multiplies
255 table.register_event(1, [](int a, int b) { return a * b; });
256
257 EXPECT_EQ(table.execute_event(0, 3, 4), 7);
258 EXPECT_EQ(table.execute_event(1, 3, 4), 12);
259}
260
261// Test string(string) with complex objects
263 Static_Event_Table<string(const string&)> table(2);
264
265 table.register_event(0, [](const string& s) { return "Hello, " + s; });
266 table.register_event(1, [](const string& s) {
267 string upper = s;
268 for (auto& c : upper) c = toupper(c);
269 return upper;
270 });
271
272 EXPECT_EQ(table.execute_event(0, "World"), "Hello, World");
273 EXPECT_EQ(table.execute_event(1, "test"), "TEST");
274}
275
276// Test Dynamic_Event_Table with lambdas
278 Dynamic_Event_Table<int(int)> table;
279
280 auto id1 = table.register_event([](int x) { return x * 2; });
281 auto id2 = table.register_event([](int x) { return x * 3; });
282 auto id3 = table.register_event([](int x) { return x * 5; });
283
284 EXPECT_EQ(table.size(), 3u);
285
286 EXPECT_EQ(table.execute_event(id1, 10), 20);
287 EXPECT_EQ(table.execute_event(id2, 10), 30);
288 EXPECT_EQ(table.execute_event(id3, 10), 50);
289}
290
291// Test with stateful lambdas (captures)
293 Dynamic_Event_Table<void(int)> table;
294
295 int total = 0;
296 int count = 0;
297
298 // Lambda capturing by reference
299 auto avg_id = table.register_event([&](int value) {
300 total += value;
301 count++;
302 });
303
304 table.execute_event(avg_id, 10);
305 table.execute_event(avg_id, 20);
306 table.execute_event(avg_id, 30);
307
308 EXPECT_EQ(total, 60);
309 EXPECT_EQ(count, 3);
310}
311
312// Test std::function directly
314 Dynamic_Event_Table<double(double)> table;
315
316 std::function<double(double)> square = [](double x) { return x * x; };
317 std::function<double(double)> cube = [](double x) { return x * x * x; };
318
319 auto square_id = table.register_event(square);
320 auto cube_id = table.register_event(cube);
321
322 EXPECT_DOUBLE_EQ(table.execute_event(square_id, 5.0), 25.0);
323 EXPECT_DOUBLE_EQ(table.execute_event(cube_id, 3.0), 27.0);
324}
325
326// Test is_registered
328 Dynamic_Event_Table<void()> table;
329
330 auto id1 = table.register_event([]() {});
331 auto id2 = table.register_event([]() {});
332
335 EXPECT_FALSE(table.is_registered(999));
336
337 table.unregister_event(id1);
340}
341
342// Test move semantics
345 table1.register_event(0, [](int x) { return x * 10; });
346
347 // Move constructor
348 Static_Event_Table<int(int)> table2(std::move(table1));
349 EXPECT_EQ(table2.size(), 3u);
350 EXPECT_EQ(table1.size(), 0u);
351
352 EXPECT_EQ(table2.execute_event(0, 5), 50);
353
354 // Move assignment
356 table3 = std::move(table2);
357 EXPECT_EQ(table3.size(), 3u);
358 EXPECT_EQ(table2.size(), 0u);
359
360 EXPECT_EQ(table3.execute_event(0, 5), 50);
361}
362
363// =============================================================================
364// Main
365// =============================================================================
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)
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::string toupper(const char *str)
Convert a C std::string to upper-case.
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.
static long counter
Definition test-splice.C:35