[libcxx-commits] [libcxx] b3ab3be - [libc++] Implement `operator<=>` for `filesystem::path`

Adrian Vogelsgesang via libcxx-commits libcxx-commits at lists.llvm.org
Thu Aug 18 14:14:05 PDT 2022


Author: Adrian Vogelsgesang
Date: 2022-08-18T14:13:48-07:00
New Revision: b3ab3bece0bf1d441518b7d3b1294cb72445cb0f

URL: https://github.com/llvm/llvm-project/commit/b3ab3bece0bf1d441518b7d3b1294cb72445cb0f
DIFF: https://github.com/llvm/llvm-project/commit/b3ab3bece0bf1d441518b7d3b1294cb72445cb0f.diff

LOG: [libc++] Implement `operator<=>` for `filesystem::path`

Implements part of P1614R2 "The Mothership has Landed"

Differential Revision: https://reviews.llvm.org/D130859

Added: 
    

Modified: 
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/__filesystem/path.h
    libcxx/include/filesystem
    libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index 5b4e52c228af5..6f3ea312e99b7 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -75,7 +75,7 @@ Section,Description,Dependencies,Assignee,Complete
 | chrono::leap_second
 | chrono::time_zone_link",A ``<chrono>`` implementation,Unassigned,|Not Started|
 | `[fs.filesystem.syn] <https://wg21.link/fs.filesystem.syn>`_,| `filesystem::space_info <https://reviews.llvm.org/D130861>`_,None,Adrian Vogelsgesang,|Complete|
-| `[fs.path.nonmember] <https://wg21.link/fs.path.nonmember>`_,| `filesystem::path <https://reviews.llvm.org/D130859>`_,None,Adrian Vogelsgesang,|In Progress|
+| `[fs.path.nonmember] <https://wg21.link/fs.path.nonmember>`_,| `filesystem::path <https://reviews.llvm.org/D130859>`_,None,Adrian Vogelsgesang,|Complete|
 | `[fs.dir.entry.obs] <https://wg21.link/fs.dir.entry.obs>`_,| `filesystem::directory_entry <https://reviews.llvm.org/D130860>`_,None,Adrian Vogelsgesang,|In Progress|
 | `[re.submatch.op] <https://wg21.link/re.submatch.op>`_,| sub_match,None,Mark de Wever,|In Progress|
 | `[thread.thread.id] <https://wg21.link/thread.thread.id>`_,| `thread::id <https://reviews.llvm.org/D131362>`_,None,Adrian Vogelsgesang,|Complete|

diff  --git a/libcxx/include/__filesystem/path.h b/libcxx/include/__filesystem/path.h
index 8fafd72c7e4f6..6307b594a888f 100644
--- a/libcxx/include/__filesystem/path.h
+++ b/libcxx/include/__filesystem/path.h
@@ -732,6 +732,37 @@ class _LIBCPP_TYPE_VIS path {
 
   path& replace_extension(const path& __replacement = path());
 
+  friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) == 0;
+  }
+#  if _LIBCPP_STD_VER <= 17
+  friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) != 0;
+  }
+  friend _LIBCPP_HIDE_FROM_ABI bool operator<(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) < 0;
+  }
+  friend _LIBCPP_HIDE_FROM_ABI bool operator<=(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) <= 0;
+  }
+  friend _LIBCPP_HIDE_FROM_ABI bool operator>(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) > 0;
+  }
+  friend _LIBCPP_HIDE_FROM_ABI bool operator>=(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) >= 0;
+  }
+#  else // _LIBCPP_STD_VER <= 17
+  friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.__compare(__rhs.__pn_) <=> 0;
+  }
+#  endif // _LIBCPP_STD_VER <= 17
+
+  friend _LIBCPP_HIDE_FROM_ABI path operator/(const path& __lhs, const path& __rhs) {
+    path __result(__lhs);
+    __result /= __rhs;
+    return __result;
+  }
+
   _LIBCPP_HIDE_FROM_ABI
   void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); }
 
@@ -1035,30 +1066,6 @@ class _LIBCPP_TYPE_VIS path {
   }
 #endif // !_LIBCPP_HAS_NO_LOCALIZATION
 
