File indexing completed on 2024-05-19 05:33:31

0001 /*
0002     SPDX-FileCopyrightText: 2019 Ivan Čukić <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef UTILS_FRONT_BIND_H
0008 #define UTILS_FRONT_BIND_H
0009 
0010 namespace std_ex {
0011 
0012 // bind_front is based on http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0356r3.html
0013 
0014 template <typename T> struct decay_unwrap;
0015 
0016 template <typename T> struct decay_unwrap<std::reference_wrapper<T>> {
0017     using type = T &;
0018 };
0019 
0020 template <typename T>
0021 struct decay_unwrap
0022     : std::conditional_t<!std::is_same<std::decay_t<T>, T>::value,
0023                          decay_unwrap<std::decay_t<T>>, std::decay<T>> {
0024 };
0025 
0026 template <typename T> using decay_unwrap_t = typename decay_unwrap<T>::type;
0027 
0028 template <typename Func, typename BoundArgsTuple, typename... CallArgs>
0029 decltype(auto) bind_front_caller(Func &&func, BoundArgsTuple &&boundArgsTuple,
0030                                  CallArgs &&... callArgs)
0031 {
0032     return std::apply(
0033         [&func, &callArgs...](auto &&... boundArgs) -> decltype(auto) {
0034             return std::invoke(std::forward<Func>(func),
0035                                std::forward<decltype(boundArgs)>(boundArgs)...,
0036                                std::forward<CallArgs>(callArgs)...);
0037         },
0038         std::forward<BoundArgsTuple>(boundArgsTuple));
0039 }
0040 
0041 template <typename Func, typename... BoundArgs> class bind_front_t {
0042 public:
0043     template <
0044         typename F, typename... BA,
0045         std::enable_if_t<!(sizeof...(BA) == 0
0046                            && std::is_base_of_v<bind_front_t, std::decay_t<F>>),
0047                          bool> = true>
0048     explicit bind_front_t(F &&f, BA &&... ba)
0049         : func(std::forward<F>(f)), boundArgs(std::forward<BA>(ba)...)
0050     {
0051     }
0052 
0053     template <typename... CallArgs>
0054         auto operator()(CallArgs &&... callArgs)
0055         & noexcept(
0056               std::is_nothrow_invocable_v<Func &, BoundArgs &..., CallArgs...>)
0057               -> std::invoke_result_t<Func &, BoundArgs &..., CallArgs...>
0058     {
0059         return bind_front_caller(func, boundArgs,
0060                                  std::forward<CallArgs>(callArgs)...);
0061     }
0062 
0063     template <typename... CallArgs>
0064     auto operator()(CallArgs &&... callArgs) const& noexcept(
0065         std::is_nothrow_invocable_v<const Func&, const BoundArgs&...,
0066                                     CallArgs...>)
0067         -> std::invoke_result_t<const Func&, const BoundArgs&..., CallArgs...>
0068     {
0069         return bind_front_caller(func, boundArgs,
0070                                  std::forward<CallArgs>(callArgs)...);
0071     }
0072 
0073     template <typename... CallArgs>
0074         auto operator()(CallArgs &&... callArgs)
0075         && noexcept(
0076                std::is_nothrow_invocable_v<Func, BoundArgs..., CallArgs...>)
0077                -> std::invoke_result_t<Func, BoundArgs..., CallArgs...>
0078     {
0079         return bind_front_caller(std::move(func), std::move(boundArgs),
0080                                  std::forward<CallArgs>(callArgs)...);
0081     }
0082 
0083     template <typename... CallArgs>
0084     auto operator()(CallArgs &&... callArgs) const&& noexcept(
0085         std::is_nothrow_invocable_v<const Func, const BoundArgs...,
0086                                     CallArgs...>)
0087         -> std::invoke_result_t<const Func, const BoundArgs..., CallArgs...>
0088     {
0089         return bind_front_caller(std::move(func), std::move(boundArgs),
0090                                  std::forward<CallArgs>(callArgs)...);
0091     }
0092 
0093 private:
0094     Func func;
0095     std::tuple<BoundArgs...> boundArgs;
0096 };
0097 
0098 template <typename Func, typename... BoundArgs>
0099 auto bind_front(Func &&func, BoundArgs &&... boundArgs)
0100 {
0101     return bind_front_t<std::decay_t<Func>, decay_unwrap_t<BoundArgs>...>{
0102         std::forward<Func>(func), std::forward<BoundArgs>(boundArgs)...
0103     };
0104 }
0105 
0106 } // namespace std_ex
0107 
0108 #endif // include guard
0109