#include <iostream>
#include <fstream>
#include <cstring>
//---------------------------------------------------------------------------
// HyperKMP
// (c) 2019 Stoian Mihail
// - compress the pi-table to get rid of the worst-case of KMP
//---------------------------------------------------------------------------
using namespace std;
//---------------------------------------------------------------------------
#define MAX_N 2000000
#define MAX_COUNT 1000
//---------------------------------------------------------------------------
unsigned length, n, countMatches;
char pattern[MAX_N + 2];
char str[MAX_N + 2];
unsigned matches[MAX_COUNT + 1];
//---------------------------------------------------------------------------
unsigned psi[MAX_N + 2];
void compressPi()
// compress pi[] and create two new arrays: psi[] and omega[]
// description in README
{
// Initialize the first values
// 0 is the first state. At this step it receives 2 sons
psi[0] = 0;
psi[1] = 0;
// Compute pi and psi
unsigned k = 0;
for (unsigned q = 1; q < length; ++q) {
// Compute psi
while ((k > 0) && (pattern[q] != pattern[k])) {
k = psi[k];
}
if (pattern[q] == pattern[k]) {
k++;
}
// Compress possible path
// For understandability reasons, keep the formula like this
psi[q + 1] = (pattern[q + 1] == pattern[k]) ? psi[k] : k;
}
}
//---------------------------------------------------------------------------
void search()
// checks if the pattern can be found in str
{
if (length > n)
return;
if (length == 1) {
cerr << "Not supported by now" << endl;
exit(0);
}
char firstChar = pattern[0];
unsigned q = 0; // current state
unsigned index = 0;
hyperKMPSearch : {
// Doesn't enter in the while anyhow
if (!q) {
const char* found = strchr(str + index, firstChar);
if (!found)
return;
unsigned pos = found - str;
cerr << pos << endl;
// Set the new state
q = 1;
index = found - str + 1;
goto hyperKMPSearch;
}
// Now we have at least the first q chars matched
// Get rid of 2 comparisons when the char matches
if (str[index] != pattern[q]) {
q = psi[q];
while ((q > 0) && (str[index] != pattern[q]))
q = psi[q];
// TODO: what happens when q == 0?
if (str[index] == pattern[q])
++q;
} else {
++q;
}
// Found?
if (q == length) {
if ((++countMatches) <= MAX_COUNT) {
matches[countMatches - 1] = index - length + 1;
}
}
++index;
goto hyperKMPSearch;
}
}
//---------------------------------------------------------------------------
int main(int argv, char** argc) {
#if 0
std::ifstream in(argc[1]);
#else
std::ifstream in("strmatch.in");
#endif
in >> pattern >> str;
in.close();
length = strlen(pattern);
n = strlen(str);
compressPi();
search();
std::ofstream out("strmatch.out");
out << countMatches << endl;
unsigned lim = (countMatches < MAX_COUNT) ? countMatches : MAX_COUNT;
for (unsigned index = 0; index < lim; ++index)
out << matches[index] << " ";
out << endl;
out.close();
return 0;
}