[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