247 lines
6.0 KiB
C++
247 lines
6.0 KiB
C++
/*
|
|
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
* Neither the name of LibCat nor the names of its contributors may be used
|
|
to endorse or promote products derived from this software without
|
|
specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef CAT_BITMATH_HPP
|
|
#define CAT_BITMATH_HPP
|
|
|
|
#include <cat/Platform.hpp>
|
|
|
|
#if defined(CAT_OS_WINDOWS)
|
|
# include <cat/port/WindowsInclude.hpp>
|
|
#endif
|
|
|
|
namespace cat {
|
|
|
|
|
|
// Next highest power of two (e.g. 13 -> 16)
|
|
CAT_INLINE u32 NextHighestPow2(u32 n)
|
|
{
|
|
n |= n >> 1;
|
|
n |= n >> 2;
|
|
n |= n >> 4;
|
|
n |= n >> 8;
|
|
n |= n >> 16;
|
|
return n + 1;
|
|
}
|
|
CAT_INLINE u64 NextHighestPow2(u64 n)
|
|
{
|
|
n |= n >> 1;
|
|
n |= n >> 2;
|
|
n |= n >> 4;
|
|
n |= n >> 8;
|
|
n |= n >> 16;
|
|
n |= n >> 32;
|
|
return n + 1;
|
|
}
|
|
|
|
// Bit Scan Forward (BSF)
|
|
// Scans from bit 0 to MSB
|
|
// Undefined when input is zero
|
|
CAT_INLINE u32 BSF32(u32 x);
|
|
CAT_INLINE u32 BSF64(u64 x);
|
|
|
|
// Bit Scan Reverse (BSR)
|
|
// Scans from MSB to bit 0
|
|
// Undefined when input is zero
|
|
CAT_INLINE u32 BSR32(u32 x);
|
|
CAT_INLINE u32 BSR64(u64 x);
|
|
|
|
// Returns the count of bits set in the input for types up to 128 bits
|
|
template<typename T> CAT_INLINE T BitCount(T v)
|
|
{
|
|
// From Stanford Bit Twiddling Hacks collection
|
|
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
|
v = v - ((v >> 1) & (T)~(T)0/3);
|
|
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);
|
|
v = (v + (v >> 4)) & (T)~(T)0/255*15;
|
|
return (T)(v * ((T)~(T)0/255)) >> ((sizeof(v) - 1) * 8);
|
|
}
|
|
|
|
// Reconstruct a 32-bit or 64-bit counter that increments by one each time,
|
|
// given a truncated sample of its low bits, and the last accepted value of the counter.
|
|
template<int BITS, typename T> CAT_INLINE T ReconstructCounter(T last_accepted_count, u32 partial_low_bits)
|
|
{
|
|
const u32 IV_MSB = (1 << BITS); // BITS < 32
|
|
const u32 IV_MASK = (IV_MSB - 1);
|
|
|
|
s32 diff = partial_low_bits - (u32)(last_accepted_count & IV_MASK);
|
|
return ((last_accepted_count & ~(T)IV_MASK) | partial_low_bits)
|
|
- (((IV_MSB >> 1) - (diff & IV_MASK)) & IV_MSB)
|
|
+ (diff & IV_MSB);
|
|
}
|
|
|
|
|
|
u32 BSF32(u32 x)
|
|
{
|
|
#if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64) && !defined(CAT_DEBUG)
|
|
|
|
u32 index;
|
|
_BitScanForward((unsigned long*)&index, x);
|
|
return index;
|
|
|
|
#elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
|
|
|
|
CAT_ASM_BEGIN
|
|
BSF eax, [x]
|
|
CAT_ASM_END
|
|
|
|
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
|
|
|
u32 retval;
|
|
|
|
CAT_ASM_BEGIN
|
|
"BSFl %1, %%eax"
|
|
: "=a" (retval)
|
|
: "r" (x)
|
|
: "cc"
|
|
CAT_ASM_END
|
|
|
|
return retval;
|
|
|
|
#else
|
|
|
|
return BSR32(x ^ (x - 1));
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
u32 BSR32(u32 x)
|
|
{
|
|
#if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64) && !defined(CAT_DEBUG)
|
|
|
|
u32 index;
|
|
_BitScanReverse((unsigned long*)&index, x);
|
|
return index;
|
|
|
|
#elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
|
|
|
|
CAT_ASM_BEGIN
|
|
BSR eax, [x]
|
|
CAT_ASM_END
|
|
|
|
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
|
|
|
u32 retval;
|
|
|
|
CAT_ASM_BEGIN
|
|
"BSRl %1, %%eax"
|
|
: "=a" (retval)
|
|
: "r" (x)
|
|
: "cc"
|
|
CAT_ASM_END
|
|
|
|
return retval;
|
|
|
|
#else
|
|
|
|
// Adapted from the Stanford Bit Twiddling Hacks collection
|
|
register u32 shift, r;
|
|
|
|
r = (x > 0xFFFF) << 4; x >>= r;
|
|
shift = (x > 0xFF) << 3; x >>= shift; r |= shift;
|
|
shift = (x > 0xF) << 2; x >>= shift; r |= shift;
|
|
shift = (x > 0x3) << 1; x >>= shift; r |= shift;
|
|
r |= (x >> 1);
|
|
return r;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
u32 BSF64(u64 x)
|
|
{
|
|
#if defined(CAT_COMPILER_MSVC) && !defined(CAT_DEBUG) && defined(CAT_WORD_64)
|
|
|
|
u32 index;
|
|
_BitScanForward64((unsigned long*)&index, x);
|
|
return index;
|
|
|
|
#elif defined(CAT_ASM_ATT) && defined(CAT_WORD_64) && defined(CAT_ISA_X86)
|
|
|
|
u32 retval;
|
|
|
|
CAT_ASM_BEGIN
|
|
"BSFq %1, %%rax"
|
|
: "=a" (retval)
|
|
: "r" (x)
|
|
: "cc"
|
|
CAT_ASM_END
|
|
|
|
return retval;
|
|
|
|
#else
|
|
|
|
return BSR64(x ^ (x - 1));
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
u32 BSR64(u64 x)
|
|
{
|
|
#if defined(CAT_COMPILER_MSVC) && !defined(CAT_DEBUG) && defined(CAT_WORD_64)
|
|
|
|
u32 index;
|
|
_BitScanReverse64((unsigned long*)&index, x);
|
|
return index;
|
|
|
|
#elif defined(CAT_ASM_ATT) && defined(CAT_WORD_64) && defined(CAT_ISA_X86)
|
|
|
|
u32 retval;
|
|
|
|
CAT_ASM_BEGIN
|
|
"BSRq %1, %%rax"
|
|
: "=a" (retval)
|
|
: "r" (x)
|
|
: "cc"
|
|
CAT_ASM_END
|
|
|
|
return retval;
|
|
|
|
#else
|
|
|
|
// Adapted from the Stanford Bit Twiddling Hacks collection
|
|
register u32 shift, r;
|
|
|
|
r = (x > 0xFFFFFFFF) << 5; x >>= r;
|
|
shift = (x > 0xFFFF) << 4; x >>= shift; r |= shift;
|
|
shift = (x > 0xFF) << 3; x >>= shift; r |= shift;
|
|
shift = (x > 0xF) << 2; x >>= shift; r |= shift;
|
|
shift = (x > 0x3) << 1; x >>= shift; r |= shift;
|
|
r |= (u32)(x >> 1);
|
|
return r;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
} // namespace cat
|
|
|
|
#endif // CAT_BITMATH_HPP
|