mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:30:12 +01:00
`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.
76 lines
2.1 KiB
C++
76 lines
2.1 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "common/find.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <vector>
|
|
|
|
namespace Carbon {
|
|
namespace {
|
|
|
|
struct NoneType {
|
|
static const NoneType None;
|
|
int i;
|
|
|
|
friend auto operator==(NoneType, NoneType) -> bool = default;
|
|
};
|
|
|
|
const NoneType NoneType::None = {.i = -1};
|
|
|
|
TEST(FindTest, ReturnType) {
|
|
const std::vector<int> c;
|
|
std::vector<int> m;
|
|
|
|
auto pred = [](int) { return true; };
|
|
static_assert(std::same_as<decltype(FindIfOrNull(c, pred)), const int*>);
|
|
static_assert(std::same_as<decltype(FindIfOrNull(m, pred)), int*>);
|
|
}
|
|
|
|
TEST(FindTest, FindIfOrNull) {
|
|
auto make_pred = [](int query) {
|
|
return [=](int elem) { return query == elem; };
|
|
};
|
|
|
|
std::vector<int> empty;
|
|
EXPECT_EQ(FindIfOrNull(empty, make_pred(0)), nullptr);
|
|
|
|
std::vector<int> range = {1, 2};
|
|
EXPECT_EQ(FindIfOrNull(range, make_pred(0)), nullptr);
|
|
// NOLINTNEXTLINE(readability-container-data-pointer)
|
|
EXPECT_EQ(FindIfOrNull(range, make_pred(1)), &range[0]);
|
|
EXPECT_EQ(FindIfOrNull(range, make_pred(2)), &range[1]);
|
|
EXPECT_EQ(FindIfOrNull(range, make_pred(3)), nullptr);
|
|
}
|
|
|
|
TEST(FindTest, FindIfOrNone) {
|
|
auto make_pred = [](NoneType query) {
|
|
return [=](NoneType elem) { return query == elem; };
|
|
};
|
|
|
|
std::vector<NoneType> empty;
|
|
EXPECT_EQ(FindIfOrNone(empty, make_pred(NoneType{0})).i, -1);
|
|
|
|
std::vector<NoneType> range = {NoneType{1}, NoneType{2}};
|
|
EXPECT_EQ(FindIfOrNone(range, make_pred(NoneType{0})).i, -1);
|
|
EXPECT_EQ(FindIfOrNone(range, make_pred(NoneType{1})).i, 1);
|
|
EXPECT_EQ(FindIfOrNone(range, make_pred(NoneType{2})).i, 2);
|
|
EXPECT_EQ(FindIfOrNone(range, make_pred(NoneType{3})).i, -1);
|
|
}
|
|
|
|
TEST(FindTest, Contains) {
|
|
std::vector<int> empty;
|
|
EXPECT_EQ(Contains(empty, 0), false);
|
|
|
|
std::vector<int> range = {1, 2};
|
|
EXPECT_EQ(Contains(range, 0), false);
|
|
EXPECT_EQ(Contains(range, 1), true);
|
|
EXPECT_EQ(Contains(range, 2), true);
|
|
EXPECT_EQ(Contains(range, 3), false);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace Carbon
|