diff base/EventSeries.cpp @ 1796:ff8c57c364a0

Make EventSeries threadsafe
author Chris Cannam
date Mon, 30 Sep 2019 20:28:03 +0100
parents 0d89abd631ac
children 13bd41bd8a17
line wrap: on
line diff
--- a/base/EventSeries.cpp	Mon Sep 30 12:36:44 2019 +0100
+++ b/base/EventSeries.cpp	Mon Sep 30 20:28:03 2019 +0100
@@ -14,6 +14,47 @@
 
 #include "EventSeries.h"
 
+#include <QMutexLocker>
+
+EventSeries::EventSeries(const EventSeries &other) :
+    EventSeries(other, QMutexLocker(&other.m_mutex))
+{
+}
+
+EventSeries::EventSeries(const EventSeries &other, const QMutexLocker &) :
+    m_events(other.m_events),
+    m_seams(other.m_seams),
+    m_finalDurationlessEventFrame(other.m_finalDurationlessEventFrame)
+{
+}
+
+EventSeries &
+EventSeries::operator=(const EventSeries &other)
+{
+    QMutexLocker locker(&m_mutex), otherLocker(&other.m_mutex);
+    m_events = other.m_events;
+    m_seams = other.m_seams;
+    m_finalDurationlessEventFrame = other.m_finalDurationlessEventFrame;
+    return *this;
+}
+
+EventSeries &
+EventSeries::operator=(EventSeries &&other)
+{
+    QMutexLocker locker(&m_mutex), otherLocker(&other.m_mutex);
+    m_events = std::move(other.m_events);
+    m_seams = std::move(other.m_seams);
+    m_finalDurationlessEventFrame = std::move(other.m_finalDurationlessEventFrame);
+    return *this;
+}
+
+bool
+EventSeries::operator==(const EventSeries &other) const
+{
+    QMutexLocker locker(&m_mutex);
+    return m_events == other.m_events;
+}
+
 EventSeries
 EventSeries::fromEvents(const EventVector &v)
 {
@@ -27,12 +68,14 @@
 bool
 EventSeries::isEmpty() const
 {
+    QMutexLocker locker(&m_mutex);
     return m_events.empty();
 }
 
 int
 EventSeries::count() const
 {
+    QMutexLocker locker(&m_mutex);
     if (m_events.size() > INT_MAX) {
         throw std::logic_error("too many events");
     }
@@ -42,6 +85,8 @@
 void
 EventSeries::add(const Event &p)
 {
+    QMutexLocker locker(&m_mutex);
+
     bool isUnique = true;
 
     auto pitr = lower_bound(m_events.begin(), m_events.end(), p);
@@ -87,6 +132,8 @@
 void
 EventSeries::remove(const Event &p)
 {
+    QMutexLocker locker(&m_mutex);
+
     // If we are removing the last (unique) example of an event,
     // then we also need to remove it from the seam map. If this
     // is only one of multiple identical events, then we don't.
@@ -198,12 +245,14 @@
 bool
 EventSeries::contains(const Event &p) const
 {
+    QMutexLocker locker(&m_mutex);
     return binary_search(m_events.begin(), m_events.end(), p);
 }
 
 void
 EventSeries::clear()
 {
+    QMutexLocker locker(&m_mutex);
     m_events.clear();
     m_seams.clear();
     m_finalDurationlessEventFrame = 0;
@@ -212,6 +261,7 @@
 sv_frame_t
 EventSeries::getStartFrame() const
 {
+    QMutexLocker locker(&m_mutex);
     if (m_events.empty()) return 0;
     return m_events.begin()->getFrame();
 }
@@ -219,6 +269,8 @@
 sv_frame_t
 EventSeries::getEndFrame() const
 {
+    QMutexLocker locker(&m_mutex);
+
     sv_frame_t latest = 0;
 
     if (m_events.empty()) return latest;
@@ -239,6 +291,8 @@
 EventSeries::getEventsSpanning(sv_frame_t frame,
                                sv_frame_t duration) const
 {
+    QMutexLocker locker(&m_mutex);
+
     EventVector span;
     
     const sv_frame_t start = frame;
@@ -286,6 +340,8 @@
                              sv_frame_t duration,
                              int overspill) const
 {
+    QMutexLocker locker(&m_mutex);
+
     EventVector span;
     
     const sv_frame_t start = frame;
@@ -336,6 +392,8 @@
 EventSeries::getEventsStartingWithin(sv_frame_t frame,
                                      sv_frame_t duration) const
 {
+    QMutexLocker locker(&m_mutex);
+
     EventVector span;
     
     const sv_frame_t start = frame;
@@ -358,6 +416,8 @@
 EventVector
 EventSeries::getEventsCovering(sv_frame_t frame) const
 {
+    QMutexLocker locker(&m_mutex);
+
     EventVector cover;
 
     // first find any zero-duration events
@@ -400,12 +460,16 @@
 EventVector
 EventSeries::getAllEvents() const
 {
+    QMutexLocker locker(&m_mutex);
+
     return m_events;
 }
 
 bool
 EventSeries::getEventPreceding(const Event &e, Event &preceding) const
 {
+    QMutexLocker locker(&m_mutex);
+
     auto pitr = lower_bound(m_events.begin(), m_events.end(), e);
     if (pitr == m_events.end() || *pitr != e) {
         return false;
@@ -421,6 +485,8 @@
 bool
 EventSeries::getEventFollowing(const Event &e, Event &following) const
 {
+    QMutexLocker locker(&m_mutex);
+
     auto pitr = lower_bound(m_events.begin(), m_events.end(), e);
     if (pitr == m_events.end() || *pitr != e) {
         return false;
@@ -441,6 +507,8 @@
                                      Direction direction,
                                      Event &found) const
 {
+    QMutexLocker locker(&m_mutex);
+
     auto pitr = lower_bound(m_events.begin(), m_events.end(),
                             Event(startSearchAt));
 
@@ -475,6 +543,8 @@
 Event
 EventSeries::getEventByIndex(int index) const
 {
+    QMutexLocker locker(&m_mutex);
+
     if (index < 0 || index >= count()) {
         throw std::logic_error("index out of range");
     }
@@ -484,6 +554,8 @@
 int
 EventSeries::getIndexForEvent(const Event &e) const
 {
+    QMutexLocker locker(&m_mutex);
+
     auto pitr = lower_bound(m_events.begin(), m_events.end(), e);
     auto d = distance(m_events.begin(), pitr);
     if (d < 0 || d > INT_MAX) return 0;
@@ -495,7 +567,17 @@
                    QString indent,
                    QString extraAttributes) const
 {
-    toXml(out, indent, extraAttributes, Event::ExportNameOptions());
+    QMutexLocker locker(&m_mutex);
+
+    out << indent << QString("<dataset id=\"%1\" %2>\n")
+        .arg(getExportId())
+        .arg(extraAttributes);
+    
+    for (const auto &p: m_events) {
+        p.toXml(out, indent + "  ", "", {});
+    }
+    
+    out << indent << "</dataset>\n";
 }
 
 void
@@ -504,6 +586,8 @@
                    QString extraAttributes,
                    Event::ExportNameOptions options) const
 {
+    QMutexLocker locker(&m_mutex);
+
     out << indent << QString("<dataset id=\"%1\" %2>\n")
         .arg(getExportId())
         .arg(extraAttributes);
@@ -524,6 +608,8 @@
                                    sv_frame_t resolution,
                                    Event fillEvent) const
 {
+    QMutexLocker locker(&m_mutex);
+
     QString s;
 
     const sv_frame_t end = startFrame + duration;