added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / utilities.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_UTILITIES_HPP
20 #define REALM_UTILITIES_HPP
21
22 #include <cstdint>
23 #include <cstdlib>
24 #include <cstdlib> // size_t
25 #include <cstdio>
26 #include <algorithm>
27 #include <functional>
28 #include <time.h>
29
30 #ifdef _WIN32
31
32 #include <WinSock2.h>
33 #include <intrin.h>
34 #include <BaseTsd.h>
35
36 #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
37 typedef SSIZE_T ssize_t;
38 #define _SSIZE_T_
39 #define _SSIZE_T_DEFINED
40 #endif
41
42 #endif // _WIN32
43
44 #include <realm/util/features.h>
45 #include <realm/util/assert.hpp>
46 #include <realm/util/safe_int_ops.hpp>
47
48 // GCC defines __i386__ and __x86_64__
49 #if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) ||               \
50      defined(__x86_64__) || defined(_M_X64))
51 #define REALM_X86_OR_X64
52 #define REALM_X86_OR_X64_TRUE true
53 #else
54 #define REALM_X86_OR_X64_TRUE false
55 #endif
56
57 // GCC defines __arm__
58 #ifdef __arm__
59 #define REALM_ARCH_ARM
60 #endif
61
62 #if defined _LP64 || defined __LP64__ || defined __64BIT__ || defined _ADDR64 || defined _WIN64 ||                   \
63     defined __arch64__ || (defined(__WORDSIZE) && __WORDSIZE == 64) || (defined __sparc && defined __sparcv9) ||     \
64     defined __x86_64 || defined __amd64 || defined __x86_64__ || defined _M_X64 || defined _M_IA64 ||                \
65     defined __ia64 || defined __IA64__
66 #define REALM_PTR_64
67 #endif
68
69
70 #if defined(REALM_PTR_64) && defined(REALM_X86_OR_X64)
71 #define REALM_COMPILER_SSE // Compiler supports SSE 4.2 through __builtin_ accessors or back-end assembler
72 #define REALM_COMPILER_AVX
73 #endif
74
75 namespace realm {
76
77 using StringCompareCallback = std::function<bool(const char* string1, const char* string2)>;
78
79 extern signed char sse_support;
80 extern signed char avx_support;
81
82 template <int version>
83 REALM_FORCEINLINE bool sseavx()
84 {
85     /*
86     Return whether or not SSE 3.0 (if version = 30) or 4.2 (for version = 42) is supported. Return value
87     is based on the CPUID instruction.
88
89     sse_support = -1: No SSE support
90     sse_support = 0: SSE3
91     sse_support = 1: SSE42
92
93     avx_support = -1: No AVX support
94     avx_support = 0: AVX1 supported
95     sse_support = 1: AVX2 supported (not yet implemented for detection in our cpuid_init(), todo)
96
97     This lets us test very rapidly at runtime because we just need 1 compare instruction (with 0) to test both for
98     SSE 3 and 4.2 by caller (compiler optimizes if calls are concecutive), and can decide branch with ja/jl/je because
99     sse_support is signed type. Also, 0 requires no immediate operand. Same for AVX.
100
101     We runtime-initialize sse_support in a constructor of a static variable which is not guaranteed to be called
102     prior to cpu_sse(). So we compile-time initialize sse_support to -2 as fallback.
103     */
104     static_assert(version == 1 || version == 2 || version == 30 || version == 42,
105                   "Only version == 1 (AVX), 2 (AVX2), 30 (SSE 3) and 42 (SSE 4.2) are supported for detection");
106 #ifdef REALM_COMPILER_SSE
107     if (version == 30)
108         return (sse_support >= 0);
109     else if (version == 42)
110         return (sse_support > 0); // faster than == 1 (0 requres no immediate operand)
111     else if (version == 1)        // avx
112         return (avx_support >= 0);
113     else if (version == 2) // avx2
114         return (avx_support > 0);
115     else
116         return false;
117 #else
118     return false;
119 #endif
120 }
121
122 void cpuid_init();
123 void* round_up(void* p, size_t align);
124 void* round_down(void* p, size_t align);
125 size_t round_up(size_t p, size_t align);
126 size_t round_down(size_t p, size_t align);
127 void millisleep(unsigned long milliseconds);
128
129 #ifdef _WIN32
130 int gettimeofday(struct timeval * tp, struct timezone * tzp);
131 #endif
132
133 int64_t platform_timegm(tm time);
134
135 #ifdef REALM_SLAB_ALLOC_TUNE
136 void process_mem_usage(double& vm_usage, double& resident_set);
137 #endif
138 // popcount
139 int fast_popcount32(int32_t x);
140 int fast_popcount64(int64_t x);
141 uint64_t fastrand(uint64_t max = 0xffffffffffffffffULL, bool is_seed = false);
142
143 // log2 - returns -1 if x==0, otherwise log2(x)
144 inline int log2(size_t x)
145 {
146     if (x == 0)
147         return -1;
148 #if defined(__GNUC__)
149 #ifdef REALM_PTR_64
150     return 63 - __builtin_clzll(x); // returns int
151 #else
152     return 31 - __builtin_clz(x); // returns int
153 #endif
154 #elif defined(_WIN32)
155     unsigned long index = 0;
156 #ifdef REALM_PTR_64
157     unsigned char c = _BitScanReverse64(&index, x); // outputs unsigned long
158 #else
159     unsigned char c = _BitScanReverse(&index, x); // outputs unsigned long
160 #endif
161     return static_cast<int>(index);
162 #else // not __GNUC__ and not _WIN32
163     int r = 0;
164     while (x >>= 1) {
165         r++;
166     }
167     return r;
168 #endif
169 }
170
171 // Implementation:
172
173 // Safe cast from 64 to 32 bits on 32 bit architecture. Differs from to_ref() by not testing alignment and
174 // REF-bitflag.
175 inline size_t to_size_t(int_fast64_t v) noexcept
176 {
177     REALM_ASSERT_DEBUG(!util::int_cast_has_overflow<size_t>(v));
178     return size_t(v);
179 }
180
181
182 template <typename ReturnType, typename OriginalType>
183 ReturnType type_punning(OriginalType variable) noexcept
184 {
185     union Both {
186         OriginalType in;
187         ReturnType out;
188     };
189     Both both;
190     both.out = ReturnType(); // Clear all bits in case ReturnType is larger than OriginalType
191     both.in = variable;
192     return both.out;
193 }
194
195 // Also see the comments in Array::index_string()
196 enum FindRes {
197     // Indicate that no results were found in the search
198     FindRes_not_found,
199     // Indicates a single result is found
200     FindRes_single,
201     // Indicates more than one result is found and they are stored in a column
202     FindRes_column
203 };
204
205 enum IndexMethod {
206     index_FindFirst,
207     index_FindAll_nocopy,
208     index_Count,
209 };
210
211 // Combined result of the index_FindAll_nocopy operation. The column returned
212 // can contain results that are not matches but all matches are within the
213 // returned start_ndx and end_ndx.
214 struct InternalFindResult {
215     // Reference to a IntegerColumn containing result rows, or a single row
216     // value if the result is FindRes_single.
217     size_t payload;
218     // Offset into the result column to start at.
219     size_t start_ndx;
220     // Offset index in the result column to end at.
221     size_t end_ndx;
222 };
223
224
225 // realm::is_any<T, U1, U2, U3, ...> ==
226 // std::is_same<T, U1>::value || std::is_same<T, U2>::value || std::is_same<T, U3>::value ...
227 template <typename... T>
228 struct is_any : std::false_type {
229 };
230
231 template <typename T, typename... Ts>
232 struct is_any<T, T, Ts...> : std::true_type {
233 };
234
235 template <typename T, typename U, typename... Ts>
236 struct is_any<T, U, Ts...> : is_any<T, Ts...> {
237 };
238
239
240 // Use realm::safe_equal() instead of std::equal() if one of the parameters can be a null pointer.
241 template <class InputIterator1, class InputIterator2>
242 bool safe_equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2)
243 {
244 #if defined(_MSC_VER)
245     // VS has a special check in debug mode against passing a null pointer std::equal(); it will give a warning
246     // at runtime if this is observed.
247     // It's uncertain if this is allowed by the C++ standard. For details, see
248     // http://stackoverflow.com/questions/19120779/is-char-p-0-stdequalp-p-p-well-defined-according-to-the-c-standard.
249     // So we use a safe C++14 method instead that takes two range pairs.
250     size_t len = last1 - first1;
251     return std::equal(first1, last1, first2, first2 + len);
252 #else
253     return std::equal(first1, last1, first2);
254 #endif
255 }
256
257 // Use realm::safe_copy_n() instead of std::copy_n() if one of the parameters can be a null pointer. See the
258 // explanation of safe_equal() above; same things apply.
259 template< class InputIt, class Size, class OutputIt>
260 OutputIt safe_copy_n(InputIt first, Size count, OutputIt result)
261 {
262 #if defined(_MSC_VER)
263     // This loop and the method prototype is copy pasted
264     // from "Possible implementation" on http://en.cppreference.com/w/cpp/algorithm/copy_n
265     if (count > 0) {
266         *result++ = *first;
267         for (Size i = 1; i < count; ++i) {
268             *result++ = *++first;
269         }
270     }
271     return result;
272 #else
273     return std::copy_n(first, count, result);
274 #endif
275 }
276
277
278 template <class T>
279 struct Wrap {
280     Wrap(const T& v)
281         : m_value(v)
282     {
283     }
284     operator T() const
285     {
286         return m_value;
287     }
288
289 private:
290     T m_value;
291 };
292
293 // PlacementDelete is intended for use with std::unique_ptr when it holds an object allocated with
294 // placement new. It simply calls the object's destructor without freeing the memory.
295 struct PlacementDelete {
296     template <class T>
297     void operator()(T* v) const
298     {
299         v->~T();
300     }
301 };
302
303 #ifdef _WIN32
304 typedef void* FileDesc;
305 #else
306 typedef int FileDesc;
307 #endif
308
309
310 } // namespace realm
311
312 #endif // REALM_UTILITIES_HPP