• 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

91.18
/src/DataManager/utils/TableView/computers/IntervalOverlapComputer.h
1
#ifndef INTERVAL_OVERLAP_COMPUTER_H
2
#define INTERVAL_OVERLAP_COMPUTER_H
3

4
#include "utils/TableView/core/ExecutionPlan.h"
5
#include "utils/TableView/interfaces/IColumnComputer.h"
6
#include "utils/TableView/interfaces/IIntervalSource.h"
7

8
#include <cstdint>
9
#include <memory>
10
#include <string>
11
#include <vector>
12

13
/**
14
 * @brief Enumeration of operations that can be performed on interval overlaps.
15
 */
16
enum class IntervalOverlapOperation : std::uint8_t {
17
    AssignID,       ///< Assigns the index of the column interval that contains/overlaps with the row interval
18
    CountOverlaps,   ///< Counts the number of column intervals that overlap with each row interval
19
    AssignID_Start,  ///< Finds the start index of the column interval that contains/overlaps with the row interval
20
    AssignID_End     ///< Finds the end index of the column interval that contains/overlaps with the row interval
21
};
22

23
/**
24
* @brief Checks if two intervals overlap.
25
* @param a First interval.
26
* @param b Second interval.
27
* @return True if intervals overlap, false otherwise.
28
*/
29
[[nodiscard]] bool intervalsOverlap(TimeFrameInterval const & a, TimeFrameInterval const & b);
30

31
/**
32
* @brief Finds the index of the column interval that contains the given row interval.
33
* @param rowInterval The row interval to find a container for.
34
* @param columnIntervals The column intervals to search through.
35
* @return Index of the containing column interval, or -1 if none found.
36
*/
37
[[nodiscard]] int64_t findContainingInterval(TimeFrameInterval const & rowInterval,
38
                                             std::vector<Interval> const & columnIntervals);
39

40
/**
41
* @brief Counts the number of column intervals that overlap with the given row interval.
42
* @param rowInterval The row interval to check overlaps for.
43
* @param columnIntervals The column intervals to check against.
44
* @param sourceTimeFrame The timeframe for the column intervals.
45
* @param destinationTimeFrame The timeframe for the row interval.
46
* @return Number of overlapping column intervals.
47
*/
48
[[nodiscard]] int64_t countOverlappingIntervals(TimeFrameInterval const & rowInterval,
49
                                                std::vector<Interval> const & columnIntervals,
50
                                                TimeFrame const * sourceTimeFrame,
51
                                                TimeFrame const * destinationTimeFrame);
52

53
/**
54
 * @brief Templated computer for analyzing overlaps between row intervals and column intervals.
55
 * 
56
 * Source type: IIntervalSource
57
 * Selector type: Interval
58
 * Output type: T
59
 * 
60
 * This computer works with two sets of intervals: the row intervals (from the ExecutionPlan)
61
 * and the column intervals (from an IIntervalSource). It can perform different operations
62
 * to analyze their relationships:
63
 * - AssignID: For each row interval, finds the index of the column interval that contains it
64
 * - CountOverlaps: For each row interval, counts how many column intervals overlap with it
65
 * 
66
 * The template parameter T determines the return type:
67
 * - IntervalOverlapOperation::AssignID requires T = int64_t (returns -1 if no overlap)
68
 * - IntervalOverlapOperation::CountOverlaps requires T = int64_t or size_t
69
 */
