Skip to content

Commit 56b5e7a

Browse files
committed
refs #70, compare windows root names case insensitive, work on LWG 2936 option
1 parent d34cf83 commit 56b5e7a

File tree

3 files changed

+112
-8
lines changed

3 files changed

+112
-8
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/*build*/
2+
.vs/
23
.vscode/
34
.idea/
45
*.swp
6+
*~
57
.DS_Store

include/ghc/filesystem.hpp

+100-5
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@
177177
// file with that name, it is superceded by P1164R1, so only activate if really needed
178178
// #define LWG_2935_BEHAVIOUR
179179
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
180+
// LWG #2936 enables new element wise (more expensive) path comparison
181+
// * if this->root_name().native().compare(p.root_name().native()) != 0 return result
182+
// * if this->has_root_directory() and !p.has_root_directory() return -1
183+
// * if !this->has_root_directory() and p.has_root_directory() return -1
184+
// * else result of element wise comparison of path iteration where first comparison is != 0 or 0
185+
// if all comparisons are 0 (on Windows this implementation does case insensitive root_name()
186+
// comparison)
187+
// #define LWG_2936_BEHAVIOUR
188+
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
180189
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
181190
#define LWG_2937_BEHAVIOUR
182191
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1754,6 +1763,21 @@ GHC_INLINE bool equals_simple_insensitive(const char* str1, const char* str2)
17541763
#endif
17551764
}
17561765

1766+
GHC_INLINE int compare_simple_insensitive(const char* str1, size_t len1, const char* str2, size_t len2)
1767+
{
1768+
while(len1 > 0 && len2 > 0 && ::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2)) {
1769+
--len1; --len2;
1770+
++str1; ++str2;
1771+
}
1772+
if (len1 && len2) {
1773+
return *str1 < *str2 ? -1 : 1;
1774+
}
1775+
if(len1 == 0 && len2 == 0) {
1776+
return 0;
1777+
}
1778+
return len1 == 0 ? -1 : 1;
1779+
}
1780+
17571781
GHC_INLINE const char* strerror_adapter(char* gnu, char*)
17581782
{
17591783
return gnu;
@@ -2652,24 +2676,75 @@ GHC_INLINE std::u32string path::generic_u32string() const
26522676
// 30.10.8.4.8, compare
26532677
GHC_INLINE int path::compare(const path& p) const noexcept
26542678
{
2655-
return native().compare(p.native());
2679+
#ifdef LWG_2936_BEHAVIOUR
2680+
auto rnl1 = root_name_length();
2681+
auto rnl2 = p.root_name_length();
2682+
#ifdef GHC_OS_WINDOWS
2683+
auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);
2684+
#else
2685+
auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2)));
2686+
#endif
2687+
if (rnc) {
2688+
return rnc;
2689+
}
2690+
bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory();
2691+
if (hrd1 != hrd2) {
2692+
return hrd1 ? 1 : -1;
2693+
}
2694+
if (hrd1) {
2695+
++rnl1;
2696+
++rnl2;
2697+
}
2698+
auto iter1 = _path.begin() + rnl1;
2699+
auto iter2 = p._path.begin() + rnl2;
2700+
while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) {
2701+
++iter1;
2702+
++iter2;
2703+
}
2704+
if (iter1 == _path.end()) {
2705+
return iter2 == p._path.end() ? 0 : -1;
2706+
}
2707+
if (iter2 == p._path.end()) {
2708+
return 1;
2709+
}
2710+
if (*iter1 == '/') {
2711+
return -1;
2712+
}
2713+
if (*iter2 == '/') {
2714+
return 1;
2715+
}
2716+
return *iter1 < *iter2 ? -1 : 1;
2717+
#else // LWG_2936_BEHAVIOUR
2718+
#ifdef GHC_OS_WINDOWS
2719+
auto rnl1 = root_name_length();
2720+
auto rnl2 = p.root_name_length();
2721+
auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);
2722+
auto p1 = _path;
2723+
std::replace(p1.begin()+rnl1, p1.end(), '/', '\\');
2724+
auto p2 = p._path;
2725+
std::replace(p2.begin()+rnl2, p2.end(), '/', '\\');
2726+
return p1.compare(rnl1, std::string::npos, p2, rnl2, std::string::npos);
2727+
#else
2728+
return _path.compare(p._path);
2729+
#endif
2730+
#endif
26562731
}
26572732

