Replaceable
[folly.git] / folly / Replaceable.h
1 /*
2  * Copyright 2004-present Facebook, Inc.
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 <initializer_list>
20 #include <new>
21 #include <type_traits>
22 #include <utility>
23
24 #include <folly/Launder.h>
25 #include <folly/Traits.h>
26 #include <folly/Utility.h>
27
28 /**
29  * An instance of `Replaceable<T>` wraps an instance of `T`.
30  *
31  * You access the inner `T` instance with `operator*` and `operator->` (as if
32  * it were a smart pointer).
33  *
34  * `Replaceable<T>` adds no indirection cost and performs no allocations.
35  *
36  * `Replaceable<T>` has the same size and alignment as `T`.
37  *
38  * You can replace the `T` within a `Replaceable<T>` using the `emplace` method
39  * (presuming that it is constructible and destructible without throwing
40  * exceptions). If the destructor or constructor you're using could throw an
41  * exception you should use `Optional<T>` instead, as it's not a logic error
42  * for that to be empty.
43  *
44  * Frequently Asked Questions
45  * ==========================
46  *
47  * Why does this need to be so complicated?
48  * ----------------------------------------
49  *
50  * If a `T` instance contains `const`-qualified member variables or reference
51  * member variables we can't safely replace a `T` instance by destructing it
52  * manually and using placement new. This is because compilers are permitted to
53  * assume that the `const` or reference members of a named, referenced, or
54  * pointed-to object do not change.
55  *
56  * For pointed-to objects in allocated storage you can use the pointer returned
57  * by placement new or use the `launder` function to get a pointer to the new
58  * object.  Note that `launder` doesn't affect its argument, it's still
59  * undefined behaviour to use the original pointer. And none of this helps if
60  * the object is a local or a member variable because the destructor call will
61  * not have been laundered. In summary, this is the only way to use placement
62  * new that is both simple and safe:
63  *
64  *      T* pT = new T(...);
65  *      pT->~T();
66  *      pT = ::new (pT) T(...);
67  *      delete pT;
68  *
69  * What are the other safe solutions to this problem?
70  * --------------------------------------------------
71  *
72  * * Ask the designer of `T` to de-`const` and -`reference` the members of `T`.
73  *  - Makes `T` harder to reason about
74  *  - Can reduce the performance of `T` methods
75  *  - They can refuse to make the change
76  * * Put the `T` on the heap and use a raw/unique/shared pointer.
77  *  - Adds a level of indirection, costing performance.
78  *  - Harder to reason about your code as you need to check for nullptr.
79  * * Put the `T` in an `Optional`.
80  *  - Harder to reason about your code as you need to check for None.
81  * * Pass the problem on, making the new code also not-replaceable
82  *  - Contagion is not really a solution
83  *
84  * Are there downsides to this?
85  * ----------------------------
86  *
87  * There is a potential performance penalty after converting `T` to
88  * `Replaceable<T>` if you have non-`T`-member-function code which repeatedly
89  * examines the value of a `const` or `reference` data member of `T`, because
90  * the compiler now has to look at the value each time whereas previously it
91  * was permitted to load it once up-front and presume that it could never
92  * change.
93  *
94  * Usage notes
95  * ===========
96  *
97  * Don't store a reference to the `T` within a `Replaceable<T>` unless you can
98  * show that its lifetime does not cross an `emplace` call. For safety a
99  * reasonable rule is to always use `operator*()` to get a fresh temporary each
100  * time you need a `T&.
101  *
102  * If you store a pointer to the `T` within a `Replaceable<T>` you **must**
103  * launder it after each call to `emplace` before using it. Again you can
104  * reasonably choose to always use `operator->()` to get a fresh temporary each
105  * time you need a `T*.
106  *
107  * Thus far I haven't thought of a good reason to use `Replaceable<T>` or
108  * `Replaceable<T> const&` as a function parameter type.
109  *
110  * `Replaceable<T>&` can make sense to pass to a function that conditionally
111  * replaces the `T`, where `T` has `const` or reference member variables.
112  *
113  * The main use of `Replaceable<T>` is as a class member type or a local type
114  * in long-running functions.
115  *
116  * It's probably time to rethink your design choices if you end up with
117  * `Replaceable<Replaceable<T>>`, `Optional<Replaceable<T>>`,
118  * `Replaceable<Optional<T>>`, `unique_ptr<Replaceable<T>>` etc. except as a
119  *  result of template expansion.
120  */
121
122 namespace folly {
123 template <class T>
124 class Replaceable;
125
126 namespace replaceable_detail {
127 /* Mixin templates to give `replaceable<T>` the following properties:
128  *
129  * 1. Trivial destructor if `T` has a trivial destructor; user-provided
130  *    otherwise
131  * 2. Move constructor if `T` has a move constructor; deleted otherwise
132  * 3. Move assignment operator if `T` has a move constructor; deleted
133  *    otherwise
134  * 4. Copy constructor if `T` has a copy constructor; deleted otherwise
135  * 5. Copy assignment operator if `T` has a copy constructor; deleted
136  *    otherwise
137  *
138  * Has to be done in this way because we can't `enable_if` them away
139  */
140 template <
141     class T,
142     bool /* true iff destructible */,
143     bool /* true iff trivially destructible */>
144 struct dtor_mixin;
145
146 /* Destructible and trivially destructible */
147 template <class T>
148 struct dtor_mixin<T, true, true> {};
149
150 /* Destructible and not trivially destructible */
151 template <class T>
152 struct dtor_mixin<T, true, false> {
153   dtor_mixin() = default;
154   dtor_mixin(dtor_mixin&&) = default;
155   dtor_mixin(dtor_mixin const&) = default;
156   dtor_mixin& operator=(dtor_mixin&&) = default;
157   dtor_mixin& operator=(dtor_mixin const&) = default;
158   ~dtor_mixin() noexcept(std::is_nothrow_destructible<T>::value) {
159     T* destruct_ptr = launder(reinterpret_cast<T*>(
160         reinterpret_cast<Replaceable<T>*>(this)->storage_));
161     destruct_ptr->~T();
162   }
163 };
164
165 /* Not destructible */
166 template <class T, bool A>
167 struct dtor_mixin<T, false, A> {
168   dtor_mixin() = default;
169   dtor_mixin(dtor_mixin&&) = default;
170   dtor_mixin(dtor_mixin const&) = default;
171   dtor_mixin& operator=(dtor_mixin&&) = default;
172   dtor_mixin& operator=(dtor_mixin const&) = default;
173   ~dtor_mixin() = delete;
174 };
175
176 template <
177     class T,
178     bool /* true iff default constructible */,
179     bool /* true iff move constructible */>
180 struct default_and_move_ctor_mixin;
181
182 /* Not default-constructible and not move-constructible */
183 template <class T>
184 struct default_and_move_ctor_mixin<T, false, false> {
185   default_and_move_ctor_mixin() = delete;
186   default_and_move_ctor_mixin(default_and_move_ctor_mixin&&) = delete;
187   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
188   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
189       default;
190   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin const&) =
191       default;
192
193  protected:
194   inline explicit default_and_move_ctor_mixin(int) {}
195 };
196
197 /* Default-constructible and move-constructible */
198 template <class T>
199 struct default_and_move_ctor_mixin<T, true, true> {
200   inline default_and_move_ctor_mixin() noexcept(
201       std::is_nothrow_constructible<T>::value) {
202     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_) T();
203   }
204   inline default_and_move_ctor_mixin(
205       default_and_move_ctor_mixin&&
206           other) noexcept(std::is_nothrow_constructible<T, T&&>::value) {
207     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
208         T(*std::move(reinterpret_cast<Replaceable<T>&>(other)));
209   }
210   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
211   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
212       default;
213   inline default_and_move_ctor_mixin& operator=(
214       default_and_move_ctor_mixin const&) = default;
215
216  protected:
217   inline explicit default_and_move_ctor_mixin(int) {}
218 };
219
220 /* Default-constructible and not move-constructible */
221 template <class T>
222 struct default_and_move_ctor_mixin<T, true, false> {
223   inline default_and_move_ctor_mixin() noexcept(
224       std::is_nothrow_constructible<T>::value) {
225     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_) T();
226   }
227   default_and_move_ctor_mixin(default_and_move_ctor_mixin&&) = delete;
228   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
229   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
230       default;
231   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin const&) =
232       default;
233
234  protected:
235   inline explicit default_and_move_ctor_mixin(int) {}
236 };
237
238 /* Not default-constructible but is move-constructible */
239 template <class T>
240 struct default_and_move_ctor_mixin<T, false, true> {
241   default_and_move_ctor_mixin() = delete;
242   inline default_and_move_ctor_mixin(
243       default_and_move_ctor_mixin&&
244           other) noexcept(std::is_nothrow_constructible<T, T&&>::value) {
245     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
246         T(*std::move(reinterpret_cast<Replaceable<T>&>(other)));
247   }
248   default_and_move_ctor_mixin(default_and_move_ctor_mixin const&) = default;
249   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin&&) =
250       default;
251   default_and_move_ctor_mixin& operator=(default_and_move_ctor_mixin const&) =
252       default;
253
254  protected:
255   inline explicit default_and_move_ctor_mixin(int) {}
256 };
257
258 template <class T, bool /* true iff destructible and move constructible */>
259 struct move_assignment_mixin;
260
261 /* Not (destructible and move-constructible) */
262 template <class T>
263 struct move_assignment_mixin<T, false> {
264   move_assignment_mixin() = default;
265   move_assignment_mixin(move_assignment_mixin&&) = default;
266   move_assignment_mixin(move_assignment_mixin const&) = default;
267   move_assignment_mixin& operator=(move_assignment_mixin&&) = delete;
268   move_assignment_mixin& operator=(move_assignment_mixin const&) = default;
269 };
270
271 /* Both destructible and move-constructible */
272 template <class T>
273 struct move_assignment_mixin<T, true> {
274   move_assignment_mixin() = default;
275   move_assignment_mixin(move_assignment_mixin&&) = default;
276   move_assignment_mixin(move_assignment_mixin const&) = default;
277   inline move_assignment_mixin&
278   operator=(move_assignment_mixin&& other) noexcept(
279       std::is_nothrow_destructible<T>::value&&
280           std::is_nothrow_move_constructible<T>::value) {
281     T* destruct_ptr = launder(reinterpret_cast<T*>(
282         reinterpret_cast<Replaceable<T>*>(this)->storage_));
283     destruct_ptr->~T();
284     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
285         T(*std::move(reinterpret_cast<Replaceable<T>&>(other)));
286     return *this;
287   }
288   move_assignment_mixin& operator=(move_assignment_mixin const&) = default;
289 };
290
291 template <class T, bool /* true iff copy constructible */>
292 struct copy_ctor_mixin;
293
294 /* Not copy-constructible */
295 template <class T>
296 struct copy_ctor_mixin<T, false> {
297   copy_ctor_mixin() = default;
298   copy_ctor_mixin(copy_ctor_mixin&&) = default;
299   copy_ctor_mixin(copy_ctor_mixin const&) = delete;
300   copy_ctor_mixin& operator=(copy_ctor_mixin&&) = default;
301   copy_ctor_mixin& operator=(copy_ctor_mixin const&) = delete;
302 };
303
304 /* Copy-constructible */
305 template <class T>
306 struct copy_ctor_mixin<T, true> {
307   copy_ctor_mixin() = default;
308   inline copy_ctor_mixin(copy_ctor_mixin const& other) noexcept(
309       std::is_nothrow_constructible<T, T const&>::value) {
310     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_) T(*other);
311   }
312   copy_ctor_mixin(copy_ctor_mixin&&) = default;
313   copy_ctor_mixin& operator=(copy_ctor_mixin&&) = default;
314   copy_ctor_mixin& operator=(copy_ctor_mixin const&) = default;
315 };
316
317 template <class T, bool /* true iff destructible and copy constructible */>
318 struct copy_assignment_mixin;
319
320 /* Not (destructible and copy-constructible) */
321 template <class T>
322 struct copy_assignment_mixin<T, false> {
323   copy_assignment_mixin() = default;
324   copy_assignment_mixin(copy_assignment_mixin&&) = default;
325   copy_assignment_mixin(copy_assignment_mixin const&) = default;
326   copy_assignment_mixin& operator=(copy_assignment_mixin&&) = default;
327   copy_assignment_mixin& operator=(copy_assignment_mixin const&) = delete;
328 };
329
330 /* Both destructible and copy-constructible */
331 template <class T>
332 struct copy_assignment_mixin<T, true> {
333   copy_assignment_mixin() = default;
334   copy_assignment_mixin(copy_assignment_mixin&&) = default;
335   copy_assignment_mixin(copy_assignment_mixin const&) = default;
336   copy_assignment_mixin& operator=(copy_assignment_mixin&&) = default;
337   inline copy_assignment_mixin&
338   operator=(copy_assignment_mixin const& other) noexcept(
339       std::is_nothrow_destructible<T>::value&&
340           std::is_nothrow_copy_constructible<T>::value) {
341     T* destruct_ptr = launder(reinterpret_cast<T*>(
342         reinterpret_cast<Replaceable<T>*>(this)->storage_));
343     destruct_ptr->~T();
344     ::new (reinterpret_cast<Replaceable<T>*>(this)->storage_)
345         T(*reinterpret_cast<Replaceable<T> const&>(other));
346     return *this;
347   }
348 };
349
350 template <typename T>
351 struct is_constructible_from_replaceable
352     : std::integral_constant<
353           bool,
354           std::is_constructible<T, Replaceable<T>&>::value ||
355               std::is_constructible<T, Replaceable<T>&&>::value ||
356               std::is_constructible<T, const Replaceable<T>&>::value ||
357               std::is_constructible<T, const Replaceable<T>&&>::value> {};
358
359 template <typename T>
360 constexpr bool is_constructible_from_replaceable_v{
361     is_constructible_from_replaceable<T>::value};
362
363 template <typename T>
364 struct is_convertible_from_replaceable
365     : std::integral_constant<
366           bool,
367           std::is_convertible<Replaceable<T>&, T>::value ||
368               std::is_convertible<Replaceable<T>&&, T>::value ||
369               std::is_convertible<const Replaceable<T>&, T>::value ||
370               std::is_convertible<const Replaceable<T>&&, T>::value> {};
371
372 template <typename T>
373 constexpr bool is_convertible_from_replaceable_v{
374     is_convertible_from_replaceable<T>::value};
375 } // namespace replaceable_detail
376
377 // Type trait template to statically test whether a type is a specialization of
378 // Replaceable
379 template <class T>
380 struct is_replaceable : std::false_type {};
381
382 template <class T>
383 struct is_replaceable<Replaceable<T>> : std::true_type {};
384
385 template <class T>
386 constexpr bool is_replaceable_v{is_replaceable<T>::value};
387
388 // Function to make a Replaceable with a type deduced from its input
389 template <class T>
390 constexpr Replaceable<std::decay_t<T>> make_replaceable(T&& t) {
391   return Replaceable<std::decay_t<T>>(std::forward<T>(t));
392 }
393
394 template <class T, class... Args>
395 constexpr Replaceable<T> make_replaceable(Args&&... args) {
396   return Replaceable<T>(in_place, std::forward<Args>(args)...);
397 }
398
399 template <class T, class U, class... Args>
400 constexpr Replaceable<T> make_replaceable(
401     std::initializer_list<U> il,
402     Args&&... args) {
403   return Replaceable<T>(in_place, il, std::forward<Args>(args)...);
404 }
405
406 template <class T>
407 class alignas(T) Replaceable
408     : public replaceable_detail::dtor_mixin<
409           T,
410           std::is_destructible<T>::value,
411           std::is_trivially_destructible<T>::value>,
412       public replaceable_detail::default_and_move_ctor_mixin<
413           T,
414           std::is_default_constructible<T>::value,
415           std::is_move_constructible<T>::value>,
416       public replaceable_detail::
417           copy_ctor_mixin<T, std::is_copy_constructible<T>::value>,
418       public replaceable_detail::move_assignment_mixin<
419           T,
420           std::is_destructible<T>::value &&
421               std::is_move_constructible<T>::value>,
422       public replaceable_detail::copy_assignment_mixin<
423           T,
424           std::is_destructible<T>::value &&
425               std::is_copy_constructible<T>::value> {
426   using ctor_base = replaceable_detail::default_and_move_ctor_mixin<
427       T,
428       std::is_constructible<T>::value,
429       std::is_move_constructible<T>::value>;
430
431  public:
432   using value_type = T;
433
434   /* Rule-of-zero default- copy- and move- constructors. The ugly code to make
435    * these work are above, in namespace folly::replaceable_detail.
436    */
437   constexpr Replaceable() = default;
438   constexpr Replaceable(const Replaceable&) = default;
439   constexpr Replaceable(Replaceable&&) = default;
440
441   /* Rule-of-zero copy- and move- assignment operators. The ugly code to make
442    * these work are above, in namespace folly::replaceable_detail.
443    *
444    * Note - these destruct the `T` and then in-place construct a new one based
445    * on what is in the other replaceable; they do not invoke the assignment
446    * operator of `T`.
447    */
448   Replaceable& operator=(const Replaceable&) = default;
449   Replaceable& operator=(Replaceable&&) = default;
450
451   /* Rule-of-zero destructor. The ugly code to make this work is above, in
452    * namespace folly::replaceable_detail.
453    */
454   ~Replaceable() = default;
455
456   /**
457    * Constructors; these are modeled very closely on the definition of
458    * `std::optional` in C++17.
459    */
460   template <
461       class... Args,
462       std::enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
463   constexpr explicit Replaceable(in_place_t, Args&&... args)
464       // clang-format off
465       noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
466       // clang-format on
467       : ctor_base(0) {
468     ::new (storage_) T(std::forward<Args>(args)...);
469   }
470
471   template <
472       class U,
473       class... Args,
474       std::enable_if_t<
475           std::is_constructible<T, std::initializer_list<U>, Args&&...>::value,
476           int> = 0>
477   constexpr explicit Replaceable(
478       in_place_t,
479       std::initializer_list<U> il,
480       Args&&... args)
481       // clang-format off
482       noexcept(std::is_nothrow_constructible<
483           T,
484           std::initializer_list<U>,
485           Args&&...>::value)
486       // clang-format on
487       : ctor_base(0) {
488     ::new (storage_) T(il, std::forward<Args>(args)...);
489   }
490
491   template <
492       class U = T,
493       std::enable_if_t<
494           std::is_constructible<T, U&&>::value &&
495               !std::is_same<std::decay_t<U>, in_place_t>::value &&
496               !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
497               std::is_convertible<U&&, T>::value,
498           int> = 0>
499   constexpr /* implicit */ Replaceable(U&& other)
500       // clang-format off
501       noexcept(std::is_nothrow_constructible<T, U&&>::value)
502       // clang-format on
503       : ctor_base(0) {
504     ::new (storage_) T(std::forward<U>(other));
505   }
506
507   template <
508       class U = T,
509       std::enable_if_t<
510           std::is_constructible<T, U&&>::value &&
511               !std::is_same<std::decay_t<U>, in_place_t>::value &&
512               !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
513               !std::is_convertible<U&&, T>::value,
514           int> = 0>
515   explicit constexpr Replaceable(U&& other)
516       // clang-format off
517       noexcept(std::is_nothrow_constructible<T, U&&>::value)
518       // clang-format on
519       : ctor_base(0) {
520     ::new (storage_) T(std::forward<U>(other));
521   }
522
523   template <
524       class U,
525       std::enable_if_t<
526           std::is_constructible<T, const U&>::value &&
527               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
528               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
529               std::is_convertible<const U&, T>::value,
530           int> = 0>
531   /* implicit */ Replaceable(const Replaceable<U>& other)
532       // clang-format off
533       noexcept(std::is_nothrow_constructible<T, U const&>::value)
534       // clang-format on
535       : ctor_base(0) {
536     ::new (storage_) T(*other);
537   }
538
539   template <
540       class U,
541       std::enable_if_t<
542           std::is_constructible<T, const U&>::value &&
543               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
544               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
545               !std::is_convertible<const U&, T>::value,
546           int> = 0>
547   explicit Replaceable(const Replaceable<U>& other)
548       // clang-format off
549       noexcept(std::is_nothrow_constructible<T, U const&>::value)
550       // clang-format on
551       : ctor_base(0) {
552     ::new (storage_) T(*other);
553   }
554
555   template <
556       class U,
557       std::enable_if_t<
558           std::is_constructible<T, U&&>::value &&
559               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
560               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
561               std::is_convertible<U&&, T>::value,
562           int> = 0>
563   /* implicit */ Replaceable(Replaceable<U>&& other)
564       // clang-format off
565       noexcept(std::is_nothrow_constructible<T, U&&>::value)
566       // clang-format on
567       : ctor_base(0) {
568     ::new (storage_) T(std::move(*other));
569   }
570
571   template <
572       class U,
573       std::enable_if_t<
574           std::is_constructible<T, U&&>::value &&
575               !replaceable_detail::is_constructible_from_replaceable_v<T> &&
576               !replaceable_detail::is_convertible_from_replaceable_v<T> &&
577               !std::is_convertible<U&&, T>::value,
578           int> = 0>
579   explicit Replaceable(Replaceable<U>&& other)
580       // clang-format off
581       noexcept(std::is_nothrow_constructible<T, U&&>::value)
582       // clang-format on
583       : ctor_base(0) {
584     ::new (storage_) T(std::move(*other));
585   }
586
587   /**
588    * `emplace` destructs the contained object and in-place constructs the
589    * replacement.
590    *
591    * The destructor must not throw (as usual). The constructor must not throw
592    * because that would violate the invariant that a `Replaceable<T>` always
593    * contains a T instance.
594    *
595    * As these methods are `noexcept` the program will be terminated if an
596    * exception is thrown. If you are encountering this issue you should look at
597    * using `Optional` instead.
598    */
599   template <class... Args>
600   T& emplace(Args&&... args) noexcept {
601     T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
602     destruct_ptr->~T();
603     return *::new (storage_) T(std::forward<Args>(args)...);
604   }
605
606   template <class U, class... Args>
607   T& emplace(std::initializer_list<U> il, Args&&... args) noexcept {
608     T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
609     destruct_ptr->~T();
610     return *::new (storage_) T(il, std::forward<Args>(args)...);
611   }
612
613   /**
614    * `swap` just calls `swap(T&, T&)`.
615    *
616    * Should be `noexcept(std::is_nothrow_swappable<T>::value)` but we don't
617    * depend on C++17 features.
618    */
619   void swap(Replaceable& other) {
620     using std::swap;
621     swap(*(*this), *other);
622   }
623
624   /**
625    * Methods to access the contained object. Intended to be very unsurprising.
626    */
627   constexpr const T* operator->() const {
628     return launder(reinterpret_cast<T const*>(storage_));
629   }
630
631   constexpr T* operator->() {
632     return launder(reinterpret_cast<T*>(storage_));
633   }
634
635   constexpr const T& operator*() const & {
636     return *launder(reinterpret_cast<T const*>(storage_));
637   }
638
639   constexpr T& operator*() & {
640     return *launder(reinterpret_cast<T*>(storage_));
641   }
642
643   constexpr T&& operator*() && {
644     return std::move(*launder(reinterpret_cast<T*>(storage_)));
645   }
646
647   constexpr const T&& operator*() const && {
648     return std::move(*launder(reinterpret_cast<T const*>(storage_)));
649   }
650
651  private:
652   friend struct replaceable_detail::dtor_mixin<
653       T,
654       std::is_destructible<T>::value,
655       std::is_trivially_destructible<T>::value>;
656   friend struct replaceable_detail::default_and_move_ctor_mixin<
657       T,
658       std::is_default_constructible<T>::value,
659       std::is_move_constructible<T>::value>;
660   friend struct replaceable_detail::
661       copy_ctor_mixin<T, std::is_constructible<T, T const&>::value>;
662   friend struct replaceable_detail::move_assignment_mixin<
663       T,
664       std::is_destructible<T>::value && std::is_move_constructible<T>::value>;
665   friend struct replaceable_detail::copy_assignment_mixin<
666       T,
667       std::is_destructible<T>::value && std::is_copy_constructible<T>::value>;
668   std::aligned_storage_t<sizeof(T), alignof(T)> storage_[1];
669 };
670
671 #if __cplusplus > 201402L
672 // C++17 allows us to define a deduction guide:
673 template <class T>
674 Replaceable(T)->Replaceable<T>;
675 #endif
676 } // namespace folly