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

paulmthompson / WhiskerToolbox / 17537238893

08 Sep 2025 01:48AM UTC coverage: 71.559% (+0.6%) from 70.935%
17537238893

push

github

paulmthompson
Merge branch 'main' of https://github.com/paulmthompson/WhiskerToolbox

36445 of 50930 relevant lines covered (71.56%)

1283.97 hits per line

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

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

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

9
#include <iostream>
10

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

18
TableRegistry::~TableRegistry() {
280✔
19
    std::cout << "TableRegistry destroyed" << std::endl;
280✔
20
}
280✔
21

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

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

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

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

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

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

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

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

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

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

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

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

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

177
bool TableRegistry::storeBuiltTable(std::string const & table_id, TableView table_view) {
22✔
178
    if (!hasTable(table_id)) {
22✔
179
        return false;
×
180
    }
181
    _table_views[table_id] = std::make_shared<TableView>(std::move(table_view));
22✔
182
    if (auto view = _table_views[table_id]) {
22✔
183
        auto column_names = view->getColumnNames();
22✔
184
        std::vector<std::string> qt_column_names;
22✔
185
        for (auto const & name : column_names) {
106✔
186
            qt_column_names.push_back(name);
84✔
187
        }
188
        _table_info[table_id].columnNames = qt_column_names;
22✔
189
    }
44✔
190
    std::cout << "Stored built table for: " << table_id << std::endl;
22✔
191
    notify(TableEventType::DataChanged, table_id);
22✔
192
    return true;
22✔
193
}
194

195
std::shared_ptr<TableView> TableRegistry::getBuiltTable(std::string const & table_id) const {
22✔
196
    auto it = _table_views.find(table_id);
22✔
197
    if (it != _table_views.end()) {
22✔
198
        return it->second;
22✔
199
    }
200
    return nullptr;
×
201
}
202

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

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

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

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

254
ComputerInfo const * TableRegistry::getComputerInfo(std::string const & computer_name) const {
×
255
    return _computer_registry->findComputerInfo(computer_name);
×
256
}
257

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

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

