internal/optional.h
Go to the documentation of this file.
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 
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 
58 // Forward declaration
59 template <typename T>
60 class optional;
61 
62 namespace optional_internal {
63 
64 // This tag type is used as a constructor parameter type for `nullopt_t`.
65 struct init_t {
66  explicit init_t() = default;
67 };
68 
69 struct empty_struct {};
70 
71 // This class stores the data in optional<T>.
72 // It is specialized based on whether T is trivially destructible.
73 // This is the specialization for non trivially destructible type.
76  struct dummy_type {
77  static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
78  // Use an array to avoid GCC 6 placement-new warning.
79  empty_struct data[sizeof(T) / sizeof(empty_struct)];
80  };
81 
82  protected:
83  // Whether there is data or not.
84  bool engaged_;
85  // Data storage
86  union {
87  dummy_type dummy_;
88  T data_;
89  };
90 
91  void destruct() noexcept {
92  if (engaged_) {
93  data_.~T();
94  engaged_ = false;
95  }
96  }
97 
98  // dummy_ must be initialized for constexpr constructor.
99  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
100 
101  template <typename... Args>
102  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
103  : engaged_(true), data_(absl::forward<Args>(args)...) {}
104 
105  ~optional_data_dtor_base() { destruct(); }
106 };
107 
108 // Specialization for trivially destructible type.
109 template <typename T>
110 class optional_data_dtor_base<T, true> {
111  struct dummy_type {
112  static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
113  // Use array to avoid GCC 6 placement-new warning.
114  empty_struct data[sizeof(T) / sizeof(empty_struct)];
115  };
116 
117  protected:
118  // Whether there is data or not.
119  bool engaged_;
120  // Data storage
121  union {
122  dummy_type dummy_;
123  T data_;
124  };
125  void destruct() noexcept { engaged_ = false; }
126 
127  // dummy_ must be initialized for constexpr constructor.
128  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
129 
130  template <typename... Args>
131  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
132  : engaged_(true), data_(absl::forward<Args>(args)...) {}
133 };
134 
135 template <typename T>
137  protected:
139 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
140  using base::base;
141 #else
142  optional_data_base() = default;
143 
144  template <typename... Args>
145  constexpr explicit optional_data_base(in_place_t t, Args&&... args)
146  : base(t, absl::forward<Args>(args)...) {}
147 #endif
148 
149  template <typename... Args>
150  void construct(Args&&... args) {
151  // Use dummy_'s address to work around casting cv-qualified T* to void*.
152  ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
153  this->engaged_ = true;
154  }
155 
156  template <typename U>
157  void assign(U&& u) {
158  if (this->engaged_) {
159  this->data_ = std::forward<U>(u);
160  } else {
161  construct(std::forward<U>(u));
162  }
163  }
164 };
165 
166 // TODO(absl-team): Add another class using
167 // std::is_trivially_move_constructible trait when available to match
168 // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
169 // have trivial move but nontrivial copy.
170 // Also, we should be checking is_trivially_copyable here, which is not
171 // supported now, so we use is_trivially_* traits instead.
172 template <typename T,
174  absl::is_trivially_copy_assignable<typename std::remove_cv<
177 
178 // Trivially copyable types
179 template <typename T>
180 class optional_data<T, true> : public optional_data_base<T> {
181  protected:
182 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
184 #else
185  optional_data() = default;
186 
187  template <typename... Args>
188  constexpr explicit optional_data(in_place_t t, Args&&... args)
189  : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
190 #endif
191 };
192 
193 template <typename T>
194 class optional_data<T, false> : public optional_data_base<T> {
195  protected:
196 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
198 #else
199  template <typename... Args>
200  constexpr explicit optional_data(in_place_t t, Args&&... args)
201  : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
202 #endif
203 
204  optional_data() = default;
205 
207  if (rhs.engaged_) {
208  this->construct(rhs.data_);
209  }
210  }
211 
212  optional_data(optional_data&& rhs) noexcept(
214  std::is_nothrow_move_constructible<T>::value)
215  : optional_data_base<T>() {
216  if (rhs.engaged_) {
217  this->construct(std::move(rhs.data_));
218  }
219  }
220 
222  if (rhs.engaged_) {
223  this->assign(rhs.data_);
224  } else {
225  this->destruct();
226  }
227  return *this;
228  }
229 
231  std::is_nothrow_move_assignable<T>::value&&
232  std::is_nothrow_move_constructible<T>::value) {
233  if (rhs.engaged_) {
234  this->assign(std::move(rhs.data_));
235  } else {
236  this->destruct();
237  }
238  return *this;
239  }
240 };
241 
242 // Ordered by level of restriction, from low to high.
243 // Copyable implies movable.
244 enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
245 
246 // Base class for enabling/disabling copy/move constructor.
247 template <copy_traits>
249 
250 template <>
252  public:
253  constexpr optional_ctor_base() = default;
254  optional_ctor_base(const optional_ctor_base&) = default;
256  optional_ctor_base& operator=(const optional_ctor_base&) = default;
257  optional_ctor_base& operator=(optional_ctor_base&&) = default;
258 };
259 
260 template <>
262  public:
263  constexpr optional_ctor_base() = default;
264  optional_ctor_base(const optional_ctor_base&) = delete;
266  optional_ctor_base& operator=(const optional_ctor_base&) = default;
267  optional_ctor_base& operator=(optional_ctor_base&&) = default;
268 };
269 
270 template <>
272  public:
273  constexpr optional_ctor_base() = default;
274  optional_ctor_base(const optional_ctor_base&) = delete;
276  optional_ctor_base& operator=(const optional_ctor_base&) = default;
277  optional_ctor_base& operator=(optional_ctor_base&&) = default;
278 };
279 
280 // Base class for enabling/disabling copy/move assignment.
281 template <copy_traits>
283 
284 template <>
286  public:
287  constexpr optional_assign_base() = default;
288  optional_assign_base(const optional_assign_base&) = default;
290  optional_assign_base& operator=(const optional_assign_base&) = default;
291  optional_assign_base& operator=(optional_assign_base&&) = default;
292 };
293 
294 template <>
296  public:
297  constexpr optional_assign_base() = default;
298  optional_assign_base(const optional_assign_base&) = default;
300  optional_assign_base& operator=(const optional_assign_base&) = delete;
301  optional_assign_base& operator=(optional_assign_base&&) = default;
302 };
303 
304 template <>
306  public:
307  constexpr optional_assign_base() = default;
308  optional_assign_base(const optional_assign_base&) = default;
310  optional_assign_base& operator=(const optional_assign_base&) = delete;
311  optional_assign_base& operator=(optional_assign_base&&) = delete;
312 };
313 
314 template <typename T>
316  static constexpr copy_traits traits =
321 };
322 
323 template <typename T>
325  static constexpr copy_traits traits =
332 };
333 
334 // Whether T is constructible or convertible from optional<U>.
335 template <typename T, typename U>
337  : std::integral_constant<
338  bool, std::is_constructible<T, optional<U>&>::value ||
339  std::is_constructible<T, optional<U>&&>::value ||
340  std::is_constructible<T, const optional<U>&>::value ||
341  std::is_constructible<T, const optional<U>&&>::value ||
342  std::is_convertible<optional<U>&, T>::value ||
343  std::is_convertible<optional<U>&&, T>::value ||
344  std::is_convertible<const optional<U>&, T>::value ||
345  std::is_convertible<const optional<U>&&, T>::value> {};
346 
347 // Whether T is constructible or convertible or assignable from optional<U>.
348 template <typename T, typename U>
350  : std::integral_constant<
351  bool, is_constructible_convertible_from_optional<T, U>::value ||
352  std::is_assignable<T&, optional<U>&>::value ||
353  std::is_assignable<T&, optional<U>&&>::value ||
354  std::is_assignable<T&, const optional<U>&>::value ||
355  std::is_assignable<T&, const optional<U>&&>::value> {};
356 
357 // Helper function used by [optional.relops], [optional.comp_with_t],
358 // for checking whether an expression is convertible to bool.
359 bool convertible_to_bool(bool);
360 
361 // Base class for std::hash<absl::optional<T>>:
362 // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
363 // compute the hash; Otherwise, it is disabled.
364 // Reference N4659 23.14.15 [unord.hash].
365 template <typename T, typename = size_t>
367  optional_hash_base() = delete;
368  optional_hash_base(const optional_hash_base&) = delete;
370  optional_hash_base& operator=(const optional_hash_base&) = delete;
371  optional_hash_base& operator=(optional_hash_base&&) = delete;
372 };
373 
374 template <typename T>
375 struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
376  std::declval<absl::remove_const_t<T> >()))> {
377  using argument_type = absl::optional<T>;
378  using result_type = size_t;
379  size_t operator()(const absl::optional<T>& opt) const {
380  absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
381  if (opt) {
382  return std::hash<absl::remove_const_t<T> >()(*opt);
383  } else {
384  return static_cast<size_t>(0x297814aaad196e6dULL);
385  }
386  }
387 };
388 
389 } // namespace optional_internal
390 } // namespace absl
391 
392 #undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
393 
394 #endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
optional_data(optional_data &&rhs) noexcept(absl::default_allocator_is_nothrow::value||std::is_nothrow_move_constructible< T >::value)
constexpr T && forward(absl::remove_reference_t< T > &t) noexcept
Definition: utility.h:228
constexpr optional_data(in_place_t t, Args &&...args)
constexpr optional_data_dtor_base(in_place_t, Args &&...args)
constexpr optional_data(in_place_t t, Args &&...args)
constexpr optional_data_dtor_base(in_place_t, Args &&...args)
Definition: algorithm.h:29
const char * data_
Definition: test_util.cc:98
bool convertible_to_bool(bool)
size_t value
static char data[kDataSize]
Definition: city_test.cc:31
hash_default_hash< typename T::first_type > hash
static std::function< void(void *, Slot *, Slot)> construct
optional_data & operator=(const optional_data &rhs)
optional_data & operator=(optional_data &&rhs) noexcept(std::is_nothrow_move_assignable< T >::value &&std::is_nothrow_move_constructible< T >::value)
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: utility.h:219
constexpr optional_data_base(in_place_t t, Args &&...args)


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:19:57