43#define FUNC_NO_EXCEPTIONS
48#define FUNC_TEMPLATE_NOEXCEPT(FUNCTOR, ALLOCATOR)
49#define FUNC_CONSTEXPR const
51#define FUNC_NOEXCEPT noexcept
52#define FUNC_TEMPLATE_NOEXCEPT(FUNCTOR, ALLOCATOR) noexcept(detail::is_inplace_allocated<FUNCTOR, ALLOCATOR>::value)
53#define FUNC_CONSTEXPR constexpr
56#pragma GCC diagnostic push
57#pragma GCC diagnostic ignored "-Wstrict-aliasing"
60#define FUNC_MOVE(value) static_cast<typename std::remove_reference<decltype(value)>::type&&>(value)
61#define FUNC_FORWARD(type, value) static_cast<type&&>(value)
64#ifndef FUNC_NO_EXCEPTIONS
65struct bad_function_call : std::exception {
66 const char* what()
const FUNC_NOEXCEPT override {
return "Bad function call"; }
87#ifndef FUNC_NO_EXCEPTIONS
88template <
typename Result,
typename... Arguments>
90 throw bad_function_call();
94template <
typename T,
typename Allocator>
100 && std::alignment_of<functor_padding>::value % std::alignment_of<T>::value == 0
102 && std::is_nothrow_move_constructible<T>::value
111template <
typename Result,
typename Class,
typename... Arguments>
113 return std::mem_fn(
func);
115template <
typename Result,
typename Class,
typename... Arguments>
116auto to_functor(Result (Class::*
func)(Arguments...)
const) ->
decltype(std::mem_fn(
func)) {
117 return std::mem_fn(
func);
129template <
typename Result,
typename... Arguments>
130bool is_null(Result (*
const& function_pointer)(Arguments...)) {
131 return function_pointer ==
nullptr;
133template <
typename Result,
typename Class,
typename... Arguments>
134bool is_null(Result (Class::*
const& function_pointer)(Arguments...)) {
135 return function_pointer ==
nullptr;
137template <
typename Result,
typename Class,
typename... Arguments>
138bool is_null(Result (Class::*
const& function_pointer)(Arguments...)
const) {
139 return function_pointer ==
nullptr;
142template <
typename,
typename>
147template <
typename Result,
typename... Arguments>
152template <
typename T,
typename Result,
typename... Arguments>
156 static const bool value =
true;
158 template <
typename U>
159 static decltype(
to_functor(std::declval<U>())(std::declval<Arguments>()...))
check(U*);
163 static const bool value = std::is_convertible<decltype(check<T>(
nullptr)), Result>
::value;
170 template <
typename Allocator>
172 return reinterpret_cast<Allocator&
>(
manager);
174 template <
typename Allocator>
176 return reinterpret_cast<const Allocator&
>(
manager);
183template <
typename T,
typename Allocator,
typename Enable =
void>
185 template <
typename Result,
typename... Arguments>
189 return const_cast<T&
>(
reinterpret_cast<const T&
>(storage))(
FUNC_FORWARD(Arguments, arguments)...);
202 return const_cast<T&
>(
reinterpret_cast<const T&
>(storage.functor));
205template <
typename T,
typename Allocator>
209 typename
std::enable_if<!is_inplace_allocated<T, Allocator>::value>::type> {
210 template <
typename Result,
typename... Arguments>
214 return (*
reinterpret_cast<const typename std::allocator_traits<Allocator>::pointer&
>(storage))(
222 sizeof(
typename std::allocator_traits<Allocator>::pointer) <=
sizeof(self.
functor),
223 "The allocator's pointer type is too big");
224 typename std::allocator_traits<Allocator>::pointer* ptr =
225 new (&get_functor_ptr_ref(self))
typename std::allocator_traits<Allocator>::pointer(
226 std::allocator_traits<Allocator>::allocate(allocator, 1));
227 std::allocator_traits<Allocator>::construct(allocator, *ptr,
FUNC_FORWARD(T, to_store));
231 std::is_nothrow_move_constructible<typename std::allocator_traits<Allocator>::pointer>::value,
232 "we can't offer a noexcept swap if the pointer type is not nothrow move constructible");
233 new (&get_functor_ptr_ref(lhs))
234 typename std::allocator_traits<Allocator>::pointer(
FUNC_MOVE(get_functor_ptr_ref(rhs)));
236 get_functor_ptr_ref(rhs) =
nullptr;
239 typename std::allocator_traits<Allocator>::pointer& pointer = get_functor_ptr_ref(storage);
240 if (!pointer)
return;
241 std::allocator_traits<Allocator>::destroy(allocator, pointer);
242 std::allocator_traits<Allocator>::deallocate(allocator, pointer, 1);
245 return *get_functor_ptr_ref(storage);
249 return reinterpret_cast<typename std::allocator_traits<Allocator>::pointer&
>(storage.functor);
253 return reinterpret_cast<const typename std::allocator_traits<Allocator>::pointer&
>(storage.functor);
257template <
typename T,
typename Allocator>
260template <
typename T,
typename Allocator>
263 storage.
manager = &get_default_manager<T, Allocator>();
269 template <
typename T,
typename Allocator>
276 {&templated_call_move_and_destroy<T, Allocator>,
277 &templated_call_copy<T, Allocator>,
278 &templated_call_copy_functor_only<T, Allocator>,
279 &templated_call_destroy<T, Allocator>,
281 &templated_call_type_id<T, Allocator>,
282 &templated_call_target<T, Allocator>
299 template <
typename T,
typename Allocator>
302 specialization::move_functor(lhs,
FUNC_MOVE(rhs));
303 specialization::destroy_functor(rhs.get_allocator<Allocator>(), rhs);
304 create_manager<T, Allocator>(lhs,
FUNC_MOVE(rhs.get_allocator<Allocator>()));
305 rhs.get_allocator<Allocator>().~Allocator();
307 template <
typename T,
typename Allocator>
310 create_manager<T, Allocator>(lhs, Allocator(rhs.
get_allocator<Allocator>()));
311 specialization::store_functor(lhs, specialization::get_functor_ref(rhs));
313 template <
typename T,
typename Allocator>
316 specialization::destroy_functor(self.
get_allocator<Allocator>(), self);
319 template <
typename T,
typename Allocator>
322 specialization::store_functor(lhs, specialization::get_functor_ref(rhs));
325 template <
typename T,
typename>
329 template <
typename T,
typename Allocator>
332 if (type ==
typeid(T))
333 return &specialization::get_functor_ref(self);
339template <
typename T,
typename Allocator>
342 return default_manager;
345template <
typename Result,
typename...>
349template <
typename Result,
typename Argument>
354template <
typename Result,
typename First_Argument,
typename Second_Argument>
362template <
typename Result,
typename... Arguments>
372 other.manager_storage.manager->call_copy(manager_storage, other.manager_storage);
374 template <
typename T>
377 typename std::enable_if<
389 template <
typename Allocator>
390 function(std::allocator_arg_t,
const Allocator&) {
394 template <
typename Allocator>
395 function(std::allocator_arg_t,
const Allocator&, std::nullptr_t) {
399 template <
typename Allocator,
typename T>
401 std::allocator_arg_t,
402 const Allocator& allocator,
404 typename std::enable_if<
405 detail::is_valid_function_argument<T, Result(Arguments...)>::value,
414 template <
typename Allocator>
415 function(std::allocator_arg_t,
const Allocator& allocator,
const function& other) : call(other.call) {
416 typedef typename std::allocator_traits<Allocator>::template rebind_alloc<function> MyAllocator;
420 &detail::get_default_manager<typename std::allocator_traits<Allocator>::value_type, Allocator>();
421 if (other.manager_storage.manager == manager_for_allocator) {
422 detail::create_manager<typename std::allocator_traits<Allocator>::value_type, Allocator>(
423 manager_storage, Allocator(allocator));
430 detail::manager_type manager_for_function = &detail::get_default_manager<function, MyAllocator>();
431 if (other.manager_storage.manager == manager_for_function) {
432 detail::create_manager<function, MyAllocator>(manager_storage, MyAllocator(allocator));
433 manager_for_function->call_copy_functor_only(manager_storage, other.manager_storage);
437 initialize(other, MyAllocator(allocator));
441 template <
typename Allocator>
442 function(std::allocator_arg_t,
const Allocator&, function&& other)
FUNC_NOEXCEPT {
452 ~function()
FUNC_NOEXCEPT { manager_storage.manager->call_destroy(manager_storage); }
454 Result operator()(Arguments... arguments)
const {
455 return call(manager_storage.functor,
FUNC_FORWARD(Arguments, arguments)...);
458 template <
typename T,
typename Allocator>
460 function(std::allocator_arg, allocator, functor).swap(*
this);
464 detail::manager_storage_type temp_storage;
465 other.manager_storage.manager->call_move_and_destroy(temp_storage,
FUNC_MOVE(other.manager_storage));
466 manager_storage.manager->call_move_and_destroy(other.manager_storage,
FUNC_MOVE(manager_storage));
467 temp_storage.manager->call_move_and_destroy(manager_storage,
FUNC_MOVE(temp_storage));
469 std::swap(call, other.call);
474 return manager_storage.manager->call_type_id();
476 template <
typename T>
478 return static_cast<T*
>(manager_storage.manager->call_target(manager_storage,
typeid(T)));
480 template <
typename T>
482 return static_cast<const T*
>(manager_storage.manager->call_target(manager_storage,
typeid(T)));
488#ifdef FUNC_NO_EXCEPTIONS
489 return call !=
nullptr;
491 return call != &detail::empty_call<Result, Arguments...>;
496 detail::manager_storage_type manager_storage;
499 template <
typename T,
typename Allocator>
502 detail::create_manager<T, Allocator>(manager_storage,
FUNC_FORWARD(Allocator, allocator));
507 typedef Result (*Empty_Function_Type)(Arguments...);
509 typedef std::allocator<Empty_Function_Type> Allocator;
512 "The empty function should benefit from small functor optimization");
514 detail::create_manager<Empty_Function_Type, Allocator>(manager_storage, Allocator());
516 manager_storage,
nullptr);
517#ifdef FUNC_NO_EXCEPTIONS
520 call = &detail::empty_call<Result, Arguments...>;
550template <
typename Result,
typename... Arguments,
typename Allocator>
551struct uses_allocator<
func::function<Result(Arguments...)>, Allocator> : std::true_type {};
564#pragma GCC diagnostic pop
567#undef FUNC_TEMPLATE_NOEXCEPT
function(const function &other)
Definition: function.h:371
void initialize(T functor, Allocator &&allocator)
Definition: function.h:500
function() FUNC_NOEXCEPT
Definition: function.h:365
function(T functor, typename std::enable_if< detail::is_valid_function_argument< T, Result(Arguments...)>::value, detail::empty_struct >::type=detail::empty_struct()) FUNC_TEMPLATE_NOEXCEPT(T
function(std::nullptr_t) FUNC_NOEXCEPT
Definition: function.h:366
function(function &&other) FUNC_NOEXCEPT
Definition: function.h:367
void initialize_empty() FUNC_NOEXCEPT
Definition: function.h:508
Definition: function.h:74
#define FUNC_CONSTEXPR
Definition: function.h:53
#define FUNC_FORWARD(type, value)
Definition: function.h:61
#define FUNC_TEMPLATE_NOEXCEPT(FUNCTOR, ALLOCATOR)
Definition: function.h:52
#define FUNC_MOVE(value)
Definition: function.h:60
#define FUNC_NOEXCEPT
Definition: function.h:51
bool is_null(const T &)
Definition: function.h:126
T to_functor(T &&func)
Definition: function.h:108
const function_manager * manager_type
Definition: function.h:167
static const function_manager & get_default_manager()
Definition: function.h:340
static void create_manager(manager_storage_type &storage, Allocator &&allocator)
Definition: function.h:261
Definition: function.h:63
void swap(function< T > &lhs, function< T > &rhs)
Definition: function.h:543
bool operator!=(std::nullptr_t, const function< T > &rhs) FUNC_NOEXCEPT
Definition: function.h:534
bool operator==(std::nullptr_t, const function< T > &rhs) FUNC_NOEXCEPT
Definition: function.h:526
Definition: function.h:549
Definition: function.h:85
static void destroy_functor(Allocator &allocator, manager_storage_type &storage) FUNC_NOEXCEPT
Definition: function.h:238
static const std::allocator_traits< Allocator >::pointer & get_functor_ptr_ref(const manager_storage_type &storage) FUNC_NOEXCEPT
Definition: function.h:251
static void move_functor(manager_storage_type &lhs, manager_storage_type &&rhs) FUNC_NOEXCEPT
Definition: function.h:229
static std::allocator_traits< Allocator >::pointer & get_functor_ptr_ref(manager_storage_type &storage) FUNC_NOEXCEPT
Definition: function.h:247
static T & get_functor_ref(const manager_storage_type &storage) FUNC_NOEXCEPT
Definition: function.h:244
static Result call(const functor_padding &storage, Arguments... arguments)
Definition: function.h:211
static void store_functor(manager_storage_type &self, T to_store)
Definition: function.h:218
Definition: function.h:184
static void move_functor(manager_storage_type &lhs, manager_storage_type &&rhs) FUNC_NOEXCEPT
Definition: function.h:195
static void store_functor(manager_storage_type &storage, T to_store)
Definition: function.h:192
static Result call(const functor_padding &storage, Arguments... arguments)
Definition: function.h:186
static T & get_functor_ref(const manager_storage_type &storage) FUNC_NOEXCEPT
Definition: function.h:201
static void destroy_functor(Allocator &, manager_storage_type &storage) FUNC_NOEXCEPT
Definition: function.h:198
Definition: function.h:268
static void templated_call_copy(manager_storage_type &lhs, const manager_storage_type &rhs)
Definition: function.h:308
static FUNC_CONSTEXPR function_manager create_default_manager()
Definition: function.h:270
void(*const call_copy)(manager_storage_type &lhs, const manager_storage_type &rhs)
Definition: function.h:291
static void templated_call_destroy(manager_storage_type &self)
Definition: function.h:314
static void templated_call_copy_functor_only(manager_storage_type &lhs, const manager_storage_type &rhs)
Definition: function.h:320
static void * templated_call_target(const manager_storage_type &self, const std::type_info &type)
Definition: function.h:330
void(*const call_move_and_destroy)(manager_storage_type &lhs, manager_storage_type &&rhs)
Definition: function.h:290
const std::type_info &(*const call_type_id)()
Definition: function.h:295
static const std::type_info & templated_call_type_id()
Definition: function.h:326
void(*const call_copy_functor_only)(manager_storage_type &lhs, const manager_storage_type &rhs)
Definition: function.h:292
void(*const call_destroy)(manager_storage_type &manager)
Definition: function.h:293
void *(*const call_target)(const manager_storage_type &manager, const std::type_info &type)
Definition: function.h:296
static void templated_call_move_and_destroy(manager_storage_type &lhs, manager_storage_type &&rhs)
Definition: function.h:300
Definition: function.h:79
size_t padding_second
Definition: function.h:82
size_t padding_first
Definition: function.h:81
Definition: function.h:121
decltype(to_functor(std::declval< T >())) type
Definition: function.h:122
Definition: function.h:95
static const bool value
Definition: function.h:98
static decltype(to_functor(std::declval< U >())(std::declval< Arguments >()...)) check(U *)
static empty_struct check(...)
Definition: function.h:143
static const bool value
Definition: function.h:144
Definition: function.h:169
const Allocator & get_allocator() const FUNC_NOEXCEPT
Definition: function.h:175
Allocator & get_allocator() FUNC_NOEXCEPT
Definition: function.h:171
manager_type manager
Definition: function.h:180
functor_padding functor
Definition: function.h:179
Argument argument_type
Definition: function.h:352
Result result_type
Definition: function.h:351
Second_Argument second_argument_type
Definition: function.h:358
First_Argument first_argument_type
Definition: function.h:357
Result result_type
Definition: function.h:356
Definition: function.h:346
Result result_type
Definition: function.h:347
Definition: function.h:71