SGPath: add comparison operators (<, >, <=, >=) and an std::hash specialization

This allows one to use SGPath in containers such as std::map,
std::unordered_map and std::unordered_set.

Like the existing == and !=, all these operators rely solely on the
UTF-8 internal representation of the path.
This commit is contained in:
Florent Rougon
2017-11-18 14:25:01 +01:00
parent 1540d6f472
commit 6064be33e5
3 changed files with 88 additions and 8 deletions

View File

@@ -2,7 +2,11 @@
#include <simgear/compiler.h>
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cstring>
@@ -286,6 +290,49 @@ void test_permissions()
SG_CHECK_EQUAL(fileInRW.canWrite(), false);
}
void test_comparisons()
{
std::cout << "Testing comparisons\n";
SG_CHECK_EQUAL(SGPath("/abc/def ghi"), SGPath("/abc/def ghi"));
SG_CHECK_NE(SGPath("/abc"), SGPath("abc"));
SG_CHECK_LT(SGPath(""), SGPath("/"));
SG_CHECK_LT(SGPath("A"), SGPath("a"));
SG_CHECK_LE(SGPath(""), SGPath("/"));
SG_CHECK_LE(SGPath("/"), SGPath("/"));
SG_CHECK_GT(SGPath("a"), SGPath("A"));
SG_CHECK_GE(SGPath("a"), SGPath("A"));
SG_CHECK_GE(SGPath("a"), SGPath("a"));
std::vector<SGPath> origVector({
std::string("/zer/gh/tr aze"),
std::string("/abc/def/ttt"),
std::string("/abc/def/ddd"),
std::string("/a"),
std::string("")});
std::vector<SGPath> sortedVector({
std::string(""),
std::string("/a"),
std::string("/abc/def/ddd"),
std::string("/abc/def/ttt"),
std::string("/zer/gh/tr aze")});
std::sort(origVector.begin(), origVector.end());
SG_CHECK_EQUAL_NOSTREAM(origVector, sortedVector);
}
void test_hash_function()
{
std::cout << "Testing the std::hash<SGPath> specialization\n";
const SGPath nullPath{};
const SGPath p{"/abc/def"};
SG_CHECK_EQUAL(std::hash<SGPath>{}(nullPath), std::hash<SGPath>{}(nullPath));
SG_CHECK_EQUAL(std::hash<SGPath>{}(p), std::hash<SGPath>{}(p));
SG_CHECK_NE(std::hash<SGPath>{}(p), std::hash<SGPath>{}(p / "foobar"));
}
int main(int argc, char* argv[])
{
SGPath pa;
@@ -389,12 +436,11 @@ int main(int argc, char* argv[])
SG_CHECK_EQUAL(pp.canWrite(), false);
test_dir();
test_path_dir();
test_path_dir();
test_permissions();
test_update_dir();
test_update_dir();
test_comparisons();
test_hash_function();
cout << "all tests passed OK" << endl;
return 0; // passed

View File

@@ -742,6 +742,18 @@ bool SGPath::operator!=(const SGPath& other) const
return (path != other.path);
}
bool operator<(const SGPath& lhs, const SGPath& rhs)
{ return lhs.path < rhs.path; }
bool operator>(const SGPath& lhs, const SGPath& rhs)
{ return operator<(rhs, lhs); }
bool operator<=(const SGPath& lhs, const SGPath& rhs)
{ return !operator>(lhs, rhs); }
bool operator>=(const SGPath& lhs, const SGPath& rhs)
{ return !operator<(lhs, rhs); }
//------------------------------------------------------------------------------
bool SGPath::rename(const SGPath& newName)
{

View File

@@ -28,12 +28,14 @@
#ifndef _SG_PATH_HXX
#define _SG_PATH_HXX
#include <functional>
#include <string>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include <simgear/compiler.h>
#include <string>
#include <ctime>
#include <simgear/math/sg_types.hxx>
#ifdef _MSC_VER
@@ -91,6 +93,8 @@ public:
bool operator==(const SGPath& other) const;
bool operator!=(const SGPath& other) const;
// Other comparison operators are declared below
friend bool operator<(const SGPath& lhs, const SGPath& rhs);
void setPermissionChecker(PermissionChecker validator);
PermissionChecker getPermissionChecker() const;
@@ -349,6 +353,24 @@ private:
mutable size_t _size;
};
// Other comparison operators are in the class definition block
bool operator> (const SGPath& lhs, const SGPath& rhs);
bool operator<=(const SGPath& lhs, const SGPath& rhs);
bool operator>=(const SGPath& lhs, const SGPath& rhs);
// Hash function for SGPath
namespace std
{
template<>
struct hash<SGPath>
{
std::size_t operator()(const SGPath& path) const noexcept
{
return std::hash<std::string>{}(path.utf8Str());
}
};
} // of namespace std
/// Output to an ostream
template<typename char_type, typename traits_type>
inline