/* * Copyright (c) 2018-2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #if defined(AK_COMPILER_CLANG) # pragma clang diagnostic ignored "-Wunqualified-std-cast-call" #endif #include #include namespace AK { template constexpr auto round_up_to_power_of_two(T value, U power_of_two) requires(AK::Detail::IsIntegral && AK::Detail::IsIntegral) { return ((value - 1) & ~(power_of_two - 1)) + power_of_two; } template constexpr bool is_power_of_two(T value) requires(AK::Detail::IsIntegral) { return value && !((value) & (value - 1)); } template void compiletime_fail(Args...); } #if !USING_AK_GLOBALLY || defined(AK_DONT_REPLACE_STD) # define AK_REPLACED_STD_NAMESPACE AK::replaced_std #else # define AK_REPLACED_STD_NAMESPACE std #endif namespace AK_REPLACED_STD_NAMESPACE { // NOLINT(cert-dcl58-cpp) Names in std to aid tools // NOTE: These are in the "std" namespace since some compilers and static analyzers rely on it. // If USING_AK_GLOBALLY is false, we can't put them in ::std, so we put them in AK::replaced_std instead // The user code should not notice anything unless it explicitly asks for std::stuff, so...don't. template constexpr T&& forward(AK::Detail::RemoveReference& param) { return static_cast(param); } template constexpr T&& forward(AK::Detail::RemoveReference&& param) noexcept { static_assert(!AK::Detail::IsLvalueReference, "Can't forward an rvalue as an lvalue."); return static_cast(param); } template constexpr T&& move(T& arg) { return static_cast(arg); } } namespace AK { using AK_REPLACED_STD_NAMESPACE::forward; using AK_REPLACED_STD_NAMESPACE::move; } namespace AK::Detail { template struct _RawPtr { using Type = T*; }; } namespace AK { template constexpr SizeType array_size(T (&)[N]) { return N; } template constexpr T min(T const& a, IdentityType const& b) { return b < a ? b : a; } template constexpr T max(T const& a, IdentityType const& b) { return a < b ? b : a; } template constexpr T clamp(T const& value, IdentityType const& min, IdentityType const& max) { VERIFY(max >= min); if (value > max) return max; if (value < min) return min; return value; } template constexpr T mix(T const& v1, T const& v2, U const& interpolation) // aka lerp { return v1 + (v2 - v1) * interpolation; } template constexpr T ceil_div(T a, U b) { static_assert(sizeof(T) == sizeof(U)); T result = a / b; if ((a % b) != 0) ++result; return result; } template inline void swap(T& a, U& b) { if (&a == &b) return; U tmp = move(static_cast(a)); a = static_cast(move(b)); b = move(tmp); } template constexpr T exchange(T& slot, U&& value) { T old_value = move(slot); slot = forward(value); return old_value; } template using RawPtr = typename Detail::_RawPtr::Type; template constexpr decltype(auto) to_underlying(V value) requires(IsEnum) { return static_cast>(value); } constexpr bool is_constant_evaluated() { #if __has_builtin(__builtin_is_constant_evaluated) return __builtin_is_constant_evaluated(); #else return false; #endif } template ALWAYS_INLINE constexpr void taint_for_optimizer(T& value) requires(IsIntegral) { if (!is_constant_evaluated()) { asm volatile("" : "+r"(value)); } } template ALWAYS_INLINE constexpr void taint_for_optimizer(T& value) requires(!IsIntegral) { if (!is_constant_evaluated()) { asm volatile("" : : "m"(value) : "memory"); } } // These can't be exported into the global namespace as they would clash with the C standard library. #define __DEFINE_GENERIC_ABS(type, zero, intrinsic) \ constexpr type abs(type num) \ { \ if (is_constant_evaluated()) \ return num < (zero) ? -num : num; \ return __builtin_##intrinsic(num); \ } __DEFINE_GENERIC_ABS(int, 0, abs); __DEFINE_GENERIC_ABS(long, 0L, labs); __DEFINE_GENERIC_ABS(long long, 0LL, llabs); #ifndef KERNEL __DEFINE_GENERIC_ABS(float, 0.0F, fabsf); __DEFINE_GENERIC_ABS(double, 0.0, fabs); __DEFINE_GENERIC_ABS(long double, 0.0L, fabsl); #endif #undef __DEFINE_GENERIC_ABS } #if USING_AK_GLOBALLY using AK::array_size; using AK::ceil_div; using AK::clamp; using AK::exchange; using AK::forward; using AK::is_constant_evaluated; using AK::is_power_of_two; using AK::max; using AK::min; using AK::mix; using AK::move; using AK::RawPtr; using AK::round_up_to_power_of_two; using AK::swap; using AK::to_underlying; #endif