perf(label_table): add TryGetIdByLabel to avoid exception overhead#1769
perf(label_table): add TryGetIdByLabel to avoid exception overhead#1769
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a TryGetIdByLabel method to the LabelTable class, providing a non-throwing way to retrieve an ID by its label, and refactors GetIdByLabel to utilize this new method. Additionally, unit tests were added to cover both the reverse map and linear lookup paths. Feedback suggests using std::optional instead of std::pair for the return type of TryGetIdByLabel to align with modern C++ idioms and improve safety.
| GetIdByLabel(LabelType label) const { | ||
| auto [success, inner_id] = TryGetIdByLabel(label); | ||
| if (not success) { | ||
| throw std::runtime_error(fmt::format("label {} is not exists", label)); | ||
| } | ||
| return inner_id; | ||
| } | ||
|
|
||
| inline std::pair<bool, InnerIdType> | ||
| TryGetIdByLabel(LabelType label) const noexcept { | ||
| if (use_reverse_map_) { | ||
| if (this->label_remap_.count(label) == 0) { | ||
| throw std::runtime_error(fmt::format("label {} is not exists", label)); | ||
| auto iter = this->label_remap_.find(label); | ||
| if (iter == this->label_remap_.end()) { | ||
| return {false, 0}; | ||
| } | ||
| return this->label_remap_.at(label); | ||
| return {true, iter->second}; | ||
| } | ||
| auto result = std::find(label_table_.begin(), label_table_.end(), label); | ||
| if (result == label_table_.end()) { | ||
| throw std::runtime_error(fmt::format("label {} is not exists", label)); | ||
| return {false, 0}; | ||
| } | ||
| return result - label_table_.begin(); | ||
| return {true, static_cast<InnerIdType>(result - label_table_.begin())}; | ||
| } |
There was a problem hiding this comment.
For representing an optional value, std::optional<InnerIdType> is more idiomatic and safer than std::pair<bool, InnerIdType> in modern C++ (C++17 and later). This avoids potential bugs where a consumer of this function might forget to check the boolean flag and incorrectly use the returned default value (0 in this case, which could be a valid ID).
This change also requires updating GetIdByLabel to handle the std::optional return type.
Note: You'll need to add #include <optional> at the top of the file.
GetIdByLabel(LabelType label) const {
auto inner_id = TryGetIdByLabel(label);
if (!inner_id) {
throw std::runtime_error(fmt::format("label {} is not exists", label));
}
return *inner_id;
}
inline std::optional<InnerIdType>
TryGetIdByLabel(LabelType label) const noexcept {
if (use_reverse_map_) {
auto iter = this->label_remap_.find(label);
if (iter == this->label_remap_.end()) {
return std::nullopt;
}
return iter->second;
}
auto result = std::find(label_table_.begin(), label_table_.end(), label);
if (result == label_table_.end()) {
return std::nullopt;
}
return static_cast<InnerIdType>(result - label_table_.begin());
}There was a problem hiding this comment.
Pull request overview
This PR backports a non-throwing label lookup API to the 0.15 branch to avoid exception overhead when probing for missing labels, and adds unit coverage for both lookup modes.
Changes:
- Refactor
LabelTable::GetIdByLabelto delegate to a new non-throwing helper. - Add
LabelTable::TryGetIdByLabelreturning{ok, inner_id}for both reverse-map and linear-scan paths. - Add unit tests covering success/failure for both reverse-map and non-reverse-map configurations.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/label_table.h | Adds TryGetIdByLabel and rewires GetIdByLabel to use it (preserving throwing behavior). |
| src/label_table_test.cpp | Adds focused Catch2 unit tests for TryGetIdByLabel under both lookup implementations. |
| inline std::pair<bool, InnerIdType> | ||
| TryGetIdByLabel(LabelType label) const noexcept { | ||
| if (use_reverse_map_) { |
There was a problem hiding this comment.
TryGetIdByLabel introduces a public std::pair return type, but this header doesn’t include the standard headers needed for the types it directly uses (std::pair/std::find/std::shared_ptr/std::function/std::tuple/std::runtime_error). This currently relies on transitive includes (e.g., from fmt/stream headers), which is fragile and can break with include-order changes. Add the appropriate <utility>, <algorithm>, <memory>, <functional>, <tuple>, and <stdexcept> includes in label_table.h.
| GetIdByLabel(LabelType label) const { | ||
| auto [success, inner_id] = TryGetIdByLabel(label); | ||
| if (not success) { | ||
| throw std::runtime_error(fmt::format("label {} is not exists", label)); |
There was a problem hiding this comment.
The thrown message "label {} is not exists" is grammatically incorrect / unclear for API consumers. Consider changing it to something like “label {} does not exist” (and keep the same phrasing anywhere else this error is surfaced).
| throw std::runtime_error(fmt::format("label {} is not exists", label)); | |
| throw std::runtime_error(fmt::format("label {} does not exist", label)); |
| if (iter == this->label_remap_.end()) { | ||
| return {false, 0}; | ||
| } | ||
| return this->label_remap_.at(label); | ||
| return {true, iter->second}; | ||
| } | ||
| auto result = std::find(label_table_.begin(), label_table_.end(), label); | ||
| if (result == label_table_.end()) { | ||
| throw std::runtime_error(fmt::format("label {} is not exists", label)); | ||
| return {false, 0}; | ||
| } |
There was a problem hiding this comment.
TryGetIdByLabel returns {false, 0} in the not-found case. Using a literal 0 here is a bit magic and couples behavior to the current InnerIdType representation; prefer returning a value-initialized InnerIdType{} (and consider whether the return value should be treated as unspecified when ok == false).
73560df to
539bf21
Compare
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## 0.15 #1769 +/- ##
==========================================
+ Coverage 90.12% 90.21% +0.09%
==========================================
Files 218 218
Lines 13537 13548 +11
==========================================
+ Hits 12200 12223 +23
+ Misses 1337 1325 -12
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
539bf21 to
6c891a7
Compare
…1701) Backport the non-throwing label lookup helper to 0.15 and update the CalDistanceById call paths to avoid exception-driven control flow. Keep the 0.15 branch shape intact by only applying the compatible caller changes on this branch. Signed-off-by: inabao <jinjiabao.jjb@antgroup.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> (cherry picked from commit cafb34b)
21ad084 to
d659222
Compare
Summary
LabelTable::TryGetIdByLabelhelper onto0.150.15branch shape intact by applying only the compatible portion ofcafb34b