@@ -313,8 +313,9 @@ inline FIXStructuralIndex build_index_xsimd(std::span<const char> data) noexcept
313313 const auto * ptr = reinterpret_cast <const uint8_t *>(data.data ());
314314
315315 // Process chunks
316- for (size_t i = 0 ; i < simd_end && idx.soh_count < MAX_FIELDS - width; i += width) {
317- auto chunk = xsimd::load_unaligned<Arch>(ptr + i);
316+ size_t simd_pos = 0 ;
317+ for (; simd_pos < simd_end && idx.soh_count < MAX_FIELDS - width; simd_pos += width) {
318+ auto chunk = xsimd::load_unaligned<Arch>(ptr + simd_pos);
318319
319320 // Detect SOH positions
320321 uint64_t soh_mask = (chunk == soh_vec).mask ();
@@ -323,15 +324,15 @@ inline FIXStructuralIndex build_index_xsimd(std::span<const char> data) noexcept
323324 uint64_t eq_mask = (chunk == eq_vec).mask ();
324325
325326 // Extract positions from masks
326- extract_positions (soh_mask, i , idx.soh_positions .data (),
327+ extract_positions (soh_mask, simd_pos , idx.soh_positions .data (),
327328 idx.soh_count , MAX_FIELDS );
328- extract_positions (eq_mask, i , idx.equals_positions .data (),
329+ extract_positions (eq_mask, simd_pos , idx.equals_positions .data (),
329330 idx.equals_count , MAX_FIELDS );
330331 }
331332
332- // Handle remaining bytes with scalar code
333+ // Handle remaining bytes with scalar code (resume from where SIMD stopped)
333334 const char * cptr = data.data ();
334- for (size_t i = simd_end ; i < data.size () && idx.soh_count < MAX_FIELDS ; ++i) {
335+ for (size_t i = simd_pos ; i < data.size () && idx.soh_count < MAX_FIELDS ; ++i) {
335336 if (cptr[i] == fix::EQUALS ) [[unlikely]] {
336337 idx.equals_positions [idx.equals_count ++] = static_cast <uint16_t >(i);
337338 }
@@ -438,9 +439,10 @@ inline FIXStructuralIndex build_index_avx2(std::span<const char> data) noexcept
438439 const char * __restrict ptr = data.data ();
439440
440441 // Process 32-byte chunks
441- for (size_t i = 0 ; i < simd_end && idx.soh_count < MAX_FIELDS - 32 ; i += 32 ) {
442+ size_t simd_pos = 0 ;
443+ for (; simd_pos < simd_end && idx.soh_count < MAX_FIELDS - 32 ; simd_pos += 32 ) {
442444 __m256i chunk = _mm256_loadu_si256 (
443- reinterpret_cast <const __m256i*>(ptr + i ));
445+ reinterpret_cast <const __m256i*>(ptr + simd_pos ));
444446
445447 // Detect SOH positions
446448 __m256i soh_cmp = _mm256_cmpeq_epi8 (chunk, soh_vec);
@@ -451,14 +453,14 @@ inline FIXStructuralIndex build_index_avx2(std::span<const char> data) noexcept
451453 uint32_t eq_mask = static_cast <uint32_t >(_mm256_movemask_epi8 (eq_cmp));
452454
453455 // Extract positions from masks
454- extract_positions_avx2 (soh_mask, i , idx.soh_positions .data (),
456+ extract_positions_avx2 (soh_mask, simd_pos , idx.soh_positions .data (),
455457 idx.soh_count , MAX_FIELDS );
456- extract_positions_avx2 (eq_mask, i , idx.equals_positions .data (),
458+ extract_positions_avx2 (eq_mask, simd_pos , idx.equals_positions .data (),
457459 idx.equals_count , MAX_FIELDS );
458460 }
459461
460- // Handle remaining bytes with scalar code
461- for (size_t i = simd_end ; i < data.size () && idx.soh_count < MAX_FIELDS ; ++i) {
462+ // Handle remaining bytes with scalar code (resume from where SIMD stopped)
463+ for (size_t i = simd_pos ; i < data.size () && idx.soh_count < MAX_FIELDS ; ++i) {
462464 if (ptr[i] == fix::EQUALS ) [[unlikely]] {
463465 idx.equals_positions [idx.equals_count ++] = static_cast <uint16_t >(i);
464466 }
@@ -545,9 +547,10 @@ inline FIXStructuralIndex build_index_avx512(std::span<const char> data) noexcep
545547 const char * __restrict ptr = data.data ();
546548
547549 // Process 64-byte chunks
548- for (size_t i = 0 ; i < simd_end && idx.soh_count < MAX_FIELDS - 64 ; i += 64 ) {
550+ size_t simd_pos = 0 ;
551+ for (; simd_pos < simd_end && idx.soh_count < MAX_FIELDS - 64 ; simd_pos += 64 ) {
549552 __m512i chunk = _mm512_loadu_si512 (
550- reinterpret_cast <const __m512i*>(ptr + i ));
553+ reinterpret_cast <const __m512i*>(ptr + simd_pos ));
551554
552555 // Detect SOH positions (returns 64-bit mask directly)
553556 __mmask64 soh_mask = _mm512_cmpeq_epi8_mask (chunk, soh_vec);
@@ -556,14 +559,14 @@ inline FIXStructuralIndex build_index_avx512(std::span<const char> data) noexcep
556559 __mmask64 eq_mask = _mm512_cmpeq_epi8_mask (chunk, eq_vec);
557560
558561 // Extract positions from masks
559- extract_positions_avx512 (soh_mask, i , idx.soh_positions .data (),
562+ extract_positions_avx512 (soh_mask, simd_pos , idx.soh_positions .data (),
560563 idx.soh_count , MAX_FIELDS );
561- extract_positions_avx512 (eq_mask, i , idx.equals_positions .data (),
564+ extract_positions_avx512 (eq_mask, simd_pos , idx.equals_positions .data (),
562565 idx.equals_count , MAX_FIELDS );
563566 }
564567
565- // Handle remaining bytes with scalar code
566- for (size_t i = simd_end ; i < data.size () && idx.soh_count < MAX_FIELDS ; ++i) {
568+ // Handle remaining bytes with scalar code (resume from where SIMD stopped)
569+ for (size_t i = simd_pos ; i < data.size () && idx.soh_count < MAX_FIELDS ; ++i) {
567570 if (ptr[i] == fix::EQUALS ) [[unlikely]] {
568571 idx.equals_positions [idx.equals_count ++] = static_cast <uint16_t >(i);
569572 }
0 commit comments