Skip to content

Commit 53afe2e

Browse files
author
Julian LALU
committed
add common trailing_zero
1 parent 12c80cf commit 53afe2e

File tree

12 files changed

+236
-169
lines changed

12 files changed

+236
-169
lines changed

core.vscode.code-workspace

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"cmake.launchBehavior": "breakAndReuseTerminal",
2525
"testMate.cpp.test.executables": "target/**/*{test}*",
2626
"cmake.options.statusBarVisibility": "compact",
27+
"debug.showVariableTypes": true,
2728
},
2829
"extensions": {
2930
"recommendations": [

interface/core/containers/hashmap.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ namespace hud
7373
return hud::bits::has_zero_byte(hud::bits::has_value_byte(value_, h2_hash));
7474
}
7575

76+
u64 mask_of_empty_slot()
77+
{
78+
return hud::bits::has_zero_byte(hud::bits::has_value_byte(value_, static_cast<u8>(control_e::empty)));
79+
}
80+
7681
private:
7782
u64 value_;
7883
};
@@ -236,6 +241,10 @@ namespace hud
236241
// for (u32 i : g.match(H2(hash)))
237242
// {
238243
// }
244+
u64 mask_of_empty_slot = g.mask_of_empty_slot();
245+
if (mask_of_empty_slot != 0) [[likely]]
246+
{
247+
}
239248
}
240249
return hud::nullopt;
241250
}

interface/core/i128/i128_portable.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "../limits.h"
44
#include "../math.h"
55
#include "../assert.h"
6+
#include "../bits.h"
67

