1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <cassert> |
20 | #include <type_traits> |
21 | #include <utility> |
22 | |
23 | #include <folly/Traits.h> |
24 | |
25 | namespace folly { |
26 | |
27 | /*** |
28 | * Indestructible |
29 | * |
30 | * When you need a Meyers singleton that will not get destructed, even at |
31 | * shutdown, and you also want the object stored inline. |
32 | * |
33 | * Use like: |
34 | * |
35 | * void doSomethingWithExpensiveData(); |
36 | * |
37 | * void doSomethingWithExpensiveData() { |
38 | * static const Indestructible<map<string, int>> data{ |
39 | * map<string, int>{{"key1", 17}, {"key2", 19}, {"key3", 23}}, |
40 | * }; |
41 | * callSomethingTakingAMapByRef(*data); |
42 | * } |
43 | * |
44 | * This should be used only for Meyers singletons, and, even then, only when |
45 | * the instance does not need to be destructed ever. |
46 | * |
47 | * This should not be used more generally, e.g., as member fields, etc. |
48 | * |
49 | * This is designed as an alternative, but with one fewer allocation at |
50 | * construction time and one fewer pointer dereference at access time, to the |
51 | * Meyers singleton pattern of: |
52 | * |
53 | * void doSomethingWithExpensiveData() { |
54 | * static const auto data = // never `delete`d |
55 | * new map<string, int>{{"key1", 17}, {"key2", 19}, {"key3", 23}}; |
56 | * callSomethingTakingAMapByRef(*data); |
57 | * } |
58 | */ |
59 | |
60 | template <typename T> |
61 | class Indestructible final { |
62 | public: |
63 | template <typename S = T, typename = decltype(S())> |
64 | constexpr Indestructible() noexcept(noexcept(T())) {} |
65 | |
66 | /** |
67 | * Constructor accepting a single argument by forwarding reference, this |
68 | * allows using list initialzation without the overhead of things like |
69 | * in_place, etc and also works with std::initializer_list constructors |
70 | * which can't be deduced, the default parameter helps there. |
71 | * |
72 | * auto i = folly::Indestructible<std::map<int, int>>{{{1, 2}}}; |
73 | * |
74 | * This provides convenience |
75 | * |
76 | * There are two versions of this constructor - one for when the element is |
77 | * implicitly constructible from the given argument and one for when the |
78 | * type is explicitly but not implicitly constructible from the given |
79 | * argument. |
80 | */ |
81 | template < |
82 | typename U = T, |
83 | std::enable_if_t<std::is_constructible<T, U&&>::value>* = nullptr, |
84 | std::enable_if_t< |
85 | !std::is_same<Indestructible<T>, remove_cvref_t<U>>::value>* = |
86 | nullptr, |
87 | std::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr> |
88 | explicit constexpr Indestructible(U&& u) noexcept( |
89 | noexcept(T(std::declval<U>()))) |
90 | : storage_(std::forward<U>(u)) {} |
91 | template < |
92 | typename U = T, |
93 | std::enable_if_t<std::is_constructible<T, U&&>::value>* = nullptr, |
94 | std::enable_if_t< |
95 | !std::is_same<Indestructible<T>, remove_cvref_t<U>>::value>* = |
96 | nullptr, |
97 | std::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr> |
98 | /* implicit */ constexpr Indestructible(U&& u) noexcept( |
99 | noexcept(T(std::declval<U>()))) |
100 | : storage_(std::forward<U>(u)) {} |
101 | |
102 | template <typename... Args, typename = decltype(T(std::declval<Args>()...))> |
103 | explicit constexpr Indestructible(Args&&... args) noexcept( |
104 | noexcept(T(std::declval<Args>()...))) |
105 | : storage_(std::forward<Args>(args)...) {} |
106 | template < |
107 | typename U, |
108 | typename... Args, |
109 | typename = decltype( |
110 | T(std::declval<std::initializer_list<U>&>(), |
111 | std::declval<Args>()...))> |
112 | explicit constexpr Indestructible(std::initializer_list<U> il, Args... args) noexcept( |
113 | noexcept( |
114 | T(std::declval<std::initializer_list<U>&>(), |
115 | std::declval<Args>()...))) |
116 | : storage_(il, std::forward<Args>(args)...) {} |
117 | |
118 | ~Indestructible() = default; |
119 | |
120 | Indestructible(Indestructible const&) = delete; |
121 | Indestructible& operator=(Indestructible const&) = delete; |
122 | |
123 | Indestructible(Indestructible&& other) noexcept( |
124 | noexcept(T(std::declval<T>()))) |
125 | : storage_(std::move(other.storage_.value)) { |
126 | other.erased_ = true; |
127 | } |
128 | Indestructible& operator=(Indestructible&& other) noexcept( |
129 | noexcept(T(std::declval<T>()))) { |
130 | storage_.value = std::move(other.storage_.value); |
131 | other.erased_ = true; |
132 | } |
133 | |
134 | T* get() noexcept { |
135 | check(); |
136 | return &storage_.value; |
137 | } |
138 | T const* get() const noexcept { |
139 | check(); |
140 | return &storage_.value; |
141 | } |
142 | T& operator*() noexcept { |
143 | return *get(); |
144 | } |
145 | T const& operator*() const noexcept { |
146 | return *get(); |
147 | } |
148 | T* operator->() noexcept { |
149 | return get(); |
150 | } |
151 | T const* operator->() const noexcept { |
152 | return get(); |
153 | } |
154 | |
155 | private: |
156 | void check() const noexcept { |
157 | assert(!erased_); |
158 | } |
159 | |
160 | union Storage { |
161 | T value; |
162 | |
163 | template <typename S = T, typename = decltype(S())> |
164 | constexpr Storage() noexcept(noexcept(T())) : value() {} |
165 | |
166 | template <typename... Args, typename = decltype(T(std::declval<Args>()...))> |
167 | explicit constexpr Storage(Args&&... args) noexcept( |
168 | noexcept(T(std::declval<Args>()...))) |
169 | : value(std::forward<Args>(args)...) {} |
170 | |
171 | ~Storage() {} |
172 | }; |
173 | |
174 | Storage storage_{}; |
175 | bool erased_{false}; |
176 | }; |
177 | } // namespace folly |
178 | |