diff --git a/source/lib/lib.cpp b/source/lib/lib.cpp index dc7a171546..a9d875ed25 100755 --- a/source/lib/lib.cpp +++ b/source/lib/lib.cpp @@ -25,11 +25,15 @@ #include "sysdep/sysdep.h" +#ifndef PERFORM_SELF_TEST +#define PERFORM_SELF_TEST 0 +#endif + // FNV1-A hash - good for strings. // if len = 0 (default), treat buf as a C-string; // otherwise, hash bytes of buf. -u32 fnv_hash(const void* buf, const size_t len) +u32 fnv_hash(const void* buf, size_t len) { u32 h = 0x811c9dc5u; // give distinct values for different length 0 buffers. @@ -65,7 +69,7 @@ u32 fnv_hash(const void* buf, const size_t len) // FNV1-A hash - good for strings. // if len = 0 (default), treat buf as a C-string; // otherwise, hash bytes of buf. -u64 fnv_hash64(const void* buf, const size_t len) +u64 fnv_hash64(const void* buf, size_t len) { u64 h = 0xCBF29CE484222325ull; // give distinct values for different length 0 buffers. @@ -101,7 +105,7 @@ u64 fnv_hash64(const void* buf, const size_t len) // special version for strings: first converts to lowercase // (useful for comparing mixed-case filenames). // note: still need , e.g. to support non-0-terminated strings -u32 fnv_lc_hash(const char* str, const size_t len) +u32 fnv_lc_hash(const char* str, size_t len) { u32 h = 0x811c9dc5u; // give distinct values for different length 0 buffers. @@ -135,44 +139,53 @@ u32 fnv_lc_hash(const char* str, const size_t len) -bool is_pow2(const long n) +bool is_pow2(uint n) { - return (n != 0l) && !(n & (n-1l)); + // 0 would pass the test below but isn't a POT. + if(n == 0) + return false; + return (n & (n-1l)) == 0; } // return -1 if not an integral power of 2, // otherwise the base2 logarithm -int ilog2(const int n) +int ilog2(uint n) { + int bit_index; // return value + #if CPU_IA32 __asm { mov ecx, [n] - or eax, -1 // return value + or eax, -1 // return value if not a POT + test ecx, ecx + jz not_pot lea edx, [ecx-1] - test ecx, edx // power of 2? - jnz skip + test ecx, edx + jnz not_pot bsf eax, ecx - skip: - mov [n], eax + not_pot: + mov [bit_index], eax } - return n; - #else - if(n || n & (n-1)) + if(!is_pow2(n)) return -1; - int i = 1, j = 0; - for(; i != n; i += i, j++) - ; - return j; + bit_index = 0; + // note: compare against n directly because it is known to be a POT. + for(uint bit_value = 1; bit_value != n; bit_value *= 2) + bit_index++; #endif + + debug_assert(-1 <= bit_index && bit_index < sizeof(int)*CHAR_BIT); + debug_assert(bit_index == -1 || n == (1u << bit_index)); + return bit_index; } @@ -193,7 +206,7 @@ uint log2(uint x) int ilog2(const float x) { - const u32 i = (u32&)x; + const u32 i = *(u32*)&x; u32 biased_exp = (i >> 23) & 0xff; return (int)biased_exp - 127; } @@ -454,3 +467,35 @@ int match_wildcardw(const wchar_t* s, const wchar_t* w) return (*w == '\0'); } + + + +////////////////////////////////////////////////////////////////////////////// +// +// built-in self test +// +////////////////////////////////////////////////////////////////////////////// + +#if PERFORM_SELF_TEST +namespace test { + +static void test_log2() +{ + debug_assert(ilog2(0) == -1); + debug_assert(ilog2(3) == -1); + debug_assert(ilog2(0xffffffff) == -1); + debug_assert(ilog2(1) == 0); + debug_assert(ilog2(256) == 8); + debug_assert(ilog2(0x80000000) == 31); +} + +static int run_tests() +{ + test_log2(); + return 0; +} + +static int dummy = run_tests(); + +} // namespace test +#endif // #if PERFORM_SELF_TEST diff --git a/source/lib/lib.h b/source/lib/lib.h index fd4363f090..6ba3d7bf8c 100755 --- a/source/lib/lib.h +++ b/source/lib/lib.h @@ -309,12 +309,12 @@ const size_t GiB = 1ul << 30; // FNV1-A hash - good for strings. // if len = 0 (default), treat buf as a C-string; // otherwise, hash bytes of buf. -extern u32 fnv_hash(const void* buf, const size_t len = 0); -extern u64 fnv_hash64(const void* buf, const size_t len = 0); +extern u32 fnv_hash(const void* buf, size_t len = 0); +extern u64 fnv_hash64(const void* buf, size_t len = 0); // special version for strings: first converts to lowercase // (useful for comparing mixed-case filenames) -extern u32 fnv_lc_hash(const char* str, const size_t len = 0); +extern u32 fnv_lc_hash(const char* str, size_t len = 0); // hash (currently FNV) of a filename typedef u32 FnHash; @@ -332,11 +332,11 @@ extern u64 movzx_64le(const u8* p, size_t size); extern i64 movsx_64le(const u8* p, size_t size); -extern bool is_pow2(long n); +extern bool is_pow2(uint n); // return -1 if not an integral power of 2, // otherwise the base2 logarithm -extern int ilog2(const int n); +extern int ilog2(uint n); // return log base 2, rounded up. extern uint log2(uint x); diff --git a/source/lib/sysdep/win/wposix.cpp b/source/lib/sysdep/win/wposix.cpp index d34a1e2b27..853953c0d1 100755 --- a/source/lib/sysdep/win/wposix.cpp +++ b/source/lib/sysdep/win/wposix.cpp @@ -535,9 +535,9 @@ int poll(struct pollfd /* fds */[], int /* nfds */, int /* timeout */) // used by mprotect. static DWORD win32_prot(int prot) { - // this covers all possible combinations of read|write|exec + // this covers all 8 combinations of read|write|exec // (note that "none" means all flags are 0). - switch(prot) + switch(prot & (PROT_READ|PROT_WRITE|PROT_EXEC)) { case PROT_NONE: return PAGE_NOACCESS; @@ -558,7 +558,7 @@ static DWORD win32_prot(int prot) case PROT_READ|PROT_WRITE|PROT_EXEC: return PAGE_EXECUTE_READWRITE; default: - return 0; + UNREACHABLE; } } @@ -687,7 +687,7 @@ void* mmap(void* user_start, size_t len, int prot, int flags, int fd, off_t ofs) } fail: - return MAP_FAILED; + return (void*)MAP_FAILED; }