78
namespace hud
89
{
@@ -833,7 +834,7 @@ namespace hud
833834
/** Left shift this and return the result */
834835
constexpr u128_portable operator<<(i32 amount) const noexcept
835836
{
836-
// uint64_t shifts of >= 64 are undefined, so we will need some
837+
// u64 shifts of >= 64 are undefined, so we will need some
837838
// special-casing.
838839
return amount >= 64 ? u128_portable(low_ << (amount - 64), 0) :
839840
amount == 0 ? *this :
@@ -843,7 +844,7 @@ namespace hud
843844
/** Right shift this and return the result */
844845
constexpr const u128_portable operator>>(i32 amount) const noexcept
845846
{
846-
// uint64_t shifts of >= 64 are undefined, so we will need some
847+
// u64 shifts of >= 64 are undefined, so we will need some
847848
// special-casing.
848849
return amount >= 64 ? u128_portable(0, high_ >> (amount - 64)) :
849850
amount == 0 ? *this :
@@ -1002,11 +1003,11 @@ namespace hud
10021003
if (u64 hi = n.high_)
10031004
{
10041005
HD_ASSUME(hi != 0);
1005-
return 127 - hud::math::count_leading_zero(hi);
1006+
return 127 - hud::bits::leading_zero(hi);
10061007
}
10071008
const u64 low = n.low_;
10081009
HD_ASSUME(low != 0);
1009-
return 63 - hud::math::count_leading_zero(low);
1010+
return 63 - hud::bits::leading_zero(low);
10101011
};
10111012

10121013
// Left aligns the MSB of the denominator and the dividend.

interface/core/os_common/bits.h

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ namespace hud::os::common
2323
* This indicates that a zero byte (0x00) is present in the word at byte index 2 and 4
2424
*/
2525
[[nodiscard]] static constexpr u64 has_zero_byte(u64 value) noexcept
26-
2726
{
2827
// From http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
2928
// value= 0x1213140015001617
@@ -53,6 +52,75 @@ namespace hud::os::common
5352
// Final result after has_zero_byte = 0x8000000000008000
5453
return has_zero_byte(value ^ (0x0101010101010101ULL * byte_value));
5554
}
55+
56+
/** Returns the number of consecutive 0 bits in the value. */
57+
[[nodiscard]] static constexpr u32 leading_zero(u8 value) noexcept
58+
{
59+
if (value == 0)
60+
return 8;
61+
62+
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_CLANG_CL) || defined(HD_COMPILER_GCC)
63+
return u8(__builtin_clz((u32(value) << 1) | 1) - 23);
64+
#else
65+
return 7 - floor_log2(u32(value));
66+
#endif
67+
}
68+
69+
/** Returns the number of consecutive 0 bits in the value. */
70+
[[nodiscard]] static constexpr u32 leading_zero(u32 value) noexcept
71+
{
72+
if (value == 0)
73+
return 32;
74+
return 31 - hud::math::floor_log2(u32(value));
75+
}
76+
77+
/** Returns the number of consecutive 0 bits in the value. */
78+
[[nodiscard]] static constexpr u32 leading_zero(u64 value) noexcept
79+
{
80+
if (value == 0)
81+
return 64;
82+
return 63 - hud::math::floor_log2(value);
83+
}
84+
85+
[[nodiscard]] static constexpr u32 trailing_zero(u32 value) noexcept
86+
{
87+
u32 c = 32; // c will be the number of zero bits on the right
88+
value &= -i32(value);
89+
if (value)
90+
c--;
91+
if (value & 0x0000FFFFu)
92+
c -= 16;
93+
if (value & 0x00FF00FFu)
94+
c -= 8;
95+
if (value & 0x0F0F0F0Fu)
96+
c -= 4;
97+
if (value & 0x33333333u)
98+
c -= 2;
99+
if (value & 0x55555555u)
100+
c -= 1;
101+
return c;
102+
}
103+
104+
[[nodiscard]] static constexpr u64 trailing_zero(u64 value) noexcept
105+
{
106+
u64 c = 64; // c sera le nombre de bits zéro à droite
107+
value &= -i64(value); // Mask les bits de poids faible avec l'opération de complément à 2
108+
if (value)
109+
c--;
110+
if (value & 0x00000000FFFFFFFFu)
111+
c -= 32;
112+
if (value & 0x0000FFFF0000FFFFu)
113+
c -= 16;
114+
if (value & 0x00FF00FF00FF00FFu)
115+
c -= 8;
116+
if (value & 0x0F0F0F0F0F0F0F0Fu)
117+
c -= 4;
118+
if (value & 0x3333333333333333u)
119+
c -= 2;
120+
if (value & 0x5555555555555555u)
121+
c -= 1;
122+
return c;
123+
}
56124
};
57125

58126
} // namespace hud::os::common

interface/core/os_common/math.h

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -144,72 +144,6 @@ namespace hud::os::common
144144
return pos;
145145
}
146146

