lambda2.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #ifndef BOOST_LAMBDA2_LAMBDA2_HPP_INCLUDED
  2. #define BOOST_LAMBDA2_LAMBDA2_HPP_INCLUDED
  3. // Copyright 2020, 2021 Peter Dimov
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. #include <functional>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <tuple>
  10. #include <cstddef>
  11. #include <iosfwd>
  12. // Same format as BOOST_VERSION:
  13. // major * 100000 + minor * 100 + patch
  14. #define BOOST_LAMBDA2_VERSION 108500
  15. namespace boost
  16. {
  17. namespace lambda2
  18. {
  19. namespace lambda2_detail
  20. {
  21. struct subscript
  22. {
  23. template<class T1, class T2> decltype(auto) operator()(T1&& t1, T2&& t2) const
  24. {
  25. return std::forward<T1>(t1)[ std::forward<T2>(t2) ];
  26. }
  27. };
  28. template<int I> struct get
  29. {
  30. template<class T> decltype(auto) operator()( T&& t ) const
  31. {
  32. return std::get<I>( std::forward<T>(t) );
  33. }
  34. };
  35. } // namespace lambda2_detail
  36. // placeholders
  37. template<int I> struct lambda2_arg
  38. {
  39. template<class... A> decltype(auto) operator()( A&&... a ) const noexcept
  40. {
  41. return std::get<std::size_t{I-1}>( std::tuple<A&&...>( std::forward<A>(a)... ) );
  42. }
  43. template<class T> auto operator[]( T&& t ) const
  44. {
  45. return std::bind( lambda2_detail::subscript(), *this, std::forward<T>( t ) );
  46. }
  47. };
  48. #if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L
  49. # define BOOST_LAMBDA2_INLINE_VAR inline
  50. #else
  51. # define BOOST_LAMBDA2_INLINE_VAR
  52. #endif
  53. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<1> _1{};
  54. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<2> _2{};
  55. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<3> _3{};
  56. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<4> _4{};
  57. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<5> _5{};
  58. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<6> _6{};
  59. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<7> _7{};
  60. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<8> _8{};
  61. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_arg<9> _9{};
  62. // first, second
  63. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_detail::get<0> first{};
  64. BOOST_LAMBDA2_INLINE_VAR constexpr lambda2_detail::get<1> second{};
  65. #undef BOOST_LAMBDA2_INLINE_VAR
  66. } // namespace lambda2
  67. } // namespace boost
  68. namespace std
  69. {
  70. template<int I> struct is_placeholder< boost::lambda2::lambda2_arg<I> >: integral_constant<int, I>
  71. {
  72. };
  73. } // namespace std
  74. namespace boost
  75. {
  76. namespace lambda2
  77. {
  78. namespace lambda2_detail
  79. {
  80. // additional function objects
  81. #define BOOST_LAMBDA2_UNARY_FN(op, fn) \
  82. struct fn \
  83. { \
  84. template<class T> decltype(auto) operator()(T&& t) const \
  85. { \
  86. return op std::forward<T>(t); \
  87. } \
  88. };
  89. #define BOOST_LAMBDA2_POSTFIX_FN(op, fn) \
  90. struct fn \
  91. { \
  92. template<class T> decltype(auto) operator()(T&& t) const \
  93. { \
  94. return std::forward<T>(t) op; \
  95. } \
  96. };
  97. #define BOOST_LAMBDA2_BINARY_FN(op, fn) \
  98. struct fn \
  99. { \
  100. template<class T1, class T2> decltype(auto) operator()(T1&& t1, T2&& t2) const \
  101. { \
  102. return std::forward<T1>(t1) op std::forward<T2>(t2); \
  103. } \
  104. };
  105. BOOST_LAMBDA2_BINARY_FN(<<, left_shift)
  106. BOOST_LAMBDA2_BINARY_FN(>>, right_shift)
  107. BOOST_LAMBDA2_UNARY_FN(+, unary_plus)
  108. BOOST_LAMBDA2_UNARY_FN(*, dereference)
  109. BOOST_LAMBDA2_UNARY_FN(++, increment)
  110. BOOST_LAMBDA2_UNARY_FN(--, decrement)
  111. BOOST_LAMBDA2_POSTFIX_FN(++, postfix_increment)
  112. BOOST_LAMBDA2_POSTFIX_FN(--, postfix_decrement)
  113. BOOST_LAMBDA2_BINARY_FN(+=, plus_equal)
  114. BOOST_LAMBDA2_BINARY_FN(-=, minus_equal)
  115. BOOST_LAMBDA2_BINARY_FN(*=, multiplies_equal)
  116. BOOST_LAMBDA2_BINARY_FN(/=, divides_equal)
  117. BOOST_LAMBDA2_BINARY_FN(%=, modulus_equal)
  118. BOOST_LAMBDA2_BINARY_FN(&=, bit_and_equal)
  119. BOOST_LAMBDA2_BINARY_FN(|=, bit_or_equal)
  120. BOOST_LAMBDA2_BINARY_FN(^=, bit_xor_equal)
  121. BOOST_LAMBDA2_BINARY_FN(<<=, left_shift_equal)
  122. BOOST_LAMBDA2_BINARY_FN(>>=, right_shift_equal)
  123. // operators
  124. template<class T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
  125. template<class T, class T2 = remove_cvref_t<T>> using is_lambda_expression =
  126. std::integral_constant<bool, std::is_placeholder<T2>::value || std::is_bind_expression<T2>::value>;
  127. template<class A> using enable_unary_lambda =
  128. std::enable_if_t<is_lambda_expression<A>::value>;
  129. template<class A, class B> using enable_binary_lambda =
  130. std::enable_if_t<is_lambda_expression<A>::value || is_lambda_expression<B>::value>;
  131. template<class T> using is_stream = std::is_base_of<std::ios_base, remove_cvref_t<T>>;
  132. } // namespace lambda2_detail
  133. #define BOOST_LAMBDA2_UNARY_LAMBDA(op, fn) \
  134. template<class A, class = lambda2_detail::enable_unary_lambda<A>> \
  135. auto operator op( A&& a ) \
  136. { \
  137. return std::bind( fn(), std::forward<A>(a) ); \
  138. }
  139. #define BOOST_LAMBDA2_POSTFIX_LAMBDA(op, fn) \
  140. template<class A, class = lambda2_detail::enable_unary_lambda<A>> \
  141. auto operator op( A&& a, int ) \
  142. { \
  143. return std::bind( fn(), std::forward<A>(a) ); \
  144. }
  145. #define BOOST_LAMBDA2_BINARY_LAMBDA(op, fn) \
  146. template<class A, class B, class = lambda2_detail::enable_binary_lambda<A, B>> \
  147. auto operator op( A&& a, B&& b ) \
  148. { \
  149. return std::bind( fn(), std::forward<A>(a), std::forward<B>(b) ); \
  150. }
  151. // standard
  152. BOOST_LAMBDA2_BINARY_LAMBDA(+, std::plus<>)
  153. BOOST_LAMBDA2_BINARY_LAMBDA(-, std::minus<>)
  154. BOOST_LAMBDA2_BINARY_LAMBDA(*, std::multiplies<>)
  155. BOOST_LAMBDA2_BINARY_LAMBDA(/, std::divides<>)
  156. BOOST_LAMBDA2_BINARY_LAMBDA(%, std::modulus<>)
  157. BOOST_LAMBDA2_UNARY_LAMBDA(-, std::negate<>)
  158. BOOST_LAMBDA2_BINARY_LAMBDA(==, std::equal_to<>)
  159. BOOST_LAMBDA2_BINARY_LAMBDA(!=, std::not_equal_to<>)
  160. BOOST_LAMBDA2_BINARY_LAMBDA(>, std::greater<>)
  161. BOOST_LAMBDA2_BINARY_LAMBDA(<, std::less<>)
  162. BOOST_LAMBDA2_BINARY_LAMBDA(>=, std::greater_equal<>)
  163. BOOST_LAMBDA2_BINARY_LAMBDA(<=, std::less_equal<>)
  164. BOOST_LAMBDA2_BINARY_LAMBDA(&&, std::logical_and<>)
  165. BOOST_LAMBDA2_BINARY_LAMBDA(||, std::logical_or<>)
  166. BOOST_LAMBDA2_UNARY_LAMBDA(!, std::logical_not<>)
  167. BOOST_LAMBDA2_BINARY_LAMBDA(&, std::bit_and<>)
  168. BOOST_LAMBDA2_BINARY_LAMBDA(|, std::bit_or<>)
  169. BOOST_LAMBDA2_BINARY_LAMBDA(^, std::bit_xor<>)
  170. BOOST_LAMBDA2_UNARY_LAMBDA(~, std::bit_not<>)
  171. // additional
  172. BOOST_LAMBDA2_UNARY_LAMBDA(+, lambda2_detail::unary_plus)
  173. BOOST_LAMBDA2_UNARY_LAMBDA(*, lambda2_detail::dereference)
  174. BOOST_LAMBDA2_UNARY_LAMBDA(++, lambda2_detail::increment)
  175. BOOST_LAMBDA2_UNARY_LAMBDA(--, lambda2_detail::decrement)
  176. BOOST_LAMBDA2_POSTFIX_LAMBDA(++, lambda2_detail::postfix_increment)
  177. BOOST_LAMBDA2_POSTFIX_LAMBDA(--, lambda2_detail::postfix_decrement)
  178. // compound assignment
  179. BOOST_LAMBDA2_BINARY_LAMBDA(+=, lambda2_detail::plus_equal)
  180. BOOST_LAMBDA2_BINARY_LAMBDA(-=, lambda2_detail::minus_equal)
  181. BOOST_LAMBDA2_BINARY_LAMBDA(*=, lambda2_detail::multiplies_equal)
  182. BOOST_LAMBDA2_BINARY_LAMBDA(/=, lambda2_detail::divides_equal)
  183. BOOST_LAMBDA2_BINARY_LAMBDA(%=, lambda2_detail::modulus_equal)
  184. BOOST_LAMBDA2_BINARY_LAMBDA(&=, lambda2_detail::bit_and_equal)
  185. BOOST_LAMBDA2_BINARY_LAMBDA(|=, lambda2_detail::bit_or_equal)
  186. BOOST_LAMBDA2_BINARY_LAMBDA(^=, lambda2_detail::bit_xor_equal)
  187. BOOST_LAMBDA2_BINARY_LAMBDA(<<=, lambda2_detail::left_shift_equal)
  188. BOOST_LAMBDA2_BINARY_LAMBDA(>>=, lambda2_detail::right_shift_equal)
  189. // operator<<
  190. template<class A, class = std::enable_if_t<!lambda2_detail::is_stream<A>::value>,
  191. class B, class = lambda2_detail::enable_binary_lambda<A, B>>
  192. auto operator<<( A&& a, B&& b )
  193. {
  194. return std::bind( lambda2_detail::left_shift(), std::forward<A>(a), std::forward<B>(b) );
  195. }
  196. template<class A, class = std::enable_if_t<lambda2_detail::is_stream<A>::value>,
  197. class B, class = lambda2_detail::enable_unary_lambda<B>>
  198. auto operator<<( A& a, B&& b )
  199. {
  200. return std::bind( lambda2_detail::left_shift(), std::ref(a), std::forward<B>(b) );
  201. }
  202. // operator>>
  203. template<class A, class = std::enable_if_t<!lambda2_detail::is_stream<A>::value>,
  204. class B, class = lambda2_detail::enable_binary_lambda<A, B>>
  205. auto operator>>( A&& a, B&& b )
  206. {
  207. return std::bind( lambda2_detail::right_shift(), std::forward<A>(a), std::forward<B>(b) );
  208. }
  209. template<class A, class = std::enable_if_t<lambda2_detail::is_stream<A>::value>,
  210. class B, class = lambda2_detail::enable_unary_lambda<B>>
  211. auto operator>>( A& a, B&& b )
  212. {
  213. return std::bind( lambda2_detail::right_shift(), std::ref(a), std::forward<B>(b) );
  214. }
  215. // operator->*
  216. template<class A, class B, class = lambda2_detail::enable_unary_lambda<A>>
  217. auto operator->*( A&& a, B&& b )
  218. {
  219. return std::bind( std::forward<B>(b), std::forward<A>(a) );
  220. }
  221. } // namespace lambda2
  222. } // namespace boost
  223. #endif // #ifndef BOOST_LAMBDA2_LAMBDA2_HPP_INCLUDED