1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/common/helper.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/common/constants.hpp" |
12 | #include "duckdb/common/shared_ptr.hpp" |
13 | #include <string.h> |
14 | #include <type_traits> |
15 | |
16 | #ifdef _MSC_VER |
17 | #define suint64_t int64_t |
18 | #endif |
19 | |
20 | #if defined(_WIN32) || defined(_WIN64) |
21 | #define DUCKDB_WINDOWS |
22 | #elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) |
23 | #define DUCKDB_POSIX |
24 | #endif |
25 | |
26 | namespace duckdb { |
27 | |
28 | // explicit fallthrough for switch_statementss |
29 | #ifndef __has_cpp_attribute // For backwards compatibility |
30 | #define __has_cpp_attribute(x) 0 |
31 | #endif |
32 | #if __has_cpp_attribute(clang::fallthrough) |
33 | #define DUCKDB_EXPLICIT_FALLTHROUGH [[clang::fallthrough]] |
34 | #elif __has_cpp_attribute(gnu::fallthrough) |
35 | #define DUCKDB_EXPLICIT_FALLTHROUGH [[gnu::fallthrough]] |
36 | #else |
37 | #define DUCKDB_EXPLICIT_FALLTHROUGH |
38 | #endif |
39 | |
40 | template<class _Tp, bool SAFE = true> |
41 | struct __unique_if |
42 | { |
43 | typedef unique_ptr<_Tp, std::default_delete<_Tp>, SAFE> __unique_single; |
44 | }; |
45 | |
46 | template<class _Tp> |
47 | struct __unique_if<_Tp[]> |
48 | { |
49 | typedef unique_ptr<_Tp[]> __unique_array_unknown_bound; |
50 | }; |
51 | |
52 | template<class _Tp, size_t _Np> |
53 | struct __unique_if<_Tp[_Np]> |
54 | { |
55 | typedef void __unique_array_known_bound; |
56 | }; |
57 | |
58 | template<class _Tp, class... _Args> |
59 | inline |
60 | typename __unique_if<_Tp, true>::__unique_single |
61 | make_uniq(_Args&&... __args) |
62 | { |
63 | return unique_ptr<_Tp, std::default_delete<_Tp>, true>(new _Tp(std::forward<_Args>(__args)...)); |
64 | } |
65 | |
66 | template<class _Tp, class... _Args> |
67 | inline |
68 | typename __unique_if<_Tp, false>::__unique_single |
69 | make_unsafe_uniq(_Args&&... __args) |
70 | { |
71 | return unique_ptr<_Tp, std::default_delete<_Tp>, false>(new _Tp(std::forward<_Args>(__args)...)); |
72 | } |
73 | |
74 | template<class _Tp> |
75 | inline unique_ptr<_Tp[], std::default_delete<_Tp>, true> |
76 | make_uniq_array(size_t __n) |
77 | { |
78 | return unique_ptr<_Tp[], std::default_delete<_Tp>, true>(new _Tp[__n]()); |
79 | } |
80 | |
81 | template<class _Tp> |
82 | inline unique_ptr<_Tp[], std::default_delete<_Tp>, false> |
83 | make_unsafe_uniq_array(size_t __n) |
84 | { |
85 | return unique_ptr<_Tp[], std::default_delete<_Tp>, false>(new _Tp[__n]()); |
86 | } |
87 | |
88 | template<class _Tp, class... _Args> |
89 | typename __unique_if<_Tp>::__unique_array_known_bound |
90 | make_uniq(_Args&&...) = delete; |
91 | |
92 | |
93 | template <typename S, typename T, typename... Args> |
94 | unique_ptr<S> make_uniq_base(Args &&... args) { |
95 | return unique_ptr<S>(new T(std::forward<Args>(args)...)); |
96 | } |
97 | |
98 | #ifdef DUCKDB_ENABLE_DEPRECATED_API |
99 | template <typename S, typename T, typename... Args> |
100 | unique_ptr<S> make_unique_base(Args &&... args) { |
101 | return unique_ptr<S>(new T(std::forward<Args>(args)...)); |
102 | } |
103 | #endif // DUCKDB_ENABLE_DEPRECATED_API |
104 | |
105 | template <typename T, typename S> |
106 | unique_ptr<S> unique_ptr_cast(unique_ptr<T> src) { |
107 | return unique_ptr<S>(static_cast<S *>(src.release())); |
108 | } |
109 | |
110 | struct SharedConstructor { |
111 | template <class T, typename... ARGS> |
112 | static shared_ptr<T> Create(ARGS &&...args) { |
113 | return make_shared<T>(std::forward<ARGS>(args)...); |
114 | } |
115 | }; |
116 | |
117 | struct UniqueConstructor { |
118 | template <class T, typename... ARGS> |
119 | static unique_ptr<T> Create(ARGS &&...args) { |
120 | return make_uniq<T>(std::forward<ARGS>(args)...); |
121 | } |
122 | }; |
123 | |
124 | #ifdef DUCKDB_DEBUG_MOVE |
125 | template<class T> |
126 | typename std::remove_reference<T>::type&& move(T&& t) noexcept { |
127 | // the nonsensical sizeof check ensures this is never instantiated |
128 | static_assert(sizeof(T) == 0, "Use std::move instead of unqualified move or duckdb::move" ); |
129 | } |
130 | #endif |
131 | |
132 | template <class T, class... _Args> |
133 | static duckdb::unique_ptr<T> make_unique(_Args&&... __args) { |
134 | #ifndef DUCKDB_ENABLE_DEPRECATED_API |
135 | static_assert(sizeof(T) == 0, "Use make_uniq instead of make_unique!" ); |
136 | #endif // DUCKDB_ENABLE_DEPRECATED_API |
137 | return unique_ptr<T>(new T(std::forward<_Args>(__args)...)); |
138 | } |
139 | |
140 | template <typename T> |
141 | T MaxValue(T a, T b) { |
142 | return a > b ? a : b; |
143 | } |
144 | |
145 | template <typename T> |
146 | T MinValue(T a, T b) { |
147 | return a < b ? a : b; |
148 | } |
149 | |
150 | template <typename T> |
151 | T AbsValue(T a) { |
152 | return a < 0 ? -a : a; |
153 | } |
154 | |
155 | //Align value (ceiling) |
156 | template<class T, T val=8> |
157 | static inline T AlignValue(T n) { |
158 | return ((n + (val - 1)) / val) * val; |
159 | } |
160 | |
161 | template<class T, T val=8> |
162 | static inline bool ValueIsAligned(T n) { |
163 | return (n % val) == 0; |
164 | } |
165 | |
166 | template <typename T> |
167 | T SignValue(T a) { |
168 | return a < 0 ? -1 : 1; |
169 | } |
170 | |
171 | template <typename T> |
172 | const T Load(const_data_ptr_t ptr) { |
173 | T ret; |
174 | memcpy(&ret, ptr, sizeof(ret)); |
175 | return ret; |
176 | } |
177 | |
178 | template <typename T> |
179 | void Store(const T &val, data_ptr_t ptr) { |
180 | memcpy(dest: ptr, src: (void *)&val, n: sizeof(val)); |
181 | } |
182 | |
183 | //! This assigns a shared pointer, but ONLY assigns if "target" is not equal to "source" |
184 | //! If this is often the case, this manner of assignment is significantly faster (~20X faster) |
185 | //! Since it avoids the need of an atomic incref/decref at the cost of a single pointer comparison |
186 | //! Benchmark: https://gist.github.com/Mytherin/4db3faa8e233c4a9b874b21f62bb4b96 |
187 | //! If the shared pointers are not the same, the penalty is very low (on the order of 1%~ slower) |
188 | //! This method should always be preferred if there is a (reasonable) chance that the pointers are the same |
189 | template<class T> |
190 | void AssignSharedPointer(shared_ptr<T> &target, const shared_ptr<T> &source) { |
191 | if (target.get() != source.get()) { |
192 | target = source; |
193 | } |
194 | } |
195 | |
196 | template<typename T> |
197 | using reference = std::reference_wrapper<T>; |
198 | |
199 | template<typename T> |
200 | using const_reference = std::reference_wrapper<const T>; |
201 | |
202 | //! Returns whether or not two reference wrappers refer to the same object |
203 | template<class T> |
204 | bool RefersToSameObject(const reference<T> &A, const reference<T> &B) { |
205 | return &A.get() == &B.get(); |
206 | } |
207 | |
208 | } // namespace duckdb |
209 | |