Merge pull request #12007 from chennes/toponamingElementNameComparator

App/Toponaming: Add Comparator for mapped elements
This commit is contained in:
Chris Hennes
2024-01-19 09:20:59 -06:00
committed by GitHub
3 changed files with 237 additions and 0 deletions

View File

@@ -22,3 +22,136 @@
#include "PreCompiled.h"
#include "MappedElement.h"
using namespace Data;
bool ElementNameComparator::operator()(const MappedName& leftName,
const MappedName& rightName) const
{
int size = static_cast<int>(std::min(leftName.size(), rightName.size()));
if (size == 0U) {
return leftName.size() < rightName.size();
}
int currentIndex = 0;
if (rightName[0] == '#') {
if (leftName[0] != '#') {
return true;
}
// If both string starts with '#', compare the following hex digits by
// its integer value.
int res = 0;
for (currentIndex = 1; currentIndex < size; ++currentIndex) {
auto ac = (unsigned char)leftName[currentIndex];
auto bc = (unsigned char)rightName[currentIndex];
if (std::isxdigit(bc) != 0) {
if (std::isxdigit(ac) == 0) {
return true;
}
if (res == 0) {
if (ac < bc) {
res = -1;
}
else if (ac > bc) {
res = 1;
}
}
}
else if (std::isxdigit(ac) != 0) {
res = 1;
}
else {
break;
}
}
if (res < 0) {
return true;
}
if (res > 0) {
return false;
}
for (; currentIndex < size; ++currentIndex) {
char ac = leftName[currentIndex];
char bc = rightName[currentIndex];
if (ac < bc) {
return true;
}
if (ac > bc) {
return false;
}
}
return leftName.size() < rightName.size();
}
if (leftName[0] == '#') {
return false;
}
// If the string does not start with '#', compare the non-digits prefix
// using lexical order.
for (currentIndex = 0; currentIndex < size; ++currentIndex) {
auto ac = (unsigned char)leftName[currentIndex];
auto bc = (unsigned char)rightName[currentIndex];
if (std::isdigit(bc) == 0) {
if (std::isdigit(ac) != 0) {
return true;
}
if (ac < bc) {
return true;
}
if (ac > bc) {
return false;
}
}
else if (std::isdigit(ac) == 0) {
return false;
}
else {
break;
}
}
// Then compare the following digits part by integer value
int res = 0;
for (; currentIndex < size; ++currentIndex) {
auto ac = (unsigned char)leftName[currentIndex];
auto bc = (unsigned char)rightName[currentIndex];
if (std::isdigit(bc) != 0) {
if (std::isdigit(ac) == 0) {
return true;
}
if (res == 0) {
if (ac < bc) {
res = -1;
}
else if (ac > bc) {
res = 1;
}
}
}
else if (std::isdigit(ac) != 0) {
return false;
}
else {
break;
}
}
if (res < 0) {
return true;
}
if (res > 0) {
return false;
}
// Finally, compare the remaining tail using lexical order
for (; currentIndex < size; ++currentIndex) {
char ac = leftName[currentIndex];
char bc = rightName[currentIndex];
if (ac < bc) {
return true;
}
if (ac > bc) {
return false;
}
}
return leftName.size() < rightName.size();
}

View File

@@ -98,6 +98,22 @@ struct AppExport MappedElement
}
};
struct AppExport ElementNameComparator {
/** Comparison function to make topo name more stable
*
* The sorting decomposes the name into either of the following two forms
* '#' + hex_digits + tail
* non_digits + digits + tail
*
* The non-digits part is compared lexically, while the digits part is
* compared by its integer value.
*
* The reason for this is to prevent names with bigger digits (which usually means
* they come later in history) from coming earlier when sorting.
*/
bool operator()(const MappedName & leftName, const MappedName & rightName) const;
};
}// namespace Data