diff --git a/orc-rt/include/orc-rt/move_only_function.h b/orc-rt/include/orc-rt/move_only_function.h index 29924060acc78..9a483a4b405e3 100644 --- a/orc-rt/include/orc-rt/move_only_function.h +++ b/orc-rt/include/orc-rt/move_only_function.h @@ -50,12 +50,71 @@ class GenericCallableImpl : public GenericCallable { CallableT Callable; }; +template class GenericConstCallable { +public: + virtual ~GenericConstCallable() = default; + virtual RetT call(ArgTs &&...Args) const = 0; +}; + +template +class GenericConstCallableImpl : public GenericConstCallable { +public: + GenericConstCallableImpl(CallableT &&Callable) + : Callable(std::move(Callable)) {} + RetT call(ArgTs &&...Args) const override { + return Callable(std::forward(Args)...); + } + +private: + CallableT Callable; +}; + } // namespace move_only_function_detail template class move_only_function; template class move_only_function { +private: + using GenericCallable = + move_only_function_detail::GenericCallable; + template + using GenericCallableImpl = + move_only_function_detail::GenericCallableImpl; + +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 + move_only_function(CallableT &&Callable) + : C(std::make_unique>>( + std::move(Callable))) {} + + RetT operator()(ArgTs... Params) const { + return C->call(std::forward(Params)...); + } + + explicit operator bool() const { return !!C; } + +private: + std::unique_ptr C; +}; + +template +class move_only_function { +private: + using GenericCallable = + move_only_function_detail::GenericConstCallable; + template + using GenericCallableImpl = + move_only_function_detail::GenericConstCallableImpl; + public: move_only_function() = default; move_only_function(std::nullptr_t) {} @@ -66,17 +125,17 @@ class move_only_function { template move_only_function(CallableT &&Callable) - : C(std::make_unique, RetT, ArgTs...>>(std::move(Callable))) {} + : C(std::make_unique>>( + std::move(Callable))) {} - RetT operator()(ArgTs... Params) { + RetT operator()(ArgTs... Params) const { return C->call(std::forward(Params)...); } explicit operator bool() const { return !!C; } private: - std::unique_ptr> C; + std::unique_ptr C; }; } // namespace orc_rt diff --git a/orc-rt/unittests/move_only_function-test.cpp b/orc-rt/unittests/move_only_function-test.cpp index c304bf111a392..334c655057849 100644 --- a/orc-rt/unittests/move_only_function-test.cpp +++ b/orc-rt/unittests/move_only_function-test.cpp @@ -174,3 +174,57 @@ TEST(MoveOnlyFunctionTest, BooleanConversion) { move_only_function 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 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 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 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 F(ConstCallCounter(NonConst, Const)); + F(); + EXPECT_EQ(NonConst, 0U); + EXPECT_EQ(Const, 1U); + } +}