147-
/** Returns the number of consecutive 0 bits in the value. */
148-
[[nodiscard]] static constexpr u32 count_leading_zero(u8 value) noexcept
149-
{
150-
if (value == 0)
151-
return 8;
152-
153-
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_CLANG_CL) || defined(HD_COMPILER_GCC)
154-
return u8(__builtin_clz((u32(value) << 1) | 1) - 23);
155-
#else
156-
return 7 - floor_log2(u32(value));
157-
#endif
158-
}
159-
160-
/** Returns the number of consecutive 0 bits in the value. */
161-
[[nodiscard]] static constexpr u32 count_leading_zero(u32 value) noexcept
162-
{
163-
if (value == 0)
164-
return 32;
165-
166-
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_CLANG_CL) || defined(HD_COMPILER_GCC)
167-
return __builtin_clz(value);
168-
#elif defined(HD_COMPILER_MSVC)
169-
u32 result = 0;
170-
if (_BitScanReverse((unsigned long *)&result, value))
171-
{
172-
return 31 - result;
173-
}
174-
return 32;
175-
#else
176-
return 31 - floor_log2(u32(value));
177-
#endif
178-
}
179-
180-
/** Returns the number of consecutive 0 bits in the value. */
181-
[[nodiscard]] static constexpr u32 count_leading_zero(u64 value) noexcept
182-
{
183-
if (value == 0)
184-
return 64;
185-
186-
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_CLANG_CL) || defined(HD_COMPILER_GCC)
187-
return __builtin_clzll(value);
188-
#elif defined(HD_COMPILER_MSVC)
189-
#if defined(HD_TARGET_X64)
190-
u32 result = 0;
191-
if (_BitScanReverse64((unsigned long *)&result, value))
192-
{
193-
return 63 - result;
194-
}
195-
return 64;
196-
#else
197-
u32 result = 0;
198-
if ((value >> 32) && _BitScanReverse((unsigned long *)&result, static_cast<u32>(value >> 32)))
199-
{
200-
return 31 - result;
201-
}
202-
if (_BitScanReverse((unsigned long *)&result, static_cast<u32>(value)))
203-
{
204-
return 63 - result;
205-
}
206-
return 64;
207-
#endif
208-
#else
209-
return 63 - floor_log2(value);
210-
#endif
211-
}
212-
213147
enum class fpclassify_e
214148
{
215149
subnormal = FP_SUBNORMAL,

interface/core/os_linux/bits.h

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
namespace hud::os::linux
1010
{
1111
struct bits : public os::common::bits
12-
{ /**
13-
* Reverses the order of bytes in an integer.
14-
* Convert from little-endian to big-endian conversion and inverse.
15-
* @param value The integer
16-
* @param The integer the order of bytes reversed
17-
*/
12+
{
13+
/**
14+
* Reverses the order of bytes in an integer.
15+
* Convert from little-endian to big-endian conversion and inverse.
16+
* @param value The integer
17+
* @param The integer the order of bytes reversed
18+
*/
1819

1920
static constexpr u32 reverse_bytes(const u32 value) noexcept
2021
{
@@ -103,7 +104,31 @@ namespace hud::os::linux
103104
return (value >> __r) | (value << ((64 - __r) % 64));
104105
#endif
105106
}
106-
};
107-
} // namespace hud::os::linux
107+
108+
/** Returns the number of consecutive 0 bits in the value. */
109+
[[nodiscard]] static constexpr u32 leading_zero(u32 value) noexcept
110+
{
111+
if (value == 0)
112+
return 32;
113+
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_GCC)
114+
return __builtin_clz(value);
115+
#else
116+
return os::common::bits::leading_zero(value);
117+
#endif
118+
}
119+
120+
/** Returns the number of consecutive 0 bits in the value. */
121+
[[nodiscard]] static constexpr u32 leading_zero(u64 value) noexcept
122+
{
123+
if (value == 0)
124+
return 64;
125+
126+
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_GCC)
127+
return __builtin_clzll(value);
128+
#else
129+
return os::common::bits::leading_zero(value);
130+
#endif
131+
};
132+
} // namespace hud::os::linux
108133

109134
#endif // HD_INC_CORE_OS_LINUX_BITS_H

interface/core/os_windows/bits.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,60 @@ namespace hud::os::windows
137137
return _rotr64(value, static_cast<i32>(shift));
138138
}
139139
}
140+
141+
/** Returns the number of consecutive 0 bits in the value. */
142+
[[nodiscard]] static constexpr u32 leading_zero(u32 value) noexcept
143+
{
144+
if (value == 0)
145+
return 32;
146+
147+
#if defined(HD_COMPILER_CLANG_CL)
148+
return __builtin_clz(value);
149+
#elif defined(HD_COMPILER_MSVC)
150+
151+
u32 result = 0;
152+
if (_BitScanReverse((unsigned long *)&result, value))
153+
{
154+
return 31 - result;
155+
}
156+
return 32;
157+
#else
158+
return os::common::bits(value);
159+
#endif
160+
}
161+
162+
/** Returns the number of consecutive 0 bits in the value. */
163+
[[nodiscard]] static constexpr u32 leading_zero(u64 value) noexcept
164+
{
165+
if (value == 0)
166+
return 64;
167+
168+
#if defined(HD_COMPILER_CLANG_CL)
169+
return __builtin_clzll(value);
170+
#elif defined(HD_COMPILER_MSVC)
171+
#if defined(HD_TARGET_X64)
172+
u32 result = 0;
173+
if (_BitScanReverse64((unsigned long *)&result, value))
174+
{
175+
return 63 - result;
176+
}
177+
return 64;
178+
#else
179+
u32 result = 0;
180+
if ((value >> 32) && _BitScanReverse((unsigned long *)&result, static_cast<u32>(value >> 32)))
181+
{
182+
return 31 - result;
183+
}
184+
if (_BitScanReverse((unsigned long *)&result, static_cast<u32>(value)))
185+
{
186+
return 63 - result;
187+
}
188+
return 64;
189+
#endif
190+
#else
191+
return os::common::bits(value);
192+
#endif
193+
}
140194
};
141195
} // namespace hud::os::windows
142196

