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

paulmthompson / WhiskerToolbox / 17737327548

15 Sep 2025 02:54PM UTC coverage: 72.602% (+0.5%) from 72.1%
17737327548

push

github

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

38155 of 52554 relevant lines covered (72.6%)

1349.01 hits per line

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

85.71
/src/DataManager/utils/TableView/core/TableView.h
1
#ifndef TABLE_VIEW_H
2
#define TABLE_VIEW_H
3

4
#include "utils/TableView/columns/ColumnTypeInfo.hpp"
5
#include "utils/TableView/columns/Column.h"
6
#include "utils/TableView/core/ExecutionPlan.h"
7
#include "utils/TableView/core/RowDescriptor.h"
8

9
#include <map>
10
#include <memory>
11
#include <set>
12
#include <span>
13
#include <stdexcept>
14
#include <string>
15
#include <vector>
16

17
class DataManagerExtension;
18
class IColumn;
19
class IRowSelector;
20
class TableViewBuilder;
21

22
/**
23
 * @brief The main orchestrator for tabular data views with lazy evaluation.
24
 * 
25
 * TableView manages a collection of heterogeneous columns and provides unified 
26
 * access to tabular data. It implements lazy evaluation with caching for both 
27
 * individual columns and ExecutionPlans. The TableView handles dependency 
28
 * resolution and ensures columns are computed in the correct order.
29
 */
