Skip to content

Commit

Permalink
[libc++] Implement operator<=> for filesystem::path
Browse files Browse the repository at this point in the history
Implements part of P1614R2 "The Mothership has Landed"

Differential Revision: https://reviews.llvm.org/D130859
  • Loading branch information
vogelsgesang committed Aug 18, 2022
1 parent f3a55a1 commit b3ab3be
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 60 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/Status/SpaceshipProjects.csv
Expand Up @@ -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|
55 changes: 31 additions & 24 deletions libcxx/include/__filesystem/path.h
Expand Up @@ -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_); }

Expand Down Expand Up @@ -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 {
Expand Down
159 changes: 140 additions & 19 deletions libcxx/include/filesystem
Expand Up @@ -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>
Expand Down
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit b3ab3be

Please sign in to comment.