changeset 1653:eaad70939848 single-point

Add nearest-event-matching search
author Chris Cannam
date Tue, 19 Mar 2019 14:24:05 +0000
parents 08bed13d3a26
children 26aa42fd60e9
files base/EventSeries.cpp base/EventSeries.h base/test/TestEventSeries.h
diffstat 3 files changed, 129 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/base/EventSeries.cpp	Tue Mar 19 13:05:56 2019 +0000
+++ b/base/EventSeries.cpp	Tue Mar 19 14:24:05 2019 +0000
@@ -401,6 +401,43 @@
     return true;
 }
 
+bool
+EventSeries::getNearestEventMatching(sv_frame_t startSearchAt,
+                                     std::function<bool(const Event &)> predicate,
+                                     Direction direction,
+                                     Event &found) const
+{
+    auto pitr = lower_bound(m_events.begin(), m_events.end(),
+                            Event(startSearchAt));
+
+    while (true) {
+
+        if (direction == Backward) {
+            if (pitr == m_events.begin()) {
+                break;
+            } else {
+                --pitr;
+            }
+        } else {
+            if (pitr == m_events.end()) {
+                break;
+            }
+        }
+
+        const Event &e = *pitr;
+        if (predicate(e)) {
+            found = e;
+            return true;
+        }
+
+        if (direction == Forward) {
+            ++pitr;
+        }
+    }
+
+    return false;
+}
+
 Event
 EventSeries::getEventByIndex(int index) const
 {
--- a/base/EventSeries.h	Tue Mar 19 13:05:56 2019 +0000
+++ b/base/EventSeries.h	Tue Mar 19 14:24:05 2019 +0000
@@ -161,6 +161,23 @@
      */
     bool getEventFollowing(const Event &e, Event &following) const;
 
+    enum Direction {
+        Forward,
+        Backward
+    };
+
+    /**
+     * Return the first event for which the given predicate returns
+     * true, searching events with start frames increasingly far from
+     * the given frame in the given direction. If the direction is
+     * Forward then the search includes events starting at the given
+     * frame, otherwise it does not.
+     */
+    bool getNearestEventMatching(sv_frame_t startSearchAt,
+                                 std::function<bool(const Event &)> predicate,
+                                 Direction direction,
+                                 Event &found) const;
+    
     /**
      * Return the event at the given numerical index in the series,
      * where 0 = the first event and count()-1 = the last.
@@ -173,7 +190,7 @@
      * return count().
      */
     int getIndexForEvent(const Event &e) const;
-    
+
     /**
      * Emit to XML as a dataset element.
      */
--- a/base/test/TestEventSeries.h	Tue Mar 19 13:05:56 2019 +0000
+++ b/base/test/TestEventSeries.h	Tue Mar 19 14:24:05 2019 +0000
@@ -617,6 +617,80 @@
         QCOMPARE(p, e);
         QCOMPARE(s.getEventFollowing(p, p), false);
     }
+    
+    void matchingForward() {
+        
+        EventSeries s;
+        Event p;
+        QCOMPARE(s.getNearestEventMatching
+                 (6, [](const Event &e) { return e.getDuration() < 4; },
+                  EventSeries::Forward, p), false);
+        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(d); // again
+        s.add(a);
+        s.add(cc);
+        s.add(dd);
+        s.add(e);
+        QCOMPARE(s.getNearestEventMatching
+                 (0, [](const Event &e) { return e.getDuration() < 4; },
+                  EventSeries::Forward, p), true);
+        QCOMPARE(p, c);
+        QCOMPARE(s.getNearestEventMatching
+                 (6, [](const Event &e) { return e.getDuration() < 4; },
+                  EventSeries::Forward, p), true);
+        QCOMPARE(p, e);
+        QCOMPARE(s.getNearestEventMatching
+                 (6, [](const Event &e) { return e.getDuration() > 4; },
+                  EventSeries::Forward, p), true);
+        QCOMPARE(p, d);
+        QCOMPARE(s.getNearestEventMatching
+                 (20, [](const Event &e) { return e.getDuration() > 4; },
+                  EventSeries::Forward, p), false);
+    }
+    
+    void matchingBackward() {
+        
+        EventSeries s;
+        Event p;
+        QCOMPARE(s.getNearestEventMatching
+                 (6, [](const Event &e) { return e.getDuration() < 4; },
+                  EventSeries::Backward, p), false);
+        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(d); // again
+        s.add(a);
+        s.add(cc);
+        s.add(dd);
+        s.add(e);
+        QCOMPARE(s.getNearestEventMatching
+                 (0, [](const Event &e) { return e.getDuration() < 4; },
+                  EventSeries::Backward, p), false);
+        QCOMPARE(s.getNearestEventMatching
+                 (6, [](const Event &e) { return e.getDuration() > 4; },
+                  EventSeries::Backward, p), true);
+        QCOMPARE(p, b);
+        QCOMPARE(s.getNearestEventMatching
+                 (20, [](const Event &e) { return e.getDuration() > 4; },
+                  EventSeries::Backward, p), true);
+        QCOMPARE(p, dd);
+    }
 };
 
 #endif