nk 1.0.0
C++ Numerical Computing Runtime
Loading...
Searching...
No Matches
function_ref.hpp
1// core/include/nk/value/function_ref.hpp
2//
3// nk::function_ref<Sig> — lightweight, non-owning callable view.
4//
5// Two-pointer type-erased reference to any callable matching the
6// signature `Sig`. Cheap to copy (16 bytes on 64-bit), no allocation,
7// no virtual dispatch overhead (single indirect call through a thunk).
8// The lifetime of the underlying callable is the caller's
9// responsibility — function_ref does NOT own it.
10//
11// Used for "matlab-style function handle" callbacks in the numerical
12// library API (fzero, integral, fminsearch, cellfun, …). The engine
13// adapter builds a stack-resident lambda that wraps a function-handle
14// Value, then passes a function_ref view to the library function.
15// The library function calls the callback as many times as needed and
16// returns; the lambda + function_ref both live in the adapter frame.
17//
18// Inspired by C++26's std::function_ref and tcb::function_ref.
19
20#pragma once
21
22#include <type_traits>
23#include <utility>
24
25namespace nk {
26
27template <class Sig>
28class function_ref; // primary template undefined — only spec'd below
29
30template <class R, class... Args>
31class function_ref<R(Args...)>
32{
33public:
37 constexpr function_ref() noexcept = default;
38
47 template <class F,
48 class = std::enable_if_t<
49 !std::is_same_v<std::decay_t<F>, function_ref> &&
50 std::is_invocable_r_v<R, F &, Args...>>>
51 function_ref(F &&f) noexcept
52 : obj_(const_cast<void *>(reinterpret_cast<const void *>(&f))),
53 thunk_(&thunkFor<std::remove_reference_t<F>>)
54 {}
55
57 R operator()(Args... args) const
58 {
59 return thunk_(obj_, std::forward<Args>(args)...);
60 }
61
63 explicit operator bool() const noexcept { return thunk_ != nullptr; }
64
65private:
66 using thunk_t = R (*)(void *, Args...);
67
68 template <class F>
69 static R thunkFor(void *obj, Args... args)
70 {
71 return (*reinterpret_cast<F *>(obj))(std::forward<Args>(args)...);
72 }
73
74 void * obj_ = nullptr;
75 thunk_t thunk_ = nullptr;
76};
77
78} // namespace nk
constexpr function_ref() noexcept=default
Default-construct an empty function_ref (calling it is UB).
R operator()(Args... args) const
Invoke the wrapped callable. UB if empty.