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

paulmthompson / WhiskerToolbox / 17846711083

19 Sep 2025 02:28AM UTC coverage: 72.02% (+0.08%) from 71.942%
17846711083

push

github

paulmthompson
event in interval computer works with entity ids

259 of 280 new or added lines in 6 files covered. (92.5%)

268 existing lines in 17 files now uncovered.

40247 of 55883 relevant lines covered (72.02%)

1227.29 hits per line

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

58.22
/src/DataManager/utils/TableView/core/TableView.cpp
1
#include "TableView.h"
2

3
#include "utils/TableView/adapters/DataManagerExtension.h"
4
#include "utils/TableView/columns/IColumn.h"
5
#include "utils/TableView/interfaces/ILineSource.h"
6
#include "utils/TableView/interfaces/IRowSelector.h"
7

8

9
#include <algorithm>
10
#include <set>
11
#include <stdexcept>
12

13
TableView::TableView(std::unique_ptr<IRowSelector> rowSelector,
113✔
14
                     std::shared_ptr<DataManagerExtension> dataManager)
113✔
15
    : m_rowSelector(std::move(rowSelector)),
113✔
16
      m_dataManager(std::move(dataManager)) {
113✔
17
    if (!m_rowSelector) {
113✔
18
        throw std::invalid_argument("IRowSelector cannot be null");
×
19
    }
20
    if (!m_dataManager) {
113✔
21
        throw std::invalid_argument("DataManagerExtension cannot be null");
×
22
    }
23
}
113✔
24

25
TableView::TableView(TableView && other) noexcept
47✔
26
    : m_rowSelector(std::move(other.m_rowSelector)),
47✔
27
      m_dataManager(std::move(other.m_dataManager)),
47✔
28
      m_columns(std::move(other.m_columns)),
47✔
29
      m_colNameToIndex(std::move(other.m_colNameToIndex)),
47✔
30
      m_planCache(std::move(other.m_planCache)),
47✔
31
      m_direct_entity_ids(std::move(other.m_direct_entity_ids)) {}
47✔
32

33
TableView & TableView::operator=(TableView && other) {
×
34
    if (this != &other) {
×
35
        m_rowSelector = std::move(other.m_rowSelector);
×
36
        m_dataManager = std::move(other.m_dataManager);
×
37
        m_columns = std::move(other.m_columns);
×
38
        m_colNameToIndex = std::move(other.m_colNameToIndex);
×
39
        m_planCache = std::move(other.m_planCache);
×
40
        m_direct_entity_ids = std::move(other.m_direct_entity_ids);
×
41
    }
42
    return *this;
×
43
}
44

45
size_t TableView::getRowCount() const {
328✔
46
    // Prefer expanded row count if any execution plan has entity-expanded rows cached
47
    for (auto const & entry : m_planCache) {
570✔
48
        if (!entry.second.getRows().empty()) {
262✔
49
            return entry.second.getRows().size();
20✔
50
        }
51
    }
52
    // If nothing cached yet, proactively attempt expansion using a line-source dependent column
53
    // Find a column whose source is an ILineSource
54
    for (auto const & column : m_columns) {
1,605✔
55
        try {
56
            auto const & dep = column->getSourceDependency();
1,314✔
57
            // Query line source without mutating the cache in a surprising way
58
            auto lineSource = m_dataManager->getLineSource(dep);
1,314✔
59
            if (lineSource) {
1,314✔
60
                // Trigger plan generation for this source to populate expansion rows
61
                auto & self = const_cast<TableView &>(*this);
17✔
62
                ExecutionPlan const & plan = self.getExecutionPlanFor(dep);
17✔
63
                if (!plan.getRows().empty()) {
17✔
64
                    return plan.getRows().size();
16✔
65
                }
66
                break; // only expand based on the first line source column
1✔
67
            }
68
        } catch (...) {
1,331✔
69
            // Ignore and continue
70
        }
×
71
    }
72
    return m_rowSelector->getRowCount();
292✔
73
}
74

75
size_t TableView::getColumnCount() const {
63✔
76
    return m_columns.size();
63✔
77
}
78

