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

paulmthompson / WhiskerToolbox / 18117112849

30 Sep 2025 02:44AM UTC coverage: 70.161% (+0.03%) from 70.132%
18117112849

push

github

paulmthompson
hungarian algorithm is actually used

60 of 77 new or added lines in 2 files covered. (77.92%)

352 existing lines in 12 files now uncovered.

45125 of 64316 relevant lines covered (70.16%)

1116.85 hits per line

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

88.57
/src/DataManager/DataManager.hpp
1
#ifndef DATAMANAGER_HPP
2
#define DATAMANAGER_HPP
3

4
#include "DataManagerTypes.hpp"
5

6
#include "TimeFrame/StrongTimeTypes.hpp"
7
#include "TimeFrame/TimeFrame.hpp"
8

9
#include <filesystem>
10
#include <functional>   // std::function
11
#include <memory>       // std::shared_ptr
12
#include <optional>     // std::optional
13
#include <string>       // std::string
14
#include <unordered_map>// std::unordered_map
15
#include <variant>      // std::variant
16
#include <vector>       // std::vector
17

18
#include "nlohmann/json_fwd.hpp"
19

20
// Forward declarations for identity
21
class EntityRegistry;
22
class EntityGroupManager;
23

24
class TableRegistry;
25
struct TableEvent;
26