test/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ set( src
4848
atomics/atomics_load.cpp
4949
atomics/atomics_store.cpp
5050
atomics/atomics_thread_fence.cpp
51-
bits/bits.cpp
52-
bits/bits_rotate.cpp
51+
bits/bits_leading_zero.cpp
5352
bits/bits_reverse.cpp
53+
bits/bits_rotate.cpp
54+
bits/bits_trailing_zero.cpp
55+
bits/bits.cpp
5456
compressed_pair/compressed_pair_constructors.cpp
5557
compressed_pair/compressed_pair_misc.cpp
5658
compressed_pair/compressed_pair_swap.cpp

test/bits/bits_leading_zero.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <core/bits.h>
2+
3+
GTEST_TEST(bits, leading_zero_u32)
4+
{
5+
hud_assert_eq(hud::bits::leading_zero(u32(0)), 32);
6+
hud_assert_eq(hud::bits::leading_zero(u32(1)), 31);
7+
hud_assert_eq(hud::bits::leading_zero(u32(2)), 30);
8+
hud_assert_eq(hud::bits::leading_zero(u32(0xFFFFFFFF)), 0);
9+
hud_assert_eq(hud::bits::leading_zero(u32(0x80000000)), 0);
10+
hud_assert_eq(hud::bits::leading_zero(u32(0x40000000)), 1);
11+
hud_assert_eq(hud::bits::leading_zero(u32(0x0F000000)), 4);
12+
hud_assert_eq(hud::bits::leading_zero(u32(0x10000000)), 3);
13+
}
14+
15+
GTEST_TEST(bits, leading_zero_u64)
16+
{
17+
hud_assert_eq(hud::bits::leading_zero(u64(0)), 64);
18+
hud_assert_eq(hud::bits::leading_zero(u64(1)), 63);
19+
hud_assert_eq(hud::bits::leading_zero(u64(2)), 62);
20+
hud_assert_eq(hud::bits::leading_zero(u64(0xFFFFFFFFFFFFFFFF)), 0);
21+
hud_assert_eq(hud::bits::leading_zero(u64(0x8000000000000000)), 0);
22+
hud_assert_eq(hud::bits::leading_zero(u64(0x4000000000000000)), 1);
23+
hud_assert_eq(hud::bits::leading_zero(u64(0x00000000FFFFFFFF)), 32);
24+
hud_assert_eq(hud::bits::leading_zero(u64(0x0000FFFF00000000)), 16);
25+
hud_assert_eq(hud::bits::leading_zero(u64(0x00F0000000000000)), 8);
26+
hud_assert_eq(hud::bits::leading_zero(u64(0x0F00000000000000)), 4);
27+
hud_assert_eq(hud::bits::leading_zero(u64(0x1000000000000000)), 3);
28+
hud_assert_eq(hud::bits::leading_zero(u64(0x2000000000000000)), 2);
29+
}

0 commit comments

Comments
 (0)