All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
curry.hpp
1 // The MIT License (MIT)
2 
3 // Copyright (c) 2012-2014 Danny Y., Rapptz
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef GEARS_FUNCTIONAL_CURRY_HPP
23 #define GEARS_FUNCTIONAL_CURRY_HPP
24 
25 #include "../adl/get.hpp"
26 #include "../meta/indices.hpp"
27 #include "../meta/meta.hpp"
28 
29 namespace gears {
30 namespace functional {
31 namespace detail {
32 template<typename Tuple>
33 using IndicesFor = meta::build_indices<std::tuple_size<Tuple>::value>;
34 
35 template<typename F, typename Tuple, size_t... Indices,
36  typename Return = decltype(std::declval<F>()(adl::get<Indices>(std::declval<Tuple>())...))>
37 constexpr Return invoke_impl(F&& f, Tuple&& t, meta::indices<Indices...>) {
38  return std::forward<F>(f)(adl::get<Indices>(std::forward<Tuple>(t))...);
39 }
40 
41 template<typename F, typename Tuple,
42  typename Return = decltype(invoke_impl(std::declval<F>(), std::declval<Tuple>(), IndicesFor<Tuple>{}))>
43 constexpr Return invoke_tup(F&& f, Tuple&& tuple) {
44  return invoke_impl(std::forward<F>(f), std::forward<Tuple>(tuple), IndicesFor<Tuple>{});
45 }
46 
47 struct is_reference_wrapper_impl {
48  template<typename T, typename U = typename T::type>
49  static auto test(int) -> decltype(std::declval<T&>().get(), std::is_convertible<T, U&>{}) {}
50  template<typename...>
51  static std::false_type test(...);
52 };
53 
54 template<typename T>
55 struct is_reference_wrapper : decltype(is_reference_wrapper_impl::test<T>(0)) {};
56 
57 template<typename T>
58 struct unref {
59  using type = typename T::type&;
60 };
61 
62 template<typename T>
63 struct special_decay {
64  using type = meta::TypeIf<is_reference_wrapper<T>, unref<T>, meta::identity<T>>;
65 };
66 
67 template<typename T>
68 using SpecialDecay = meta::Type<special_decay<meta::Decay<T>>>;
69 } // detail
70 
71 template<typename Function, typename... Args>
72 struct curry_type {
73  using tuple_type = std::tuple<Args...>;
74 private:
75  Function func;
76  tuple_type args;
77 public:
78  constexpr curry_type(Function&& f, tuple_type n) noexcept: func(std::forward<Function>(f)), args(std::move(n)) {}
79 
80  template<typename... T>
81  constexpr auto operator()(T&&... t) -> decltype(detail::invoke_tup(func, std::tuple_cat(std::move(args), std::make_tuple(t...)))) {
82  return detail::invoke_tup(func, std::tuple_cat(std::move(args), std::make_tuple(t...)));
83  }
84 };
85 
115 template<typename Function, typename... Args>
116 constexpr curry_type<Function, detail::SpecialDecay<Args>...> curry(Function&& f, Args&&... args) {
117  return { std::forward<Function>(f), std::make_tuple(args...) };
118 }
119 } // functional
120 } // gears
121 
122 #endif // GEARS_FUNCTIONAL_CURRY_HPP