changeset 1632:0890c10e5129 single-point

Add some more handy methods
author Chris Cannam
date Tue, 12 Mar 2019 14:52:11 +0000
parents b2048f350906
children 6ac92836cd86
files base/EventSeries.cpp base/EventSeries.h base/test/TestEventSeries.h
diffstat 3 files changed, 143 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/base/EventSeries.cpp	Tue Mar 12 14:14:00 2019 +0000
+++ b/base/EventSeries.cpp	Tue Mar 12 14:52:11 2019 +0000
@@ -24,7 +24,7 @@
 EventSeries::count() const
 {
     if (m_events.size() > INT_MAX) {
-        throw std::runtime_error("too many events");
+        throw std::logic_error("too many events");
     }
     return int(m_events.size());
 }
@@ -271,6 +271,45 @@
     return cover;
 }
 
+bool
+EventSeries::getEventPreceding(const Event &e, Event &preceding) const
+{
+    auto pitr = lower_bound(m_events.begin(), m_events.end(), e);
+    if (pitr == m_events.end() || *pitr != e) {
+        return false;
+    }
+    if (pitr == m_events.begin()) {
+        return false;
+    }
+    --pitr;
+    preceding = *pitr;
+    return true;
+}
+
+bool
+EventSeries::getEventFollowing(const Event &e, Event &following) const
+{
+    auto pitr = lower_bound(m_events.begin(), m_events.end(), e);
+    if (pitr == m_events.end() || *pitr != e) {
+        return false;
+    }
+    ++pitr;
+    if (pitr == m_events.end()) {
+        return false;
+    }
+    following = *pitr;
+    return true;
+}
+
+Event
+EventSeries::getEventByIndex(int index) const
+{
+    if (index < 0 || index >= count()) {
+        throw std::logic_error("index out of range");
+    }
+    return m_events[index];
+}
+
 void
 EventSeries::toXml(QTextStream &out,
                    QString indent,
--- a/base/EventSeries.h	Tue Mar 12 14:14:00 2019 +0000
+++ b/base/EventSeries.h	Tue Mar 12 14:52:11 2019 +0000
@@ -34,12 +34,10 @@
  * at or from that position. These are updated when an event is added
  * or removed.
  *
- * Performance is highly dependent on the extent of overlapping events
- * and the order in which events are added. Each event (with duration)
- * that is added requires updating all the seams within the extent of
- * that event, taking a number of ordered-set updates proportional to
- * the number of events already existing within its extent. Add events
- * in order of start frame if possible.
+ * This class is highly optimised for inserting events in increasing
+ * order of start frame. Inserting (or deleting) events in the middle
+ * does work, and should be acceptable in interactive use, but it is
+ * very slow in bulk.
  */
 class EventSeries : public XmlExportable
 {
@@ -56,9 +54,9 @@
     }
     
     void clear();
-    void add(const Event &p);
-    void remove(const Event &p);
-    bool contains(const Event &p) const;
+    void add(const Event &e);
+    void remove(const Event &e);
+    bool contains(const Event &e) const;
     bool isEmpty() const;
     int count() const;
 
@@ -92,6 +90,36 @@
     EventVector getEventsCovering(sv_frame_t frame) const;
 
     /**
+     * If e is in the series and is not the first event in it, set
+     * preceding to the event immediate preceding it according to the
+     * standard event ordering and return true. Otherwise leave
+     * preceding unchanged and return false.
+     *
+     * If there are multiple events identical to e in the series,
+     * assume that the event passed in is the first one (i.e. never
+     * set preceding equal to e).
+     */
+    bool getEventPreceding(const Event &e, Event &preceding) const;
+
+    /**
+     * If e is in the series and is not the final event in it, set
+     * following to the event immediate following it according to the
+     * standard event ordering and return true. Otherwise leave
+     * following unchanged and return false.
+     *
+     * If there are multiple events identical to e in the series,
+     * assume that the event passed in is the last one (i.e. never set
+     * following equal to e).
+     */
+    bool getEventFollowing(const Event &e, Event &following) const;
+
+    /**
+     * Return the event at the given numerical index in the series,
+     * where 0 = the first event and count()-1 = the last.
+     */
+    Event getEventByIndex(int index) const;
+    
+    /**
      * Emit to XML as a dataset element.
      */
     void toXml(QTextStream &out,
--- a/base/test/TestEventSeries.h	Tue Mar 12 14:14:00 2019 +0000
+++ b/base/test/TestEventSeries.h	Tue Mar 12 14:52:11 2019 +0000
@@ -463,6 +463,72 @@
         QCOMPARE(s.count(), 0);
         QCOMPARE(s.isEmpty(), true);
     }
+
+    void preceding() {
+        
+        EventSeries s;
+        Event a(0, 1.0f, 18, QString("a"));
+        Event b(3, 2.0f, 6, QString("b"));
+        Event c(5, 3.0f, 2, QString("c"));
+        Event cc(5, 3.1f, 2, QString("cc"));
+        Event d(6, 4.0f, 10, QString("d"));
+        Event dd(6, 4.5f, 10, QString("dd"));
+        Event e(14, 5.0f, 3, QString("e"));
+        s.add(b);
+        s.add(c);
+        s.add(d);
+        s.add(a);
+        s.add(cc);
+        s.add(dd);
+        s.add(e);
+        Event p;
+        QCOMPARE(s.getEventPreceding(e, p), true);
+        QCOMPARE(p, dd);
+        QCOMPARE(s.getEventPreceding(p, p), true);
+        QCOMPARE(p, d);
+        QCOMPARE(s.getEventPreceding(p, p), true);
+        QCOMPARE(p, cc);
+        QCOMPARE(s.getEventPreceding(p, p), true);
+        QCOMPARE(p, c);
+        QCOMPARE(s.getEventPreceding(p, p), true);
+        QCOMPARE(p, b);
+        QCOMPARE(s.getEventPreceding(p, p), true);
+        QCOMPARE(p, a);
+        QCOMPARE(s.getEventPreceding(p, p), false);
+    }
+    
+    void following() {
+        
+        EventSeries s;
+        Event a(0, 1.0f, 18, QString("a"));
+        Event b(3, 2.0f, 6, QString("b"));
+        Event c(5, 3.0f, 2, QString("c"));
+        Event cc(5, 3.1f, 2, QString("cc"));
+        Event d(6, 4.0f, 10, QString("d"));
+        Event dd(6, 4.5f, 10, QString("dd"));
+        Event e(14, 5.0f, 3, QString("e"));
+        s.add(b);
+        s.add(c);
+        s.add(d);
+        s.add(a);
+        s.add(cc);
+        s.add(dd);
+        s.add(e);
+        Event p;
+        QCOMPARE(s.getEventFollowing(a, p), true);
+        QCOMPARE(p, b);
+        QCOMPARE(s.getEventFollowing(p, p), true);
+        QCOMPARE(p, c);
+        QCOMPARE(s.getEventFollowing(p, p), true);
+        QCOMPARE(p, cc);
+        QCOMPARE(s.getEventFollowing(p, p), true);
+        QCOMPARE(p, d);
+        QCOMPARE(s.getEventFollowing(p, p), true);
+        QCOMPARE(p, dd);
+        QCOMPARE(s.getEventFollowing(p, p), true);
+        QCOMPARE(p, e);
+        QCOMPARE(s.getEventFollowing(p, p), false);
+    }
 };
 
 #endif