diff --git a/autotest/memcnt/memcnt.cpp b/autotest/memcnt/memcnt.cpp new file mode 100644 index 000000000..b1b5cf4b2 --- /dev/null +++ b/autotest/memcnt/memcnt.cpp @@ -0,0 +1,64 @@ +#include + +using namespace Upp; + +template +size_t memcnt_t_e(const T *p, const T& value, size_t sz) +{ + const T *e = p + sz; + size_t n = 0; + while(p < e) + n += (*p++ == value); + return n; +} + +template +size_t memcnt_t(const T *data, dword value, size_t sz) +{ + if(sizeof(T) == 1) + return memcnt8(data, value, sz); + if(sizeof(T) == 2) + return memcnt16(data, value, sz); + if(sizeof(T) == 4) + return memcnt32(data, value, sz); + return 0; +} + +template +void Test(int mul) { + const int N = 255533; + T data[N]; + for(int i = 0; i < N; i++) + data[i] = Random(256) * mul; + for(int value = 0; value < 256; value++) { + T x = mul * value; + DLOG((int)x << " " << memcnt_t(data, x, N) << " " << memcnt_t_e(data, x, N)); + ASSERT(memcnt_t(data, x, N) == memcnt_t_e(data, x, N)); + } +} + +CONSOLE_APP_MAIN +{ + StdLogSetup(LOG_COUT|LOG_FILE); + +#if 0 + word h[] = { 0, 0, 0, 4, 4, 0, 0, 4, + 0, 4, 0 }; + + int cnt = memcnt16(h, 4, __countof(h)); + DDUMP(cnt); + cnt = memcnt_t(h, 4, __countof(h)); + DDUMP(cnt); + cnt = memcnt16(h, 0, __countof(h)); + DDUMP(cnt); + + Test(253); + return; +#endif + + Test(1); + Test(253); + Test(70000); + + DLOG("========== OK"); +} diff --git a/autotest/memcnt/memcnt.upp b/autotest/memcnt/memcnt.upp new file mode 100644 index 000000000..cc02add73 --- /dev/null +++ b/autotest/memcnt/memcnt.upp @@ -0,0 +1,9 @@ +uses + Core; + +file + memcnt.cpp; + +mainconfig + "" = ""; + diff --git a/uppsrc/Core/Mem.h b/uppsrc/Core/Mem.h index 0ed3677a1..cc92836c9 100644 --- a/uppsrc/Core/Mem.h +++ b/uppsrc/Core/Mem.h @@ -739,3 +739,75 @@ bool memeq_t(const T *p, const T *q, size_t count) } hash_t memhash(const void *ptr, size_t count); + +inline +size_t memcnt8(const void *s, dword value, size_t sz) +{ + const byte *p = (byte *)s; + const byte *e = p + sz; + size_t n = 0; + +#ifdef CPU_SIMD + const byte *e16 = p + (sz & ~15); // Process in 16-byte chunks + if(p < e16) { + i8x16 value16 = i8all(value); + do { + n += CountTrue(i8x16(p) == value16); + p += 16; + } + while(p < e16); + } +#endif + + while(p < e) // Process remaining bytes (less than 16) + n += (*p++ == value); + return n; +} + +inline +size_t memcnt16(const void *s, dword value, size_t sz) +{ + const word *p = (word *)s; + const word *e = p + sz; + size_t n = 0; + +#ifdef CPU_SIMD + const word *e16 = p + (sz & ~7); // Process in 16-byte chunks + if(p < e16) { + i16x8 value8 = i16all(value); + do { + n += CountTrue(i16x8(p) == value8); + p += 8; + } + while(p < e16); + } +#endif + + while(p < e) // Process remaining bytes (less than 16) + n += (*p++ == value); + return n; +} + +inline +size_t memcnt32(const void *s, dword value, size_t sz) +{ + const dword *p = (dword *)s; + const dword *e = p + sz; + size_t n = 0; + +#ifdef CPU_SIMD + const dword *e16 = p + (sz & ~3); // Process in 16-byte chunks + if(p < e16) { + i32x4 value4 = i32all(value); + do { + n += CountTrue(i32x4(p) == value4); + p += 4; + } + while(p < e16); + } +#endif + + while(p < e) // Process remaining bytes (less than 16) + n += (*p++ == value); + return n; +} diff --git a/uppsrc/Core/src.tpp/Mem_en-us.tpp b/uppsrc/Core/src.tpp/Mem_en-us.tpp index a9596d59d..336badd53 100644 --- a/uppsrc/Core/src.tpp/Mem_en-us.tpp +++ b/uppsrc/Core/src.tpp/Mem_en-us.tpp @@ -113,12 +113,24 @@ about the same speed. Provided mostly for completeness.&] [*@3 p][@(0.0.255) `[][/ position][@(0.0.255) `] !`=] [*@3 q][@(0.0.255) `[][/ position][@(0.0.255) `] ]. If no such position exists, returns [*@3 count]. In other words returns count of bytes at p and q that are equal.&] +[s3;%% &] +[s4; &] +[s5;:Upp`:`:memcnt8`(const void`*`,dword`,size`_t`): size`_t [* memcnt8]([@(0.0.255) cons +t] [@(0.0.255) void] [@(0.0.255) `*][*@3 s], dword [*@3 value], size`_t +[*@3 sz])&] +[s5;:Upp`:`:memcnt16`(const void`*`,dword`,size`_t`): size`_t [* memcnt16]([@(0.0.255) co +nst] [@(0.0.255) void] [@(0.0.255) `*][*@3 s], dword [*@3 value], size`_t +[*@3 sz])&] +[s5;:Upp`:`:memcnt32`(const void`*`,dword`,size`_t`): size`_t [* memcnt32]([@(0.0.255) co +nst] [@(0.0.255) void] [@(0.0.255) `*][*@3 s], dword [*@3 value], size`_t +[*@3 sz])&] +[s2;%% Counts the number of items equal to [%-*@3 value].&] [s3; &] [s4; &] [s5;:Upp`:`:memhash`(const void`*`,size`_t`): [_^Upp`:`:hash`_t^ hash`_t]_[* memhash]([@(0.0.255) c onst]_[@(0.0.255) void]_`*[*@3 ptr], [_^size`_t^ size`_t]_[*@3 size])&] [s2;%% Computes a non`-cryptographic hash of memory block. &] -[s3;%% &] +[s3; &] [s4; &] [s5;:Upp`:`:FoldHash`(Upp`:`:qword`): [_^Upp`:`:dword^ dword]_[* FoldHash]([_^Upp`:`:qword^ q word]_[*@3 h])&]