Introduce FindIfOrNull() FindIfOrNone() and Contains() (#5322)

`FindIfOrNull` returns a pointer to the element in the range if it's
found, and nullptr otherwise. `FindIfOrNone` returns a copy of the
element in the range if it's found, and `T::None` (for a range of
elements of type `T`) otherwise. `Contains` returns a bool indicating
whether the element in the range is found.

These functions replace `llvm::find()` and `llvm::find_if()` when you
want a single answer back instead of an iterator. This avoids the need
to check against `end()`, allowing the return condition to be tested as
a standard bool.

We replace uses of `find()` and `find_if()` that did not require an
iterator with these new helpers.

Note that the return type of `FindIfOrNull` is a pointer since we can
not write `optional<T&>`, which must be tested for null. If the null
check is omitted, UB occurs and the resulting code may end up with an
incorrect pointer (https://crbug.com/40153300) into the range (or
elsewhere), rather than a null dereference. And this would be very
confusing to debug. Hopefully debug builds and sanitizers keep this from
being an issue we sink a bunch of time into debugging.
This commit is contained in:
Dana Jansens
2025-04-18 14:17:48 +00:00
committed by GitHub
parent 55705aaef8
commit 9a6c74f0cd
11 changed files with 207 additions and 17 deletions
+1
View File
@@ -43,6 +43,7 @@ cc_library(
"//common:check",
"//common:error",
"//common:exe_path",
"//common:find",
"//common:init_llvm",
"//common:ostream",
"//common:raw_string_ostream",
+6 -6
View File
@@ -11,6 +11,7 @@
#include "common/check.h"
#include "common/error.h"
#include "common/find.h"
#include "common/raw_string_ostream.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/JSON.h"
@@ -132,14 +133,13 @@ static auto AutoFillDidOpenParams(llvm::json::Object* params,
}
CARBON_ASSIGN_OR_RETURN(auto file_path, ExtractFilePathFromUri(*uri));
const auto* split_it =
llvm::find_if(splits, [&](const TestFile::Split& split) {
return split.filename == file_path;
});
if (split_it == splits.end()) {
const auto* split = FindIfOrNull(splits, [&](const TestFile::Split& split) {
return split.filename == file_path;
});
if (!split) {
return ErrorBuilder() << "No split found for uri: " << *uri;
}
attr_it->second = split_it->content;
attr_it->second = split->content;
return Success();
}