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

paulmthompson / WhiskerToolbox / 17920603410

22 Sep 2025 03:39PM UTC coverage: 71.97% (-0.05%) from 72.02%
17920603410

push

github

paulmthompson
all tests pass

277 of 288 new or added lines in 8 files covered. (96.18%)

520 existing lines in 35 files now uncovered.

40275 of 55961 relevant lines covered (71.97%)

1225.8 hits per line

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

95.45
/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 Helper function to check if a column interval overlaps with a row interval using absolute time coordinates.
33
* @param rowInterval The row interval to check against.
34
* @param columnInterval The column interval to check.
35
* @param sourceTimeFrame The timeframe for the column interval.
36
* @param destinationTimeFrame The timeframe for the row interval.
37
* @return True if intervals overlap, false otherwise.
38
*/
39
[[nodiscard]] bool intervalsOverlapInAbsoluteTime(TimeFrameInterval const & rowInterval,
40
                                                 Interval const & columnInterval,
41
                                                 TimeFrame const * sourceTimeFrame,
42
                                                 TimeFrame const * destinationTimeFrame);
43

44
/**
45
* @brief Finds the index of the column interval that contains the given row interval.
46
* @param rowInterval The row interval to find a container for.
47
* @param columnIntervals The column intervals to search through.
48
* @return Index of the containing column interval, or -1 if none found.
49
*/
50
[[nodiscard]] int64_t findContainingInterval(TimeFrameInterval const & rowInterval,
51
                                             std::vector<Interval> const & columnIntervals);
52

53
/**
54
* @brief Counts the number of column intervals that overlap with the given row interval.
55
* @param rowInterval The row interval to check overlaps for.
56
* @param columnIntervals The column intervals to check against.
57
* @param sourceTimeFrame The timeframe for the column intervals.
58
* @param destinationTimeFrame The timeframe for the row interval.
59
* @return Number of overlapping column intervals.
60
*/
61
[[nodiscard]] int64_t countOverlappingIntervals(TimeFrameInterval const & rowInterval,
62
                                                std::vector<Interval> const & columnIntervals,
63
                                                TimeFrame const * sourceTimeFrame,
64
                                                TimeFrame const * destinationTimeFrame);
65

66
/**
67
* @brief Counts the number of column intervals that overlap with the given row interval and returns their EntityIDs.
68
* @param rowInterval The row interval to check overlaps for.
69
* @param columnIntervalsWithIds The column intervals with their EntityIDs to check against.
70
* @param sourceTimeFrame The timeframe for the column intervals.
71
* @param destinationTimeFrame The timeframe for the row interval.
72
* @return Pair of count and vector of EntityIDs of overlapping intervals.
73
*/
74
[[nodiscard]] std::pair<int64_t, std::vector<EntityId>> countOverlappingIntervalsWithIds(TimeFrameInterval const & rowInterval,
75
                                                                                         std::vector<IntervalWithId> const & columnIntervalsWithIds,
76
                                                                                         TimeFrame const * sourceTimeFrame,
77
                                                                                         TimeFrame const * destinationTimeFrame);
78

79
/**
80
 * @brief Templated computer for analyzing overlaps between row intervals and column intervals.
81
 * 
82
 * Source type: IIntervalSource
83
 * Selector type: Interval
84
 * Output type: T
85
 * 
86
 * This computer works with two sets of intervals: the row intervals (from the ExecutionPlan)
87
 * and the column intervals (from an IIntervalSource). It can perform different operations
88
 * to analyze their relationships:
89
 * - AssignID: For each row interval, finds the index of the column interval that contains it
90
 * - CountOverlaps: For each row interval, counts how many column intervals overlap with it
91
 * 
92
 * The template parameter T determines the return type:
93
 * - IntervalOverlapOperation::AssignID requires T = int64_t (returns -1 if no overlap)
94
 * - IntervalOverlapOperation::CountOverlaps requires T = int64_t or size_t
95
 */