26582733
GHC_INLINE int path::compare(const string_type& s) const
26592734
{
2660-
return native().compare(path(s).native());
2735+
return compare(path(s));
26612736
}
26622737

26632738
#ifdef __cpp_lib_string_view
26642739
GHC_INLINE int path::compare(std::basic_string_view<value_type> s) const
26652740
{
2666-
return native().compare(path(s).native());
2741+
return compare(path(s));
26672742
}
26682743
#endif
26692744

26702745
GHC_INLINE int path::compare(const value_type* s) const
26712746
{
2672-
return native().compare(path(s).native());
2747+
return compare(path(s));
26732748
}
26742749

26752750
//-----------------------------------------------------------------------------
@@ -3116,32 +3191,52 @@ GHC_INLINE size_t hash_value(const path& p) noexcept
31163191

31173192
GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept
31183193
{
3194+
#ifdef LWG_2936_BEHAVIOUR
3195+
return lhs.compare(rhs) == 0;
3196+
#else
31193197
return lhs.generic_string() == rhs.generic_string();
3198+
#endif
31203199
}
31213200

31223201
GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept
31233202
{
3124-
return lhs.generic_string() != rhs.generic_string();
3203+
return !(lhs == rhs);
31253204
}
31263205

31273206
GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept
31283207
{
3208+
#ifdef LWG_2936_BEHAVIOUR
3209+
return lhs.compare(rhs) < 0;
3210+
#else
31293211
return lhs.generic_string() < rhs.generic_string();
3212+
#endif
31303213
}
31313214

31323215
GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept
31333216
{
3217+
#ifdef LWG_2936_BEHAVIOUR
3218+
return lhs.compare(rhs) <= 0;
3219+
#else
31343220
return lhs.generic_string() <= rhs.generic_string();
3221+
#endif
31353222
}
31363223

31373224
GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept
31383225
{
3226+
#ifdef LWG_2936_BEHAVIOUR
3227+
return lhs.compare(rhs) > 0;
3228+
#else
31393229
return lhs.generic_string() > rhs.generic_string();
3230+
#endif
31403231
}
31413232

31423233
GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept
31433234
{
3235+
#ifdef LWG_2936_BEHAVIOUR
3236+
return lhs.compare(rhs) >= 0;
3237+
#else
31443238
return lhs.generic_string() >= rhs.generic_string();
3239+
#endif
31453240
}
31463241

31473242
GHC_INLINE path operator/(const path& lhs, const path& rhs)

test/filesystem_test.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,16 @@ TEST_CASE("30.10.8.4.8 path compare", "[filesystem][path][fs.path.compare]")
615615
CHECK(fs::path("/foo/b").compare(fs::path("/foo/a")) > 0);
616616
CHECK(fs::path("/foo/b").compare(fs::path("/foo/b")) == 0);
617617
CHECK(fs::path("/foo/b").compare(fs::path("/foo/c")) < 0);
618+
619+
#ifdef GHC_OS_WINDOWS
620+
CHECK(fs::path("c:\\a\\b").compare("C:\\a\\b") == 0);
621+
CHECK(fs::path("c:\\a\\b").compare("C:\\A\\b") != 0);
622+
#endif
623+
624+
#ifdef LWG_2936_BEHAVIOUR
625+
CHECK(fs::path("/a/b/").compare("/a/b/c") < 0);
626+
CHECK(fs::path("/a/b/").compare("a/c") > 0);
627+
#endif // LWG_2936_BEHAVIOUR
618628
}
619629

620630
TEST_CASE("30.10.8.4.9 path decomposition", "[filesystem][path][fs.path.decompose]")
@@ -2331,12 +2341,9 @@ TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_wr
23312341
CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
23322342
nt = timeFromString("2015-10-21T04:29:00");
23332343
CHECK_NOTHROW(fs::last_write_time("foo", nt, ec));
2334-
std::cout << "about to call last_write_time" << std::endl;
23352344
CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
23362345
CHECK(!ec);
2337-
std::cout << "about to call last_write_time" << std::endl;
23382346
CHECK_THROWS_AS(fs::last_write_time("bar", nt), fs::filesystem_error);
2339-
std::cout << "about to call last_write_time" << std::endl;
23402347
CHECK_NOTHROW(fs::last_write_time("bar", nt, ec));
23412348
CHECK(ec);
23422349
#endif

0 commit comments

Comments
 (0)