79
std::vector<std::string> TableView::getColumnNames() const {
63✔
80
    std::vector<std::string> names;
63✔
81
    names.reserve(m_columns.size());
63✔
82

83
    for (auto const & column: m_columns) {
331✔
84
        names.push_back(column->getName());
268✔
85
    }
86

87
    return names;
63✔
88
}
×
89

90
bool TableView::hasColumn(std::string const & name) const {
653✔
91
    return m_colNameToIndex.find(name) != m_colNameToIndex.end();
653✔
92
}
93

94
std::type_info const & TableView::getColumnType(std::string const & name) const {
160✔
95
    auto it = m_colNameToIndex.find(name);
160✔
96
    if (it == m_colNameToIndex.end()) {
160✔
97
        throw std::runtime_error("Column '" + name + "' not found in table");
×
98
    }
99
    
100
    return m_columns[it->second]->getType();
320✔
101
}
102

103
std::type_index TableView::getColumnTypeIndex(std::string const & name) const {
160✔
104
    return std::type_index(getColumnType(name));
160✔
105
}
106

107
ColumnDataVariant TableView::getColumnDataVariant(std::string const & name) {
118✔
108
    auto type_index = getColumnTypeIndex(name);
118✔
109
    
110
    // Dispatch from element type_index to vector type using template metaprogramming
111
    std::optional<ColumnDataVariant> result;
118✔
112
    
113
    for_each_type<SupportedColumnElementTypes>([&](auto, auto type_instance) {
1,180✔
114
        using ElementType = std::decay_t<decltype(type_instance)>;
115
        
116
        if (!result.has_value() && type_index == std::type_index(typeid(ElementType))) {
1,062✔
117
            // Found matching element type, get the vector data
118
            auto vectorData = getColumnValues<ElementType>(name);
118✔
119
            result = vectorData;  // This will construct the variant with the correct vector type
118✔
120
        }
118✔
121
    });
1,062✔
122

123
    if (!result.has_value()) {
118✔
124
        throw std::runtime_error("Unsupported column type: " + std::string(type_index.name()) + 
×
125
                                " for column: " + name);
×
126
    }
127
    
128
    return result.value();
236✔
129
}
118✔
130

131

132
void TableView::materializeAll() {
15✔
133
    std::set<std::string> materializing;
15✔
134

135
    for (auto const & column: m_columns) {
93✔
136
        if (!column->isMaterialized()) {
78✔
137
            materializeColumn(column->getName(), materializing);
78✔
138
        }
139
    }
140
}
30✔
141

142
void TableView::clearCache() {
×
143
    // Clear column caches
144
    for (auto & column: m_columns) {
×
145
        column->clearCache();
×
146
    }
147

148
    // Clear execution plan cache
149
    m_planCache.clear();
×
150
}
×
151

152
ExecutionPlan const & TableView::getExecutionPlanFor(std::string const & sourceName) {
335✔
153
    // Check cache first
154
    auto it = m_planCache.find(sourceName);
335✔
155
    if (it != m_planCache.end()) {
335✔
156
        return it->second;
213✔
157
    }
158

159
    // Generate new plan
160
    ExecutionPlan plan = generateExecutionPlan(sourceName);
122✔
161

162
    // Store in cache and return reference
163
    auto [insertedIt, inserted] = m_planCache.emplace(sourceName, std::move(plan));
122✔
164
    if (!inserted) {
122✔
165
        throw std::runtime_error("Failed to cache ExecutionPlan for source: " + sourceName);
×
166
    }
167

168
    return insertedIt->second;
122✔
169
}
122✔
170

171
void TableView::addColumn(std::shared_ptr<IColumn> column) {
407✔
172
    if (!column) {
407✔
173
        throw std::invalid_argument("Column cannot be null");
×
174
    }
175

176
    std::string const & name = column->getName();
407✔
177

178
    // Check for duplicate names
179
    if (hasColumn(name)) {
407✔
180
        throw std::runtime_error("Column '" + name + "' already exists");
×
181
    }
182

183
    // Add to collections
184
    size_t index = m_columns.size();
407✔
185
    m_columns.push_back(std::move(column));
407✔
186
    m_colNameToIndex[name] = index;
407✔
187
}
407✔
188

