ip2net: optimize ipv6 sort for all endianness

This commit is contained in:
bol-van 2022-06-16 19:45:01 +03:00
parent 9529953594
commit 9cf2e3f1de
10 changed files with 21 additions and 12 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -65,33 +65,42 @@ static int cmp6(const void * a, const void * b, void *arg)
// this function is critical to sort performance
// on big endian systems cpu byte order is equal to network byte order
// no conversion required. it's possible to improve speed by using big size compares
// on little endian systems byte conversion also gives better result than byte comparision
// 64-bit archs often have cpu command to reverse byte order
// assume that a and b are properly aligned
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_BIG_ENDIAN__)
#ifdef __SIZEOF_INT128__
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_BIG_ENDIAN__) && defined(__SIZEOF_INT128__)
// the fastest possible way (MIPS64/PPC64 only ?)
const unsigned __int128 *pa = (unsigned __int128*)((struct in6_addr *)a)->s6_addr;
const unsigned __int128 *pb = (unsigned __int128*)((struct in6_addr *)b)->s6_addr;
return *pa < *pb ? -1 : *pa == *pb ? 0 : 1;
#elif defined(__BYTE_ORDER__) && ((__BYTE_ORDER__==__ORDER_BIG_ENDIAN__) || (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__))
uint64_t am,al,bm,bl;
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
am = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[0]);
al = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[1]);
bm = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[0]);
bl = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[1]);
#else
const uint64_t *pa = (uint64_t*)((struct in6_addr *)a)->s6_addr;
const uint64_t *pb = (uint64_t*)((struct in6_addr *)b)->s6_addr;
if (pa[0] < pb[0])
am = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[0];
al = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[1];
bm = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[0];
bl = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[1];
#endif
if (am < bm)
return -1;
else if (pa[0] == pb[0])
else if (am == bm)
{
if (pa[1] < pb[1])
if (al < bl)
return -1;
else if (pa[1] > pb[1])
else if (al > bl)
return 1;
else
return 0;
}
else
return 1; // pa[0] > pb[0]
#endif
return 1;
#else
// little endian or unknown. reversing byte order voids performance improvement. so do byte comparision
// fallback case
for (uint8_t i = 0; i < sizeof(((struct in6_addr *)0)->s6_addr); i++)
{
if (((struct in6_addr *)a)->s6_addr[i] < ((struct in6_addr *)b)->s6_addr[i])