Merge "base: steal Chromium's NoDestructor." am: 9e6ac64871 am: 3360201a57
am: 9be57a715f
Change-Id: I3071fbb3dc9dcd9091933ebf2d02fd36dc32a8ae
diff --git a/base/Android.bp b/base/Android.bp
index aeb8864..8351461 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -149,6 +149,7 @@
"logging_test.cpp",
"macros_test.cpp",
"mapped_file_test.cpp",
+ "no_destructor_test.cpp",
"parsedouble_test.cpp",
"parsebool_test.cpp",
"parseint_test.cpp",
diff --git a/base/include/android-base/no_destructor.h b/base/include/android-base/no_destructor.h
new file mode 100644
index 0000000..ce0dc9f
--- /dev/null
+++ b/base/include/android-base/no_destructor.h
@@ -0,0 +1,94 @@
+#pragma once
+
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utility>
+
+#include "android-base/macros.h"
+
+namespace android {
+namespace base {
+
+// A wrapper that makes it easy to create an object of type T with static
+// storage duration that:
+// - is only constructed on first access
+// - never invokes the destructor
+// in order to satisfy the styleguide ban on global constructors and
+// destructors.
+//
+// Runtime constant example:
+// const std::string& GetLineSeparator() {
+// // Forwards to std::string(size_t, char, const Allocator&) constructor.
+// static const base::NoDestructor<std::string> s(5, '-');
+// return *s;
+// }
+//
+// More complex initialization with a lambda:
+// const std::string& GetSessionNonce() {
+// static const base::NoDestructor<std::string> nonce([] {
+// std::string s(16);
+// crypto::RandString(s.data(), s.size());
+// return s;
+// }());
+// return *nonce;
+// }
+//
+// NoDestructor<T> stores the object inline, so it also avoids a pointer
+// indirection and a malloc. Also note that since C++11 static local variable
+// initialization is thread-safe and so is this pattern. Code should prefer to
+// use NoDestructor<T> over:
+// - A function scoped static T* or T& that is dynamically initialized.
+// - A global base::LazyInstance<T>.
+//
+// Note that since the destructor is never run, this *will* leak memory if used
+// as a stack or member variable. Furthermore, a NoDestructor<T> should never
+// have global scope as that may require a static initializer.
+template <typename T>
+class NoDestructor {
+ public:
+ // Not constexpr; just write static constexpr T x = ...; if the value should
+ // be a constexpr.
+ template <typename... Args>
+ explicit NoDestructor(Args&&... args) {
+ new (storage_) T(std::forward<Args>(args)...);
+ }
+
+ // Allows copy and move construction of the contained type, to allow
+ // construction from an initializer list, e.g. for std::vector.
+ explicit NoDestructor(const T& x) { new (storage_) T(x); }
+ explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
+
+ NoDestructor(const NoDestructor&) = delete;
+ NoDestructor& operator=(const NoDestructor&) = delete;
+
+ ~NoDestructor() = default;
+
+ const T& operator*() const { return *get(); }
+ T& operator*() { return *get(); }
+
+ const T* operator->() const { return get(); }
+ T* operator->() { return get(); }
+
+ const T* get() const { return reinterpret_cast<const T*>(storage_); }
+ T* get() { return reinterpret_cast<T*>(storage_); }
+
+ private:
+ alignas(T) char storage_[sizeof(T)];
+};
+
+} // namespace base
+} // namespace android
diff --git a/base/no_destructor_test.cpp b/base/no_destructor_test.cpp
new file mode 100644
index 0000000..f19468a
--- /dev/null
+++ b/base/no_destructor_test.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/no_destructor.h"
+
+#include <gtest/gtest.h>
+
+struct __attribute__((packed)) Bomb {
+ Bomb() : magic_(123) {}
+
+ ~Bomb() { exit(42); }
+
+ int get() const { return magic_; }
+
+ private:
+ [[maybe_unused]] char padding_;
+ int magic_;
+};
+
+TEST(no_destructor, bomb) {
+ ASSERT_EXIT(({
+ {
+ Bomb b;
+ if (b.get() != 123) exit(1);
+ }
+
+ exit(0);
+ }),
+ ::testing::ExitedWithCode(42), "");
+}
+
+TEST(no_destructor, defused) {
+ ASSERT_EXIT(({
+ {
+ android::base::NoDestructor<Bomb> b;
+ if (b->get() != 123) exit(1);
+ }
+
+ exit(0);
+ }),
+ ::testing::ExitedWithCode(0), "");
+}
+
+TEST(no_destructor, operators) {
+ android::base::NoDestructor<Bomb> b;
+ const android::base::NoDestructor<Bomb>& c = b;
+ ASSERT_EQ(123, b.get()->get());
+ ASSERT_EQ(123, b->get());
+ ASSERT_EQ(123, (*b).get());
+ ASSERT_EQ(123, c.get()->get());
+ ASSERT_EQ(123, c->get());
+ ASSERT_EQ(123, (*c).get());
+}