189
void TableView::materializeColumn(std::string const & columnName, std::set<std::string> & materializing) {
78✔
190
    // Check for circular dependencies
191
    if (materializing.find(columnName) != materializing.end()) {
78✔
192
        throw std::runtime_error("Circular dependency detected involving column: " + columnName);
×
193
    }
194

195
    // Check if column exists
196
    if (!hasColumn(columnName)) {
78✔
197
        throw std::runtime_error("Column '" + columnName + "' not found");
×
198
    }
199

200
    auto & column = m_columns[m_colNameToIndex[columnName]];
78✔
201

202
    // If already materialized, nothing to do
203
    if (column->isMaterialized()) {
78✔
204
        return;
×
205
    }
206

207
    // Mark as being materialized
208
    materializing.insert(columnName);
78✔
209

210
    // Materialize dependencies first
211
    auto const dependencies = column->getDependencies();
78✔
212
    for (auto const & dependency: dependencies) {
78✔
213
        if (hasColumn(dependency)) {
×
214
            materializeColumn(dependency, materializing);
×
215
        }
216
    }
217

218
    // Materialize this column
219
    column->materialize(this);// Use the IColumn interface method
78✔
220

221
    // Remove from materializing set
222
    materializing.erase(columnName);
78✔
223
}
78✔
224

