1 // Copyright 2022 gRPC 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 //     http://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 #ifndef GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H
16 #define GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <type_traits>
21 #include <utility>
22 
23 #include "src/core/lib/gprpp/construct_destruct.h"
24 
25 namespace grpc_core {
26 
27 // NoDestruct<T> is a wrapper around an object of type T that:
28 // - stores the value inline - no heap allocation
29 // - is non-copyable
30 // - is eagerly constructed (i.e. the constructor is called when NoDestruct is
31 //   constructed)
32 // - *NEVER* calls ~T()
33 // It's useful in cases where no ordering can be assumed between destructors of
34 // objects that need to refer to each other - such as at program destruction
35 // time.
36 // Examples:
37 //  // globally available object:
38 //  static NoDestruct<Foo> g_foo(1, "foo", 2.0);
39 //  // used as:
40 //  g_foo->DoSomething();
41 //  // singleton function:
42 //  Bar* BarSingleton() {
43 //   static NoDestruct<Bar> bar(1, "bar", 2.0);
44 //   return &*bar;
45 //  }
46 // The globally available version is constructed at program startup, and the
47 // singleton version is constructed at the first call to BarSingleton().
48 // Neither Foo nor Bar instance will be destructed.
49 template <typename T>
50 class NoDestruct {
51  public:
52   template <typename... Args>
NoDestruct(Args &&...args)53   explicit NoDestruct(Args&&... args) {
54     static_assert(std::is_trivially_destructible<NoDestruct<T>>::value,
55                   "NoDestruct must be trivially destructible");
56     Construct(reinterpret_cast<T*>(&space_), std::forward<Args>(args)...);
57   }
58   NoDestruct(const NoDestruct&) = delete;
59   NoDestruct& operator=(const NoDestruct&) = delete;
60   ~NoDestruct() = default;
61 
62   T* operator->() { return get(); }
63   const T* operator->() const { return get(); }
64   T& operator*() { return *get(); }
65   const T& operator*() const { return *get(); }
66 
get()67   T* get() { return reinterpret_cast<T*>(&space_); }
get()68   const T* get() const { return reinterpret_cast<const T*>(&space_); }
69 
70  private:
71   typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
72 };
73 
74 // Helper for when a program desires a single *process wide* instance of a
75 // default constructed T to be always available.
76 // The instance is constructed eagerly at program startup, so it's essentially
77 // free to load the pointer to the instance.
78 template <typename T>
79 class NoDestructSingleton {
80  public:
Get()81   static T* Get() { return &*value_; }
82 
83  private:
84   NoDestructSingleton() = delete;
85   ~NoDestructSingleton() = delete;
86 
87   static NoDestruct<T> value_;
88 };
89 
90 template <typename T>
91 NoDestruct<T> NoDestructSingleton<T>::value_;
92 
93 }  // namespace grpc_core
94 
95 #endif  // GRPC_SRC_CORE_LIB_GPRPP_NO_DESTRUCT_H
96