• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 18050758459

26 Sep 2025 09:57PM UTC coverage: 69.825% (+0.1%) from 69.725%
18050758459

push

github

paulmthompson
multi computer tables show up now

192 of 242 new or added lines in 5 files covered. (79.34%)

22 existing lines in 3 files now uncovered.

43180 of 61840 relevant lines covered (69.83%)

1137.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.72
/src/DataManager/utils/TableView/TableRegistry.cpp
1
#include "TableRegistry.hpp"
2

3
#include "DataManager.hpp"
4
#include "TableObserverBridge.hpp"
5
#include "utils/TableView/ComputerRegistry.hpp"
6
#include "utils/TableView/adapters/DataManagerExtension.h"
7
#include "utils/TableView/core/TableView.h"
8
#include "utils/TableView/core/TableViewBuilder.h"
9

10
#include <iostream>
11

12
TableRegistry::TableRegistry(DataManager & data_manager)
331✔
13
    : _data_manager(data_manager),
331✔
14
      _data_manager_extension(std::make_shared<DataManagerExtension>(data_manager)),
331✔
15
      _computer_registry(std::make_unique<ComputerRegistry>()) {
331✔
16
    // std::cout << "TableRegistry initialized" << std::endl;
17
}
331✔
18

19
TableRegistry::~TableRegistry() {
331✔
20
    // std::cout << "TableRegistry destroyed" << std::endl;
21
}
331✔
22

23
bool TableRegistry::createTable(std::string const & table_id, std::string const & table_name, std::string const & table_description) {
36✔
24
    if (hasTable(table_id)) {
36✔
25
        std::cout << "Table with ID already exists: " << table_id << std::endl;
×
26
        return false;
×
27
    }
28
    TableInfo info(table_id, table_name, table_description);
36✔
29
    _table_info[table_id] = info;
36✔
30
    std::cout << "Created table: " << table_id << std::endl;
36✔
31
    notify(TableEventType::Created, table_id);
36✔
32
    return true;
36✔
33
}
36✔
34

35
bool TableRegistry::removeTable(std::string const & table_id) {
×
36
    if (!hasTable(table_id)) {
×
37
        return false;
×
38
    }
39
    _table_info.erase(table_id);
×
40
    _table_views.erase(table_id);
×
41
    std::cout << "Removed table: " << table_id << std::endl;
×
42
    notify(TableEventType::Removed, table_id);
×
43
    return true;
×
44
}
45

46
bool TableRegistry::hasTable(std::string const & table_id) const {
121✔
47
    return _table_info.find(table_id) != _table_info.end();
121✔
48
}
49

50
TableInfo TableRegistry::getTableInfo(std::string const & table_id) const {
31✔
51
    auto it = _table_info.find(table_id);
31✔
52
    if (it != _table_info.end()) {
31✔
53
        return it->second;
31✔
54
    }
55
    return TableInfo();
×
56
}
57

58
std::vector<std::string> TableRegistry::getTableIds() const {
×
59
    std::vector<std::string> ids;
×
60
    ids.reserve(_table_info.size());
×
61
    for (auto it = _table_info.begin(); it != _table_info.end(); ++it) {
×
62
        ids.push_back(it->first);
×
63
    }
64
    return ids;
×
65
}
×
66

67
std::vector<TableInfo> TableRegistry::getAllTableInfo() const {
31✔
68
    std::vector<TableInfo> infos;
31✔
69
    infos.reserve(_table_info.size());
31✔
70
    for (auto it = _table_info.begin(); it != _table_info.end(); ++it) {
47✔
71
        infos.push_back(it->second);
16✔
72
    }
73
    return infos;
31✔
74
}
×
75

76
bool TableRegistry::setTableView(std::string const & table_id, std::shared_ptr<TableView> table_view) {
×
77
    if (!hasTable(table_id)) {
×
78
        return false;
×
79
    }
80
    _table_views[table_id] = std::move(table_view);
×
81
    if (auto view = _table_views[table_id]) {
×
82
        auto column_names = view->getColumnNames();
×
83
        std::vector<std::string> qt_column_names;
×
84
        for (auto const & name: column_names) {
×
85
            qt_column_names.push_back(name);
×
86
        }
87
        _table_info[table_id].columnNames = qt_column_names;
×
88
    }
×
89
    std::cout << "Set TableView for table: " << table_id << std::endl;
×
90
    notify(TableEventType::DataChanged, table_id);
×
91
    return true;
×
92
}
93

