C/C++ API Reference
Loading...
Searching...
No Matches
function_ref.h
1// Copyright 2026 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstring>
17#include <type_traits>
18#include <utility>
19
20namespace pw {
21
40template <typename Signature>
42
43namespace function::internal {
44
45template <bool IsConst, bool IsNoExcept, typename R, typename... Args>
47
48// Specialization for non-noexcept
49template <bool IsConst, typename R, typename... Args>
50class BasicFunctionRef<IsConst, false, R, Args...> {
51 public:
52 using ObjPtr = void*;
53 using Invoker = R (*)(ObjPtr, Args...);
54
55 union Storage {
56 void* ptr;
57 alignas(void*) char buffer[sizeof(void*)];
58 };
59
60 // Constructor for lvalue reference
61 template <typename F,
62 std::enable_if_t<
63 !std::is_same_v<std::decay_t<F>, BasicFunctionRef> &&
64 std::is_invocable_r_v<
65 R,
66 std::conditional_t<IsConst,
67 const std::remove_reference_t<F>&,
68 std::remove_reference_t<F>&>,
69 Args...>,
70 int> = 0>
71 BasicFunctionRef(F&& f) noexcept
72 : invoker_([](ObjPtr obj_ptr, Args... args) -> R {
73 Storage* s = static_cast<Storage*>(obj_ptr);
74 using FPtr = std::conditional_t<IsConst,
75 const std::remove_reference_t<F>*,
76 std::remove_reference_t<F>*>;
77 FPtr f_ptr;
78 if constexpr (std::is_function_v<std::remove_reference_t<F>>) {
79 f_ptr = reinterpret_cast<FPtr>(s->ptr);
80 } else {
81 f_ptr = static_cast<FPtr>(s->ptr);
82 }
83 return (*f_ptr)(std::forward<Args>(args)...);
84 }) {
85 if constexpr (std::is_function_v<std::remove_reference_t<F>>) {
86 obj_.ptr = reinterpret_cast<void*>(&f);
87 } else {
88 obj_.ptr = const_cast<void*>(static_cast<const void*>(&f));
89 }
90 }
91
92 BasicFunctionRef(const BasicFunctionRef&) noexcept = default;
93 BasicFunctionRef& operator=(const BasicFunctionRef&) noexcept = default;
94
95 R operator()(Args... args) const {
96 return invoker_(const_cast<Storage*>(&obj_), std::forward<Args>(args)...);
97 }
98
99 protected:
100 Storage obj_;
101 Invoker invoker_;
102};
103
104// Specialization for noexcept
105template <bool IsConst, typename R, typename... Args>
106class BasicFunctionRef<IsConst, true, R, Args...> {
107 public:
108 using ObjPtr = void*;
109 using Invoker = R (*)(ObjPtr, Args...) noexcept;
110
111 union Storage {
112 void* ptr;
113 alignas(void*) char buffer[sizeof(void*)];
114 };
115
116 // Constructor for lvalue reference
117 template <typename F,
118 std::enable_if_t<
119 !std::is_same_v<std::decay_t<F>, BasicFunctionRef> &&
120 std::is_invocable_r_v<
121 R,
122 std::conditional_t<IsConst,
123 const std::remove_reference_t<F>&,
124 std::remove_reference_t<F>&>,
125 Args...> &&
126 std::is_nothrow_invocable_v<
127 std::conditional_t<IsConst,
128 const std::remove_reference_t<F>&,
129 std::remove_reference_t<F>&>,
130 Args...>,
131 int> = 0>
132 BasicFunctionRef(F&& f) noexcept
133 : invoker_([](ObjPtr obj_ptr, Args... args) noexcept -> R {
134 Storage* s = static_cast<Storage*>(obj_ptr);
135 using FPtr = std::conditional_t<IsConst,
136 const std::remove_reference_t<F>*,
137 std::remove_reference_t<F>*>;
138 FPtr f_ptr;
139 if constexpr (std::is_function_v<std::remove_reference_t<F>>) {
140 f_ptr = reinterpret_cast<FPtr>(s->ptr);
141 } else {
142 f_ptr = static_cast<FPtr>(s->ptr);
143 }
144 return (*f_ptr)(std::forward<Args>(args)...);
145 }) {
146 if constexpr (std::is_function_v<std::remove_reference_t<F>>) {
147 obj_.ptr = reinterpret_cast<void*>(&f);
148 } else {
149 obj_.ptr = const_cast<void*>(static_cast<const void*>(&f));
150 }
151 }
152
153 BasicFunctionRef(const BasicFunctionRef&) noexcept = default;
154 BasicFunctionRef& operator=(const BasicFunctionRef&) noexcept = default;
155
156 R operator()(Args... args) const noexcept {
157 return invoker_(const_cast<Storage*>(&obj_), std::forward<Args>(args)...);
158 }
159
160 protected:
161 Storage obj_;
162 Invoker invoker_;
163};
164
165} // namespace function::internal
166
167// Specialization for R(Args...)
168template <typename R, typename... Args>
169class FunctionRef<R(Args...)>
170 : public function::internal::BasicFunctionRef<false, false, R, Args...> {
171 using Base = function::internal::BasicFunctionRef<false, false, R, Args...>;
172
173 public:
174 using Base::Base;
175 FunctionRef(const FunctionRef&) noexcept = default;
176 FunctionRef& operator=(const FunctionRef&) noexcept = default;
177};
178
179// Specialization for R(Args...) const
180template <typename R, typename... Args>
181class FunctionRef<R(Args...) const>
182 : public function::internal::BasicFunctionRef<true, false, R, Args...> {
183 using Base = function::internal::BasicFunctionRef<true, false, R, Args...>;
184
185 public:
186 using Base::Base;
187 FunctionRef(const FunctionRef&) noexcept = default;
188 FunctionRef& operator=(const FunctionRef&) noexcept = default;
189};
190
191// Specialization for R(Args...) noexcept
192template <typename R, typename... Args>
193class FunctionRef<R(Args...) noexcept>
194 : public function::internal::BasicFunctionRef<false, true, R, Args...> {
195 using Base = function::internal::BasicFunctionRef<false, true, R, Args...>;
196
197 public:
198 using Base::Base;
199 FunctionRef(const FunctionRef&) noexcept = default;
200 FunctionRef& operator=(const FunctionRef&) noexcept = default;
201};
202
203// Specialization for R(Args...) const noexcept
204template <typename R, typename... Args>
205class FunctionRef<R(Args...) const noexcept>
206 : public function::internal::BasicFunctionRef<true, true, R, Args...> {
207 using Base = function::internal::BasicFunctionRef<true, true, R, Args...>;
208
209 public:
210 using Base::Base;
211 FunctionRef(const FunctionRef&) noexcept = default;
212 FunctionRef& operator=(const FunctionRef&) noexcept = default;
213};
214
215} // namespace pw
Definition: function_ref.h:41
Definition: function_ref.h:46
The Pigweed namespace.
Definition: alignment.h:27