From 6064be33e5bd76460982b252b6c04c1a353a6a85 Mon Sep 17 00:00:00 2001 From: Florent Rougon Date: Sat, 18 Nov 2017 14:25:01 +0100 Subject: [PATCH] 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. --- simgear/misc/path_test.cxx | 56 ++++++++++++++++++++++++++++++++++---- simgear/misc/sg_path.cxx | 12 ++++++++ simgear/misc/sg_path.hxx | 28 +++++++++++++++++-- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/simgear/misc/path_test.cxx b/simgear/misc/path_test.cxx index d9364336..19e82a27 100644 --- a/simgear/misc/path_test.cxx +++ b/simgear/misc/path_test.cxx @@ -2,7 +2,11 @@ #include +#include +#include #include +#include + #include #include @@ -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 origVector({ + std::string("/zer/gh/tr aze"), + std::string("/abc/def/ttt"), + std::string("/abc/def/ddd"), + std::string("/a"), + std::string("")}); + std::vector 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 specialization\n"; + + const SGPath nullPath{}; + const SGPath p{"/abc/def"}; + + SG_CHECK_EQUAL(std::hash{}(nullPath), std::hash{}(nullPath)); + SG_CHECK_EQUAL(std::hash{}(p), std::hash{}(p)); + SG_CHECK_NE(std::hash{}(p), std::hash{}(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 diff --git a/simgear/misc/sg_path.cxx b/simgear/misc/sg_path.cxx index 31f84bc7..299a004c 100644 --- a/simgear/misc/sg_path.cxx +++ b/simgear/misc/sg_path.cxx @@ -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) { diff --git a/simgear/misc/sg_path.hxx b/simgear/misc/sg_path.hxx index f18ffe18..a9ef7c03 100644 --- a/simgear/misc/sg_path.hxx +++ b/simgear/misc/sg_path.hxx @@ -28,12 +28,14 @@ #ifndef _SG_PATH_HXX #define _SG_PATH_HXX +#include +#include + +#include +#include #include #include -#include -#include - #include #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 +{ + std::size_t operator()(const SGPath& path) const noexcept + { + return std::hash{}(path.utf8Str()); + } +}; +} // of namespace std + /// Output to an ostream template inline