Files
CST-agent/vendor/sashidown/src/block_scan.h
T
WHCandCursor 1f1fcba7ad Initial CST-Agent: portable Linux/Termux/Windows coding agent.
Vendored sashidown, OpenAI-compatible env (OPENAI_*), and bootstrap scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-07 22:42:32 +08:00

197 lines
7.1 KiB
C

#ifndef SASHIDOWN_BLOCK_SCAN_H
#define SASHIDOWN_BLOCK_SCAN_H
#include "sashidown.h"
#include "render.h"
#include "fsm.h"
#include "line_index.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef __SSE2__
#include <emmintrin.h>
#elif defined(__ARM_NEON) || defined(__aarch64__)
#include <arm_neon.h>
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverride-init"
static inline size_t block_utf8_seq_len(unsigned char ch)
{
static const unsigned char tbl[256] = {
[0x00 ... 0xFF] = 1,
[0xC0 ... 0xDF] = 2,
[0xE0 ... 0xEF] = 3,
[0xF0 ... 0xF7] = 4,
};
return tbl[ch];
}
#pragma GCC diagnostic pop
static inline size_t block_scan_plain_ascii(const char *restrict input, size_t end, size_t i)
{
#ifdef __SSE2__
const __m128i m_star = _mm_set1_epi8('*');
const __m128i m_us = _mm_set1_epi8('_');
const __m128i m_tick = _mm_set1_epi8('`');
const __m128i m_dol = _mm_set1_epi8('$');
const __m128i m_bang = _mm_set1_epi8('!');
const __m128i m_lb = _mm_set1_epi8('[');
const __m128i m_amp = _mm_set1_epi8('&');
const __m128i m_lt = _mm_set1_epi8('<');
const __m128i m_gt = _mm_set1_epi8('>');
const __m128i m_bs = _mm_set1_epi8('\\');
const __m128i m_tilde = _mm_set1_epi8('~');
while (i + 16 <= end) {
__m128i v = _mm_loadu_si128((const __m128i *)(input + i));
if (_mm_movemask_epi8(v))
break; /* high bit => UTF-8 */
__m128i hit = _mm_cmpeq_epi8(v, m_star);
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_us));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_tick));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_dol));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_bang));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_lb));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_amp));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_lt));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_gt));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_bs));
hit = _mm_or_si128(hit, _mm_cmpeq_epi8(v, m_tilde));
int mask = _mm_movemask_epi8(hit);
if (mask)
return i + (unsigned)__builtin_ctz(mask);
i += 16;
}
#elif defined(__ARM_NEON) || defined(__aarch64__)
while (i + 16 <= end) {
uint8x16_t v = vld1q_u8((const uint8_t *)(input + i));
if (vmaxvq_u8(vandq_u8(v, vdupq_n_u8(0x80))))
break;
uint8x16_t hit = vceqq_u8(v, vdupq_n_u8('*'));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('_')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('`')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('$')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('!')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('[')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('&')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('<')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('>')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('\\')));
hit = vorrq_u8(hit, vceqq_u8(v, vdupq_n_u8('~')));
if (vmaxvq_u8(hit)) {
uint8_t lanes[16];
vst1q_u8(lanes, hit);
size_t pos = 0;
while (pos < 16 && !lanes[pos]) pos++;
return i + pos;
}
i += 16;
}
#endif
size_t j = i;
while (j + 4 <= end) {
uint32_t v;
memcpy(&v, input + j, 4);
if (v & 0x80808080)
break;
if (CH_SCAN_STOP[(v & 0xFF)] ||
CH_SCAN_STOP[(v >> 8) & 0xFF] ||
CH_SCAN_STOP[(v >> 16) & 0xFF] ||
CH_SCAN_STOP[(v >> 24) & 0xFF])
break;
j += 4;
}
while (j < end) {
unsigned char c = (unsigned char)input[j];
if ((c & 0x80))
break;
if (unlikely(CH_SCAN_STOP[c]))
break;
j++;
}
return j;
}
static inline size_t block_scan_utf8_run(const char *input, size_t end, size_t i)
{
size_t j = i;
while (j < end) {
unsigned char c = (unsigned char)input[j];
if (likely((c & 0x80) == 0))
break;
size_t seq = block_utf8_seq_len(c);
if (j + seq > end)
break;
j += seq;
}
return j;
}
static inline size_t block_scan_until_byte(const char *input, size_t end, size_t i, char delim)
{
if (i >= end)
return i;
const char *hit = memchr(input + i, delim, end - i);
return hit ? (size_t)(hit - input) : end;
}
static inline size_t block_scan_until_2byte(const char *input, size_t end, size_t start,
char c1, char c2)
{
size_t i = start;
while (i + 1 < end) {
const char *hit = memchr(input + i, c1, end - i);
if (!hit) return end;
i = (size_t)(hit - input);
if (i + 1 < end && input[i + 1] == c2)
return i;
i++;
}
return end;
}
static inline size_t block_line_end(sashidown_ctx_t *ctx, const char *input, size_t len, size_t pos)
{
return line_end_ix((line_index_t *)ctx->line_ix, input, len, pos);
}
static inline size_t block_skip_line(sashidown_ctx_t *ctx, const char *input, size_t len, size_t pos)
{
return skip_line_ix((line_index_t *)ctx->line_ix, input, len, pos);
}
static inline void block_line_seek(sashidown_ctx_t *ctx, size_t pos)
{
line_index_seek((line_index_t *)ctx->line_ix, pos);
}
int block_count_heading(const char *input, size_t len, size_t pos, size_t *content_start);
int block_is_fence(const char *input, size_t len, size_t pos,
int *fence_len, char *fence_char);
void block_fence_info_range(const char *input, size_t len, size_t pos,
int fence_len, char fence_char,
size_t *info_start, size_t *info_end);
int block_is_thematic_break(const char *input, size_t pos, size_t le);
int block_is_setext_underline(const char *input, size_t pos, size_t le, int *level);
int block_is_blockquote(const char *input, size_t len, size_t pos, size_t *content_start);
int block_is_ul(const char *input, size_t len, size_t pos, size_t *content_start);
int block_is_ol(const char *input, size_t len, size_t pos, size_t *content_start, int *num);
int block_parse_task_marker(const char *input, size_t len, size_t content_start,
int *task, size_t *text_start);
int block_line_starts_table(const char *input, size_t len, size_t pos);
int block_is_latex_line(sashidown_ctx_t *ctx, const char *input, size_t len,
size_t pos, size_t *content_start, size_t *content_end);
/* Peek next-line setext underline. Does NOT advance line_index on failure.
* `le` must be block_line_end(pos). Caller should only invoke for LK_PARA lines.
* Returns 1 = heading, 0 = no, -1 = defer (need next line). */
int block_try_setext(sashidown_ctx_t *ctx, const char *input, size_t len,
size_t pos, size_t le, size_t stop, int is_final,
line_info_t *info, size_t *end_pos);
line_info_t block_classify_line(sashidown_ctx_t *ctx, const char *input, size_t len,
size_t pos, size_t le);
#endif /* SASHIDOWN_BLOCK_SCAN_H */