Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 63 additions & 4 deletions orc-rt/include/orc-rt/move_only_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,71 @@ class GenericCallableImpl : public GenericCallable<RetT, ArgTs...> {
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) {}
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<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<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) {}
Expand All @@ -66,17 +125,17 @@ class move_only_function<RetT(ArgTs...)> {

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<const 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<const GenericCallable> C;
};

} // namespace orc_rt
Expand Down
54 changes: 54 additions & 0 deletions orc-rt/unittests/move_only_function-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Loading