177 lines
4 KiB
C++
177 lines
4 KiB
C++
// Interface functions for libac.so
|
|
//
|
|
#include <vector>
|
|
#include <string>
|
|
#include "ac_slow.hpp"
|
|
#include "ac_fast.hpp"
|
|
#include "ac.h" // for the definition of ac_result_t
|
|
#include "ac_util.hpp"
|
|
|
|
extern "C" {
|
|
#include <lua.h>
|
|
#include <lauxlib.h>
|
|
}
|
|
|
|
#if defined(USE_SLOW_VER)
|
|
#error "Not going to implement it"
|
|
#endif
|
|
|
|
#if defined(__CYGWIN__)
|
|
#undef _L
|
|
#endif
|
|
|
|
using namespace std;
|
|
static const char* tname = "aho-corasick";
|
|
|
|
class BufAlloc : public Buf_Allocator {
|
|
public:
|
|
BufAlloc(lua_State* L) : _L(L) {}
|
|
virtual AC_Buffer* alloc(int sz) {
|
|
return (AC_Buffer*)lua_newuserdata (_L, sz);
|
|
}
|
|
|
|
// Let GC to take care.
|
|
virtual void free() {}
|
|
|
|
private:
|
|
lua_State* _L;
|
|
};
|
|
|
|
static bool
|
|
_create_helper(lua_State* L, const vector<const char*>& str_v,
|
|
const vector<unsigned int>& strlen_v) {
|
|
ASSERT(str_v.size() == strlen_v.size());
|
|
|
|
ACS_Constructor acc;
|
|
BufAlloc ba(L);
|
|
|
|
// Step 1: construt the slow version.
|
|
unsigned int strnum = str_v.size();
|
|
const char** str_vect = new const char*[strnum];
|
|
unsigned int* strlen_vect = new unsigned int[strnum];
|
|
|
|
int idx = 0;
|
|
for (vector<const char*>::const_iterator i = str_v.begin(), e = str_v.end();
|
|
i != e; i++) {
|
|
str_vect[idx++] = *i;
|
|
}
|
|
|
|
idx = 0;
|
|
for (vector<unsigned int>::const_iterator i = strlen_v.begin(),
|
|
e = strlen_v.end(); i != e; i++) {
|
|
strlen_vect[idx++] = *i;
|
|
}
|
|
|
|
acc.Construct(str_vect, strlen_vect, idx);
|
|
delete[] str_vect;
|
|
delete[] strlen_vect;
|
|
|
|
// Step 2: convert to fast version
|
|
AC_Converter cvt(acc, ba);
|
|
return cvt.Convert() != 0;
|
|
}
|
|
|
|
static ac_result_t
|
|
_match_helper(buf_header_t* ac, const char *str, unsigned int len) {
|
|
AC_Buffer* buf = (AC_Buffer*)(void*)ac;
|
|
ASSERT(ac->magic_num == AC_MAGIC_NUM);
|
|
|
|
ac_result_t r = Match(buf, str, len);
|
|
return r;
|
|
}
|
|
|
|
// LUA sematic:
|
|
// input: array of strings
|
|
// output: userdata containing the AC-graph (i.e. the AC_Buffer).
|
|
//
|
|
static int
|
|
lac_create(lua_State* L) {
|
|
// The table of the array must be the 1st argument.
|
|
int input_tab = 1;
|
|
|
|
luaL_checktype(L, input_tab, LUA_TTABLE);
|
|
|
|
// Init the "iteartor".
|
|
lua_pushnil(L);
|
|
|
|
vector<const char*> str_v;
|
|
vector<unsigned int> strlen_v;
|
|
|
|
// Loop over the elements
|
|
while (lua_next(L, input_tab)) {
|
|
size_t str_len;
|
|
const char* s = luaL_checklstring(L, -1, &str_len);
|
|
str_v.push_back(s);
|
|
strlen_v.push_back(str_len);
|
|
|
|
// remove the value, but keep the key as the iterator.
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
// pop the nil value
|
|
lua_pop(L, 1);
|
|
|
|
if (_create_helper(L, str_v, strlen_v)) {
|
|
// The AC graph, as a userdata is already pushed to the stack, hence 1.
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// LUA input:
|
|
// arg1: the userdata, representing the AC graph, returned from l_create().
|
|
// arg2: the string to be matched.
|
|
//
|
|
// LUA return:
|
|
// if match, return index range of the match; otherwise nil is returned.
|
|
//
|
|
static int
|
|
lac_match(lua_State* L) {
|
|
buf_header_t* ac = (buf_header_t*)lua_touserdata(L, 1);
|
|
if (!ac) {
|
|
luaL_checkudata(L, 1, tname);
|
|
return 0;
|
|
}
|
|
|
|
size_t len;
|
|
const char* str;
|
|
#if LUA_VERSION_NUM >= 502
|
|
str = luaL_tolstring(L, 2, &len);
|
|
#else
|
|
str = lua_tolstring(L, 2, &len);
|
|
#endif
|
|
if (!str) {
|
|
luaL_checkstring(L, 2);
|
|
return 0;
|
|
}
|
|
|
|
ac_result_t r = _match_helper(ac, str, len);
|
|
if (r.match_begin != -1) {
|
|
lua_pushinteger(L, r.match_begin);
|
|
lua_pushinteger(L, r.match_end);
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct luaL_Reg lib_funcs[] = {
|
|
{ "create", lac_create },
|
|
{ "match", lac_match },
|
|
{0, 0}
|
|
};
|
|
|
|
extern "C" int AC_EXPORT
|
|
luaopen_ahocorasick(lua_State* L) {
|
|
luaL_newmetatable(L, tname);
|
|
|
|
#if LUA_VERSION_NUM == 501
|
|
luaL_register(L, tname, lib_funcs);
|
|
#elif LUA_VERSION_NUM >= 502
|
|
luaL_newlib(L, lib_funcs);
|
|
#else
|
|
#error "Don't know how to do it right"
|
|
#endif
|
|
return 1;
|
|
}
|