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
20#include "pw_preprocessor/compiler.h"
21
22namespace pw {
23
42template <typename Signature>
44
45template <typename T>
46inline constexpr bool is_function_ref_v = false;
47
48template <typename Sig>
49inline constexpr bool is_function_ref_v<FunctionRef<Sig>> = true;
50
51namespace function::internal {
52
53template <bool kIsConst, bool IsNoExcept, typename R, typename... Args>
55
56union Storage {
57 void* ptr;
58 alignas(void*) char buffer[sizeof(void*)];
59};
60
61// Specialization for non-noexcept
62template <bool kIsConst, typename R, typename... Args>
63class BasicFunctionRef<kIsConst, false, R, Args...> {
64 public:
65 // Constructor for function pointers
66 template <typename F,
67 std::enable_if_t<std::is_function_v<F> &&
68 std::is_invocable_r_v<R, F*, Args...>,
69 int> = 0>
70 BasicFunctionRef(F* f) noexcept
71 : invoker_([](void* obj_ptr, Args... args) -> R {
72 Storage* s = static_cast<Storage*>(obj_ptr);
73 return (*reinterpret_cast<F*>(s->ptr))(std::forward<Args>(args)...);
74 }) {
75 obj_.ptr = reinterpret_cast<void*>(f);
76 }
77
78 // Constructor for callable objects
79 template <typename F,
80 std::enable_if_t<
81 !is_function_ref_v<std::decay_t<F>> &&
82 !std::is_member_pointer_v<std::remove_reference_t<F>> &&
83 std::is_invocable_r_v<
84 R,
85 std::conditional_t<kIsConst,
86 const std::remove_reference_t<F>&,
87 std::remove_reference_t<F>&>,
88 Args...>,
89 int> = 0>
91 : invoker_([](void* obj_ptr, Args... args) -> R {
92 Storage* s = static_cast<Storage*>(obj_ptr);
93 using FPtr = std::conditional_t<kIsConst,
94 const std::remove_reference_t<F>*,
95 std::remove_reference_t<F>*>;
96 return (*static_cast<FPtr>(s->ptr))(std::forward<Args>(args)...);
97 }) {
98 obj_.ptr = const_cast<void*>(static_cast<const void*>(&f));
99 }
100
101 // Converting constructor from compatible BasicFunctionRef
102 template <bool kOtherConst,
103 bool kOtherNoExcept,
104 std::enable_if_t<(!kOtherConst || kIsConst), int> = 0>
107 other) noexcept
108 : obj_(other.obj_), invoker_(other.invoker_) {}
109
110 BasicFunctionRef(const BasicFunctionRef&) noexcept = default;
111 BasicFunctionRef& operator=(const BasicFunctionRef&) noexcept = default;
112
113 R operator()(Args... args) const {
114 return invoker_(const_cast<Storage*>(&obj_), std::forward<Args>(args)...);
115 }
116
117 private:
118 template <bool, bool, typename, typename...>
119 friend class BasicFunctionRef;
120
121 using Invoker = R (*)(void*, Args...);
122
123 Storage obj_;
124 Invoker invoker_;
125};
126
127// Specialization for noexcept
128template <bool kIsConst, typename R, typename... Args>
129class BasicFunctionRef<kIsConst, true, R, Args...> {
130 public:
131 // Constructor for function pointers
132 template <typename F,
133 std::enable_if_t<std::is_function_v<F> &&
134 std::is_invocable_r_v<R, F*, Args...> &&
135 std::is_nothrow_invocable_v<F*, Args...>,
136 int> = 0>
137 BasicFunctionRef(F* f) noexcept
138 : invoker_([](void* obj_ptr, Args... args) noexcept -> R {
139 Storage* s = static_cast<Storage*>(obj_ptr);
140 return (*reinterpret_cast<F*>(s->ptr))(std::forward<Args>(args)...);
141 }) {
142 obj_.ptr = reinterpret_cast<void*>(f);
143 }
144
145 // Constructor for callable objects
146 template <typename F,
147 std::enable_if_t<
148 !is_function_ref_v<std::decay_t<F>> &&
149 !std::is_member_pointer_v<std::remove_reference_t<F>> &&
150 std::is_invocable_r_v<
151 R,
152 std::conditional_t<kIsConst,
153 const std::remove_reference_t<F>&,
154 std::remove_reference_t<F>&>,
155 Args...> &&
156 std::is_nothrow_invocable_v<
157 std::conditional_t<kIsConst,
158 const std::remove_reference_t<F>&,
159 std::remove_reference_t<F>&>,
160 Args...>,
161 int> = 0>
163 : invoker_([](void* obj_ptr, Args... args) noexcept -> R {
164 Storage* s = static_cast<Storage*>(obj_ptr);
165 using FPtr = std::conditional_t<kIsConst,
166 const std::remove_reference_t<F>*,
167 std::remove_reference_t<F>*>;
168 return (*static_cast<FPtr>(s->ptr))(std::forward<Args>(args)...);
169 }) {
170 obj_.ptr = const_cast<void*>(static_cast<const void*>(&f));
171 }
172
173 // Converting constructor from compatible BasicFunctionRef
174 template <
175 bool kOtherConst,
176 bool kOtherNoExcept,
177 std::enable_if_t<kOtherNoExcept && (!kOtherConst || kIsConst), int> = 0>
180 other) noexcept
181 : obj_(other.obj_), invoker_(other.invoker_) {}
182
183 BasicFunctionRef(const BasicFunctionRef&) noexcept = default;
184 BasicFunctionRef& operator=(const BasicFunctionRef&) noexcept = default;
185
186 R operator()(Args... args) const noexcept {
187 return invoker_(const_cast<Storage*>(&obj_), std::forward<Args>(args)...);
188 }
189
190 private:
191 template <bool, bool, typename, typename...>
192 friend class BasicFunctionRef;
193
194 using Invoker = R (*)(void*, Args...) noexcept;
195
196 Storage obj_;
197 Invoker invoker_;
198};
199
200} // namespace function::internal
201
202// Specialization for R(Args...)
203template <typename R, typename... Args>
204class FunctionRef<R(Args...)> final
205 : public function::internal::BasicFunctionRef<false, false, R, Args...> {
206 using Base = function::internal::BasicFunctionRef<false, false, R, Args...>;
207
208 public:
209 using Base::Base;
210 FunctionRef(const FunctionRef&) noexcept = default;
211 FunctionRef& operator=(const FunctionRef&) noexcept = default;
212};
213
214// Specialization for R(Args...) const
215template <typename R, typename... Args>
216class FunctionRef<R(Args...) const> final
217 : public function::internal::BasicFunctionRef<true, false, R, Args...> {
218 using Base = function::internal::BasicFunctionRef<true, false, R, Args...>;
219
220 public:
221 using Base::Base;
222 FunctionRef(const FunctionRef&) noexcept = default;
223 FunctionRef& operator=(const FunctionRef&) noexcept = default;
224};
225
226// Specialization for R(Args...) noexcept
227template <typename R, typename... Args>
228class FunctionRef<R(Args...) noexcept> final
229 : public function::internal::BasicFunctionRef<false, true, R, Args...> {
230 using Base = function::internal::BasicFunctionRef<false, true, R, Args...>;
231
232 public:
233 using Base::Base;
234 FunctionRef(const FunctionRef&) noexcept = default;
235 FunctionRef& operator=(const FunctionRef&) noexcept = default;
236};
237
238// Specialization for R(Args...) const noexcept
239template <typename R, typename... Args>
240class FunctionRef<R(Args...) const noexcept> final
241 : public function::internal::BasicFunctionRef<true, true, R, Args...> {
242 using Base = function::internal::BasicFunctionRef<true, true, R, Args...>;
243
244 public:
245 using Base::Base;
246 FunctionRef(const FunctionRef&) noexcept = default;
247 FunctionRef& operator=(const FunctionRef&) noexcept = default;
248};
249
250} // namespace pw
Definition: function_ref.h:43
Definition: function_ref.h:54
#define PW_ATTRIBUTE_LIFETIME_BOUND
Definition: compiler.h:267
The Pigweed namespace.
Definition: alignment.h:27
Definition: function_ref.h:56