[llvm] [orc-rt] Add bind_front, a pre-c++-20 std::bind_front substitute. (PR #155557)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 26 23:01:00 PDT 2025
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/155557
This can be used until the ORC runtime is able to move to c++-20.
Also adds a CommonTestUtils header with a utility class, OpCounter, that counts the number of default constructions, copy constructions and assignments, move constructions and assignments, and destructions. This is used to test that orc_rt::bind_front doesn't introduce unnecessary copies / moves.
>From d702705674b9c433d61b6169f2a88b2f539a8e14 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Wed, 27 Aug 2025 15:52:29 +1000
Subject: [PATCH] [orc-rt] Add bind_front, a pre-c++-20 std::bind_front
substitute.
This can be used until the ORC runtime is able to move to c++-20.
Also adds a CommonTestUtils header with a utility class, OpCounter, that counts
the number of default constructions, copy constructions and assignments, move
constructions and assignments, and destructions. This is used to test that
orc_rt::bind_front doesn't introduce unnecessary copies / moves.
---
orc-rt/include/CMakeLists.txt | 1 +
orc-rt/include/orc-rt/bind.h | 56 ++++++++++++++++++
orc-rt/unittests/CMakeLists.txt | 2 +
orc-rt/unittests/CommonTestUtils.cpp | 20 +++++++
orc-rt/unittests/CommonTestUtils.h | 60 ++++++++++++++++++++
orc-rt/unittests/bind-test.cpp | 85 ++++++++++++++++++++++++++++
6 files changed, 224 insertions(+)
create mode 100644 orc-rt/include/orc-rt/bind.h
create mode 100644 orc-rt/unittests/CommonTestUtils.cpp
create mode 100644 orc-rt/unittests/CommonTestUtils.h
create mode 100644 orc-rt/unittests/bind-test.cpp
diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index 61834f765fc8c..a270fd7c06c73 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -12,6 +12,7 @@ set(ORC_RT_HEADERS
orc-rt/RTTI.h
orc-rt/WrapperFunctionResult.h
orc-rt/SimplePackedSerialization.h
+ orc-rt/bind.h
orc-rt/bit.h
orc-rt/move_only_function.h
orc-rt/span.h
diff --git a/orc-rt/include/orc-rt/bind.h b/orc-rt/include/orc-rt/bind.h
new file mode 100644
index 0000000000000..ca1f20d1b5b3d
--- /dev/null
+++ b/orc-rt/include/orc-rt/bind.h
@@ -0,0 +1,56 @@
+//===---- bind.h - Substitute for future STL bind_front APIs ----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Substitute for STL bind* APIs that aren't available to the ORC runtime yet.
+//
+// TODO: Replace all uses once the respective APIs are available.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_BIND_H
+#define ORC_RT_BIND_H
+
+#include <tuple>
+#include <type_traits>
+
+namespace orc_rt {
+namespace detail {
+
+template <typename Fn, typename... BoundArgTs> class BoundFn {
+private:
+ template <size_t... Is, typename... ArgTs>
+ auto callExpandingBound(std::index_sequence<Is...>, ArgTs &&...Args) {
+ return F(std::get<Is>(BoundArgs)..., std::move(Args)...);
+ }
+
+public:
+ BoundFn(Fn &&F, BoundArgTs &&...BoundArgs)
+ : F(std::move(F)), BoundArgs(std::forward<BoundArgTs>(BoundArgs)...) {}
+
+ template <typename... ArgTs> auto operator()(ArgTs &&...Args) {
+ return callExpandingBound(std::index_sequence_for<BoundArgTs...>(),
+ std::forward<ArgTs>(Args)...);
+ }
+
+private:
+ std::decay_t<Fn> F;
+ std::tuple<std::decay_t<BoundArgTs>...> BoundArgs;
+};
+
+} // namespace detail
+
+template <typename Fn, typename... BoundArgTs>
+detail::BoundFn<Fn, BoundArgTs...> bind_front(Fn &&F,
+ BoundArgTs &&...BoundArgs) {
+ return detail::BoundFn<Fn, BoundArgTs...>(
+ std::forward<Fn>(F), std::forward<BoundArgTs>(BoundArgs)...);
+}
+
+} // namespace orc_rt
+
+#endif // ORC_RT_BIND_H
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 0fd0d09d10aa5..39d9223f5b0eb 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -13,6 +13,7 @@ endfunction()
add_orc_rt_unittest(CoreTests
BitmaskEnumTest.cpp
+ CommonTestUtils.cpp
ErrorTest.cpp
ExecutorAddressTest.cpp
IntervalMapTest.cpp
@@ -21,6 +22,7 @@ add_orc_rt_unittest(CoreTests
RTTITest.cpp
SimplePackedSerializationTest.cpp
WrapperFunctionResultTest.cpp
+ bind-test.cpp
bit-test.cpp
move_only_function-test.cpp
span-test.cpp
diff --git a/orc-rt/unittests/CommonTestUtils.cpp b/orc-rt/unittests/CommonTestUtils.cpp
new file mode 100644
index 0000000000000..d9f9433d167fd
--- /dev/null
+++ b/orc-rt/unittests/CommonTestUtils.cpp
@@ -0,0 +1,20 @@
+//===- CommonTestUtils.cpp ------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Common test utilities.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommonTestUtils.h"
+
+size_t OpCounter::DefaultConstructions = 0;
+size_t OpCounter::CopyConstructions = 0;
+size_t OpCounter::CopyAssignments = 0;
+size_t OpCounter::MoveConstructions = 0;
+size_t OpCounter::MoveAssignments = 0;
+size_t OpCounter::Destructions = 0;
diff --git a/orc-rt/unittests/CommonTestUtils.h b/orc-rt/unittests/CommonTestUtils.h
new file mode 100644
index 0000000000000..5ff2c8e6e8989
--- /dev/null
+++ b/orc-rt/unittests/CommonTestUtils.h
@@ -0,0 +1,60 @@
+//===- CommonTestUtils.h --------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_UNITTEST_COMMONTESTUTILS_H
+#define ORC_RT_UNITTEST_COMMONTESTUTILS_H
+
+#include <cstddef>
+
+class OpCounter {
+public:
+ OpCounter() { ++DefaultConstructions; }
+ OpCounter(const OpCounter &Other) { ++CopyConstructions; }
+ OpCounter &operator=(const OpCounter &Other) {
+ ++CopyAssignments;
+ return *this;
+ }
+ OpCounter(OpCounter &&Other) { ++MoveConstructions; }
+ OpCounter &operator=(OpCounter &&Other) {
+ ++MoveAssignments;
+ return *this;
+ }
+ ~OpCounter() { ++Destructions; }
+
+ static size_t defaultConstructions() { return DefaultConstructions; }
+ static size_t copyConstructions() { return CopyConstructions; }
+ static size_t copyAssignments() { return CopyAssignments; }
+ static size_t copies() { return copyConstructions() + copyAssignments(); }
+ static size_t moveConstructions() { return MoveConstructions; }
+ static size_t moveAssignments() { return MoveAssignments; }
+ static size_t moves() { return moveConstructions() + moveAssignments(); }
+ static size_t destructions() { return Destructions; }
+
+ static bool destructionsMatch() {
+ return destructions() == defaultConstructions() + copies() + moves();
+ }
+
+ static void reset() {
+ DefaultConstructions = 0;
+ CopyConstructions = 0;
+ CopyAssignments = 0;
+ MoveConstructions = 0;
+ MoveAssignments = 0;
+ Destructions = 0;
+ }
+
+private:
+ static size_t DefaultConstructions;
+ static size_t CopyConstructions;
+ static size_t CopyAssignments;
+ static size_t MoveConstructions;
+ static size_t MoveAssignments;
+ static size_t Destructions;
+};
+
+#endif // ORC_RT_UNITTEST_COMMONTESTUTILS_H
diff --git a/orc-rt/unittests/bind-test.cpp b/orc-rt/unittests/bind-test.cpp
new file mode 100644
index 0000000000000..26b868aaef77b
--- /dev/null
+++ b/orc-rt/unittests/bind-test.cpp
@@ -0,0 +1,85 @@
+//===- bind-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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for orc-rt's bind-test.h APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommonTestUtils.h"
+#include "orc-rt/bind.h"
+#include "orc-rt/move_only_function.h"
+#include "gtest/gtest.h"
+
+using namespace orc_rt;
+
+static void voidVoid(void) {}
+
+TEST(BindTest, VoidVoid) {
+ auto B = bind_front(voidVoid);
+ B();
+}
+
+static int addInts(int X, int Y) { return X + Y; }
+
+TEST(BindTest, SimpleBind) {
+ auto Add1 = bind_front(addInts, 1);
+ EXPECT_EQ(Add1(2), 3);
+}
+
+TEST(BindTest, NoBoundArguments) {
+ auto Add = bind_front(addInts);
+ EXPECT_EQ(Add(1, 2), 3);
+}
+
+TEST(BindTest, NoFreeArguments) {
+ auto Add1And2 = bind_front(addInts, 1, 2);
+ EXPECT_EQ(Add1And2(), 3);
+}
+
+TEST(BindTest, LambdaCapture) {
+ auto Add1 = bind_front([](int X, int Y) { return X + Y; }, 1);
+ EXPECT_EQ(Add1(2), 3);
+}
+
+TEST(BindTest, MinimalMoves) {
+ OpCounter::reset();
+ {
+ auto B = bind_front([](OpCounter &O, int) {}, OpCounter());
+ B(0);
+ }
+ EXPECT_EQ(OpCounter::defaultConstructions(), 1U);
+ EXPECT_EQ(OpCounter::copies(), 0U);
+ EXPECT_EQ(OpCounter::moves(), 1U);
+ EXPECT_EQ(OpCounter::destructions(), 2U);
+}
+
+TEST(BindTest, MinimalCopies) {
+ OpCounter::reset();
+ {
+ OpCounter O;
+ auto B = bind_front([](OpCounter &O, int) {}, O);
+ B(0);
+ }
+ EXPECT_EQ(OpCounter::defaultConstructions(), 1U);
+ EXPECT_EQ(OpCounter::copies(), 1U);
+ EXPECT_EQ(OpCounter::moves(), 0U);
+ EXPECT_EQ(OpCounter::destructions(), 2U);
+}
+
+static int increment(int N) { return N + 1; }
+
+TEST(BindTest, BindFunction) {
+ auto Op = bind_front([](int op(int), int arg) { return op(arg); }, increment);
+ EXPECT_EQ(Op(1), 2);
+}
+
+TEST(BindTest, BindTo_move_only_function) {
+ move_only_function<int(int, int)> Add = [](int X, int Y) { return X + Y; };
+ auto Add1 = bind_front(std::move(Add), 1);
+ EXPECT_EQ(Add1(2), 3);
+}
More information about the llvm-commits
mailing list