libsemigroups  v3.0.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
function-ref.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2019-2025 James D. Mitchell
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18
19// This file contains a class for FunctionRef, a light-weight wrapper for
20// callables, from:
21// https://vittorioromeo.info/index/blog/passing_functions_to_functions.html
22//
23// Note that it is ok to use FunctionRef's as parameters for functions, and in
24// other situations where the callable is guaranteed to exist when it is
25// called. For example, the following is not valid:
26//
27// auto foo = FunctionRef([](){ return 42; });
28// ...
29// foo();
30//
31// since the lambda which is the argument to the FunctionRef constructor is a
32// temporary, and so the FunctionRef is not valid after the line where it is
33// created.
34
35#ifndef LIBSEMIGROUPS_DETAIL_FUNCTION_REF_HPP_
36#define LIBSEMIGROUPS_DETAIL_FUNCTION_REF_HPP_
37
38#include <type_traits> // for is_invocable_v
39
40#include "libsemigroups/debug.hpp" // for LIBSEMIGROUPS_ASSERT
41
42namespace libsemigroups {
43 namespace detail {
44 template <typename TSignature>
45 class FunctionRef;
46
47 template <typename TReturn, typename... TArgs>
48 class FunctionRef<TReturn(TArgs...)> {
49 private:
50 void* _ptr;
51 TReturn (*_erased_fn)(void*, TArgs...);
52
53 public:
54 FunctionRef() noexcept : _ptr(nullptr) {}
55
56 template <typename T,
57 typename = std::enable_if_t<
58 std::is_invocable_v<T(TArgs...)>
59 && !std::is_same_v<std::decay_t<T>, FunctionRef>>>
60 FunctionRef(T&& x) noexcept
61 : _ptr{reinterpret_cast<void*>(std::addressof(x))} {
62 _erased_fn = [](void* ptr, TArgs... xs) -> TReturn {
63 return (*reinterpret_cast<std::add_pointer_t<T>>(ptr))(
64 std::forward<TArgs>(xs)...);
65 };
66 }
67
68 decltype(auto) operator()(TArgs... xs) const
69 noexcept(noexcept(_erased_fn(_ptr, std::forward<TArgs>(xs)...))) {
70 LIBSEMIGROUPS_ASSERT(valid());
71 return _erased_fn(_ptr, std::forward<TArgs>(xs)...);
72 }
73
74 inline bool valid() const noexcept {
75 return _ptr != nullptr;
76 }
77
78 inline void invalidate() noexcept {
79 _ptr = nullptr;
80 }
81 };
82 } // namespace detail
83} // namespace libsemigroups
84
85#endif // LIBSEMIGROUPS_DETAIL_FUNCTION_REF_HPP_
T addressof(T... args)
T forward(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44