1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 **************************************************************************/
19 #ifndef REALM_NULL_HPP
20 #define REALM_NULL_HPP
25 #include <realm/util/features.h>
26 #include <realm/util/optional.hpp>
27 #include <realm/utilities.hpp>
28 #include <realm/exceptions.hpp>
33 Represents null in Query, find(), get(), set(), etc.
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
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.
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.
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.
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.
54 A NaN doubule is the same as above, but for `s eeeeeeeeeee S xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
56 The `S` bit is at position 22 (float) or 51 (double).
65 throw(LogicError::type_mismatch);
68 operator util::Optional<T>()
74 bool operator==(const T&) const
80 bool operator!=(const T&) const
86 bool operator>(const T&) const
92 bool operator>=(const T&) const
98 bool operator<=(const T&) const
104 bool operator<(const T&) const
110 /// Returns whether `v` bitwise equals the null bit-pattern
112 static bool is_null_float(T v)
114 T i = null::get_null_float<T>();
115 return std::memcmp(&i, &v, sizeof(T)) == 0;
118 /// Returns the quiet NaNs that represent null for floats/doubles in Realm in stored payload.
120 static T get_null_float()
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));
131 /// Takes a NaN as argument and returns whether or not it's signaling
133 static bool is_signaling(T v)
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));
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.
145 static T to_realm(T v)
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;
153 i = static_cast<decltype(i)>(is_signaling(v) ? 0x7ff4000000000000 : 0x7ff8000000000000);
155 return type_punning<T, decltype(i)>(i);
164 OS& operator<<(OS& os, const null&)
172 #endif // REALM_NULL_HPP