225
ExecutionPlan TableView::generateExecutionPlan(std::string const & sourceName) {
122✔
226
    // Try to get the data source to understand its structure
227
    // First try as analog source
228

229
    
230

231
    auto analogSource = m_dataManager->getAnalogSource(sourceName);
122✔
232
    if (analogSource) {
122✔
233
        // Generate plan based on row selector type for analog data
234
        if (auto intervalSelector = dynamic_cast<IntervalSelector *>(m_rowSelector.get())) {
48✔
235
            auto const & intervals = intervalSelector->getIntervals();
25✔
236
            auto timeFrame = intervalSelector->getTimeFrame();
25✔
237
            return ExecutionPlan(intervals, timeFrame);
25✔
238
        }
25✔
239

240
        if (auto timestampSelector = dynamic_cast<TimestampSelector *>(m_rowSelector.get())) {
23✔
241
            auto const & indices = timestampSelector->getTimestamps();
23✔
242
            auto timeFrame = timestampSelector->getTimeFrame();
23✔
243
            return ExecutionPlan(indices, timeFrame);
23✔
244
        }
23✔
245

246
        if (auto indexSelector = dynamic_cast<IndexSelector *>(m_rowSelector.get())) {
×
247
            auto const & indices = indexSelector->getIndices();
×
248
            std::vector<TimeFrameIndex> timeFrameIndices;
×
249
            timeFrameIndices.reserve(indices.size());
×
250

251
            for (size_t index: indices) {
×
252
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
253
            }
254

255
            std::cout << "WARNING: IndexSelector is not supported for analog data" << std::endl;
×
256
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
257
        }
×
258
    }
259

260
    // Try as interval source
261
    auto intervalSource = m_dataManager->getIntervalSource(sourceName);
74✔
262
    if (intervalSource) {
74✔
263
        // Generate plan based on row selector type for interval data
264
        if (auto intervalSelector = dynamic_cast<IntervalSelector *>(m_rowSelector.get())) {
30✔
265
            auto const & intervals = intervalSelector->getIntervals();
22✔
266
            auto timeFrame = intervalSelector->getTimeFrame();
22✔
267
            return ExecutionPlan(intervals, timeFrame);
22✔
268
        }
22✔
269

270
        if (auto timestampSelector = dynamic_cast<TimestampSelector *>(m_rowSelector.get())) {
8✔
271
            auto const & indices = timestampSelector->getTimestamps();
8✔
272
            auto timeFrame = timestampSelector->getTimeFrame();
8✔
273
            return ExecutionPlan(indices, timeFrame);
8✔
274
        }
8✔
275

276
        if (auto indexSelector = dynamic_cast<IndexSelector *>(m_rowSelector.get())) {
×
277
            auto const & indices = indexSelector->getIndices();
×
278
            std::vector<TimeFrameIndex> timeFrameIndices;
×
279
            timeFrameIndices.reserve(indices.size());
×
280

281
            for (size_t index: indices) {
×
282
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
283
            }
284

285
            std::cout << "WARNING: IndexSelector is not supported for interval data" << std::endl;
×
286
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
287
        }
×
288
    }
289

290
    // Try as event source
291
    auto eventSource = m_dataManager->getEventSource(sourceName);
44✔
292
    if (eventSource) {
44✔
293
        // Generate plan based on row selector type for event data
294
        if (auto intervalSelector = dynamic_cast<IntervalSelector *>(m_rowSelector.get())) {
24✔
295
            auto const & intervals = intervalSelector->getIntervals();
24✔
296
            auto timeFrame = intervalSelector->getTimeFrame();
24✔
297
            return ExecutionPlan(intervals, timeFrame);
24✔
298
        }
24✔
299

300
        if (auto timestampSelector = dynamic_cast<TimestampSelector *>(m_rowSelector.get())) {
×
301
            auto const & indices = timestampSelector->getTimestamps();
×
302
            auto timeFrame = timestampSelector->getTimeFrame();
×
303
            return ExecutionPlan(indices, timeFrame);
×
304
        }
×
305

306
        if (auto indexSelector = dynamic_cast<IndexSelector *>(m_rowSelector.get())) {
×
307
            auto const & indices = indexSelector->getIndices();
×
308
            std::vector<TimeFrameIndex> timeFrameIndices;
×
309
            timeFrameIndices.reserve(indices.size());
×
310

311
            for (size_t index: indices) {
×
312
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
313
            }
314

315
            std::cout << "WARNING: IndexSelector is not supported for event data" << std::endl;
×
316

317
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
318
        }
×
319
    }
320

321
    // Try as line source
322
    auto lineSource = m_dataManager->getLineSource(sourceName);
20✔
323
    if (lineSource) {
20✔
324
        // Default-on entity expansion for TimestampSelector
325
        if (auto timestampSelector = dynamic_cast<TimestampSelector *>(m_rowSelector.get())) {
18✔
326
            auto const & timestamps = timestampSelector->getTimestamps();
18✔
327
            auto timeFrame = timestampSelector->getTimeFrame();
18✔
328

329
            ExecutionPlan plan(std::vector<TimeFrameIndex>{}, timeFrame);
18✔
330
            // Build expanded rows: one row per line at that timestamp; drop timestamps with zero lines
331
            std::vector<RowId> rows;
18✔
332
            rows.reserve(timestamps.size());
18✔
333
            std::map<TimeFrameIndex, std::pair<size_t,size_t>> spans;
18✔
334

335
            // Determine if table contains any non-line columns; if so, we include singleton rows
336
            bool anyNonLineColumn = false;
18✔
337
            for (auto const & col : m_columns) {
146✔
338
                try {
339
                    auto const & dep = col->getSourceDependency();
129✔
340
                    if (!m_dataManager->getLineSource(dep)) {
129✔
341
                        anyNonLineColumn = true;
1✔
342
                        break;
1✔
343
                    }
344
                } catch (...) {
129✔
345
                    // Ignore
346
                }
×
347
            }
348

349
            size_t cursor = 0;
18✔
350
            for (auto const & t : timestamps) {
76✔
351
                auto const count = lineSource->getEntityCountAt(t);
58✔
352
                if (count == 0) {
58✔
353
                    if (anyNonLineColumn) {
8✔
354
                        spans.emplace(t, std::make_pair(cursor, static_cast<size_t>(1)));
3✔
355
                        rows.push_back(RowId{t, std::nullopt});
3✔
356
                        ++cursor;
3✔
357
                    }
358
                } else {
359
                    spans.emplace(t, std::make_pair(cursor, static_cast<size_t>(count)));
50✔
360
                    for (size_t i = 0; i < count; ++i) {
129✔
361
                        rows.push_back(RowId{t, static_cast<int>(i)});
79✔
362
                        ++cursor;
79✔
363
                    }
364
                }
365
            }
366

367
            plan.setRows(std::move(rows));
18✔
368
            plan.setTimeToRowSpan(std::move(spans));
18✔
369
            plan.setSourceId(DataSourceNameInterner::instance().intern(lineSource->getName()));
18✔
370
            plan.setSourceKind(ExecutionPlan::DataSourceKind::Line);
18✔
371
            return plan;
18✔
372
        }
18✔
373

374
        // IntervalSelector: keep legacy behavior (no expansion) for now
375
        if (auto intervalSelector = dynamic_cast<IntervalSelector *>(m_rowSelector.get())) {
×
376
            auto const & intervals = intervalSelector->getIntervals();
×
377
            auto timeFrame = intervalSelector->getTimeFrame();
×
378
            return ExecutionPlan(intervals, timeFrame);
×
379
        }
×
380

381
        if (auto indexSelector = dynamic_cast<IndexSelector *>(m_rowSelector.get())) {
×
382
            auto const & indices = indexSelector->getIndices();
×
383
            std::vector<TimeFrameIndex> timeFrameIndices;
×
384
            timeFrameIndices.reserve(indices.size());
×
385
            for (size_t index: indices) {
×
386
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
387
            }
388
            std::cout << "WARNING: IndexSelector is not supported for line data" << std::endl;
×
389
            auto plan = ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
390
            plan.setSourceId(DataSourceNameInterner::instance().intern(lineSource->getName()));
×
391
            plan.setSourceKind(ExecutionPlan::DataSourceKind::Line);
×
392
            return plan;
×
393
        }
×
394
    }
395

396
    // Generic fallback: generate plan solely based on row selector when the source is unknown
397
    if (auto intervalSelector = dynamic_cast<IntervalSelector *>(m_rowSelector.get())) {
2✔
398
        auto const & intervals = intervalSelector->getIntervals();
×
399
        auto timeFrame = intervalSelector->getTimeFrame();
×
400
        std::cout << "WARNING: Data source '" << sourceName
401
                  << "' not found. Generating plan from IntervalSelector only." << std::endl;
×
402
        return ExecutionPlan(intervals, timeFrame);
×
403
    }
×
404

405
    if (auto timestampSelector = dynamic_cast<TimestampSelector *>(m_rowSelector.get())) {
2✔
406
        auto const & indices = timestampSelector->getTimestamps();
2✔
407
        auto timeFrame = timestampSelector->getTimeFrame();
2✔
408
        std::cout << "WARNING: Data source '" << sourceName
409
                  << "' not found. Generating plan from TimestampSelector only." << std::endl;
2✔
410
        return ExecutionPlan(indices, timeFrame);
2✔
411
    }
2✔
412

413
    if (auto indexSelector = dynamic_cast<IndexSelector *>(m_rowSelector.get())) {
×
414
        auto const & indices = indexSelector->getIndices();
×
415
        std::vector<TimeFrameIndex> timeFrameIndices;
×
416
        timeFrameIndices.reserve(indices.size());
×
417
        for (size_t index: indices) {
×
418
            timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
419
        }
420
        std::cout << "WARNING: Data source '" << sourceName
421
                  << "' not found. Generating plan from IndexSelector only." << std::endl;
×
422
        return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
423
    }
×
424

425
    throw std::runtime_error("Data source '" + sourceName + "' not found as analog, interval, event, or line source");
×
426
}
122✔
427

