common: Add unique function
This commit is contained in:
parent
f28dd32275
commit
2c8d337418
|
@ -188,6 +188,7 @@ add_library(common STATIC
|
||||||
tiny_mt.h
|
tiny_mt.h
|
||||||
tree.h
|
tree.h
|
||||||
uint128.h
|
uint128.h
|
||||||
|
unique_function.h
|
||||||
uuid.cpp
|
uuid.cpp
|
||||||
uuid.h
|
uuid.h
|
||||||
vector_math.h
|
vector_math.h
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
/// General purpose function wrapper similar to std::function.
|
||||||
|
/// Unlike std::function, the captured values don't have to be copyable.
|
||||||
|
/// This class can be moved but not copied.
|
||||||
|
template <typename ResultType, typename... Args>
|
||||||
|
class UniqueFunction {
|
||||||
|
class CallableBase {
|
||||||
|
public:
|
||||||
|
virtual ~CallableBase() = default;
|
||||||
|
virtual ResultType operator()(Args&&...) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Functor>
|
||||||
|
class Callable final : public CallableBase {
|
||||||
|
public:
|
||||||
|
Callable(Functor&& functor_) : functor{std::move(functor_)} {}
|
||||||
|
~Callable() override = default;
|
||||||
|
|
||||||
|
ResultType operator()(Args&&... args) override {
|
||||||
|
return functor(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Functor functor;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
UniqueFunction() = default;
|
||||||
|
|
||||||
|
template <typename Functor>
|
||||||
|
UniqueFunction(Functor&& functor)
|
||||||
|
: callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
|
||||||
|
|
||||||
|
UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
|
||||||
|
UniqueFunction(UniqueFunction&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
UniqueFunction& operator=(const UniqueFunction&) = delete;
|
||||||
|
UniqueFunction(const UniqueFunction&) = delete;
|
||||||
|
|
||||||
|
ResultType operator()(Args&&... args) const {
|
||||||
|
return (*callable)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept {
|
||||||
|
return static_cast<bool>(callable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<CallableBase> callable;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -5,6 +5,7 @@ add_executable(tests
|
||||||
common/host_memory.cpp
|
common/host_memory.cpp
|
||||||
common/param_package.cpp
|
common/param_package.cpp
|
||||||
common/ring_buffer.cpp
|
common/ring_buffer.cpp
|
||||||
|
common/unique_function.cpp
|
||||||
core/core_timing.cpp
|
core/core_timing.cpp
|
||||||
core/network/network.cpp
|
core/network/network.cpp
|
||||||
tests.cpp
|
tests.cpp
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "common/unique_function.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct Noisy {
|
||||||
|
Noisy() : state{"Default constructed"} {}
|
||||||
|
Noisy(Noisy&& rhs) noexcept : state{"Move constructed"} {
|
||||||
|
rhs.state = "Moved away";
|
||||||
|
}
|
||||||
|
Noisy& operator=(Noisy&& rhs) noexcept {
|
||||||
|
state = "Move assigned";
|
||||||
|
rhs.state = "Moved away";
|
||||||
|
}
|
||||||
|
Noisy(const Noisy&) : state{"Copied constructed"} {}
|
||||||
|
Noisy& operator=(const Noisy&) {
|
||||||
|
state = "Copied assigned";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string state;
|
||||||
|
};
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
TEST_CASE("UniqueFunction", "[common]") {
|
||||||
|
SECTION("Capture reference") {
|
||||||
|
int value = 0;
|
||||||
|
Common::UniqueFunction<void> func = [&value] { value = 5; };
|
||||||
|
func();
|
||||||
|
REQUIRE(value == 5);
|
||||||
|
}
|
||||||
|
SECTION("Capture pointer") {
|
||||||
|
int value = 0;
|
||||||
|
int* pointer = &value;
|
||||||
|
Common::UniqueFunction<void> func = [pointer] { *pointer = 5; };
|
||||||
|
func();
|
||||||
|
REQUIRE(value == 5);
|
||||||
|
}
|
||||||
|
SECTION("Move object") {
|
||||||
|
Noisy noisy;
|
||||||
|
REQUIRE(noisy.state == "Default constructed");
|
||||||
|
|
||||||
|
Common::UniqueFunction<void> func = [noisy = std::move(noisy)] {
|
||||||
|
REQUIRE(noisy.state == "Move constructed");
|
||||||
|
};
|
||||||
|
REQUIRE(noisy.state == "Moved away");
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
SECTION("Move construct function") {
|
||||||
|
int value = 0;
|
||||||
|
Common::UniqueFunction<void> func = [&value] { value = 5; };
|
||||||
|
Common::UniqueFunction<void> new_func = std::move(func);
|
||||||
|
new_func();
|
||||||
|
REQUIRE(value == 5);
|
||||||
|
}
|
||||||
|
SECTION("Move assign function") {
|
||||||
|
int value = 0;
|
||||||
|
Common::UniqueFunction<void> func = [&value] { value = 5; };
|
||||||
|
Common::UniqueFunction<void> new_func;
|
||||||
|
new_func = std::move(func);
|
||||||
|
new_func();
|
||||||
|
REQUIRE(value == 5);
|
||||||
|
}
|
||||||
|
SECTION("Default construct then assign function") {
|
||||||
|
int value = 0;
|
||||||
|
Common::UniqueFunction<void> func;
|
||||||
|
func = [&value] { value = 5; };
|
||||||
|
func();
|
||||||
|
REQUIRE(value == 5);
|
||||||
|
}
|
||||||
|
SECTION("Pass arguments") {
|
||||||
|
int result = 0;
|
||||||
|
Common::UniqueFunction<void, int, int> func = [&result](int a, int b) { result = a + b; };
|
||||||
|
func(5, 4);
|
||||||
|
REQUIRE(result == 9);
|
||||||
|
}
|
||||||
|
SECTION("Pass arguments and return value") {
|
||||||
|
Common::UniqueFunction<int, int, int> func = [](int a, int b) { return a + b; };
|
||||||
|
REQUIRE(func(5, 4) == 9);
|
||||||
|
}
|
||||||
|
SECTION("Destructor") {
|
||||||
|
int num_destroyed = 0;
|
||||||
|
struct Foo {
|
||||||
|
Foo(int* num_) : num{num_} {}
|
||||||
|
Foo(Foo&& rhs) : num{std::exchange(rhs.num, nullptr)} {}
|
||||||
|
Foo(const Foo&) = delete;
|
||||||
|
|
||||||
|
~Foo() {
|
||||||
|
if (num) {
|
||||||
|
++*num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int* num = nullptr;
|
||||||
|
};
|
||||||
|
Foo object{&num_destroyed};
|
||||||
|
{
|
||||||
|
Common::UniqueFunction<void> func = [object = std::move(object)] {};
|
||||||
|
REQUIRE(num_destroyed == 0);
|
||||||
|
}
|
||||||
|
REQUIRE(num_destroyed == 1);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue