#include #include #define MAX_STACK_LPS 128 static void compute_LPS_table(const char* pattern, c_size_t m, long long* lps) { c_size_t len = 0; // Length of the previous longest prefix suffix lps[0] = 0; // lps[0] is always 0 c_size_t i = 1; while (i < m) { if (pattern[i] == pattern[len]) { len++; lps[i] = (long long)len; i++; } else { if (len != 0) { len = (c_size_t)lps[len - 1]; // Backtrack without shifting 'i' } else { lps[i] = 0; i++; } } } } long long c_StrIndexKmp(const char* text, const char* pattern) { if (!text || !pattern) return -1; const c_size_t n = strlen(text); const c_size_t m = strlen(pattern); if (m == 0) return 0; // An empty pattern matches at the very beginning if (m > n) return -1; // Pattern is longer than the text container // Optimization: Use a stack buffer if the pattern length fits, avoiding heap allocation cycles long long stack_lps[MAX_STACK_LPS]; long long* lps = (m <= MAX_STACK_LPS) ? stack_lps : (long long*)C_ALLOC(m * sizeof(long long)); if (!lps) return -1; // Allocation failure fallback // Step 1: Precompute the lookup table compute_LPS_table(pattern, m, lps); // Step 2: Linear string matching phase c_size_t i = 0; // Index for text c_size_t j = 0; // Index for pattern long long matched_index = -1; while (i < n) { if (pattern[j] == text[i]) { i++; j++; } if (j == m) { matched_index = (long long)(i - j); // Found match at index (i - j) break; // Terminate early for the first occurrence } // Mismatch after j matches else if (i < n && pattern[j] != text[i]) { if (j != 0) { j = (size_t)lps[j - 1]; // Slide the pattern using the precomputed LPS table } else { i++; } } } // Clean up heap memory if it was allocated if (lps != stack_lps) { C_FREE(lps); } return matched_index; }