[llvm] [orc-rt] Rename unique_function to move_only_function. (PR #154888)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 21 22:15:41 PDT 2025
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/154888
This will allow the ORC runtime and its clients to easily adopt the c++-23 std::move_only_function type.
>From 3f09d8db5bf278cfeadb3ff0d4fd083eef296a00 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Fri, 22 Aug 2025 14:34:45 +1000
Subject: [PATCH] [orc-rt] Rename unique_function to move_only_function to
align with c++-23 API.
This will allow the ORC runtime and its clients to easily adopt the c++-23
std::move_only_function type.
---
orc-rt/include/CMakeLists.txt | 2 +-
orc-rt/include/orc-rt/move_only_function.h | 84 +++++++++++++++++++
orc-rt/include/orc-rt/unique-function.h | 80 ------------------
orc-rt/unittests/CMakeLists.txt | 2 +-
...n-test.cpp => move_only_function-test.cpp} | 60 ++++++-------
5 files changed, 117 insertions(+), 111 deletions(-)
create mode 100644 orc-rt/include/orc-rt/move_only_function.h
delete mode 100644 orc-rt/include/orc-rt/unique-function.h
rename orc-rt/unittests/{unique-function-test.cpp => move_only_function-test.cpp} (65%)
diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index 33545547e17d7..ed90a7a45e2fa 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -5,8 +5,8 @@ set(ORC_RT_HEADERS
orc-rt/Error.h
orc-rt/Math.h
orc-rt/RTTI.h
+ orc-rt/move_only_function.h
orc-rt/span.h
- orc-rt/unique-function.h
)
# TODO: Switch to filesets when we move to cmake-3.23.
diff --git a/orc-rt/include/orc-rt/move_only_function.h b/orc-rt/include/orc-rt/move_only_function.h
new file mode 100644
index 0000000000000..d37801b4a97af
--- /dev/null
+++ b/orc-rt/include/orc-rt/move_only_function.h
@@ -0,0 +1,84 @@
+//===-- move_only_function.h - moveable, type-erasing function --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// A substitute for std::move_only_function that can be used until the ORC
+/// runtime is allowed to assume c++-23.
+///
+/// TODO: Replace all uses with std::move_only_function once we can assume
+/// c++-23.
+///
+/// TODO: Re-implement using techniques from LLVM's unique_function
+/// (llvm/include/llvm/ADT/FunctionExtras.h), which uses some extra
+/// inline storage to avoid heap allocations for small objects. This
+/// would require first porting some other LLVM utilities like
+/// PointerIntPair, PointerUnion, and PointerLikeTypeTraits. (These are
+/// likely to be independently useful in the orc runtime, so porting will
+/// have additional benefits).
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_MOVE_ONLY_FUNCTION_H
+#define ORC_RT_MOVE_ONLY_FUNCTION_H
+
+#include <memory>
+
+namespace orc_rt {
+
+namespace move_only_function_detail {
+
+template <typename RetT, typename... ArgTs> class Callable {
+public:
+ virtual ~Callable() = default;
+ virtual RetT call(ArgTs &&...Args) = 0;
+};
+
+template <typename CallableT, typename RetT, typename... ArgTs>
+class CallableImpl : public Callable<RetT, ArgTs...> {
+public:
+ CallableImpl(CallableT &&Callable) : Callable(std::move(Callable)) {}
+ RetT call(ArgTs &&...Args) override {
+ return Callable(std::forward<ArgTs>(Args)...);
+ }
+
+private:
+ CallableT Callable;
+};
+
+} // namespace move_only_function_detail
+
+template <typename FnT> class move_only_function;
+
+template <typename RetT, typename... ArgTs>
+class move_only_function<RetT(ArgTs...)> {
+public:
+ move_only_function() = default;
+ move_only_function(std::nullptr_t) {}
+ move_only_function(move_only_function &&) = default;
+ move_only_function(const move_only_function &&) = delete;
+ move_only_function &operator=(move_only_function &&) = default;
+ move_only_function &operator=(const move_only_function &&) = delete;
+
+ template <typename CallableT>
+ move_only_function(CallableT &&Callable)
+ : C(std::make_unique<
+ move_only_function_detail::CallableImpl<CallableT, RetT, ArgTs...>>(
+ std::forward<CallableT>(Callable))) {}
+
+ RetT operator()(ArgTs... Params) {
+ return C->call(std::forward<ArgTs>(Params)...);
+ }
+
+ explicit operator bool() const { return !!C; }
+
+private:
+ std::unique_ptr<move_only_function_detail::Callable<RetT, ArgTs...>> C;
+};
+
+} // namespace orc_rt
+
+#endif // ORC_RT_MOVE_ONLY_FUNCTION_H
diff --git a/orc-rt/include/orc-rt/unique-function.h b/orc-rt/include/orc-rt/unique-function.h
deleted file mode 100644
index 467476c7623cd..0000000000000
--- a/orc-rt/include/orc-rt/unique-function.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//===----- unique_function.h - moveable type-erasing function ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// unique_function works like std::function, but supports move-only callable
-/// objects.
-///
-/// TODO: Use LLVM's unique_function (llvm/include/llvm/ADT/FunctionExtras.h),
-/// which uses some extra inline storage to avoid heap allocations for
-/// small objects. Using LLVM's unique_function will require first
-/// porting some other utilities like PointerIntPair, PointerUnion, and
-/// PointerLikeTypeTraits. (These are likely to be independently useful
-/// in the orc runtime, so porting will have additional benefits).
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef ORC_RT_UNIQUE_FUNCTION_H
-#define ORC_RT_UNIQUE_FUNCTION_H
-
-#include <memory>
-
-namespace orc_rt {
-
-namespace unique_function_detail {
-
-template <typename RetT, typename... ArgTs> class Callable {
-public:
- virtual ~Callable() = default;
- virtual RetT call(ArgTs &&...Args) = 0;
-};
-
-template <typename CallableT, typename RetT, typename... ArgTs>
-class CallableImpl : public Callable<RetT, ArgTs...> {
-public:
- CallableImpl(CallableT &&Callable) : Callable(std::move(Callable)) {}
- RetT call(ArgTs &&...Args) override {
- return Callable(std::forward<ArgTs>(Args)...);
- }
-
-private:
- CallableT Callable;
-};
-
-} // namespace unique_function_detail
-
-template <typename FnT> class unique_function;
-
-template <typename RetT, typename... ArgTs>
-class unique_function<RetT(ArgTs...)> {
-public:
- unique_function() = default;
- unique_function(std::nullptr_t) {}
- unique_function(unique_function &&) = default;
- unique_function(const unique_function &&) = delete;
- unique_function &operator=(unique_function &&) = default;
- unique_function &operator=(const unique_function &&) = delete;
-
- template <typename CallableT>
- unique_function(CallableT &&Callable)
- : C(std::make_unique<
- unique_function_detail::CallableImpl<CallableT, RetT, ArgTs...>>(
- std::forward<CallableT>(Callable))) {}
-
- RetT operator()(ArgTs... Params) {
- return C->call(std::forward<ArgTs>(Params)...);
- }
-
- explicit operator bool() const { return !!C; }
-
-private:
- std::unique_ptr<unique_function_detail::Callable<RetT, ArgTs...>> C;
-};
-
-} // namespace orc_rt
-
-#endif // ORC_RT_UNIQUE_FUNCTION_H
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 09696da982ed2..6a1f5d6f8bce2 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -16,8 +16,8 @@ add_orc_rt_unittest(CoreTests
ErrorTest.cpp
MathTest.cpp
RTTITest.cpp
+ move_only_function-test.cpp
span-test.cpp
- unique-function-test.cpp
DISABLE_LLVM_LINK_LLVM_DYLIB
)
target_link_libraries(CoreTests PRIVATE orc-rt-executor)
diff --git a/orc-rt/unittests/unique-function-test.cpp b/orc-rt/unittests/move_only_function-test.cpp
similarity index 65%
rename from orc-rt/unittests/unique-function-test.cpp
rename to orc-rt/unittests/move_only_function-test.cpp
index 03cb924a83673..95194edc69f6d 100644
--- a/orc-rt/unittests/unique-function-test.cpp
+++ b/orc-rt/unittests/move_only_function-test.cpp
@@ -1,4 +1,4 @@
-//===-- unique-function-test.cpp ------------------------------------------===//
+//===- move_only_function-test.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,41 +6,41 @@
//
//===----------------------------------------------------------------------===//
-#include "orc-rt/unique-function.h"
+#include "orc-rt/move_only_function.h"
#include "gtest/gtest.h"
using namespace orc_rt;
-TEST(UniqueFunctionTest, Basic) {
- unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
+TEST(MoveOnlyFunctionTest, Basic) {
+ move_only_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
EXPECT_EQ(Sum(1, 2), 3);
- unique_function<int(int, int)> Sum2 = std::move(Sum);
+ move_only_function<int(int, int)> Sum2 = std::move(Sum);
EXPECT_EQ(Sum2(1, 2), 3);
- unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
+ move_only_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
Sum2 = std::move(Sum3);
EXPECT_EQ(Sum2(1, 2), 3);
- Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
+ Sum2 = move_only_function<int(int, int)>([](int A, int B) { return A + B; });
EXPECT_EQ(Sum2(1, 2), 3);
// Explicit self-move test.
*&Sum2 = std::move(Sum2);
EXPECT_EQ(Sum2(1, 2), 3);
- Sum2 = unique_function<int(int, int)>();
+ Sum2 = move_only_function<int(int, int)>();
EXPECT_FALSE(Sum2);
// Make sure we can forward through l-value reference parameters.
- unique_function<void(int &)> Inc = [](int &X) { ++X; };
+ move_only_function<void(int &)> Inc = [](int &X) { ++X; };
int X = 42;
Inc(X);
EXPECT_EQ(X, 43);
// Make sure we can forward through r-value reference parameters with
// move-only types.
- unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
+ move_only_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
[](std::unique_ptr<int> &&Ptr) {
int V = *Ptr;
Ptr.reset();
@@ -54,7 +54,7 @@ TEST(UniqueFunctionTest, Basic) {
EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
// Make sure we can pass a move-only type by-value.
- unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
+ move_only_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
[](std::unique_ptr<int> Ptr) {
int V = *Ptr;
Ptr.reset();
@@ -67,50 +67,52 @@ TEST(UniqueFunctionTest, Basic) {
EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
}
-TEST(UniqueFunctionTest, Captures) {
+TEST(MoveOnlyFunctionTest, Captures) {
long A = 1, B = 2, C = 3, D = 4, E = 5;
- unique_function<long()> Tmp;
+ move_only_function<long()> Tmp;
- unique_function<long()> C1 = [A]() { return A; };
+ move_only_function<long()> C1 = [A]() { return A; };
EXPECT_EQ(C1(), 1);
Tmp = std::move(C1);
EXPECT_EQ(Tmp(), 1);
- unique_function<long()> C2 = [A, B]() { return A + B; };
+ move_only_function<long()> C2 = [A, B]() { return A + B; };
EXPECT_EQ(C2(), 3);
Tmp = std::move(C2);
EXPECT_EQ(Tmp(), 3);
- unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
+ move_only_function<long()> C3 = [A, B, C]() { return A + B + C; };
EXPECT_EQ(C3(), 6);
Tmp = std::move(C3);
EXPECT_EQ(Tmp(), 6);
- unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
+ move_only_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
EXPECT_EQ(C4(), 10);
Tmp = std::move(C4);
EXPECT_EQ(Tmp(), 10);
- unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
+ move_only_function<long()> C5 = [A, B, C, D, E]() {
+ return A + B + C + D + E;
+ };
EXPECT_EQ(C5(), 15);
Tmp = std::move(C5);
EXPECT_EQ(Tmp(), 15);
}
-TEST(UniqueFunctionTest, MoveOnly) {
+TEST(MoveOnlyFunctionTest, MoveOnly) {
struct SmallCallable {
std::unique_ptr<int> A = std::make_unique<int>(1);
int operator()(int B) { return *A + B; }
};
- unique_function<int(int)> Small = SmallCallable();
+ move_only_function<int(int)> Small = SmallCallable();
EXPECT_EQ(Small(2), 3);
- unique_function<int(int)> Small2 = std::move(Small);
+ move_only_function<int(int)> Small2 = std::move(Small);
EXPECT_EQ(Small2(2), 3);
}
-TEST(UniqueFunctionTest, CountForwardingCopies) {
+TEST(MoveOnlyFunctionTest, CountForwardingCopies) {
struct CopyCounter {
int &CopyCount;
@@ -120,7 +122,7 @@ TEST(UniqueFunctionTest, CountForwardingCopies) {
}
};
- unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
+ move_only_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
int CopyCount = 0;
ByValF(CopyCounter(CopyCount));
EXPECT_EQ(1, CopyCount);
@@ -134,8 +136,8 @@ TEST(UniqueFunctionTest, CountForwardingCopies) {
// Check that we don't generate a copy at all when we can bind a reference all
// the way down, even if that reference could *in theory* allow copies.
- unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
- };
+ move_only_function<void(const CopyCounter &)> ByRefF =
+ [](const CopyCounter &) {};
CopyCount = 0;
ByRefF(CopyCounter(CopyCount));
EXPECT_EQ(0, CopyCount);
@@ -153,17 +155,17 @@ TEST(UniqueFunctionTest, CountForwardingCopies) {
Uncopyable() = default;
Uncopyable(const Uncopyable &) = delete;
};
- unique_function<void(const Uncopyable &)> UncopyableF =
+ move_only_function<void(const Uncopyable &)> UncopyableF =
[](const Uncopyable &) {};
UncopyableF(Uncopyable());
Uncopyable X;
UncopyableF(X);
}
-TEST(UniqueFunctionTest, BooleanConversion) {
- unique_function<void()> D;
+TEST(MoveOnlyFunctionTest, BooleanConversion) {
+ move_only_function<void()> D;
EXPECT_FALSE(D);
- unique_function<void()> F = []() {};
+ move_only_function<void()> F = []() {};
EXPECT_TRUE(F);
}
More information about the llvm-commits
mailing list