428
RowDescriptor TableView::getRowDescriptor(size_t row_index) const {
×
429
    if (m_rowSelector) {
×
430
        return m_rowSelector->getDescriptor(row_index);
×
431
    }
432
    return std::monostate{};
×
433
}
434

435
std::vector<EntityId> TableView::getRowEntityIds(size_t row_index) const {
32✔
436
    // First check if we have direct EntityIds (for transformed tables)
437
    if (!m_direct_entity_ids.empty()) {
32✔
438
        if (row_index < m_direct_entity_ids.size()) {
×
439
            EntityId id = m_direct_entity_ids[row_index];
×
440
            return id != 0 ? std::vector<EntityId>{id} : std::vector<EntityId>{};
×
441
        }
442
        return {};
×
443
    }
444
    
445
    // Fallback to execution plan-based EntityIds (for original tables)
446
    // Prefer entity-expanded plans if present
447
    for (auto const & [name, plan] : m_planCache) {
32✔
448
        (void)name;
449
        auto const & rows = plan.getRows();
32✔
450
        if (rows.empty() || row_index >= rows.size()) continue;
32✔
451
        auto const & row = rows[row_index];
32✔
452
        if (!row.entityIndex.has_value()) continue;
32✔
453

454
        // Resolve by source kind
455
        auto const sourceName = DataSourceNameInterner::instance().nameOf(plan.getSourceId());
32✔
456
        switch (plan.getSourceKind()) {
32✔
457
            case ExecutionPlan::DataSourceKind::Line: {
32✔
458
                auto lineSource = m_dataManager->getLineSource(sourceName);
32✔
459
                if (!lineSource) break;
32✔
460
                EntityId id = lineSource->getEntityIdAt(row.timeIndex, *row.entityIndex);
32✔
461
                if (id != 0) return {id};
96✔
462
                break;
×
463
            }
32✔
464
            case ExecutionPlan::DataSourceKind::Event: {
×
465
                auto eventSource = m_dataManager->getEventSource(sourceName);
×
466
                if (!eventSource) break;
×
467
                // For events we typically do not expand per-entity rows yet; fall through
468
                break;
×
469
            }
×
470
            case ExecutionPlan::DataSourceKind::IntervalKind: {
×
471
                auto intervalSource = m_dataManager->getIntervalSource(sourceName);
×
472
                if (!intervalSource) break;
×
473
                // Interval entity expansion not yet implemented here
474
                break;
×
475
            }
×
476
            default: break;
×
477
        }
478
    }
32✔
479
    return {};
×
480
}
481

