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(),