#include #include /** * @brief 私有辅助内部函数:为模式串动态解包并构建 KMP 高速失配跳转跳转表 */ C_STATIC_FORCE_INLINE c_err_t c_Kmp_BuildNextTable(const uint8_t* p, c_size_t m, c_size_t* next) { next[0] = 0; // KMP 起始基石 c_size_t len = 0; // 前缀的核心长度 c_size_t i = 1; while (i < m) { if (p[i] == p[len]) { len++; next[i] = len; i++; } else { if (len != 0) { len = next[len - 1]; // 顺着失配位置向左回溯 } else { next[i] = 0; i++; } } } return C_ERR_OK; } c_size_t c_StrIndexKmpEx(const void* text, c_size_t text_len, const void* pattern, c_size_t pattern_len, c_size_t start_offset, c_Allocator_t* allocator) { // 1. 强御级无效边界防御 if (!text || !pattern) return C_KMP_NOT_FOUND; const uint8_t* t = (const uint8_t*)text; const uint8_t* p = (const uint8_t*)pattern; // 如果传入 0 则自适应兼容裸字符串 c_size_t n = (text_len == 0) ? (c_size_t)strlen((const char*)text) : text_len; c_size_t m = (pattern_len == 0) ? (c_size_t)strlen((const char*)pattern) : pattern_len; if (m == 0 || n == 0 || start_offset >= n || m > (n - start_offset)) { return C_KMP_NOT_FOUND; } c_Allocator_t* alloc = (allocator != NULL) ? allocator : &c_DefaultAllocator; // 2. 【安全机制】:坚决不使用栈上的局部可变长数组(VLA),防止被大特征串顶爆引发 Stack Overflow // 从内部绑定的专属多态分配器中动态申领物理块资源 c_size_t* next = (c_size_t*)c_Allocator_Alloc(alloc, m * sizeof(c_size_t)); if (!next) return C_KMP_NOT_FOUND; // 3. 构建 KMP 高速失配加速表 c_Kmp_BuildNextTable(p, m, next); // 4. 开始执行双指针拉平线性单向匹配检索流 (无回溯 O(M+N)) c_size_t i = start_offset; // 文本大字符串的推进指针 c_size_t j = 0; // 模式串的局部指针 while (i < n) { if (t[i] == p[j]) { i++; j++; } if (j == m) { // 完美踩中特征指纹,捕获命中! c_size_t found_idx = i - j; // 强异常安全性物理火化:归还申领的跳转数组块,杜绝堆碎片跑飞 c_Allocator_Free(alloc, next); return found_idx; // 返回命中位置相对于首地址的绝对物理偏移量 } else if (i < n && t[i] != p[j]) { // 发生失配抖动,KMP 的精髓:文本指针 i 绝对不后退,只原位等待,而模式串指针 j 顺着失配表向左高速跳转 if (j != 0) { j = next[j - 1]; } else { i++; } } } // 全文扫描结束,未发生特征匹配,体面卸载资源退出 c_Allocator_Free(alloc, next); return C_KMP_NOT_FOUND; }