sort: Do not use Variant to sort UDA strings

String UDA defer the evaluation of the sort_compare method
to the '<' operator of the Variant class, since the logic for
comparing string UDAs (which can have custom sort orders) is
already implemented there.

However, since primary use case of Variant is the filter evaluation,
it handles trivial (empty) values in a manner which does not allow
for its direct usage as the comparison operator between sort UDAs.

When filtering, a trivial (empty) value should neither match
'uda < A' nor 'uda >= A'. However, when sorting tasks upon values of
this UDA, precisely one of the above expressions *must* be true.

This commit implements the UDA string sorting logic directly in
the sort_compare method.
This commit is contained in:
Tomas Babej
2015-09-13 14:49:55 +02:00
committed by Paul Beckingham
parent b9f217a716
commit 514c869aea

View File

@@ -30,7 +30,6 @@
#include <string>
#include <stdlib.h>
#include <Context.h>
#include <Variant.h>
#include <ISO8601.h>
#include <Task.h>
#include <text.h>
@@ -68,7 +67,6 @@ void sort_tasks (
// require re-parsing.
//
// Essentially a static implementation of a dynamic operator<.
// UDA string values delegate to Variant::operator<.
static bool sort_compare (int left, int right)
{
std::string field;
@@ -213,20 +211,36 @@ static bool sort_compare (int left, int right)
return ascending ? (left_real < right_real)
: (left_real > right_real);
}
// UDA values of type 'string' are sorted by Variant::operator<.
// By setting 'source' to the UDA name, the comparison operator can use
// the custom sort order, if defined.
else if (type == "string")
{
Variant l ((*global_data)[left].get_ref (field));
Variant r ((*global_data)[right].get_ref (field));
if (l == r)
const std::string left_string = (*global_data)[left].get_ref (field);
const std::string right_string = (*global_data)[right].get_ref (field);
if (left_string == right_string)
continue;
l.source (field);
r.source (field);
return ascending ? (l < r) : (r < l);
// UDAs of the type string can have custom sort orders, which need to be considered.
auto order = Task::customOrder.find (field);
if (order != Task::customOrder.end ())
{
// Guaranteed to be found, because of ColUDA::validate ().
auto posLeft = std::find (order->second.begin (), order->second.end (), left_string);
auto posRight = std::find (order->second.begin (), order->second.end (), right_string);
return ascending ? (posLeft < posRight) : (posLeft > posRight);
}
else
{
// Empty values are unconditionally last, if no custom order was specified.
if (left_string == "")
return false;
else if (right_string == "")
return true;
return ascending ? (left_string < right_string)
: (left_string > right_string);
}
}
else if (type == "date")
{
const std::string& left_string = (*global_data)[left].get_ref (field);