Introduce base::NoDestructor<T> to simplify static objects

For accessors, I intentionally avoided operator* and operator->, as I believe
that they're very opaque at the call site, especially if the contained object
itself has these operators (and imo operator-> is in general weird as its
evaluation is iterative, and would depend on T).

Also decided not to bother with getting initializer list constructor matching
to work. We can add that when needed.

Change-Id: I845f10239eb58e7751550b7ead385961c2ce98ae
diff --git a/Android.bp b/Android.bp
index ab6c201..110ac0a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2849,6 +2849,7 @@
     "src/base/event.cc",
     "src/base/file_utils.cc",
     "src/base/metatrace.cc",
+    "src/base/no_destructor_unittest.cc",
     "src/base/optional_unittest.cc",
     "src/base/paged_memory.cc",
     "src/base/paged_memory_unittest.cc",
diff --git a/include/perfetto/base/no_destructor.h b/include/perfetto/base/no_destructor.h
new file mode 100644
index 0000000..24c2a38
--- /dev/null
+++ b/include/perfetto/base/no_destructor.h
@@ -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.
+ */
+
+#ifndef INCLUDE_PERFETTO_BASE_NO_DESTRUCTOR_H_
+#define INCLUDE_PERFETTO_BASE_NO_DESTRUCTOR_H_
+
+#include <new>
+#include <utility>
+
+namespace perfetto {
+namespace base {
+
+// Wrapper that can hold an object of type T, without invoking the contained
+// object's destructor when being destroyed. Useful for creating statics while
+// avoiding static destructors.
+//
+// Stores the object inline, and therefore doesn't incur memory allocation and
+// pointer indirection overheads.
+//
+// Example of use:
+//
+//   const std::string& GetStr() {
+//     static base::NoDestructor<std::string> s("hello");
+//     return s.ref();
+//   }
+//
+template <typename T>
+class NoDestructor {
+ public:
+  // Forward arguments to T's constructor. Note that this doesn't cover
+  // construction from initializer lists.
+  template <typename... Args>
+  explicit NoDestructor(Args&&... args) {
+    new (storage_) T(std::forward<Args>(args)...);
+  }
+
+  NoDestructor(const NoDestructor&) = delete;
+  NoDestructor& operator=(const NoDestructor&) = delete;
+  NoDestructor(NoDestructor&&) = delete;
+  NoDestructor& operator=(NoDestructor&&) = delete;
+
+  ~NoDestructor() = default;
+
+  T& ref() { return *reinterpret_cast<T*>(storage_); }
+
+ private:
+  alignas(T) char storage_[sizeof(T)];
+};
+
+}  // namespace base
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_BASE_NO_DESTRUCTOR_H_
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index 447a9b1..0f03049 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -141,6 +141,7 @@
   }
   sources = [
     "circular_queue_unittest.cc",
+    "no_destructor_unittest.cc",
     "optional_unittest.cc",
     "paged_memory_unittest.cc",
     "scoped_file_unittest.cc",
diff --git a/src/base/no_destructor_unittest.cc b/src/base/no_destructor_unittest.cc
new file mode 100644
index 0000000..1d1702f
--- /dev/null
+++ b/src/base/no_destructor_unittest.cc
@@ -0,0 +1,89 @@
+
+/*
+ * 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 <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "perfetto/base/logging.h"
+#include "perfetto/base/no_destructor.h"
+
+namespace perfetto {
+namespace base {
+namespace {
+
+class FatalDestructor {
+ public:
+  __attribute__((noreturn)) ~FatalDestructor() {
+    PERFETTO_FATAL("Should not be called.");
+  }
+};
+
+TEST(NoDestructorTest, DoesNotDestruct) {
+  // Fatal without wrapper.
+  EXPECT_DEATH({ FatalDestructor f; }, "");
+
+  // Not destructed when wrapped.
+  EXPECT_NO_FATAL_FAILURE({ NoDestructor<FatalDestructor> f; });
+}
+
+#pragma GCC diagnostic push
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wexit-time-destructors"
+#endif
+TEST(NoDestructorTest, DoesNotDestructStatic) {
+  // Fatal without wrapper.
+  ASSERT_DEATH(
+      {
+        static FatalDestructor f;
+        exit(0);
+      },
+      "");
+
+  // Not destructed when wrapped.
+  ASSERT_EXIT(
+      {
+        static NoDestructor<FatalDestructor> f;
+        exit(0);
+      },
+      ::testing::ExitedWithCode(0), "");
+}
+#pragma GCC diagnostic pop
+
+class NonTrivial {
+ public:
+  NonTrivial(std::vector<int> v, std::unique_ptr<int> p)
+      : vec_(v), ptr_(std::move(p)) {}
+
+  std::vector<int> vec_;
+  std::unique_ptr<int> ptr_;
+};
+
+TEST(NoDestructorTest, ContainedObjectUsable) {
+  static NoDestructor<NonTrivial> x(std::vector<int>{1, 2, 3},
+                                    std::unique_ptr<int>(new int(42)));
+
+  ASSERT_THAT(x.ref().vec_, ::testing::ElementsAre(1, 2, 3));
+  ASSERT_EQ(*x.ref().ptr_, 42);
+
+  x.ref().vec_ = {4, 5, 6};
+  ASSERT_THAT(x.ref().vec_, ::testing::ElementsAre(4, 5, 6));
+}
+
+}  // namespace
+}  // namespace base
+}  // namespace perfetto