1 #pragma once
2 
3 /*
4  * Copyright (C) 2019 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <utility>
20 
21 #include "android-base/macros.h"
22 
23 namespace android {
24 namespace base {
25 
26 // A wrapper that makes it easy to create an object of type T with static
27 // storage duration that:
28 // - is only constructed on first access
29 // - never invokes the destructor
30 // in order to satisfy the styleguide ban on global constructors and
31 // destructors.
32 //
33 // Runtime constant example:
34 // const std::string& GetLineSeparator() {
35 //  // Forwards to std::string(size_t, char, const Allocator&) constructor.
36 //   static const base::NoDestructor<std::string> s(5, '-');
37 //   return *s;
38 // }
39 //
40 // More complex initialization with a lambda:
41 // const std::string& GetSessionNonce() {
42 //   static const base::NoDestructor<std::string> nonce([] {
43 //     std::string s(16);
44 //     crypto::RandString(s.data(), s.size());
45 //     return s;
46 //   }());
47 //   return *nonce;
48 // }
49 //
50 // NoDestructor<T> stores the object inline, so it also avoids a pointer
51 // indirection and a malloc. Also note that since C++11 static local variable
52 // initialization is thread-safe and so is this pattern. Code should prefer to
53 // use NoDestructor<T> over:
54 // - A function scoped static T* or T& that is dynamically initialized.
55 // - A global base::LazyInstance<T>.
56 //
57 // Note that since the destructor is never run, this *will* leak memory if used
58 // as a stack or member variable. Furthermore, a NoDestructor<T> should never
59 // have global scope as that may require a static initializer.
60 template <typename T>
61 class NoDestructor {
62  public:
63   // Not constexpr; just write static constexpr T x = ...; if the value should
64   // be a constexpr.
65   template <typename... Args>
NoDestructor(Args &&...args)66   explicit NoDestructor(Args&&... args) {
67     new (storage_) T(std::forward<Args>(args)...);
68   }
69 
70   // Allows copy and move construction of the contained type, to allow
71   // construction from an initializer list, e.g. for std::vector.
NoDestructor(const T & x)72   explicit NoDestructor(const T& x) { new (storage_) T(x); }
NoDestructor(T && x)73   explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
74 
75   NoDestructor(const NoDestructor&) = delete;
76   NoDestructor& operator=(const NoDestructor&) = delete;
77 
78   ~NoDestructor() = default;
79 
80   const T& operator*() const { return *get(); }
81   T& operator*() { return *get(); }
82 
83   const T* operator->() const { return get(); }
84   T* operator->() { return get(); }
85 
get()86   const T* get() const { return reinterpret_cast<const T*>(storage_); }
get()87   T* get() { return reinterpret_cast<T*>(storage_); }
88 
89  private:
90   alignas(T) char storage_[sizeof(T)];
91 };
92 
93 }  // namespace base
94 }  // namespace android
95