482
bool TableView::hasEntityColumn() const {
11✔
483
    // Check if we have direct EntityIds first
484
    if (!m_direct_entity_ids.empty()) {
11✔
485
        return true;
4✔
486
    }
487
    
488
    // Fallback to execution plan-based check
489
    size_t row_count = getRowCount();
7✔
490
    if (row_count == 0) {
7✔
491
        return false;
×
492
    }
493
    
494
    // Check the first row to see if EntityIds are available
495
    auto entity_ids = getRowEntityIds(0);
7✔
496
    return !entity_ids.empty();
7✔
497
}
7✔
498

499
std::vector<EntityId> TableView::getEntityIds() const {
9✔
500
    // If we have direct EntityIds, return them
501
    if (!m_direct_entity_ids.empty()) {
9✔
502
        return m_direct_entity_ids;
4✔
503
    }
504
    
505
    // Fallback to execution plan-based EntityIds
506
    std::vector<EntityId> all_entity_ids;
5✔
507
    size_t row_count = getRowCount();
5✔
508
    all_entity_ids.reserve(row_count);
5✔
509
    
510
    for (size_t i = 0; i < row_count; ++i) {
30✔
511
        auto row_entity_ids = getRowEntityIds(i);
25✔
512
        if (!row_entity_ids.empty()) {
25✔
513
            // Use the first (primary) EntityId for this row
514
            all_entity_ids.push_back(row_entity_ids[0]);
25✔
515
        } else {
516
            // No EntityId available for this row
517
            all_entity_ids.push_back(0);
×
518
        }
519
    }
25✔
520
    
521
    return all_entity_ids;
5✔
522
}
5✔
523

524
void TableView::setDirectEntityIds(std::vector<EntityId> entity_ids) {
2✔
525
    m_direct_entity_ids = std::move(entity_ids);
2✔
526
}
2✔
527

