1#ifndef NEFORCE_CORE_SIMD_BYTES_HPP__
2#define NEFORCE_CORE_SIMD_BYTES_HPP__
13NEFORCE_BEGIN_NAMESPACE__
27#ifdef NEFORCE_SIMD_SSE2
28 return ::_mm_set1_epi8(
static_cast<char>(c));
29#elif defined(NEFORCE_SIMD_NEON)
30 return ::vdupq_n_u8(c);
33 for (
int i = 0; i < 16; ++i) {
46#ifdef NEFORCE_SIMD_SSE2
47 return ::_mm_loadu_si128(
static_cast<const vec128_t*
>(ptr));
48#elif defined(NEFORCE_SIMD_NEON)
49 return vld1q_u8(
static_cast<const uint8_t*
>(ptr));
52 const auto* src =
static_cast<const byte_t*
>(ptr);
53 for (
int i = 0; i < 16; ++i) {
54 result.data[i] = src[i];
67#ifdef NEFORCE_SIMD_SSE2
68 return ::_mm_cmpeq_epi8(a, b);
69#elif defined(NEFORCE_SIMD_NEON)
70 return ::vceqq_u8(a, b);
73 for (
int i = 0; i < 16; ++i) {
74 result.data[i] = (a.data[i] == b.data[i]) ? 0xFF : 0x00;
86#ifdef NEFORCE_SIMD_SSE2
87 return ::_mm_movemask_epi8(v);
88#elif defined(NEFORCE_SIMD_NEON)
90 const auto* bytes =
reinterpret_cast<const byte_t*
>(&v);
91 for (
int i = 0; i < 16; ++i) {
92 if ((bytes[i] & 0x80) != 0) {
99 for (
int i = 0; i < 16; ++i) {
100 if (v.data[i] & 0x80) {
115#ifdef NEFORCE_SIMD_SSE2
116 return ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_set1_epi8(
static_cast<char>(c)))) != 0;
117#elif defined(NEFORCE_SIMD_NEON)
118 const ::uint8x16_t match = ::vceqq_u8(v, ::vdupq_n_u8(c));
119 const auto* bytes =
reinterpret_cast<const byte_t*
>(&match);
120 for (
int i = 0; i < 16; ++i) {
127 for (
int i = 0; i < 16; ++i) {
128 if (v.data[i] == c) {
143#ifdef NEFORCE_SIMD_SSE2
144 const int mask = ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_set1_epi8(
static_cast<char>(c))));
149#elif defined(NEFORCE_SIMD_NEON)
150 const ::uint8x16_t match = ::vceqq_u8(v, ::vdupq_n_u8(c));
151 const auto* bytes =
reinterpret_cast<const byte_t*
>(&match);
152 for (
int i = 0; i < 16; ++i) {
159 for (
int i = 0; i < 16; ++i) {
160 if (v.data[i] == c) {
175#ifdef NEFORCE_SIMD_SSE2
176 const int mask = ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_set1_epi8(
static_cast<char>(c))));
181#elif defined(NEFORCE_SIMD_NEON)
182 const ::uint8x16_t match = ::vceqq_u8(v, ::vdupq_n_u8(c));
183 const auto* bytes =
reinterpret_cast<const byte_t*
>(&match);
184 for (
int i = 15; i >= 0; --i) {
191 for (
int i = 15; i >= 0; --i) {
192 if (v.data[i] == c) {
207#ifdef NEFORCE_SIMD_SSE2
208 const ::__m128i match = ::_mm_cmpeq_epi8(v, ::_mm_set1_epi8(
static_cast<char>(c)));
209 const ::__m128i ones = ::_mm_and_si128(match, ::_mm_set1_epi8(1));
210 const ::__m128i sums = ::_mm_sad_epu8(ones, ::_mm_setzero_si128());
211 return _mm_extract_epi16(sums, 0) + _mm_extract_epi16(sums, 4);
212#elif defined(NEFORCE_SIMD_NEON)
213 const ::uint8x16_t match = ::vceqq_u8(v, ::vdupq_n_u8(c));
214 const ::uint8x16_t ones = ::vandq_u8(match, ::vdupq_n_u8(1));
215# ifdef NEFORCE_ARCH_AARCH64
216 return static_cast<int>(::vaddvq_u8(ones));
219 const auto* bytes =
reinterpret_cast<const byte_t*
>(&ones);
220 for (
int i = 0; i < 16; ++i) {
227 for (
int i = 0; i < 16; ++i) {
228 if (v.data[i] == c) {
242#ifdef NEFORCE_SIMD_SSE2
243 return ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_setzero_si128())) == 0xFFFF;
244#elif defined(NEFORCE_SIMD_NEON)
245 ::uint64x2_t v64 = ::vreinterpretq_u64_u8(v);
246 return (vgetq_lane_u64(v64, 0) | vgetq_lane_u64(v64, 1)) == 0;
248 for (
int i = 0; i < 16; ++i) {
249 if (v.data[i] != 0) {
263#ifdef NEFORCE_SIMD_SSE2
264 return ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_setzero_si128())) != 0;
265#elif defined(NEFORCE_SIMD_NEON)
266 const ::uint8x16_t match = ::vceqq_u8(v, ::vdupq_n_u8(0));
267 ::uint64x2_t v64 = ::vreinterpretq_u64_u8(match);
268 return (vgetq_lane_u64(v64, 0) | vgetq_lane_u64(v64, 1)) != 0;
270 for (
int i = 0; i < 16; ++i) {
271 if (v.data[i] == 0) {
285#ifdef NEFORCE_SIMD_SSSE3
286 const ::__m128i indices = ::_mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
287 return ::_mm_shuffle_epi8(v, indices);
288#elif defined(NEFORCE_SIMD_SSE2)
289 const auto* src =
reinterpret_cast<const byte_t*
>(&v);
290 alignas(16)
byte_t buf[16];
291 for (
int i = 0; i < 16; ++i) {
292 buf[15 - i] = src[i];
294 return ::_mm_loadu_si128(
reinterpret_cast<const ::__m128i*
>(buf));
295#elif defined(NEFORCE_SIMD_NEON)
296 const auto lo = ::vrev64_u8(::vget_low_u8(v));
297 const auto hi = ::vrev64_u8(::vget_high_u8(v));
298 return ::vcombine_u8(hi, lo);
301 for (
int i = 0; i < 16; ++i) {
302 result.data[15 - i] = v.data[i];
316#ifdef NEFORCE_SIMD_SSSE3
317 return ::_mm_shuffle_epi8(v, indices);
318#elif defined(NEFORCE_SIMD_SSE2)
319 alignas(16)
byte_t src[16];
320 alignas(16)
byte_t idx[16];
321 ::_mm_store_si128(
reinterpret_cast<::__m128i*
>(src), v);
322 ::_mm_store_si128(
reinterpret_cast<::__m128i*
>(idx), indices);
323 alignas(16)
byte_t result[16] = {};
324 for (
int i = 0; i < 16; ++i) {
325 const int index = idx[i] & 0x0F;
326 result[i] = src[index];
328 return ::_mm_load_si128(
reinterpret_cast<const ::__m128i*
>(result));
329#elif defined(NEFORCE_SIMD_NEON)
330 return ::vqtbl1q_u8(v, ::vandq_u8(indices, ::vdupq_n_u8(0x0F)));
333 for (
int i = 0; i < 16; ++i) {
334 const int index = indices.data[i] & 0x0F;
335 result.data[i] = v.data[index];
349#ifdef NEFORCE_SIMD_SSE4_1
350 return ::_mm_blendv_epi8(a, b, mask);
351#elif defined(NEFORCE_SIMD_SSE2)
352 const ::__m128i sel = ::_mm_cmpgt_epi8(::_mm_setzero_si128(), mask);
353 return ::_mm_or_si128(::_mm_and_si128(sel, b), ::_mm_andnot_si128(sel, a));
354#elif defined(NEFORCE_SIMD_NEON)
355 const ::int8x16_t sel = vshrq_n_s8(::vreinterpretq_s8_u8(mask), 7);
356 return ::vbslq_u8(::vreinterpretq_u8_s8(sel), b, a);
359 for (
int i = 0; i < 16; ++i) {
360 result.data[i] = (mask.data[i] & 0x80) ? b.data[i] : a.data[i];
374#ifdef NEFORCE_SIMD_SSE2
375 alignas(16)
byte_t buf[16];
376 ::_mm_store_si128(
reinterpret_cast<::__m128i*
>(buf), v);
377 for (
int i = 0; i < n; ++i) {
378 static_cast<byte_t*
>(ptr)[i] = buf[i];
380#elif defined(NEFORCE_SIMD_NEON)
381 alignas(16)
byte_t buf[16];
383 for (
int i = 0; i < n; ++i) {
384 static_cast<byte_t*
>(ptr)[i] = buf[i];
387 for (
int i = 0; i < n; ++i) {
388 static_cast<byte_t*
>(ptr)[i] = v.data[i];
401#ifdef NEFORCE_SIMD_SSE2
402 alignas(16)
byte_t buf[16] = {};
403 const auto* src =
static_cast<const byte_t*
>(ptr);
404 for (
int i = 0; i < n; ++i) {
407 return ::_mm_load_si128(
reinterpret_cast<const ::__m128i*
>(buf));
408#elif defined(NEFORCE_SIMD_NEON)
409 alignas(16)
byte_t buf[16] = {};
410 const auto* src =
static_cast<const byte_t*
>(ptr);
411 for (
int i = 0; i < n; ++i) {
414 return vld1q_u8(buf);
417 const auto* src =
static_cast<const byte_t*
>(ptr);
418 for (
int i = 0; i < n; ++i) {
419 result.data[i] = src[i];
428NEFORCE_END_NAMESPACE__
constexpr int highest_set_bit_pos(const intptr_t x) noexcept
获取最高设置位的位置
constexpr int countr_zero(const uintptr_t x) noexcept
计算整数尾随零的个数
unsigned char byte_t
字节类型,定义为无符号字符
unsigned char uint8_t
8位无符号整数类型
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
::__m128i vec128_t
128-bit 整型向量(16×i8 / 8×i16 / 4×i32 / 2×i64)
vec128_t reverse_bytes(vec128_t v) noexcept
反转向量中 16 字节的顺序
int to_bitmask(vec128_t v) noexcept
提取向量中每个字节的最高位,组成 16-bit 掩码
void store_bytes_n(void *ptr, vec128_t v, int n) noexcept
存储向量的前 n 字节到内存,不写入越界数据
vec128_t shuffle_bytes(vec128_t v, vec128_t indices) noexcept
按索引表逐字节重排向量
vec128_t fill_byte(byte_t c) noexcept
将单字节广播到 128-bit SIMD 向量的全部 16 个位置
vec128_t blend_bytes(vec128_t a, vec128_t b, vec128_t mask) noexcept
按掩码逐字节混合两个向量
bool has_any_zero(vec128_t v) noexcept
检测向量中是否存在零字节
bool contains_byte(vec128_t v, byte_t c) noexcept
检测向量中是否包含指定字节
vec128_t load_bytes_n(const void *ptr, int n) noexcept
从内存加载 n 字节到向量,不足部分填零
bool is_all_zero(vec128_t v) noexcept
检测向量是否全为零
int find_first_byte(vec128_t v, byte_t c) noexcept
查找向量中指定字节首次出现的位置
int count_byte(vec128_t v, byte_t c) noexcept
统计向量中指定字节出现的次数
vec128_t load_unaligned(const void *ptr) noexcept
非对齐加载 16 字节到 128-bit SIMD 向量
int find_last_byte(vec128_t v, byte_t c) noexcept
查找向量中指定字节末次出现的位置
vec128_t match_bytes(vec128_t a, vec128_t b) noexcept
逐字节比较两个 128-bit SIMD 向量的相等性