24 simd_inline std::size_t
common_bytes(
void const * lhs,
void const * rhs, std::size_t count)
noexcept {
25 auto a =
static_cast<unsigned char const *
>(lhs);
26 auto b =
static_cast<unsigned char const *
>(rhs);
28 if constexpr (!std::is_same_v<Arch, simd::scalar>) {
29 constexpr auto lanes = backend_detail::register_bytes<Arch>;
30 using V = simd::vec<std::uint8_t, lanes, Arch>;
31 for (; count - at >= lanes; at += lanes) {
32 auto different = V::load(a + at) != V::load(b + at);
33 if constexpr (std::is_same_v<Arch, simd::neon>) {
35 if (any(different))
break;
36 }
else if (
auto bits = different.to_bitset())
return at + std::countr_zero(bits);
39 for (; count - at >= 8; at += 8) {
41 std::memcpy(&x, a + at, 8); std::memcpy(&y, b + at, 8);
42 if (
auto different = x ^ y) {
43 if constexpr (std::endian::native == std::endian::little)
return at + (std::countr_zero(different) >> 3);
44 else if constexpr (std::endian::native == std::endian::big)
return at + (std::countl_zero(different) >> 3);
48 while (at != count && a[at] == b[at]) ++at;
57 inline std::uint64_t
load_big(
void const * source)
noexcept {
58 if constexpr (std::endian::native == std::endian::little || std::endian::native == std::endian::big) {
59 std::uint64_t value; std::memcpy(&value, source, 8);
60 if constexpr (std::endian::native == std::endian::little)
return reverse_bytes(value);
63 auto bytes =
static_cast<unsigned char const *
>(source);
64 std::uint64_t value = 0;
65 for (
unsigned i = 0; i != 8; ++i) value = (value << 8) | bytes[i];
69 inline void store_big(
void * target, std::uint64_t value)
noexcept {
70 if constexpr (std::endian::native == std::endian::little) {
72 }
else if constexpr (std::endian::native == std::endian::big) std::memcpy(target, &value, 8);
74 auto bytes =
static_cast<unsigned char *
>(target);
75 for (
unsigned i = 0; i != 8; ++i) bytes[i] =
static_cast<unsigned char>(value >> (56 - (i << 3)));