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_UTILITIES_HPP
20 #define REALM_UTILITIES_HPP
24 #include <cstdlib> // size_t
36 #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
37 typedef SSIZE_T ssize_t;
39 #define _SSIZE_T_DEFINED
44 #include <realm/util/features.h>
45 #include <realm/util/assert.hpp>
46 #include <realm/util/safe_int_ops.hpp>
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
54 #define REALM_X86_OR_X64_TRUE false
57 // GCC defines __arm__
59 #define REALM_ARCH_ARM
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__
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
77 using StringCompareCallback = std::function<bool(const char* string1, const char* string2)>;
79 extern signed char sse_support;
80 extern signed char avx_support;
82 template <int version>
83 REALM_FORCEINLINE bool sseavx()
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.
89 sse_support = -1: No SSE support
91 sse_support = 1: SSE42
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)
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.
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.
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
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);
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);
130 int gettimeofday(struct timeval * tp, struct timezone * tzp);
133 int64_t platform_timegm(tm time);
135 #ifdef REALM_SLAB_ALLOC_TUNE
136 void process_mem_usage(double& vm_usage, double& resident_set);
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);
143 // log2 - returns -1 if x==0, otherwise log2(x)
144 inline int log2(size_t x)
148 #if defined(__GNUC__)
150 return 63 - __builtin_clzll(x); // returns int
152 return 31 - __builtin_clz(x); // returns int
154 #elif defined(_WIN32)
155 unsigned long index = 0;
157 unsigned char c = _BitScanReverse64(&index, x); // outputs unsigned long
159 unsigned char c = _BitScanReverse(&index, x); // outputs unsigned long
161 return static_cast<int>(index);
162 #else // not __GNUC__ and not _WIN32
173 // Safe cast from 64 to 32 bits on 32 bit architecture. Differs from to_ref() by not testing alignment and
175 inline size_t to_size_t(int_fast64_t v) noexcept
177 REALM_ASSERT_DEBUG(!util::int_cast_has_overflow<size_t>(v));
182 template <typename ReturnType, typename OriginalType>
183 ReturnType type_punning(OriginalType variable) noexcept
190 both.out = ReturnType(); // Clear all bits in case ReturnType is larger than OriginalType
195 // Also see the comments in Array::index_string()
197 // Indicate that no results were found in the search
199 // Indicates a single result is found
201 // Indicates more than one result is found and they are stored in a column
207 index_FindAll_nocopy,
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.
218 // Offset into the result column to start at.
220 // Offset index in the result column to end at.
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 {
231 template <typename T, typename... Ts>
232 struct is_any<T, T, Ts...> : std::true_type {
235 template <typename T, typename U, typename... Ts>
236 struct is_any<T, U, Ts...> : is_any<T, Ts...> {
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)
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);
253 return std::equal(first1, last1, first2);
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)
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
267 for (Size i = 1; i < count; ++i) {
268 *result++ = *++first;
273 return std::copy_n(first, count, result);
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 {
297 void operator()(T* v) const
304 typedef void* FileDesc;
306 typedef int FileDesc;
312 #endif // REALM_UTILITIES_HPP