70
template<typename T>
71
class IntervalOverlapComputer : public IColumnComputer<T> {
72
public:
73
    /**
74
     * @brief Constructor for IntervalOverlapComputer.
75
     * @param source Shared pointer to the interval source (column intervals).
76
     * @param operation The operation to perform on interval overlaps.
77
     * @param sourceName The name of the data source (for dependency tracking).
78
     */
79
    IntervalOverlapComputer(std::shared_ptr<IIntervalSource> source,
39✔
80
                            IntervalOverlapOperation operation,
81
                            std::string sourceName)
82
        : m_source(std::move(source)),
39✔
83
          m_operation(operation),
39✔
84
          m_sourceName(std::move(sourceName)) {}
78✔
85

86
    /**
87
     * @brief Computes the result for all row intervals in the execution plan.
88
     * @param plan The execution plan containing row interval boundaries.
89
     * @return Vector of computed results for each row interval.
90
     */
91
    [[nodiscard]] auto compute(ExecutionPlan const & plan) const -> std::vector<T> override {
32✔
92
        if (!plan.hasIntervals()) {
32✔
93
            throw std::runtime_error("IntervalOverlapComputer requires an ExecutionPlan with intervals");
1✔
94
        }
95

96
        auto rowIntervals = plan.getIntervals();
31✔
97
        auto destinationTimeFrame = plan.getTimeFrame();
31✔
98
        auto sourceTimeFrame = m_source->getTimeFrame();
31✔
99

100
        std::vector<T> results;
31✔
101
        results.reserve(rowIntervals.size());
31✔
102
        if (m_operation == IntervalOverlapOperation::AssignID ||
31✔
103
            m_operation == IntervalOverlapOperation::AssignID_Start ||
17✔
104
            m_operation == IntervalOverlapOperation::AssignID_End) {
16✔
105
                for (auto const & rowInterval: rowIntervals) {
108✔
106
                    auto columnIntervals = m_source->getIntervalsInRange(
92✔
107
                        TimeFrameIndex(0), 
108
                        rowInterval.end, 
109
                        destinationTimeFrame.get());
46✔
110
                    if (columnIntervals.empty()) {
46✔
111
                        results.push_back(static_cast<T>(-1));
3✔
112
                        continue;
3✔
113
                    }
114
                    // Need to convert to their time coordinates
115
                    auto source_start = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnIntervals.back().start));
43✔
116
                    auto source_end = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnIntervals.back().end));
43✔
117
                    auto destination_start = destinationTimeFrame->getTimeAtIndex(rowInterval.start);
43✔
118
                    auto destination_end = destinationTimeFrame->getTimeAtIndex(rowInterval.end);
43✔
119

120
                    if (source_start <= destination_end && destination_start <= source_end) {
43✔
121

122
                        if (m_operation == IntervalOverlapOperation::AssignID_Start) {
38✔
123
                            // Convert into row time frame
124
                            auto source_start_index = destinationTimeFrame->getIndexAtTime(static_cast<float>(source_start));
4✔
125
                            results.push_back(static_cast<T>(source_start_index.getValue()));
4✔
126
                        } else if (m_operation == IntervalOverlapOperation::AssignID_End) {
34✔
127
                            // Convert into row time frame
128
                            auto source_end_index = destinationTimeFrame->getIndexAtTime(static_cast<float>(source_end));
4✔
129
                            results.push_back(static_cast<T>(source_end_index.getValue()));
4✔
130
                        } else {
131
                            results.push_back(static_cast<T>(columnIntervals.size() - 1));
30✔
132
                        }
133
                    } else {
38✔
134
                        results.push_back(static_cast<T>(-1));
5✔
135
                    }
136
                }
137
        } else if (m_operation == IntervalOverlapOperation::CountOverlaps) {
15✔
138
            for (auto const & rowInterval: rowIntervals) {
93✔
139
                auto columnIntervals = m_source->getIntervalsInRange(
78✔
140
                    rowInterval.start, 
141
                    rowInterval.end, 
142
                    destinationTimeFrame.get());
39✔
143

144
                results.push_back(static_cast<T>(countOverlappingIntervals(rowInterval, columnIntervals, sourceTimeFrame.get(), destinationTimeFrame.get())));
39✔
145
            }
146
        }
147

148
        return results;
62✔
149
    }
31✔
150

151
    [[nodiscard]] auto getSourceDependency() const -> std::string override {
97✔
152
        return m_sourceName;
97✔
153
    }
154

155
    [[nodiscard]] EntityIdStructure getEntityIdStructure() const override {
29✔
156
        switch (m_operation) {
29✔
157
            case IntervalOverlapOperation::AssignID:
12✔
158
            case IntervalOverlapOperation::AssignID_Start:
159
            case IntervalOverlapOperation::AssignID_End:
160
                return EntityIdStructure::Simple;  // One EntityID per row (the assigned interval)
12✔
161
            case IntervalOverlapOperation::CountOverlaps:
17✔
162
                return EntityIdStructure::Complex; // Multiple EntityIDs per row (all overlapping intervals)
17✔
UNCOV
163
            default:
×
UNCOV
164
                return EntityIdStructure::None;
×
165
        }
166
    }
167

