Skip to content

Commit

Permalink
retire qsort in favor of std::sort, std::stable_sort (GPSBabel#888)
Browse files Browse the repository at this point in the history
* replace qsort with std::sort or std::stable_sort

* add test for duplicate filter using gc_data exported dates.

* fix reference file permissions.

* fix smplrout sort bug that shows up on macos with std::sort.

the compare function has always generated incorrect values when
both objects are HUGEVAL. The historic function worked with qsort
everywhere, worked with std::sort on linux and windows, but failed
with std::sort on macos.
  • Loading branch information
tsteven4 authored Jul 7, 2022
1 parent f7ee0ea commit 5c93d07
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 64 deletions.
47 changes: 7 additions & 40 deletions duplicate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
*/

#include <algorithm> // for stable_sort
#include <cstdio> // for sprintf
#include <cstdlib> // for qsort
#include <cstring> // for memset, strncpy

#include <QDateTime> // for QDateTime
Expand Down Expand Up @@ -114,30 +114,6 @@ be zero so the sort will end up being an expensive no-op (expensive
because, sadly, quicksort can be O(n^2) on presorted elements.)
*/


int DuplicateFilter::compare(const void* a, const void* b)
{
const wpt_ptr* wa = (wpt_ptr*)a;
const wpt_ptr* wb = (wpt_ptr*)b;

if (wa->wpt->gc_data->exported < wb->wpt->gc_data->exported) {
return 1;
} else if (wa->wpt->gc_data->exported > wb->wpt->gc_data->exported) {
return -1;
}

/* If the exported dates are the same, sort by index. */
if (wa->index < wb->index) {
return -1;
} else if (wa->index > wb->index) {
return 1;
}

/* If index and date are the same, it's the same element. */
return 0;

}

void DuplicateFilter::process()
{
btree_node* btmp = nullptr;
Expand All @@ -150,22 +126,14 @@ void DuplicateFilter::process()
} dupe;
Waypoint* delwpt = nullptr;

int ct = waypt_count();

auto* htable = (wpt_ptr*) xmalloc(ct * sizeof(wpt_ptr));
wpt_ptr* bh = htable;
auto htable = *global_waypoint_list;

int i = 0;
foreach (Waypoint* waypointp, *global_waypoint_list) {
bh->wpt = waypointp;
bh->index = i;
i ++;
bh ++;
}
qsort(htable, ct, sizeof(*htable), compare);
auto compare_lambda = [](const Waypoint* wa, const Waypoint* wb)->bool {
return wa->gc_data->exported > wb->gc_data->exported;
};
std::stable_sort(htable.begin(), htable.end(), compare_lambda);

for (i=0; i<ct; i++) {
auto* waypointp = htable[i].wpt;
for (Waypoint* waypointp : htable) {

memset(&dupe, '\0', sizeof(dupe));

Expand Down Expand Up @@ -218,7 +186,6 @@ void DuplicateFilter::process()

delete delwpt;

xfree(htable);
if (sup_tree) {
free_tree(sup_tree);
}
Expand Down
7 changes: 0 additions & 7 deletions duplicate.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,6 @@ class DuplicateFilter:public Filter
static btree_node* addnode(btree_node* tree, btree_node* newnode, btree_node** oldnode);
void free_tree(btree_node* tree);

struct wpt_ptr {
Waypoint* wpt;
int index;
};

static int compare(const void* a, const void* b);

};
#endif
#endif // DUPLICATE_H_INCLUDED_
24 changes: 9 additions & 15 deletions garmin_txt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
#include "defs.h"

#if CSVFMTS_ENABLED
#include <algorithm> // for sort
#include <cctype> // for toupper
#include <cmath> // for fabs, floor
#include <cstdio> // for NULL, snprintf, sscanf
#include <cstdint>
#include <cstdlib> // for atoi, abs, qsort
#include <cstdlib> // for atoi, abs
#include <cstring> // for memset, strstr, strcat, strchr, strlen, strcmp, strcpy, strncpy
#include <ctime> // for gmtime, localtime, strftime

Expand Down Expand Up @@ -240,15 +241,6 @@ enum_waypt_cb(const Waypoint* wpt)

}

static int
sort_waypt_cb(const void* a, const void* b)
{
const Waypoint* wa = *(Waypoint**)a;
const Waypoint* wb = *(Waypoint**)b;
return wa->shortname.compare(wb->shortname, Qt::CaseInsensitive);
}


/* common route and track pre-work */

static void
Expand Down Expand Up @@ -834,17 +826,19 @@ garmin_txt_write()

if (waypoints > 0) {
wpt_a_ct = 0;
wpt_a = (const Waypoint**)xcalloc(waypoints, sizeof(*wpt_a));
wpt_a = new const Waypoint*[waypoints]{};
waypt_disp_all(enum_waypt_cb);
route_disp_all(nullptr, nullptr, enum_waypt_cb);
qsort(wpt_a, waypoints, sizeof(*wpt_a), sort_waypt_cb);
auto sort_waypt_lambda = [](const Waypoint* wa, const Waypoint* wb)->bool {
return wa->shortname.compare(wb->shortname, Qt::CaseInsensitive) < 0;
};
std::sort(wpt_a, wpt_a + waypoints, sort_waypt_lambda);

*fout << QString::asprintf("Header\t%s\r\n\r\n", headers[waypt_header]);
for (int i = 0; i < waypoints; i++) {
const Waypoint* wpt = wpt_a[i];
write_waypt(wpt);
write_waypt(wpt_a[i]);
}
xfree(wpt_a);
delete[] wpt_a;

route_idx = 0;
route_info = (info_t*) xcalloc(route_count(), sizeof(info_t));
Expand Down
5 changes: 5 additions & 0 deletions reference/duplicate_exported_1.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
No,Latitude,Longitude,Name,Exported
1,40.0,-105.1,"zero",2015/06/24 00:00:00
1,40.0,-105.2,"one",2015/06/25 00:00:01
1,40.0,-105.2,"two",2015/06/25 00:00:00
1,40.0,-105.1,"three",2015/06/24 00:00:01
3 changes: 3 additions & 0 deletions reference/duplicate_exported_1~csv.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
No,Latitude,Longitude,Name,Exported
1,40.000000,-105.200000,"one","2015/06/25 00:00:01"
2,40.000000,-105.100000,"three","2015/06/24 00:00:01"
5 changes: 5 additions & 0 deletions reference/duplicate_exported_2.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
No,Latitude,Longitude,Name,Exported
1,40.0,-105.1,"zero",2015/06/24 00:00:02
1,40.0,-105.2,"one",2015/06/25 00:00:01
1,40.0,-105.2,"two",2015/06/25 00:00:02
1,40.0,-105.1,"three",2015/06/24 00:00:01
3 changes: 3 additions & 0 deletions reference/duplicate_exported_2~csv.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
No,Latitude,Longitude,Name,Exported
1,40.000000,-105.100000,"zero","2015/06/24 00:00:02"
2,40.000000,-105.200000,"two","2015/06/25 00:00:02"
12 changes: 10 additions & 2 deletions smplrout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
2008/08/20: added "relative" option, (Carsten Allefeld, [email protected])
*/

#include <cstdlib> // for qsort, strtol
#include <algorithm> // for sort
#include <cstdlib> // for strtol
#include <utility> // for swap

#include <QDateTime> // for QDateTime
Expand Down Expand Up @@ -158,6 +159,9 @@ int SimplifyRouteFilter::compare_xte(const void* a, const void* b)
const auto* xte_b = static_cast<const struct xte*>(b);

if (HUGEVAL == xte_a->distance) {
if (HUGEVAL == xte_b->distance) {
return 0;
}
return -1;
}

Expand Down Expand Up @@ -238,7 +242,11 @@ void SimplifyRouteFilter::routesimple_tail(const route_head* rte)


/* sort XTE array, lowest XTE last */
qsort(xte_recs, xte_count, sizeof(struct xte), compare_xte);
auto compare_xte_lambda = [](const xte& a, const xte& b)->bool {
return compare_xte(&a, &b) < 0;
};
std::sort(xte_recs, xte_recs + xte_count, compare_xte_lambda);


for (i = 0; i < xte_count; i++) {
xte_recs[i].intermed->xte_rec = xte_recs+i;
Expand Down
5 changes: 5 additions & 0 deletions testo.d/duplicate.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ gpsbabel -i geo -f ${REFERENCE}/geocaching.loc -o csv -F ${TMPDIR}/filterdupe.cs
gpsbabel -i geo -f ${REFERENCE}/geocaching.loc -f ${REFERENCE}/geocaching.loc -x duplicate,shortname \
-o csv -F ${TMPDIR}/filterdupe.csv2
sort_and_compare ${TMPDIR}/filterdupe.csv1 ${TMPDIR}/filterdupe.csv2

gpsbabel -i unicsv,utc -f ${REFERENCE}/duplicate_exported_1.csv -x duplicate,location -o unicsv,utc -F ${TMPDIR}/duplicate_exported_1~csv.csv
compare ${REFERENCE}/duplicate_exported_1~csv.csv ${TMPDIR}/duplicate_exported_1~csv.csv
gpsbabel -i unicsv,utc -f ${REFERENCE}/duplicate_exported_2.csv -x duplicate,location -o unicsv,utc -F ${TMPDIR}/duplicate_exported_2~csv.csv
compare ${REFERENCE}/duplicate_exported_2~csv.csv ${TMPDIR}/duplicate_exported_2~csv.csv

0 comments on commit 5c93d07

Please sign in to comment.