Skip to content

Commit

Permalink
src: use spaceship operator in SocketAddress
Browse files Browse the repository at this point in the history
PR-URL: nodejs#56059
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
  • Loading branch information
jasnell committed Dec 3, 2024
1 parent 3b6da7c commit b915124
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 76 deletions.
19 changes: 3 additions & 16 deletions src/node_sockaddr-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,22 +172,9 @@ bool SocketAddress::operator!=(const SocketAddress& other) const {
return !(*this == other);
}

bool SocketAddress::operator<(const SocketAddress& other) const {
return compare(other) == CompareResult::LESS_THAN;
}

bool SocketAddress::operator>(const SocketAddress& other) const {
return compare(other) == CompareResult::GREATER_THAN;
}

bool SocketAddress::operator<=(const SocketAddress& other) const {
CompareResult c = compare(other);
return c == CompareResult::NOT_COMPARABLE ? false :
c <= CompareResult::SAME;
}

bool SocketAddress::operator>=(const SocketAddress& other) const {
return compare(other) >= CompareResult::SAME;
std::partial_ordering SocketAddress::operator<=>(
const SocketAddress& other) const {
return compare(other);
}

template <typename T>
Expand Down
65 changes: 30 additions & 35 deletions src/node_sockaddr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,8 @@ bool is_match_ipv4_ipv6(
sizeof(uint32_t)) == 0;
}

