change type naming style
[kazan.git] / src / util / optional.h
1 /*
2 * Copyright 2017 Jacob Lifshay
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 */
23
24 #ifndef UTIL_OPTIONAL_H_
25 #define UTIL_OPTIONAL_H_
26
27 #include <type_traits>
28 #include <new>
29 #include <memory>
30 #include <initializer_list>
31 #include <utility>
32 #include <cassert>
33 #include <exception>
34 #include <functional>
35 #include "in_place.h"
36 #include "is_swappable.h"
37
38 namespace vulkan_cpu
39 {
40 namespace util
41 {
42 struct nullopt_t
43 {
44 constexpr explicit nullopt_t(int)
45 {
46 }
47 };
48
49 constexpr nullopt_t nullopt(0);
50
51 class bad_optional_access : public std::exception
52 {
53 public:
54 virtual const char *what() const noexcept override
55 {
56 return "bad_optional_access";
57 }
58 };
59
60 namespace detail
61 {
62 template <typename T,
63 bool Is_Trivially_Destructible = std::is_trivially_destructible<T>::value,
64 bool Is_Trivially_Copyable = std::is_trivially_copyable<T>::value>
65 struct Optional_base
66 {
67 union
68 {
69 T full_value;
70 alignas(T) char empty_value[sizeof(T)];
71 };
72 bool is_full;
73 constexpr Optional_base() noexcept : empty_value{}, is_full(false)
74 {
75 }
76 constexpr Optional_base(nullopt_t) noexcept : empty_value{}, is_full(false)
77 {
78 }
79 void reset() noexcept
80 {
81 if(is_full)
82 full_value.~T();
83 }
84 template <typename... Types>
85 T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
86 {
87 reset();
88 ::new(static_cast<void *>(std::addressof(full_value))) T(std::forward<Types>(args)...);
89 is_full = true;
90 return full_value;
91 }
92 template <
93 typename U,
94 typename... Types,
95 typename = typename std::
96 enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
97 T &emplace(std::initializer_list<U> init_list, Types &&... args) noexcept(
98 std::is_nothrow_constructible<T, std::initializer_list<U>, Types...>::value)
99 {
100 reset();
101 ::new(static_cast<void *>(std::addressof(full_value)))
102 T(init_list, std::forward<Types>(args)...);
103 is_full = true;
104 return full_value;
105 }
106 Optional_base(const Optional_base &rt) noexcept(std::is_nothrow_copy_constructible<T>::value)
107 : empty_value{}, is_full(false)
108 {
109 if(rt.is_full)
110 emplace(rt.full_value);
111 }
112 Optional_base(Optional_base &&rt) noexcept(std::is_nothrow_move_constructible<T>::value)
113 : empty_value{}, is_full(false)
114 {
115 if(rt.is_full)
116 emplace(std::move(rt.full_value));
117 }
118 template <typename... Types,
119 typename = typename std::enable_if<std::is_constructible<T, Types...>::value>::type>
120 constexpr explicit Optional_base(in_place_t, Types &&... args) noexcept(
121 std::is_nothrow_constructible<T, Types...>::value)
122 : full_value(std::forward<Types>(args)...), is_full(true)
123 {
124 }
125 template <
126 typename U,
127 typename... Types,
128 typename = typename std::
129 enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
130 constexpr explicit Optional_base(
131 in_place_t,
132 std::initializer_list<U> init_list,
133 Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
134 : full_value(init_list, std::forward<Types>(args)...), is_full(true)
135 {
136 }
137 ~Optional_base()
138 {
139 reset();
140 }
141 Optional_base &operator=(const Optional_base &rt) noexcept(
142 std::is_nothrow_copy_assignable<T>::value)
143 {
144 if(!rt.is_full)
145 reset();
146 else if(!is_full)
147 emplace(rt.full_value);
148 else
149 full_value = rt.full_value;
150 return *this;
151 }
152 Optional_base &operator=(Optional_base &&rt) noexcept(std::is_nothrow_move_assignable<T>::value)
153 {
154 if(!rt.is_full)
155 reset();
156 else if(!is_full)
157 emplace(std::move(rt.full_value));
158 else
159 full_value = std::move(rt.full_value);
160 return *this;
161 }
162 };
163
164 template <typename T>
165 struct Optional_base<T, true, false>
166 {
167 union
168 {
169 T full_value;
170 alignas(T) char empty_value[sizeof(T)];
171 };
172 bool is_full;
173 constexpr Optional_base() noexcept : empty_value{}, is_full(false)
174 {
175 }
176 constexpr Optional_base(nullopt_t) noexcept : empty_value{}, is_full(false)
177 {
178 }
179 void reset() noexcept
180 {
181 // full_value.~T() not needed
182 }
183 template <typename... Types>
184 T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
185 {
186 reset();
187 ::new(static_cast<void *>(std::addressof(full_value))) T(std::forward<Types>(args)...);
188 is_full = true;
189 return full_value;
190 }
191 template <
192 typename U,
193 typename... Types,
194 typename = typename std::
195 enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
196 T &emplace(std::initializer_list<U> init_list, Types &&... args) noexcept(
197 std::is_nothrow_constructible<T, std::initializer_list<U>, Types...>::value)
198 {
199 reset();
200 ::new(static_cast<void *>(std::addressof(full_value)))
201 T(init_list, std::forward<Types>(args)...);
202 is_full = true;
203 return full_value;
204 }
205 Optional_base(const Optional_base &rt) noexcept(std::is_nothrow_copy_constructible<T>::value)
206 : empty_value{}, is_full(false)
207 {
208 if(rt.is_full)
209 emplace(rt.full_value);
210 }
211 Optional_base(Optional_base &&rt) noexcept(std::is_nothrow_move_constructible<T>::value)
212 : empty_value{}, is_full(false)
213 {
214 if(rt.is_full)
215 emplace(std::move(rt.full_value));
216 }
217 template <typename... Types,
218 typename = typename std::enable_if<std::is_constructible<T, Types...>::value>::type>
219 constexpr explicit Optional_base(in_place_t, Types &&... args) noexcept(
220 std::is_nothrow_constructible<T, Types...>::value)
221 : full_value(std::forward<Types>(args)...), is_full(true)
222 {
223 }
224 template <
225 typename U,
226 typename... Types,
227 typename = typename std::
228 enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
229 constexpr explicit Optional_base(
230 in_place_t,
231 std::initializer_list<U> init_list,
232 Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
233 : full_value(init_list, std::forward<Types>(args)...), is_full(true)
234 {
235 }
236 ~Optional_base() = default;
237 Optional_base &operator=(const Optional_base &rt) noexcept(
238 std::is_nothrow_copy_assignable<T>::value)
239 {
240 if(!rt.is_full)
241 reset();
242 else if(!is_full)
243 emplace(rt.full_value);
244 else
245 full_value = rt.full_value;
246 return *this;
247 }
248 Optional_base &operator=(Optional_base &&rt) noexcept(std::is_nothrow_move_assignable<T>::value)
249 {
250 if(!rt.is_full)
251 reset();
252 else if(!is_full)
253 emplace(std::move(rt.full_value));
254 else
255 full_value = std::move(rt.full_value);
256 return *this;
257 }
258 };
259
260 template <typename T>
261 struct Optional_base<T, true, true>
262 {
263 union
264 {
265 T full_value;
266 alignas(T) char empty_value[sizeof(T)];
267 };
268 bool is_full;
269 constexpr Optional_base() noexcept : empty_value{}, is_full(false)
270 {
271 }
272 constexpr Optional_base(nullopt_t) noexcept : empty_value{}, is_full(false)
273 {
274 }
275 void reset() noexcept
276 {
277 // full_value.~T() not needed
278 }
279 template <typename... Types>
280 T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
281 {
282 reset();
283 ::new(static_cast<void *>(std::addressof(full_value))) T(std::forward<Types>(args)...);
284 is_full = true;
285 return full_value;
286 }
287 template <
288 typename U,
289 typename... Types,
290 typename = typename std::
291 enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
292 T &emplace(std::initializer_list<U> init_list, Types &&... args) noexcept(
293 std::is_nothrow_constructible<T, std::initializer_list<U>, Types...>::value)
294 {
295 reset();
296 ::new(static_cast<void *>(std::addressof(full_value)))
297 T(init_list, std::forward<Types>(args)...);
298 is_full = true;
299 return full_value;
300 }
301 constexpr Optional_base(const Optional_base &rt) noexcept = default;
302 constexpr Optional_base(Optional_base &&rt) noexcept = default;
303 template <typename... Types,
304 typename = typename std::enable_if<std::is_constructible<T, Types...>::value>::type>
305 constexpr explicit Optional_base(in_place_t, Types &&... args) noexcept(
306 std::is_nothrow_constructible<T, Types...>::value)
307 : full_value(std::forward<Types>(args)...), is_full(true)
308 {
309 }
310 template <
311 typename U,
312 typename... Types,
313 typename = typename std::
314 enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
315 constexpr explicit Optional_base(
316 in_place_t,
317 std::initializer_list<U> init_list,
318 Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
319 : full_value(init_list, std::forward<Types>(args)...), is_full(true)
320 {
321 }
322 ~Optional_base() = default;
323 Optional_base &operator=(const Optional_base &rt) noexcept = default;
324 Optional_base &operator=(Optional_base &&rt) noexcept = default;
325 };
326 }
327
328 template <typename T>
329 class optional;
330
331 namespace detail
332 {
333 template <typename T, typename U, typename U_Ref>
334 constexpr bool optional_needs_conversion_constructors() noexcept
335 {
336 if(!std::is_constructible<T, U_Ref>::value)
337 return false;
338 if(std::is_constructible<T, optional<U> &>::value)
339 return false;
340 if(std::is_constructible<T, const optional<U> &>::value)
341 return false;
342 if(std::is_constructible<T, optional<U> &&>::value)
343 return false;
344 if(std::is_constructible<T, const optional<U> &&>::value)
345 return false;
346 if(std::is_convertible<optional<U> &, T>::value)
347 return false;
348 if(std::is_convertible<const optional<U> &, T>::value)
349 return false;
350 if(std::is_convertible<optional<U> &&, T>::value)
351 return false;
352 if(std::is_convertible<const optional<U> &&, T>::value)
353 return false;
354 return true;
355 }
356
357 template <typename T, typename U, typename U_Ref>
358 constexpr bool optional_needs_conversion_from_optional_assign_operators() noexcept
359 {
360 if(!std::is_constructible<T, U_Ref>::value)
361 return false;
362 if(!std::is_assignable<T &, U_Ref>::value)
363 return false;
364 if(std::is_constructible<T, optional<U> &>::value)
365 return false;
366 if(std::is_constructible<T, const optional<U> &>::value)
367 return false;
368 if(std::is_constructible<T, optional<U> &&>::value)
369 return false;
370 if(std::is_constructible<T, const optional<U> &&>::value)
371 return false;
372 if(std::is_convertible<optional<U> &, T>::value)
373 return false;
374 if(std::is_convertible<const optional<U> &, T>::value)
375 return false;
376 if(std::is_convertible<optional<U> &&, T>::value)
377 return false;
378 if(std::is_convertible<const optional<U> &&, T>::value)
379 return false;
380 if(std::is_assignable<T &, optional<U> &>::value)
381 return false;
382 if(std::is_assignable<T &, const optional<U> &>::value)
383 return false;
384 if(std::is_assignable<T &, optional<U> &&>::value)
385 return false;
386 if(std::is_assignable<T &, const optional<U> &&>::value)
387 return false;
388 return true;
389 }
390 }
391
392 template <typename T>
393 class optional : private detail::Optional_base<T>
394 {
395 private:
396 typedef detail::Optional_base<T> Base;
397 using Base::is_full;
398 using Base::full_value;
399
400 public:
401 using Base::Base;
402 using Base::operator=;
403 using Base::reset;
404 using Base::emplace;
405 constexpr optional() noexcept = default;
406 template <typename U,
407 typename = typename std::
408 enable_if<detail::optional_needs_conversion_constructors<T, U, const U &>()
409 && std::is_convertible<const U &, T>::value>::type>
410 optional(const optional<U> &rt) noexcept(std::is_nothrow_constructible<T, const U &>::value)
411 : Base()
412 {
413 if(rt)
414 emplace(*rt);
415 }
416 template <typename U,
417 typename = typename std::
418 enable_if<detail::optional_needs_conversion_constructors<T, U, const U &>()
419 && !std::is_convertible<const U &, T>::value>::type,
420 typename = void>
421 explicit optional(const optional<U> &rt) noexcept(
422 std::is_nothrow_constructible<T, const U &>::value)
423 : Base()
424 {
425 if(rt)
426 emplace(*rt);
427 }
428 template <
429 typename U,
430 typename =
431 typename std::enable_if<detail::optional_needs_conversion_constructors<T, U, U &&>()
432 && std::is_convertible<U &&, T>::value>::type>
433 optional(optional<U> &&rt) noexcept(std::is_nothrow_constructible<T, U &&>::value)
434 : Base()
435 {
436 if(rt)
437 emplace(std::move(*rt));
438 }
439 template <
440 typename U,
441 typename =
442 typename std::enable_if<detail::optional_needs_conversion_constructors<T, U, U &&>()
443 && !std::is_convertible<U &&, T>::value>::type,
444 typename = void>
445 explicit optional(optional<U> &&rt) noexcept(std::is_nothrow_constructible<T, U &&>::value)
446 : Base()
447 {
448 if(rt)
449 emplace(std::move(*rt));
450 }
451 template <typename U,
452 typename = typename std::
453 enable_if<std::is_constructible<T, U &&>::value
454 && !std::is_same<typename std::decay<U>::type, in_place_t>::value
455 && !std::is_same<typename std::decay<U>::type, optional>::value
456 && std::is_convertible<U &&, T>::value>::type,
457 typename = void>
458 constexpr optional(U &&value) noexcept(std::is_nothrow_constructible<T, U &&>::value)
459 : Base(in_place, std::forward<U>(value))
460 {
461 }
462 template <typename U,
463 typename = typename std::
464 enable_if<std::is_constructible<T, U &&>::value
465 && !std::is_same<typename std::decay<U>::type, in_place_t>::value
466 && !std::is_same<typename std::decay<U>::type, optional>::value
467 && !std::is_convertible<U &&, T>::value>::type>
468 explicit constexpr optional(U &&value) noexcept(std::is_nothrow_constructible<T, U &&>::value)
469 : Base(in_place, std::forward<U>(value))
470 {
471 }
472 template <typename U = T,
473 typename = typename std::
474 enable_if<!std::is_same<typename std::decay<U>::type, optional>::value
475 && std::is_constructible<T, U>::value
476 && std::is_assignable<T &, U>::value
477 && (!std::is_scalar<T>::value
478 || !std::is_same<typename std::decay<U>::type, T>::value)>::type>
479 optional &operator=(U &&value) noexcept(std::is_nothrow_constructible<T, U &&>::value
480 &&std::is_nothrow_assignable<T &, U &&>::value)
481 {
482 if(is_full)
483 full_value = std::forward<U>(value);
484 else
485 emplace(std::forward<U>(value));
486 return *this;
487 }
488 optional &operator=(nullopt_t) noexcept
489 {
490 reset();
491 return *this;
492 }
493 template <
494 typename U,
495 typename = typename std::enable_if< //
496 detail::optional_needs_conversion_from_optional_assign_operators<T, U, const U &>()>::
497 type>
498 optional &operator=(const optional<U> &rt) noexcept(
499 std::is_nothrow_constructible<T, const U &>::value
500 &&std::is_nothrow_assignable<T &, const U &>::value)
501 {
502 if(!rt)
503 reset();
504 else if(!is_full)
505 emplace(*rt);
506 else
507 full_value = *rt;
508 return *this;
509 }
510 template <
511 typename U,
512 typename = typename std::enable_if< //
513 detail::optional_needs_conversion_from_optional_assign_operators<T, U, U &&>()>::type>
514 optional &operator=(optional<U> &&rt) noexcept(std::is_nothrow_constructible<T, U &&>::value &&
515 std::is_nothrow_assignable<T &, U &&>::value)
516 {
517 if(!rt)
518 reset();
519 else if(!is_full)
520 emplace(std::move(*rt));
521 else
522 full_value = std::move(*rt);
523 return *this;
524 }
525 constexpr const T *operator->() const noexcept
526 {
527 assert(is_full);
528 return std::addressof(full_value);
529 }
530 constexpr T *operator->() noexcept
531 {
532 assert(is_full);
533 return std::addressof(full_value);
534 }
535 constexpr const T &operator*() const &noexcept
536 {
537 assert(is_full);
538 return full_value;
539 }
540 constexpr T &operator*() & noexcept
541 {
542 assert(is_full);
543 return full_value;
544 }
545 constexpr const T &&operator*() const &&noexcept
546 {
547 assert(is_full);
548 return std::move(full_value);
549 }
550 constexpr T &&operator*() && noexcept
551 {
552 assert(is_full);
553 return std::move(full_value);
554 }
555 constexpr explicit operator bool() const noexcept
556 {
557 return is_full;
558 }
559 constexpr bool has_value() const noexcept
560 {
561 return is_full;
562 }
563 constexpr T &value() &
564 {
565 if(!is_full)
566 throw bad_optional_access();
567 return full_value;
568 }
569 constexpr const T &value() const &
570 {
571 if(!is_full)
572 throw bad_optional_access();
573 return full_value;
574 }
575 constexpr T &&value() &&
576 {
577 if(!is_full)
578 throw bad_optional_access();
579 return std::move(full_value);
580 }
581 constexpr const T &&value() const &&
582 {
583 if(!is_full)
584 throw bad_optional_access();
585 return std::move(full_value);
586 }
587 template <typename U>
588 constexpr T value_or(U &&default_value) const &noexcept(
589 std::is_nothrow_copy_constructible<T>::value //
590 &&noexcept(static_cast<T>(std::declval<U>())))
591 {
592 return is_full ? full_value : static_cast<T>(std::forward<U>(default_value));
593 }
594 template <typename U>
595 constexpr T value_or(U &&default_value)
596 && noexcept(std::is_nothrow_copy_constructible<T>::value //
597 &&noexcept(static_cast<T>(std::declval<U>())))
598 {
599 return is_full ? std::move(full_value) : static_cast<T>(std::forward<U>(default_value));
600 }
601 void swap(optional &other) noexcept(
602 std::is_nothrow_move_constructible<T>::value &&util::is_nothrow_swappable<T>::value)
603 {
604 if(is_full)
605 {
606 if(other.is_full)
607 {
608 using std::swap;
609 swap(full_value, other.full_value);
610 }
611 else
612 {
613 other.emplace(std::move(full_value));
614 reset();
615 }
616 }
617 else if(other.is_full)
618 {
619 emplace(std::move(other.full_value));
620 other.reset();
621 }
622 }
623 };
624
625 template <typename T, typename U>
626 constexpr bool operator==(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
627 {
628 if(!l.has_value() || !r.has_value())
629 return !r.has_value();
630 return *l == *r;
631 }
632
633 template <typename T, typename U>
634 constexpr bool operator!=(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
635 {
636 if(!l.has_value() || !r.has_value())
637 return r.has_value();
638 return *l != *r;
639 }
640
641 template <typename T, typename U>
642 constexpr bool operator<(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
643 {
644 if(!l.has_value() || !r.has_value())
645 return r.has_value();
646 return *l < *r;
647 }
648
649 template <typename T, typename U>
650 constexpr bool operator>(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
651 {
652 if(!l.has_value() || !r.has_value())
653 return l.has_value();
654 return *l > *r;
655 }
656
657 template <typename T, typename U>
658 constexpr bool operator<=(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
659 {
660 if(!l.has_value() || !r.has_value())
661 return !l.has_value();
662 return *l <= *r;
663 }
664
665 template <typename T, typename U>
666 constexpr bool operator>=(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
667 {
668 if(!l.has_value() || !r.has_value())
669 return !r.has_value();
670 return *l >= *r;
671 }
672
673 template <typename T>
674 constexpr bool operator==(const optional<T> &v, nullopt_t) noexcept
675 {
676 return !v.has_value();
677 }
678
679 template <typename T>
680 constexpr bool operator!=(const optional<T> &v, nullopt_t) noexcept
681 {
682 return v.has_value();
683 }
684
685 template <typename T>
686 constexpr bool operator<(const optional<T> &v, nullopt_t) noexcept
687 {
688 return false;
689 }
690
691 template <typename T>
692 constexpr bool operator>(const optional<T> &v, nullopt_t) noexcept
693 {
694 return v.has_value();
695 }
696
697 template <typename T>
698 constexpr bool operator<=(const optional<T> &v, nullopt_t) noexcept
699 {
700 return !v.has_value();
701 }
702
703 template <typename T>
704 constexpr bool operator>=(const optional<T> &v, nullopt_t) noexcept
705 {
706 return true;
707 }
708
709 template <typename T>
710 constexpr bool operator==(nullopt_t, const optional<T> &v) noexcept
711 {
712 return !v.has_value();
713 }
714
715 template <typename T>
716 constexpr bool operator!=(nullopt_t, const optional<T> &v) noexcept
717 {
718 return v.has_value();
719 }
720
721 template <typename T>
722 constexpr bool operator<(nullopt_t, const optional<T> &v) noexcept
723 {
724 return v.has_value();
725 }
726
727 template <typename T>
728 constexpr bool operator>(nullopt_t, const optional<T> &v) noexcept
729 {
730 return false;
731 }
732
733 template <typename T>
734 constexpr bool operator<=(nullopt_t, const optional<T> &v) noexcept
735 {
736 return true;
737 }
738
739 template <typename T>
740 constexpr bool operator>=(nullopt_t, const optional<T> &v) noexcept
741 {
742 return !v.has_value();
743 }
744
745 template <typename T, typename U>
746 constexpr bool operator==(const optional<T> &l, const U &r) noexcept(
747 noexcept(static_cast<bool>(std::declval<const T &>() == std::declval<const U &>())))
748 {
749 if(l)
750 return *l == r;
751 return false;
752 }
753
754 template <typename T, typename U>
755 constexpr bool operator==(const U &l, const optional<T> &r) noexcept(
756 noexcept(static_cast<bool>(std::declval<const U &>() == std::declval<const T &>())))
757 {
758 if(r)
759 return l == *r;
760 return false;
761 }
762
763 template <typename T, typename U>
764 constexpr bool operator!=(const optional<T> &l, const U &r) noexcept(
765 noexcept(static_cast<bool>(std::declval<const T &>() != std::declval<const U &>())))
766 {
767 if(l)
768 return *l != r;
769 return true;
770 }
771
772 template <typename T, typename U>
773 constexpr bool operator!=(const U &l, const optional<T> &r) noexcept(
774 noexcept(static_cast<bool>(std::declval<const U &>() != std::declval<const T &>())))
775 {
776 if(r)
777 return l != *r;
778 return true;
779 }
780
781 template <typename T, typename U>
782 constexpr bool operator<(const optional<T> &l, const U &r) noexcept(
783 noexcept(static_cast<bool>(std::declval<const T &>() < std::declval<const U &>())))
784 {
785 if(l)
786 return *l < r;
787 return true;
788 }
789
790 template <typename T, typename U>
791 constexpr bool operator<(const U &l, const optional<T> &r) noexcept(
792 noexcept(static_cast<bool>(std::declval<const U &>() < std::declval<const T &>())))
793 {
794 if(r)
795 return l < *r;
796 return false;
797 }
798
799 template <typename T, typename U>
800 constexpr bool operator>(const optional<T> &l, const U &r) noexcept(
801 noexcept(static_cast<bool>(std::declval<const T &>() > std::declval<const U &>())))
802 {
803 if(l)
804 return *l > r;
805 return false;
806 }
807
808 template <typename T, typename U>
809 constexpr bool operator>(const U &l, const optional<T> &r) noexcept(
810 noexcept(static_cast<bool>(std::declval<const U &>() > std::declval<const T &>())))
811 {
812 if(r)
813 return l > *r;
814 return true;
815 }
816
817 template <typename T, typename U>
818 constexpr bool operator<=(const optional<T> &l, const U &r) noexcept(
819 noexcept(static_cast<bool>(std::declval<const T &>() <= std::declval<const U &>())))
820 {
821 if(l)
822 return *l <= r;
823 return true;
824 }
825
826 template <typename T, typename U>
827 constexpr bool operator<=(const U &l, const optional<T> &r) noexcept(
828 noexcept(static_cast<bool>(std::declval<const U &>() <= std::declval<const T &>())))
829 {
830 if(r)
831 return l <= *r;
832 return false;
833 }
834
835 template <typename T, typename U>
836 constexpr bool operator>=(const optional<T> &l, const U &r) noexcept(
837 noexcept(static_cast<bool>(std::declval<const T &>() >= std::declval<const U &>())))
838 {
839 if(l)
840 return *l >= r;
841 return false;
842 }
843
844 template <typename T, typename U>
845 constexpr bool operator>=(const U &l, const optional<T> &r) noexcept(
846 noexcept(static_cast<bool>(std::declval<const U &>() >= std::declval<const T &>())))
847 {
848 if(r)
849 return l >= *r;
850 return true;
851 }
852
853 template <typename T>
854 constexpr optional<typename std::decay<T>::type> make_optional(T &&value)
855 {
856 return optional<typename std::decay<T>::type>(in_place, std::forward<T>(value));
857 }
858
859 template <typename T, typename... Args>
860 constexpr optional<T> make_optional(Args &&... args)
861 {
862 return optional<T>(in_place, std::forward<T>(args)...);
863 }
864
865 template <typename T, typename U, typename... Args>
866 constexpr optional<T> make_optional(std::initializer_list<U> init_list, Args &&... args)
867 {
868 return optional<T>(in_place, init_list, std::forward<T>(args)...);
869 }
870
871 template <typename T,
872 typename = typename std::enable_if<std::is_move_constructible<T>::value
873 && is_swappable<T>::value>::type>
874 void swap(optional<T> &l, optional<T> &r) noexcept(noexcept(l.swap(r)))
875 {
876 l.swap(r);
877 }
878
879 namespace detail
880 {
881 template <typename T, bool Is_Enabled = std::is_default_constructible<std::hash<T>>::value>
882 struct optional_hash
883 {
884 constexpr std::size_t operator()(const optional<T> &value) const
885 noexcept(noexcept(static_cast<std::size_t>(std::hash<T>()(std::declval<const T &>()))))
886 {
887 if(value)
888 return std::hash<T>()(*value);
889 return 0;
890 }
891 };
892
893 template <typename T>
894 struct optional_hash<T, false>
895 {
896 optional_hash() noexcept = delete;
897 ~optional_hash() = delete;
898 optional_hash(const optional_hash &) noexcept = delete;
899 optional_hash &operator=(const optional_hash &) noexcept = delete;
900 std::size_t operator()(const optional<T> &value) const noexcept = delete;
901 };
902 }
903 }
904 }
905
906 namespace std
907 {
908 template <typename T>
909 struct hash<vulkan_cpu::util::optional<T>> : public vulkan_cpu::util::detail::optional_hash<T>
910 {
911 };
912 }
913
914 #endif /* UTIL_OPTIONAL_H_ */