528
std::unique_ptr<IRowSelector> TableView::cloneRowSelectorFiltered(std::vector<size_t> const & keep_indices) const {
×
529
    if (!m_rowSelector) {
×
530
        return nullptr;
×
531
    }
532

533
    // IndexSelector
534
    if (auto indexSelector = dynamic_cast<IndexSelector const *>(m_rowSelector.get())) {
×
535
        std::vector<size_t> const & indices = indexSelector->getIndices();
×
536
        std::vector<size_t> filtered;
×
537
        filtered.reserve(keep_indices.size());
×
538
        for (size_t k : keep_indices) {
×
539
            if (k < indices.size()) {
×
540
                filtered.push_back(indices[k]);
×
541
            }
542
        }
543
        return std::make_unique<IndexSelector>(std::move(filtered));
×
544
    }
×
545

546
    // TimestampSelector
547
    if (auto timestampSelector = dynamic_cast<TimestampSelector const *>(m_rowSelector.get())) {
×
548
        auto const & timestamps = timestampSelector->getTimestamps();
×
549
        auto timeFrame = timestampSelector->getTimeFrame();
×
550
        std::vector<TimeFrameIndex> filtered;
×
551
        filtered.reserve(keep_indices.size());
×
552
        for (size_t k : keep_indices) {
×
553
            if (k < timestamps.size()) {
×
554
                filtered.push_back(timestamps[k]);
×
555
            }
556
        }
557
        return std::make_unique<TimestampSelector>(std::move(filtered), timeFrame);
×
558
    }
×
559

560
    // IntervalSelector
561
    if (auto intervalSelector = dynamic_cast<IntervalSelector const *>(m_rowSelector.get())) {
×
562
        auto const & intervals = intervalSelector->getIntervals();
×
563
        auto timeFrame = intervalSelector->getTimeFrame();
×
564
        std::vector<TimeFrameInterval> filtered;
×
565
        filtered.reserve(keep_indices.size());
×
566
        for (size_t k : keep_indices) {
×
567
            if (k < intervals.size()) {
×
568
                filtered.push_back(intervals[k]);
×
569
            }
570
        }
571
        return std::make_unique<IntervalSelector>(std::move(filtered), timeFrame);
×
572
    }
×
573

574
    // Fallback: preserve by indices if unknown type
575
    std::vector<size_t> identity;
×
576
    identity.reserve(keep_indices.size());
×
577
    for (size_t k : keep_indices) identity.push_back(k);
×
578
    return std::make_unique<IndexSelector>(std::move(identity));
×
579
}
×
580

581
bool TableView::hasColumnEntityIds(std::string const & columnName) const {
8✔
582
    auto it = m_colNameToIndex.find(columnName);
8✔
583
    if (it == m_colNameToIndex.end()) {
8✔
UNCOV
584
        return false;
×
585
    }
586
    
587
    size_t columnIndex = it->second;
8✔
588
    if (columnIndex >= m_columns.size()) {
8✔
UNCOV
589
        return false;
×
590
    }
591
    
592
    return m_columns[columnIndex]->hasEntityIds();
8✔
593
}
594

595
ColumnEntityIds TableView::getColumnEntityIds(std::string const & columnName) const {
18✔
596
    auto it = m_colNameToIndex.find(columnName);
18✔
597
    if (it == m_colNameToIndex.end()) {
18✔
UNCOV
598
        return {};
×
599
    }
600
    
601
    size_t columnIndex = it->second;
18✔
602
    if (columnIndex >= m_columns.size()) {
18✔
UNCOV
603
        return {};
×
604
    }
605
    
606
    // Need to cast away const to pass this to column method
607
    return m_columns[columnIndex]->getColumnEntityIds(const_cast<TableView*>(this));
18✔
608
}
609

610
std::vector<EntityId> TableView::getCellEntityIds(std::string const & columnName, size_t rowIndex) const {
40✔
611
    auto it = m_colNameToIndex.find(columnName);
40✔
612
    if (it == m_colNameToIndex.end()) {
40✔
UNCOV
613
        return {};
×
614
    }
615
    
616
    size_t columnIndex = it->second;
40✔
617
    if (columnIndex >= m_columns.size()) {
40✔
UNCOV
618
        return {};
×
619
    }
620
    
621
    // Need to cast away const to pass this to column method
622
    return m_columns[columnIndex]->getCellEntityIds(const_cast<TableView*>(this), rowIndex);
40✔
623
}
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