94
bool TableRegistry::updateTableInfo(std::string const & table_id, std::string const & table_name, std::string const & table_description) {
4✔
95
    if (!hasTable(table_id)) {
4✔
96
        return false;
×
97
    }
98
    _table_info[table_id].name = table_name;
4✔
99
    _table_info[table_id].description = table_description;
4✔
100
    std::cout << "Updated table info for: " << table_id << std::endl;
4✔
101
    notify(TableEventType::InfoUpdated, table_id);
4✔
102
    return true;
4✔
103
}
104

105
bool TableRegistry::updateTableRowSource(std::string const & table_id, std::string const & row_source_name) {
9✔
106
    if (!hasTable(table_id)) {
9✔
107
        return false;
×
108
    }
109
    _table_info[table_id].rowSourceName = row_source_name;
9✔
110
    std::cout << "Updated row source for: " << table_id << std::endl;
9✔
111
    notify(TableEventType::InfoUpdated, table_id);
9✔
112
    return true;
9✔
113
}
114

115
bool TableRegistry::addTableColumn(std::string const & table_id, ColumnInfo const & column_info) {
×
116
    if (!hasTable(table_id)) {
×
117
        return false;
×
118
    }
119
    auto & table = _table_info[table_id];
×
120
    table.columns.push_back(column_info);
×
121
    table.columnNames.clear();
×
122
    for (auto const & column: table.columns) {
×
123
        table.columnNames.push_back(column.name);
×
124
    }
125
    std::cout << "Added column " << column_info.name << " to table " << table_id << std::endl;
×
126
    notify(TableEventType::InfoUpdated, table_id);
×
127
    return true;
×
128
}
129

130
bool TableRegistry::updateTableColumn(std::string const & table_id, size_t column_index, ColumnInfo const & column_info) {
×
131
    if (!hasTable(table_id)) {
×
132
        return false;
×
133
    }
134
    auto & table = _table_info[table_id];
×
135
    if (column_index >= table.columns.size()) {
×
136
        return false;
×
137
    }
138
    table.columns[column_index] = column_info;
×
139
    table.columnNames.clear();
×
140
    for (auto const & column: table.columns) {
×
141
        table.columnNames.push_back(column.name);
×
142
    }
143
    std::cout << "Updated column index " << column_index << " in table " << table_id << std::endl;
×
144
    notify(TableEventType::InfoUpdated, table_id);
×
145
    return true;
×
146
}
147

148
bool TableRegistry::removeTableColumn(std::string const & table_id, size_t column_index) {
×
149
    if (!hasTable(table_id)) {
×
150
        return false;
×
151
    }
152
    auto & table = _table_info[table_id];
×
153
    if (column_index >= table.columns.size()) {
×
154
        return false;
×
155
    }
156
    std::string removed = table.columns[column_index].name;
×
157
    table.columns.erase(table.columns.begin() + static_cast<long int>(column_index));
×
158
    table.columnNames.clear();
×
159
    for (auto const & column: table.columns) {
×
160
        table.columnNames.push_back(column.name);
×
161
    }
162
    std::cout << "Removed column " << removed << " from table " << table_id << std::endl;
×
163
    notify(TableEventType::InfoUpdated, table_id);
×
164
    return true;
×
165
}
×
166

167
ColumnInfo TableRegistry::getTableColumn(std::string const & table_id, size_t column_index) const {
×
168
    if (!hasTable(table_id)) {
×
169
        return ColumnInfo();
×
170
    }
171
    auto const & table = _table_info.at(table_id);
×
172
    if (column_index >= table.columns.size()) {
×
173
        return ColumnInfo();
×
174
    }
175
    return table.columns[column_index];
×
176
}
177

178
bool TableRegistry::storeBuiltTable(std::string const & table_id, std::unique_ptr<TableView> table_view) {
26✔
179
    if (!hasTable(table_id)) {
26✔
180
        return false;
×
181
    }
182
    if (!table_view) {
26✔
183
        return false;
×
184
    }
185
    _table_views[table_id] = std::shared_ptr<TableView>(table_view.release());
26✔
186
    if (auto view = _table_views[table_id]) {
26✔
187
        auto column_names = view->getColumnNames();
26✔
188
        std::vector<std::string> qt_column_names;
26✔
189
        for (auto const & name: column_names) {
126✔
190
            qt_column_names.push_back(name);
100✔
191
        }
192
        _table_info[table_id].columnNames = qt_column_names;
26✔
193
    }
52✔
194
    std::cout << "Stored built table for: " << table_id << std::endl;
26✔
195
    notify(TableEventType::DataChanged, table_id);
26✔
196
    return true;
26✔
197
}
198

