comparison base/EventSeries.h @ 1796:ff8c57c364a0

Make EventSeries threadsafe
author Chris Cannam
date Mon, 30 Sep 2019 20:28:03 +0100
parents 94b488d4b299
children e8b552549225
comparison
equal deleted inserted replaced
1795:94b488d4b299 1796:ff8c57c364a0
18 #include "Event.h" 18 #include "Event.h"
19 #include "XmlExportable.h" 19 #include "XmlExportable.h"
20 20
21 #include <set> 21 #include <set>
22 #include <functional> 22 #include <functional>
23
24 #include <QMutex>
23 25
24 //#define DEBUG_EVENT_SERIES 1 26 //#define DEBUG_EVENT_SERIES 1
25 27
26 /** 28 /**
27 * Container storing a series of events, with or without durations, 29 * Container storing a series of events, with or without durations,
38 * This class is highly optimised for inserting events in increasing 40 * This class is highly optimised for inserting events in increasing
39 * order of start frame. Inserting (or deleting) events in the middle 41 * order of start frame. Inserting (or deleting) events in the middle
40 * does work, and should be acceptable in interactive use, but it is 42 * does work, and should be acceptable in interactive use, but it is
41 * very slow in bulk. 43 * very slow in bulk.
42 * 44 *
43 * EventSeries is not thread-safe. 45 * EventSeries is thread-safe.
44 */ 46 */
45 class EventSeries : public XmlExportable 47 class EventSeries : public XmlExportable
46 { 48 {
47 public: 49 public:
48 EventSeries() : m_finalDurationlessEventFrame(0) { } 50 EventSeries() : m_finalDurationlessEventFrame(0) { }
49 ~EventSeries() =default; 51 ~EventSeries() =default;
50 52
51 EventSeries(const EventSeries &) =default; 53 EventSeries(const EventSeries &);
52 54
53 EventSeries &operator=(const EventSeries &) =delete; 55 EventSeries &operator=(const EventSeries &);
54 EventSeries &operator=(EventSeries &&) =delete; 56 EventSeries &operator=(EventSeries &&);
55 57
56 bool operator==(const EventSeries &other) const { 58 bool operator==(const EventSeries &other) const;
57 return m_events == other.m_events;
58 }
59 59
60 static EventSeries fromEvents(const EventVector &ee); 60 static EventSeries fromEvents(const EventVector &ee);
61 61
62 void clear(); 62 void clear();
63 void add(const Event &e); 63 void add(const Event &e);
231 sv_samplerate_t sampleRate, 231 sv_samplerate_t sampleRate,
232 sv_frame_t resolution, 232 sv_frame_t resolution,
233 Event fillEvent) const; 233 Event fillEvent) const;
234 234
235 private: 235 private:
236 mutable QMutex m_mutex;
237
238 EventSeries::EventSeries(const EventSeries &other, const QMutexLocker &);
239
236 /** 240 /**
237 * This vector contains all events in the series, in the normal 241 * This vector contains all events in the series, in the normal
238 * sort order. For backward compatibility we must support series 242 * sort order. For backward compatibility we must support series
239 * containing multiple instances of identical events, so 243 * containing multiple instances of identical events, so
240 * consecutive events in this vector will not always be distinct. 244 * consecutive events in this vector will not always be distinct.
276 * overall end frame or to find the last frame of all events 280 * overall end frame or to find the last frame of all events
277 * without this. 281 * without this.
278 */ 282 */
279 sv_frame_t m_finalDurationlessEventFrame; 283 sv_frame_t m_finalDurationlessEventFrame;
280 284
281 /** Create a seam at the given frame, copying from the prior seam 285 /**
282 * if there is one. If a seam already exists at the given frame, 286 * Create a seam at the given frame, copying from the prior seam
283 * leave it untouched. 287 * if there is one. If a seam already exists at the given frame,
288 * leave it untouched.
289 *
290 * Call with m_mutex locked.
284 */ 291 */
285 void createSeam(sv_frame_t frame) { 292 void createSeam(sv_frame_t frame) {
286 auto itr = m_seams.lower_bound(frame); 293 auto itr = m_seams.lower_bound(frame);
287 if (itr == m_seams.end() || itr->first > frame) { 294 if (itr == m_seams.end() || itr->first > frame) {
288 if (itr != m_seams.begin()) { 295 if (itr != m_seams.begin()) {
296 } else if (itr->first > frame) { // itr must be begin() 303 } else if (itr->first > frame) { // itr must be begin()
297 m_seams[frame] = {}; 304 m_seams[frame] = {};
298 } 305 }
299 } 306 }
300 307
308 /**
309 * Return true if the two seam map entries contain the same set of
310 * events.
311 *
312 * Precondition: no duplicates, i.e. no event appears more than
313 * once in s1 or more than once in s2.
314 *
315 * Call with m_mutex locked.
316 */
301 bool seamsEqual(const std::vector<Event> &s1, 317 bool seamsEqual(const std::vector<Event> &s1,
302 const std::vector<Event> &s2) const { 318 const std::vector<Event> &s2) const {
303 319
304 if (s1.size() != s2.size()) { 320 if (s1.size() != s2.size()) {
305 return false; 321 return false;
306 } 322 }
307
308 // precondition: no event appears more than once in s1 or more
309 // than once in s2
310 323
311 #ifdef DEBUG_EVENT_SERIES 324 #ifdef DEBUG_EVENT_SERIES
312 for (int i = 0; in_range_for(s1, i); ++i) { 325 for (int i = 0; in_range_for(s1, i); ++i) {
313 for (int j = i + 1; in_range_for(s1, j); ++j) { 326 for (int j = i + 1; in_range_for(s1, j); ++j) {
314 if (s1[i] == s1[j] || s2[i] == s2[j]) { 327 if (s1[i] == s1[j] || s2[i] == s2[j]) {