Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:00:52

0001 // Copyright 2023 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 //
0015 // -----------------------------------------------------------------------------
0016 // File: no_destructor.h
0017 // -----------------------------------------------------------------------------
0018 //
0019 // This header file defines the absl::NoDestructor<T> wrapper for defining a
0020 // static type that does not need to be destructed upon program exit. Instead,
0021 // such an object survives during program exit (and can be safely accessed at
0022 // any time).
0023 //
0024 // Objects of such type, if constructed safely and under the right conditions,
0025 // provide two main benefits over other alternatives:
0026 //
0027 //   * Global objects not normally allowed due to concerns of destruction order
0028 //     (i.e. no "complex globals") can be safely allowed, provided that such
0029 //     objects can be constant initialized.
0030 //   * Function scope static objects can be optimized to avoid heap allocation,
0031 //     pointer chasing, and allow lazy construction.
0032 //
0033 // See below for complete details.
0034 
0035 
0036 #ifndef ABSL_BASE_NO_DESTRUCTOR_H_
0037 #define ABSL_BASE_NO_DESTRUCTOR_H_
0038 
0039 #include <new>
0040 #include <type_traits>
0041 #include <utility>
0042 
0043 #include "absl/base/config.h"
0044 
0045 namespace absl {
0046 ABSL_NAMESPACE_BEGIN
0047 
0048 // absl::NoDestructor<T>
0049 //
0050 // NoDestructor<T> is a wrapper around an object of type T that behaves as an
0051 // object of type T but never calls T's destructor. NoDestructor<T> makes it
0052 // safer and/or more efficient to use such objects in static storage contexts:
0053 // as global or function scope static variables.
0054 //
0055 // An instance of absl::NoDestructor<T> has similar type semantics to an
0056 // instance of T:
0057 //
0058 // * Constructs in the same manner as an object of type T through perfect
0059 //   forwarding.
0060 // * Provides pointer/reference semantic access to the object of type T via
0061 //   `->`, `*`, and `get()`.
0062 //   (Note that `const NoDestructor<T>` works like a pointer to const `T`.)
0063 //
0064 // An object of type NoDestructor<T> should be defined in static storage:
0065 // as either a global static object, or as a function scope static variable.
0066 //
0067 // Additionally, NoDestructor<T> provides the following benefits:
0068 //
0069 // * Never calls T's destructor for the object
0070 // * If the object is a function-local static variable, the type can be
0071 //   lazily constructed.
0072 //
0073 // An object of type NoDestructor<T> is "trivially destructible" in the notion
0074 // that its destructor is never run. Provided that an object of this type can be
0075 // safely initialized and does not need to be cleaned up on program shutdown,
0076 // NoDestructor<T> allows you to define global static variables, since Google's
0077 // C++ style guide ban on such objects doesn't apply to objects that are
0078 // trivially destructible.
0079 //
0080 // Usage as Global Static Variables
0081 //
0082 // NoDestructor<T> allows declaration of a global object with a non-trivial
0083 // constructor in static storage without needing to add a destructor.
0084 // However, such objects still need to worry about initialization order, so
0085 // such objects should be const initialized:
0086 //
0087 //    // Global or namespace scope.
0088 //    ABSL_CONST_INIT absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008};
0089 //
0090 // Note that if your object already has a trivial destructor, you don't need to
0091 // use NoDestructor<T>.
0092 //
0093 // Usage as Function Scope Static Variables
0094 //
0095 // Function static objects will be lazily initialized within static storage:
0096 //
0097 //    // Function scope.
0098 //    const std::string& MyString() {
0099 //      static const absl::NoDestructor<std::string> x("foo");
0100 //      return *x;
0101 //    }
0102 //
0103 // For function static variables, NoDestructor avoids heap allocation and can be
0104 // inlined in static storage, resulting in exactly-once, thread-safe
0105 // construction of an object, and very fast access thereafter (the cost is a few
0106 // extra cycles).
0107 //
0108 // Using NoDestructor<T> in this manner is generally better than other patterns
0109 // which require pointer chasing:
0110 //
0111 //   // Prefer using absl::NoDestructor<T> instead for the static variable.
0112 //   const std::string& MyString() {
0113 //     static const std::string* x = new std::string("foo");
0114 //     return *x;
0115 //   }
0116 //
0117 template <typename T>
0118 class NoDestructor {
0119  public:
0120   // Forwards arguments to the T's constructor: calls T(args...).
0121   template <typename... Ts,
0122             // Disable this overload when it might collide with copy/move.
0123             typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...),
0124                                                   void(NoDestructor&)>::value,
0125                                     int>::type = 0>
0126   explicit constexpr NoDestructor(Ts&&... args)
0127       : impl_(std::forward<Ts>(args)...) {}
0128 
0129   // Forwards copy and move construction for T. Enables usage like this:
0130   //   static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}};
0131   //   static NoDestructor<std::vector<int>> x{{1, 2, 3}};
0132   explicit constexpr NoDestructor(const T& x) : impl_(x) {}
0133   explicit constexpr NoDestructor(T&& x)
0134       : impl_(std::move(x)) {}
0135 
0136   // No copying.
0137   NoDestructor(const NoDestructor&) = delete;
0138   NoDestructor& operator=(const NoDestructor&) = delete;
0139 
0140   // Pretend to be a smart pointer to T with deep constness.
0141   // Never returns a null pointer.
0142   T& operator*() { return *get(); }
0143   T* operator->() { return get(); }
0144   T* get() { return impl_.get(); }
0145   const T& operator*() const { return *get(); }
0146   const T* operator->() const { return get(); }
0147   const T* get() const { return impl_.get(); }
0148 
0149  private:
0150   class DirectImpl {
0151    public:
0152     template <typename... Args>
0153     explicit constexpr DirectImpl(Args&&... args)
0154         : value_(std::forward<Args>(args)...) {}
0155     const T* get() const { return &value_; }
0156     T* get() { return &value_; }
0157 
0158    private:
0159     T value_;
0160   };
0161 
0162   class PlacementImpl {
0163    public:
0164     template <typename... Args>
0165     explicit PlacementImpl(Args&&... args) {
0166       new (&space_) T(std::forward<Args>(args)...);
0167     }
0168     const T* get() const {
0169       return Launder(reinterpret_cast<const T*>(&space_));
0170     }
0171     T* get() { return Launder(reinterpret_cast<T*>(&space_)); }
0172 
0173    private:
0174     template <typename P>
0175     static P* Launder(P* p) {
0176 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
0177       return std::launder(p);
0178 #elif ABSL_HAVE_BUILTIN(__builtin_launder)
0179       return __builtin_launder(p);
0180 #else
0181       // When `std::launder` or equivalent are not available, we rely on
0182       // undefined behavior, which works as intended on Abseil's officially
0183       // supported platforms as of Q3 2023.
0184 #if defined(__GNUC__) && !defined(__clang__)
0185 #pragma GCC diagnostic push
0186 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
0187 #endif
0188       return p;
0189 #if defined(__GNUC__) && !defined(__clang__)
0190 #pragma GCC diagnostic pop
0191 #endif
0192 #endif
0193     }
0194 
0195     alignas(T) unsigned char space_[sizeof(T)];
0196   };
0197 
0198   // If the object is trivially destructible we use a member directly to avoid
0199   // potential once-init runtime initialization. It somewhat defeats the
0200   // purpose of NoDestructor in this case, but this makes the class more
0201   // friendly to generic code.
0202   std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl,
0203                      PlacementImpl>
0204       impl_;
0205 };
0206 
0207 #ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
0208 // Provide 'Class Template Argument Deduction': the type of NoDestructor's T
0209 // will be the same type as the argument passed to NoDestructor's constructor.
0210 template <typename T>
0211 NoDestructor(T) -> NoDestructor<T>;
0212 #endif  // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
0213 
0214 ABSL_NAMESPACE_END
0215 }  // namespace absl
0216 
0217 #endif  // ABSL_BASE_NO_DESTRUCTOR_H_