diff --git a/autotest/CountBits/CountBits.cpp b/autotest/CountBits/CountBits.cpp new file mode 100644 index 000000000..40a5b73db --- /dev/null +++ b/autotest/CountBits/CountBits.cpp @@ -0,0 +1,33 @@ +#include + +using namespace Upp; + +CONSOLE_APP_MAIN +{ + StdLogSetup(LOG_FILE|LOG_COUT); + + DUMP(CountBits(0x0001)); + DUMP(CountBits(0x000f)); + DUMP(CountBits(0x00ff)); + DUMP(CountBits(0x0fff)); + DUMP(CountBits(0xffff)); + DUMP(CountBits(0x000fffff)); + DUMP(CountBits(0x00ffffff)); + DUMP(CountBits(0x0fffffff)); + DUMP(CountBits(0xffffffff)); + + + LOG("===================="); + + DUMP(CountBits64(0x00000001ffffffff)); + DUMP(CountBits64(0x0000000fffffffff)); + DUMP(CountBits64(0x000000ffffffffff)); + DUMP(CountBits64(0x00000fffffffffff)); + DUMP(CountBits64(0x0000ffffffffffff)); + DUMP(CountBits64(0x000fffffffffffff)); + DUMP(CountBits64(0x00ffffffffffffff)); + DUMP(CountBits64(0x0fffffffffffffff)); + DUMP(CountBits64(0xffffffffffffffff)); + + CheckLogEtalon(); +} diff --git a/autotest/CountBits/CountBits.upp b/autotest/CountBits/CountBits.upp new file mode 100644 index 000000000..ceda0ff43 --- /dev/null +++ b/autotest/CountBits/CountBits.upp @@ -0,0 +1,10 @@ +uses + Core; + +file + Etalon.log, + CountBits.cpp; + +mainconfig + "" = ""; + diff --git a/autotest/CountBits/Etalon.log b/autotest/CountBits/Etalon.log new file mode 100644 index 000000000..3bf9570e1 --- /dev/null +++ b/autotest/CountBits/Etalon.log @@ -0,0 +1,21 @@ +* /home/maldoror//upp/.cache/upp.out/autotest/CLANG.Debug.Debug_Full.Shared/CountBits 08.02.2025 14:47:07, user: maldoror + +CountBits(0x0001) = 1 +CountBits(0x000f) = 4 +CountBits(0x00ff) = 8 +CountBits(0x0fff) = 12 +CountBits(0xffff) = 16 +CountBits(0x000fffff) = 20 +CountBits(0x00ffffff) = 24 +CountBits(0x0fffffff) = 28 +CountBits(0xffffffff) = 32 +==================== +CountBits64(0x00000001ffffffff) = 33 +CountBits64(0x0000000fffffffff) = 36 +CountBits64(0x000000ffffffffff) = 40 +CountBits64(0x00000fffffffffff) = 44 +CountBits64(0x0000ffffffffffff) = 48 +CountBits64(0x000fffffffffffff) = 52 +CountBits64(0x00ffffffffffffff) = 56 +CountBits64(0x0fffffffffffffff) = 60 +CountBits64(0xffffffffffffffff) = 64 diff --git a/uppsrc/Core/Ops.h b/uppsrc/Core/Ops.h index dc36a13f2..a4017f40f 100644 --- a/uppsrc/Core/Ops.h +++ b/uppsrc/Core/Ops.h @@ -202,6 +202,47 @@ inline bool FitsInInt64(double x) return x >= -9223372036854775808.0 && x < 9223372036854775808.0; } +force_inline +int CountBits(dword mask) +{ +#if defined(__GNUC__) || defined(__clang__) + return __builtin_popcount(mask); +#elif defined(_MSC_VER) + return __popcnt(mask); +#else + // Fallback (unlikely) + mask = mask - ((mask >> 1) & 0x55555555); + mask = (mask & 0x33333333) + ((mask >> 2) & 0x33333333); + mask = (mask + (mask >> 4)) & 0x0F0F0F0F; + mask = mask + (mask >> 8); + mask = mask + (mask >> 16); + return mask & 0x3F; +#endif +} + +force_inline +int CountBits64(uint64 mask) +{ +#if defined(__GNUC__) || defined(__clang__) + return __builtin_popcountll(mask); +#elif defined(_MSC_VER) + #if defined(_WIN64) + return __popcnt64(mask); + #else + return CountBits(static_cast(mask)) + CountBits(static_cast(mask >> 32)); + #endif +#else + // Fallback (unlikely) + mask = mask - ((mask >> 1) & 0x5555555555555555ULL); + mask = (mask & 0x3333333333333333ULL) + ((mask >> 2) & 0x3333333333333333ULL); + mask = (mask + (mask >> 4)) & 0x0F0F0F0F0F0F0F0FULL; + mask = mask + (mask >> 8); + mask = mask + (mask >> 16); + mask = mask + (mask >> 32); + return mask & 0x7F; +#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 3f6703e6a..a5a6b3b33 100644 --- a/uppsrc/Core/src.tpp/Mem_en-us.tpp +++ b/uppsrc/Core/src.tpp/Mem_en-us.tpp @@ -132,6 +132,13 @@ for binary value 1010, this value is 4. For 0, the value is 0.&] loosing the precision.&] [s3;%% &] [s4; &] +[s5;:Upp`:`:CountBits`(dword`): [@(0.0.255) int] [* CountBits]([_^Upp`:`:dword^ dword] +[*@3 mask])&] +[s5;:Upp`:`:CountBits64`(uint64`): [@(0.0.255) int] [* CountBits64]([_^Upp`:`:uint64^ uint6 +4] [*@3 mask])&] +[s2;%% Returns the total number of set bits in a given bit [%-*@3 mask].&] +[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