SocketAddress::CompareResult compare_ipv4(
const SocketAddress& one,
const SocketAddress& two) {
std::partial_ordering compare_ipv4(const SocketAddress& one,
const SocketAddress& two) {
const sockaddr_in* one_in =
reinterpret_cast<const sockaddr_in*>(one.data());
const sockaddr_in* two_in =
Expand All @@ -165,31 +164,29 @@ SocketAddress::CompareResult compare_ipv4(
const uint32_t s_addr_two = ntohl(two_in->sin_addr.s_addr);

if (s_addr_one < s_addr_two)
return SocketAddress::CompareResult::LESS_THAN;
return std::partial_ordering::less;
else if (s_addr_one == s_addr_two)
return SocketAddress::CompareResult::SAME;
return std::partial_ordering::equivalent;
else
return SocketAddress::CompareResult::GREATER_THAN;
return std::partial_ordering::greater;
}

SocketAddress::CompareResult compare_ipv6(
const SocketAddress& one,
const SocketAddress& two) {
std::partial_ordering compare_ipv6(const SocketAddress& one,
const SocketAddress& two) {
const sockaddr_in6* one_in =
reinterpret_cast<const sockaddr_in6*>(one.data());
const sockaddr_in6* two_in =
reinterpret_cast<const sockaddr_in6*>(two.data());
int ret = memcmp(&one_in->sin6_addr, &two_in->sin6_addr, 16);
if (ret < 0)
return SocketAddress::CompareResult::LESS_THAN;
return std::partial_ordering::less;
else if (ret > 0)
return SocketAddress::CompareResult::GREATER_THAN;
return SocketAddress::CompareResult::SAME;
return std::partial_ordering::greater;
return std::partial_ordering::equivalent;
}

SocketAddress::CompareResult compare_ipv4_ipv6(
const SocketAddress& ipv4,
const SocketAddress& ipv6) {
std::partial_ordering compare_ipv4_ipv6(const SocketAddress& ipv4,
const SocketAddress& ipv6) {
const sockaddr_in* ipv4_in =
reinterpret_cast<const sockaddr_in*>(ipv4.data());
const sockaddr_in6 * ipv6_in =
Expand All @@ -199,18 +196,18 @@ SocketAddress::CompareResult compare_ipv4_ipv6(
reinterpret_cast<const uint8_t*>(&ipv6_in->sin6_addr);

if (memcmp(ptr, mask, sizeof(mask)) != 0)
return SocketAddress::CompareResult::NOT_COMPARABLE;
return std::partial_ordering::unordered;

int ret = memcmp(
&ipv4_in->sin_addr,
ptr + sizeof(mask),
sizeof(uint32_t));

if (ret < 0)
return SocketAddress::CompareResult::LESS_THAN;
return std::partial_ordering::less;
else if (ret > 0)
return SocketAddress::CompareResult::GREATER_THAN;
return SocketAddress::CompareResult::SAME;
return std::partial_ordering::greater;
return std::partial_ordering::equivalent;
}

bool in_network_ipv4(
Expand All @@ -235,7 +232,7 @@ bool in_network_ipv6(
// Special case, if prefix == 128, then just do a
// straight comparison.
if (prefix == 128)
return compare_ipv6(ip, net) == SocketAddress::CompareResult::SAME;
return compare_ipv6(ip, net) == std::partial_ordering::equivalent;

uint8_t r = prefix % 8;
int len = (prefix - r) / 8;
Expand Down Expand Up @@ -263,7 +260,7 @@ bool in_network_ipv4_ipv6(
int prefix) {

if (prefix == 128)
return compare_ipv4_ipv6(ip, net) == SocketAddress::CompareResult::SAME;
return compare_ipv4_ipv6(ip, net) == std::partial_ordering::equivalent;

uint8_t r = prefix % 8;
int len = (prefix - r) / 8;
Expand Down Expand Up @@ -293,7 +290,7 @@ bool in_network_ipv6_ipv4(
const SocketAddress& net,
int prefix) {
if (prefix == 32)
return compare_ipv4_ipv6(net, ip) == SocketAddress::CompareResult::SAME;
return compare_ipv4_ipv6(net, ip) == std::partial_ordering::equivalent;

uint32_t m = ((1ull << prefix) - 1) << (32 - prefix);

Expand Down Expand Up @@ -337,8 +334,7 @@ bool SocketAddress::is_match(const SocketAddress& other) const {
return false;
}

SocketAddress::CompareResult SocketAddress::compare(
const SocketAddress& other) const {
std::partial_ordering SocketAddress::compare(const SocketAddress& other) const {
switch (family()) {
case AF_INET:
switch (other.family()) {
Expand All @@ -349,24 +345,23 @@ SocketAddress::CompareResult SocketAddress::compare(
case AF_INET6:
switch (other.family()) {
case AF_INET: {
CompareResult c = compare_ipv4_ipv6(other, *this);
switch (c) {
case SocketAddress::CompareResult::NOT_COMPARABLE:
// Fall through
case SocketAddress::CompareResult::SAME:
return c;
case SocketAddress::CompareResult::GREATER_THAN:
return SocketAddress::CompareResult::LESS_THAN;
case SocketAddress::CompareResult::LESS_THAN:
return SocketAddress::CompareResult::GREATER_THAN;
auto c = compare_ipv4_ipv6(other, *this);
if (c == std::partial_ordering::unordered) {
return std::partial_ordering::unordered;
} else if (c == std::partial_ordering::equivalent) {
return std::partial_ordering::equivalent;
} else if (c == std::partial_ordering::less) {
return std::partial_ordering::greater;
} else if (c == std::partial_ordering::greater) {
return std::partial_ordering::less;
}
break;
}
case AF_INET6: return compare_ipv6(*this, other);
}
break;
}
return SocketAddress::CompareResult::NOT_COMPARABLE;
return std::partial_ordering::unordered;
}

bool SocketAddress::is_in_network(
Expand Down
17 changes: 4 additions & 13 deletions src/node_sockaddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
#include "uv.h"
#include "v8.h"

#include <compare>
#include <list>
#include <memory>
#include <string>
#include <list>
#include <unordered_map>

namespace node {
Expand All @@ -22,24 +23,14 @@ class Environment;

class SocketAddress : public MemoryRetainer {
public:
enum class CompareResult {
NOT_COMPARABLE = -2,
LESS_THAN,
SAME,
GREATER_THAN
};

struct Hash {
size_t operator()(const SocketAddress& addr) const;
};

inline bool operator==(const SocketAddress& other) const;
inline bool operator!=(const SocketAddress& other) const;

inline bool operator<(const SocketAddress& other) const;
inline bool operator>(const SocketAddress& other) const;
inline bool operator<=(const SocketAddress& other) const;
inline bool operator>=(const SocketAddress& other) const;
inline std::partial_ordering operator<=>(const SocketAddress& other) const;

inline static bool is_numeric_host(const char* hostname);
inline static bool is_numeric_host(const char* hostname, int family);
Expand Down Expand Up @@ -102,7 +93,7 @@ class SocketAddress : public MemoryRetainer {
bool is_match(const SocketAddress& other) const;

// Compares this SocketAddress to the given other SocketAddress.
CompareResult compare(const SocketAddress& other) const;
std::partial_ordering compare(const SocketAddress& other) const;

// Returns true if this SocketAddress is within the subnet
// identified by the given network address and CIDR prefix.
Expand Down
24 changes: 12 additions & 12 deletions test/cctest/test_sockaddr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,19 @@ TEST(SocketAddress, Comparison) {
SocketAddress addr5(reinterpret_cast<const sockaddr*>(&storage[4]));
SocketAddress addr6(reinterpret_cast<const sockaddr*>(&storage[5]));

CHECK_EQ(addr1.compare(addr1), SocketAddress::CompareResult::SAME);
CHECK_EQ(addr1.compare(addr2), SocketAddress::CompareResult::LESS_THAN);
CHECK_EQ(addr2.compare(addr1), SocketAddress::CompareResult::GREATER_THAN);
CHECK_EQ(addr1.compare(addr1), std::partial_ordering::equivalent);
CHECK_EQ(addr1.compare(addr2), std::partial_ordering::less);
CHECK_EQ(addr2.compare(addr1), std::partial_ordering::greater);
CHECK(addr1 <= addr1);
CHECK(addr1 < addr2);
CHECK(addr1 <= addr2);
CHECK(addr2 >= addr2);
CHECK(addr2 > addr1);
CHECK(addr2 >= addr1);

CHECK_EQ(addr3.compare(addr3), SocketAddress::CompareResult::SAME);
CHECK_EQ(addr3.compare(addr4), SocketAddress::CompareResult::LESS_THAN);
CHECK_EQ(addr4.compare(addr3), SocketAddress::CompareResult::GREATER_THAN);
CHECK_EQ(addr3.compare(addr3), std::partial_ordering::equivalent);
CHECK_EQ(addr3.compare(addr4), std::partial_ordering::less);
CHECK_EQ(addr4.compare(addr3), std::partial_ordering::greater);
CHECK(addr3 <= addr3);
CHECK(addr3 < addr4);
CHECK(addr3 <= addr4);
Expand All @@ -166,8 +166,8 @@ TEST(SocketAddress, Comparison) {
CHECK(addr4 >= addr3);

// Not comparable
CHECK_EQ(addr1.compare(addr3), SocketAddress::CompareResult::NOT_COMPARABLE);
CHECK_EQ(addr3.compare(addr1), SocketAddress::CompareResult::NOT_COMPARABLE);
CHECK_EQ(addr1.compare(addr3), std::partial_ordering::unordered);
CHECK_EQ(addr3.compare(addr1), std::partial_ordering::unordered);
CHECK(!(addr1 < addr3));
CHECK(!(addr1 > addr3));
CHECK(!(addr1 >= addr3));
Expand All @@ -178,10 +178,10 @@ TEST(SocketAddress, Comparison) {
CHECK(!(addr3 <= addr1));

// Comparable
CHECK_EQ(addr1.compare(addr5), SocketAddress::CompareResult::SAME);
CHECK_EQ(addr2.compare(addr6), SocketAddress::CompareResult::SAME);
CHECK_EQ(addr1.compare(addr6), SocketAddress::CompareResult::LESS_THAN);
CHECK_EQ(addr6.compare(addr1), SocketAddress::CompareResult::GREATER_THAN);
CHECK_EQ(addr1.compare(addr5), std::partial_ordering::equivalent);
CHECK_EQ(addr2.compare(addr6), std::partial_ordering::equivalent);
CHECK_EQ(addr1.compare(addr6), std::partial_ordering::less);
CHECK_EQ(addr6.compare(addr1), std::partial_ordering::greater);
CHECK(addr1 <= addr5);
CHECK(addr1 <= addr6);
CHECK(addr1 < addr6);
Expand Down

0 comments on commit b915124

Please sign in to comment.