| /* |
| * Copyright 2017 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 <cassert> |
| #include <utility> |
| |
| 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 S = T, typename = decltype(S())> |
| constexpr Indestructible() noexcept(noexcept(T())) {} |
| |
| template <typename... Args, typename = decltype(T(std::declval<Args&&>()...))> |
| explicit constexpr Indestructible(Args&&... args) noexcept( |
| noexcept(T(std::declval<Args&&>()...))) |
| : storage_(std::forward<Args>(args)...) {} |
| |
| ~Indestructible() = default; |
| |
| Indestructible(Indestructible const&) = delete; |
| Indestructible& operator=(Indestructible const&) = delete; |
| |
| Indestructible(Indestructible&& other) noexcept( |
| noexcept(T(std::declval<T&&>()))) |
| : storage_(std::move(other.storage_.value)) { |
| other.erased_ = true; |
| } |
| Indestructible& operator=(Indestructible&& other) noexcept( |
| noexcept(T(std::declval<T&&>()))) { |
| storage_.value = std::move(other.storage_.value); |
| other.erased_ = true; |
| } |
| |
| T* get() noexcept { |
| check(); |
| return &storage_.value; |
| } |
| T const* get() const noexcept { |
| check(); |
| return &storage_.value; |
| } |
| T& operator*() noexcept { return *get(); } |
| T const& operator*() const noexcept { return *get(); } |
| T* operator->() noexcept { return get(); } |
| T const* operator->() const noexcept { return get(); } |
| |
| private: |
| void check() const noexcept { |
| assert(!erased_); |
| } |
| |
| union Storage { |
| T value; |
| |
| template <typename S = T, typename = decltype(S())> |
| constexpr Storage() noexcept(noexcept(T())) : value() {} |
| |
| template < |
| typename... Args, |
| typename = decltype(T(std::declval<Args&&>()...))> |
| explicit constexpr Storage(Args&&... args) noexcept( |
| noexcept(T(std::declval<Args&&>()...))) |
| : value(std::forward<Args>(args)...) {} |
| |
| ~Storage() {} |
| }; |
| |
| Storage storage_{}; |
| bool erased_{false}; |
| }; |
| } |