From d4eb5f7c9aa53e97b1bbcf946417925ab6477370 Mon Sep 17 00:00:00 2001 From: Yenda Li Date: Tue, 29 Oct 2024 20:11:29 -0700 Subject: [PATCH] Add custom comparator to IPAddressType (#11347) Summary: We need a comparator for IPAddressType. - Provide providesCustomComparison = true to constructor to support custom comparison - Compare by converting the int128_t/BIGINT to a byteArray, and reversing the byte order. We then use memcmp - support between for IPAddressType - register the type to saber since comparison now takes IpAddress Differential Revision: D64880148 --- velox/functions/prestosql/GreatestLeast.h | 5 +- .../ComparisonFunctionsRegistration.cpp | 5 + .../GeneralFunctionsRegistration.cpp | 2 + .../prestosql/tests/ComparisonsTest.cpp | 264 ++++++++++++++++++ .../prestosql/tests/GreatestLeastTest.cpp | 40 +++ .../prestosql/types/IPAddressType.cpp | 43 ++- .../functions/prestosql/types/IPAddressType.h | 51 +++- .../types/tests/IPAddressTypeTest.cpp | 84 ++++++ 8 files changed, 463 insertions(+), 31 deletions(-) diff --git a/velox/functions/prestosql/GreatestLeast.h b/velox/functions/prestosql/GreatestLeast.h index a5a0a23e00d5..c4b04e95d54b 100644 --- a/velox/functions/prestosql/GreatestLeast.h +++ b/velox/functions/prestosql/GreatestLeast.h @@ -66,8 +66,9 @@ struct ExtremeValueFunction { return wrapper; } - int64_t extractValue( - const exec::CustomTypeWithCustomComparisonView& wrapper) const { + template + U extractValue( + const exec::CustomTypeWithCustomComparisonView& wrapper) const { return *wrapper; } diff --git a/velox/functions/prestosql/registration/ComparisonFunctionsRegistration.cpp b/velox/functions/prestosql/registration/ComparisonFunctionsRegistration.cpp index b1f34da9c629..2870a3ff787f 100644 --- a/velox/functions/prestosql/registration/ComparisonFunctionsRegistration.cpp +++ b/velox/functions/prestosql/registration/ComparisonFunctionsRegistration.cpp @@ -16,6 +16,7 @@ #include "velox/functions/Registerer.h" #include "velox/functions/lib/RegistrationHelpers.h" #include "velox/functions/prestosql/Comparisons.h" +#include "velox/functions/prestosql/types/IPAddressType.h" #include "velox/functions/prestosql/types/TimestampWithTimeZoneType.h" #include "velox/type/Type.h" @@ -30,6 +31,7 @@ void registerNonSimdizableScalar(const std::vector& aliases) { registerFunction(aliases); registerFunction( aliases); + registerFunction(aliases); } } // namespace @@ -37,6 +39,7 @@ void registerComparisonFunctions(const std::string& prefix) { // Comparison functions also need TimestampWithTimezoneType, // independent of DateTimeFunctions registerTimestampWithTimeZoneType(); + registerIPAddressType(); registerNonSimdizableScalar({prefix + "eq"}); VELOX_REGISTER_VECTOR_FUNCTION(udf_simd_comparison_eq, prefix + "eq"); @@ -116,6 +119,8 @@ void registerComparisonFunctions(const std::string& prefix) { TimestampWithTimezone, TimestampWithTimezone, TimestampWithTimezone>({prefix + "between"}); + registerFunction( + {prefix + "between"}); } } // namespace facebook::velox::functions diff --git a/velox/functions/prestosql/registration/GeneralFunctionsRegistration.cpp b/velox/functions/prestosql/registration/GeneralFunctionsRegistration.cpp index dda91e413da9..a33d0a62a6bf 100644 --- a/velox/functions/prestosql/registration/GeneralFunctionsRegistration.cpp +++ b/velox/functions/prestosql/registration/GeneralFunctionsRegistration.cpp @@ -21,6 +21,7 @@ #include "velox/functions/prestosql/GreatestLeast.h" #include "velox/functions/prestosql/InPredicate.h" #include "velox/functions/prestosql/Reduce.h" +#include "velox/functions/prestosql/types/IPAddressType.h" #include "velox/functions/prestosql/types/TimestampWithTimeZoneType.h" namespace facebook::velox::functions { @@ -57,6 +58,7 @@ void registerAllGreatestLeastFunctions(const std::string& prefix) { registerGreatestLeastFunction(prefix); registerGreatestLeastFunction(prefix); registerGreatestLeastFunction(prefix); + registerGreatestLeastFunction(prefix); } } // namespace diff --git a/velox/functions/prestosql/tests/ComparisonsTest.cpp b/velox/functions/prestosql/tests/ComparisonsTest.cpp index 14be9d7a8cd6..707a61d108fa 100644 --- a/velox/functions/prestosql/tests/ComparisonsTest.cpp +++ b/velox/functions/prestosql/tests/ComparisonsTest.cpp @@ -19,6 +19,7 @@ #include "velox/functions/Udf.h" #include "velox/functions/lib/RegistrationHelpers.h" #include "velox/functions/prestosql/tests/utils/FunctionBaseTest.h" +#include "velox/functions/prestosql/types/IPAddressType.h" #include "velox/functions/prestosql/types/TimestampWithTimeZoneType.h" #include "velox/type/tests/utils/CustomTypesForTesting.h" #include "velox/type/tz/TimeZoneMap.h" @@ -1182,6 +1183,269 @@ TEST_F(ComparisonsTest, TimestampWithTimezone) { false})); } +TEST_F(ComparisonsTest, IpAddressType) { + auto makeIpAdressFromString = [](const std::string& ipAddr) -> int128_t { + auto ret = ipaddress::tryGetIPv6asInt128FromString(ipAddr); + return ret.value(); + }; + + auto runAndCompare = [&](const std::string& expr, + RowVectorPtr inputs, + VectorPtr expectedResult) { + auto actual = evaluate>(expr, inputs); + test::assertEqualVectors(expectedResult, actual); + }; + + auto lhs = makeNullableFlatVector( + { + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("1.2.3.4"), + makeIpAdressFromString("1.1.1.2"), + makeIpAdressFromString("1.1.2.1"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("::1"), + makeIpAdressFromString("2001:0db8:0000:0000:0000:ff00:0042:8329"), + makeIpAdressFromString("::ffff:1.2.3.4"), + makeIpAdressFromString("::ffff:0.1.1.1"), + makeIpAdressFromString("::FFFF:FFFF:FFFF"), + makeIpAdressFromString("::0001:255.255.255.255"), + makeIpAdressFromString("::ffff:ffff:ffff"), + std::nullopt, + makeIpAdressFromString("::0001:255.255.255.255"), + }, + IPADDRESS()); + + auto rhs = makeNullableFlatVector( + { + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("1.1.1.2"), + makeIpAdressFromString("1.1.2.1"), + makeIpAdressFromString("255.1.1.1"), + makeIpAdressFromString("::1"), + makeIpAdressFromString("2001:db8::ff00:42:8329"), + makeIpAdressFromString("1.2.3.4"), + makeIpAdressFromString("::ffff:1.1.1.0"), + makeIpAdressFromString("::0001:255.255.255.255"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("255.255.255.255"), + std::nullopt, + }, + IPADDRESS()); + + auto input = makeRowVector({lhs, rhs}); + + runAndCompare( + "c0 = c1", + input, + makeNullableFlatVector( + {true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + std::nullopt, + std::nullopt})); + + runAndCompare( + "c0 <> c1", + input, + makeNullableFlatVector( + {false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + std::nullopt, + std::nullopt})); + + runAndCompare( + "c0 < c1", + input, + makeNullableFlatVector( + {false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + false, + true, + false, + std::nullopt, + std::nullopt})); + + runAndCompare( + "c0 > c1", + input, + makeNullableFlatVector( + {false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + false, + std::nullopt, + std::nullopt})); + + runAndCompare( + "c0 <= c1", + input, + makeNullableFlatVector( + {true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + std::nullopt, + std::nullopt})); + + runAndCompare( + "c0 >= c1", + input, + makeNullableFlatVector( + {true, + true, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + false, + true, + std::nullopt, + std::nullopt})); + + runAndCompare( + "c0 is distinct from c1", + input, + makeNullableFlatVector( + {false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + true, + true})); + + auto betweenInput = makeRowVector({ + makeNullableFlatVector( + {makeIpAdressFromString("2001:db8::ff00:42:8329"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("::ffff:1.1.1.1"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("0.0.0.0"), + makeIpAdressFromString("::ffff"), + makeIpAdressFromString("0.0.0.0"), + std::nullopt, + makeIpAdressFromString("0.0.0.0"), + makeIpAdressFromString("0.0.0.0")}, + IPADDRESS()), + makeNullableFlatVector( + {makeIpAdressFromString("::ffff"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("::ffff:0.1.1.1"), + makeIpAdressFromString("0.1.1.1"), + makeIpAdressFromString("0.0.0.1"), + makeIpAdressFromString("::ffff:0.0.0.1"), + makeIpAdressFromString("2001:db8::0:0:0:1"), + makeIpAdressFromString("2001:db8::0:0:0:1"), + std::nullopt, + makeIpAdressFromString("2001:db8::0:0:0:1")}, + IPADDRESS()), + makeNullableFlatVector( + {makeIpAdressFromString("2001:db8::ff00:42:8329"), + makeIpAdressFromString("1.1.1.1"), + makeIpAdressFromString("255.255.255.255"), + makeIpAdressFromString("2001:0db8:0000:0000:0000:ff00:0042:8329"), + makeIpAdressFromString("2001:0db8:0000:0000:0000:ff00:0042:8329"), + makeIpAdressFromString("0.0.0.2"), + makeIpAdressFromString("0.0.0.2"), + makeIpAdressFromString("2001:db8::1:0:0:1"), + makeIpAdressFromString("2001:db8::1:0:0:1"), + makeIpAdressFromString("2001:db8::1:0:0:1"), + std::nullopt}, + IPADDRESS()), + }); + + runAndCompare( + "c0 between c1 and c2", + betweenInput, + makeNullableFlatVector( + {true, + true, + true, + true, + true, + false, + false, + false, + std::nullopt, + std::nullopt, + std::nullopt})); +} + TEST_F(ComparisonsTest, CustomComparisonWithGenerics) { // Tests that functions that support signatures with generics handle custom // comparison correctly. diff --git a/velox/functions/prestosql/tests/GreatestLeastTest.cpp b/velox/functions/prestosql/tests/GreatestLeastTest.cpp index a8b9bc3ed8a5..028081ccf99a 100644 --- a/velox/functions/prestosql/tests/GreatestLeastTest.cpp +++ b/velox/functions/prestosql/tests/GreatestLeastTest.cpp @@ -286,6 +286,46 @@ TEST_F(GreatestLeastTest, leastDate) { DATE()); } +TEST_F(GreatestLeastTest, greatestLeastIpAddress) { + auto greatest = [&](const std::optional& a, + const std::optional& b, + const std::optional& c) { + return evaluateOnce( + "cast(greatest(cast(c0 as ipaddress), cast(c1 as ipaddress), cast(c2 as ipaddress)) as varchar)", + a, + b, + c); + }; + + auto least = [&](const std::optional& a, + const std::optional& b, + const std::optional& c) { + return evaluateOnce( + "cast(least(cast(c0 as ipaddress), cast(c1 as ipaddress), cast(c2 as ipaddress)) as varchar)", + a, + b, + c); + }; + + auto greatestValue = greatest( + "1.1.1.1", "255.255.255.255", "2001:0db8:0000:0000:0000:ff00:0042:832"); + EXPECT_EQ("2001:db8::ff00:42:832", greatestValue.value()); + + auto leastValue = least( + "1.1.1.1", "255.255.255.255", "2001:0db8:0000:0000:0000:ff00:0042:832"); + EXPECT_EQ("1.1.1.1", leastValue.value()); + + auto greatestValueWithNulls = + greatest("1.1.1.1", "255.255.255.255", std::nullopt); + EXPECT_FALSE(greatestValueWithNulls.has_value()); + + auto leastValueWithNulls = least( + std::nullopt, + "255.255.255.255", + "2001:0db8:0000:0000:0000:ff00:0042:832"); + EXPECT_FALSE(leastValueWithNulls.has_value()); +} + TEST_F(GreatestLeastTest, stringBuffersMoved) { runTest( "least(c0, c1)", diff --git a/velox/functions/prestosql/types/IPAddressType.cpp b/velox/functions/prestosql/types/IPAddressType.cpp index 691ca0a28ce2..d9569c01f7a9 100644 --- a/velox/functions/prestosql/types/IPAddressType.cpp +++ b/velox/functions/prestosql/types/IPAddressType.cpp @@ -15,14 +15,8 @@ */ #include "velox/functions/prestosql/types/IPAddressType.h" -#include #include "velox/expression/CastExpr.h" -static constexpr int kIPV4AddressBytes = 4; -static constexpr int kIPV4ToV6FFIndex = 10; -static constexpr int kIPV4ToV6Index = 12; -static constexpr int kIPAddressBytes = 16; - namespace facebook::velox { namespace { @@ -97,7 +91,7 @@ class IPAddressCastOperator : public exec::CastOperator { context.applyToSelectedNoThrow(rows, [&](auto row) { const auto intAddr = ipaddresses->valueAt(row); - memcpy(&addrBytes, &intAddr, kIPAddressBytes); + memcpy(&addrBytes, &intAddr, ipaddress::kIPAddressBytes); std::reverse(addrBytes.begin(), addrBytes.end()); folly::IPAddressV6 v6Addr(addrBytes); @@ -123,9 +117,10 @@ class IPAddressCastOperator : public exec::CastOperator { context.applyToSelectedNoThrow(rows, [&](auto row) { const auto ipAddressString = ipAddressStrings->valueAt(row); + auto maybeIpAsInt128 = + ipaddress::tryGetIPv6asInt128FromString(ipAddressString); - auto maybeIp = folly::IPAddress::tryFromString(ipAddressString); - if (maybeIp.hasError()) { + if (maybeIpAsInt128.hasError()) { if (threadSkipErrorDetails()) { context.setStatus(row, Status::UserError()); } else { @@ -135,13 +130,7 @@ class IPAddressCastOperator : public exec::CastOperator { } return; } - folly::IPAddress addr = maybeIp.value(); - auto addrBytes = folly::IPAddress::createIPv6(addr).toByteArray(); - - std::reverse(addrBytes.begin(), addrBytes.end()); - memcpy(&intAddr, &addrBytes, kIPAddressBytes); - - flatResult->set(row, intAddr); + flatResult->set(row, maybeIpAsInt128.value()); }); } @@ -156,12 +145,12 @@ class IPAddressCastOperator : public exec::CastOperator { context.applyToSelectedNoThrow(rows, [&](auto row) { const auto intAddr = ipaddresses->valueAt(row); folly::ByteArray16 addrBytes; - memcpy(&addrBytes, &intAddr, kIPAddressBytes); + memcpy(&addrBytes, &intAddr, ipaddress::kIPAddressBytes); std::reverse(addrBytes.begin(), addrBytes.end()); exec::StringWriter result(flatResult, row); - result.resize(kIPAddressBytes); - memcpy(result.data(), &addrBytes, kIPAddressBytes); + result.resize(ipaddress::kIPAddressBytes); + memcpy(result.data(), &addrBytes, ipaddress::kIPAddressBytes); result.finalize(); }); } @@ -179,15 +168,15 @@ class IPAddressCastOperator : public exec::CastOperator { folly::ByteArray16 addrBytes = {}; const auto ipAddressBinary = ipAddressBinaries->valueAt(row); - if (ipAddressBinary.size() == kIPV4AddressBytes) { - addrBytes[kIPV4ToV6FFIndex] = 0xFF; - addrBytes[kIPV4ToV6FFIndex + 1] = 0xFF; + if (ipAddressBinary.size() == ipaddress::kIPV4AddressBytes) { + addrBytes[ipaddress::kIPV4ToV6FFIndex] = 0xFF; + addrBytes[ipaddress::kIPV4ToV6FFIndex + 1] = 0xFF; memcpy( - &addrBytes[kIPV4ToV6Index], + &addrBytes[ipaddress::kIPV4ToV6Index], ipAddressBinary.data(), - kIPV4AddressBytes); - } else if (ipAddressBinary.size() == kIPAddressBytes) { - memcpy(&addrBytes, ipAddressBinary.data(), kIPAddressBytes); + ipaddress::kIPV4AddressBytes); + } else if (ipAddressBinary.size() == ipaddress::kIPAddressBytes) { + memcpy(&addrBytes, ipAddressBinary.data(), ipaddress::kIPAddressBytes); } else { if (threadSkipErrorDetails()) { context.setStatus(row, Status::UserError()); @@ -202,7 +191,7 @@ class IPAddressCastOperator : public exec::CastOperator { } std::reverse(addrBytes.begin(), addrBytes.end()); - memcpy(&intAddr, &addrBytes, kIPAddressBytes); + memcpy(&intAddr, &addrBytes, ipaddress::kIPAddressBytes); flatResult->set(row, intAddr); }); } diff --git a/velox/functions/prestosql/types/IPAddressType.h b/velox/functions/prestosql/types/IPAddressType.h index e1e2d9fc1bf2..9c6c880f9e82 100644 --- a/velox/functions/prestosql/types/IPAddressType.h +++ b/velox/functions/prestosql/types/IPAddressType.h @@ -15,13 +15,37 @@ */ #pragma once +#include + #include "velox/type/SimpleFunctionApi.h" #include "velox/type/Type.h" namespace facebook::velox { +namespace ipaddress { +constexpr int kIPV4AddressBytes = 4; +constexpr int kIPV4ToV6FFIndex = 10; +constexpr int kIPV4ToV6Index = 12; +constexpr int kIPAddressBytes = 16; + +inline folly::Expected +tryGetIPv6asInt128FromString(const std::string& ipAddressStr) { + auto maybeIp = folly::IPAddress::tryFromString(ipAddressStr); + if (maybeIp.hasError()) { + return folly::makeUnexpected(maybeIp.error()); + } + + int128_t intAddr; + folly::IPAddress addr = maybeIp.value(); + auto addrBytes = folly::IPAddress::createIPv6(addr).toByteArray(); + std::reverse(addrBytes.begin(), addrBytes.end()); + memcpy(&intAddr, &addrBytes, kIPAddressBytes); + return intAddr; +} +} // namespace ipaddress + class IPAddressType : public HugeintType { - IPAddressType() = default; + IPAddressType() : HugeintType(/*providesCustomComparison*/ true) {} public: static const std::shared_ptr& get() { @@ -31,6 +55,19 @@ class IPAddressType : public HugeintType { return instance; } + int32_t compare(const int128_t& left, const int128_t& right) const override { + const auto leftAddrBytes = toIPv6ByteArray(left); + const auto rightAddrBytes = toIPv6ByteArray(right); + return memcmp( + leftAddrBytes.begin(), + rightAddrBytes.begin(), + ipaddress::kIPAddressBytes); + } + + uint64_t hash(const int128_t& value) const override { + return folly::hasher()(value); + } + bool equivalent(const Type& other) const override { // Pointer comparison works since this type is a singleton. return this == &other; @@ -50,6 +87,16 @@ class IPAddressType : public HugeintType { obj["type"] = name(); return obj; } + + private: + static folly::ByteArray16 toIPv6ByteArray(const int128_t& ipAddr) { + folly::ByteArray16 bytes{{0}}; + memcpy(bytes.data(), &ipAddr, sizeof(ipAddr)); + // Reverse because the velox is always on little endian system + // and the byte array needs to be big endian (network byte order) + std::reverse(bytes.begin(), bytes.end()); + return bytes; + } }; FOLLY_ALWAYS_INLINE bool isIPAddressType(const TypePtr& type) { @@ -67,7 +114,7 @@ struct IPAddressT { static constexpr const char* typeName = "ipaddress"; }; -using IPAddress = CustomType; +using IPAddress = CustomType; void registerIPAddressType(); diff --git a/velox/functions/prestosql/types/tests/IPAddressTypeTest.cpp b/velox/functions/prestosql/types/tests/IPAddressTypeTest.cpp index f024c785d94b..f65691e1c05f 100644 --- a/velox/functions/prestosql/types/tests/IPAddressTypeTest.cpp +++ b/velox/functions/prestosql/types/tests/IPAddressTypeTest.cpp @@ -23,6 +23,11 @@ class IPAddressTypeTest : public testing::Test, public TypeTestBase { IPAddressTypeTest() { registerIPAddressType(); } + + int128_t getIPv6asInt128FromStringUnchecked(const std::string& ipAddr) { + auto ret = ipaddress::tryGetIPv6asInt128FromString(ipAddr); + return ret.value(); + } }; TEST_F(IPAddressTypeTest, basic) { @@ -38,4 +43,83 @@ TEST_F(IPAddressTypeTest, basic) { TEST_F(IPAddressTypeTest, serde) { testTypeSerde(IPADDRESS()); } + +TEST_F(IPAddressTypeTest, compare) { + auto ipAddr = IPADDRESS(); + // Baisc IPv4 test + ASSERT_EQ( + 0, + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("1.1.1.1"), + getIPv6asInt128FromStringUnchecked("1.1.1.1"))); + ASSERT_EQ( + 0, + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("255.255.255.255"), + getIPv6asInt128FromStringUnchecked("255.255.255.255"))); + ASSERT_GT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("1.2.3.4"), + getIPv6asInt128FromStringUnchecked("1.1.1.1")), + 0); + ASSERT_GT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("1.1.1.2"), + getIPv6asInt128FromStringUnchecked("1.1.1.1")), + 0); + ASSERT_GT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("1.1.2.1"), + getIPv6asInt128FromStringUnchecked("1.1.1.2")), + 0); + ASSERT_LT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("1.1.1.1"), + getIPv6asInt128FromStringUnchecked("1.1.2.1")), + 0); + ASSERT_LT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("1.1.1.1"), + getIPv6asInt128FromStringUnchecked("255.1.1.1")), + 0); + + // Basic IPv6 test + ASSERT_EQ( + 0, + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("::1"), + getIPv6asInt128FromStringUnchecked("::1"))); + ASSERT_EQ( + 0, + ipAddr->compare( + getIPv6asInt128FromStringUnchecked( + "2001:0db8:0000:0000:0000:ff00:0042:8329"), + getIPv6asInt128FromStringUnchecked("2001:db8::ff00:42:8329"))); + ASSERT_EQ( + 0, + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("::ffff:1.2.3.4"), + getIPv6asInt128FromStringUnchecked("1.2.3.4"))); + ASSERT_LT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("::ffff:0.1.1.1"), + getIPv6asInt128FromStringUnchecked("::ffff:1.1.1.0")), + 0); + + ASSERT_GT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("::FFFF:FFFF:FFFF"), + getIPv6asInt128FromStringUnchecked("::0001:255.255.255.255")), + 0); + ASSERT_LT( + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("::0001:255.255.255.255"), + getIPv6asInt128FromStringUnchecked("255.255.255.255")), + 0); + ASSERT_EQ( + 0, + ipAddr->compare( + getIPv6asInt128FromStringUnchecked("::ffff:ffff:ffff"), + getIPv6asInt128FromStringUnchecked("255.255.255.255"))); +} } // namespace facebook::velox::test