1
0
mirror of https://github.com/SerenityOS/serenity synced 2024-07-09 11:00:46 +00:00
serenity/AK/BuiltinWrappers.h
Ali Mohammad Pur ad120606fd AK: Fix build with !USING_AK_GLOBALLY
A couple headers expected names to be in the global namespace, qualify
those names to make sure they're resolved even when the names are not
exported.
One header placed its functions in the global namespace, move those to
the AK namespace to make the concepts resolve.
2022-12-13 08:09:56 +03:30

163 lines
5.2 KiB
C++

/*
* Copyright (c) 2021, Nick Johnson <sylvyrfysh@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include "Concepts.h"
namespace AK {
template<Unsigned IntType>
inline constexpr int popcount(IntType value)
{
#if defined(AK_COMPILER_CLANG) || defined(AK_COMPILER_GCC)
static_assert(sizeof(IntType) <= sizeof(unsigned long long));
if constexpr (sizeof(IntType) <= sizeof(unsigned int))
return __builtin_popcount(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long))
return __builtin_popcountl(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long long))
return __builtin_popcountll(value);
VERIFY_NOT_REACHED();
#else
int ones = 0;
for (size_t i = 0; i < 8 * sizeof(IntType); ++i) {
if ((value >> i) & 1) {
++ones;
}
}
return ones;
#endif
}
// The function will return the number of trailing zeroes in the type. If
// the given number if zero, this function may contain undefined
// behavior, or it may return the number of bits in the number. If
// this function can be called with zero, the use of
// count_trailing_zeroes_safe is preferred.
template<Unsigned IntType>
inline constexpr int count_trailing_zeroes(IntType value)
{
#if defined(AK_COMPILER_CLANG) || defined(AK_COMPILER_GCC)
static_assert(sizeof(IntType) <= sizeof(unsigned long long));
if constexpr (sizeof(IntType) <= sizeof(unsigned int))
return __builtin_ctz(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long))
return __builtin_ctzl(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long long))
return __builtin_ctzll(value);
VERIFY_NOT_REACHED();
#else
for (size_t i = 0; i < 8 * sizeof(IntType); ++i) {
if ((value >> i) & 1) {
return i;
}
}
return 8 * sizeof(IntType);
#endif
}
// The function will return the number of trailing zeroes in the type. If
// the given number is zero, this function will return the number of bits
// bits in the IntType.
template<Unsigned IntType>
inline constexpr int count_trailing_zeroes_safe(IntType value)
{
if (value == 0)
return 8 * sizeof(IntType);
return count_trailing_zeroes(value);
}
// The function will return the number of leading zeroes in the type. If
// the given number if zero, this function may contain undefined
// behavior, or it may return the number of bits in the number. If
// this function can be called with zero, the use of
// count_leading_zeroes_safe is preferred.
template<Unsigned IntType>
inline constexpr int count_leading_zeroes(IntType value)
{
#if defined(AK_COMPILER_CLANG) || defined(AK_COMPILER_GCC)
static_assert(sizeof(IntType) <= sizeof(unsigned long long));
if constexpr (sizeof(IntType) <= sizeof(unsigned int))
return __builtin_clz(value) - (32 - (8 * sizeof(IntType)));
if constexpr (sizeof(IntType) == sizeof(unsigned long))
return __builtin_clzl(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long long))
return __builtin_clzll(value);
VERIFY_NOT_REACHED();
#else
// Wrap around, catch going past zero by noticing that i is greater than the number of bits in the number
for (size_t i = (8 * sizeof(IntType)) - 1; i < 8 * sizeof(IntType); --i) {
if ((value >> i) & 1) {
return i;
}
}
return 8 * sizeof(IntType);
#endif
}
#ifdef __SIZEOF_INT128__
// This is required for math.cpp internal_scalbn
inline constexpr int count_leading_zeroes(unsigned __int128 value)
{
# if defined(AK_COMPILER_CLANG) || defined(AK_COMPILER_GCC)
return (value > __UINT64_MAX__) ? __builtin_clzll(value >> 64) : 64 + __builtin_clzll(value);
# else
unsigned __int128 mask = (unsigned __int128)1 << 127;
int ret = 0;
while ((value & mask) == 0) {
++ret;
mask >>= 1;
}
return ret;
# endif
}
#endif
// The function will return the number of leading zeroes in the type. If
// the given number is zero, this function will return the number of bits
// in the IntType.
template<Unsigned IntType>
inline constexpr int count_leading_zeroes_safe(IntType value)
{
if (value == 0)
return 8 * sizeof(IntType);
return count_leading_zeroes(value);
}
// The function will return the number of leading zeroes in the type. If
// the given number is zero, this function will return the number of bits
// in the IntType.
template<Integral IntType>
inline constexpr int bit_scan_forward(IntType value)
{
#if defined(AK_COMPILER_CLANG) || defined(AK_COMPILER_GCC)
static_assert(sizeof(IntType) <= sizeof(unsigned long long));
if constexpr (sizeof(IntType) <= sizeof(unsigned int))
return __builtin_ffs(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long))
return __builtin_ffsl(value);
if constexpr (sizeof(IntType) == sizeof(unsigned long long))
return __builtin_ffsll(value);
VERIFY_NOT_REACHED();
#else
if (value == 0)
return 0;
return 1 + count_trailing_zeroes(static_cast<MakeUnsigned<IntType>>(value));
#endif
}
}
#if USING_AK_GLOBALLY
using AK::bit_scan_forward;
using AK::count_leading_zeroes;
using AK::count_leading_zeroes_safe;
using AK::count_trailing_zeroes;
using AK::count_trailing_zeroes_safe;
using AK::popcount;
#endif