1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_
16 #define ABSL_TYPES_INTERNAL_OPTIONAL_H_
17 
18 #include <functional>
19 #include <new>
20 #include <type_traits>
21 #include <utility>
22 
23 #include "absl/base/internal/inline_variable.h"
24 #include "absl/memory/memory.h"
25 #include "absl/meta/type_traits.h"
26 #include "absl/utility/utility.h"
27 
28 // ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
29 //
30 // Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
31 // __cpp_inheriting_constructors is a predefined macro and a recommended way to
32 // check for this language feature, but GCC doesn't support it until 5.0 and
33 // Clang doesn't support it until 3.6.
34 // Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
35 // constructor. For example, the following code won't work on MSVC 2015 Update3:
36 // struct Base {
37 //   int t;
38 //   template <typename T>
39 //   constexpr Base(T t_) : t(t_) {}
40 // };
41 // struct Foo : Base {
42 //   using Base::Base;
43 // }
44 // constexpr Foo foo(0);  // doesn't work on MSVC 2015
45 #if defined(__clang__)
46 #if __has_feature(cxx_inheriting_constructors)
47 #define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
48 #endif
49 #elif (defined(__GNUC__) &&                                       \
50        (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
51     (__cpp_inheriting_constructors >= 200802) ||                  \
52     (defined(_MSC_VER) && _MSC_VER >= 1910)
53 #define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
54 #endif
55 
56 namespace absl {
57 ABSL_NAMESPACE_BEGIN
58 
59 // Forward declaration
60 template <typename T>
61 class optional;
62 
63 namespace optional_internal {
64 
65 // This tag type is used as a constructor parameter type for `nullopt_t`.
66 struct init_t {
67   explicit init_t() = default;
68 };
69 
70 struct empty_struct {};
71 
72 // This class stores the data in optional<T>.
73 // It is specialized based on whether T is trivially destructible.
74 // This is the specialization for non trivially destructible type.
75 template <typename T, bool unused = std::is_trivially_destructible<T>::value>
76 class optional_data_dtor_base {
77   struct dummy_type {
78     static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
79     // Use an array to avoid GCC 6 placement-new warning.
80     empty_struct data[sizeof(T) / sizeof(empty_struct)];
81   };
82 
83  protected:
84   // Whether there is data or not.
85   bool engaged_;
86   // Data storage
87   union {
88     T data_;
89     dummy_type dummy_;
90   };
91 
destruct()92   void destruct() noexcept {
93     if (engaged_) {
94       data_.~T();
95       engaged_ = false;
96     }
97   }
98 
99   // dummy_ must be initialized for constexpr constructor.
optional_data_dtor_base()100   constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
101 
102   template <typename... Args>
optional_data_dtor_base(in_place_t,Args &&...args)103   constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
104       : engaged_(true), data_(absl::forward<Args>(args)...) {}
105 
~optional_data_dtor_base()106   ~optional_data_dtor_base() { destruct(); }
107 };
108 
109 // Specialization for trivially destructible type.
110 template <typename T>
111 class optional_data_dtor_base<T, true> {
112   struct dummy_type {
113     static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
114     // Use array to avoid GCC 6 placement-new warning.
115     empty_struct data[sizeof(T) / sizeof(empty_struct)];
116   };
117 
118  protected:
119   // Whether there is data or not.
120   bool engaged_;
121   // Data storage
122   union {
123     T data_;
124     dummy_type dummy_;
125   };
destruct()126   void destruct() noexcept { engaged_ = false; }
127 
128   // dummy_ must be initialized for constexpr constructor.
optional_data_dtor_base()129   constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
130 
131   template <typename... Args>
optional_data_dtor_base(in_place_t,Args &&...args)132   constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
133       : engaged_(true), data_(absl::forward<Args>(args)...) {}
134 };
135 
136 template <typename T>
137 class optional_data_base : public optional_data_dtor_base<T> {
138  protected:
139   using base = optional_data_dtor_base<T>;
140 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
141   using base::base;
142 #else
143   optional_data_base() = default;
144 
145   template <typename... Args>
optional_data_base(in_place_t t,Args &&...args)146   constexpr explicit optional_data_base(in_place_t t, Args&&... args)
147       : base(t, absl::forward<Args>(args)...) {}
148 #endif
149 
150   template <typename... Args>
construct(Args &&...args)151   void construct(Args&&... args) {
152     // Use dummy_'s address to work around casting cv-qualified T* to void*.
153     ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
154     this->engaged_ = true;
155   }
156 
157   template <typename U>
assign(U && u)158   void assign(U&& u) {
159     if (this->engaged_) {
160       this->data_ = std::forward<U>(u);
161     } else {
162       construct(std::forward<U>(u));
163     }
164   }
165 };
166 
167 // TODO(absl-team): Add another class using
168 // std::is_trivially_move_constructible trait when available to match
169 // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
170 // have trivial move but nontrivial copy.
171 // Also, we should be checking is_trivially_copyable here, which is not
172 // supported now, so we use is_trivially_* traits instead.
173 template <typename T,
174           bool unused = absl::is_trivially_copy_constructible<T>::value&&
175               absl::is_trivially_copy_assignable<typename std::remove_cv<
176                   T>::type>::value&& std::is_trivially_destructible<T>::value>
177 class optional_data;
178 
179 // Trivially copyable types
180 template <typename T>
181 class optional_data<T, true> : public optional_data_base<T> {
182  protected:
183 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
184   using optional_data_base<T>::optional_data_base;
185 #else
186   optional_data() = default;
187 
188   template <typename... Args>
189   constexpr explicit optional_data(in_place_t t, Args&&... args)
190       : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
191 #endif
192 };
193 
194 template <typename T>
195 class optional_data<T, false> : public optional_data_base<T> {
196  protected:
197 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
198   using optional_data_base<T>::optional_data_base;
199 #else
200   template <typename... Args>
201   constexpr explicit optional_data(in_place_t t, Args&&... args)
202       : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
203 #endif
204 
205   optional_data() = default;
206 
optional_data(const optional_data & rhs)207   optional_data(const optional_data& rhs) : optional_data_base<T>() {
208     if (rhs.engaged_) {
209       this->construct(rhs.data_);
210     }
211   }
212 
213   optional_data(optional_data&& rhs) noexcept(
214       absl::default_allocator_is_nothrow::value ||
215       std::is_nothrow_move_constructible<T>::value)
216       : optional_data_base<T>() {
217     if (rhs.engaged_) {
218       this->construct(std::move(rhs.data_));
219     }
220   }
221 
222   optional_data& operator=(const optional_data& rhs) {
223     if (rhs.engaged_) {
224       this->assign(rhs.data_);
225     } else {
226       this->destruct();
227     }
228     return *this;
229   }
230 
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)231   optional_data& operator=(optional_data&& rhs) noexcept(
232       std::is_nothrow_move_assignable<T>::value&&
233           std::is_nothrow_move_constructible<T>::value) {
234     if (rhs.engaged_) {
235       this->assign(std::move(rhs.data_));
236     } else {
237       this->destruct();
238     }
239     return *this;
240   }
241 };
242 
243 // Ordered by level of restriction, from low to high.
244 // Copyable implies movable.
245 enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
246 
247 // Base class for enabling/disabling copy/move constructor.
248 template <copy_traits>
249 class optional_ctor_base;
250 
251 template <>
252 class optional_ctor_base<copy_traits::copyable> {
253  public:
254   constexpr optional_ctor_base() = default;
255   optional_ctor_base(const optional_ctor_base&) = default;
256   optional_ctor_base(optional_ctor_base&&) = default;
257   optional_ctor_base& operator=(const optional_ctor_base&) = default;
258   optional_ctor_base& operator=(optional_ctor_base&&) = default;
259 };
260 
261 template <>
262 class optional_ctor_base<copy_traits::movable> {
263  public:
264   constexpr optional_ctor_base() = default;
265   optional_ctor_base(const optional_ctor_base&) = delete;
266   optional_ctor_base(optional_ctor_base&&) = default;
267   optional_ctor_base& operator=(const optional_ctor_base&) = default;
268   optional_ctor_base& operator=(optional_ctor_base&&) = default;
269 };
270 
271 template <>
272 class optional_ctor_base<copy_traits::non_movable> {
273  public:
274   constexpr optional_ctor_base() = default;
275   optional_ctor_base(const optional_ctor_base&) = delete;
276   optional_ctor_base(optional_ctor_base&&) = delete;
277   optional_ctor_base& operator=(const optional_ctor_base&) = default;
278   optional_ctor_base& operator=(optional_ctor_base&&) = default;
279 };
280 
281 // Base class for enabling/disabling copy/move assignment.
282 template <copy_traits>
283 class optional_assign_base;
284 
285 template <>
286 class optional_assign_base<copy_traits::copyable> {
287  public:
288   constexpr optional_assign_base() = default;
289   optional_assign_base(const optional_assign_base&) = default;
290   optional_assign_base(optional_assign_base&&) = default;
291   optional_assign_base& operator=(const optional_assign_base&) = default;
292   optional_assign_base& operator=(optional_assign_base&&) = default;
293 };
294 
295 template <>
296 class optional_assign_base<copy_traits::movable> {
297  public:
298   constexpr optional_assign_base() = default;
299   optional_assign_base(const optional_assign_base&) = default;
300   optional_assign_base(optional_assign_base&&) = default;
301   optional_assign_base& operator=(const optional_assign_base&) = delete;
302   optional_assign_base& operator=(optional_assign_base&&) = default;
303 };
304 
305 template <>
306 class optional_assign_base<copy_traits::non_movable> {
307  public:
308   constexpr optional_assign_base() = default;
309   optional_assign_base(const optional_assign_base&) = default;
310   optional_assign_base(optional_assign_base&&) = default;
311   optional_assign_base& operator=(const optional_assign_base&) = delete;
312   optional_assign_base& operator=(optional_assign_base&&) = delete;
313 };
314 
315 template <typename T>
316 struct ctor_copy_traits {
317   static constexpr copy_traits traits =
318       std::is_copy_constructible<T>::value
319           ? copy_traits::copyable
320           : std::is_move_constructible<T>::value ? copy_traits::movable
321                                                  : copy_traits::non_movable;
322 };
323 
324 template <typename T>
325 struct assign_copy_traits {
326   static constexpr copy_traits traits =
327       absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
328           ? copy_traits::copyable
329           : absl::is_move_assignable<T>::value &&
330                     std::is_move_constructible<T>::value
331                 ? copy_traits::movable
332                 : copy_traits::non_movable;
333 };
334 
335 // Whether T is constructible or convertible from optional<U>.
336 template <typename T, typename U>
337 struct is_constructible_convertible_from_optional
338     : std::integral_constant<
339           bool, std::is_constructible<T, optional<U>&>::value ||
340                     std::is_constructible<T, optional<U>&&>::value ||
341                     std::is_constructible<T, const optional<U>&>::value ||
342                     std::is_constructible<T, const optional<U>&&>::value ||
343                     std::is_convertible<optional<U>&, T>::value ||
344                     std::is_convertible<optional<U>&&, T>::value ||
345                     std::is_convertible<const optional<U>&, T>::value ||
346                     std::is_convertible<const optional<U>&&, T>::value> {};
347 
348 // Whether T is constructible or convertible or assignable from optional<U>.
349 template <typename T, typename U>
350 struct is_constructible_convertible_assignable_from_optional
351     : std::integral_constant<
352           bool, is_constructible_convertible_from_optional<T, U>::value ||
353                     std::is_assignable<T&, optional<U>&>::value ||
354                     std::is_assignable<T&, optional<U>&&>::value ||
355                     std::is_assignable<T&, const optional<U>&>::value ||
356                     std::is_assignable<T&, const optional<U>&&>::value> {};
357 
358 // Helper function used by [optional.relops], [optional.comp_with_t],
359 // for checking whether an expression is convertible to bool.
360 bool convertible_to_bool(bool);
361 
362 // Base class for std::hash<absl::optional<T>>:
363 // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
364 // compute the hash; Otherwise, it is disabled.
365 // Reference N4659 23.14.15 [unord.hash].
366 template <typename T, typename = size_t>
367 struct optional_hash_base {
368   optional_hash_base() = delete;
369   optional_hash_base(const optional_hash_base&) = delete;
370   optional_hash_base(optional_hash_base&&) = delete;
371   optional_hash_base& operator=(const optional_hash_base&) = delete;
372   optional_hash_base& operator=(optional_hash_base&&) = delete;
373 };
374 
375 template <typename T>
376 struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
377                                  std::declval<absl::remove_const_t<T> >()))> {
378   using argument_type = absl::optional<T>;
379   using result_type = size_t;
380   size_t operator()(const absl::optional<T>& opt) const {
381     absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
382     if (opt) {
383       return std::hash<absl::remove_const_t<T> >()(*opt);
384     } else {
385       return static_cast<size_t>(0x297814aaad196e6dULL);
386     }
387   }
388 };
389 
390 }  // namespace optional_internal
391 ABSL_NAMESPACE_END
392 }  // namespace absl
393 
394 #undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
395 
396 #endif  // ABSL_TYPES_INTERNAL_OPTIONAL_H_
397