30
class TableView {
31
public:
32

33
    // Movable but not copyable
34
    TableView(TableView && other) noexcept;
35
    TableView & operator=(TableView && other);
36
    TableView(const TableView & other) = delete;
37
    TableView & operator=(const TableView & other) = delete;
38

39
    /**
40
     * @brief Gets the number of rows in the table.
41
     * @return The row count as determined by the row selector.
42
     */
43
    [[nodiscard]] auto getRowCount() const -> size_t;
44

45
    /**
46
     * @brief Gets the number of columns in the table.
47
     * @return The column count.
48
     */
49
    [[nodiscard]] auto getColumnCount() const -> size_t;
50

51
    /**
52
     * @brief Gets the values of a column with the specified type.
53
     * 
54
     * This method provides type-safe access to column data. It performs a
55
     * dynamic_cast to ensure the column is of the correct type, and triggers
56
     * computation if the column is not yet materialized.
57
     * 
58
     * @tparam T The expected type of the column data.
59
     * @param name The name of the column to retrieve.
60
     * @return Reference to the column's data vector.
61
     * @throws std::runtime_error if the column is not found or type mismatch.
62
     */
63
    template<SupportedColumnType T>
64
    [[nodiscard]] auto getColumnValues(std::string const & name) -> std::vector<T> const &;
65

66
    /**
67
     * @brief Gets the names of all columns in the table.
68
     * @return Vector of column names.
69
     */
70
    [[nodiscard]] auto getColumnNames() const -> std::vector<std::string>;
71

72
    /**
73
     * @brief Checks if a column exists in the table.
74
     * @param name The column name to check.
75
     * @return True if the column exists, false otherwise.
76
     */
77
    [[nodiscard]] auto hasColumn(std::string const & name) const -> bool;
78

79
    /**
80
     * @brief Gets the runtime type information for a column.
81
     * @param name The column name.
82
     * @return The std::type_info for the column's data type.
83
     * @throws std::runtime_error if the column is not found.
84
     */
85
    [[nodiscard]] auto getColumnType(std::string const & name) const -> std::type_info const &;
86

87
    /**
88
     * @brief Gets the type index for a column.
89
     * @param name The column name.
90
     * @return The std::type_index for the column's data type.
91
     * @throws std::runtime_error if the column is not found.
92
     */
93
    [[nodiscard]] auto getColumnTypeIndex(std::string const & name) const -> std::type_index;
94

95
    /**
96
     * @brief Gets column data as a variant, avoiding try/catch for type detection.
97
     * 
98
     * This method returns column data in a type-safe variant that contains
99
     * all possible column types. Consumers can use std::visit or pattern
100
     * matching to handle the data without try/catch blocks.
101
     * 
102
     * @param name The column name.
103
     * @return ColumnDataVariant containing the column data.
104
     * @throws std::runtime_error if the column is not found or type not supported.
105
     */
106
    [[nodiscard]] auto getColumnDataVariant(std::string const & name) -> ColumnDataVariant;
107

108
    /**
109
     * @brief Applies a visitor to column data in a type-safe manner.
110
     * @tparam Visitor The visitor type that implements visit methods for all supported types.
111
     * @param name The column name.
112
     * @param visitor The visitor instance.
113
     * @return The result of the visitor.
114
     * @throws std::runtime_error if the column is not found or type not supported.
115
     */
116
    template<typename Visitor>
117
    auto visitColumnData(std::string const & name, Visitor&& visitor) -> decltype(auto);
118

119
    /**
120
     * @brief Materializes all columns in the table.
121
     * 
122
     * This method computes all columns that haven't been materialized yet.
123
     * It respects dependencies and computes columns in the correct order.
124
     */
125
    void materializeAll();
126

127
    /**
128
     * @brief Clears all cached data, forcing recomputation on next access.
129
     */
130
    void clearCache();
131

132
    /**
133
     * @brief Gets a descriptor containing the source information for a given row index.
134
     * 
135
     * This method provides reverse lookup capability, allowing clients to trace
136
     * a row back to its original source definition (e.g., timestamp, interval).
137
     * This is particularly useful for interactive applications like plotting libraries
138
     * that need to display tooltips or navigate back to source data.
139
     * 
140
     * @param row_index The index of the row to get the descriptor for.
141
     * @return RowDescriptor containing the source information for the row.
142
     */
143
    [[nodiscard]] auto getRowDescriptor(size_t row_index) const -> RowDescriptor;
144

145
    /**
146
     * @brief Get contributing EntityIds for a given row, if available.
147
     * @return Vector of EntityIds; empty if not available.
148
     */
149
    [[nodiscard]] auto getRowEntityIds(size_t row_index) const -> std::vector<EntityId>;
150

151
    /**
152
     * @brief Check if this table has EntityID information available.
153
     * @return True if EntityIDs are available for rows, false otherwise.
154
     */
155
    [[nodiscard]] bool hasEntityColumn() const;
156

157
    /**
158
     * @brief Get all EntityIds for all rows in the table.
159
     * 
160
     * For tables where each row corresponds to a single entity, this returns
161
     * a vector with one EntityId per row. For tables where rows can have multiple
162
     * contributing entities, this returns the primary EntityId for each row.
163
     * 
164
     * @return Vector of EntityIds, one per row. Empty vector if no EntityIDs available.
165
     */
166
    [[nodiscard]] auto getEntityIds() const -> std::vector<EntityId>;
167

168
    /**
169
     * @brief Set EntityIds directly for transformed tables.
170
     * 
171
     * This method allows transforms to preserve EntityId information
172
     * when creating new tables that don't have execution plans linking
173
     * back to original data sources.
174
     * 
175
     * @param entity_ids Vector of EntityIds, one per row
176
     */
177
    void setDirectEntityIds(std::vector<EntityId> entity_ids);
178

179
    /**
180
     * @brief Create a new row selector of the same concrete type, filtered to a subset of rows.
181
     *
182
     * @param keep_indices Indices of rows to keep (relative to this table's current rows), in ascending order.
183
     * @return A new row selector that preserves the original selector's semantics while containing only the kept rows.
184
     */
185
    [[nodiscard]] auto cloneRowSelectorFiltered(std::vector<size_t> const & keep_indices) const -> std::unique_ptr<IRowSelector>;
186

187
    /**
188
     * @brief Access the data manager extension backing this table.
189
     * @return Shared pointer to the `DataManagerExtension`.
190
     */
191
    [[nodiscard]] auto getDataManagerExtension() const -> std::shared_ptr<DataManagerExtension> { return m_dataManager; }
2✔
192

193
private:
194
    friend class TableViewBuilder;
195
    // Grant friend access to the templated Column class
196
    template<SupportedColumnType T>
197
    friend class Column;
198

199
    /**
200
     * @brief Private constructor for TableViewBuilder.
201
     * @param rowSelector The row selector defining table rows.
202
     * @param dataManager The data manager for accessing data sources.
203
     */
204
    TableView(std::unique_ptr<IRowSelector> rowSelector,
205
              std::shared_ptr<DataManagerExtension> dataManager);
206

207
    /**
208
     * @brief Gets or creates the ExecutionPlan for a given data source.
209
     * 
210
     * This method is critical for the caching system. It checks the plan cache
211
     * first, and if not found, uses the IRowSelector to generate the necessary
212
     * indices for the given data source, then stores the new plan in the cache.
213
     * 
214
     * @param sourceName The name of the data source (e.g., "LFP", "Spikes.x").
215
     * @return Reference to the ExecutionPlan for the source.
216
     */
217
    [[nodiscard]] auto getExecutionPlanFor(std::string const & sourceName) -> ExecutionPlan const &;
218

219
    /**
220
     * @brief Adds a column to the table.
221
     * @param column Shared pointer to the column to add.
222
     * @throws std::runtime_error if a column with the same name already exists.
223
     */
224
    void addColumn(std::shared_ptr<IColumn> column);
225

226
    /**
227
     * @brief Materializes a column and its dependencies.
228
     * 
229
     * This method ensures that all dependencies are materialized before
230
     * materializing the target column. It handles circular dependency detection.
231
     * 
232
     * @param columnName The name of the column to materialize.
233
     * @param materializing Set of columns currently being materialized (for cycle detection).
234
     */
235
    void materializeColumn(std::string const & columnName, std::set<std::string> & materializing);
236

237
    /**
238
     * @brief Generates an ExecutionPlan for a specific data source.
239
     * 
240
     * This method uses the row selector to create the appropriate ExecutionPlan
241
     * based on the type of row selector and the requirements of the data source.
242
     * 
243
     * @param sourceName The name of the data source.
244
     * @return The generated ExecutionPlan.
245
     */
246
    [[nodiscard]] auto generateExecutionPlan(std::string const & sourceName) -> ExecutionPlan;
247

248
    std::unique_ptr<IRowSelector> m_rowSelector;
249
    std::shared_ptr<DataManagerExtension> m_dataManager;
250
    std::vector<std::shared_ptr<IColumn>> m_columns;
251
    std::map<std::string, size_t> m_colNameToIndex;
252

253
    // Caches ExecutionPlans, keyed by data source name
254
    std::map<std::string, ExecutionPlan> m_planCache;
255
    
256
    // Direct EntityId storage for transformed tables
257
    std::vector<EntityId> m_direct_entity_ids;
258
};
259