27
class DataManager {
28

29
public:
30
    DataManager();
31
    ~DataManager();
32
    // ======= Table Registry access =======
33
    /**
34
     * @brief Get the centralized TableRegistry owned by this DataManager
35
     */
36
    TableRegistry * getTableRegistry();
37
    TableRegistry const * getTableRegistry() const;
38

39
    // ======= Table observer channel (separate from data observers) =======
40
    using TableObserver = std::function<void(TableEvent const &)>;
41
    /**
42
     * @brief Subscribe to table events
43
     * @return Subscription id (>=1) or -1 on failure
44
     */
45
    [[nodiscard]] int addTableObserver(TableObserver callback);
46
    /**
47
     * @brief Unsubscribe from table events
48
     */
49
    bool removeTableObserver(int callback_id);
50

51
    /**
52
    * @brief Register a new temporal coordinate system with a unique key
53
    *
54
    * This function stores a TimeFrame object in the DataManager under the provided key.
55
    * The TimeFrame specifies the temporal coordinate system that can be assigned to data objects.
56
    *
57
    * @param key The unique identifier for this TimeFrame
58
    * @param timeframe The TimeFrame object to register
59
    * @return bool True if the TimeFrame was successfully registered, false otherwise
60
    *
61
    * @note If the key already exists or timeframe is nullptr, a warning message will be printed
62
    *       to std::cerr and the function will return false
63
    */
64
    bool setTime(TimeKey const & key, std::shared_ptr<TimeFrame> timeframe, bool overwrite = false);
65

66
    /**
67
    * @brief Get the default time frame object
68
    *
69
    * Returns the TimeFrame associated with the default "time" key.
70
    *
71
    * @return A shared pointer to the default TimeFrame object
72
    * @note This function always returns a valid pointer since the default TimeFrame
73
    *       is created in the constructor
74
    */
75
    [[nodiscard]] std::shared_ptr<TimeFrame> getTime();
76

77
    /**
78
    * @brief Get the time frame object for a specific key
79
    *
80
    * @param key The key to retrieve the TimeFrame for
81
    * @return A shared pointer to the TimeFrame if the key exists, nullptr otherwise
82
     */
83
    [[nodiscard]] std::shared_ptr<TimeFrame> getTime(TimeKey const & key);
84

85
    [[nodiscard]] TimeIndexAndFrame getCurrentIndexAndFrame(TimeKey const & key);
86

87
    bool removeTime(TimeKey const & key);
88

89
    /**
90
    * @brief Set the time key for a specific data key
91
    *
92
    * Associates a data object with a specific temporal coordinate system.
93
    *
94
    * @param data_key The data key to set the time key for
95
    * @param time_key The time key to associate with the data
96
    * @return bool True if the time frame was successfully set, false otherwise
97
    *
98
    * @note If data_key or time_key doesn't exist, an error message will be printed
99
    *       to std::cerr and the function will return false
100
    */
101
    bool setTimeKey(std::string const & data_key, TimeKey const & time_key);
102

103
    /**
104
    * @brief Get the time key for a specific data key
105
    *
106
    * Retrieves the TimeFrame key associated with a particular data object.
107
    *
108
    * @param data_key The data key to get the time frame for
109
    * @return The TimeKey, or empty string if an error occurred
110
    *
111
    * @note If data_key doesn't exist or doesn't have an associated TimeFrame,
112
    *       an error message will be printed to std::cerr and an empty string will be returned
113
    */
114
    [[nodiscard]] TimeKey getTimeKey(std::string const & data_key);
115

116
    /**
117
    * @brief Get all registered TimeFrame keys
118
    *
119
    * Retrieves a vector of all keys used for TimeFrame objects in the DataManager.
120
    *
121
    * @return A vector of strings containing all TimeFrame keys
122
    * @note The default "time" key will always be included in the returned vector
123
    */
124
    [[nodiscard]] std::vector<TimeKey> getTimeFrameKeys();
125

126
    /**
127
    * @brief Clear all data and reset DataManager to initial state
128
    *
129
    * This function removes all loaded data objects, TimeFrame objects (except the default "time" frame),
130
    * and clears all mappings between data keys and time frame keys. This is useful for batch processing
131
    * where you want to load different datasets with the same configuration.
132
    * 
133
    * The function will:
134
    * - Remove all data objects from _data
135
    * - Remove all TimeFrame objects except the default "time" frame
136
    * - Clear all data-to-timeframe mappings
137
    * - Remove all TimeFrameV2 objects and mappings
138
    * - Reset media data to default empty state
139
    * - Notify observers of the state change
140
    *
141
    * @note The default "time" TimeFrame and "media" data key are preserved but reset to empty state
142
    */
143
    void reset();
144

145

146
    int64_t getCurrentTime() { return _current_time; };
105✔
147
    void setCurrentTime(int64_t time) { _current_time = time; }
×
148

149
    using ObserverCallback = std::function<void()>;
150

151
    /**
152
    * @brief Add a callback function to a specific data object
153
    *
154
    * Registers a callback function that will be invoked when the specified data object changes.
155
    *
156
    * @param key The data key to attach the callback to
157
    * @param callback The function to call when the data changes
158
    * @return int A unique identifier for the callback (>= 0) or -1 if registration failed
159
    *
160
    * @note If the data key doesn't exist, the function returns -1
161
    */
162
    [[nodiscard]] int addCallbackToData(std::string const & key, ObserverCallback callback);
163

164
    /**
165
    * @brief Remove a callback from a specific data object
166
    *
167
    * Removes a previously registered callback using its unique identifier.
168
    *
169
    * @param key The data key from which to remove the callback
170
    * @param callback_id The unique identifier of the callback to remove
171
    * @return bool True if the callback was successfully removed, false if the key doesn't exist
172
    *
173
    * @note If the data key doesn't exist, the function returns false.
174
    *       The underlying removeObserver implementation determines what happens if the callback_id is invalid.
175
    */
176
    bool removeCallbackFromData(std::string const & key, int callback_id);
177

178
    /**
179
    * @brief Register a callback function for DataManager state changes
180
    *
181
    * Adds a callback function that will be invoked when the DataManager's state changes,
182
    * such as when data is added or modified.
183
    *
184
    * @param callback The function to call when the DataManager state changes
185
    *
186
    * @note Unlike addCallbackToData, this function doesn't return an ID,
187
    *       so callbacks cannot be selectively removed later
188
    */
189
    void addObserver(ObserverCallback callback);
190

191
    /**
192
    * @brief Get all registered data keys
193
    *
194
    * Retrieves a vector of all data object keys in the DataManager.
195
    *
196
    * @return A vector of strings containing all data keys
197
    *
198
    * @example
199
    * @code
200
    * DataManager dm;
201
    * dm.setData<PointData>("points1");
202
    * dm.setData<LineData>("line1");
203
    *
204
    * // Get all keys
205
    * auto keys = dm.getAllKeys(); // Returns ["media", "points1", "line1"]
206
    * @endcode
207
    */
208
    [[nodiscard]] std::vector<std::string> getAllKeys();
209

210
    /**
211
    * @brief Get all keys associated with a specific data type
212
    *
213
    * Retrieves a vector of all keys that correspond to data objects
214
    * of the specified template type T.
215
    *
216
    * @tparam T The data type to filter by (e.g., PointData, LineData)
217
    * @return A vector of strings containing all keys with data of type T
218
    *
219
    * @example
220
    * @code
221
    * DataManager dm;
222
    * dm.setData<PointData>("points1");
223
    * dm.setData<PointData>("points2");
224
    * dm.setData<LineData>("line1");
225
    *
226
    * // Get only keys for PointData objects
227
    * auto pointKeys = dm.getKeys<PointData>(); // Returns ["points1", "points2"]
228
    * @endcode
229
    */
230
    template<typename T>
231
    [[nodiscard]] std::vector<std::string> getKeys() {
465✔
232
        std::vector<std::string> keys;
465✔
233
        for (auto const & [key, value]: _data) {
3,596✔
234
            if (std::holds_alternative<std::shared_ptr<T>>(value)) {
3,131✔
235
                keys.push_back(key);
682✔
236
            }
237
        }
238
        return keys;
465✔
239
    }
×
240

241
    /**
242
    * @brief Get data as a variant type
243
    *
244
    * Retrieves data associated with the specified key as a variant wrapper,
245
    * allowing access without knowing the concrete type at compile time.
246
    *
247
    * @param key The key associated with the data to retrieve
248
    * @return An optional containing the data variant if the key exists, empty optional otherwise
249
    *
250
    */
251
    std::optional<DataTypeVariant> getDataVariant(std::string const & key);
252

253
    template<typename T>
254
    std::shared_ptr<T> getData(std::string const & key) {
2,939✔
255
        if (_data.find(key) != _data.end()) {
2,939✔
256
            return std::get<std::shared_ptr<T>>(_data[key]);
2,796✔
257
        }
258
        return nullptr;
143✔
259
    }
260

261
    template<typename T>
262
    void setData(std::string const & key, TimeKey const & time_key) {
44✔
263
        _data[key] = std::make_shared<T>();
44✔
264
        setTimeKey(key, time_key);
44✔
265

266
        //Rebuild the EntityIds
267
        if constexpr ((std::is_same_v<T, LineData>) ||
268
                      (std::is_same_v<T, PointData>) ||
269
                      (std::is_same_v<T, DigitalEventSeries>) ||
270
                      (std::is_same_v<T, DigitalIntervalSeries>) ) {
271
            //std::is_same_v<T, MaskData>) {
272
            std::get<std::shared_ptr<T>>(_data[key])->setIdentityContext(key, getEntityRegistry());
41✔
273
            std::get<std::shared_ptr<T>>(_data[key])->rebuildAllEntityIds();
41✔
274
        }
275
        _notifyObservers();
44✔
276
    }
44✔
277

278
    void setData(std::string const & key, DataTypeVariant data, TimeKey const & time_key);
279

280
    template<typename T>
281
    void setData(std::string const & key, std::shared_ptr<T> data, TimeKey const & time_key) {
908✔
282
        // Loop through all _data. If shared_ptr data is already in _data, return
283
        for (auto const & [existing_key, existing_variant]: _data) {
3,453✔
284
            bool found = std::visit([&data](auto const & existing_ptr) -> bool {
5,090✔
285
                using ExistingType = std::decay_t<decltype(*existing_ptr)>;
286
                using NewType = std::decay_t<decltype(*data)>;
287
                if constexpr (std::is_same_v<ExistingType, NewType>) {
288
                    return existing_ptr == data;
562✔
289
                } else {
290
                    return false;
1,983✔
291
                }
292
            },
293
                                    existing_variant);
294
            if (found) {
2,545✔
295
                std::cerr << "Data with key '" << key
UNCOV
296
                          << "' already exists, not setting again." << std::endl;
×
UNCOV
297
                return;// Data already exists, do not set again
×
298
            }
299
        }
300

301
        _data[key] = data;
908✔
302
        setTimeKey(key, time_key);
908✔
303

304
        if constexpr ((std::is_same_v<T, LineData>) ||
305
                      (std::is_same_v<T, PointData>) ||
306
                      (std::is_same_v<T, DigitalEventSeries>) ||
307
                      (std::is_same_v<T, DigitalIntervalSeries>) ) {
308
            //std::is_same_v<T, MaskData>) {
309
            std::get<std::shared_ptr<T>>(_data[key])->setIdentityContext(key, getEntityRegistry());
632✔
310
            std::get<std::shared_ptr<T>>(_data[key])->rebuildAllEntityIds();
632✔
311
        }
312

313
        _notifyObservers();
908✔
314
    }
315

316
    /**
317
     * @brief Delete data associated with the specified key
318
     * 
319
     * Removes the data object and its associated time frame mapping from the DataManager.
320
     * All observers are notified of the change, allowing dependent widgets to clean up.
321
     * 
322
     * @param key The key of the data to delete
323
     * @return bool True if the data was successfully deleted, false if the key doesn't exist
324
     * 
325
     * @note This method will:
326
     *       - Remove the data from the internal storage
327
     *       - Remove the time frame mapping for this data
328
     *       - Notify all observers of the change
329
     *       - The shared_ptr will be automatically cleaned up when no other references exist
330
     */
331
    bool deleteData(std::string const & key);
332

333
    [[nodiscard]] DM_DataType getType(std::string const & key) const;
334

335
    void setOutputPath(std::filesystem::path const & output_path) { _output_path = output_path; };
336

337
    [[nodiscard]] std::filesystem::path getOutputPath() const {
338
        return _output_path;
339
    }
340

341
    void notifyTableObservers(TableEvent const & ev);
342

343
    /**
344
     * @brief Access the session-scoped EntityRegistry.
345
     */
346
    [[nodiscard]] EntityRegistry * getEntityRegistry() const { return _entity_registry.get(); }
910✔
347

348
    /**
349
     * @brief Access the session-scoped EntityGroupManager.
350
     */
351
    [[nodiscard]] EntityGroupManager * getEntityGroupManager() const { return _entity_group_manager.get(); }
37✔
352

353
private:
354
    std::unordered_map<TimeKey, std::shared_ptr<TimeFrame>> _times;
355

356
    std::vector<ObserverCallback> _observers;
357

358
    std::unordered_map<std::string, DataTypeVariant>
359
            _data;
360

361
    std::unordered_map<std::string, TimeKey> _time_frames;
362

363
    std::filesystem::path _output_path;
364

365
    void _notifyObservers();
366

367
    int64_t _current_time{0};
368

369
    // ======= Table Registry and observer internals =======
370
    std::unique_ptr<TableRegistry> _table_registry;
371
    std::unordered_map<int, TableObserver> _table_observers;
372
    int _next_table_observer_id{1};
373

374
    // ======= Identity / Entity registry =======
375
    std::unique_ptr<EntityRegistry> _entity_registry;
376
    std::unique_ptr<EntityGroupManager> _entity_group_manager;
377
};
378

