| 1102 | } |
| 1103 | |
| 1104 | py::UniqueObj PhraserObject::call(PyObject* words) const |
| 1105 | { |
| 1106 | py::UniqueObj ret{ PyList_New(0) }; |
| 1107 | deque<tomoto::Vid> buffer; |
| 1108 | size_t c_found = 0; |
| 1109 | auto* node = trie_nodes.data(); |
| 1110 | py::foreachWithPy<string>(words, [&](const string& w, PyObject* pw) |
| 1111 | { |
| 1112 | auto wid = vocabs.toWid(w); |
| 1113 | |
| 1114 | if (wid != tomoto::non_vocab_id) |
| 1115 | { |
| 1116 | auto* nnode = node->getNext(wid); |
| 1117 | if (!nnode) |
| 1118 | { |
| 1119 | if (c_found) |
| 1120 | { |
| 1121 | auto& info = cand_info[c_found - 1]; |
| 1122 | if (buffer.size() >= info.second) |
| 1123 | { |
| 1124 | PyList_Append(ret.get(), py::buildPyValue(info.first).get()); |
| 1125 | buffer.erase(buffer.begin(), buffer.begin() + info.second); |
| 1126 | } |
| 1127 | c_found = 0; |
| 1128 | } |
| 1129 | } |
| 1130 | |
| 1131 | while (!nnode) |
| 1132 | { |
| 1133 | size_t curDepth = node->depth; |
| 1134 | node = node->getFail(); |
| 1135 | for (size_t d = node ? node->depth : 0; !buffer.empty() && d < curDepth; ++d) |
| 1136 | { |
| 1137 | PyList_Append(ret.get(), py::buildPyValue(vocabs.toWord(buffer.front())).get()); |
| 1138 | buffer.pop_front(); |
| 1139 | } |
| 1140 | if (node) nnode = node->getNext(wid); |
| 1141 | else break; |
| 1142 | } |
| 1143 | |
| 1144 | if (nnode) |
| 1145 | { |
| 1146 | node = nnode; |
| 1147 | if (nnode->val && nnode->val != (size_t)-1) |
| 1148 | { |
| 1149 | c_found = nnode->val; |
| 1150 | } |
| 1151 | buffer.emplace_back(wid); |
| 1152 | return; |
| 1153 | } |
| 1154 | } |
| 1155 | |
| 1156 | for (auto v : buffer) PyList_Append(ret.get(), py::buildPyValue(vocabs.toWord(v)).get()); |
| 1157 | buffer.clear(); |
| 1158 | PyList_Append(ret.get(), pw); |
| 1159 | node = trie_nodes.data(); |
| 1160 | }, "`words` must be an iterable of `str`s."); |
| 1161 | if (c_found) |
nothing calls this directly
no test coverage detected