//===----------------------------------------------------------------------===// // DuckDB // // duckdb/common/helper.hpp // // //===----------------------------------------------------------------------===// #pragma once #include "duckdb/common/constants.hpp" #include "duckdb/common/shared_ptr.hpp" #include #include #ifdef _MSC_VER #define suint64_t int64_t #endif #if defined(_WIN32) || defined(_WIN64) #define DUCKDB_WINDOWS #elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #define DUCKDB_POSIX #endif namespace duckdb { // explicit fallthrough for switch_statementss #ifndef __has_cpp_attribute // For backwards compatibility #define __has_cpp_attribute(x) 0 #endif #if __has_cpp_attribute(clang::fallthrough) #define DUCKDB_EXPLICIT_FALLTHROUGH [[clang::fallthrough]] #elif __has_cpp_attribute(gnu::fallthrough) #define DUCKDB_EXPLICIT_FALLTHROUGH [[gnu::fallthrough]] #else #define DUCKDB_EXPLICIT_FALLTHROUGH #endif template struct __unique_if { typedef unique_ptr<_Tp, std::default_delete<_Tp>, SAFE> __unique_single; }; template struct __unique_if<_Tp[]> { typedef unique_ptr<_Tp[]> __unique_array_unknown_bound; }; template struct __unique_if<_Tp[_Np]> { typedef void __unique_array_known_bound; }; template inline typename __unique_if<_Tp, true>::__unique_single make_uniq(_Args&&... __args) { return unique_ptr<_Tp, std::default_delete<_Tp>, true>(new _Tp(std::forward<_Args>(__args)...)); } template inline typename __unique_if<_Tp, false>::__unique_single make_unsafe_uniq(_Args&&... __args) { return unique_ptr<_Tp, std::default_delete<_Tp>, false>(new _Tp(std::forward<_Args>(__args)...)); } template inline unique_ptr<_Tp[], std::default_delete<_Tp>, true> make_uniq_array(size_t __n) { return unique_ptr<_Tp[], std::default_delete<_Tp>, true>(new _Tp[__n]()); } template inline unique_ptr<_Tp[], std::default_delete<_Tp>, false> make_unsafe_uniq_array(size_t __n) { return unique_ptr<_Tp[], std::default_delete<_Tp>, false>(new _Tp[__n]()); } template typename __unique_if<_Tp>::__unique_array_known_bound make_uniq(_Args&&...) = delete; template unique_ptr make_uniq_base(Args &&... args) { return unique_ptr(new T(std::forward(args)...)); } #ifdef DUCKDB_ENABLE_DEPRECATED_API template unique_ptr make_unique_base(Args &&... args) { return unique_ptr(new T(std::forward(args)...)); } #endif // DUCKDB_ENABLE_DEPRECATED_API template unique_ptr unique_ptr_cast(unique_ptr src) { return unique_ptr(static_cast(src.release())); } struct SharedConstructor { template static shared_ptr Create(ARGS &&...args) { return make_shared(std::forward(args)...); } }; struct UniqueConstructor { template static unique_ptr Create(ARGS &&...args) { return make_uniq(std::forward(args)...); } }; #ifdef DUCKDB_DEBUG_MOVE template typename std::remove_reference::type&& move(T&& t) noexcept { // the nonsensical sizeof check ensures this is never instantiated static_assert(sizeof(T) == 0, "Use std::move instead of unqualified move or duckdb::move"); } #endif template static duckdb::unique_ptr make_unique(_Args&&... __args) { #ifndef DUCKDB_ENABLE_DEPRECATED_API static_assert(sizeof(T) == 0, "Use make_uniq instead of make_unique!"); #endif // DUCKDB_ENABLE_DEPRECATED_API return unique_ptr(new T(std::forward<_Args>(__args)...)); } template T MaxValue(T a, T b) { return a > b ? a : b; } template T MinValue(T a, T b) { return a < b ? a : b; } template T AbsValue(T a) { return a < 0 ? -a : a; } //Align value (ceiling) template static inline T AlignValue(T n) { return ((n + (val - 1)) / val) * val; } template static inline bool ValueIsAligned(T n) { return (n % val) == 0; } template T SignValue(T a) { return a < 0 ? -1 : 1; } template const T Load(const_data_ptr_t ptr) { T ret; memcpy(&ret, ptr, sizeof(ret)); return ret; } template void Store(const T &val, data_ptr_t ptr) { memcpy(ptr, (void *)&val, sizeof(val)); } //! This assigns a shared pointer, but ONLY assigns if "target" is not equal to "source" //! If this is often the case, this manner of assignment is significantly faster (~20X faster) //! Since it avoids the need of an atomic incref/decref at the cost of a single pointer comparison //! Benchmark: https://gist.github.com/Mytherin/4db3faa8e233c4a9b874b21f62bb4b96 //! If the shared pointers are not the same, the penalty is very low (on the order of 1%~ slower) //! This method should always be preferred if there is a (reasonable) chance that the pointers are the same template void AssignSharedPointer(shared_ptr &target, const shared_ptr &source) { if (target.get() != source.get()) { target = source; } } template using reference = std::reference_wrapper; template using const_reference = std::reference_wrapper; //! Returns whether or not two reference wrappers refer to the same object template bool RefersToSameObject(const reference &A, const reference &B) { return &A.get() == &B.get(); } } // namespace duckdb