/* * 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 #include #include #include 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> data{ * map{{"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{{"key1", 17}, {"key2", 19}, {"key3", 23}}; * callSomethingTakingAMapByRef(*data); * } */ template class Indestructible final { public: template explicit constexpr Indestructible(Args&&... args) noexcept( std::is_nothrow_constructible::value) : storage_(std::forward(args)...), inited_(true) {} ~Indestructible() = default; Indestructible(Indestructible const&) = delete; Indestructible& operator=(Indestructible const&) = delete; Indestructible(Indestructible&& other) noexcept( std::is_nothrow_move_constructible::value) : storage_(std::move(other.storage_.value)) { other.inited_ = false; } Indestructible& operator=(Indestructible&& other) noexcept( std::is_nothrow_move_assignable::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(); } } [[noreturn]] FOLLY_NOINLINE static void fail() { LOG(FATAL) << "Indestructible is not initialized"; } union Storage { T value; template explicit constexpr Storage(Args&&... args) : value(std::forward(args)...) {} ~Storage() {} }; Storage storage_; bool inited_{false}; }; }