tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

no_destructor.h (7148B)


      1 // Copyright 2023 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: no_destructor.h
     17 // -----------------------------------------------------------------------------
     18 //
     19 // This header file defines the absl::NoDestructor<T> wrapper for defining a
     20 // static type that does not need to be destructed upon program exit. Instead,
     21 // such an object survives during program exit (and can be safely accessed at
     22 // any time).
     23 //
     24 // absl::NoDestructor<T> is useful when when a variable has static storage
     25 // duration but its type has a non-trivial destructor. Global constructors are
     26 // not recommended because of the C++'s static initialization order fiasco (See
     27 // https://en.cppreference.com/w/cpp/language/siof). Global destructors are not
     28 // allowed due to similar concerns about destruction ordering. Using
     29 // absl::NoDestructor<T> as a function-local static prevents both of these
     30 // issues.
     31 //
     32 // See below for complete details.
     33 
     34 
     35 #ifndef ABSL_BASE_NO_DESTRUCTOR_H_
     36 #define ABSL_BASE_NO_DESTRUCTOR_H_
     37 
     38 #include <new>
     39 #include <type_traits>
     40 #include <utility>
     41 
     42 #include "absl/base/config.h"
     43 #include "absl/base/nullability.h"
     44 
     45 namespace absl {
     46 ABSL_NAMESPACE_BEGIN
     47 
     48 // absl::NoDestructor<T>
     49 //
     50 // NoDestructor<T> is a wrapper around an object of type T that behaves as an
     51 // object of type T but never calls T's destructor. NoDestructor<T> makes it
     52 // safer and/or more efficient to use such objects in static storage contexts,
     53 // ideally as function scope static variables.
     54 //
     55 // An instance of absl::NoDestructor<T> has similar type semantics to an
     56 // instance of T:
     57 //
     58 // * Constructs in the same manner as an object of type T through perfect
     59 //   forwarding.
     60 // * Provides pointer/reference semantic access to the object of type T via
     61 //   `->`, `*`, and `get()`.
     62 //   (Note that `const NoDestructor<T>` works like a pointer to const `T`.)
     63 //
     64 // Additionally, NoDestructor<T> provides the following benefits:
     65 //
     66 // * Never calls T's destructor for the object
     67 // * If the object is a function-local static variable, the type can be
     68 //   lazily constructed.
     69 //
     70 // An object of type NoDestructor<T> is "trivially destructible" in the notion
     71 // that its destructor is never run.
     72 //
     73 // Usage as Function Scope Static Variables
     74 //
     75 // Function static objects will be lazily initialized within static storage:
     76 //
     77 //    // Function scope.
     78 //    const std::string& MyString() {
     79 //      static const absl::NoDestructor<std::string> x("foo");
     80 //      return *x;
     81 //    }
     82 //
     83 // For function static variables, NoDestructor avoids heap allocation and can be
     84 // inlined in static storage, resulting in exactly-once, thread-safe
     85 // construction of an object, and very fast access thereafter (the cost is a few
     86 // extra cycles).
     87 //
     88 // Using NoDestructor<T> in this manner is generally better than other patterns
     89 // which require pointer chasing:
     90 //
     91 //   // Prefer using absl::NoDestructor<T> instead for the static variable.
     92 //   const std::string& MyString() {
     93 //     static const std::string* x = new std::string("foo");
     94 //     return *x;
     95 //   }
     96 //
     97 // Usage as Global Static Variables
     98 //
     99 // NoDestructor<T> allows declaration of a global object of type T that has a
    100 // non-trivial destructor since its destructor is never run. However, such
    101 // objects still need to worry about initialization order, so such use is not
    102 // recommended, strongly discouraged by the Google C++ Style Guide, and outright
    103 // banned in Chromium.
    104 // See https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
    105 //
    106 //    // Global or namespace scope.
    107 //    absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008};
    108 //
    109 // Note that if your object already has a trivial destructor, you don't need to
    110 // use NoDestructor<T>.
    111 //
    112 template <typename T>
    113 class NoDestructor {
    114 public:
    115  // Forwards arguments to the T's constructor: calls T(args...).
    116  template <typename... Ts,
    117            // Disable this overload when it might collide with copy/move.
    118            typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...),
    119                                                  void(NoDestructor&)>::value,
    120                                    int>::type = 0>
    121  explicit constexpr NoDestructor(Ts&&... args)
    122      : impl_(std::forward<Ts>(args)...) {}
    123 
    124  // Forwards copy and move construction for T. Enables usage like this:
    125  //   static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}};
    126  //   static NoDestructor<std::vector<int>> x{{1, 2, 3}};
    127  explicit constexpr NoDestructor(const T& x) : impl_(x) {}
    128  explicit constexpr NoDestructor(T&& x)
    129      : impl_(std::move(x)) {}
    130 
    131  // No copying.
    132  NoDestructor(const NoDestructor&) = delete;
    133  NoDestructor& operator=(const NoDestructor&) = delete;
    134 
    135  // Pretend to be a smart pointer to T with deep constness.
    136  // Never returns a null pointer.
    137  T& operator*() { return *get(); }
    138  absl::Nonnull<T*> operator->() { return get(); }
    139  absl::Nonnull<T*> get() { return impl_.get(); }
    140  const T& operator*() const { return *get(); }
    141  absl::Nonnull<const T*> operator->() const { return get(); }
    142  absl::Nonnull<const T*> get() const { return impl_.get(); }
    143 
    144 private:
    145  class DirectImpl {
    146   public:
    147    template <typename... Args>
    148    explicit constexpr DirectImpl(Args&&... args)
    149        : value_(std::forward<Args>(args)...) {}
    150    absl::Nonnull<const T*> get() const { return &value_; }
    151    absl::Nonnull<T*> get() { return &value_; }
    152 
    153   private:
    154    T value_;
    155  };
    156 
    157  class PlacementImpl {
    158   public:
    159    template <typename... Args>
    160    explicit PlacementImpl(Args&&... args) {
    161      new (&space_) T(std::forward<Args>(args)...);
    162    }
    163    absl::Nonnull<const T*> get() const {
    164      return std::launder(reinterpret_cast<const T*>(&space_));
    165    }
    166    absl::Nonnull<T*> get() {
    167      return std::launder(reinterpret_cast<T*>(&space_));
    168    }
    169 
    170   private:
    171    alignas(T) unsigned char space_[sizeof(T)];
    172  };
    173 
    174  // If the object is trivially destructible we use a member directly to avoid
    175  // potential once-init runtime initialization. It somewhat defeats the
    176  // purpose of NoDestructor in this case, but this makes the class more
    177  // friendly to generic code.
    178  std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl,
    179                     PlacementImpl>
    180      impl_;
    181 };
    182 
    183 // Provide 'Class Template Argument Deduction': the type of NoDestructor's T
    184 // will be the same type as the argument passed to NoDestructor's constructor.
    185 template <typename T>
    186 NoDestructor(T) -> NoDestructor<T>;
    187 
    188 ABSL_NAMESPACE_END
    189 }  // namespace absl
    190 
    191 #endif  // ABSL_BASE_NO_DESTRUCTOR_H_