Mercurial > hg > svcore
comparison base/EventSeries.cpp @ 1796:ff8c57c364a0
Make EventSeries threadsafe
author | Chris Cannam |
---|---|
date | Mon, 30 Sep 2019 20:28:03 +0100 |
parents | 0d89abd631ac |
children | 13bd41bd8a17 |
comparison
equal
deleted
inserted
replaced
1795:94b488d4b299 | 1796:ff8c57c364a0 |
---|---|
12 COPYING included with this distribution for more information. | 12 COPYING included with this distribution for more information. |
13 */ | 13 */ |
14 | 14 |
15 #include "EventSeries.h" | 15 #include "EventSeries.h" |
16 | 16 |
17 #include <QMutexLocker> | |
18 | |
19 EventSeries::EventSeries(const EventSeries &other) : | |
20 EventSeries(other, QMutexLocker(&other.m_mutex)) | |
21 { | |
22 } | |
23 | |
24 EventSeries::EventSeries(const EventSeries &other, const QMutexLocker &) : | |
25 m_events(other.m_events), | |
26 m_seams(other.m_seams), | |
27 m_finalDurationlessEventFrame(other.m_finalDurationlessEventFrame) | |
28 { | |
29 } | |
30 | |
31 EventSeries & | |
32 EventSeries::operator=(const EventSeries &other) | |
33 { | |
34 QMutexLocker locker(&m_mutex), otherLocker(&other.m_mutex); | |
35 m_events = other.m_events; | |
36 m_seams = other.m_seams; | |
37 m_finalDurationlessEventFrame = other.m_finalDurationlessEventFrame; | |
38 return *this; | |
39 } | |
40 | |
41 EventSeries & | |
42 EventSeries::operator=(EventSeries &&other) | |
43 { | |
44 QMutexLocker locker(&m_mutex), otherLocker(&other.m_mutex); | |
45 m_events = std::move(other.m_events); | |
46 m_seams = std::move(other.m_seams); | |
47 m_finalDurationlessEventFrame = std::move(other.m_finalDurationlessEventFrame); | |
48 return *this; | |
49 } | |
50 | |
51 bool | |
52 EventSeries::operator==(const EventSeries &other) const | |
53 { | |
54 QMutexLocker locker(&m_mutex); | |
55 return m_events == other.m_events; | |
56 } | |
57 | |
17 EventSeries | 58 EventSeries |
18 EventSeries::fromEvents(const EventVector &v) | 59 EventSeries::fromEvents(const EventVector &v) |
19 { | 60 { |
20 EventSeries s; | 61 EventSeries s; |
21 for (const auto &e: v) { | 62 for (const auto &e: v) { |
25 } | 66 } |
26 | 67 |
27 bool | 68 bool |
28 EventSeries::isEmpty() const | 69 EventSeries::isEmpty() const |
29 { | 70 { |
71 QMutexLocker locker(&m_mutex); | |
30 return m_events.empty(); | 72 return m_events.empty(); |
31 } | 73 } |
32 | 74 |
33 int | 75 int |
34 EventSeries::count() const | 76 EventSeries::count() const |
35 { | 77 { |
78 QMutexLocker locker(&m_mutex); | |
36 if (m_events.size() > INT_MAX) { | 79 if (m_events.size() > INT_MAX) { |
37 throw std::logic_error("too many events"); | 80 throw std::logic_error("too many events"); |
38 } | 81 } |
39 return int(m_events.size()); | 82 return int(m_events.size()); |
40 } | 83 } |
41 | 84 |
42 void | 85 void |
43 EventSeries::add(const Event &p) | 86 EventSeries::add(const Event &p) |
44 { | 87 { |
88 QMutexLocker locker(&m_mutex); | |
89 | |
45 bool isUnique = true; | 90 bool isUnique = true; |
46 | 91 |
47 auto pitr = lower_bound(m_events.begin(), m_events.end(), p); | 92 auto pitr = lower_bound(m_events.begin(), m_events.end(), p); |
48 if (pitr != m_events.end() && *pitr == p) { | 93 if (pitr != m_events.end() && *pitr == p) { |
49 isUnique = false; | 94 isUnique = false; |
85 } | 130 } |
86 | 131 |
87 void | 132 void |
88 EventSeries::remove(const Event &p) | 133 EventSeries::remove(const Event &p) |
89 { | 134 { |
135 QMutexLocker locker(&m_mutex); | |
136 | |
90 // If we are removing the last (unique) example of an event, | 137 // If we are removing the last (unique) example of an event, |
91 // then we also need to remove it from the seam map. If this | 138 // then we also need to remove it from the seam map. If this |
92 // is only one of multiple identical events, then we don't. | 139 // is only one of multiple identical events, then we don't. |
93 bool isUnique = true; | 140 bool isUnique = true; |
94 | 141 |
196 } | 243 } |
197 | 244 |
198 bool | 245 bool |
199 EventSeries::contains(const Event &p) const | 246 EventSeries::contains(const Event &p) const |
200 { | 247 { |
248 QMutexLocker locker(&m_mutex); | |
201 return binary_search(m_events.begin(), m_events.end(), p); | 249 return binary_search(m_events.begin(), m_events.end(), p); |
202 } | 250 } |
203 | 251 |
204 void | 252 void |
205 EventSeries::clear() | 253 EventSeries::clear() |
206 { | 254 { |
255 QMutexLocker locker(&m_mutex); | |
207 m_events.clear(); | 256 m_events.clear(); |
208 m_seams.clear(); | 257 m_seams.clear(); |
209 m_finalDurationlessEventFrame = 0; | 258 m_finalDurationlessEventFrame = 0; |
210 } | 259 } |
211 | 260 |
212 sv_frame_t | 261 sv_frame_t |
213 EventSeries::getStartFrame() const | 262 EventSeries::getStartFrame() const |
214 { | 263 { |
264 QMutexLocker locker(&m_mutex); | |
215 if (m_events.empty()) return 0; | 265 if (m_events.empty()) return 0; |
216 return m_events.begin()->getFrame(); | 266 return m_events.begin()->getFrame(); |
217 } | 267 } |
218 | 268 |
219 sv_frame_t | 269 sv_frame_t |
220 EventSeries::getEndFrame() const | 270 EventSeries::getEndFrame() const |
221 { | 271 { |
272 QMutexLocker locker(&m_mutex); | |
273 | |
222 sv_frame_t latest = 0; | 274 sv_frame_t latest = 0; |
223 | 275 |
224 if (m_events.empty()) return latest; | 276 if (m_events.empty()) return latest; |
225 | 277 |
226 latest = m_finalDurationlessEventFrame; | 278 latest = m_finalDurationlessEventFrame; |
237 | 289 |
238 EventVector | 290 EventVector |
239 EventSeries::getEventsSpanning(sv_frame_t frame, | 291 EventSeries::getEventsSpanning(sv_frame_t frame, |
240 sv_frame_t duration) const | 292 sv_frame_t duration) const |
241 { | 293 { |
294 QMutexLocker locker(&m_mutex); | |
295 | |
242 EventVector span; | 296 EventVector span; |
243 | 297 |
244 const sv_frame_t start = frame; | 298 const sv_frame_t start = frame; |
245 const sv_frame_t end = frame + duration; | 299 const sv_frame_t end = frame + duration; |
246 | 300 |
284 EventVector | 338 EventVector |
285 EventSeries::getEventsWithin(sv_frame_t frame, | 339 EventSeries::getEventsWithin(sv_frame_t frame, |
286 sv_frame_t duration, | 340 sv_frame_t duration, |
287 int overspill) const | 341 int overspill) const |
288 { | 342 { |
343 QMutexLocker locker(&m_mutex); | |
344 | |
289 EventVector span; | 345 EventVector span; |
290 | 346 |
291 const sv_frame_t start = frame; | 347 const sv_frame_t start = frame; |
292 const sv_frame_t end = frame + duration; | 348 const sv_frame_t end = frame + duration; |
293 | 349 |
334 | 390 |
335 EventVector | 391 EventVector |
336 EventSeries::getEventsStartingWithin(sv_frame_t frame, | 392 EventSeries::getEventsStartingWithin(sv_frame_t frame, |
337 sv_frame_t duration) const | 393 sv_frame_t duration) const |
338 { | 394 { |
395 QMutexLocker locker(&m_mutex); | |
396 | |
339 EventVector span; | 397 EventVector span; |
340 | 398 |
341 const sv_frame_t start = frame; | 399 const sv_frame_t start = frame; |
342 const sv_frame_t end = frame + duration; | 400 const sv_frame_t end = frame + duration; |
343 | 401 |
356 } | 414 } |
357 | 415 |
358 EventVector | 416 EventVector |
359 EventSeries::getEventsCovering(sv_frame_t frame) const | 417 EventSeries::getEventsCovering(sv_frame_t frame) const |
360 { | 418 { |
419 QMutexLocker locker(&m_mutex); | |
420 | |
361 EventVector cover; | 421 EventVector cover; |
362 | 422 |
363 // first find any zero-duration events | 423 // first find any zero-duration events |
364 | 424 |
365 auto pitr = lower_bound(m_events.begin(), m_events.end(), | 425 auto pitr = lower_bound(m_events.begin(), m_events.end(), |
398 } | 458 } |
399 | 459 |
400 EventVector | 460 EventVector |
401 EventSeries::getAllEvents() const | 461 EventSeries::getAllEvents() const |
402 { | 462 { |
463 QMutexLocker locker(&m_mutex); | |
464 | |
403 return m_events; | 465 return m_events; |
404 } | 466 } |
405 | 467 |
406 bool | 468 bool |
407 EventSeries::getEventPreceding(const Event &e, Event &preceding) const | 469 EventSeries::getEventPreceding(const Event &e, Event &preceding) const |
408 { | 470 { |
471 QMutexLocker locker(&m_mutex); | |
472 | |
409 auto pitr = lower_bound(m_events.begin(), m_events.end(), e); | 473 auto pitr = lower_bound(m_events.begin(), m_events.end(), e); |
410 if (pitr == m_events.end() || *pitr != e) { | 474 if (pitr == m_events.end() || *pitr != e) { |
411 return false; | 475 return false; |
412 } | 476 } |
413 if (pitr == m_events.begin()) { | 477 if (pitr == m_events.begin()) { |
419 } | 483 } |
420 | 484 |
421 bool | 485 bool |
422 EventSeries::getEventFollowing(const Event &e, Event &following) const | 486 EventSeries::getEventFollowing(const Event &e, Event &following) const |
423 { | 487 { |
488 QMutexLocker locker(&m_mutex); | |
489 | |
424 auto pitr = lower_bound(m_events.begin(), m_events.end(), e); | 490 auto pitr = lower_bound(m_events.begin(), m_events.end(), e); |
425 if (pitr == m_events.end() || *pitr != e) { | 491 if (pitr == m_events.end() || *pitr != e) { |
426 return false; | 492 return false; |
427 } | 493 } |
428 while (*pitr == e) { | 494 while (*pitr == e) { |
439 EventSeries::getNearestEventMatching(sv_frame_t startSearchAt, | 505 EventSeries::getNearestEventMatching(sv_frame_t startSearchAt, |
440 std::function<bool(const Event &)> predicate, | 506 std::function<bool(const Event &)> predicate, |
441 Direction direction, | 507 Direction direction, |
442 Event &found) const | 508 Event &found) const |
443 { | 509 { |
510 QMutexLocker locker(&m_mutex); | |
511 | |
444 auto pitr = lower_bound(m_events.begin(), m_events.end(), | 512 auto pitr = lower_bound(m_events.begin(), m_events.end(), |
445 Event(startSearchAt)); | 513 Event(startSearchAt)); |
446 | 514 |
447 while (true) { | 515 while (true) { |
448 | 516 |
473 } | 541 } |
474 | 542 |
475 Event | 543 Event |
476 EventSeries::getEventByIndex(int index) const | 544 EventSeries::getEventByIndex(int index) const |
477 { | 545 { |
546 QMutexLocker locker(&m_mutex); | |
547 | |
478 if (index < 0 || index >= count()) { | 548 if (index < 0 || index >= count()) { |
479 throw std::logic_error("index out of range"); | 549 throw std::logic_error("index out of range"); |
480 } | 550 } |
481 return m_events[index]; | 551 return m_events[index]; |
482 } | 552 } |
483 | 553 |
484 int | 554 int |
485 EventSeries::getIndexForEvent(const Event &e) const | 555 EventSeries::getIndexForEvent(const Event &e) const |
486 { | 556 { |
557 QMutexLocker locker(&m_mutex); | |
558 | |
487 auto pitr = lower_bound(m_events.begin(), m_events.end(), e); | 559 auto pitr = lower_bound(m_events.begin(), m_events.end(), e); |
488 auto d = distance(m_events.begin(), pitr); | 560 auto d = distance(m_events.begin(), pitr); |
489 if (d < 0 || d > INT_MAX) return 0; | 561 if (d < 0 || d > INT_MAX) return 0; |
490 return int(d); | 562 return int(d); |
491 } | 563 } |
493 void | 565 void |
494 EventSeries::toXml(QTextStream &out, | 566 EventSeries::toXml(QTextStream &out, |
495 QString indent, | 567 QString indent, |
496 QString extraAttributes) const | 568 QString extraAttributes) const |
497 { | 569 { |
498 toXml(out, indent, extraAttributes, Event::ExportNameOptions()); | 570 QMutexLocker locker(&m_mutex); |
571 | |
572 out << indent << QString("<dataset id=\"%1\" %2>\n") | |
573 .arg(getExportId()) | |
574 .arg(extraAttributes); | |
575 | |
576 for (const auto &p: m_events) { | |
577 p.toXml(out, indent + " ", "", {}); | |
578 } | |
579 | |
580 out << indent << "</dataset>\n"; | |
499 } | 581 } |
500 | 582 |
501 void | 583 void |
502 EventSeries::toXml(QTextStream &out, | 584 EventSeries::toXml(QTextStream &out, |
503 QString indent, | 585 QString indent, |
504 QString extraAttributes, | 586 QString extraAttributes, |
505 Event::ExportNameOptions options) const | 587 Event::ExportNameOptions options) const |
506 { | 588 { |
589 QMutexLocker locker(&m_mutex); | |
590 | |
507 out << indent << QString("<dataset id=\"%1\" %2>\n") | 591 out << indent << QString("<dataset id=\"%1\" %2>\n") |
508 .arg(getExportId()) | 592 .arg(getExportId()) |
509 .arg(extraAttributes); | 593 .arg(extraAttributes); |
510 | 594 |
511 for (const auto &p: m_events) { | 595 for (const auto &p: m_events) { |
522 sv_frame_t duration, | 606 sv_frame_t duration, |
523 sv_samplerate_t sampleRate, | 607 sv_samplerate_t sampleRate, |
524 sv_frame_t resolution, | 608 sv_frame_t resolution, |
525 Event fillEvent) const | 609 Event fillEvent) const |
526 { | 610 { |
611 QMutexLocker locker(&m_mutex); | |
612 | |
527 QString s; | 613 QString s; |
528 | 614 |
529 const sv_frame_t end = startFrame + duration; | 615 const sv_frame_t end = startFrame + duration; |
530 | 616 |
531 auto pitr = lower_bound(m_events.begin(), m_events.end(), | 617 auto pitr = lower_bound(m_events.begin(), m_events.end(), |