mirror of
https://github.com/matrix-construct/construct
synced 2024-10-31 19:08:59 +01:00
120 lines
3.2 KiB
C++
120 lines
3.2 KiB
C++
// Matrix Construct
|
|
//
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
// full license for this software is available in the LICENSE file.
|
|
|
|
#pragma once
|
|
#define HAVE_IRCD_UTIL_CLOSURE_H
|
|
|
|
namespace ircd {
|
|
inline namespace util
|
|
{
|
|
template<template<class, class...>
|
|
class F,
|
|
class R,
|
|
class... A>
|
|
struct closure;
|
|
|
|
template<template<class, class...>
|
|
class F,
|
|
class... A>
|
|
struct closure<F, bool, A...>;
|
|
|
|
/// Template for creating callback-based iterations allowing closures of
|
|
/// either `void (...)` or `bool (...)` to be passed to the same overload.
|
|
///
|
|
/// This reduces/deduplicates interfaces which offer an overload for each
|
|
/// and thus two library symbols, usually just calling each other...
|
|
///
|
|
template<template<class, class...>
|
|
class F,
|
|
class... A>
|
|
using closure_bool = closure<F, bool, A...>;
|
|
|
|
template<class... A>
|
|
using function_bool = closure_bool<std::function, A...>;
|
|
}}
|
|
|
|
template<template<class, class...>
|
|
class F,
|
|
class R,
|
|
class... A>
|
|
struct ircd::util::closure
|
|
:F<R (A...)>
|
|
{
|
|
using proto_type = R (A...);
|
|
using func_type = F<proto_type>;
|
|
|
|
using func_type::func_type;
|
|
using func_type::operator=;
|
|
};
|
|
|
|
template<template<class, class...>
|
|
class F,
|
|
class... A>
|
|
struct ircd::util::closure<F, bool, A...>
|
|
:F<bool (A...)>
|
|
{
|
|
using proto_bool_type = bool (A...);
|
|
using proto_void_type = void (A...);
|
|
|
|
using func_bool_type = F<proto_bool_type>;
|
|
using func_void_type = F<proto_void_type>;
|
|
|
|
template<class lambda>
|
|
closure(lambda &&o,
|
|
typename std::enable_if<!std::is_constructible<func_bool_type, lambda>::value, int>::type = 0)
|
|
noexcept(std::is_nothrow_invocable<lambda, void, A...>());
|
|
|
|
template<class lambda>
|
|
closure(lambda &&o,
|
|
typename std::enable_if<std::is_constructible<func_bool_type, lambda>::value, int>::type = 0)
|
|
noexcept(std::is_nothrow_invocable<lambda, bool, A...>());
|
|
|
|
closure() = default;
|
|
};
|
|
|
|
template<template<class, class...>
|
|
class F,
|
|
class... A>
|
|
template<class lambda>
|
|
[[gnu::always_inline]]
|
|
inline
|
|
ircd::util::closure<F, bool, A...>::closure(lambda &&o,
|
|
typename std::enable_if<!std::is_constructible<func_bool_type, lambda>::value, int>::type)
|
|
noexcept(std::is_nothrow_invocable<lambda, void, A...>())
|
|
:F<bool (A...)>
|
|
{
|
|
[o(std::move(o))](A&&... a)
|
|
noexcept(std::is_nothrow_invocable<lambda, void, A...>())
|
|
{
|
|
static_assert
|
|
(
|
|
std::is_same<void, decltype(o(std::forward<A>(a)...))>()
|
|
);
|
|
|
|
o(std::forward<A>(a)...);
|
|
return true;
|
|
}
|
|
}
|
|
{}
|
|
|
|
template<template<class, class...>
|
|
class F,
|
|
class... A>
|
|
template<class lambda>
|
|
[[gnu::always_inline]]
|
|
inline
|
|
ircd::util::closure<F, bool, A...>::closure(lambda &&o,
|
|
typename std::enable_if<std::is_constructible<func_bool_type, lambda>::value, int>::type)
|
|
noexcept(std::is_nothrow_invocable<lambda, bool, A...>())
|
|
:F<bool (A...)>
|
|
{
|
|
std::forward<lambda>(o)
|
|
}
|
|
{}
|