1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 #include "td/utils/common.h"
10 
11 #include <functional>
12 #include <tuple>
13 #include <type_traits>
14 #include <utility>
15 
16 namespace td {
17 
18 namespace detail {
19 
20 template <std::size_t... S>
21 struct IntSeq {};
22 
23 template <std::size_t L, std::size_t N, std::size_t... S>
24 struct IntSeqGen : IntSeqGen<L, N - 1, L + N - 1, S...> {};
25 
26 template <std::size_t L, std::size_t... S>
27 struct IntSeqGen<L, 0, S...> {
28   using type = IntSeq<S...>;
29 };
30 
31 template <bool... Args>
32 class LogicAndImpl {};
33 
34 template <bool Res, bool X, bool... Args>
35 class LogicAndImpl<Res, X, Args...> {
36  public:
37   static constexpr bool value = LogicAndImpl<(Res && X), Args...>::value;
38 };
39 
40 template <bool Res>
41 class LogicAndImpl<Res> {
42  public:
43   static constexpr bool value = Res;
44 };
45 
46 template <std::size_t N>
47 using IntRange = typename IntSeqGen<0, N>::type;
48 
49 template <class T>
50 struct is_reference_wrapper : std::false_type {};
51 
52 template <class U>
53 struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};
54 
55 template <class Base, class T, class Derived, class... Args>
56 auto invoke_impl(T Base::*pmf, Derived &&ref,
57                  Args &&... args) noexcept(noexcept((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...)))
58     -> std::enable_if_t<std::is_function<T>::value && std::is_base_of<Base, std::decay<Derived>>::value,
59                         decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))> {
60   return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...);
61 }
62 
63 template <class Base, class T, class RefWrap, class... Args>
64 auto invoke_impl(T Base::*pmf, RefWrap &&ref,
65                  Args &&... args) noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...)))
66     -> std::enable_if_t<std::is_function<T>::value && is_reference_wrapper<std::decay_t<RefWrap>>::value,
67                         decltype((ref.get().*pmf)(std::forward<Args>(args)...))>
68 
69 {
70   return (ref.get().*pmf)(std::forward<Args>(args)...);
71 }
72 
73 template <class Base, class T, class Pointer, class... Args>
74 auto invoke_impl(T Base::*pmf, Pointer &&ptr,
75                  Args &&... args) noexcept(noexcept(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...)))
76     -> std::enable_if_t<std::is_function<T>::value && !is_reference_wrapper<std::decay_t<Pointer>>::value &&
77                             !std::is_base_of<Base, std::decay_t<Pointer>>::value,
78                         decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))> {
79   return ((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...);
80 }
81 
82 template <class Base, class T, class Derived>
83 auto invoke_impl(T Base::*pmd, Derived &&ref) noexcept(noexcept(std::forward<Derived>(ref).*pmd))
84     -> std::enable_if_t<!std::is_function<T>::value && std::is_base_of<Base, std::decay_t<Derived>>::value,
85                         decltype(std::forward<Derived>(ref).*pmd)> {
86   return std::forward<Derived>(ref).*pmd;
87 }
88 
89 template <class Base, class T, class RefWrap>
90 auto invoke_impl(T Base::*pmd, RefWrap &&ref) noexcept(noexcept(ref.get().*pmd))
91     -> std::enable_if_t<!std::is_function<T>::value && is_reference_wrapper<std::decay_t<RefWrap>>::value,
92                         decltype(ref.get().*pmd)> {
93   return ref.get().*pmd;
94 }
95 
96 template <class Base, class T, class Pointer>
97 auto invoke_impl(T Base::*pmd, Pointer &&ptr) noexcept(noexcept((*std::forward<Pointer>(ptr)).*pmd))
98     -> std::enable_if_t<!std::is_function<T>::value && !is_reference_wrapper<std::decay_t<Pointer>>::value &&
99                             !std::is_base_of<Base, std::decay_t<Pointer>>::value,
100                         decltype((*std::forward<Pointer>(ptr)).*pmd)> {
101   return (*std::forward<Pointer>(ptr)).*pmd;
102 }
103 
104 template <class F, class... Args>
105 auto invoke_impl(F &&f, Args &&... args) noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...)))
106     -> std::enable_if_t<!std::is_member_pointer<std::decay_t<F>>::value,
107                         decltype(std::forward<F>(f)(std::forward<Args>(args)...))> {
108   return std::forward<F>(f)(std::forward<Args>(args)...);
109 }
110 
111 template <class F, class... ArgTypes>
112 auto invoke(F &&f,
113             ArgTypes &&... args) noexcept(noexcept(invoke_impl(std::forward<F>(f), std::forward<ArgTypes>(args)...)))
114     -> decltype(invoke_impl(std::forward<F>(f), std::forward<ArgTypes>(args)...)) {
115   return invoke_impl(std::forward<F>(f), std::forward<ArgTypes>(args)...);
116 }
117 
118 template <class F, class... Args, std::size_t... S>
119 auto call_tuple_impl(F &&func, std::tuple<Args...> &&tuple, IntSeq<S...>) {
120   return func(std::forward<Args>(std::get<S>(tuple))...);
121 }
122 
123 template <class... Args, std::size_t... S>
124 auto invoke_tuple_impl(std::tuple<Args...> &&tuple, IntSeq<S...>) {
125   return invoke(std::forward<Args>(std::get<S>(tuple))...);
126 }
127 
128 template <class ActorT, class F, class... Args, std::size_t... S>
129 auto mem_call_tuple_impl(ActorT *actor, std::tuple<F, Args...> &&tuple, IntSeq<0, S...>) {
130   return (actor->*std::get<0>(tuple))(std::forward<Args>(std::get<S>(tuple))...);
131 }
132 
133 template <class F, class... Args, std::size_t... S>
134 void tuple_for_each_impl(std::tuple<Args...> &tuple, const F &func, IntSeq<S...>) {
135   const auto &dummy = {0, (func(std::get<S>(tuple)), 0)...};
136   (void)dummy;
137 }
138 
139 template <class F, class... Args, std::size_t... S>
140 void tuple_for_each_impl(const std::tuple<Args...> &tuple, const F &func, IntSeq<S...>) {
141   const auto &dummy = {0, (func(std::get<S>(tuple)), 0)...};
142   (void)dummy;
143 }
144 
145 }  // namespace detail
146 
147 template <bool... Args>
148 class LogicAnd {
149  public:
150   static constexpr bool value = detail::LogicAndImpl<true, Args...>::value;
151 };
152 
153 template <class F, class... Args>
154 auto call_tuple(F &&func, std::tuple<Args...> &&tuple) {
155   return detail::call_tuple_impl(func, std::move(tuple), detail::IntRange<sizeof...(Args)>());
156 }
157 
158 template <class... Args>
159 auto invoke_tuple(std::tuple<Args...> &&tuple) {
160   return detail::invoke_tuple_impl(std::move(tuple), detail::IntRange<sizeof...(Args)>());
161 }
162 
163 template <class ActorT, class... Args>
164 auto mem_call_tuple(ActorT *actor, std::tuple<Args...> &&tuple) {
165   return detail::mem_call_tuple_impl(actor, std::move(tuple), detail::IntRange<sizeof...(Args)>());
166 }
167 
168 template <class F, class... Args>
169 void tuple_for_each(std::tuple<Args...> &tuple, const F &func) {
170   detail::tuple_for_each_impl(tuple, func, detail::IntRange<sizeof...(Args)>());
171 }
172 
173 template <class F, class... Args>
174 void tuple_for_each(const std::tuple<Args...> &tuple, const F &func) {
175   detail::tuple_for_each_impl(tuple, func, detail::IntRange<sizeof...(Args)>());
176 }
177 
178 template <size_t N, class Arg, class... Args, std::enable_if_t<N == 0, int> = 0>
179 auto &&get_nth_argument(Arg &&arg, Args &&... args) {
180   return std::forward<Arg>(arg);
181 }
182 
183 template <size_t N, class Arg, class... Args, std::enable_if_t<N != 0, int> = 0>
184 auto &&get_nth_argument(Arg &&arg, Args &&... args) {
185   return get_nth_argument<N - 1>(std::forward<Args &&>(args)...);
186 }
187 
188 template <class... Args>
189 auto &&get_last_argument(Args &&... args) {
190   return get_nth_argument<sizeof...(Args) - 1>(std::forward<Args &&>(args)...);
191 }
192 
193 namespace detail {
194 template <class F, class... Args, std::size_t... S>
195 auto call_n_arguments_impl(IntSeq<S...>, F &&f, Args &&... args) {
196   return f(get_nth_argument<S>(std::forward<Args>(args)...)...);
197 }
198 }  // namespace detail
199 
200 template <size_t N, class F, class... Args>
201 auto call_n_arguments(F &&f, Args &&... args) {
202   return detail::call_n_arguments_impl(detail::IntRange<N>(), f, std::forward<Args>(args)...);
203 }
204 
205 template <class F, class X, class = void>
206 struct is_callable final : public std::false_type {};
207 template <class F, class X>
208 struct is_callable<F, X, decltype(std::declval<F>()(std::declval<X>()))> final : public std::true_type {};
209 
210 }  // namespace td
211