Skip to content
38 changes: 22 additions & 16 deletions components/core/src/clp/DictionaryReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ class DictionaryReader {
*/
std::string const& get_value(DictionaryIdType id) const;
/**
* Gets the entry exactly matching the given search string
* Gets the entries matching the given search string
* @param search_string
* @param ignore_case
* @return nullptr if an exact match is not found, the entry otherwise
* @return a vector of matching entries, or an empty vector if no entry matches.
*/
EntryType const*
std::vector<EntryType const*>
get_entry_matching_value(std::string const& search_string, bool ignore_case) const;
/**
* Gets the entries that match a given wildcard string
Expand Down Expand Up @@ -233,26 +233,32 @@ std::string const& DictionaryReader<DictionaryIdType, EntryType>::get_value(Dict
}

template <typename DictionaryIdType, typename EntryType>
EntryType const* DictionaryReader<DictionaryIdType, EntryType>::get_entry_matching_value(
std::vector<EntryType const*>
DictionaryReader<DictionaryIdType, EntryType>::get_entry_matching_value(
Comment thread
aestriplex marked this conversation as resolved.
std::string const& search_string,
bool ignore_case
) const {
if (false == ignore_case) {
for (auto const& entry : m_entries) {
if (entry.get_value() == search_string) {
return &entry;
}
}
} else {
auto const& search_string_uppercase = boost::algorithm::to_upper_copy(search_string);
for (auto const& entry : m_entries) {
if (boost::algorithm::to_upper_copy(entry.get_value()) == search_string_uppercase) {
return &entry;
}
// In case-sensitive match, there can be only one matched entry.
if (auto const it = std::ranges::find_if(
m_entries,
[&](auto const& entry) { return entry.get_value() == search_string; }
);
m_entries.cend() != it)
{
return {&(*it)};
}
return {};
}

return nullptr;
std::vector<EntryType const*> entries;
auto const search_string_uppercase = boost::algorithm::to_upper_copy(search_string);
for (auto const& entry : m_entries) {
if (boost::algorithm::to_upper_copy(entry.get_value()) == search_string_uppercase) {
entries.push_back(&entry);
}
}
return entries;
}

template <typename DictionaryIdType, typename EntryType>
Expand Down
24 changes: 20 additions & 4 deletions components/core/src/clp/EncodedVariableInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cassert>
#include <cmath>
#include <unordered_set>

#include <string_utils/string_utils.hpp>

Expand Down Expand Up @@ -386,15 +387,30 @@ bool EncodedVariableInterpreter::encode_and_search_dictionary(
LogTypeDictionaryEntry::add_float_var(logtype);
sub_query.add_non_dict_var(encoded_var);
} else {
auto entry = var_dict.get_entry_matching_value(var_str, ignore_case);
if (nullptr == entry) {
auto const entries = var_dict.get_entry_matching_value(var_str, ignore_case);
if (entries.empty()) {
// Not in dictionary
return false;
}
encoded_var = encode_var_dict_id(entry->get_id());

LogTypeDictionaryEntry::add_dict_var(logtype);
sub_query.add_dict_var(encoded_var, entry);

if (entries.size() == 1) {
auto const* entry = entries.at(0);
sub_query.add_dict_var(encode_var_dict_id(entry->get_id()), entry);
return true;
}

std::unordered_set<clp::VariableDictionaryEntry const*> const entries_set{
entries.cbegin(),
entries.cend()
};
std::unordered_set<encoded_variable_t> encoded_vars;
Comment thread
aestriplex marked this conversation as resolved.
Comment thread
aestriplex marked this conversation as resolved.
encoded_vars.reserve(entries.size());
for (auto const* entry : entries) {
encoded_vars.emplace(encode_var_dict_id(entry->get_id()));
}
sub_query.add_imprecise_dict_var(encoded_vars, entries_set);
}

return true;
Expand Down
38 changes: 22 additions & 16 deletions components/core/src/clp_s/DictionaryReader.hpp

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gibber9809 The change in CLP-S looks reasonable to me, but can you take another look?

Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ class DictionaryReader {
std::string const& get_value(DictionaryIdType id) const;

/**
* Gets the entry exactly matching the given search string
* Gets the entries matching the given search string
* @param search_string
* @param ignore_case
* @return nullptr if an exact match is not found, the entry otherwise
* @return a vector of matching entries, or an empty vector if no entry matches.
*/
EntryType const*
std::vector<EntryType const*>
get_entry_matching_value(std::string const& search_string, bool ignore_case) const;

/**
Expand Down Expand Up @@ -156,26 +156,32 @@ std::string const& DictionaryReader<DictionaryIdType, EntryType>::get_value(Dict
}

template <typename DictionaryIdType, typename EntryType>
EntryType const* DictionaryReader<DictionaryIdType, EntryType>::get_entry_matching_value(
std::vector<EntryType const*>
DictionaryReader<DictionaryIdType, EntryType>::get_entry_matching_value(
std::string const& search_string,
bool ignore_case
) const {
if (false == ignore_case) {
for (auto const& entry : m_entries) {
if (entry.get_value() == search_string) {
return &entry;
}
}
} else {
auto const& search_string_uppercase = boost::algorithm::to_upper_copy(search_string);
for (auto const& entry : m_entries) {
if (boost::algorithm::to_upper_copy(entry.get_value()) == search_string_uppercase) {
return &entry;
}
// In case-sensitive match, there can be only one matched entry.
if (auto const it = std::ranges::find_if(
m_entries,
[&](auto const& entry) { return entry.get_value() == search_string; }
);
m_entries.cend() != it)
{
return {&(*it)};
}
return {};
}

return nullptr;
std::vector<EntryType const*> entries;
auto const search_string_uppercase = boost::algorithm::to_upper_copy(search_string);
for (auto const& entry : m_entries) {
if (boost::algorithm::to_upper_copy(entry.get_value()) == search_string_uppercase) {
entries.push_back(&entry);
}
}
return entries;
}

template <typename DictionaryIdType, typename EntryType>
Expand Down
4 changes: 2 additions & 2 deletions components/core/src/clp_s/search/Output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -932,12 +932,12 @@ void Output::populate_string_queries(std::shared_ptr<Expression> const& expr) {
}
}

auto const* entry = m_var_dict->get_entry_matching_value(
auto const entries = m_var_dict->get_entry_matching_value(
unescaped_query_string,
m_ignore_case
);

if (entry != nullptr) {
for (auto const& entry : entries) {
matching_vars.insert(entry->get_id());
}
} else if (EncodedVariableInterpreter::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <cassert>
#include <cmath>
#include <unordered_set>

#include <spdlog/spdlog.h>

Expand Down Expand Up @@ -34,15 +35,30 @@ bool EncodedVariableInterpreter::encode_and_search_dictionary(
LogTypeDictionaryEntry::add_double_var(logtype);
sub_query.add_non_dict_var(encoded_var);
} else {
auto entry = var_dict.get_entry_matching_value(var_str, ignore_case);
if (nullptr == entry) {
auto const entries = var_dict.get_entry_matching_value(var_str, ignore_case);
if (entries.empty()) {
// Not in dictionary
return false;
}
encoded_var = VariableEncoder::encode_var_dict_id(entry->get_id());

LogTypeDictionaryEntry::add_non_double_var(logtype);
sub_query.add_dict_var(encoded_var, entry);

if (entries.size() == 1) {
auto const* entry = entries.at(0);
sub_query.add_dict_var(VariableEncoder::encode_var_dict_id(entry->get_id()), entry);
return true;
}

std::unordered_set<VariableDictionaryEntry const*> const entries_set{
entries.cbegin(),
entries.cend()
};
std::unordered_set<encoded_variable_t> encoded_vars;
encoded_vars.reserve(entries.size());
for (auto const* entry : entries) {
encoded_vars.emplace(VariableEncoder::encode_var_dict_id(entry->get_id()));
}
sub_query.add_imprecise_dict_var(encoded_vars, entries_set);
}

return true;
Expand Down
45 changes: 45 additions & 0 deletions components/core/tests/test-EncodedVariableInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,51 @@ TEST_CASE("EncodedVariableInterpreter", "[EncodedVariableInterpreter]") {
));
}

SECTION("Test multiple metching values") {
constexpr std::string_view cVarDictPath{"var.dict"};
constexpr std::string_view cVarSegmentIndexPath{"var.segindex"};
constexpr std::array<std::string_view, 4> var_strs
= {"python2.7.3", "Python2.7.3", "PyThOn2.7.3", "PYTHON2.7.3"};
clp::VariableDictionaryWriter var_dict_writer;
Comment thread
aestriplex marked this conversation as resolved.
Outdated

var_dict_writer.open(
std::string{cVarDictPath},
std::string{cVarSegmentIndexPath},
cVariableDictionaryIdMax
);

std::vector<encoded_variable_t> encoded_vars;
std::vector<clp::variable_dictionary_id_t> var_ids;
clp::LogTypeDictionaryEntry logtype_dict_entry;
std::string const msg_template{"here is a string with a dictionary var: "};

for (auto const& var_str : var_strs) {
EncodedVariableInterpreter::encode_and_add_to_dictionary(
Comment thread
aestriplex marked this conversation as resolved.
Outdated
msg_template + std::string{var_str},
logtype_dict_entry,
var_dict_writer,
encoded_vars,
var_ids
);
}
var_dict_writer.close();

clp::VariableDictionaryReader var_dict_reader;
var_dict_reader.open(std::string{cVarDictPath}, std::string{cVarSegmentIndexPath});
var_dict_reader.read_new_entries();

REQUIRE(var_dict_reader.get_entry_matching_value(std::string{var_strs.at(0)}, true).size()
== var_strs.size());
REQUIRE(var_dict_reader.get_entry_matching_value(std::string{var_strs.at(0)}, false).size()
== 1);

var_dict_reader.close();

// Clean-up
REQUIRE(0 == unlink(cVarDictPath.data()));
REQUIRE(0 == unlink(cVarSegmentIndexPath.data()));
}

SECTION("Test encoding and decoding") {
string msg;

Expand Down