packages feed

wireform-core-0.1.0.0: cbits/fast_scan.c

/*
 * Format-agnostic SIMD byte-scanning primitives.
 *
 * These used to live in wireform-xml/cbits/fast_xml.c under
 * XML-specific names because that's where they were first
 * introduced. CSV, NDJSON, and a few other decoders reached
 * into that file to reuse hs_xml_find_byte; to keep the
 * dependency graph honest the generic helper lives here and is
 * exported under a neutral name. The XML-specific scanners
 * (find_lt, find_attr_end, find_cdata_end, etc.) remain in
 * wireform-xml since they encode XML-grammar knowledge.
 *
 * Uses SSE2 via simde for portable SIMD. Fallback to scalar
 * loops on architectures without simde support.
 */

#include <stdint.h>
#include <string.h>
#include <simde/x86/sse2.h>

/*
 * Scan buf[offset..len) for the first occurrence of target_byte.
 * Returns the absolute position of the match, or len if no
 * match was found. Used by CSV delimiter scanning, NDJSON
 * newline scanning, XML structural scanning, etc.
 */
int hs_find_byte(const uint8_t *buf, int offset, int len, uint8_t target_byte)
{
    int i = offset;
    simde__m128i target = simde_mm_set1_epi8((char)target_byte);

    /* Scalar prologue until 16-byte aligned. */
    while (i < len && ((uintptr_t)(buf + i) & 15) != 0) {
        if (buf[i] == target_byte) return i;
        i++;
    }

    /* SIMD main loop: 16 bytes at a time. */
    for (; i + 16 <= len; i += 16) {
        simde__m128i chunk = simde_mm_load_si128((const simde__m128i *)(buf + i));
        int mask = simde_mm_movemask_epi8(simde_mm_cmpeq_epi8(chunk, target));
        if (mask != 0) return i + __builtin_ctz(mask);
    }

    /* Scalar epilogue for the remaining <16 bytes. */
    for (; i < len; i++) {
        if (buf[i] == target_byte) return i;
    }

    return len;
}