Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I static assert to disallow "mixed endianness" in a non-templated member function

I am using 2 x std::uint64_t and 1 x std::uint32_t in a high performance implementation of of operator<=> in a struct conataining a std::array<std::byte, 20>.

I am trying to make it cross compiler and architecture compatible.

As part of that I am trying to outright reject any architecture with std::endian::native which is not std::endian::little or std::endian::big.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I think I am running foul of the "static_assert must depend on a template parameter rule", as the struct and the member function are not templated.

  std::strong_ordering operator<=>(const pawned_pw& rhs) const {

    static_assert(sizeof(std::uint64_t) == 8);
    static_assert(sizeof(std::uint32_t) == 4);

    if constexpr (std::endian::native == std::endian::little) {

      // c++23 will have std::byteswap, so we won't need this
#ifdef _MSC_VER
#define BYTE_SWAP_32 _byteswap_ulong
#define BYTE_SWAP_64 _byteswap_uint64
#else
#define BYTE_SWAP_32 __builtin_bswap32
#define BYTE_SWAP_64 __builtin_bswap64
#endif

      // this compiles to a load and `bswap` which should be fast
      // measured > 33% faster than hash < rhs.hash, which compiles to `memcmp`
      std::uint64_t head     = BYTE_SWAP_64(*(std::uint64_t*)(&hash[0]));     // NOLINT
      std::uint64_t rhs_head = BYTE_SWAP_64(*(std::uint64_t*)(&rhs.hash[0])); // NOLINT
      if (head != rhs_head) return head <=> rhs_head;

      std::uint64_t mid     = BYTE_SWAP_64(*(std::uint64_t*)(&hash[8]));     // NOLINT
      std::uint64_t rhs_mid = BYTE_SWAP_64(*(std::uint64_t*)(&rhs.hash[8])); // NOLINT
      if (mid != rhs_mid) return mid <=> rhs_mid;

      std::uint32_t tail     = BYTE_SWAP_32(*(std::uint32_t*)(&hash[16]));     // NOLINT
      std::uint32_t rhs_tail = BYTE_SWAP_32(*(std::uint32_t*)(&rhs.hash[16])); // NOLINT
      return tail <=> rhs_tail;
    } else if constexpr (std::endian::native == std::endian::big) {
      // can use big_endian directly
      std::uint64_t head     = *(std::uint64_t*)(&hash[0]);     // NOLINT
      std::uint64_t rhs_head = *(std::uint64_t*)(&rhs.hash[0]); // NOLINT
      if (head != rhs_head) return head <=> rhs_head;

      std::uint64_t mid     = *(std::uint64_t*)(&hash[8]);     // NOLINT
      std::uint64_t rhs_mid = *(std::uint64_t*)(&rhs.hash[8]); // NOLINT
      if (mid != rhs_mid) return mid <=> rhs_mid;

      std::uint32_t tail     = *(std::uint32_t*)(&hash[16]);     // NOLINT
      std::uint32_t rhs_tail = *(std::uint32_t*)(&rhs.hash[16]); // NOLINT
      return tail <=> rhs_tail;
    } else {
      static_assert(std::endian::native != std::endian::big &&
                    std::endian::native != std::endian::little,
                    "mixed-endianess architectures are not supported");
    }
  }


I guess I could just fall back instead of static_assert

    } else {
      // fall back to the slow way
      hash <=> rhs.hash;
    }

>Solution :

I suggest asserting that it’s either big or little endian:

#include <bit>
#include <compare>

struct pawned_pw {
    std::strong_ordering operator<=>(const pawned_pw& rhs) const {
        static_assert(std::endian::native == std::endian::big ||
                          std::endian::native == std::endian::little,
                      "mixed-endianess architectures are not supported");

        if constexpr (std::endian::native == std::endian::little) {
            return ...;
        } else {
            // big
            return ...;
        }
    }
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading