-
Notifications
You must be signed in to change notification settings - Fork 51
/
load_ac.lua
90 lines (77 loc) · 2.25 KB
/
load_ac.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
-- Helper wrappring script for loading shared object libac.so (FFI interface)
-- from package.cpath instead of LD_LIBRARTY_PATH.
--
local ffi = require 'ffi'
ffi.cdef[[
void* ac_create(const char** str_v, unsigned int* strlen_v,
unsigned int v_len);
int ac_match2(void*, const char *str, int len);
void ac_free(void*);
]]
local _M = {}
local string_gmatch = string.gmatch
local string_match = string.match
local ac_lib = nil
local ac_create = nil
local ac_match = nil
local ac_free = nil
--[[ Find shared object file package.cpath, obviating the need of setting
LD_LIBRARY_PATH
]]
local function find_shared_obj(cpath, so_name)
for k, v in string_gmatch(cpath, "[^;]+") do
local so_path = string_match(k, "(.*/)")
if so_path then
-- "so_path" could be nil. e.g, the dir path component is "."
so_path = so_path .. so_name
-- Don't get me wrong, the only way to know if a file exist is
-- trying to open it.
local f = io.open(so_path)
if f ~= nil then
io.close(f)
return so_path
end
end
end
end
function _M.load_ac_lib()
if ac_lib ~= nil then
return ac_lib
else
local so_path = find_shared_obj(package.cpath, "libac.so")
if so_path ~= nil then
ac_lib = ffi.load(so_path)
ac_create = ac_lib.ac_create
ac_match = ac_lib.ac_match2
ac_free = ac_lib.ac_free
return ac_lib
end
end
end
-- Create an Aho-Corasick instance, and return the instance if it was
-- successful.
function _M.create_ac(dict)
local strnum = #dict
if ac_lib == nil then
_M.load_ac_lib()
end
local str_v = ffi.new("const char *[?]", strnum)
local strlen_v = ffi.new("unsigned int [?]", strnum)
for i = 1, strnum do
local s = dict[i]
str_v[i - 1] = s
strlen_v[i - 1] = #s
end
local ac = ac_create(str_v, strlen_v, strnum);
if ac ~= nil then
return ffi.gc(ac, ac_free)
end
end
-- Return nil if str doesn't match the dictionary, else return non-nil.
function _M.match(ac, str)
local r = ac_match(ac, str, #str);
if r >= 0 then
return r
end
end
return _M