summaryrefslogtreecommitdiff
path: root/boost/hana/functional/placeholder.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/hana/functional/placeholder.hpp')
-rw-r--r--boost/hana/functional/placeholder.hpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/boost/hana/functional/placeholder.hpp b/boost/hana/functional/placeholder.hpp
new file mode 100644
index 0000000000..71a25389cd
--- /dev/null
+++ b/boost/hana/functional/placeholder.hpp
@@ -0,0 +1,263 @@
+/*!
+@file
+Defines `boost::hana::_`.
+
+@copyright Louis Dionne 2013-2016
+Distributed under the Boost Software License, Version 1.0.
+(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
+ */
+
+#ifndef BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
+#define BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
+
+#include <boost/hana/basic_tuple.hpp>
+#include <boost/hana/config.hpp>
+#include <boost/hana/detail/create.hpp>
+#include <boost/hana/detail/decay.hpp>
+
+#include <cstddef>
+#include <utility>
+
+
+BOOST_HANA_NAMESPACE_BEGIN
+ //! @ingroup group-functional
+ //! Create simple functions representing C++ operators inline.
+ //!
+ //! Specifically, `_` is an object used as a placeholder to build
+ //! function objects representing calls to C++ operators. It works
+ //! by overloading the operators between `_` and any object so that
+ //! they return a function object which actually calls the corresponding
+ //! operator on its argument(s). Hence, for any supported operator `@`:
+ //! @code
+ //! (_ @ _)(x, y) == x @ y
+ //! @endcode
+ //!
+ //! Operators may also be partially applied to one argument inline:
+ //! @code
+ //! (x @ _)(y) == x @ y
+ //! (_ @ y)(x) == x @ y
+ //! @endcode
+ //!
+ //! When invoked with more arguments than required, functions created with
+ //! `_` will discard the superfluous instead of triggering an error:
+ //! @code
+ //! (_ @ _)(x, y, z...) == x @ y
+ //! @endcode
+ //!
+ //! This makes functions created with `_` easier to use in higher-order
+ //! algorithms, which sometime provide more information than necessary
+ //! to their callbacks.
+ //!
+ //! ### Supported operators
+ //! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-`
+ //! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>`
+ //! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
+ //! - %Logical: `||`, `&&`, `!`
+ //! - Member access: `*` (dereference), `[]` (array subscript)
+ //! - Other: `()` (function call)
+ //!
+ //! More complex functionality like the ability to compose placeholders
+ //! into larger function objects inline are not supported. This is on
+ //! purpose; you should either use C++14 generic lambdas or a library
+ //! like [Boost.Phoenix][] if you need bigger guns. The goal here is
+ //! to save you a couple of characters in simple situations.
+ //!
+ //! ### Example
+ //! @include example/functional/placeholder.cpp
+ //!
+ //! [Boost.Phoenix]: http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html
+#ifdef BOOST_HANA_DOXYGEN_INVOKED
+ constexpr unspecified _{};
+#else
+ namespace placeholder_detail {
+ template <typename I>
+ struct subscript {
+ I i;
+
+ template <typename Xs, typename ...Z>
+ constexpr auto operator()(Xs&& xs, Z const& ...) const&
+ -> decltype(static_cast<Xs&&>(xs)[i])
+ { return static_cast<Xs&&>(xs)[i]; }
+
+ template <typename Xs, typename ...Z>
+ constexpr auto operator()(Xs&& xs, Z const& ...) &
+ -> decltype(static_cast<Xs&&>(xs)[i])
+ { return static_cast<Xs&&>(xs)[i]; }
+
+ template <typename Xs, typename ...Z>
+ constexpr auto operator()(Xs&& xs, Z const& ...) &&
+ -> decltype(static_cast<Xs&&>(xs)[std::declval<I>()])
+ { return static_cast<Xs&&>(xs)[std::move(i)]; }
+ };
+
+ template <typename F, typename Xs, std::size_t ...i>
+ constexpr decltype(auto) invoke_impl(F&& f, Xs&& xs, std::index_sequence<i...>) {
+ return static_cast<F&&>(f)(hana::get_impl<i>(static_cast<Xs&&>(xs).storage_)...);
+ }
+
+ template <typename ...X>
+ struct invoke;
+
+ struct placeholder {
+ struct secret { };
+
+ template <typename X>
+ constexpr decltype(auto) operator[](X&& x) const
+ { return detail::create<subscript>{}(static_cast<X&&>(x)); }
+
+ template <typename ...X>
+ constexpr invoke<typename detail::decay<X>::type...>
+ operator()(X&& ...x) const {
+ return {secret{}, static_cast<X&&>(x)...};
+ }
+ };
+
+ template <typename ...X>
+ struct invoke {
+ template <typename ...Y>
+ constexpr invoke(placeholder::secret, Y&& ...y)
+ : storage_{static_cast<Y&&>(y)...}
+ { }
+
+ basic_tuple<X...> storage_;
+
+ template <typename F, typename ...Z>
+ constexpr auto operator()(F&& f, Z const& ...) const& -> decltype(
+ static_cast<F&&>(f)(std::declval<X const&>()...)
+ ) {
+ return invoke_impl(static_cast<F&&>(f), *this,
+ std::make_index_sequence<sizeof...(X)>{});
+ }
+
+ template <typename F, typename ...Z>
+ constexpr auto operator()(F&& f, Z const& ...) & -> decltype(
+ static_cast<F&&>(f)(std::declval<X&>()...)
+ ) {
+ return invoke_impl(static_cast<F&&>(f), *this,
+ std::make_index_sequence<sizeof...(X)>{});
+ }
+
+ template <typename F, typename ...Z>
+ constexpr auto operator()(F&& f, Z const& ...) && -> decltype(
+ static_cast<F&&>(f)(std::declval<X&&>()...)
+ ) {
+ return invoke_impl(static_cast<F&&>(f), static_cast<invoke&&>(*this),
+ std::make_index_sequence<sizeof...(X)>{});
+ }
+ };
+
+#define BOOST_HANA_PLACEHOLDER_BINARY_OP(op, op_name) \
+ template <typename X> \
+ struct op_name ## _left { \
+ X x; \
+ \
+ template <typename Y, typename ...Z> \
+ constexpr auto operator()(Y&& y, Z const& ...) const& -> decltype( \
+ std::declval<X const&>() op static_cast<Y&&>(y)) \
+ { return x op static_cast<Y&&>(y); } \
+ \
+ template <typename Y, typename ...Z> \
+ constexpr auto operator()(Y&& y, Z const& ...) & -> decltype( \
+ std::declval<X&>() op static_cast<Y&&>(y)) \
+ { return x op static_cast<Y&&>(y); } \
+ \
+ template <typename Y, typename ...Z> \
+ constexpr auto operator()(Y&& y, Z const& ...) && -> decltype( \
+ std::declval<X>() op static_cast<Y&&>(y)) \
+ { return std::move(x) op static_cast<Y&&>(y); } \
+ }; \
+ \
+ template <typename Y> \
+ struct op_name ## _right { \
+ Y y; \
+ \
+ template <typename X, typename ...Z> \
+ constexpr auto operator()(X&& x, Z const& ...) const& -> decltype( \
+ static_cast<X&&>(x) op std::declval<Y const&>()) \
+ { return static_cast<X&&>(x) op y; } \
+ \
+ template <typename X, typename ...Z> \
+ constexpr auto operator()(X&& x, Z const& ...) & -> decltype( \
+ static_cast<X&&>(x) op std::declval<Y&>()) \
+ { return static_cast<X&&>(x) op y; } \
+ \
+ template <typename X, typename ...Z> \
+ constexpr auto operator()(X&& x, Z const& ...) && -> decltype( \
+ static_cast<X&&>(x) op std::declval<Y>()) \
+ { return static_cast<X&&>(x) op std::move(y); } \
+ }; \
+ \
+ struct op_name { \
+ template <typename X, typename Y, typename ...Z> \
+ constexpr auto operator()(X&& x, Y&& y, Z const& ...) const -> decltype(\
+ static_cast<X&&>(x) op static_cast<Y&&>(y)) \
+ { return static_cast<X&&>(x) op static_cast<Y&&>(y); } \
+ }; \
+ \
+ template <typename X> \
+ constexpr decltype(auto) operator op (X&& x, placeholder) \
+ { return detail::create<op_name ## _left>{}(static_cast<X&&>(x)); } \
+ \
+ template <typename Y> \
+ constexpr decltype(auto) operator op (placeholder, Y&& y) \
+ { return detail::create<op_name ## _right>{}(static_cast<Y&&>(y)); } \
+ \
+ inline constexpr decltype(auto) operator op (placeholder, placeholder) \
+ { return op_name{}; } \
+/**/
+
+#define BOOST_HANA_PLACEHOLDER_UNARY_OP(op, op_name) \
+ struct op_name { \
+ template <typename X, typename ...Z> \
+ constexpr auto operator()(X&& x, Z const& ...) const \
+ -> decltype(op static_cast<X&&>(x)) \
+ { return op static_cast<X&&>(x); } \
+ }; \
+ \
+ inline constexpr decltype(auto) operator op (placeholder) \
+ { return op_name{}; } \
+/**/
+ // Arithmetic
+ BOOST_HANA_PLACEHOLDER_UNARY_OP(+, unary_plus)
+ BOOST_HANA_PLACEHOLDER_UNARY_OP(-, unary_minus)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(+, plus)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(-, minus)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(*, times)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(/, divide)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(%, modulo)
+
+ // Bitwise
+ BOOST_HANA_PLACEHOLDER_UNARY_OP(~, bitwise_not)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(&, bitwise_and)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(|, bitwise_or)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(^, bitwise_xor)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(<<, left_shift)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(>>, right_shift)
+
+ // Comparison
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(==, equal)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(!=, not_equal)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(<, less)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(<=, less_equal)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(>, greater)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(>=, greater_equal)
+
+ // Logical
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(||, logical_or)
+ BOOST_HANA_PLACEHOLDER_BINARY_OP(&&, logical_and)
+ BOOST_HANA_PLACEHOLDER_UNARY_OP(!, logical_not)
+
+ // Member access (array subscript is a member function)
+ BOOST_HANA_PLACEHOLDER_UNARY_OP(*, dereference)
+
+ // Other (function call is a member function)
+
+#undef BOOST_HANA_PREFIX_PLACEHOLDER_OP
+#undef BOOST_HANA_BINARY_PLACEHOLDER_OP
+ } // end namespace placeholder_detail
+
+ constexpr placeholder_detail::placeholder _{};
+#endif
+BOOST_HANA_NAMESPACE_END
+
+#endif // !BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP