| 278 | // |request|. Each feature will be passed to |toDo| only once. |
| 279 | template <typename DFA, typename ValueList, typename Filter, typename ToDo> |
| 280 | void MatchFeaturesInTrie(SearchTrieRequest<DFA> const & request, trie::Iterator<ValueList> const & trieRoot, |
| 281 | Filter const & filter, ToDo && toDo) |
| 282 | { |
| 283 | using Value = typename ValueList::Value; |
| 284 | |
| 285 | TrieValuesHolder<Filter, Value> categoriesHolder(filter); |
| 286 | bool const categoriesExist = MatchCategoriesInTrie(request, trieRoot, categoriesHolder); |
| 287 | |
| 288 | /// @todo Not sure why do we have OffsetIntersector here? We are doing aggregation only. |
| 289 | impl::OffsetIntersector<Filter, Value> intersector(filter); |
| 290 | |
| 291 | ForEachLangPrefix(request, trieRoot, [&request, &intersector](TrieRootPrefix<ValueList> & langRoot, int8_t /* lang */) |
| 292 | { |
| 293 | // Aggregate for all languages. |
| 294 | MatchInTrie(request.m_names, langRoot, intersector); |
| 295 | }); |
| 296 | |
| 297 | if (categoriesExist) |
| 298 | { |
| 299 | // Aggregate categories. |
| 300 | categoriesHolder.ForEachValue(intersector); |
| 301 | } |
| 302 | |
| 303 | intersector.NextStep(); |
| 304 | intersector.ForEachResult(toDo); |
| 305 | } |
| 306 | |
| 307 | template <typename ValueList, typename Filter, typename ToDo> |
| 308 | void MatchPostcodesInTrie(TokenSlice const & slice, trie::Iterator<ValueList> const & trieRoot, Filter const & filter, |