[libc++] Implement operator<=> for filesystem::directory_entry

Implements part of P1614R2 "The Mothership has Landed"

Differential Revision: https://reviews.llvm.org/D130860
This commit is contained in:
Adrian Vogelsgesang 2022-07-31 15:57:10 -07:00 committed by Adrian Vogelsgesang
parent 3838245dc4
commit f1974f039f
4 changed files with 104 additions and 59 deletions

View File

@ -76,6 +76,6 @@ Section,Description,Dependencies,Assignee,Complete
| 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,|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|
| `[fs.dir.entry.obs] <https://wg21.link/fs.dir.entry.obs>`_,| `filesystem::directory_entry <https://reviews.llvm.org/D130860>`_,None,Adrian Vogelsgesang,|Complete|
| `[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|

1 Section Description Dependencies Assignee Complete
76
77
78
79
80
81

View File

@ -215,21 +215,23 @@ public:
return __get_symlink_status(&__ec);
}
_LIBCPP_INLINE_VISIBILITY
bool operator<(directory_entry const& __rhs) const noexcept {
return __p_ < __rhs.__p_;
}
_LIBCPP_INLINE_VISIBILITY
bool operator==(directory_entry const& __rhs) const noexcept {
return __p_ == __rhs.__p_;
}
#if _LIBCPP_STD_VER <= 17
_LIBCPP_INLINE_VISIBILITY
bool operator!=(directory_entry const& __rhs) const noexcept {
return __p_ != __rhs.__p_;
}
_LIBCPP_INLINE_VISIBILITY
bool operator<(directory_entry const& __rhs) const noexcept {
return __p_ < __rhs.__p_;
}
_LIBCPP_INLINE_VISIBILITY
bool operator<=(directory_entry const& __rhs) const noexcept {
return __p_ <= __rhs.__p_;
@ -245,6 +247,15 @@ public:
return __p_ >= __rhs.__p_;
}
#else // _LIBCPP_STD_VER <= 17
_LIBCPP_HIDE_FROM_ABI
strong_ordering operator<=>(const directory_entry& __rhs) const noexcept {
return __p_ <=> __rhs.__p_;
}
#endif // _LIBCPP_STD_VER <= 17
template <class _CharT, class _Traits>
_LIBCPP_INLINE_VISIBILITY
friend basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const directory_entry& __d) {

View File

@ -164,7 +164,73 @@
path u8path(InputIterator first, InputIterator last);
class filesystem_error;
class directory_entry;
class directory_entry {
public:
directory_entry() noexcept = default;
directory_entry(const directory_entry&) = default;
directory_entry(directory_entry&&) noexcept = default;
explicit directory_entry(const filesystem::path& p);
directory_entry(const filesystem::path& p, error_code& ec);
~directory_entry();
directory_entry& operator=(const directory_entry&) = default;
directory_entry& operator=(directory_entry&&) noexcept = default;
void assign(const filesystem::path& p);
void assign(const filesystem::path& p, error_code& ec);
void replace_filename(const filesystem::path& p);
void replace_filename(const filesystem::path& p, error_code& ec);
void refresh();
void refresh(error_code& ec) noexcept;
const filesystem::path& path() const noexcept;
operator const filesystem::path&() const noexcept;
bool exists() const;
bool exists(error_code& ec) const noexcept;
bool is_block_file() const;
bool is_block_file(error_code& ec) const noexcept;
bool is_character_file() const;
bool is_character_file(error_code& ec) const noexcept;
bool is_directory() const;
bool is_directory(error_code& ec) const noexcept;
bool is_fifo() const;
bool is_fifo(error_code& ec) const noexcept;
bool is_other() const;
bool is_other(error_code& ec) const noexcept;
bool is_regular_file() const;
bool is_regular_file(error_code& ec) const noexcept;
bool is_socket() const;
bool is_socket(error_code& ec) const noexcept;
bool is_symlink() const;
bool is_symlink(error_code& ec) const noexcept;
uintmax_t file_size() const;
uintmax_t file_size(error_code& ec) const noexcept;
uintmax_t hard_link_count() const;
uintmax_t hard_link_count(error_code& ec) const noexcept;
file_time_type last_write_time() const;
file_time_type last_write_time(error_code& ec) const noexcept;
file_status status() const;
file_status status(error_code& ec) const noexcept;
file_status symlink_status() const;
file_status symlink_status(error_code& ec) const noexcept;
bool operator==(const directory_entry& rhs) const noexcept;
bool operator!=(const directory_entry& rhs) const noexcept; // removed in C++20
bool operator< (const directory_entry& rhs) const noexcept; // removed in C++20
bool operator<=(const directory_entry& rhs) const noexcept; // removed in C++20
bool operator> (const directory_entry& rhs) const noexcept; // removed in C++20
bool operator>=(const directory_entry& rhs) const noexcept; // removed in C++20
strong_ordering operator<=>(const directory_entry& rhs) const noexcept; // since C++20
template<class charT, class traits>
friend basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, const directory_entry& d);
private:
filesystem::path pathobject; // exposition only
friend class directory_iterator; // exposition only
};
class directory_iterator;

View File

@ -18,6 +18,7 @@
// bool operator<=(directory_entry const&) const noexcept;
// bool operator> (directory_entry const&) const noexcept;
// bool operator>=(directory_entry const&) const noexcept;
// strong_ordering operator<=>(directory_entry const&) const noexcept;
#include "filesystem_include.h"
#include <cassert>
@ -25,61 +26,28 @@
#include <utility>
#include "test_macros.h"
#define CHECK_OP(Op) \
static_assert(std::is_same<decltype(ce Op ce), bool>::value, ""); \
static_assert(noexcept(ce Op ce), "Operation must be noexcept" )
void test_comparison_signatures() {
using namespace fs;
path const p("foo/bar/baz");
// Check that the operators are valid, yield bool, and are not
// potentially-throwing.
{
directory_entry const ce(p);
CHECK_OP(==);
CHECK_OP(!=);
CHECK_OP(< );
CHECK_OP(<=);
CHECK_OP(> );
CHECK_OP(>=);
}
}
#undef CHECK_OP
// The actual semantics of the comparisons are testing via paths operators.
void test_comparisons_simple() {
using namespace fs;
typedef std::pair<path, path> TestType;
TestType TestCases[] =
{
{"", ""},
{"", "a"},
{"a", "a"},
{"a", "b"},
{"foo/bar/baz", "foo/bar/baz/"}
};
auto TestFn = [](path const& LHS, const directory_entry& LHSE,
path const& RHS, const directory_entry& RHSE) {
assert((LHS == RHS) == (LHSE == RHSE));
assert((LHS != RHS) == (LHSE != RHSE));
assert((LHS < RHS) == (LHSE < RHSE));
assert((LHS <= RHS) == (LHSE <= RHSE));
assert((LHS > RHS) == (LHSE > RHSE));
assert((LHS >= RHS) == (LHSE >= RHSE));
};
for (auto const& TC : TestCases) {
const directory_entry L(TC.first);
const directory_entry R(TC.second);
TestFn(TC.first, L, TC.second, R);
TestFn(TC.second, R, TC.first, L);
}
}
#include "test_comparisons.h"
int main(int, char**) {
test_comparison_signatures();
test_comparisons_simple();
using namespace fs;
AssertComparisonsAreNoexcept<directory_entry>();
AssertComparisonsReturnBool<directory_entry>();
#if TEST_STD_VER > 17
AssertOrderAreNoexcept<directory_entry>();
AssertOrderReturn<std::strong_ordering, directory_entry>();
#endif
typedef std::pair<path, path> TestType;
TestType TestCases[] = {{"", ""}, {"", "a"}, {"a", "a"}, {"a", "b"}, {"foo/bar/baz", "foo/bar/baz/"}};
for (auto const& TC : TestCases) {
assert(testComparisonsValues<directory_entry>(TC.first, TC.second));
assert(testComparisonsValues<directory_entry>(TC.second, TC.first));
#if TEST_STD_VER > 17
assert(testOrderValues<directory_entry>(TC.first, TC.second));
assert(testOrderValues<directory_entry>(TC.second, TC.first));
#endif
}
return 0;
}