[llvm] 21a3447 - [Support] Add llvm::transformOptional
Kazu Hirata via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 14 14:51:11 PST 2022
Author: Kazu Hirata
Date: 2022-12-14T14:51:05-08:00
New Revision: 21a3447564735833909b14b681454997991f35f8
URL: https://github.com/llvm/llvm-project/commit/21a3447564735833909b14b681454997991f35f8
DIFF: https://github.com/llvm/llvm-project/commit/21a3447564735833909b14b681454997991f35f8.diff
LOG: [Support] Add llvm::transformOptional
llvm::Optional<T> has transform, which is equivalent to
std::optional<T>::transform. The problem is that
std::optional<T>::transform won't be available until C++23, implying
that we probably cannot use it in our codebase untli 2028 or so. We
certainly don't want to keep llvm::Optional just for transform.
This patch adds llvm::transformOptional to STLForwardCompat.h so that
we can use transform during the migration to std::optional and beyond.
I've shamelessly borrowed the implementation and test from
llvm/include/llvm/ADT/Optional.h and
llvm/unittests/ADT/OptionalTest.cpp respectively.
This is part of an effort to migrate from llvm::Optional to
std::optional:
https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
Differential Revision: https://reviews.llvm.org/D139779
Added:
Modified:
llvm/include/llvm/ADT/STLForwardCompat.h
llvm/unittests/ADT/STLForwardCompatTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h
index 117285dab9b61..539e825470418 100644
--- a/llvm/include/llvm/ADT/STLForwardCompat.h
+++ b/llvm/include/llvm/ADT/STLForwardCompat.h
@@ -17,6 +17,8 @@
#ifndef LLVM_ADT_STLFORWARDCOMPAT_H
#define LLVM_ADT_STLFORWARDCOMPAT_H
+#include "llvm/ADT/Optional.h"
+#include <optional>
#include <type_traits>
namespace llvm {
@@ -35,6 +37,50 @@ template <typename T>
using remove_cvref_t // NOLINT(readability-identifier-naming)
= typename llvm::remove_cvref<T>::type;
+//===----------------------------------------------------------------------===//
+// Features from C++23
+//===----------------------------------------------------------------------===//
+
+// TODO: Remove this in favor of std::optional<T>::transform once we switch to
+// C++23.
+template <typename T, typename Function>
+auto transformOptional(const std::optional<T> &O, const Function &F)
+ -> std::optional<decltype(F(O.value()))> {
+ if (O)
+ return F(O.value());
+ return std::nullopt;
+}
+
+// TODO: Remove this in favor of std::optional<T>::transform once we switch to
+// C++23.
+template <typename T, typename Function>
+auto transformOptional(std::optional<T> &&O, const Function &F)
+ -> std::optional<decltype(F(std::move(O).value()))> {
+ if (O)
+ return F(std::move(O).value());
+ return std::nullopt;
+}
+
+// TODO: Remove this once the migration from llvm::Optional to std::optional is
+// complete.
+template <typename T, typename Function>
+auto transformOptional(const Optional<T> &O, const Function &F)
+ -> Optional<decltype(F(O.value()))> {
+ if (O)
+ return F(O.value());
+ return std::nullopt;
+}
+
+// TODO: Remove this once the migration from llvm::Optional to std::optional is
+// complete.
+template <typename T, typename Function>
+auto transformOptional(Optional<T> &&O, const Function &F)
+ -> Optional<decltype(F(std::move(O).value()))> {
+ if (O)
+ return F(std::move(O).value());
+ return std::nullopt;
+}
+
} // namespace llvm
#endif // LLVM_ADT_STLFORWARDCOMPAT_H
diff --git a/llvm/unittests/ADT/STLForwardCompatTest.cpp b/llvm/unittests/ADT/STLForwardCompatTest.cpp
index 33c261b79a440..04770b1095df9 100644
--- a/llvm/unittests/ADT/STLForwardCompatTest.cpp
+++ b/llvm/unittests/ADT/STLForwardCompatTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLForwardCompat.h"
+#include "MoveOnly.h"
#include "gtest/gtest.h"
namespace {
@@ -44,4 +45,76 @@ TYPED_TEST(STLForwardCompatRemoveCVRefTest, RemoveCVRefT) {
llvm::remove_cvref_t<From>>::value));
}
+TEST(TransformTest, TransformStd) {
+ std::optional<int> A;
+
+ std::optional<int> B = llvm::transformOptional(A, [&](int N) { return N + 1; });
+ EXPECT_FALSE(B.has_value());
+
+ A = 3;
+ std::optional<int> C = llvm::transformOptional(A, [&](int N) { return N + 1; });
+ EXPECT_TRUE(C.has_value());
+ EXPECT_EQ(4, C.value());
+}
+
+TEST(TransformTest, MoveTransformStd) {
+ using llvm::MoveOnly;
+
+ std::optional<MoveOnly> A;
+
+ MoveOnly::ResetCounts();
+ std::optional<int> B = llvm::transformOptional(
+ std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+ EXPECT_FALSE(B.has_value());
+ EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+ EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+ EXPECT_EQ(0u, MoveOnly::Destructions);
+
+ A = MoveOnly(5);
+ MoveOnly::ResetCounts();
+ std::optional<int> C = llvm::transformOptional(
+ std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+ EXPECT_TRUE(C.has_value());
+ EXPECT_EQ(7, C.value());
+ EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+ EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+ EXPECT_EQ(0u, MoveOnly::Destructions);
+}
+
+TEST(TransformTest, TransformLlvm) {
+ llvm::Optional<int> A;
+
+ llvm::Optional<int> B = llvm::transformOptional(A, [&](int N) { return N + 1; });
+ EXPECT_FALSE(B.has_value());
+
+ A = 3;
+ llvm::Optional<int> C = llvm::transformOptional(A, [&](int N) { return N + 1; });
+ EXPECT_TRUE(C.has_value());
+ EXPECT_EQ(4, C.value());
+}
+
+TEST(TransformTest, MoveTransformLlvm) {
+ using llvm::MoveOnly;
+
+ llvm::Optional<MoveOnly> A;
+
+ MoveOnly::ResetCounts();
+ llvm::Optional<int> B = llvm::transformOptional(
+ std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+ EXPECT_FALSE(B.has_value());
+ EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+ EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+ EXPECT_EQ(0u, MoveOnly::Destructions);
+
+ A = MoveOnly(5);
+ MoveOnly::ResetCounts();
+ llvm::Optional<int> C = llvm::transformOptional(
+ std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+ EXPECT_TRUE(C.has_value());
+ EXPECT_EQ(7, C.value());
+ EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+ EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+ EXPECT_EQ(0u, MoveOnly::Destructions);
+}
+
} // namespace
More information about the llvm-commits
mailing list