From 0b39a83a929e127f2312c4efb85b005d646de412 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Thu, 5 Mar 2020 17:49:25 -0600 Subject: [PATCH] Filtering with tags should preserve the interval IDs. This fixes the bug where, when filtering by tags, the interval IDs are not preserved when not using any tags in the filter. Notice below how when filtering with tag1, the two intervals are @4 and @5 instead of @1 and @5 like they should be: $ timew summ :ids Wk Date Day ID Tags Start End Time Total W9 2020-02-29 Sat @5 tag1 15:28:31 15:28:33 0:00:02 @4 tag2 15:28:33 15:28:35 0:00:02 @3 tag3 15:28:35 15:28:36 0:00:01 @2 tag4 15:28:36 15:28:48 0:00:12 @1 tag1 15:28:48 - 0:02:25 0:02:42 0:02:42 $ timew summ tag1 :ids Wk Date Day ID Tags Start End Time Total W9 2020-02-29 Sat @5 tag1 15:28:31 15:28:33 0:00:02 @4 tag1 15:28:48 - 0:02:28 0:02:30 0:02:30 This fixes a bug introduced in 86bb1465e867d5. Closes issue #293 (thanks sskras) Signed-off-by: Shaun Ruffell --- src/data.cpp | 49 +++++++++++++++++++++++++++++++++++++++++-------- src/timew.h | 1 + 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/data.cpp b/src/data.cpp index 2be27c5b..fe46c2ab 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -24,6 +24,7 @@ // //////////////////////////////////////////////////////////////////////////////// +#include #include #include @@ -586,6 +587,15 @@ std::vector subtractRanges ( return results; } +//////////////////////////////////////////////////////////////////////////////// +// An interval matches a filter range if the start/end overlaps +bool matchesRange (const Interval& interval, const Range& filter) +{ + return ((filter.start.toEpoch () == 0 && + filter.end.toEpoch () == 0 + ) || interval.intersects (filter)); +} + //////////////////////////////////////////////////////////////////////////////// // An interval matches a filter interval if the start/end overlaps, and all // filter interval tags are found in the interval. @@ -625,14 +635,15 @@ std::vector subtractRanges ( // bool matchesFilter (const Interval& interval, const Interval& filter) { - if ((filter.start.toEpoch () == 0 && - filter.end.toEpoch () == 0 - ) || interval.intersects (filter)) + if (matchesRange (interval, filter)) { for (auto& tag : filter.tags ()) + { if (! interval.hasTag (tag)) + { return false; - + } + } return true; } @@ -696,9 +707,9 @@ std::vector getTracked ( // Since we are moving backwards, and the intervals are in sorted order, // if the filter is after the interval, we know there will be no more // matches - if (matchesFilter (interval, filter)) + if (matchesRange (interval, filter)) { - intervals.push_front (interval); + intervals.push_front (std::move (interval)); } else if (interval.start.toEpoch () >= filter.start.toEpoch ()) { @@ -738,14 +749,36 @@ std::vector getTracked ( } } - // Assign an ID to each interval. + // Assign an ID to each interval before we prune ones that do not have + // matching tags for (unsigned int i = 0; i < intervals.size (); ++i) { intervals[i].id = intervals.size () - i + id_skip; } + // Now prune the intervals without matching tags + if (filter.tags ().size () > 0) + { + auto cmp = [&filter] (const Interval& interval) + { + for (const auto& tag : filter.tags ()) + { + if (! interval.hasTag (tag)) + { + return true; + } + } + return false; + }; + + intervals.erase (std::remove_if (intervals.begin (), intervals.end (), cmp), + intervals.end ()); + } + debug (format ("Loaded {1} tracked intervals", intervals.size ())); - return subset (filter, intervals); + + return std::vector (std::make_move_iterator (intervals.begin ()), + std::make_move_iterator (intervals.end ())); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/timew.h b/src/timew.h index f55331bb..5bda960b 100644 --- a/src/timew.h +++ b/src/timew.h @@ -50,6 +50,7 @@ std::vector merge (const std::vector &); std::vector addRanges (const Range&, const std::vector &, const std::vector &); std::vector subtractRanges (const std::vector &, const std::vector &); Range outerRange (const std::vector &); +bool matchesRange (const Interval&, const Range&); bool matchesFilter (const Interval&, const Interval&); Interval clip (const Interval&, const Range&); std::vector getTracked (Database&, const Rules&, Interval&);