Commit ffde95a6 authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: add function_ref code

parent f93dcfb2
......@@ -260,6 +260,95 @@ almost_equal(T x, T y, int ulp)
std::fabs(x - y) < std::numeric_limits<T>::min();
}
/*****************************************************************************
*
* Definition of a lightweight std::function
*
****************************************************************************/
template<class F>
class function_ref;
template<class R, class... Args>
class function_ref<R(Args...)>
{
public:
constexpr function_ref() noexcept = delete;
/// Creates a `function_ref` which refers to the same callable as `rhs`.
constexpr function_ref(const function_ref<R(Args...)>& rhs) noexcept =
default;
/// Constructs a `function_ref` referring to `f`.
///
/// \synopsis template <typename F> constexpr function_ref(F &&f) noexcept
template<
typename F,
std::enable_if_t<!std::is_same<std::decay_t<F>, function_ref>::value &&
std::is_invocable_r<R, F&&, Args...>::value>* = nullptr>
constexpr function_ref(F&& f) noexcept
: obj(const_cast<void*>(reinterpret_cast<const void*>(std::addressof(f))))
{
cb = [](void* obj, Args... args) -> R {
return std::invoke(
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
std::forward<Args>(args)...);
};
}
/// Makes `*this` refer to the same callable as `rhs`.
constexpr function_ref<R(Args...)>& operator=(
const function_ref<R(Args...)>& rhs) noexcept = default;
/// Makes `*this` refer to `f`.
///
/// \synopsis template <typename F> constexpr function_ref &operator=(F &&f)
/// noexcept;
template<
typename F,
std::enable_if_t<std::is_invocable_r<R, F&&, Args...>::value>* = nullptr>
constexpr function_ref<R(Args...)>& operator=(F&& f) noexcept
{
obj = reinterpret_cast<void*>(std::addressof(f));
cb = [](void* obj, Args... args) {
return std::invoke(
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
std::forward<Args>(args)...);
};
return *this;
}
constexpr void swap(function_ref<R(Args...)>& rhs) noexcept
{
std::swap(obj, rhs.obj);
std::swap(cb, rhs.cb);
}
R operator()(Args... args) const
{
return cb(obj, std::forward<Args>(args)...);
}
private:
void* obj = nullptr;
R (*cb)(void*, Args...) = nullptr;
};
/// Swaps the referred callables of `lhs` and `rhs`.
template<typename R, typename... Args>
constexpr void
swap(function_ref<R(Args...)>& lhs, function_ref<R(Args...)>& rhs) noexcept
{
lhs.swap(rhs);
}
template<typename R, typename... Args>
function_ref(R (*)(Args...)) -> function_ref<R(Args...)>;
template<typename R, typename... Args>
function_ref(R (*)(Args...) noexcept) -> function_ref<R(Args...) noexcept>;
/*****************************************************************************
*
* Definition of Time
......
......@@ -50,6 +50,31 @@ file_output_observe(const irt::observer& obs,
fmt::print(output->os, "{},{}\n", t, msg.real[0]);
}
bool function_ref_called = false;
void
function_ref_f()
{
function_ref_called = true;
}
struct function_ref_class
{
bool baz_called = false;
void baz()
{
baz_called = true;
}
bool qux_called = false;
void qux()
{
qux_called = true;
}
};
static void empty_fun(irt::model_id /*id*/) noexcept
{}
......@@ -188,6 +213,40 @@ main()
expect(irt::is_bad(s2) == true);
};
"function_ref"_test = [] {
{
irt::function_ref<void(void)> fr = function_ref_f;
fr();
expect(function_ref_called == true);
}
{
function_ref_class o;
auto x = &function_ref_class::baz;
irt::function_ref<void(function_ref_class&)> fr = x;
fr(o);
expect(o.baz_called);
x = &function_ref_class::qux;
fr = x;
fr(o);
expect(o.qux_called);
}
{
auto x = [] { return 42; };
irt::function_ref<int()> fr = x;
expect(fr() == 42);
}
{
int i = 0;
auto x = [&i] { i = 42; };
irt::function_ref<void()> fr = x;
fr();
expect(i == 42);
}
};
"time"_test = [] {
expect(irt::time_domain<irt::time>::infinity >
irt::time_domain<irt::time>::zero);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment