added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / util / optional.hpp
1 /*************************************************************************
2  *
3  * Copyright 2016 Realm Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  **************************************************************************/
18
19 #pragma once
20 #ifndef REALM_UTIL_OPTIONAL_HPP
21 #define REALM_UTIL_OPTIONAL_HPP
22
23 #include <realm/util/features.h>
24
25 #include <stdexcept>  // std::logic_error
26 #include <functional> // std::less
27
28 namespace realm {
29 namespace util {
30
31 template <class T>
32 class Optional;
33
34 // some() should be the equivalent of the proposed C++17 `make_optional`.
35 template <class T, class... Args>
36 Optional<T> some(Args&&...);
37 template <class T>
38 struct Some;
39
40 // Note: Should conform with the future std::nullopt_t and std::in_place_t.
41 struct None {
42     constexpr explicit None(int)
43     {
44     }
45 };
46 static constexpr None none{0};
47 struct InPlace {
48     constexpr InPlace()
49     {
50     }
51 };
52 static constexpr InPlace in_place;
53
54 // Note: Should conform with the future std::bad_optional_access.
55 struct BadOptionalAccess : std::logic_error {
56     explicit BadOptionalAccess(const std::string& what_arg)
57         : std::logic_error(what_arg)
58     {
59     }
60     explicit BadOptionalAccess(const char* what_arg)
61         : std::logic_error(what_arg)
62     {
63     }
64 };
65
66 } // namespace util
67
68 namespace _impl {
69
70 template <class T, bool = std::is_trivially_destructible<T>::value>
71 struct OptionalStorage;
72
73 template <class T, class U>
74 struct TypeIsAssignableToOptional {
75     // Constraints from [optional.object.assign.18]
76     static const bool value = (std::is_same<typename std::remove_reference<U>::type, T>::value &&
77                                std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value);
78 };
79
80 } // namespace _impl
81
82 namespace util {
83
84 // Note: Should conform with the future std::optional.
85 template <class T>
86 class Optional : private _impl::OptionalStorage<T> {
87 public:
88     using value_type = T;
89
90     constexpr Optional();
91     constexpr Optional(None);
92     Optional(Optional<T>&& other);
93     Optional(const Optional<T>& other);
94
95     constexpr Optional(T&& value);
96     constexpr Optional(const T& value);
97
98     template <class... Args>
99     constexpr Optional(InPlace tag, Args&&...);
100     // FIXME: std::optional specifies an std::initializer_list constructor overload as well.
101
102     Optional<T>& operator=(None);
103     Optional<T>& operator=(Optional<T>&& other);
104     Optional<T>& operator=(const Optional<T>& other);
105
106     template <class U, class = typename std::enable_if<_impl::TypeIsAssignableToOptional<T, U>::value>::type>
107     Optional<T>& operator=(U&& value);
108
109     explicit constexpr operator bool() const;
110     constexpr const T& value() const;      // Throws
111     T& value();                            // Throws, FIXME: Can be constexpr with C++14
112     constexpr const T& operator*() const;  // Throws
113     T& operator*();                        // Throws, FIXME: Can be constexpr with C++14
114     constexpr const T* operator->() const; // Throws
115     T* operator->();                       // Throws, FIXME: Can be constexpr with C++14
116
117     template <class U>
118     constexpr T value_or(U&& value) const &;
119
120     template <class U>
121     T value_or(U&& value) &&;
122
123     void swap(Optional<T>& other); // FIXME: Add noexcept() clause
124
125     template <class... Args>
126     void emplace(Args&&...);
127     // FIXME: std::optional specifies an std::initializer_list overload for `emplace` as well.
128 private:
129     using Storage = _impl::OptionalStorage<T>;
130     using Storage::m_engaged;
131     using Storage::m_value;
132
133     constexpr bool is_engaged() const
134     {
135         return m_engaged;
136     }
137     void set_engaged(bool b)
138     {
139         m_engaged = b;
140     }
141     void clear();
142 };
143
144 /// An Optional<void> is functionally equivalent to a bool.
145 /// Note: C++17 does not (yet) specify this specialization, but it is convenient
146 /// as a "safer bool", especially in the presence of `fmap`.
147 /// Disabled for compliance with std::optional.
148 // template <>
149 // class Optional<void> {
150 // public:
151 //     Optional() {}
152 //     Optional(None) {}
153 //     Optional(Optional<void>&&) = default;
154 //     Optional(const Optional<void>&) = default;
155 //     explicit operator bool() const { return m_engaged; }
156 // private:
157 //     bool m_engaged = false;
158 //     friend struct Some<void>;
159 // };
160
161 /// An Optional<T&> is a non-owning nullable pointer that throws on dereference.
162 // FIXME: Visual Studio 2015's constexpr support isn't sufficient to allow Optional<T&> to compile
163 // in constexpr contexts.
164 template <class T>
165 class Optional<T&> {
166 public:
167     using value_type = T&;
168     using target_type = typename std::decay<T>::type;
169
170     constexpr Optional()
171     {
172     }
173     constexpr Optional(None)
174     {
175     } // FIXME: Was a delegating constructor, but not fully supported in VS2015
176     Optional(const Optional<T&>& other) = default;
177     template <class U>
178     Optional(const Optional<U&>& other)
179         : m_ptr(other.m_ptr)
180     {
181     }
182     template <class U>
183     Optional(std::reference_wrapper<U> ref)
184         : m_ptr(&ref.get())
185     {
186     }
187
188     constexpr Optional(T& init_value)
189         : m_ptr(&init_value)
190     {
191     }
192     Optional(T&& value) = delete; // Catches accidental references to rvalue temporaries.
193
194     Optional<T&>& operator=(None)
195     {
196         m_ptr = nullptr;
197         return *this;
198     }
199     Optional<T&>& operator=(const Optional<T&>& other)
200     {
201         m_ptr = other.m_ptr;
202         return *this;
203     }
204
205     template <class U>
206     Optional<T&>& operator=(std::reference_wrapper<U> ref)
207     {
208         m_ptr = &ref.get();
209         return *this;
210     }
211
212     explicit constexpr operator bool() const
213     {
214         return m_ptr;
215     }
216     constexpr const target_type& value() const; // Throws
217     target_type& value();                       // Throws
218     constexpr const target_type& operator*() const
219     {
220         return value();
221     }
222     target_type& operator*()
223     {
224         return value();
225     }
226     constexpr const target_type* operator->() const
227     {
228         return &value();
229     }
230     target_type* operator->()
231     {
232         return &value();
233     }
234
235     void swap(Optional<T&> other); // FIXME: Add noexcept() clause
236 private:
237     T* m_ptr = nullptr;
238
239     template <class U>
240     friend class Optional;
241 };
242
243
244 template <class T>
245 struct RemoveOptional {
246     using type = T;
247 };
248 template <class T>
249 struct RemoveOptional<Optional<T>> {
250     using type = typename RemoveOptional<T>::type; // Remove recursively
251 };
252
253
254 /// Implementation:
255
256 template <class T>
257 struct Some {
258     template <class... Args>
259     static Optional<T> some(Args&&... args)
260     {
261         return Optional<T>{std::forward<Args>(args)...};
262     }
263 };
264
265 /// Disabled for compliance with std::optional.
266 // template <>
267 // struct Some<void> {
268 //     static Optional<void> some()
269 //     {
270 //         Optional<void> opt;
271 //         opt.m_engaged = true;
272 //         return opt;
273 //     }
274 // };
275
276 template <class T, class... Args>
277 Optional<T> some(Args&&... args)
278 {
279     return Some<T>::some(std::forward<Args>(args)...);
280 }
281
282
283 template <class T>
284 constexpr Optional<T>::Optional()
285     : Storage(none)
286 {
287 }
288
289 template <class T>
290 constexpr Optional<T>::Optional(None)
291     : Storage(none)
292 {
293 }
294
295 template <class T>
296 Optional<T>::Optional(Optional<T>&& other)
297     : Storage(none)
298 {
299     if (other.m_engaged) {
300         new (&m_value) T(std::move(other.m_value));
301         m_engaged = true;
302     }
303 }
304
305 template <class T>
306 Optional<T>::Optional(const Optional<T>& other)
307     : Storage(none)
308 {
309     if (other.m_engaged) {
310         new (&m_value) T(other.m_value);
311         m_engaged = true;
312     }
313 }
314
315 template <class T>
316 constexpr Optional<T>::Optional(T&& r_value)
317     : Storage(std::move(r_value))
318 {
319 }
320
321 template <class T>
322 constexpr Optional<T>::Optional(const T& l_value)
323     : Storage(l_value)
324 {
325 }
326
327 template <class T>
328 template <class... Args>
329 constexpr Optional<T>::Optional(InPlace, Args&&... args)
330     : Storage(std::forward<Args>(args)...)
331 {
332 }
333
334 template <class T>
335 void Optional<T>::clear()
336 {
337     if (m_engaged) {
338         m_value.~T();
339         m_engaged = false;
340     }
341 }
342
343 template <class T>
344 Optional<T>& Optional<T>::operator=(None)
345 {
346     clear();
347     return *this;
348 }
349
350 template <class T>
351 Optional<T>& Optional<T>::operator=(Optional<T>&& other)
352 {
353     if (m_engaged) {
354         if (other.m_engaged) {
355             m_value = std::move(other.m_value);
356         }
357         else {
358             clear();
359         }
360     }
361     else {
362         if (other.m_engaged) {
363             new (&m_value) T(std::move(other.m_value));
364             m_engaged = true;
365         }
366     }
367     return *this;
368 }
369
370 template <class T>
371 Optional<T>& Optional<T>::operator=(const Optional<T>& other)
372 {
373     if (m_engaged) {
374         if (other.m_engaged) {
375             m_value = other.m_value;
376         }
377         else {
378             clear();
379         }
380     }
381     else {
382         if (other.m_engaged) {
383             new (&m_value) T(other.m_value);
384             m_engaged = true;
385         }
386     }
387     return *this;
388 }
389
390 template <class T>
391 template <class U, class>
392 Optional<T>& Optional<T>::operator=(U&& r_value)
393 {
394     if (m_engaged) {
395         m_value = std::forward<U>(r_value);
396     }
397     else {
398         new (&m_value) T(std::forward<U>(r_value));
399         m_engaged = true;
400     }
401     return *this;
402 }
403
404 template <class T>
405 constexpr Optional<T>::operator bool() const
406 {
407     return m_engaged;
408 }
409
410 template <class T>
411 constexpr const T& Optional<T>::value() const
412 {
413     return m_engaged ? m_value : (throw BadOptionalAccess{"bad optional access"}, m_value);
414 }
415
416 template <class T>
417 T& Optional<T>::value()
418 {
419     if (!m_engaged) {
420         throw BadOptionalAccess{"bad optional access"};
421     }
422     return m_value;
423 }
424
425 template <class T>
426 constexpr const typename Optional<T&>::target_type& Optional<T&>::value() const
427 {
428     return m_ptr ? *m_ptr : (throw BadOptionalAccess{"bad optional access"}, *m_ptr);
429 }
430
431 template <class T>
432 typename Optional<T&>::target_type& Optional<T&>::value()
433 {
434     if (!m_ptr) {
435         throw BadOptionalAccess{"bad optional access"};
436     }
437     return *m_ptr;
438 }
439
440 template <class T>
441 constexpr const T& Optional<T>::operator*() const
442 {
443     // Note: This differs from std::optional, which doesn't throw.
444     return value();
445 }
446
447 template <class T>
448 T& Optional<T>::operator*()
449 {
450     // Note: This differs from std::optional, which doesn't throw.
451     return value();
452 }
453
454 template <class T>
455 constexpr const T* Optional<T>::operator->() const
456 {
457     // Note: This differs from std::optional, which doesn't throw.
458     return &value();
459 }
460
461 template <class T>
462 T* Optional<T>::operator->()
463 {
464     // Note: This differs from std::optional, which doesn't throw.
465     return &value();
466 }
467
468 template <class T>
469 template <class U>
470 constexpr T Optional<T>::value_or(U&& otherwise) const &
471 {
472     return m_engaged ? T{m_value} : T{std::forward<U>(otherwise)};
473 }
474
475 template <class T>
476 template <class U>
477 T Optional<T>::value_or(U&& otherwise) &&
478 {
479     if (is_engaged()) {
480         return T(std::move(m_value));
481     }
482     else {
483         return T(std::forward<U>(otherwise));
484     }
485 }
486
487 template <class T>
488 void Optional<T>::swap(Optional<T>& other)
489 {
490     // FIXME: This might be optimizable.
491     Optional<T> tmp = std::move(other);
492     other = std::move(*this);
493     *this = std::move(tmp);
494 }
495
496 template <class T>
497 template <class... Args>
498 void Optional<T>::emplace(Args&&... args)
499 {
500     clear();
501     new (&m_value) T(std::forward<Args>(args)...);
502     m_engaged = true;
503 }
504
505
506 template <class T>
507 constexpr Optional<typename std::decay<T>::type> make_optional(T&& value)
508 {
509     using Type = typename std::decay<T>::type;
510     return some<Type>(std::forward<T>(value));
511 }
512
513 template <class T>
514 bool operator==(const Optional<T>& lhs, const Optional<T>& rhs)
515 {
516     if (!lhs && !rhs) {
517         return true;
518     }
519     if (lhs && rhs) {
520         return *lhs == *rhs;
521     }
522     return false;
523 }
524
525 template <class T>
526 bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs)
527 {
528     return !(lhs == rhs);
529 }
530
531 template <class T>
532 bool operator<(const Optional<T>& lhs, const Optional<T>& rhs)
533 {
534     if (!rhs) {
535         return false;
536     }
537     if (!lhs) {
538         return true;
539     }
540     return std::less<T>{}(*lhs, *rhs);
541 }
542
543 template <class T>
544 bool operator>(const util::Optional<T>& lhs, const util::Optional<T>& rhs)
545 {
546     if (!lhs) {
547         return false;
548     }
549     if (!rhs) {
550         return true;
551     }
552     return std::greater<T>{}(*lhs, *rhs);
553 }
554
555 template <class T>
556 bool operator==(const Optional<T>& lhs, None)
557 {
558     return !bool(lhs);
559 }
560
561 template <class T>
562 bool operator!=(const Optional<T>& lhs, None)
563 {
564     return bool(lhs);
565 }
566
567 template <class T>
568 bool operator<(const Optional<T>& lhs, None)
569 {
570     static_cast<void>(lhs);
571     return false;
572 }
573
574 template <class T>
575 bool operator==(None, const Optional<T>& rhs)
576 {
577     return !bool(rhs);
578 }
579
580 template <class T>
581 bool operator!=(None, const Optional<T>& rhs)
582 {
583     return bool(rhs);
584 }
585
586 template <class T>
587 bool operator<(None, const Optional<T>& rhs)
588 {
589     return bool(rhs);
590 }
591
592 template <class T, class U>
593 bool operator==(const Optional<T>& lhs, const U& rhs)
594 {
595     return lhs ? *lhs == rhs : false;
596 }
597
598 template <class T>
599 bool operator<(const Optional<T>& lhs, const T& rhs)
600 {
601     return lhs ? std::less<T>{}(*lhs, rhs) : true;
602 }
603
604 template <class T, class U>
605 bool operator==(const T& lhs, const Optional<U>& rhs)
606 {
607     return rhs ? lhs == *rhs : false;
608 }
609
610 template <class T>
611 bool operator<(const T& lhs, const Optional<T>& rhs)
612 {
613     return rhs ? std::less<T>{}(lhs, *rhs) : false;
614 }
615
616 template <class T, class F>
617 auto operator>>(Optional<T> lhs, F&& rhs) -> decltype(fmap(lhs, std::forward<F>(rhs)))
618 {
619     return fmap(lhs, std::forward<F>(rhs));
620 }
621
622 template <class OS, class T>
623 OS& operator<<(OS& os, const Optional<T>& rhs)
624 {
625     if (rhs) {
626         os << "some(" << *rhs << ")";
627     }
628     else {
629         os << "none";
630     }
631     return os;
632 }
633
634 template <class T>
635 T unwrap(T&& value)
636 {
637     return value;
638 }
639
640 template <class T>
641 T unwrap(util::Optional<T>&& value)
642 {
643     return *value;
644 }
645
646 template <class T>
647 T unwrap(const util::Optional<T>& value)
648 {
649     return *value;
650 }
651
652 template <class T>
653 T unwrap(util::Optional<T>& value)
654 {
655     return *value;
656 }
657
658 } // namespace util
659
660 namespace _impl {
661
662 // T is trivially destructible.
663 template <class T>
664 struct OptionalStorage<T, true> {
665     union {
666         T m_value;
667         char m_null_state;
668     };
669     bool m_engaged = false;
670
671     constexpr OptionalStorage(realm::util::None)
672         : m_null_state()
673     {
674     }
675     constexpr OptionalStorage(T&& value)
676         : m_value(std::move(value))
677         , m_engaged(true)
678     {
679     }
680
681     template <class... Args>
682     constexpr OptionalStorage(Args&&... args)
683         : m_value(args...)
684         , m_engaged(true)
685     {
686     }
687 };
688
689 // T is not trivially destructible.
690 template <class T>
691 struct OptionalStorage<T, false> {
692     union {
693         T m_value;
694         char m_null_state;
695     };
696     bool m_engaged = false;
697
698     constexpr OptionalStorage(realm::util::None)
699         : m_null_state()
700     {
701     }
702     constexpr OptionalStorage(T&& value)
703         : m_value(std::move(value))
704         , m_engaged(true)
705     {
706     }
707
708     template <class... Args>
709     constexpr OptionalStorage(Args&&... args)
710         : m_value(args...)
711         , m_engaged(true)
712     {
713     }
714
715     ~OptionalStorage()
716     {
717         if (m_engaged)
718             m_value.~T();
719     }
720 };
721
722 } // namespace _impl
723
724 using util::none;
725
726 } // namespace realm
727
728 #endif // REALM_UTIL_OPTIONAL_HPP