379
std::vector<DataInfo> load_data_from_json_config(DataManager *, std::string const & json_filepath);
380
std::vector<DataInfo> load_data_from_json_config(DataManager * dm, nlohmann::json const & j, std::filesystem::path const & base_path);
381

382
std::string convert_data_type_to_string(DM_DataType type);
383

384

385
extern template std::shared_ptr<AnalogTimeSeries> DataManager::getData<AnalogTimeSeries>(std::string const & key);
386
extern template void DataManager::setData<AnalogTimeSeries>(std::string const & key, TimeKey const & time_key);
387
extern template void DataManager::setData<AnalogTimeSeries>(std::string const & key, std::shared_ptr<AnalogTimeSeries> data, TimeKey const & time_key);
388

389
extern template std::shared_ptr<DigitalEventSeries> DataManager::getData<DigitalEventSeries>(std::string const & key);
390
extern template void DataManager::setData<DigitalEventSeries>(std::string const & key, TimeKey const & time_key);
391
extern template void DataManager::setData<DigitalEventSeries>(std::string const & key, std::shared_ptr<DigitalEventSeries> data, TimeKey const & time_key);
392

393
extern template std::shared_ptr<DigitalIntervalSeries> DataManager::getData<DigitalIntervalSeries>(std::string const & key);
394
extern template void DataManager::setData<DigitalIntervalSeries>(std::string const & key, TimeKey const & time_key);
395
extern template void DataManager::setData<DigitalIntervalSeries>(std::string const & key, std::shared_ptr<DigitalIntervalSeries> data, TimeKey const & time_key);
396

