Refactor FOLLY_GCC_DISABLE_WARNING to play nice with clang-format
[folly.git] / folly / Partial.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <folly/ApplyTuple.h>
20
21 namespace folly {
22
23 namespace detail {
24 namespace partial {
25
26 // helper type to make sure that the templated constructor in Partial does
27 // not accidentally act as copy or move constructor
28 struct PartialConstructFromCallable {};
29
30 template <typename F, typename Tuple>
31 class Partial {
32  private:
33   F f_;
34   Tuple stored_args_;
35
36  public:
37   template <typename Callable, typename... Args>
38   Partial(PartialConstructFromCallable, Callable&& callable, Args&&... args)
39       : f_(std::forward<Callable>(callable)),
40         stored_args_(std::forward<Args>(args)...) {}
41
42   // full auto doesn't work here due to
43   // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70983 :(
44
45   template <typename... CArgs>
46   auto operator()(CArgs&&... cargs) & -> decltype(applyTuple(
47       static_cast<F&>(f_),
48       static_cast<Tuple&>(stored_args_),
49       std::forward_as_tuple(std::forward<CArgs>(cargs)...))) {
50     return applyTuple(
51         static_cast<F&>(f_),
52         static_cast<Tuple&>(stored_args_),
53         std::forward_as_tuple(std::forward<CArgs>(cargs)...));
54   }
55
56   template <typename... CArgs>
57   auto operator()(CArgs&&... cargs) const& -> decltype(applyTuple(
58       static_cast<F const&>(f_),
59       static_cast<Tuple const&>(stored_args_),
60       std::forward_as_tuple(std::forward<CArgs>(cargs)...))) {
61     return applyTuple(
62         static_cast<F const&>(f_),
63         static_cast<Tuple const&>(stored_args_),
64         std::forward_as_tuple(std::forward<CArgs>(cargs)...));
65   }
66
67   template <typename... CArgs>
68   auto operator()(CArgs&&... cargs) && -> decltype(applyTuple(
69       static_cast<F&&>(f_),
70       static_cast<Tuple&&>(stored_args_),
71       std::forward_as_tuple(std::forward<CArgs>(cargs)...))) {
72     return applyTuple(
73         static_cast<F&&>(f_),
74         static_cast<Tuple&&>(stored_args_),
75         std::forward_as_tuple(std::forward<CArgs>(cargs)...));
76   }
77 };
78
79 } // namespace partial
80 } // namespace detail
81
82 /**
83  * Partially applies arguments to a callable
84  *
85  * `partial` takes a callable and zero or more additional arguments and returns
86  * a callable object, which when called with zero or more arguments, will invoke
87  * the original callable with the additional arguments passed to `partial`,
88  * followed by those passed to the call.
89  *
90  * E.g. `partial(Foo, 1, 2)(3)` is equivalent to `Foo(1, 2, 3)`.
91  *
92  * `partial` can be used to bind a class method to an instance:
93  * `partial(&Foo::method, foo_pointer)` returns a callable object that can be
94  * invoked in the same way as `foo_pointer->method`. In case the first
95  * argument in a call to `partial` is a member pointer, the second argument
96  * can be a reference, pointer or any object that can be dereferenced to
97  * an object of type Foo (like `std::shared_ptr` or `std::unique_ptr`).
98  *
99  * `partial` is similar to `std::bind`, but you don't have to use placeholders
100  * to have arguments passed on. Any number of arguments passed to the object
101  * returned by `partial` when called will be added to those passed to `partial`
102  * and passed to the original callable.
103  */
104 template <typename F, typename... Args>
105 auto partial(F&& f, Args&&... args) -> detail::partial::Partial<
106     typename std::decay<F>::type,
107     std::tuple<typename std::decay<Args>::type...>> {
108   return {detail::partial::PartialConstructFromCallable{},
109           std::forward<F>(f),
110           std::forward<Args>(args)...};
111 }
112
113 } // namespace folly