274
    try {
275
        // Create DataSourceVariant from column data source
276
        DataSourceVariant data_source_variant;
80✔
277
        bool valid_source = false;
80✔
278

279
        std::string column_source = column_info.dataSourceName;
80✔
280

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

341
        if (!valid_source) {
80✔
342
            std::cout << "Failed to create data source for column: " << column_info.name << std::endl;
×
343
            return false;
×
344
        }
345

346
        // Create the computer from the registry
347
        auto const & registry = *_computer_registry;
80✔
348
        
349
        // Get type information for the computer
350
        auto computer_info_ptr = registry.findComputerInfo(column_info.computerName);
80✔
351
        if (!computer_info_ptr) {
80✔
352
            std::cout << "Computer info not found for " << column_info.computerName << std::endl;
×
353
            return false;
×
354
        }
355
        
356
        auto computer_base = registry.createComputer(column_info.computerName, data_source_variant, column_info.parameters);
80✔
357
        if (!computer_base) {
80✔
358
            std::cout << "Failed to create computer " << column_info.computerName << " for column: " << column_info.name << std::endl;
×
359
            // Continue; the computer may be multi-output and use a different factory
360
        }
361

362
        // Use the actual return type from the computer info instead of hardcoding double
363
        std::type_index return_type = computer_info_ptr->outputType;
80✔
364
        std::cout << "Computer " << column_info.computerName << " returns type: " << computer_info_ptr->outputTypeName << std::endl;
80✔
365
        
366
        // Handle different return types using runtime type dispatch
367
        bool success = false;
80✔
368
        
369
        if (computer_info_ptr->isMultiOutput) {
80✔
370
            // Multi-output: expand into multiple columns using builder.addColumns
371
            if (return_type == typeid(double)) {
×
372
                auto multi = registry.createTypedMultiComputer<double>(
×
373
                    column_info.computerName, data_source_variant, column_info.parameters);
×
374
                if (!multi) {
×
375
                    std::cout << "Failed to create typed MULTI computer for " << column_info.computerName << std::endl;
×
376
                    return false;
×
377
                }
378
                builder.addColumns<double>(column_info.name, std::move(multi));
×
379
                success = true;
×
380
            } else if (return_type == typeid(int)) {
×
381
                auto multi = registry.createTypedMultiComputer<int>(
×
382
                    column_info.computerName, data_source_variant, column_info.parameters);
×
383
                if (!multi) {
×
384
                    std::cout << "Failed to create typed MULTI computer<int> for " << column_info.computerName << std::endl;
×
385
                    return false;
×
386
                }
387
                builder.addColumns<int>(column_info.name, std::move(multi));
×
388
                success = true;
×
389
            } else if (return_type == typeid(bool)) {
×
390
                auto multi = registry.createTypedMultiComputer<bool>(
×
391
                    column_info.computerName, data_source_variant, column_info.parameters);
×
392
                if (!multi) {
×
393
                    std::cout << "Failed to create typed MULTI computer<bool> for " << column_info.computerName << std::endl;
×
394
                    return false;
×
395
                }
396
                builder.addColumns<bool>(column_info.name, std::move(multi));
×
397
                success = true;
×
398
            } else {
×
399
                std::cout << "Unsupported multi-output element type for " << column_info.computerName << std::endl;
×
400
                return false;
×
401
            }
402
        } else {
403
            // Single output computers
404
            if (return_type == typeid(double)) {
80✔
405
                auto computer = registry.createTypedComputer<double>(column_info.computerName, data_source_variant, column_info.parameters);
7✔
406
                if (computer) {
7✔
407
                    builder.addColumn<double>(column_info.name, std::move(computer));
7✔
408
                    success = true;
7✔
409
                }
410
            } else if (return_type == typeid(int)) {
80✔
411
                auto computer = registry.createTypedComputer<int>(column_info.computerName, data_source_variant, column_info.parameters);
36✔
412
                if (computer) {
36✔
413
                    builder.addColumn<int>(column_info.name, std::move(computer));
36✔
414
                    success = true;
36✔
415
                }
416
            } else if (return_type == typeid(bool)) {
73✔
417
                auto computer = registry.createTypedComputer<bool>(column_info.computerName, data_source_variant, column_info.parameters);
36✔
418
                if (computer) {
36✔
419
                    builder.addColumn<bool>(column_info.name, std::move(computer));
36✔
420
                    success = true;
36✔
421
                }
422
            } else if (return_type == typeid(std::vector<double>)) {
37✔
423
                auto computer = registry.createTypedComputer<std::vector<double>>(column_info.computerName, data_source_variant, column_info.parameters);
×
424
                if (computer) {
×
425
                    builder.addColumn<std::vector<double>>(column_info.name, std::move(computer));
×
426
                    success = true;
×
427
                }
428
            } else if (return_type == typeid(std::vector<int>)) {
1✔
429
                auto computer = registry.createTypedComputer<std::vector<int>>(column_info.computerName, data_source_variant, column_info.parameters);
×
430
                if (computer) {
×
431
                    builder.addColumn<std::vector<int>>(column_info.name, std::move(computer));
×
432
                    success = true;
×
433
                }
434
            } else if (return_type == typeid(std::vector<float>)) {
1✔
435
                auto computer = registry.createTypedComputer<std::vector<float>>(column_info.computerName, data_source_variant, column_info.parameters);
1✔
436
                if (computer) {
1✔
437
                    builder.addColumn<std::vector<float>>(column_info.name, std::move(computer));
1✔
438
                    success = true;
1✔
439
                }
440
            } else {
1✔
441
                std::cout << "Unsupported output type for " << column_info.computerName << ": " << computer_info_ptr->outputTypeName << std::endl;
×
442
                return false;
×
443
            }
444
        }
445

446
        if (!success) {
80✔
447
            std::cout << "Failed to add column " << column_info.name << " with computer " << column_info.computerName << std::endl;
×
448
            return false;
×
449
        }
450
        
451
        return true;
80✔
452
        
453
    } catch (std::exception const & e) {
80✔
454
        std::cout << "Exception adding column " << column_info.name << ": " << e.what() << std::endl;
×
455
        return false;
×
456
    }
×
457
}
458

459
void TableRegistry::notify(TableEventType type, std::string const & table_id) const {
51✔
460
    TableEvent ev{type, table_id};
51✔
461
    DataManager__NotifyTableObservers(_data_manager, ev);
51✔
462
}
102✔
463

464

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