[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