397
extern template std::shared_ptr<LineData> DataManager::getData<LineData>(std::string const & key);
398
extern template void DataManager::setData<LineData>(std::string const & key, TimeKey const & time_key);
399
extern template void DataManager::setData<LineData>(std::string const & key, std::shared_ptr<LineData> data, TimeKey const & time_key);
400

401
extern template std::shared_ptr<MaskData> DataManager::getData<MaskData>(std::string const & key);
402
extern template void DataManager::setData<MaskData>(std::string const & key, TimeKey const & time_key);
403
extern template void DataManager::setData<MaskData>(std::string const & key, std::shared_ptr<MaskData> data, TimeKey const & time_key);
404

405
extern template std::shared_ptr<MediaData> DataManager::getData<MediaData>(std::string const & key);
406

407
extern template std::shared_ptr<PointData> DataManager::getData<PointData>(std::string const & key);
408
extern template void DataManager::setData<PointData>(std::string const & key, TimeKey const & time_key);
409
extern template void DataManager::setData<PointData>(std::string const & key, std::shared_ptr<PointData> data, TimeKey const & time_key);
410

411
extern template std::shared_ptr<TensorData> DataManager::getData<TensorData>(std::string const & key);
412
extern template void DataManager::setData<TensorData>(std::string const & key, TimeKey const & time_key);
413
extern template void DataManager::setData<TensorData>(std::string const & key, std::shared_ptr<TensorData> data, TimeKey const & time_key);
414

415

416
#endif// DATAMANAGER_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