--- /dev/null
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <utility>
+#include <glog/logging.h>
+#include <folly/Likely.h>
+#include <folly/Portability.h>
+
+namespace folly {
+
+/***
+ * Indestructible
+ *
+ * When you need a Meyers singleton that will not get destructed, even at
+ * shutdown, and you also want the object stored inline.
+ *
+ * Use like:
+ *
+ * void doSomethingWithExpensiveData();
+ *
+ * void doSomethingWithExpensiveData() {
+ * static const Indestructible<map<string, int>> data{
+ * map<string, int>{{"key1", 17}, {"key2", 19}, {"key3", 23}},
+ * };
+ * callSomethingTakingAMapByRef(*data);
+ * }
+ *
+ * This should be used only for Meyers singletons, and, even then, only when
+ * the instance does not need to be destructed ever.
+ *
+ * This should not be used more generally, e.g., as member fields, etc.
+ *
+ * This is designed as an alternative, but with one fewer allocation at
+ * construction time and one fewer pointer dereference at access time, to the
+ * Meyers singleton pattern of:
+ *
+ * void doSomethingWithExpensiveData() {
+ * static const auto data = // never `delete`d
+ * new map<string, int>{{"key1", 17}, {"key2", 19}, {"key3", 23}};
+ * callSomethingTakingAMapByRef(*data);
+ * }
+ */
+
+template <typename T>
+class Indestructible final {
+
+ public:
+ template <typename... Args>
+ explicit constexpr Indestructible(Args&&... args) noexcept(
+ std::is_nothrow_constructible<T, decltype(args)...>::value)
+ : storage_(std::forward<Args>(args)...), inited_(true) {}
+
+ ~Indestructible() = default;
+
+ Indestructible(Indestructible const&) = delete;
+ Indestructible& operator=(Indestructible const&) = delete;
+
+ Indestructible(Indestructible&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value)
+ : storage_(std::move(other.storage_.value)) {
+ other.inited_ = false;
+ }
+ Indestructible& operator=(Indestructible&& other) noexcept(
+ std::is_nothrow_move_assignable<T>::value) {
+ storage_.value = std::move(other.storage_.value);
+ other.inited_ = false;
+ }
+
+ T* get() {
+ check();
+ return &storage_.value;
+ }
+ T const* get() const {
+ check();
+ return &storage_.value;
+ }
+ T& operator*() { return *get(); }
+ T const& operator*() const { return *get(); }
+ T* operator->() { return get(); }
+ T const* operator->() const { return get(); }
+
+ private:
+ void check() const {
+ if (UNLIKELY(!inited_)) {
+ fail();
+ }
+ }
+
+ FOLLY_NORETURN FOLLY_NOINLINE static void fail() {
+ LOG(FATAL) << "Indestructible is not initialized";
+ }
+
+ union Storage {
+ T value;
+
+ template <typename... Args>
+ explicit constexpr Storage(Args&&... args)
+ : value(std::forward<Args>(args)...) {}
+
+ ~Storage() {}
+ };
+
+ Storage storage_;
+ bool inited_{false};
+};
+}
--- /dev/null
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * 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 <folly/Indestructible.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <gtest/gtest.h>
+#include <folly/Memory.h>
+
+using namespace std;
+using namespace folly;
+
+namespace {
+
+struct Magic {
+ function<void()> dtor_;
+ function<void()> move_;
+ Magic(function<void()> ctor, function<void()> dtor, function<void()> move)
+ : dtor_(std::move(dtor)), move_(std::move(move)) {
+ ctor();
+ }
+ Magic(Magic&& other) /* may throw */ { *this = std::move(other); }
+ Magic& operator=(Magic&& other) {
+ dtor_ = std::move(other.dtor_);
+ move_ = std::move(other.move_);
+ move_();
+ return *this;
+ }
+ ~Magic() { dtor_(); }
+};
+
+class IndestructibleTest : public testing::Test {};
+}
+
+TEST_F(IndestructibleTest, access) {
+ const Indestructible<map<string, int>> data{
+ map<string, int>{{"key1", 17}, {"key2", 19}, {"key3", 23}}};
+
+ auto& m = *data;
+ EXPECT_EQ(19, m.at("key2"));
+}
+
+TEST_F(IndestructibleTest, no_destruction) {
+ int state = 0;
+ int value = 0;
+
+ auto sing = make_unique<Indestructible<Magic>>(
+ [&] {
+ ++state;
+ value = 7;
+ },
+ [&] { state = -1; },
+ [] {});
+ EXPECT_EQ(1, state);
+ EXPECT_EQ(7, value);
+
+ sing = nullptr;
+ EXPECT_EQ(1, state);
+}
+
+TEST_F(IndestructibleTest, move) {
+ int state = 0;
+ int value = 0;
+ int moves = 0;
+
+ Indestructible<Magic> sing( // move assignment
+ [&] {
+ ++state;
+ value = 7;
+ },
+ [&] { state = -1; },
+ [&] { ++moves; });
+
+ EXPECT_EQ(1, state);
+ EXPECT_EQ(7, value);
+ EXPECT_EQ(0, moves);
+
+ Indestructible<Magic> move_ctor(std::move(sing)); // move constructor
+ EXPECT_EQ(1, state);
+ EXPECT_EQ(1, moves);
+
+ Indestructible<Magic> move_assign = std::move(move_ctor); // move assignment
+ EXPECT_EQ(1, state);
+ EXPECT_EQ(2, moves);
+}