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 86bb1465e8.

Closes issue #293 (thanks sskras)

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
This commit is contained in:
Shaun Ruffell 2020-03-05 17:49:25 -06:00 committed by lauft
parent b62b7b3435
commit 0b39a83a92
2 changed files with 42 additions and 8 deletions

View file

@ -24,6 +24,7 @@
//
////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <deque>
#include <cmake.h>
@ -586,6 +587,15 @@ std::vector <Range> 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 <Range> 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 <Interval> 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 <Interval> 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 <Interval> (std::make_move_iterator (intervals.begin ()),
std::make_move_iterator (intervals.end ()));
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -50,6 +50,7 @@ std::vector <Range> merge (const std::vector <Range>&);
std::vector <Range> addRanges (const Range&, const std::vector <Range>&, const std::vector <Range>&);
std::vector <Range> subtractRanges (const std::vector <Range>&, const std::vector <Range>&);
Range outerRange (const std::vector <Interval>&);
bool matchesRange (const Interval&, const Range&);
bool matchesFilter (const Interval&, const Interval&);
Interval clip (const Interval&, const Range&);
std::vector <Interval> getTracked (Database&, const Rules&, Interval&);