#ifndef MD_LINE_INDEX_H #define MD_LINE_INDEX_H #include #include #define SASHIDOWN_MAX_LINE_INDEX 16384 typedef struct { uint32_t *off; /* line-start offsets; off[n] is end sentinel */ uint32_t n; /* number of line starts (off[0]..off[n-1]) */ uint32_t cur; /* sequential cursor: line index for last lookup */ uint32_t cap; /* slots in off[] (must be >= n+1 when valid) */ int valid; /* 0 if doc exceeded index capacity / OOM */ int owned; /* 1 if off was malloc'd (stream path) */ } line_index_t; /* Stack-backed index for zero-malloc parse/convert hot path. */ #define LINE_INDEX_STACK(name) \ uint32_t name##_off_[SASHIDOWN_MAX_LINE_INDEX + 1]; \ line_index_t name = { \ .off = name##_off_, .n = 0, .cur = 0, \ .cap = SASHIDOWN_MAX_LINE_INDEX + 1, .valid = 1, .owned = 0 \ } int line_index_init_dynamic(line_index_t *ix, uint32_t initial_cap); void line_index_free(line_index_t *ix); void line_index_build(const char *input, size_t len, line_index_t *ix); /* Extend for input[old_len..new_len). Returns absolute offset after the last * newline in that range, or 0 if none. */ size_t line_index_extend(line_index_t *ix, const char *input, size_t old_len, size_t new_len); void line_index_seek(line_index_t *ix, size_t pos); size_t line_end_ix(line_index_t *ix, const char *input, size_t len, size_t pos); size_t skip_line_ix(line_index_t *ix, const char *input, size_t len, size_t pos); #endif /* MD_LINE_INDEX_H */