diff --git a/autotest/CountTrailingZeroBits/CountTrailingZeroBits.cpp b/autotest/CountTrailingZeroBits/CountTrailingZeroBits.cpp new file mode 100644 index 000000000..a7ba24a05 --- /dev/null +++ b/autotest/CountTrailingZeroBits/CountTrailingZeroBits.cpp @@ -0,0 +1,24 @@ +#include + +using namespace Upp; + +CONSOLE_APP_MAIN +{ + StdLogSetup(LOG_FILE|LOG_COUT); + + for(int i = 0; i < 32; i++) + DLOG(i << " " << CountTrailingZeroBits(1 << i)); + DDUMP(CountTrailingZeroBits(0x78)); + DDUMP(CountTrailingZeroBits(0xf000)); + DDUMP(CountTrailingZeroBits(0xf0000000)); + + for(int i = 0; i < 64; i++) + DLOG(i << " " << CountTrailingZeroBits64((uint64)1 << i)); + DDUMP(CountTrailingZeroBits64(0x78)); + DDUMP(CountTrailingZeroBits64(0xf000)); + DDUMP(CountTrailingZeroBits64(0xf0000000)); + DDUMP(CountTrailingZeroBits64(0xf0000000f0000000)); + DDUMP(CountTrailingZeroBits64(0xf000000000000000)); + + CheckLogEtalon(); +} diff --git a/autotest/CountTrailingZeroBits/CountTrailingZeroBits.upp b/autotest/CountTrailingZeroBits/CountTrailingZeroBits.upp new file mode 100644 index 000000000..d2389914c --- /dev/null +++ b/autotest/CountTrailingZeroBits/CountTrailingZeroBits.upp @@ -0,0 +1,10 @@ +uses + Core; + +file + Etalon.log, + CountTrailingZeroBits.cpp; + +mainconfig + "" = ""; + diff --git a/autotest/CountTrailingZeroBits/Etalon.log b/autotest/CountTrailingZeroBits/Etalon.log new file mode 100644 index 000000000..73d6426c2 --- /dev/null +++ b/autotest/CountTrailingZeroBits/Etalon.log @@ -0,0 +1,106 @@ +* C:\upp\out\autotest\CLANGx64.Debug.Debug_Full\CountTrailingZeroBits.exe 31.03.2025 11:30:38, user: mirek + +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +CountTrailingZeroBits(0x78) = 3 +CountTrailingZeroBits(0xf000) = 12 +CountTrailingZeroBits(0xf0000000) = 28 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 +33 33 +34 34 +35 35 +36 36 +37 37 +38 38 +39 39 +40 40 +41 41 +42 42 +43 43 +44 44 +45 45 +46 46 +47 47 +48 48 +49 49 +50 50 +51 51 +52 52 +53 53 +54 54 +55 55 +56 56 +57 57 +58 58 +59 59 +60 60 +61 61 +62 62 +63 63 +CountTrailingZeroBits64(0x78) = 3 +CountTrailingZeroBits64(0xf000) = 12 +CountTrailingZeroBits64(0xf0000000) = 28 +CountTrailingZeroBits64(0xf0000000f0000000) = 28 +CountTrailingZeroBits64(0xf000000000000000) = 60 diff --git a/uppsrc/Core/Ops.h b/uppsrc/Core/Ops.h index 8907b44a0..924bed32a 100644 --- a/uppsrc/Core/Ops.h +++ b/uppsrc/Core/Ops.h @@ -243,6 +243,55 @@ int CountBits64(uint64 mask) #endif } +force_inline +int CountTrailingZeroBits(dword x) +{ +#if COMPILER_GCC && !defined(flagLEGACY_CPU) + return __builtin_ctz(x); +#elif COMPILER_MSC && !defined(flagLEGACY_CPU) + unsigned long index; + _BitScanForward(&index, x); + return index; +#else + // unlikely fallback + int ret = 0; + if((x & 0xffff) == 0) { + x >>= 16; + ret += 16; + } + if((x & 0xff) == 0) { + x >>= 8; + ret += 8; + } + if((x & 0xf) == 0) { + x >>= 4; + ret += 4; + } + if((x & 0x3) == 0) { + x >>= 2; + ret += 2; + } + if((x & 0x1) == 0) + ret += 1; + return ret; +#endif +} + +force_inline +int CountTrailingZeroBits64(uint64 x) +{ +#if COMPILER_GCC && !defined(flagLEGACY_CPU) + return __builtin_ctzll(x); +#elif COMPILER_MSC && !defined(flagLEGACY_CPU) + unsigned long index; + _BitScanForward64(&index, x); + return index; +#else + // unlikely fallback + return (x & 0xffffffff) ? CountTrailingZeroBits((dword)x) : CountTrailingZeroBits((dword)(x >> 32)) + 32; +#endif +} + #if defined(__SIZEOF_INT128__) && (__GNUC__ > 5 || __clang_major__ >= 5) #ifdef CPU_X86 diff --git a/uppsrc/Core/src.tpp/Mem_en-us.tpp b/uppsrc/Core/src.tpp/Mem_en-us.tpp index a5a6b3b33..9d8065e43 100644 --- a/uppsrc/Core/src.tpp/Mem_en-us.tpp +++ b/uppsrc/Core/src.tpp/Mem_en-us.tpp @@ -114,7 +114,7 @@ onst]_[@(0.0.255) void]_`*[*@3 ptr], [_^size`_t^ size`_t]_[*@3 size])&] word]_[*@3 h])&] [s2;%% This functions `"hashes all bits together`". One purpose is to bring the entropy of higher bits down so that the hash can -be limited by masking, other purpose is to provide hash for integral +be limited by masking, other purpose is to provide hash for integer numbers.&] [s2;%% &] [s4; &] @@ -139,6 +139,14 @@ loosing the precision.&] [s2;%% Returns the total number of set bits in a given bit [%-*@3 mask].&] [s3; &] [s4; &] +[s5;:Upp`:`:CountTrailingZeroBits`(dword`): [@(0.0.255) int] [* CountTrailingZeroBits](dw +ord [*@3 x])&] +[s5;:Upp`:`:CountTrailingZeroBits64`(uint64`): [@(0.0.255) int] [* CountTrailingZeroBits6 +4](uint64 [*@3 x])&] +[s2; [%% Returns the index of first non`-zero bit in (from least significant +bit). If] [*@3 x] is zero, the result is undefined.&] +[s3; &] +[s4; &] [s5;:Upp`:`:Peek16le`(const void`*`): [@(0.0.255) int]_[* Peek16le]([@(0.0.255) const]_[@(0.0.255) v oid]_`*[*@3 ptr])&] [s5;:Upp`:`:Peek32le`(const void`*`): [@(0.0.255) int]_[* Peek32le]([@(0.0.255) const]_[@(0.0.255) v