Skip to content

Commit 5991caa

Browse files
kazutakahiratabenlangmuir
authored andcommitted
[ADT] Implement Optional::transform
This patch implements Optional::transform for consistency with std::optional::transform in C++23. Note that the new function is identical to Optional::map. My plan is to deprecate Optional::map after migrating all of its uses to Optional::transform. Differential Revision: https://reviews.llvm.org/D131829 (cherry picked from commit 2a47485)
1 parent 9f54baa commit 5991caa

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

llvm/include/llvm/ADT/Optional.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,12 @@ template <typename T> class Optional {
324324

325325
/// Apply a function to the value if present; otherwise return None.
326326
template <class Function>
327+
auto transform(const Function &F) const & -> Optional<decltype(F(value()))> {
328+
if (*this)
329+
return F(value());
330+
return None;
331+
}
332+
template <class Function>
327333
auto map(const Function &F) const & -> Optional<decltype(F(value()))> {
328334
if (*this)
329335
return F(value());
@@ -343,6 +349,13 @@ template <typename T> class Optional {
343349

344350
/// Apply a function to the value if present; otherwise return None.
345351
template <class Function>
352+
auto transform(
353+
const Function &F) && -> Optional<decltype(F(std::move(*this).value()))> {
354+
if (*this)
355+
return F(std::move(*this).value());
356+
return None;
357+
}
358+
template <class Function>
346359
auto map(const Function &F)
347360
&& -> Optional<decltype(F(std::move(*this).value()))> {
348361
if (*this)

llvm/unittests/ADT/OptionalTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,40 @@ TEST(OptionalTest, MoveGetValueOr) {
622622
EXPECT_EQ(2u, MoveOnly::Destructions);
623623
}
624624

625+
TEST(OptionalTest, Transform) {
626+
Optional<int> A;
627+
628+
Optional<int> B = A.transform([&](int N) { return N + 1; });
629+
EXPECT_FALSE(B.has_value());
630+
631+
A = 3;
632+
Optional<int> C = A.transform([&](int N) { return N + 1; });
633+
EXPECT_TRUE(C.has_value());
634+
EXPECT_EQ(4, C.value());
635+
}
636+
637+
TEST(OptionalTest, MoveTransform) {
638+
Optional<MoveOnly> A;
639+
640+
MoveOnly::ResetCounts();
641+
Optional<int> B =
642+
std::move(A).transform([&](const MoveOnly &M) { return M.val + 2; });
643+
EXPECT_FALSE(B.has_value());
644+
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
645+
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
646+
EXPECT_EQ(0u, MoveOnly::Destructions);
647+
648+
A = MoveOnly(5);
649+
MoveOnly::ResetCounts();
650+
Optional<int> C =
651+
std::move(A).transform([&](const MoveOnly &M) { return M.val + 2; });
652+
EXPECT_TRUE(C.has_value());
653+
EXPECT_EQ(7, C.value());
654+
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
655+
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
656+
EXPECT_EQ(0u, MoveOnly::Destructions);
657+
}
658+
625659
struct EqualTo {
626660
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
627661
return X == Y;

0 commit comments

Comments
 (0)