Skip to content

Commit 2a47485

Browse files
[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
1 parent 83fa975 commit 2a47485

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
@@ -342,6 +342,12 @@ template <typename T> class Optional {
342342

343343
/// Apply a function to the value if present; otherwise return None.
344344
template <class Function>
345+
auto transform(const Function &F) const & -> Optional<decltype(F(value()))> {
346+
if (*this)
347+
return F(value());
348+
return None;
349+
}
350+
template <class Function>
345351
auto map(const Function &F) const & -> Optional<decltype(F(value()))> {
346352
if (*this)
347353
return F(value());
@@ -365,6 +371,13 @@ template <typename T> class Optional {
365371

366372
/// Apply a function to the value if present; otherwise return None.
367373
template <class Function>
374+
auto transform(
375+
const Function &F) && -> Optional<decltype(F(std::move(*this).value()))> {
376+
if (*this)
377+
return F(std::move(*this).value());
378+
return None;
379+
}
380+
template <class Function>
368381
auto map(const Function &F)
369382
&& -> Optional<decltype(F(std::move(*this).value()))> {
370383
if (*this)

llvm/unittests/ADT/OptionalTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,40 @@ TEST(OptionalTest, MoveValueOr) {
603603
EXPECT_EQ(2u, MoveOnly::Destructions);
604604
}
605605

606+
TEST(OptionalTest, Transform) {
607+
Optional<int> A;
608+
609+
Optional<int> B = A.transform([&](int N) { return N + 1; });
610+
EXPECT_FALSE(B.has_value());
611+
612+
A = 3;
613+
Optional<int> C = A.transform([&](int N) { return N + 1; });
614+
EXPECT_TRUE(C.has_value());
615+
EXPECT_EQ(4, C.value());
616+
}
617+
618+
TEST(OptionalTest, MoveTransform) {
619+
Optional<MoveOnly> A;
620+
621+
MoveOnly::ResetCounts();
622+
Optional<int> B =
623+
std::move(A).transform([&](const MoveOnly &M) { return M.val + 2; });
624+
EXPECT_FALSE(B.has_value());
625+
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
626+
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
627+
EXPECT_EQ(0u, MoveOnly::Destructions);
628+
629+
A = MoveOnly(5);
630+
MoveOnly::ResetCounts();
631+
Optional<int> C =
632+
std::move(A).transform([&](const MoveOnly &M) { return M.val + 2; });
633+
EXPECT_TRUE(C.has_value());
634+
EXPECT_EQ(7, C.value());
635+
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
636+
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
637+
EXPECT_EQ(0u, MoveOnly::Destructions);
638+
}
639+
606640
struct EqualTo {
607641
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
608642
return X == Y;

0 commit comments

Comments
 (0)