199
std::shared_ptr<TableView> TableRegistry::getBuiltTable(std::string const & table_id) const {
24✔
200
    auto it = _table_views.find(table_id);
24✔
201
    if (it != _table_views.end()) {
24✔
202
        return it->second;
24✔
203
    }
204
    return nullptr;
×
205
}
206

207
std::string TableRegistry::generateUniqueTableId(std::string const & base_name) const {
13✔
208
    std::string candidate;
13✔
209
    while (true) {
210
        candidate = base_name + "_" + std::to_string(_next_table_counter);
13✔
211
        const_cast<TableRegistry *>(this)->_next_table_counter++;
13✔
212
        if (!hasTable(candidate)) {
13✔
213
            break;
13✔
214
        }
215
    }
216
    return candidate;
13✔
217
}
×
218

219
bool TableRegistry::addTableColumnWithTypeInfo(std::string const & table_id, ColumnInfo & column_info) {
×
220
    if (!hasTable(table_id)) {
×
221
        std::cout << "Table does not exist: " << table_id << std::endl;
×
222
        return false;
×
223
    }
224
    auto computer_info = _computer_registry->findComputerInfo(column_info.computerName);
×
225
    if (!computer_info) {
×
226
        std::cout << "Computer not found in registry: " << column_info.computerName << std::endl;
×
227
        return false;
×
228
    }
229
    column_info.outputType = computer_info->outputType;
×
230
    column_info.outputTypeName = computer_info->outputTypeName;
×
231
    column_info.isVectorType = computer_info->isVectorType;
×
232
    column_info.elementType = computer_info->elementType;
×
233
    column_info.elementTypeName = computer_info->elementTypeName;
×
234
    return addTableColumn(table_id, column_info);
×
235
}
236

237
std::vector<std::string> TableRegistry::getAvailableComputersForDataSource(std::string const & /*row_selector_type*/, std::string const & /*data_source_name*/) const {
×
238
    std::vector<std::string> computers;
×
239
    auto all_computer_names = _computer_registry->getAllComputerNames();
×
240
    for (auto const & name: all_computer_names) {
×
241
        computers.push_back(name);
×
242
    }
243
    return computers;
×
244
}
×
245

246
std::tuple<std::string, bool, std::string> TableRegistry::getComputerTypeInfo(std::string const & computer_name) const {
×
247
    auto computer_info = _computer_registry->findComputerInfo(computer_name);
×
248
    if (!computer_info) {
×
249
        return std::make_tuple(std::string("unknown"), false, std::string("unknown"));
×
250
    }
251
    return std::make_tuple(
252
            computer_info->outputTypeName,
×
253
            computer_info->isVectorType,
×
254
            computer_info->elementTypeName);
×
255
}
256

257
ComputerInfo const * TableRegistry::getComputerInfo(std::string const & computer_name) const {
×
258
    return _computer_registry->findComputerInfo(computer_name);
×
259
}
260

261
std::vector<std::string> TableRegistry::getAvailableOutputTypes() const {
×
262
    auto type_names = _computer_registry->getOutputTypeNames();
×
263
    std::vector<std::string> result;
×
264
    for (auto const & [type_index, name]: type_names) {
×
265
        (void) type_index;
266
        result.push_back(name);
×
267
    }
268
    return result;
×
269
}
×
270