96
template<typename T>
97
class IntervalOverlapComputer : public IColumnComputer<T> {
98
public:
99
    /**
100
     * @brief Constructor for IntervalOverlapComputer.
101
     * @param source Shared pointer to the interval source (column intervals).
102
     * @param operation The operation to perform on interval overlaps.
103
     * @param sourceName The name of the data source (for dependency tracking).
104
     */
105
    IntervalOverlapComputer(std::shared_ptr<IIntervalSource> source,
39✔
106
                            IntervalOverlapOperation operation,
107
                            std::string sourceName)
108
        : m_source(std::move(source)),
39✔
109
          m_operation(operation),
39✔
110
          m_sourceName(std::move(sourceName)) {}
78✔
111

112
    /**
113
     * @brief Computes the result for all row intervals in the execution plan.
114
     * @param plan The execution plan containing row interval boundaries.
115
     * @return Vector of computed results for each row interval.
116
     */
117
    [[nodiscard]] std::pair<std::vector<T>, ColumnEntityIds> compute(ExecutionPlan const & plan) const override {
37✔
118
        if (!plan.hasIntervals()) {
37✔
119
            throw std::runtime_error("IntervalOverlapComputer requires an ExecutionPlan with intervals");
1✔
120
        }
121

122
        auto rowIntervals = plan.getIntervals();
36✔
123
        auto destinationTimeFrame = plan.getTimeFrame();
36✔
124
        auto sourceTimeFrame = m_source->getTimeFrame();
36✔
125

126
        std::vector<T> results;
36✔
127
        results.reserve(rowIntervals.size());
36✔
128
       
129
        //entity_ids.reserve(rowIntervals.size());
130
        if (m_operation == IntervalOverlapOperation::AssignID ||
36✔
131
            m_operation == IntervalOverlapOperation::AssignID_Start ||
20✔
132
            m_operation == IntervalOverlapOperation::AssignID_End) {
19✔
133

134
                std::vector<EntityId> entity_ids;
18✔
135
                for (auto const & rowInterval: rowIntervals) {
126✔
136
                    auto columnIntervalsWithIds = m_source->getIntervalsWithIdsInRange(
108✔
137
                        TimeFrameIndex(0), 
138
                        rowInterval.end, 
139
                        destinationTimeFrame.get());
54✔
140
                    if (columnIntervalsWithIds.empty()) {
54✔
141
                        results.push_back(static_cast<T>(-1));
3✔
142
                        entity_ids.push_back(0);
3✔
143
                        continue;
3✔
144
                    }
145
                    // Need to convert to their time coordinates
146
                    auto source_start = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnIntervalsWithIds.back().interval.start));
51✔
147
                    auto source_end = sourceTimeFrame->getTimeAtIndex(TimeFrameIndex(columnIntervalsWithIds.back().interval.end));
51✔
148
                    auto destination_start = destinationTimeFrame->getTimeAtIndex(rowInterval.start);
51✔
149
                    auto destination_end = destinationTimeFrame->getTimeAtIndex(rowInterval.end);
51✔
150

151
                    if (source_start <= destination_end && destination_start <= source_end) {
51✔
152

153
                        if (m_operation == IntervalOverlapOperation::AssignID_Start) {
46✔
154
                            // Convert into row time frame
155
                            auto source_start_index = destinationTimeFrame->getIndexAtTime(static_cast<float>(source_start));
4✔
156
                            results.push_back(static_cast<T>(source_start_index.getValue()));
4✔
157
                            entity_ids.push_back(columnIntervalsWithIds.back().entity_id);
4✔
158
                        } else if (m_operation == IntervalOverlapOperation::AssignID_End) {
42✔
159
                            // Convert into row time frame
160
                            auto source_end_index = destinationTimeFrame->getIndexAtTime(static_cast<float>(source_end));
4✔
161
                            results.push_back(static_cast<T>(source_end_index.getValue()));
4✔
162
                            entity_ids.push_back(columnIntervalsWithIds.back().entity_id);
4✔
163
                        } else {
164
                            results.push_back(static_cast<T>(columnIntervalsWithIds.size() - 1));
38✔
165
                            entity_ids.push_back(columnIntervalsWithIds.back().entity_id);
38✔
166
                        }
167
                    } else {
46✔
168
                        results.push_back(static_cast<T>(-1));
5✔
169
                        entity_ids.push_back(0);
5✔
170
                    }
171
                }
172

173
            return {results, entity_ids}; // std::vector<EntityId>
18✔
174

175
        } else if (m_operation == IntervalOverlapOperation::CountOverlaps) {
36✔
176

177
            std::vector<std::vector<EntityId>> entity_ids;
18✔
178

179
            for (auto const & rowInterval: rowIntervals) {
120✔
180
                auto columnIntervalsWithIds = m_source->getIntervalsWithIdsInRange(
102✔
181
                    rowInterval.start, 
182
                    rowInterval.end, 
183
                    destinationTimeFrame.get());
51✔
184

185
                auto [count, overlappingEntityIds] = countOverlappingIntervalsWithIds(rowInterval, 
102✔
186
                    columnIntervalsWithIds, 
187
                    sourceTimeFrame.get(), 
51✔
188
                    destinationTimeFrame.get());
51✔
189

190
                results.push_back(static_cast<T>(count));
51✔
191
                entity_ids.push_back(overlappingEntityIds);
51✔
192
            }
193

194
            return {results, entity_ids}; // std::vector<std::vector<EntityId>>
18✔
195
        }
18✔
196
        
197
        // This should never be reached, but provide a default return
UNCOV
198
        return {results, std::vector<EntityId>()};
×
199
    }
36✔
200

201
    [[nodiscard]] auto getSourceDependency() const -> std::string override {
77✔
202
        return m_sourceName;
77✔
203
    }
204

205
    [[nodiscard]] EntityIdStructure getEntityIdStructure() const override {
56✔
206
        switch (m_operation) {
56✔
207
            case IntervalOverlapOperation::AssignID:
18✔
208
            case IntervalOverlapOperation::AssignID_Start:
209
            case IntervalOverlapOperation::AssignID_End:
210
                return EntityIdStructure::Simple;  // One EntityID per row (the assigned interval)
18✔
211
                break;
212
            case IntervalOverlapOperation::CountOverlaps:
38✔
213
                return EntityIdStructure::Complex; // Multiple EntityIDs per row (all overlapping intervals)
38✔
214
                break;
UNCOV
215
            default:
×
UNCOV
216
                return EntityIdStructure::None;
×
217
        }
218
    }
219

220
private:
221
    std::shared_ptr<IIntervalSource> m_source;
222
    IntervalOverlapOperation m_operation;
223
    std::string m_sourceName;
224
};
225

226

227
#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