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
26namespace 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
40template<class _Tp, bool SAFE = true>
41struct __unique_if
42{
43 typedef unique_ptr<_Tp, std::default_delete<_Tp>, SAFE> __unique_single;
44};
45
46template<class _Tp>
47struct __unique_if<_Tp[]>
48{
49 typedef unique_ptr<_Tp[]> __unique_array_unknown_bound;
50};
51
52template<class _Tp, size_t _Np>
53struct __unique_if<_Tp[_Np]>
54{
55 typedef void __unique_array_known_bound;
56};
57
58template<class _Tp, class... _Args>
59inline
60typename __unique_if<_Tp, true>::__unique_single
61make_uniq(_Args&&... __args)
62{
63 return unique_ptr<_Tp, std::default_delete<_Tp>, true>(new _Tp(std::forward<_Args>(__args)...));
64}
65
66template<class _Tp, class... _Args>
67inline
68typename __unique_if<_Tp, false>::__unique_single
69make_unsafe_uniq(_Args&&... __args)
70{
71 return unique_ptr<_Tp, std::default_delete<_Tp>, false>(new _Tp(std::forward<_Args>(__args)...));
72}
73
74template<class _Tp>
75inline unique_ptr<_Tp[], std::default_delete<_Tp>, true>
76make_uniq_array(size_t __n)
77{
78 return unique_ptr<_Tp[], std::default_delete<_Tp>, true>(new _Tp[__n]());
79}
80
81template<class _Tp>
82inline unique_ptr<_Tp[], std::default_delete<_Tp>, false>
83make_unsafe_uniq_array(size_t __n)
84{
85 return unique_ptr<_Tp[], std::default_delete<_Tp>, false>(new _Tp[__n]());
86}
87
88template<class _Tp, class... _Args>
89 typename __unique_if<_Tp>::__unique_array_known_bound
90 make_uniq(_Args&&...) = delete;
91
92
93template <typename S, typename T, typename... Args>
94unique_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
99template <typename S, typename T, typename... Args>
100unique_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
105template <typename T, typename S>
106unique_ptr<S> unique_ptr_cast(unique_ptr<T> src) {
107 return unique_ptr<S>(static_cast<S *>(src.release()));
108}
109
110struct 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
117struct 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
125template<class T>
126typename 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
132template <class T, class... _Args>
133static 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
140template <typename T>
141T MaxValue(T a, T b) {
142 return a > b ? a : b;
143}
144
145template <typename T>
146T MinValue(T a, T b) {
147 return a < b ? a : b;
148}
149
150template <typename T>
151T AbsValue(T a) {
152 return a < 0 ? -a : a;
153}
154
155//Align value (ceiling)
156template<class T, T val=8>
157static inline T AlignValue(T n) {
158 return ((n + (val - 1)) / val) * val;
159}
160
161template<class T, T val=8>
162static inline bool ValueIsAligned(T n) {
163 return (n % val) == 0;
164}
165
166template <typename T>
167T SignValue(T a) {
168 return a < 0 ? -1 : 1;
169}
170
171template <typename T>
172const T Load(const_data_ptr_t ptr) {
173 T ret;
174 memcpy(&ret, ptr, sizeof(ret));
175 return ret;
176}
177
178template <typename T>
179void 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
189template<class T>
190void AssignSharedPointer(shared_ptr<T> &target, const shared_ptr<T> &source) {
191 if (target.get() != source.get()) {
192 target = source;
193 }
194}
195
196template<typename T>
197using reference = std::reference_wrapper<T>;
198
199template<typename T>
200using const_reference = std::reference_wrapper<const T>;
201
202//! Returns whether or not two reference wrappers refer to the same object
203template<class T>
204bool RefersToSameObject(const reference<T> &A, const reference<T> &B) {
205 return &A.get() == &B.get();
206}
207
208} // namespace duckdb
209