Partial.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * Copyright 2016-present 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. #pragma once
  17. #include <folly/Utility.h>
  18. #include <folly/functional/Invoke.h>
  19. #include <tuple>
  20. #include <utility>
  21. namespace folly {
  22. namespace detail {
  23. namespace partial {
  24. // helper type to make sure that the templated constructor in Partial does
  25. // not accidentally act as copy or move constructor
  26. struct PartialConstructFromCallable {};
  27. template <typename F, typename Tuple>
  28. class Partial {
  29. using Indexes = make_index_sequence<std::tuple_size<Tuple>{}>;
  30. template <typename Self, std::size_t... I, typename... Args>
  31. static auto invokeForward(Self&& self, index_sequence<I...>, Args&&... args)
  32. -> decltype(invoke(
  33. std::declval<Self>().f_,
  34. std::get<I>(std::declval<Self>().stored_args_)...,
  35. std::declval<Args>()...)) {
  36. return invoke(
  37. std::forward<Self>(self).f_,
  38. std::get<I>(std::forward<Self>(self).stored_args_)...,
  39. std::forward<Args>(args)...);
  40. }
  41. public:
  42. template <typename Callable, typename... Args>
  43. Partial(PartialConstructFromCallable, Callable&& callable, Args&&... args)
  44. : f_(std::forward<Callable>(callable)),
  45. stored_args_(std::forward<Args>(args)...) {}
  46. template <typename... CArgs>
  47. auto operator()(CArgs&&... cargs) & -> decltype(invokeForward(
  48. std::declval<Partial&>(),
  49. Indexes{},
  50. std::declval<CArgs>()...)) {
  51. return invokeForward(*this, Indexes{}, std::forward<CArgs>(cargs)...);
  52. }
  53. template <typename... CArgs>
  54. auto operator()(CArgs&&... cargs) const& -> decltype(invokeForward(
  55. std::declval<const Partial&>(),
  56. Indexes{},
  57. std::declval<CArgs>()...)) {
  58. return invokeForward(*this, Indexes{}, std::forward<CArgs>(cargs)...);
  59. }
  60. template <typename... As>
  61. auto operator()(As&&... a) && -> decltype(invokeForward(
  62. std::declval<Partial&&>(),
  63. Indexes{},
  64. std::declval<As>()...)) {
  65. return invokeForward(std::move(*this), Indexes{}, std::forward<As>(a)...);
  66. }
  67. template <typename... As>
  68. auto operator()(As&&... as) const&& -> decltype(invokeForward(
  69. std::declval<const Partial&&>(),
  70. Indexes{},
  71. std::declval<As>()...)) {
  72. return invokeForward(std::move(*this), Indexes{}, std::forward<As>(as)...);
  73. }
  74. private:
  75. // the stored callable
  76. F f_;
  77. // the stored arguments, these will be forwarded along with the actual
  78. // argumnets to the callable above
  79. Tuple stored_args_;
  80. };
  81. } // namespace partial
  82. } // namespace detail
  83. /**
  84. * Partially applies arguments to a callable
  85. *
  86. * `partial` takes a callable and zero or more additional arguments and returns
  87. * a callable object, which when called with zero or more arguments, will invoke
  88. * the original callable with the additional arguments passed to `partial`,
  89. * followed by those passed to the call.
  90. *
  91. * E.g. `partial(Foo, 1, 2)(3)` is equivalent to `Foo(1, 2, 3)`.
  92. *
  93. * `partial` can be used to bind a class method to an instance:
  94. * `partial(&Foo::method, foo_pointer)` returns a callable object that can be
  95. * invoked in the same way as `foo_pointer->method`. In case the first
  96. * argument in a call to `partial` is a member pointer, the second argument
  97. * can be a reference, pointer or any object that can be dereferenced to
  98. * an object of type Foo (like `std::shared_ptr` or `std::unique_ptr`).
  99. *
  100. * `partial` is similar to `std::bind`, but you don't have to use placeholders
  101. * to have arguments passed on. Any number of arguments passed to the object
  102. * returned by `partial` when called will be added to those passed to `partial`
  103. * and passed to the original callable.
  104. */
  105. template <typename F, typename... Args>
  106. auto partial(F&& f, Args&&... args) -> detail::partial::Partial<
  107. typename std::decay<F>::type,
  108. std::tuple<typename std::decay<Args>::type...>> {
  109. return {detail::partial::PartialConstructFromCallable{},
  110. std::forward<F>(f),
  111. std::forward<Args>(args)...};
  112. }
  113. } // namespace folly