# HG changeset patch # User Chris Cannam # Date 1552402331 0 # Node ID 0890c10e512920f7253919188331711e29aea181 # Parent b2048f35090640ddf6453e3e528df21459fc9cec Add some more handy methods diff -r b2048f350906 -r 0890c10e5129 base/EventSeries.cpp --- 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, diff -r b2048f350906 -r 0890c10e5129 base/EventSeries.h --- 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, diff -r b2048f350906 -r 0890c10e5129 base/test/TestEventSeries.h --- 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