[orc-rt] Add const support to move_only_function. (#157781)

Adds support for both const move_only_functions, and const callees.
This commit is contained in:
Lang Hames 2025-09-10 12:39:23 +10:00 committed by GitHub
parent cc052667b4
commit 55906374f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 117 additions and 4 deletions

View File

@ -50,12 +50,38 @@ private:
CallableT Callable;
};
template <typename RetT, typename... ArgTs> class GenericConstCallable {
public:
virtual ~GenericConstCallable() = default;
virtual RetT call(ArgTs &&...Args) const = 0;
};
template <typename CallableT, typename RetT, typename... ArgTs>
class GenericConstCallableImpl : public GenericConstCallable<RetT, ArgTs...> {
public:
GenericConstCallableImpl(CallableT &&Callable)
: Callable(std::move(Callable)) {}
RetT call(ArgTs &&...Args) const 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...)> {
private:
using GenericCallable =
move_only_function_detail::GenericCallable<RetT, ArgTs...>;
template <typename CallableT>
using GenericCallableImpl =
move_only_function_detail::GenericCallableImpl<CallableT, RetT, ArgTs...>;
public:
move_only_function() = default;
move_only_function(std::nullptr_t) {}
@ -66,17 +92,50 @@ public:
template <typename CallableT>
move_only_function(CallableT &&Callable)
: C(std::make_unique<move_only_function_detail::GenericCallableImpl<
std::decay_t<CallableT>, RetT, ArgTs...>>(std::move(Callable))) {}
: C(std::make_unique<GenericCallableImpl<std::decay_t<CallableT>>>(
std::move(Callable))) {}
RetT operator()(ArgTs... Params) {
RetT operator()(ArgTs... Params) const {
return C->call(std::forward<ArgTs>(Params)...);
}
explicit operator bool() const { return !!C; }
private:
std::unique_ptr<move_only_function_detail::GenericCallable<RetT, ArgTs...>> C;
std::unique_ptr<GenericCallable> C;
};
template <typename RetT, typename... ArgTs>
class move_only_function<RetT(ArgTs...) const> {
private:
using GenericCallable =
move_only_function_detail::GenericConstCallable<RetT, ArgTs...>;
template <typename CallableT>
using GenericCallableImpl =
move_only_function_detail::GenericConstCallableImpl<CallableT, 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<const GenericCallableImpl<std::decay_t<CallableT>>>(
std::move(Callable))) {}
RetT operator()(ArgTs... Params) const {
return C->call(std::forward<ArgTs>(Params)...);
}
explicit operator bool() const { return !!C; }
private:
std::unique_ptr<const GenericCallable> C;
};
} // namespace orc_rt

View File

@ -174,3 +174,57 @@ TEST(MoveOnlyFunctionTest, BooleanConversion) {
move_only_function<void()> F = []() {};
EXPECT_TRUE(F);
}
class ConstCallCounter {
public:
ConstCallCounter(size_t &NonConst, size_t &Const)
: NonConst(NonConst), Const(Const) {}
void operator()() { ++NonConst; }
void operator()() const { ++Const; }
private:
size_t &NonConst;
size_t &Const;
};
TEST(MoveOnlyFunctionTest, Constness) {
{
// Non-const move-only-function, non-const callable.
size_t NonConst = 0;
size_t Const = 0;
move_only_function<void()> F(ConstCallCounter(NonConst, Const));
F();
EXPECT_EQ(NonConst, 1U);
EXPECT_EQ(Const, 0U);
}
{
// const move-only-function, non-const callable.
size_t NonConst = 0;
size_t Const = 0;
const move_only_function<void()> F(ConstCallCounter(NonConst, Const));
F();
EXPECT_EQ(NonConst, 1U);
EXPECT_EQ(Const, 0U);
}
{
// Non-const move-only-function, const callable.
size_t NonConst = 0;
size_t Const = 0;
move_only_function<void() const> F(ConstCallCounter(NonConst, Const));
F();
EXPECT_EQ(NonConst, 0U);
EXPECT_EQ(Const, 1U);
}
{
// const move-only-function, const callable.
size_t NonConst = 0;
size_t Const = 0;
const move_only_function<void() const> F(ConstCallCounter(NonConst, Const));
F();
EXPECT_EQ(NonConst, 0U);
EXPECT_EQ(Const, 1U);
}
}