| 1173 | } |
| 1174 | |
| 1175 | py::UniqueObj PhraserObject::findall(PyObject* words) const |
| 1176 | { |
| 1177 | py::UniqueObj ret{ PyList_New(0) }; |
| 1178 | size_t c_found = 0, stack_size = 0, cur_pos = 0; |
| 1179 | auto* node = trie_nodes.data(); |
| 1180 | py::foreach<string>(words, [&](const string& w) |
| 1181 | { |
| 1182 | auto wid = vocabs.toWid(w); |
| 1183 | |
| 1184 | if (wid != tomoto::non_vocab_id) |
| 1185 | { |
| 1186 | auto* nnode = node->getNext(wid); |
| 1187 | if (!nnode) |
| 1188 | { |
| 1189 | if (c_found) |
| 1190 | { |
| 1191 | auto& info = cand_info[c_found - 1]; |
| 1192 | if (stack_size >= info.second) |
| 1193 | { |
| 1194 | assert(cur_pos - stack_size < PyObject_Length(words)); |
| 1195 | assert(cur_pos - stack_size + info.second <= PyObject_Length(words)); |
| 1196 | PyList_Append(ret.get(), py::buildPyTuple(info.first, py::buildPyTuple(cur_pos - stack_size, cur_pos - stack_size + info.second)).get()); |
| 1197 | stack_size -= info.second; |
| 1198 | |
| 1199 | size_t targetDepth = node->depth - info.second; |
| 1200 | while (node->depth > targetDepth) |
| 1201 | { |
| 1202 | node = node->getFail(); |
| 1203 | } |
| 1204 | nnode = node->getNext(wid); |
| 1205 | } |
| 1206 | c_found = 0; |
| 1207 | } |
| 1208 | |
| 1209 | while (!nnode) |
| 1210 | { |
| 1211 | size_t curDepth = node->depth; |
| 1212 | node = node->getFail(); |
| 1213 | stack_size -= curDepth - (node ? node->depth : 0); |
| 1214 | if (node) nnode = node->getNext(wid); |
| 1215 | else break; |
| 1216 | } |
| 1217 | } |
| 1218 | |
| 1219 | if (nnode) |
| 1220 | { |
| 1221 | node = nnode; |
| 1222 | if (nnode->val && nnode->val != (size_t)-1) |
| 1223 | { |
| 1224 | c_found = nnode->val; |
| 1225 | } |
| 1226 | stack_size++; |
| 1227 | cur_pos++; |
| 1228 | return; |
| 1229 | } |
| 1230 | } |
| 1231 | stack_size = 0; |
| 1232 | node = trie_nodes.data(); |
no test coverage detected