-  friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept {
-    return __lhs.__compare(__rhs.__pn_) == 0;
-  }
-  friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const path& __lhs, const path& __rhs) noexcept {
-    return __lhs.__compare(__rhs.__pn_) != 0;
-  }
-  friend _LIBCPP_HIDE_FROM_ABI bool operator<(const path& __lhs, const path& __rhs) noexcept {
-    return __lhs.__compare(__rhs.__pn_) < 0;
-  }
-  friend _LIBCPP_HIDE_FROM_ABI bool operator<=(const path& __lhs, const path& __rhs) noexcept {
-    return __lhs.__compare(__rhs.__pn_) <= 0;
-  }
-  friend _LIBCPP_HIDE_FROM_ABI bool operator>(const path& __lhs, const path& __rhs) noexcept {
-    return __lhs.__compare(__rhs.__pn_) > 0;
-  }
-  friend _LIBCPP_HIDE_FROM_ABI bool operator>=(const path& __lhs, const path& __rhs) noexcept {
-    return __lhs.__compare(__rhs.__pn_) >= 0;
-  }
-
-  friend _LIBCPP_HIDE_FROM_ABI path operator/(const path& __lhs, const path& __rhs) {
-    path __result(__lhs);
-    __result /= __rhs;
-    return __result;
-  }
 private:
   inline _LIBCPP_HIDE_FROM_ABI path&
   __assign_view(__string_view const& __s) noexcept {

diff  --git a/libcxx/include/filesystem b/libcxx/include/filesystem
index aa0cd562e2afb..8b81e10515a6e 100644
--- a/libcxx/include/filesystem
+++ b/libcxx/include/filesystem
@@ -14,29 +14,150 @@
 
     namespace std::filesystem {
 
-    class path;
+    // `class path` from http://eel.is/c++draft/fs.class.path.general#6
+    class path {
+      public:
+        using value_type  = see below;
+        using string_type = basic_string<value_type>;
+        static constexpr value_type preferred_separator = see below;
+
+        enum format;
+
+        path() noexcept;
+        path(const path& p);
+        path(path&& p) noexcept;
+        path(string_type&& source, format fmt = auto_format);
+        template<class Source>
+          path(const Source& source, format fmt = auto_format);
+        template<class InputIterator>
+          path(InputIterator first, InputIterator last, format fmt = auto_format);
+        template<class Source>
+          path(const Source& source, const locale& loc, format fmt = auto_format);
+        template<class InputIterator>
+          path(InputIterator first, InputIterator last, const locale& loc, format fmt = auto_format);
+        ~path();
+
+        path& operator=(const path& p);
+        path& operator=(path&& p) noexcept;
+        path& operator=(string_type&& source);
+        path& assign(string_type&& source);
+        template<class Source>
+          path& operator=(const Source& source);
+        template<class Source>
+          path& assign(const Source& source);
+        template<class InputIterator>
+          path& assign(InputIterator first, InputIterator last);
+
+        path& operator/=(const path& p);
+        template<class Source>
+          path& operator/=(const Source& source);
+        template<class Source>
+          path& append(const Source& source);
+        template<class InputIterator>
+          path& append(InputIterator first, InputIterator last);
+
+        path& operator+=(const path& x);
+        path& operator+=(const string_type& x);
+        path& operator+=(basic_string_view<value_type> x);
+        path& operator+=(const value_type* x);
+        path& operator+=(value_type x);
+        template<class Source>
+          path& operator+=(const Source& x);
+        template<class EcharT>
+          path& operator+=(EcharT x);
+        template<class Source>
+          path& concat(const Source& x);
+        template<class InputIterator>
+          path& concat(InputIterator first, InputIterator last);
+
+        void  clear() noexcept;
+        path& make_preferred();
+        path& remove_filename();
+        path& replace_filename(const path& replacement);
+        path& replace_extension(const path& replacement = path());
+        void  swap(path& rhs) noexcept;
+
+        friend bool operator==(const path& lhs, const path& rhs) noexcept;
+        friend bool operator!=(const path& lhs, const path& rhs) noexcept;             // removed in C++20
+        friend bool operator< (const path& lhs, const path& rhs) noexcept;             // removed in C++20
+        friend bool operator<=(const path& lhs, const path& rhs) noexcept;             // removed in C++20
+        friend bool operator> (const path& lhs, const path& rhs) noexcept;             // removed in C++20
+        friend bool operator>=(const path& lhs, const path& rhs) noexcept;             // removed in C++20
+        friend strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept; // C++20
+
+        friend path operator/(const path& lhs, const path& rhs);
+
+        const string_type& native() const noexcept;
+        const value_type*  c_str() const noexcept;
+        operator string_type() const;
+
+        template<class EcharT, class traits = char_traits<EcharT>,
+                 class Allocator = allocator<EcharT>>
+          basic_string<EcharT, traits, Allocator>
+            string(const Allocator& a = Allocator()) const;
+        std::string    string() const;
+        std::wstring   wstring() const;
+        std::u8string  u8string() const;
+        std::u16string u16string() const;
+        std::u32string u32string() const;
+
+        template<class EcharT, class traits = char_traits<EcharT>,
+                 class Allocator = allocator<EcharT>>
+          basic_string<EcharT, traits, Allocator>
+            generic_string(const Allocator& a = Allocator()) const;
+        std::string    generic_string() const;
+        std::wstring   generic_wstring() const;
+        std::u8string  generic_u8string() const;
+        std::u16string generic_u16string() const;
+        std::u32string generic_u32string() const;
+
+        int compare(const path& p) const noexcept;
+        int compare(const string_type& s) const;
+        int compare(basic_string_view<value_type> s) const;
+        int compare(const value_type* s) const;
+
+        path root_name() const;
+        path root_directory() const;
+        path root_path() const;
+        path relative_path() const;
+        path parent_path() const;
+        path filename() const;
+        path stem() const;
+        path extension() const;
+
+        [[nodiscard]] bool empty() const noexcept;
+        bool has_root_name() const;
+        bool has_root_directory() const;
+        bool has_root_path() const;
+        bool has_relative_path() const;
+        bool has_parent_path() const;
+        bool has_filename() const;
+        bool has_stem() const;
+        bool has_extension() const;
+        bool is_absolute() const;
+        bool is_relative() const;
+
+        path lexically_normal() const;
+        path lexically_relative(const path& base) const;
+        path lexically_proximate(const path& base) const;
+
+        class iterator;
+        using const_iterator = iterator;
+
+        iterator begin() const;
+        iterator end() const;
+
+        template<class charT, class traits>
+          friend basic_ostream<charT, traits>&
+            operator<<(basic_ostream<charT, traits>& os, const path& p);
+        template<class charT, class traits>
+          friend basic_istream<charT, traits>&
+            operator>>(basic_istream<charT, traits>& is, path& p);
+    };
 
     void swap(path& lhs, path& rhs) noexcept;
     size_t hash_value(const path& p) noexcept;
 
-    bool operator==(const path& lhs, const path& rhs) noexcept;
-    bool operator!=(const path& lhs, const path& rhs) noexcept;
-    bool operator< (const path& lhs, const path& rhs) noexcept;
-    bool operator<=(const path& lhs, const path& rhs) noexcept;
-    bool operator> (const path& lhs, const path& rhs) noexcept;
-    bool operator>=(const path& lhs, const path& rhs) noexcept;
-
-    path operator/ (const path& lhs, const path& rhs);
-
-    // fs.path.io operators are friends of path.
-    template <class charT, class traits>
-    friend basic_ostream<charT, traits>&
-    operator<<(basic_ostream<charT, traits>& os, const path& p);
-
-    template <class charT, class traits>
-    friend basic_istream<charT, traits>&
-    operator>>(basic_istream<charT, traits>& is, path& p);
-
     template <class Source>
       path u8path(const Source& source);
     template <class InputIterator>

diff  --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
index 975e96c3031cf..3e194a7816132 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
@@ -22,16 +22,17 @@
 // bool operator<=(path const&, path const&) noexcept;
 // bool operator> (path const&, path const&) noexcept;
 // bool operator>=(path const&, path const&) noexcept;
+// strong_ordering operator<=>(path const&, path const&) noexcept;
 //
 // size_t hash_value(path const&) noexcept;
 
-
 #include "filesystem_include.h"
 #include <type_traits>
 #include <vector>
 #include <cassert>
 
 #include "test_macros.h"
+#include "test_comparisons.h"
 #include "test_iterators.h"
 #include "count_new.h"
 #include "filesystem_test_helper.h"
@@ -111,21 +112,19 @@ void test_compare_basic()
     { // comparison operators
       DisableAllocationGuard g; // none of these operations should allocate
 
-      // Check runtime result
-      assert((p1 == p2) == (E == 0));
-      assert((p1 != p2) == (E != 0));
-      assert((p1 <  p2) == (E <  0));
-      assert((p1 <= p2) == (E <= 0));
-      assert((p1 >  p2) == (E >  0));
-      assert((p1 >= p2) == (E >= 0));
-
-      // Check signatures
-      ASSERT_NOEXCEPT(p1 == p2);
-      ASSERT_NOEXCEPT(p1 != p2);
-      ASSERT_NOEXCEPT(p1 <  p2);
-      ASSERT_NOEXCEPT(p1 <= p2);
-      ASSERT_NOEXCEPT(p1 >  p2);
-      ASSERT_NOEXCEPT(p1 >= p2);
+      // check signatures
+      AssertComparisonsAreNoexcept<path>();
+      AssertComparisonsReturnBool<path>();
+#if TEST_STD_VER > 17
+      AssertOrderAreNoexcept<path>();
+      AssertOrderReturn<std::strong_ordering, path>();
+#endif
+
+      // check comarison results
+      assert(testComparisons(p1, p2, /*isEqual*/ E == 0, /*isLess*/ E < 0));
+#if TEST_STD_VER > 17
+      assert(testOrder(p1, p2, E <=> 0));
+#endif
     }
     { // check hash values
       auto h1 = hash_value(p1);


        


More information about the libcxx-commits mailing list