added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / null.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 #ifndef REALM_NULL_HPP
20 #define REALM_NULL_HPP
21
22 #include <cmath>
23 #include <cstring>
24
25 #include <realm/util/features.h>
26 #include <realm/util/optional.hpp>
27 #include <realm/utilities.hpp>
28 #include <realm/exceptions.hpp>
29
30 namespace realm {
31
32 /*
33 Represents null in Query, find(), get(), set(), etc.
34
35 Float/Double: Realm can both store user-given NaNs and null. Any user-given signaling NaN is converted to
36 0x7fa00000 (if float) or 0x7ff4000000000000 (if double). Any user-given quiet NaN is converted to
37 0x7fc00000 (if float) or 0x7ff8000000000000 (if double). So Realm does not preserve the optional bits in
38 user-given NaNs.
39
40 However, since both clang and gcc on x64 and ARM, and also Java on x64, return these bit patterns when
41 requesting NaNs, these will actually seem to roundtrip bit-exact for the end-user in most cases.
42
43 If set_null() is called, a null is stored in form of the bit pattern 0xffffffff (if float) or
44 0xffffffffffffffff (if double). These are quiet NaNs.
45
46 Executing a query that involves a float/double column that contains NaNs gives an undefined result. If
47 it contains signaling NaNs, it may throw an exception.
48
49 Notes on IEEE:
50
51 A NaN float is any bit pattern `s 11111111 S xxxxxxxxxxxxxxxxxxxxxx` where `s` and `x` are arbitrary, but at
52 least 1 `x` must be 1. If `S` is 1, it's a quiet NaN, else it's a signaling NaN.
53
54 A NaN doubule is the same as above, but for `s eeeeeeeeeee S xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
55
56 The `S` bit is at position 22 (float) or 51 (double).
57 */
58
59 struct null {
60     null()
61     {
62     }
63     operator int64_t()
64     {
65         throw(LogicError::type_mismatch);
66     }
67     template <class T>
68     operator util::Optional<T>()
69     {
70         return util::none;
71     }
72
73     template <class T>
74     bool operator==(const T&) const
75     {
76         REALM_ASSERT(false);
77         return false;
78     }
79     template <class T>
80     bool operator!=(const T&) const
81     {
82         REALM_ASSERT(false);
83         return false;
84     }
85     template <class T>
86     bool operator>(const T&) const
87     {
88         REALM_ASSERT(false);
89         return false;
90     }
91     template <class T>
92     bool operator>=(const T&) const
93     {
94         REALM_ASSERT(false);
95         return false;
96     }
97     template <class T>
98     bool operator<=(const T&) const
99     {
100         REALM_ASSERT(false);
101         return false;
102     }
103     template <class T>
104     bool operator<(const T&) const
105     {
106         REALM_ASSERT(false);
107         return false;
108     }
109
110     /// Returns whether `v` bitwise equals the null bit-pattern
111     template <class T>
112     static bool is_null_float(T v)
113     {
114         T i = null::get_null_float<T>();
115         return std::memcmp(&i, &v, sizeof(T)) == 0;
116     }
117
118     /// Returns the quiet NaNs that represent null for floats/doubles in Realm in stored payload.
119     template <class T>
120     static T get_null_float()
121     {
122         typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type i;
123         int64_t double_nan = 0x7ff80000000000aa;
124         i = std::is_same<T, float>::value ? 0x7fc000aa : static_cast<decltype(i)>(double_nan);
125         T d = type_punning<T, decltype(i)>(i);
126         REALM_ASSERT_DEBUG(std::isnan(d));
127         REALM_ASSERT_DEBUG(!is_signaling(d));
128         return d;
129     }
130
131     /// Takes a NaN as argument and returns whether or not it's signaling
132     template <class T>
133     static bool is_signaling(T v)
134     {
135         REALM_ASSERT(std::isnan(static_cast<double>(v)));
136         typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type i;
137         size_t signal_bit = std::is_same<T, float>::value ? 22 : 51; // If this bit is set, it's quiet
138         i = type_punning<decltype(i), T>(v);
139         return !(i & (1ull << signal_bit));
140     }
141
142     /// Converts any signaling or quiet NaN to their their respective bit patterns that are used on x64 gcc+clang,
143     /// ARM clang and x64 Java.
144     template <class T>
145     static T to_realm(T v)
146     {
147         if (std::isnan(static_cast<double>(v))) {
148             typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type i;
149             if (std::is_same<T, float>::value) {
150                 i = is_signaling(v) ? 0x7fa00000 : 0x7fc00000;
151             }
152             else {
153                 i = static_cast<decltype(i)>(is_signaling(v) ? 0x7ff4000000000000 : 0x7ff8000000000000);
154             }
155             return type_punning<T, decltype(i)>(i);
156         }
157         else {
158             return v;
159         }
160     }
161 };
162
163 template <class OS>
164 OS& operator<<(OS& os, const null&)
165 {
166     os << "(null)";
167     return os;
168 }
169
170 } // namespace realm
171
172 #endif // REALM_NULL_HPP