NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
bytes.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_SIMD_BYTES_HPP__
2#define NEFORCE_CORE_SIMD_BYTES_HPP__
3
10
13NEFORCE_BEGIN_NAMESPACE__
14NEFORCE_BEGIN_SIMD__
15
20
26NEFORCE_ALWAYS_INLINE_INLINE vec128_t fill_byte(byte_t c) noexcept {
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);
31#else
32 vec128_t result;
33 for (int i = 0; i < 16; ++i) {
34 result.data[i] = c;
35 }
36 return result;
37#endif
38}
39
45NEFORCE_ALWAYS_INLINE_INLINE vec128_t load_unaligned(const void* ptr) noexcept {
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));
50#else
51 vec128_t result;
52 const auto* src = static_cast<const byte_t*>(ptr);
53 for (int i = 0; i < 16; ++i) {
54 result.data[i] = src[i];
55 }
56 return result;
57#endif
58}
59
66NEFORCE_ALWAYS_INLINE_INLINE vec128_t match_bytes(vec128_t a, vec128_t b) noexcept {
67#ifdef NEFORCE_SIMD_SSE2
68 return ::_mm_cmpeq_epi8(a, b);
69#elif defined(NEFORCE_SIMD_NEON)
70 return ::vceqq_u8(a, b);
71#else
72 vec128_t result;
73 for (int i = 0; i < 16; ++i) {
74 result.data[i] = (a.data[i] == b.data[i]) ? 0xFF : 0x00;
75 }
76 return result;
77#endif
78}
79
85NEFORCE_ALWAYS_INLINE_INLINE int to_bitmask(vec128_t v) noexcept {
86#ifdef NEFORCE_SIMD_SSE2
87 return ::_mm_movemask_epi8(v);
88#elif defined(NEFORCE_SIMD_NEON)
89 int mask = 0;
90 const auto* bytes = reinterpret_cast<const byte_t*>(&v);
91 for (int i = 0; i < 16; ++i) {
92 if ((bytes[i] & 0x80) != 0) {
93 mask |= (1 << i);
94 }
95 }
96 return mask;
97#else
98 int mask = 0;
99 for (int i = 0; i < 16; ++i) {
100 if (v.data[i] & 0x80) {
101 mask |= (1 << i);
102 }
103 }
104 return mask;
105#endif
106}
107
114NEFORCE_ALWAYS_INLINE_INLINE bool contains_byte(vec128_t v, byte_t c) noexcept {
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) {
121 if (bytes[i] != 0) {
122 return true;
123 }
124 }
125 return false;
126#else
127 for (int i = 0; i < 16; ++i) {
128 if (v.data[i] == c) {
129 return true;
130 }
131 }
132 return false;
133#endif
134}
135
142NEFORCE_ALWAYS_INLINE_INLINE int find_first_byte(vec128_t v, byte_t c) noexcept {
143#ifdef NEFORCE_SIMD_SSE2
144 const int mask = ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_set1_epi8(static_cast<char>(c))));
145 if (mask == 0) {
146 return -1;
147 }
148 return countr_zero(mask);
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) {
153 if (bytes[i] != 0) {
154 return i;
155 }
156 }
157 return -1;
158#else
159 for (int i = 0; i < 16; ++i) {
160 if (v.data[i] == c) {
161 return i;
162 }
163 }
164 return -1;
165#endif
166}
167
174NEFORCE_ALWAYS_INLINE_INLINE int find_last_byte(vec128_t v, byte_t c) noexcept {
175#ifdef NEFORCE_SIMD_SSE2
176 const int mask = ::_mm_movemask_epi8(::_mm_cmpeq_epi8(v, ::_mm_set1_epi8(static_cast<char>(c))));
177 if (mask == 0) {
178 return -1;
179 }
180 return highest_set_bit_pos(static_cast<intptr_t>(mask));
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) {
185 if (bytes[i] != 0) {
186 return i;
187 }
188 }
189 return -1;
190#else
191 for (int i = 15; i >= 0; --i) {
192 if (v.data[i] == c) {
193 return i;
194 }
195 }
196 return -1;
197#endif
198}
199
206NEFORCE_ALWAYS_INLINE_INLINE int count_byte(vec128_t v, byte_t c) noexcept {
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));
217# else
218 int count = 0;
219 const auto* bytes = reinterpret_cast<const byte_t*>(&ones);
220 for (int i = 0; i < 16; ++i) {
221 count += bytes[i];
222 }
223 return count;
224# endif
225#else
226 int count = 0;
227 for (int i = 0; i < 16; ++i) {
228 if (v.data[i] == c) {
229 ++count;
230 }
231 }
232 return count;
233#endif
234}
235
241NEFORCE_ALWAYS_INLINE_INLINE bool is_all_zero(vec128_t v) noexcept {
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;
247#else
248 for (int i = 0; i < 16; ++i) {
249 if (v.data[i] != 0) {
250 return false;
251 }
252 }
253 return true;
254#endif
255}
256
262NEFORCE_ALWAYS_INLINE_INLINE bool has_any_zero(vec128_t v) noexcept {
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;
269#else
270 for (int i = 0; i < 16; ++i) {
271 if (v.data[i] == 0) {
272 return true;
273 }
274 }
275 return false;
276#endif
277}
278
284NEFORCE_ALWAYS_INLINE_INLINE vec128_t reverse_bytes(vec128_t v) noexcept {
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];
293 }
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);
299#else
300 vec128_t result;
301 for (int i = 0; i < 16; ++i) {
302 result.data[15 - i] = v.data[i];
303 }
304 return result;
305#endif
306}
307
315NEFORCE_ALWAYS_INLINE_INLINE vec128_t shuffle_bytes(vec128_t v, vec128_t indices) noexcept {
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];
327 }
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)));
331#else
332 vec128_t result;
333 for (int i = 0; i < 16; ++i) {
334 const int index = indices.data[i] & 0x0F;
335 result.data[i] = v.data[index];
336 }
337 return result;
338#endif
339}
340
348NEFORCE_ALWAYS_INLINE_INLINE vec128_t blend_bytes(vec128_t a, vec128_t b, vec128_t mask) noexcept {
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);
357#else
358 vec128_t result;
359 for (int i = 0; i < 16; ++i) {
360 result.data[i] = (mask.data[i] & 0x80) ? b.data[i] : a.data[i];
361 }
362 return result;
363#endif
364}
365
373NEFORCE_ALWAYS_INLINE_INLINE void store_bytes_n(void* ptr, vec128_t v, int n) noexcept {
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];
379 }
380#elif defined(NEFORCE_SIMD_NEON)
381 alignas(16) byte_t buf[16];
382 vst1q_u8(buf, v);
383 for (int i = 0; i < n; ++i) {
384 static_cast<byte_t*>(ptr)[i] = buf[i];
385 }
386#else
387 for (int i = 0; i < n; ++i) {
388 static_cast<byte_t*>(ptr)[i] = v.data[i];
389 }
390#endif
391}
392
400NEFORCE_ALWAYS_INLINE_INLINE vec128_t load_bytes_n(const void* ptr, int n) noexcept {
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) {
405 buf[i] = src[i];
406 }
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) {
412 buf[i] = src[i];
413 }
414 return vld1q_u8(buf);
415#else
416 vec128_t result = {};
417 const auto* src = static_cast<const byte_t*>(ptr);
418 for (int i = 0; i < n; ++i) {
419 result.data[i] = src[i];
420 }
421 return result;
422#endif
423}
424 // SIMD
426
427NEFORCE_END_SIMD__
428NEFORCE_END_NAMESPACE__
429#endif // NEFORCE_CORE_SIMD_BYTES_HPP__
位操作函数
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)
统计范围内等于指定值的元素数量
int64_t intptr_t
可容纳指针的有符号整数类型
::__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 向量的相等性
SIMD 向量类型定义