168
    [[nodiscard]] ColumnEntityIds computeColumnEntityIds(ExecutionPlan const & plan) const override {
25✔
169
        if (!plan.hasIntervals()) {
25✔
UNCOV
170
            throw std::runtime_error("IntervalOverlapComputer requires an ExecutionPlan with intervals");
×
171
        }
172

173
        auto rowIntervals = plan.getIntervals();
25✔
174
        auto destinationTimeFrame = plan.getTimeFrame();
25✔
175
        auto sourceTimeFrame = m_source->getTimeFrame();
25✔
176

177
        switch (m_operation) {
25✔
178
            case IntervalOverlapOperation::AssignID:
10✔
179
            case IntervalOverlapOperation::AssignID_Start:
180
            case IntervalOverlapOperation::AssignID_End: {
181
                // Simple structure: one EntityID per row
182
                std::vector<EntityId> result;
10✔
183
                result.reserve(rowIntervals.size());
10✔
184
                
185
                for (auto const & rowInterval : rowIntervals) {
90✔
186
                    auto columnIntervals = m_source->getIntervalsInRange(
80✔
187
                        TimeFrameIndex(0), 
188
                        rowInterval.end, 
189
                        destinationTimeFrame.get());
40✔
190
                    
191
                    if (columnIntervals.empty()) {
40✔
UNCOV
192
                        result.push_back(0); // No overlapping interval
×
UNCOV
193
                        continue;
×
194
                    }
195
                    
196
                    // Check if the last interval overlaps
197
                    auto source_start = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnIntervals.back().start));
40✔
198
                    auto source_end = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnIntervals.back().end));
40✔
199
                    auto destination_start = destinationTimeFrame->getTimeAtIndex(rowInterval.start);
40✔
200
                    auto destination_end = destinationTimeFrame->getTimeAtIndex(rowInterval.end);
40✔
201

202
                    if (source_start <= destination_end && destination_start <= source_end) {
40✔
203
                        // Get EntityID of the overlapping interval
204
                        size_t interval_index = columnIntervals.size() - 1;
40✔
205
                        EntityId entityId = m_source->getEntityIdAt(interval_index);
40✔
206
                        result.push_back(entityId);
40✔
207
                    } else {
UNCOV
208
                        result.push_back(0); // No overlap
×
209
                    }
210
                }
211
                
212
                return result;
10✔
213
            }
10✔
214
            
215
            case IntervalOverlapOperation::CountOverlaps: {
15✔
216
                // Complex structure: multiple EntityIDs per row
217
                std::vector<std::vector<EntityId>> result;
15✔
218
                result.reserve(rowIntervals.size());
15✔
219
                
220
                for (auto const & rowInterval : rowIntervals) {
135✔
221
                    auto columnIntervals = m_source->getIntervalsInRange(
120✔
222
                        rowInterval.start, 
223
                        rowInterval.end, 
224
                        destinationTimeFrame.get());
60✔
225
                    
226
                    std::vector<EntityId> row_entities;
60✔
227
                    
228
                    // Find all overlapping intervals and collect their EntityIDs
229
                    for (size_t i = 0; i < columnIntervals.size(); ++i) {
120✔
230
                        auto const & columnInterval = columnIntervals[i];
60✔
231
                        
232
                        // Check for overlap
233
                        auto source_start = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnInterval.start));
60✔
234
                        auto source_end = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnInterval.end));
60✔
235
                        auto destination_start = destinationTimeFrame->getTimeAtIndex(rowInterval.start);
60✔
236
                        auto destination_end = destinationTimeFrame->getTimeAtIndex(rowInterval.end);
60✔
237
                        
238
                        if (source_start <= destination_end && destination_start <= source_end) {
60✔
239
                            EntityId entityId = m_source->getEntityIdAt(i);
60✔
240
                            if (entityId != 0) {
60✔
UNCOV
241
                                row_entities.push_back(entityId);
×
242
                            }
243
                        }
244
                    }
245
                    
246
                    result.push_back(std::move(row_entities));
60✔
247
                }
248
                
249
                return result;
15✔
250
            }
15✔
251
            
UNCOV
252
            default:
×
UNCOV
253
                return std::monostate{};
×
254
        }
255
    }
25✔
256

257
private:
258
    std::shared_ptr<IIntervalSource> m_source;
259
    IntervalOverlapOperation m_operation;
260
    std::string m_sourceName;
261
};
262

263

264
#endif// INTERVAL_OVERLAP_COMPUTER_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