From b3451220ca2788b69e0db9c6bcfd6f6e0aa4cfe6 Mon Sep 17 00:00:00 2001 From: Steffen Schuemann Date: Sun, 27 Dec 2020 02:20:55 +0100 Subject: [PATCH] refs #71, work on c++20 api changes --- include/ghc/filesystem.hpp | 66 +++++++++++++++++++++++++++++++++++--- test/filesystem_test.cpp | 16 +++++++++ 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 1e57047..35529f9 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -141,6 +141,13 @@ #include #endif +#if defined(__cpp_impl_three_way_comparison) && defined(__has_include) +#if __has_include() +#define GHC_HAS_THREEWAY_COMP +#include +#endif +#endif + #include #include #include @@ -159,6 +166,13 @@ #include #else // GHC_EXPAND_IMPL + +#if defined(__cpp_impl_three_way_comparison) && defined(__has_include) +#if __has_include() +#define GHC_HAS_THREEWAY_COMP +#include +#endif +#endif #include #include #include @@ -203,6 +217,10 @@ // instead of replacing them with the unicode replacement character (U+FFFD). // #define GHC_RAISE_UNICODE_ERRORS //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Enforce C++17 API where possible when compiling for C++20, handles the following cases: +// * fs::path::u8string() returns std::string instead of std::u8string +// #define GHC_FILESYSTEM_ENFORCE_CPP17_API +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) #define GHC_FILESYSTEM_VERSION 10309L @@ -381,7 +399,11 @@ class GHC_FS_API_CLASS path std::basic_string string(const Allocator& a = Allocator()) const; std::string string() const; std::wstring wstring() const; +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + std::u8string u8string() const; +#else std::string u8string() const; +#endif std::u16string u16string() const; std::u32string u32string() const; @@ -390,7 +412,11 @@ class GHC_FS_API_CLASS path std::basic_string generic_string(const Allocator& a = Allocator()) const; const std::string& generic_string() const; // this is different from the standard, that returns by value std::wstring generic_wstring() const; +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + std::u8string generic_u8string() const; +#else std::string generic_u8string() const; +#endif std::u16string generic_u16string() const; std::u32string generic_u32string() const; @@ -480,13 +506,15 @@ class GHC_FS_API_CLASS path // 30.10.8.6 path non-member functions GHC_FS_API void swap(path& lhs, path& rhs) noexcept; GHC_FS_API size_t hash_value(const path& p) noexcept; +#ifdef GHC_HAS_THREEWAY_COMP +GHC_FS_API std::strong_ordering operator<=>( const path& lhs, const path& rhs ) noexcept; +#endif GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; - GHC_FS_API path operator/(const path& lhs, const path& rhs); // 30.10.8.6.1 path inserter and extractor @@ -497,8 +525,14 @@ std::basic_istream& operator>>(std::basic_istream& // 30.10.8.6.2 path factory functions template > +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) +[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] +#endif path u8path(const Source& source); template +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) +[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] +#endif path u8path(InputIterator first, InputIterator last); // 30.10.9 class filesystem_error @@ -2370,7 +2404,7 @@ GHC_INLINE path& path::operator/=(const path& p) } return *this; } - if ((p.is_absolute() && (_path != root_name() || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { + if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { assign(p); return *this; } @@ -2640,10 +2674,17 @@ GHC_INLINE std::wstring path::wstring() const #endif } +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) +GHC_INLINE std::u8string path::u8string() const +{ + return std::u8string(reinterpret_cast(native_impl().c_str())); +} +#else GHC_INLINE std::string path::u8string() const { return native_impl(); } +#endif GHC_INLINE std::u16string path::u16string() const { @@ -2677,10 +2718,17 @@ GHC_INLINE std::wstring path::generic_wstring() const return detail::fromUtf8(_path); } +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) +GHC_INLINE std::u8string path::generic_u8string() const +{ + return std::u8string(reinterpret_cast(_path.c_str())); +} +#else GHC_INLINE std::string path::generic_u8string() const { return _path; } +#endif GHC_INLINE std::u16string path::generic_u16string() const { @@ -3212,6 +3260,13 @@ GHC_INLINE size_t hash_value(const path& p) noexcept return std::hash()(p.generic_string()); } +#ifdef GHC_HAS_THREEWAY_COMP +GHC_INLINE std::strong_ordering operator<=>( const path& lhs, const path& rhs ) noexcept +{ + return lhs.compare(rhs) <=> 0; +} +#endif + GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) == 0; @@ -3242,6 +3297,7 @@ GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept return lhs.compare(rhs) >= 0; } + GHC_INLINE path operator/(const path& lhs, const path& rhs) { path result(lhs); @@ -3324,7 +3380,7 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const , _p1(p1) { if (!_p1.empty()) { - _what_arg += ": '" + _p1.u8string() + "'"; + _what_arg += ": '" + _p1.string() + "'"; } } @@ -3336,10 +3392,10 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const , _p2(p2) { if (!_p1.empty()) { - _what_arg += ": '" + _p1.u8string() + "'"; + _what_arg += ": '" + _p1.string() + "'"; } if (!_p2.empty()) { - _what_arg += ", '" + _p2.u8string() + "'"; + _what_arg += ", '" + _p2.string() + "'"; } } diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index ab80861..3fac64c 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -558,7 +558,11 @@ TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.pat CHECK((std::string)fs::u8path("\xc3\xa4\\\xe2\x82\xac") == std::string("\xc3\xa4\\\xe2\x82\xac")); #endif CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").wstring() == std::wstring(L"\u00E4\\\u20AC")); +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::u8string(u8"\xc3\xa4\\\xe2\x82\xac")); +#else CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::string("\xc3\xa4\\\xe2\x82\xac")); +#endif CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u16string() == std::u16string(u"\u00E4\\\u20AC")); CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4\\\U000020AC")); #else @@ -567,7 +571,11 @@ TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.pat CHECK((std::string)fs::u8path("\xc3\xa4/\xe2\x82\xac") == std::string("\xc3\xa4/\xe2\x82\xac")); CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").string() == std::string("\xc3\xa4/\xe2\x82\xac")); CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").wstring() == std::wstring(L"ä/€")); +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac")); +#else CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::string("\xc3\xa4/\xe2\x82\xac")); +#endif CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u16string() == std::u16string(u"\u00E4/\u20AC")); INFO("This check might fail on GCC8 (with \"Illegal byte sequence\") due to not detecting the valid unicode codepoint U+1D11E."); CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e").u16string() == std::u16string(u"\u00E4/\u20AC\U0001D11E")); @@ -586,7 +594,11 @@ TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.pa CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac")); #endif CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_wstring() == std::wstring(L"\U000000E4/\U000020AC")); +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac")); +#else CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac")); +#endif CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC")); CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC")); #else @@ -596,7 +608,11 @@ TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.pa CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac")); #endif CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_wstring() == std::wstring(L"ä/€")); +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac")); +#else CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac")); +#endif CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC")); CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC")); #endif