mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-11 17:00:37 +00:00
AK: Add BuiltinWrappers.h
The goal of this file is to enable C++ overloaded functions for standard builtin functions that we use. It contains fallback implementations for systems that do not have the builtins available.
This commit is contained in:
parent
01eefc344a
commit
548529ace4
Notes:
sideshowbarker
2024-07-17 22:38:31 +09:00
Author: https://github.com/Sylvyrfysh Commit: https://github.com/SerenityOS/serenity/commit/548529ace40 Pull-request: https://github.com/SerenityOS/serenity/pull/11223 Reviewed-by: https://github.com/BenWiederhake ✅ Reviewed-by: https://github.com/BertalanD
3 changed files with 165 additions and 0 deletions
110
AK/BuiltinWrappers.h
Normal file
110
AK/BuiltinWrappers.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Nick Johnson <sylvyrfysh@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Concepts.h"
|
||||
#include "Platform.h"
|
||||
|
||||
template<Unsigned IntType>
|
||||
inline constexpr int popcount(IntType value)
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
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 ((val >> 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(__GNUC__) || defined(__clang__)
|
||||
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 ((val >> 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(__GNUC__) || defined(__clang__)
|
||||
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 ((val >> i) & 1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 8 * sizeof(IntType);
|
||||
#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);
|
||||
}
|
|
@ -10,6 +10,7 @@ set(AK_TEST_SOURCES
|
|||
TestBinarySearch.cpp
|
||||
TestBitCast.cpp
|
||||
TestBitmap.cpp
|
||||
TestBuiltinWrappers.cpp
|
||||
TestByteBuffer.cpp
|
||||
TestCharacterTypes.cpp
|
||||
TestChecked.cpp
|
||||
|
|
54
Tests/AK/TestBuiltinWrappers.cpp
Normal file
54
Tests/AK/TestBuiltinWrappers.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Nick Johnson <sylvyrfysh@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibTest/TestCase.h>
|
||||
|
||||
#include <AK/BuiltinWrappers.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
TEST_CASE(wrapped_popcount)
|
||||
{
|
||||
EXPECT_EQ(popcount(NumericLimits<u8>::max()), 8);
|
||||
EXPECT_EQ(popcount(NumericLimits<u16>::max()), 16);
|
||||
EXPECT_EQ(popcount(NumericLimits<u32>::max()), 32);
|
||||
EXPECT_EQ(popcount(NumericLimits<u64>::max()), 64);
|
||||
EXPECT_EQ(popcount(NumericLimits<size_t>::max()), static_cast<int>(8 * sizeof(size_t)));
|
||||
EXPECT_EQ(popcount(0u), 0);
|
||||
EXPECT_EQ(popcount(0b01010101ULL), 4);
|
||||
}
|
||||
|
||||
TEST_CASE(wrapped_count_leading_zeroes)
|
||||
{
|
||||
EXPECT_EQ(count_leading_zeroes(NumericLimits<u8>::max()), 0);
|
||||
EXPECT_EQ(count_leading_zeroes(static_cast<u8>(0x20)), 2);
|
||||
EXPECT_EQ(count_leading_zeroes_safe(static_cast<u8>(0)), 8);
|
||||
EXPECT_EQ(count_leading_zeroes(NumericLimits<u16>::max()), 0);
|
||||
EXPECT_EQ(count_leading_zeroes(static_cast<u16>(0x20)), 10);
|
||||
EXPECT_EQ(count_leading_zeroes_safe(static_cast<u16>(0)), 16);
|
||||
EXPECT_EQ(count_leading_zeroes(NumericLimits<u32>::max()), 0);
|
||||
EXPECT_EQ(count_leading_zeroes(static_cast<u32>(0x20)), 26);
|
||||
EXPECT_EQ(count_leading_zeroes_safe(static_cast<u32>(0)), 32);
|
||||
EXPECT_EQ(count_leading_zeroes(NumericLimits<u64>::max()), 0);
|
||||
}
|
||||
|
||||
TEST_CASE(wrapped_count_trailing_zeroes)
|
||||
{
|
||||
EXPECT_EQ(count_trailing_zeroes(NumericLimits<u8>::max()), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u8>(1)), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u8>(2)), 1);
|
||||
EXPECT_EQ(count_trailing_zeroes_safe(static_cast<u8>(0)), 8);
|
||||
EXPECT_EQ(count_trailing_zeroes(NumericLimits<u16>::max()), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u16>(1)), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u16>(2)), 1);
|
||||
EXPECT_EQ(count_trailing_zeroes_safe(static_cast<u16>(0)), 16);
|
||||
EXPECT_EQ(count_trailing_zeroes(NumericLimits<u32>::max()), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u32>(1)), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u32>(2)), 1);
|
||||
EXPECT_EQ(count_trailing_zeroes_safe(static_cast<u32>(0)), 32);
|
||||
EXPECT_EQ(count_trailing_zeroes(NumericLimits<u64>::max()), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u64>(1)), 0);
|
||||
EXPECT_EQ(count_trailing_zeroes(static_cast<u64>(2)), 1);
|
||||
}
|
Loading…
Reference in a new issue