#pragma once #include "indexer/scales.hpp" #include "coding/string_utf8_multilang.hpp" #include "base/assert.hpp" #include "base/small_set.hpp" #include "base/string_utils.hpp" #include #include #include #include #include #include #include namespace search { class TokenRange; class QueryParams { public: using String = strings::UniString; using TypeIndices = std::vector; using Langs = base::SafeSmallSet; class Token { public: Token() = default; Token(String const & original) : m_original(original) {} void AddSynonym(std::string const & s); void AddSynonym(String const & s); // Calls |fn| on the original token and on synonyms. template std::enable_if_t, void>::value> ForEach( Fn && fn) const { fn(m_original); std::for_each(m_synonyms.begin(), m_synonyms.end(), std::forward(fn)); } // Calls |fn| on the original token and on synonyms until |fn| return false. template std::enable_if_t, bool>::value> ForEach( Fn && fn) const { if (!fn(m_original)) return; for (auto const & synonym : m_synonyms) { if (!fn(synonym)) return; } } template std::enable_if_t, bool>::value, bool> AnyOf( Fn && fn) const { if (fn(m_original)) return true; return std::any_of(m_synonyms.begin(), m_synonyms.end(), std::forward(fn)); } String const & GetOriginal() const { return m_original; } void Clear() { m_original.clear(); m_synonyms.clear(); } private: friend std::string DebugPrint(QueryParams::Token const & token); String m_original; std::vector m_synonyms; }; QueryParams() = default; template void InitNoPrefix(It tokenBegin, It tokenEnd) { Clear(); for (; tokenBegin != tokenEnd; ++tokenBegin) m_tokens.emplace_back(*tokenBegin); m_typeIndices.resize(GetNumTokens()); AddSynonyms(); } template void InitWithPrefix(It tokenBegin, It tokenEnd, String const & prefix) { Clear(); for (; tokenBegin != tokenEnd; ++tokenBegin) m_tokens.emplace_back(*tokenBegin); m_prefixToken = Token(prefix); m_hasPrefix = true; m_typeIndices.resize(GetNumTokens()); AddSynonyms(); } size_t GetNumTokens() const { return m_hasPrefix ? m_tokens.size() + 1 : m_tokens.size(); } bool LastTokenIsPrefix() const { return m_hasPrefix; } bool IsEmpty() const { return GetNumTokens() == 0; } void Clear(); bool IsCategorySynonym(size_t i) const; TypeIndices & GetTypeIndices(size_t i); TypeIndices const & GetTypeIndices(size_t i) const; bool IsPrefixToken(size_t i) const; Token const & GetToken(size_t i) const; Token & GetToken(size_t i); // Returns true if all tokens in |range| have integral synonyms. bool IsNumberTokens(TokenRange const & range) const; void RemoveToken(size_t i); Langs & GetLangs() { return m_langs; } Langs const & GetLangs() const { return m_langs; } bool LangExists(int8_t lang) const { return m_langs.Contains(lang); } void SetCategorialRequest(bool isCategorial) { m_isCategorialRequest = isCategorial; } bool IsCategorialRequest() const { return m_isCategorialRequest; } int GetScale() const { return m_scale; } private: friend std::string DebugPrint(QueryParams const & params); void AddSynonyms(); std::vector m_tokens; Token m_prefixToken; bool m_hasPrefix = false; bool m_isCategorialRequest = false; std::vector m_typeIndices; Langs m_langs; int m_scale = scales::GetUpperScale(); }; } // namespace search