"Fossies" - the Fresh Open Source Software Archive

Member "abseil-cpp-20230802.1/absl/functional/any_invocable.h" (18 Sep 2023, 12543 Bytes) of package /linux/misc/abseil-cpp-20230802.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "any_invocable.h" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20230125.3_vs_20230802.0.

    1 // Copyright 2022 The Abseil Authors.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 //
    7 //      https://www.apache.org/licenses/LICENSE-2.0
    8 //
    9 // Unless required by applicable law or agreed to in writing, software
   10 // distributed under the License is distributed on an "AS IS" BASIS,
   11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12 // See the License for the specific language governing permissions and
   13 // limitations under the License.
   14 //
   15 // -----------------------------------------------------------------------------
   16 // File: any_invocable.h
   17 // -----------------------------------------------------------------------------
   18 //
   19 // This header file defines an `absl::AnyInvocable` type that assumes ownership
   20 // and wraps an object of an invocable type. (Invocable types adhere to the
   21 // concept specified in https://en.cppreference.com/w/cpp/concepts/invocable.)
   22 //
   23 // In general, prefer `absl::AnyInvocable` when you need a type-erased
   24 // function parameter that needs to take ownership of the type.
   25 //
   26 // NOTE: `absl::AnyInvocable` is similar to the C++23 `std::move_only_function`
   27 // abstraction, but has a slightly different API and is not designed to be a
   28 // drop-in replacement or C++11-compatible backfill of that type.
   29 //
   30 // Credits to Matt Calabrese (https://github.com/mattcalabrese) for the original
   31 // implementation.
   32 
   33 #ifndef ABSL_FUNCTIONAL_ANY_INVOCABLE_H_
   34 #define ABSL_FUNCTIONAL_ANY_INVOCABLE_H_
   35 
   36 #include <cstddef>
   37 #include <initializer_list>
   38 #include <type_traits>
   39 #include <utility>
   40 
   41 #include "absl/base/config.h"
   42 #include "absl/functional/internal/any_invocable.h"
   43 #include "absl/meta/type_traits.h"
   44 #include "absl/utility/utility.h"
   45 
   46 namespace absl {
   47 ABSL_NAMESPACE_BEGIN
   48 
   49 // absl::AnyInvocable
   50 //
   51 // `absl::AnyInvocable` is a functional wrapper type, like `std::function`, that
   52 // assumes ownership of an invocable object. Unlike `std::function`, an
   53 // `absl::AnyInvocable` is more type-safe and provides the following additional
   54 // benefits:
   55 //
   56 // * Properly adheres to const correctness of the underlying type
   57 // * Is move-only so avoids concurrency problems with copied invocables and
   58 //   unnecessary copies in general.
   59 // * Supports reference qualifiers allowing it to perform unique actions (noted
   60 //   below).
   61 //
   62 // `absl::AnyInvocable` is a template, and an `absl::AnyInvocable` instantiation
   63 // may wrap any invocable object with a compatible function signature, e.g.
   64 // having arguments and return types convertible to types matching the
   65 // `absl::AnyInvocable` signature, and also matching any stated reference
   66 // qualifiers, as long as that type is moveable. It therefore provides broad
   67 // type erasure for functional objects.
   68 //
   69 // An `absl::AnyInvocable` is typically used as a type-erased function parameter
   70 // for accepting various functional objects:
   71 //
   72 // // Define a function taking an AnyInvocable parameter.
   73 // void my_func(absl::AnyInvocable<int()> f) {
   74 //   ...
   75 // };
   76 //
   77 // // That function can accept any invocable type:
   78 //
   79 // // Accept a function reference. We don't need to move a reference.
   80 // int func1() { return 0; };
   81 // my_func(func1);
   82 //
   83 // // Accept a lambda. We use std::move here because otherwise my_func would
   84 // // copy the lambda.
   85 // auto lambda = []() { return 0; };
   86 // my_func(std::move(lambda));
   87 //
   88 // // Accept a function pointer. We don't need to move a function pointer.
   89 // func2 = &func1;
   90 // my_func(func2);
   91 //
   92 // // Accept an std::function by moving it. Note that the lambda is copyable
   93 // // (satisfying std::function requirements) and moveable (satisfying
   94 // // absl::AnyInvocable requirements).
   95 // std::function<int()> func6 = []() { return 0; };
   96 // my_func(std::move(func6));
   97 //
   98 // `AnyInvocable` also properly respects `const` qualifiers, reference
   99 // qualifiers, and the `noexcept` specification (only in C++ 17 and beyond) as
  100 // part of the user-specified function type (e.g.
  101 // `AnyInvocable<void()&& const noexcept>`). These qualifiers will be applied to
  102 // the `AnyInvocable` object's `operator()`, and the underlying invocable must
  103 // be compatible with those qualifiers.
  104 //
  105 // Comparison of const and non-const function types:
  106 //
  107 //   // Store a closure inside of `func` with the function type `int()`.
  108 //   // Note that we have made `func` itself `const`.
  109 //   const AnyInvocable<int()> func = [](){ return 0; };
  110 //
  111 //   func();  // Compile-error: the passed type `int()` isn't `const`.
  112 //
  113 //   // Store a closure inside of `const_func` with the function type
  114 //   // `int() const`.
  115 //   // Note that we have also made `const_func` itself `const`.
  116 //   const AnyInvocable<int() const> const_func = [](){ return 0; };
  117 //
  118 //   const_func();  // Fine: `int() const` is `const`.
  119 //
  120 // In the above example, the call `func()` would have compiled if
  121 // `std::function` were used even though the types are not const compatible.
  122 // This is a bug, and using `absl::AnyInvocable` properly detects that bug.
  123 //
  124 // In addition to affecting the signature of `operator()`, the `const` and
  125 // reference qualifiers of the function type also appropriately constrain which
  126 // kinds of invocable objects you are allowed to place into the `AnyInvocable`
  127 // instance. If you specify a function type that is const-qualified, then
  128 // anything that you attempt to put into the `AnyInvocable` must be callable on
  129 // a `const` instance of that type.
  130 //
  131 // Constraint example:
  132 //
  133 //   // Fine because the lambda is callable when `const`.
  134 //   AnyInvocable<int() const> func = [=](){ return 0; };
  135 //
  136 //   // This is a compile-error because the lambda isn't callable when `const`.
  137 //   AnyInvocable<int() const> error = [=]() mutable { return 0; };
  138 //
  139 // An `&&` qualifier can be used to express that an `absl::AnyInvocable`
  140 // instance should be invoked at most once:
  141 //
  142 //   // Invokes `continuation` with the logical result of an operation when
  143 //   // that operation completes (common in asynchronous code).
  144 //   void CallOnCompletion(AnyInvocable<void(int)&&> continuation) {
  145 //     int result_of_foo = foo();
  146 //
  147 //     // `std::move` is required because the `operator()` of `continuation` is
  148 //     // rvalue-reference qualified.
  149 //     std::move(continuation)(result_of_foo);
  150 //   }
  151 //
  152 // Attempting to call `absl::AnyInvocable` multiple times in such a case
  153 // results in undefined behavior.
  154 template <class Sig>
  155 class AnyInvocable : private internal_any_invocable::Impl<Sig> {
  156  private:
  157   static_assert(
  158       std::is_function<Sig>::value,
  159       "The template argument of AnyInvocable must be a function type.");
  160 
  161   using Impl = internal_any_invocable::Impl<Sig>;
  162 
  163  public:
  164   // The return type of Sig
  165   using result_type = typename Impl::result_type;
  166 
  167   // Constructors
  168 
  169   // Constructs the `AnyInvocable` in an empty state.
  170   AnyInvocable() noexcept = default;
  171   AnyInvocable(std::nullptr_t) noexcept {}  // NOLINT
  172 
  173   // Constructs the `AnyInvocable` from an existing `AnyInvocable` by a move.
  174   // Note that `f` is not guaranteed to be empty after move-construction,
  175   // although it may be.
  176   AnyInvocable(AnyInvocable&& /*f*/) noexcept = default;
  177 
  178   // Constructs an `AnyInvocable` from an invocable object.
  179   //
  180   // Upon construction, `*this` is only empty if `f` is a function pointer or
  181   // member pointer type and is null, or if `f` is an `AnyInvocable` that is
  182   // empty.
  183   template <class F, typename = absl::enable_if_t<
  184                          internal_any_invocable::CanConvert<Sig, F>::value>>
  185   AnyInvocable(F&& f)  // NOLINT
  186       : Impl(internal_any_invocable::ConversionConstruct(),
  187              std::forward<F>(f)) {}
  188 
  189   // Constructs an `AnyInvocable` that holds an invocable object of type `T`,
  190   // which is constructed in-place from the given arguments.
  191   //
  192   // Example:
  193   //
  194   //   AnyInvocable<int(int)> func(
  195   //       absl::in_place_type<PossiblyImmovableType>, arg1, arg2);
  196   //
  197   template <class T, class... Args,
  198             typename = absl::enable_if_t<
  199                 internal_any_invocable::CanEmplace<Sig, T, Args...>::value>>
  200   explicit AnyInvocable(absl::in_place_type_t<T>, Args&&... args)
  201       : Impl(absl::in_place_type<absl::decay_t<T>>,
  202              std::forward<Args>(args)...) {
  203     static_assert(std::is_same<T, absl::decay_t<T>>::value,
  204                   "The explicit template argument of in_place_type is required "
  205                   "to be an unqualified object type.");
  206   }
  207 
  208   // Overload of the above constructor to support list-initialization.
  209   template <class T, class U, class... Args,
  210             typename = absl::enable_if_t<internal_any_invocable::CanEmplace<
  211                 Sig, T, std::initializer_list<U>&, Args...>::value>>
  212   explicit AnyInvocable(absl::in_place_type_t<T>,
  213                         std::initializer_list<U> ilist, Args&&... args)
  214       : Impl(absl::in_place_type<absl::decay_t<T>>, ilist,
  215              std::forward<Args>(args)...) {
  216     static_assert(std::is_same<T, absl::decay_t<T>>::value,
  217                   "The explicit template argument of in_place_type is required "
  218                   "to be an unqualified object type.");
  219   }
  220 
  221   // Assignment Operators
  222 
  223   // Assigns an `AnyInvocable` through move-assignment.
  224   // Note that `f` is not guaranteed to be empty after move-assignment
  225   // although it may be.
  226   AnyInvocable& operator=(AnyInvocable&& /*f*/) noexcept = default;
  227 
  228   // Assigns an `AnyInvocable` from a nullptr, clearing the `AnyInvocable`. If
  229   // not empty, destroys the target, putting `*this` into an empty state.
  230   AnyInvocable& operator=(std::nullptr_t) noexcept {
  231     this->Clear();
  232     return *this;
  233   }
  234 
  235   // Assigns an `AnyInvocable` from an existing `AnyInvocable` instance.
  236   //
  237   // Upon assignment, `*this` is only empty if `f` is a function pointer or
  238   // member pointer type and is null, or if `f` is an `AnyInvocable` that is
  239   // empty.
  240   template <class F, typename = absl::enable_if_t<
  241                          internal_any_invocable::CanAssign<Sig, F>::value>>
  242   AnyInvocable& operator=(F&& f) {
  243     *this = AnyInvocable(std::forward<F>(f));
  244     return *this;
  245   }
  246 
  247   // Assigns an `AnyInvocable` from a reference to an invocable object.
  248   // Upon assignment, stores a reference to the invocable object in the
  249   // `AnyInvocable` instance.
  250   template <
  251       class F,
  252       typename = absl::enable_if_t<
  253           internal_any_invocable::CanAssignReferenceWrapper<Sig, F>::value>>
  254   AnyInvocable& operator=(std::reference_wrapper<F> f) noexcept {
  255     *this = AnyInvocable(f);
  256     return *this;
  257   }
  258 
  259   // Destructor
  260 
  261   // If not empty, destroys the target.
  262   ~AnyInvocable() = default;
  263 
  264   // absl::AnyInvocable::swap()
  265   //
  266   // Exchanges the targets of `*this` and `other`.
  267   void swap(AnyInvocable& other) noexcept { std::swap(*this, other); }
  268 
  269   // absl::AnyInvocable::operator bool()
  270   //
  271   // Returns `true` if `*this` is not empty.
  272   //
  273   // WARNING: An `AnyInvocable` that wraps an empty `std::function` is not
  274   // itself empty. This behavior is consistent with the standard equivalent
  275   // `std::move_only_function`.
  276   //
  277   // In other words:
  278   //   std::function<void()> f;  // empty
  279   //   absl::AnyInvocable<void()> a = std::move(f);  // not empty
  280   explicit operator bool() const noexcept { return this->HasValue(); }
  281 
  282   // Invokes the target object of `*this`. `*this` must not be empty.
  283   //
  284   // Note: The signature of this function call operator is the same as the
  285   //       template parameter `Sig`.
  286   using Impl::operator();
  287 
  288   // Equality operators
  289 
  290   // Returns `true` if `*this` is empty.
  291   friend bool operator==(const AnyInvocable& f, std::nullptr_t) noexcept {
  292     return !f.HasValue();
  293   }
  294 
  295   // Returns `true` if `*this` is empty.
  296   friend bool operator==(std::nullptr_t, const AnyInvocable& f) noexcept {
  297     return !f.HasValue();
  298   }
  299 
  300   // Returns `false` if `*this` is empty.
  301   friend bool operator!=(const AnyInvocable& f, std::nullptr_t) noexcept {
  302     return f.HasValue();
  303   }
  304 
  305   // Returns `false` if `*this` is empty.
  306   friend bool operator!=(std::nullptr_t, const AnyInvocable& f) noexcept {
  307     return f.HasValue();
  308   }
  309 
  310   // swap()
  311   //
  312   // Exchanges the targets of `f1` and `f2`.
  313   friend void swap(AnyInvocable& f1, AnyInvocable& f2) noexcept { f1.swap(f2); }
  314 
  315  private:
  316   // Friending other instantiations is necessary for conversions.
  317   template <bool /*SigIsNoexcept*/, class /*ReturnType*/, class... /*P*/>
  318   friend class internal_any_invocable::CoreImpl;
  319 };
  320 
  321 ABSL_NAMESPACE_END
  322 }  // namespace absl
  323 
  324 #endif  // ABSL_FUNCTIONAL_ANY_INVOCABLE_H_