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

paulmthompson / WhiskerToolbox / 17270491352

27 Aug 2025 02:57PM UTC coverage: 65.333%. Remained the same
17270491352

push

github

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

352 of 628 new or added lines in 92 files covered. (56.05%)

357 existing lines in 24 files now uncovered.

26429 of 40453 relevant lines covered (65.33%)

1119.34 hits per line

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

37.5
/src/DataManager/DigitalTimeSeries/Digital_Interval_Series.cpp
1
#include "Digital_Interval_Series.hpp"
2
#include "Entity/EntityRegistry.hpp"
3

4
#include <algorithm>
5
#include <utility>  
6
#include <vector>
7

8
// ========== Constructors ==========
9

10
DigitalIntervalSeries::DigitalIntervalSeries(std::vector<Interval> digital_vector) {
93✔
11
    _data = std::move(digital_vector);
93✔
12
    _sortData();
93✔
13
}
93✔
14

15
DigitalIntervalSeries::DigitalIntervalSeries(std::vector<std::pair<float, float>> const & digital_vector) {
1✔
16
    std::vector<Interval> intervals;
1✔
17
    intervals.reserve(digital_vector.size());
1✔
18
    for (auto & interval: digital_vector) {
6✔
19
        intervals.emplace_back(Interval{static_cast<int64_t>(interval.first), static_cast<int64_t>(interval.second)});
5✔
20
    }
21
    _data = std::move(intervals);
1✔
22
    _sortData();
1✔
23
}
2✔
24

25
// ========== Getters ==========
26

27
std::vector<Interval> const & DigitalIntervalSeries::getDigitalIntervalSeries() const {
70✔
28
    return _data;
70✔
29
}
30

31
bool DigitalIntervalSeries::isEventAtTime(TimeFrameIndex const time) const {
×
32

33
    auto Contained = [time](auto const & event) {
×
34
        return is_contained(event, time.getValue());
×
35
    };
×
36

37
    if (std::ranges::any_of(_data, Contained)) return true;
×
38

39
    return false;
×
40
}
41

42
void DigitalIntervalSeries::addEvent(Interval new_interval) {
338✔
43
    _addEvent(new_interval);
338✔
44

45
    notifyObservers();
338✔
46
}
338✔
47

48
void DigitalIntervalSeries::_addEvent(Interval new_interval) {
338✔
49
    auto it = _data.begin();
338✔
50
    while (it != _data.end()) {
809✔
51
        if (is_overlapping(*it, new_interval) || is_contiguous(*it, new_interval)) {
471✔
52
            new_interval.start = std::min(new_interval.start, it->start);
12✔
53
            new_interval.end = std::max(new_interval.end, it->end);
12✔
54
            it = _data.erase(it);
12✔
55
        } else if (is_contained(new_interval, *it)) {
459✔
56
            // The new interval is completely contained within an existing interval, so we do nothing.
UNCOV
57
            return;
×
58
        } else {
59
            ++it;
459✔
60
        }
61
    }
62
    _data.push_back(new_interval);
338✔
63
    _sortData();
338✔
64
}
65

66
void DigitalIntervalSeries::setEventAtTime(TimeFrameIndex time, bool const event) {
×
UNCOV
67
    _setEventAtTime(time, event);
×
68
    notifyObservers();
×
69
}
×
70

71
bool DigitalIntervalSeries::removeInterval(Interval const & interval) {
×
72
    auto it = std::find(_data.begin(), _data.end(), interval);
×
73
    if (it != _data.end()) {
×
UNCOV
74
        _data.erase(it);
×
75
        notifyObservers();
×
UNCOV
76
        return true;
×
77
    }
78
    return false;
×
79
}
80

81
size_t DigitalIntervalSeries::removeIntervals(std::vector<Interval> const & intervals) {
×
82
    size_t removed_count = 0;
×
83
    
84
    for (auto const & interval : intervals) {
×
85
        auto it = std::find(_data.begin(), _data.end(), interval);
×
UNCOV
86
        if (it != _data.end()) {
×
UNCOV
87
            _data.erase(it);
×
UNCOV
88
            removed_count++;
×
89
        }
90
    }
91
    
UNCOV
92
    if (removed_count > 0) {
×
UNCOV
93
        _sortData();  // Re-sort after removals
×
94
        notifyObservers();
×
95
    }
96
    
97
    return removed_count;
×
98
}
99

UNCOV
100
void DigitalIntervalSeries::_setEventAtTime(TimeFrameIndex time, bool const event) {
×
101
    if (!event) {
×
UNCOV
102
        _removeEventAtTime(time);
×
103
    } else {
UNCOV
104
        _addEvent(Interval{time.getValue(), time.getValue()});
×
105
    }
106
}
×
107

108
void DigitalIntervalSeries::_removeEventAtTime(TimeFrameIndex const time) {
×
109
    for (auto it = _data.begin(); it != _data.end(); ++it) {
×
110
        if (is_contained(*it, time.getValue())) {
×
111
            if (time.getValue() == it->start && time.getValue() == it->end) {
×
112
                _data.erase(it);
×
113
            } else if (time.getValue() == it->start) {
×
UNCOV
114
                it->start = time.getValue() + 1;
×
115
            } else if (time.getValue() == it->end) {
×
116
                it->end = time.getValue() - 1;
×
117
            } else {
118
                auto preceding_event = Interval{it->start, time.getValue() - 1};
×
119
                auto following_event = Interval{time.getValue() + 1, it->end};
×
UNCOV
120
                _data.erase(it);
×
121
                _data.push_back(preceding_event);
×
UNCOV
122
                _data.push_back(following_event);
×
123

UNCOV
124
                _sortData();
×
125
            }
UNCOV
126
            return;
×
127
        }
128
    }
129
}
130

131
void DigitalIntervalSeries::_sortData() {
432✔
132
    std::sort(_data.begin(), _data.end());
432✔
133
}
432✔
134

135
void DigitalIntervalSeries::rebuildAllEntityIds() {
1✔
136
    if (!_identity_registry) {
1✔
UNCOV
137
        _entity_ids.assign(_data.size(), 0);
×
UNCOV
138
        return;
×
139
    }
140
    _entity_ids.clear();
1✔
141
    _entity_ids.reserve(_data.size());
1✔
142
    for (size_t i = 0; i < _data.size(); ++i) {
6✔
143
        // Use start as the discrete time index representative, and i as stable local index
144
        _entity_ids.push_back(
5✔
145
            _identity_registry->ensureId(_identity_data_key, EntityKind::IntervalEntity, TimeFrameIndex{_data[i].start}, static_cast<int>(i))
5✔
146
        );
147
    }
148
}
149

UNCOV
150
int find_closest_preceding_event(DigitalIntervalSeries * digital_series, TimeFrameIndex time) {
×
151
    auto const & events = digital_series->getDigitalIntervalSeries();
×
152

153
    // Check if sorted
NEW
154
    for (size_t i = 1; i < events.size(); ++i) {
×
UNCOV
155
        if (events[i].start < events[i - 1].start) {
×
156
            throw std::runtime_error("DigitalIntervalSeries is not sorted");
×
157
        }
158
    }
159
    int closest_index = -1;
×
NEW
160
    for (size_t i = 0; i < events.size(); ++i) {
×
161
        if (events[i].start <= time.getValue()) {
×
NEW
162
            closest_index = static_cast<int>(i);
×
UNCOV
163
            if (time.getValue() <= events[i].end) {
×
NEW
164
                return static_cast<int>(i);
×
165
            }
166
        } else {
167
            break;
×
168
        }
169
    }
UNCOV
170
    return closest_index;
×
171
}
172

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