260
// Template method implementation for getColumnValues
261
template<SupportedColumnType T>
262
auto TableView::getColumnValues(std::string const & name) -> std::vector<T> const & {
293✔
263
    // 1. Find the IColumn pointer by name
264
    auto it = m_colNameToIndex.find(name);
293✔
265
    if (it == m_colNameToIndex.end()) {
293✔
266
        throw std::runtime_error("Column '" + name + "' not found in table");
×
267
    }
268

269
    // 2. Get the column and attempt dynamic_cast to Column<T>
270
    auto & column = m_columns[it->second];
293✔
271
    auto * typedColumn = dynamic_cast<Column<T> *>(column.get());
293✔
272

273
    // 3. If cast fails, throw exception for type mismatch
274
    if (!typedColumn) {
293✔
275
        throw std::runtime_error("Column '" + name + "' is not of the requested type");
×
276
    }
277

278
    // 4. Call getValues on the typed column
279
    return typedColumn->getValues(this);
586✔
280
}
281

282
// Template method implementation for visitColumnData
283
template<typename Visitor>
284
auto TableView::visitColumnData(std::string const & name, Visitor&& visitor) -> decltype(auto) {
118✔
285
    auto variant = getColumnDataVariant(name);
118✔
286
    return std::visit(std::forward<Visitor>(visitor), variant);
236✔
287
}
118✔
288

289
#endif// TABLE_VIEW_H
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