1 // Copyright 2021 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIB_LAZY_INIT_INTERNAL_STORAGE_H_
6 #define LIB_LAZY_INIT_INTERNAL_STORAGE_H_
7 
8 #include <lib/lazy_init/options.h>
9 
10 #include <type_traits>
11 #include <utility>
12 
13 #include "assert.h"
14 
15 namespace lazy_init {
16 namespace internal {
17 
18 // Empty type that is trivially constructible/destructible.
19 struct Empty {};
20 
21 // Lazy-initialized storage type for trivially destructible value types.
22 template <typename T, bool = std::is_trivially_destructible_v<T>>
23 union LazyInitStorage {
LazyInitStorage()24   constexpr LazyInitStorage() : empty{} {}
25 
26   // Trivial destructor required so that the overall union is also trivially
27   // destructible.
28   ~LazyInitStorage() = default;
29 
30   constexpr T& operator*() { return value; }
31   constexpr T* operator->() { return &value; }
GetStorageAddress()32   constexpr T* GetStorageAddress() { return &value; }
33 
34   constexpr const T& operator*() const { return value; }
35   constexpr const T* operator->() const { return &value; }
GetStorageAddress()36   constexpr const T* GetStorageAddress() const { return &value; }
37 
38   Empty empty;
39   T value;
40 };
41 
42 // Lazy-initialized storage type for non-trivially destructible value types.
43 template <typename T>
44 union LazyInitStorage<T, false> {
45   constexpr LazyInitStorage() : empty{} {}
46 
47   // Non-trivial destructor required when at least one variant is non-
48   // trivially destructible, making the overall union also non-trivially
49   // destructible.
50   ~LazyInitStorage() {}
51 
52   constexpr T& operator*() { return value; }
53   constexpr T* operator->() { return &value; }
54   constexpr T* GetStorageAddress() { return &value; }
55 
56   constexpr const T& operator*() const { return value; }
57   constexpr const T* operator->() const { return &value; }
58   constexpr const T* GetStorageAddress() const { return &value; }
59 
60   Empty empty;
61   T value;
62 };
63 
64 }  // namespace internal
65 }  // namespace lazy_init
66 #endif  // LIB_LAZY_INIT_INTERNAL_STORAGE_H_
67