|
13 | 13 |
|
14 | 14 | #include "CommonUtils/ConfigurableParam.h" |
15 | 15 | #include <cstddef> |
| 16 | +#include "CommonUtils/ConfigurableParamHelper.h" |
16 | 17 | #include "CommonUtils/StringUtils.h" |
17 | 18 | #include "CommonUtils/KeyValParam.h" |
18 | 19 | #include "CommonUtils/ConfigurableParamReaders.h" |
@@ -433,6 +434,60 @@ const ContainerHandler* getContainerHandler(const std::type_info& type) |
433 | 434 | return iter == handlers.end() ? nullptr : &iter->second; |
434 | 435 | } |
435 | 436 |
|
| 437 | +std::pair<std::string_view, std::string_view> splitConfigurableParamKey(std::string_view key) |
| 438 | +{ |
| 439 | + const auto separator = key.find('.'); |
| 440 | + if (separator == std::string_view::npos) { |
| 441 | + return {key, {}}; |
| 442 | + } |
| 443 | + return {key.substr(0, separator), key.substr(separator + 1)}; |
| 444 | +} |
| 445 | + |
| 446 | +std::string findClosestConfigurableParamKey(const std::string& requestedKey, |
| 447 | + const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap) |
| 448 | +{ |
| 449 | + if (storageMap.empty()) { |
| 450 | + return {}; |
| 451 | + } |
| 452 | + |
| 453 | + const auto [requestedMainKey, requestedSubKey] = splitConfigurableParamKey(requestedKey); |
| 454 | + bool mainKeyExists = false; |
| 455 | + for (const auto& entry : storageMap) { |
| 456 | + const auto mainKey = splitConfigurableParamKey(entry.first).first; |
| 457 | + if (mainKey == requestedMainKey) { |
| 458 | + mainKeyExists = true; |
| 459 | + break; |
| 460 | + } |
| 461 | + } |
| 462 | + |
| 463 | + std::string closest; |
| 464 | + std::size_t closestDistance = std::numeric_limits<std::size_t>::max(); |
| 465 | + for (const auto& entry : storageMap) { |
| 466 | + const auto& key = entry.first; |
| 467 | + const auto [mainKey, subKey] = splitConfigurableParamKey(key); |
| 468 | + if (mainKeyExists && mainKey != requestedMainKey) { |
| 469 | + continue; |
| 470 | + } |
| 471 | + const auto distance = mainKeyExists ? damerauLevenshteinDistance(requestedSubKey, subKey) : damerauLevenshteinDistance(requestedKey, key); |
| 472 | + if (distance < closestDistance || (distance == closestDistance && (closest.empty() || key < closest))) { |
| 473 | + closest = key; |
| 474 | + closestDistance = distance; |
| 475 | + } |
| 476 | + } |
| 477 | + return closest; |
| 478 | +} |
| 479 | + |
| 480 | +std::string formatUnknownConfigurableParamKeyMessage(const std::string& prefix, const std::string& key, |
| 481 | + const std::map<std::string, std::pair<std::type_info const&, void*>>& storageMap) |
| 482 | +{ |
| 483 | + std::string message = prefix + key; |
| 484 | + auto closest = findClosestConfigurableParamKey(key, storageMap); |
| 485 | + if (!closest.empty()) { |
| 486 | + message += ". Did you mean '" + closest + "'?"; |
| 487 | + } |
| 488 | + return message; |
| 489 | +} |
| 490 | + |
436 | 491 | } // namespace |
437 | 492 |
|
438 | 493 | // ------------------------------------------------------------------ |
@@ -978,10 +1033,10 @@ void ConfigurableParam::setValues(std::vector<std::pair<std::string, std::string |
978 | 1033 |
|
979 | 1034 | if (!keyInTree(sPtree, key)) { |
980 | 1035 | if (nonFatal) { |
981 | | - LOG(warn) << "Ignoring non-existent ConfigurableParam key: " << key; |
| 1036 | + LOG(warn) << formatUnknownConfigurableParamKeyMessage("Ignoring non-existent ConfigurableParam key: ", key, *sKeyToStorageMap); |
982 | 1037 | continue; |
983 | 1038 | } |
984 | | - LOG(fatal) << "Inexistent ConfigurableParam key: " << key; |
| 1039 | + LOG(fatal) << formatUnknownConfigurableParamKeyMessage("Inexistent ConfigurableParam key: ", key, *sKeyToStorageMap); |
985 | 1040 | } |
986 | 1041 |
|
987 | 1042 | auto iter = sKeyToStorageMap->find(key); |
|
0 commit comments