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

paulmthompson / WhiskerToolbox / 18685379784

21 Oct 2025 01:25PM UTC coverage: 72.522% (+0.1%) from 72.391%
18685379784

push

github

paulmthompson
fix failing tests

18 of 40 new or added lines in 1 file covered. (45.0%)

1765 existing lines in 32 files now uncovered.

53998 of 74457 relevant lines covered (72.52%)

46177.73 hits per line

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

87.5
/src/DataManager/utils/map_timeseries.hpp
1
#ifndef MAP_TIMESERIES_HPP
2
#define MAP_TIMESERIES_HPP
3

4
#include "TimeFrame/TimeFrame.hpp"
5

6
#include <map>
7
#include <vector>
8
#include <algorithm>
9
#include <ranges>
10
#include <unordered_set>
11

12
template<typename T>
13
[[nodiscard]] bool clear_at_time(TimeFrameIndex const time, T & data) {
×
14
    auto it = data.find(time);
×
15
    if (it != data.end()) {
×
16
        data.erase(it);
×
UNCOV
17
        return true;
×
18
    }
UNCOV
19
    return false;
×
20
}
21

22
template<typename T>
23
[[nodiscard]] bool clear_at_time(TimeFrameIndex const time, size_t const index, T & data) {
24
    auto it = data.find(time);
25
    if (it != data.end()) {
26
        if (index >= it->second.size()) {
27
            return false;
28
        }
29
        it->second.erase(it->second.begin() + static_cast<std::ptrdiff_t>(index));
30
        return true;
31
    }
32
    return false;
33
}
34

35
template<typename T, typename M> 
36
void add_at_time(TimeFrameIndex const time, T const & data, M & data_map) {
37
    data_map[time].push_back(data);
38
}
39

40
template<typename T, typename M>
41
[[nodiscard]] std::vector<T> const & get_at_time(TimeFrameIndex const time, M const & data, std::vector<T> const & empty) {
42
    auto it = data.find(time);
43
    if (it != data.end()) {
44
        return it->second;
45
    }
46
    return empty;
47
}
48

49
template<typename T, typename M>
50
[[nodiscard]] std::vector<T> const & get_at_time(TimeFrameIndex const time, 
51
                                                M const & data, 
52
                                                std::vector<T> const & empty, 
53
                                                TimeFrame const * source_timeframe, 
54
                                                TimeFrame const * target_timeframe) {
55

56
    // If the timeframes are the same object, no conversion is needed
57
    if (source_timeframe == target_timeframe) {
58
        return get_at_time(time, data, empty);
59
    }
60

61
    // If either timeframe is null, fall back to original behavior
62
    if (!source_timeframe || !target_timeframe) {
63
        return get_at_time(time, data, empty);
64
    }
65

66
    // Convert the time index from source timeframe to target timeframe
67
    // 1. Get the time value from the source timeframe
68
    auto time_value = source_timeframe->getTimeAtIndex(time);
69
    
70
    // 2. Convert that time value to an index in the target timeframe  
71
    auto target_index = target_timeframe->getIndexAtTime(static_cast<float>(time_value));
72

73
    return get_at_time(target_index, data, empty);
74
}
75

76

77
// Convert a time index between timeframes; falls back to original when null/equal
78
inline TimeFrameIndex convert_time_index(TimeFrameIndex const time,
25✔
79
                                         TimeFrame const * source_timeframe,
80
                                         TimeFrame const * target_timeframe) {
81
    if (source_timeframe == target_timeframe) {
25✔
82
        return time;
22✔
83
    }
84
    if (!source_timeframe || !target_timeframe) {
3✔
85
        return time;
1✔
86
    }
87
    auto const time_value = source_timeframe->getTimeAtIndex(time);
2✔
88
    auto const target_index = target_timeframe->getIndexAtTime(static_cast<float>(time_value));
2✔
89
    return target_index;
2✔
90
}
91

92
// Fill an output vector by extracting a field from a vector of entries
93
template <typename Entry, typename Out, typename Extractor>
94
inline void fill_extracted_vector(std::vector<Entry> const & entries,
95
                                  std::vector<Out> & out,
96
                                  Extractor extractor) {
97
    out.clear();
98
    out.reserve(entries.size());
99
    for (auto const & entry : entries) {
100
        out.push_back(extractor(entry));
101
    }
102
}
103

104
// Template function for moving entries by EntityIds (unordered_set variant for O(1) lookups)
105
template <typename SourceDataMap, typename TargetType, typename DataExtractor>
106
inline std::size_t move_by_entity_ids(SourceDataMap & source_data,
11✔
107
                                      TargetType & target,
108
                                      std::unordered_set<EntityId> const & entity_ids_set,
109
                                      bool const notify,
110
                                      DataExtractor extract_data) {
111
    std::size_t total_moved = 0;
11✔
112
    std::vector<std::pair<TimeFrameIndex, size_t>> entries_to_remove;
11✔
113

114
    for (auto const & [time, entries] : source_data) {
39✔
115
        for (size_t i = 0; i < entries.size(); ++i) {
65✔
116
            auto const & entry = entries[i];
37✔
117
            if (entity_ids_set.contains(entry.entity_id)) {
37✔
118
                target.addEntryAtTime(time, extract_data(entry), entry.entity_id, false);
16✔
119
                entries_to_remove.emplace_back(time, i);
16✔
120
                total_moved++;
16✔
121
            }
122
        }
123
    }
124

125
    std::ranges::sort(entries_to_remove,
11✔
126
                      [](auto const & a, auto const & b) {
8✔
127
                          if (a.first != b.first) return a.first > b.first;
8✔
128
                          return a.second > b.second;
5✔
129
                      });
130

131
    for (auto const & [time, index] : entries_to_remove) {
27✔
132
        auto it = source_data.find(time);
16✔
133
        if (it != source_data.end() && index < it->second.size()) {
16✔
134
            it->second.erase(it->second.begin() + static_cast<long>(index));
16✔
135
            if (it->second.empty()) {
16✔
136
                source_data.erase(it);
9✔
137
            }
138
        }
139
    }
140

141
    if (notify && total_moved > 0) {
11✔
142
        target.notifyObservers();
8✔
143
        // Note: Source notification for the source container should be handled by the calling class
144
    }
145

146
    return total_moved;
11✔
147
}
11✔
148

149
// Copy entries by EntityIds (unordered_set variant for O(1) lookups)
150
template <typename SourceDataMap, typename TargetType, typename DataExtractor>
151
inline std::size_t copy_by_entity_ids(SourceDataMap const & source_data,
13✔
152
                                      TargetType & target,
153
                                      std::unordered_set<EntityId> const & entity_ids_set,
154
                                      bool const notify,
155
                                      DataExtractor extract_data) {
156
    std::size_t total_copied = 0;
13✔
157
    for (auto const & [time, entries] : source_data) {
42✔
158
        for (auto const & entry : entries) {
67✔
159
            if (entity_ids_set.contains(entry.entity_id)) {
38✔
160
                target.addAtTime(time, extract_data(entry), false);
16✔
161
                total_copied++;
16✔
162
            }
163
        }
164
    }
165
    if (notify && total_copied > 0) {
13✔
166
        target.notifyObservers();
8✔
167
    }
168
    return total_copied;
13✔
169
}
170

171

172
#endif // MAP_TIMESERIES_HPP
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