Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions include/beman/inplace_vector/inplace_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,8 +1009,7 @@ struct inplace_vector

constexpr friend auto operator<=>(const inplace_vector &x,
const inplace_vector &y)
requires(std::equality_comparable<T> &&
beman::details::inplace_vector::lessthan_comparable<T>)
requires(beman::details::inplace_vector::lessthan_comparable<T>)
{
if constexpr (std::three_way_comparable<T>) {
return std::lexicographical_compare_three_way(x.begin(), x.end(),
Expand Down
72 changes: 42 additions & 30 deletions tests/beman/inplace_vector/compare.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ concept has_threeway = requires(const T &t) {
{ t <=> t };
};

template <class T>
concept lessthan_comparable =
beman::details::inplace_vector::lessthan_comparable<T>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It strikes me that the namespace is backwards here -- should be beman::inplace_vector::detail -- but that's an existing issue of course. And maybe something we don't address clearly in the standard.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong here, but beman::inplace_vector clashes with the inplace_vector struct under the beman namespace.


template <typename T> struct vec_list {
T empty;
T base; // base
Expand All @@ -25,7 +29,7 @@ template <typename T> struct vec_list {

template <typename T> static void runtests(vec_list<T> &list) {

static_assert(std::three_way_comparable<T>);
static_assert(std::three_way_comparable<T> || lessthan_comparable<T>);

// if T::value_type is threewaycomparable with ordering X then T must also
// be comparable with ordering X
Expand All @@ -41,8 +45,10 @@ template <typename T> static void runtests(vec_list<T> &list) {
if constexpr (std::three_way_comparable<VT, std::partial_ordering>)
static_assert(std::three_way_comparable<T, std::partial_ordering>);

EXPECT_TRUE(list.empty == list.empty);
EXPECT_TRUE(list.empty != list.base);
if constexpr (std::equality_comparable<VT>) {
EXPECT_TRUE(list.empty == list.empty);
EXPECT_TRUE(list.empty != list.base);
}

EXPECT_TRUE((list.base <=> list.copy) == 0);
EXPECT_TRUE((list.base <=> list.greater) < 0);
Expand All @@ -54,15 +60,23 @@ template <typename T> static void runtests(vec_list<T> &list) {
EXPECT_TRUE((list.base <=> list.greater_smaller) < 0);
EXPECT_TRUE((list.base <=> list.lesser_bigger) > 0);

EXPECT_TRUE(list.base == list.copy);
if constexpr (std::equality_comparable<VT>) {
EXPECT_TRUE(list.base == list.copy);
EXPECT_TRUE(list.base != list.greater);
EXPECT_TRUE(list.base != list.lesser);
}
EXPECT_TRUE(list.base <= list.copy);
EXPECT_TRUE(list.base >= list.copy);
EXPECT_TRUE(list.base < list.greater);
EXPECT_TRUE(list.base <= list.greater);
EXPECT_TRUE(list.base > list.lesser);
EXPECT_TRUE(list.base >= list.lesser);

EXPECT_TRUE(list.copy == list.base);
if constexpr (std::equality_comparable<VT>) {
EXPECT_TRUE(list.copy == list.base);
EXPECT_TRUE(list.copy != list.greater);
EXPECT_TRUE(list.copy != list.lesser);
}
EXPECT_TRUE(list.copy <= list.base);
EXPECT_TRUE(list.copy >= list.base);
EXPECT_TRUE(list.greater > list.base);
Expand Down Expand Up @@ -101,6 +115,25 @@ TEST(Compare, threeway_float) {
};

runtests(list);

// compare unorderable values

EXPECT_EQ(std::nanf("") <=> std::nanf(""), std::partial_ordering::unordered);
EXPECT_FALSE(std::nanf("") == std::nanf(""));
EXPECT_FALSE(std::nanf("") < std::nanf(""));
EXPECT_FALSE(std::nanf("") > std::nanf(""));
EXPECT_FALSE(std::nanf("") >= std::nanf(""));
EXPECT_FALSE(std::nanf("") <= std::nanf(""));

inplace_vector<float, 4> vnan{std::nanf("")};
inplace_vector<float, 4> vnan2{std::nanf("")};

EXPECT_EQ(vnan <=> vnan2, std::partial_ordering::unordered);
EXPECT_FALSE(vnan == vnan2);
EXPECT_FALSE(vnan < vnan2);
EXPECT_FALSE(vnan > vnan2);
EXPECT_FALSE(vnan >= vnan2);
EXPECT_FALSE(vnan <= vnan2);
}

TEST(Compare, threeway_comparable1) {
Expand Down Expand Up @@ -135,14 +168,15 @@ TEST(Compare, threeway_comparable2) {
struct comparable2 {
int a;
int b;
constexpr bool operator==(const comparable2 &) const = default;
constexpr bool operator==(const comparable2 &) const = delete;
constexpr bool operator<(const comparable2 &other) const {
return a < other.a || (a == other.a && b < other.b);
};
};

static_assert(!std::three_way_comparable<comparable2>);
static_assert(!has_threeway<comparable2>);
static_assert(lessthan_comparable<comparable2>);
static_assert(std::three_way_comparable<inplace_vector<comparable2, 4>>);
static_assert(has_threeway<inplace_vector<comparable2, 4>>);

Expand All @@ -159,25 +193,6 @@ TEST(Compare, threeway_comparable2) {
};

runtests(list);

// compare unorderable values

EXPECT_EQ(std::nanf("") <=> std::nanf(""), std::partial_ordering::unordered);
EXPECT_FALSE(std::nanf("") == std::nanf(""));
EXPECT_FALSE(std::nanf("") < std::nanf(""));
EXPECT_FALSE(std::nanf("") > std::nanf(""));
EXPECT_FALSE(std::nanf("") >= std::nanf(""));
EXPECT_FALSE(std::nanf("") <= std::nanf(""));

inplace_vector<float, 4> vnan{std::nanf("")};
inplace_vector<float, 4> vnan2{std::nanf("")};

EXPECT_EQ(vnan <=> vnan2, std::partial_ordering::unordered);
EXPECT_FALSE(vnan == vnan2);
EXPECT_FALSE(vnan < vnan2);
EXPECT_FALSE(vnan > vnan2);
EXPECT_FALSE(vnan >= vnan2);
EXPECT_FALSE(vnan <= vnan2);
}

TEST(Compare, threeway_strong_ordering) {
Expand Down Expand Up @@ -301,14 +316,11 @@ TEST(Compare, threeway_uncomparable) {

struct uncomparable3 {
int a;
constexpr auto operator<=>(const uncomparable3 &) const {
return std::partial_ordering::unordered;
}
constexpr bool operator==(const uncomparable3 &) const = delete;
constexpr auto operator<=>(const uncomparable3 &) const = delete;
};

static_assert(!std::three_way_comparable<uncomparable3>);
static_assert(has_threeway<uncomparable3>); // has <=> but no == operator
static_assert(!has_threeway<uncomparable3>);
static_assert(!std::three_way_comparable<inplace_vector<uncomparable3, 4>>);
static_assert(!has_threeway<inplace_vector<uncomparable3, 4>>);
}