Skip to content

Commit 61526f5

Browse files
authored
[orc-rt] Add bind_front, a pre-c++-20 std::bind_front substitute. (#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.
1 parent 5e587b1 commit 61526f5

File tree

6 files changed

+224
-0
lines changed

6 files changed

+224
-0
lines changed

orc-rt/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(ORC_RT_HEADERS
1212
orc-rt/RTTI.h
1313
orc-rt/WrapperFunctionResult.h
1414
orc-rt/SimplePackedSerialization.h
15+
orc-rt/bind.h
1516
orc-rt/bit.h
1617
orc-rt/move_only_function.h
1718
orc-rt/span.h

orc-rt/include/orc-rt/bind.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===---- bind.h - Substitute for future STL bind_front APIs ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Substitute for STL bind* APIs that aren't available to the ORC runtime yet.
10+
//
11+
// TODO: Replace all uses once the respective APIs are available.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef ORC_RT_BIND_H
16+
#define ORC_RT_BIND_H
17+
18+
#include <tuple>
19+
#include <type_traits>
20+
21+
namespace orc_rt {
22+
namespace detail {
23+
24+
template <typename Fn, typename... BoundArgTs> class BoundFn {
25+
private:
26+
template <size_t... Is, typename... ArgTs>
27+
auto callExpandingBound(std::index_sequence<Is...>, ArgTs &&...Args) {
28+
return F(std::get<Is>(BoundArgs)..., std::move(Args)...);
29+
}
30+
31+
public:
32+
BoundFn(Fn &&F, BoundArgTs &&...BoundArgs)
33+
: F(std::move(F)), BoundArgs(std::forward<BoundArgTs>(BoundArgs)...) {}
34+
35+
template <typename... ArgTs> auto operator()(ArgTs &&...Args) {
36+
return callExpandingBound(std::index_sequence_for<BoundArgTs...>(),
37+
std::forward<ArgTs>(Args)...);
38+
}
39+
40+
private:
41+
std::decay_t<Fn> F;
42+
std::tuple<std::decay_t<BoundArgTs>...> BoundArgs;
43+
};
44+
45+
} // namespace detail
46+
47+
template <typename Fn, typename... BoundArgTs>
48+
detail::BoundFn<Fn, BoundArgTs...> bind_front(Fn &&F,
49+
BoundArgTs &&...BoundArgs) {
50+
return detail::BoundFn<Fn, BoundArgTs...>(
51+
std::forward<Fn>(F), std::forward<BoundArgTs>(BoundArgs)...);
52+
}
53+
54+
} // namespace orc_rt
55+
56+
#endif // ORC_RT_BIND_H

orc-rt/unittests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ endfunction()
1313

1414
add_orc_rt_unittest(CoreTests
1515
BitmaskEnumTest.cpp
16+
CommonTestUtils.cpp
1617
ErrorTest.cpp
1718
ExecutorAddressTest.cpp
1819
IntervalMapTest.cpp
@@ -21,6 +22,7 @@ add_orc_rt_unittest(CoreTests
2122
RTTITest.cpp
2223
SimplePackedSerializationTest.cpp
2324
WrapperFunctionResultTest.cpp
25+
bind-test.cpp
2426
bit-test.cpp
2527
move_only_function-test.cpp
2628
span-test.cpp
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===- CommonTestUtils.cpp ------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Common test utilities.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "CommonTestUtils.h"
14+
15+
size_t OpCounter::DefaultConstructions = 0;
16+
size_t OpCounter::CopyConstructions = 0;
17+
size_t OpCounter::CopyAssignments = 0;
18+
size_t OpCounter::MoveConstructions = 0;
19+
size_t OpCounter::MoveAssignments = 0;
20+
size_t OpCounter::Destructions = 0;

orc-rt/unittests/CommonTestUtils.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===- CommonTestUtils.h --------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef ORC_RT_UNITTEST_COMMONTESTUTILS_H
10+
#define ORC_RT_UNITTEST_COMMONTESTUTILS_H
11+
12+
#include <cstddef>
13+
14+
class OpCounter {
15+
public:
16+
OpCounter() { ++DefaultConstructions; }
17+
OpCounter(const OpCounter &Other) { ++CopyConstructions; }
18+
OpCounter &operator=(const OpCounter &Other) {
19+
++CopyAssignments;
20+
return *this;
21+
}
22+
OpCounter(OpCounter &&Other) { ++MoveConstructions; }
23+
OpCounter &operator=(OpCounter &&Other) {
24+
++MoveAssignments;
25+
return *this;
26+
}
27+
~OpCounter() { ++Destructions; }
28+
29+
static size_t defaultConstructions() { return DefaultConstructions; }
30+
static size_t copyConstructions() { return CopyConstructions; }
31+
static size_t copyAssignments() { return CopyAssignments; }
32+
static size_t copies() { return copyConstructions() + copyAssignments(); }
33+
static size_t moveConstructions() { return MoveConstructions; }
34+
static size_t moveAssignments() { return MoveAssignments; }
35+
static size_t moves() { return moveConstructions() + moveAssignments(); }
36+
static size_t destructions() { return Destructions; }
37+
38+
static bool destructionsMatch() {
39+
return destructions() == defaultConstructions() + copies() + moves();
40+
}
41+
42+
static void reset() {
43+
DefaultConstructions = 0;
44+
CopyConstructions = 0;
45+
CopyAssignments = 0;
46+
MoveConstructions = 0;
47+
MoveAssignments = 0;
48+
Destructions = 0;
49+
}
50+
51+
private:
52+
static size_t DefaultConstructions;
53+
static size_t CopyConstructions;
54+
static size_t CopyAssignments;
55+
static size_t MoveConstructions;
56+
static size_t MoveAssignments;
57+
static size_t Destructions;
58+
};
59+
60+
#endif // ORC_RT_UNITTEST_COMMONTESTUTILS_H

orc-rt/unittests/bind-test.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//===- bind-test.cpp ------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Tests for orc-rt's bind-test.h APIs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "CommonTestUtils.h"
14+
#include "orc-rt/bind.h"
15+
#include "orc-rt/move_only_function.h"
16+
#include "gtest/gtest.h"
17+
18+
using namespace orc_rt;
19+
20+
static void voidVoid(void) {}
21+
22+
TEST(BindTest, VoidVoid) {
23+
auto B = bind_front(voidVoid);
24+
B();
25+
}
26+
27+
static int addInts(int X, int Y) { return X + Y; }
28+
29+
TEST(BindTest, SimpleBind) {
30+
auto Add1 = bind_front(addInts, 1);
31+
EXPECT_EQ(Add1(2), 3);
32+
}
33+
34+
TEST(BindTest, NoBoundArguments) {
35+
auto Add = bind_front(addInts);
36+
EXPECT_EQ(Add(1, 2), 3);
37+
}
38+
39+
TEST(BindTest, NoFreeArguments) {
40+
auto Add1And2 = bind_front(addInts, 1, 2);
41+
EXPECT_EQ(Add1And2(), 3);
42+
}
43+
44+
TEST(BindTest, LambdaCapture) {
45+
auto Add1 = bind_front([](int X, int Y) { return X + Y; }, 1);
46+
EXPECT_EQ(Add1(2), 3);
47+
}
48+
49+
TEST(BindTest, MinimalMoves) {
50+
OpCounter::reset();
51+
{
52+
auto B = bind_front([](OpCounter &O, int) {}, OpCounter());
53+
B(0);
54+
}
55+
EXPECT_EQ(OpCounter::defaultConstructions(), 1U);
56+
EXPECT_EQ(OpCounter::copies(), 0U);
57+
EXPECT_EQ(OpCounter::moves(), 1U);
58+
EXPECT_EQ(OpCounter::destructions(), 2U);
59+
}
60+
61+
TEST(BindTest, MinimalCopies) {
62+
OpCounter::reset();
63+
{
64+
OpCounter O;
65+
auto B = bind_front([](OpCounter &O, int) {}, O);
66+
B(0);
67+
}
68+
EXPECT_EQ(OpCounter::defaultConstructions(), 1U);
69+
EXPECT_EQ(OpCounter::copies(), 1U);
70+
EXPECT_EQ(OpCounter::moves(), 0U);
71+
EXPECT_EQ(OpCounter::destructions(), 2U);
72+
}
73+
74+
static int increment(int N) { return N + 1; }
75+
76+
TEST(BindTest, BindFunction) {
77+
auto Op = bind_front([](int op(int), int arg) { return op(arg); }, increment);
78+
EXPECT_EQ(Op(1), 2);
79+
}
80+
81+
TEST(BindTest, BindTo_move_only_function) {
82+
move_only_function<int(int, int)> Add = [](int X, int Y) { return X + Y; };
83+
auto Add1 = bind_front(std::move(Add), 1);
84+
EXPECT_EQ(Add1(2), 3);
85+
}

0 commit comments

Comments
 (0)