271
bool TableRegistry::addColumnToBuilder(TableViewBuilder & builder, ColumnInfo const & column_info) const {
135✔
272
    if (column_info.dataSourceName.empty() || column_info.computerName.empty()) {
135✔
273
        std::cout << "Column " << column_info.name << " missing data source or computer configuration" << std::endl;
×
274
        return false;
×
275
    }
276

277
    try {
278
        // Create DataSourceVariant from column data source
279
        DataSourceVariant data_source_variant;
135✔
280
        bool valid_source = false;
135✔
281

282
        std::string column_source = column_info.dataSourceName;
135✔
283

284
        if (column_source.starts_with("analog:")) {
135✔
285
            std::string source_name = column_source.substr(7);// Remove "analog:" prefix
9✔
286
            auto analog_source = _data_manager_extension->getAnalogSource(source_name);
9✔
287
            if (analog_source) {
9✔
288
                data_source_variant = analog_source;
9✔
289
                valid_source = true;
9✔
290
            }
291
        } else if (column_source.starts_with("events:")) {
135✔
292
            std::string source_name = column_source.substr(7);// Remove "events:" prefix
15✔
293
            auto event_source = _data_manager_extension->getEventSource(source_name);
15✔
294
            if (event_source) {
15✔
295
                data_source_variant = event_source;
15✔
296
                valid_source = true;
15✔
297
            }
298
        } else if (column_source.starts_with("intervals:")) {
126✔
299
            std::string source_name = column_source.substr(10);// Remove "intervals:" prefix
17✔
300
            auto interval_source = _data_manager_extension->getIntervalSource(source_name);
17✔
301
            if (interval_source) {
17✔
302
                data_source_variant = interval_source;
17✔
303
                valid_source = true;
17✔
304
            }
305
        } else if (column_source.starts_with("points_x:")) {
111✔
306
            std::string source_name = column_source.substr(9);// Remove "points_x:" prefix
×
307
            auto analog_source = _data_manager_extension->getAnalogSource(source_name + ".x");
×
308
            if (analog_source) {
×
309
                data_source_variant = analog_source;
×
310
                valid_source = true;
×
311
            }
312
        } else if (column_source.starts_with("points_y:")) {
94✔
313
            std::string source_name = column_source.substr(9);// Remove "points_y:" prefix
×
314
            auto analog_source = _data_manager_extension->getAnalogSource(source_name + ".y");
×
315
            if (analog_source) {
×
316
                data_source_variant = analog_source;
×
317
                valid_source = true;
×
318
            }
319
        } else if (column_source.starts_with("lines:")) {
94✔
320
            std::string source_name = column_source.substr(6);// Remove "lines:" prefix
4✔
321
            auto line_source = _data_manager_extension->getLineSource(source_name);
4✔
322
            if (line_source) {
4✔
323
                data_source_variant = line_source;
4✔
324
                valid_source = true;
4✔
325
            }
326
        } else {
4✔
327
            // Fallback: try to infer source kind when no prefix is provided
328
            // Prefer events -> intervals -> analog -> lines
329
            if (auto ev = _data_manager_extension->getEventSource(column_source)) {
90✔
330
                data_source_variant = ev;
90✔
331
                valid_source = true;
90✔
332
            } else if (auto iv = _data_manager_extension->getIntervalSource(column_source)) {
×
333
                data_source_variant = iv;
×
334
                valid_source = true;
×
335
            } else if (auto an = _data_manager_extension->getAnalogSource(column_source)) {
×
336
                data_source_variant = an;
×
337
                valid_source = true;
×
338
            } else if (auto ln = _data_manager_extension->getLineSource(column_source)) {
×
339
                data_source_variant = ln;
×
340
                valid_source = true;
×
341
            }
90✔
342
        }
343

344
        if (!valid_source) {
135✔
345
            std::cout << "Failed to create data source for column: " << column_info.name << std::endl;
×
346
            return false;
×
347
        }
348

349
        // Create the computer from the registry
350
        auto const & registry = *_computer_registry;
135✔
351

352
        // Get type information for the computer
353
        auto computer_info_ptr = registry.findComputerInfo(column_info.computerName);
135✔
354
        if (!computer_info_ptr) {
135✔
355
            std::cout << "Computer info not found for " << column_info.computerName << std::endl;
×
356
            return false;
×
357
        }
358

359
        // Skip regular computer creation for multi-output computers to avoid error messages
360
        std::unique_ptr<IComputerBase> computer_base = nullptr;
135✔
361
        if (!computer_info_ptr->isMultiOutput) {
135✔
362
            computer_base = registry.createComputer(column_info.computerName, data_source_variant, column_info.parameters);
131✔
363
            if (!computer_base) {
131✔
NEW
364
                std::cout << "Failed to create computer " << column_info.computerName << " for column: " << column_info.name << std::endl;
×
NEW
365
                return false;
×
366
            }
367
        }
368

369
        // Use the actual return type from the computer info instead of hardcoding double
370
        std::type_index return_type = computer_info_ptr->outputType;
135✔
371
        std::cout << "Computer " << column_info.computerName << " returns type: " << computer_info_ptr->outputTypeName << std::endl;
135✔
372

373
        // Handle different return types using runtime type dispatch
374
        bool success = false;
135✔
375

376
        if (computer_info_ptr->isMultiOutput) {
135✔
377
            // Multi-output: expand into multiple columns using builder.addColumns
378
            if (return_type == typeid(double)) {
4✔
379
                auto multi = registry.createTypedMultiComputer<double>(
4✔
380
                        column_info.computerName, data_source_variant, column_info.parameters);
4✔
381
                if (!multi) {
4✔
382
                    std::cout << "Failed to create typed MULTI computer for " << column_info.computerName << std::endl;
×
383
                    return false;
×
384
                }
385
                builder.addColumns<double>(column_info.name, std::move(multi));
4✔
386
                success = true;
4✔
387
            } else if (return_type == typeid(int)) {
4✔
388
                auto multi = registry.createTypedMultiComputer<int>(
×
389
                        column_info.computerName, data_source_variant, column_info.parameters);
×
390
                if (!multi) {
×
391
                    std::cout << "Failed to create typed MULTI computer<int> for " << column_info.computerName << std::endl;
×
392
                    return false;
×
393
                }
394
                builder.addColumns<int>(column_info.name, std::move(multi));
×
395
                success = true;
×
396
            } else if (return_type == typeid(bool)) {
×
397
                auto multi = registry.createTypedMultiComputer<bool>(
×
398
                        column_info.computerName, data_source_variant, column_info.parameters);
×
399
                if (!multi) {
×
400
                    std::cout << "Failed to create typed MULTI computer<bool> for " << column_info.computerName << std::endl;
×
401
                    return false;
×
402
                }
403
                builder.addColumns<bool>(column_info.name, std::move(multi));
×
404
                success = true;
×
405
            } else {
×
406
                std::cout << "Unsupported multi-output element type for " << column_info.computerName << std::endl;
×
407
                return false;
×
408
            }
409
        } else {
410
            // Single output computers
411
            if (return_type == typeid(double)) {
131✔
412
                auto computer = registry.createTypedComputer<double>(column_info.computerName, data_source_variant, column_info.parameters);
24✔
413
                if (computer) {
24✔
414
                    builder.addColumn<double>(column_info.name, std::move(computer));
24✔
415
                    success = true;
24✔
416
                }
417
            } else if (return_type == typeid(int)) {
131✔
418
                auto computer = registry.createTypedComputer<int>(column_info.computerName, data_source_variant, column_info.parameters);
46✔
419
                if (computer) {
46✔
420
                    builder.addColumn<int>(column_info.name, std::move(computer));
46✔
421
                    success = true;
46✔
422
                }
423
            } else if (return_type == typeid(int64_t)) {
107✔
424
                auto computer = registry.createTypedComputer<int64_t>(column_info.computerName, data_source_variant, column_info.parameters);
2✔
425
                if (computer) {
2✔
426
                    builder.addColumn<int64_t>(column_info.name, std::move(computer));
2✔
427
                    success = true;
2✔
428
                }
429
            } else if (return_type == typeid(bool)) {
61✔
430
                auto computer = registry.createTypedComputer<bool>(column_info.computerName, data_source_variant, column_info.parameters);
57✔
431
                if (computer) {
57✔
432
                    builder.addColumn<bool>(column_info.name, std::move(computer));
57✔
433
                    success = true;
57✔
434
                }
435
            } else if (return_type == typeid(std::vector<double>)) {
59✔
436
                auto computer = registry.createTypedComputer<std::vector<double>>(column_info.computerName, data_source_variant, column_info.parameters);
×
437
                if (computer) {
×
438
                    builder.addColumn<std::vector<double>>(column_info.name, std::move(computer));
×
439
                    success = true;
×
440
                }
441
            } else if (return_type == typeid(std::vector<int>)) {
2✔
442
                auto computer = registry.createTypedComputer<std::vector<int>>(column_info.computerName, data_source_variant, column_info.parameters);
×
443
                if (computer) {
×
444
                    builder.addColumn<std::vector<int>>(column_info.name, std::move(computer));
×
445
                    success = true;
×
446
                }
447
            } else if (return_type == typeid(std::vector<float>)) {
2✔
448
                auto computer = registry.createTypedComputer<std::vector<float>>(column_info.computerName, data_source_variant, column_info.parameters);
2✔
449
                if (computer) {
2✔
450
                    builder.addColumn<std::vector<float>>(column_info.name, std::move(computer));
2✔
451
                    success = true;
2✔
452
                }
453
            } else {
2✔
454
                std::cout << "Unsupported output type for " << column_info.computerName << ": " << computer_info_ptr->outputTypeName << std::endl;
×
455
                return false;
×
456
            }
457
        }
458

459
        if (!success) {
135✔
460
            std::cout << "Failed to add column " << column_info.name << " with computer " << column_info.computerName << std::endl;
×
461
            return false;
×
462
        }
463

464
        return true;
135✔
465

466
    } catch (std::exception const & e) {
135✔
467
        std::cout << "Exception adding column " << column_info.name << ": " << e.what() << std::endl;
×
468
        return false;
×
469
    }
×
470
}
471

472
void TableRegistry::notify(TableEventType type, std::string const & table_id) const {
75✔
473
    TableEvent ev{type, table_id};
75✔
474
    DataManager__NotifyTableObservers(_data_manager, ev);
75✔
475
}
150✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc