replace most BIT macros with a Bit() template for better 64-bit safety

test_bits: add tests for all routines in bits.h
hpet: add safety check
unit.h, bits.h, DOMEvent.h: change T(~0) to ~T(0) (required when T is
64-bit)

This was SVN commit r6335.
This commit is contained in:
janwas 2008-09-06 21:15:53 +00:00
parent c15cbe12d4
commit 2624069993
12 changed files with 146 additions and 58 deletions

View File

@ -12,7 +12,7 @@ class CEntity;
class CSkeletonAnim;
class CUnitAnimation;
// note: we can't declare as static const size_t invalidId = size_t(~0) in
// note: we can't declare as static const size_t invalidId = ~size_t(0) in
// the class because it seems to be a grey area in the C++ standard whether
// or not the constant is propagated or needs an external definition.
// an enum causes conversion warnings in MSC, so we go with a file-scope

View File

@ -106,7 +106,7 @@ InReaction CGUI::HandleEvent(const SDL_Event_* ev)
case SDL_BUTTON_LEFT:
case SDL_BUTTON_RIGHT:
case SDL_BUTTON_MIDDLE:
m_MouseButtons |= BIT(ev->ev.button.button);
m_MouseButtons |= Bit<unsigned int>(ev->ev.button.button);
break;
default:
break;
@ -280,7 +280,7 @@ InReaction CGUI::HandleEvent(const SDL_Event_* ev)
case SDL_BUTTON_LEFT:
case SDL_BUTTON_RIGHT:
case SDL_BUTTON_MIDDLE:
m_MouseButtons &= ~BIT(ev->ev.button.button);
m_MouseButtons &= ~Bit<unsigned int>(ev->ev.button.button);
break;
default:
break;

View File

@ -273,7 +273,7 @@ public:
const size_t sizeClass = SizeClass(freedBlock->Size());
m_rangeLists[sizeClass].Insert<AddressOrder>(freedBlock);
m_bitmap |= BIT(sizeClass);
m_bitmap |= Bit<u32>(sizeClass);
}
/**
@ -298,7 +298,7 @@ public:
// apparently all classes above minSizeClass are empty,
// or the above would have succeeded.
debug_assert(m_bitmap < BIT(minSizeClass+1));
debug_assert(m_bitmap < Bit<u32>(minSizeClass+1));
return 0;
}
@ -309,7 +309,7 @@ public:
// (masking with !IsEmpty() << sizeClass would probably be faster)
if(m_rangeLists[sizeClass].IsEmpty())
m_bitmap &= ~BIT(sizeClass);
m_bitmap &= ~Bit<u32>(sizeClass);
}
void Validate(u32 id) const
@ -319,7 +319,7 @@ public:
m_rangeLists[i].Validate(id);
// both bitmap and list must agree on whether they are empty
debug_assert(((m_bitmap & BIT(i)) == 0) == m_rangeLists[i].IsEmpty());
debug_assert(((m_bitmap & Bit<u32>(i)) == 0) == m_rangeLists[i].IsEmpty());
}
}

View File

@ -12,23 +12,33 @@
#define INCLUDED_BITS
/**
* value of bit number <n> as unsigned long.
* value of bit number <n>.
*
* @param n bit index (0..CHAR_BIT*sizeof(int)-1)
* @param n bit index.
*
* requirements:
* - T should be an unsigned type
* - n must be in [0, CHAR_BIT*sizeof(T)), else the result is undefined!
**/
#define BIT(n) (1ul << (n))
template<typename T>
T Bit(size_t n)
{
const T one = T(1);
return (one << n);
}
/**
* value of bit number <n> as unsigned long long.
*
* @param n bit index (0..CHAR_BIT*sizeof(int)-1)
* pretty much the same as Bit<unsigned>.
* this is intended for the initialization of enum values, where a
* compile-time constant is required.
**/
#define BIT64(n) (1ull << (n))
#define BIT(n) (1u << (n))
template<typename T>
bool IsBitSet(T value, size_t index)
{
const T bit = T(1) << index;
const T bit = Bit<T>(index);
return (value & bit) != 0;
}
@ -51,7 +61,7 @@ T bit_mask(size_t numBits)
// note: the perhaps more intuitive (1 << numBits)-1 cannot
// handle numBits == bitsInT, but this implementation does.
const T bitsInT = sizeof(T)*CHAR_BIT;
T mask = T(~0);
T mask = ~T(0);
mask >>= T(bitsInT-numBits);
return mask;
}

View File

@ -191,7 +191,7 @@ static inline i64 SignExtend(u64 bits, size_t size_bytes)
// no point in sign-extending if >= 8 bytes were requested
if(size_bytes < 8)
{
const u64 sign_bit = BIT64((size_bytes*8)-1);
const u64 sign_bit = Bit<u64>((size_bytes*8)-1);
// number would be negative in the smaller type,
// so sign-extend, i.e. set all more significant bits.

View File

@ -361,7 +361,7 @@ struct ListPos
static inline bool is_marked_as_deleted(Node* p)
{
const uintptr_t u = (uintptr_t)p;
return (u & BIT(0)) != 0;
return (u & Bit<uintptr_t>(0)) != 0;
}
static inline Node* with_mark(Node* p)

View File

@ -114,7 +114,7 @@ bool x86_x64_cap(x86_x64_Cap cap)
DEBUG_WARN_ERR(ERR::INVALID_PARAM);
return false;
}
return (x86_x64_caps[tbl_idx] & BIT(bit_idx)) != 0;
return (x86_x64_caps[tbl_idx] & Bit<u32>(bit_idx)) != 0;
}

View File

@ -44,9 +44,9 @@ struct CounterHPET::HpetRegisters
#pragma pack(pop)
static const u64 CAP_SIZE64 = BIT64(13);
static const u64 CAP_SIZE64 = Bit<u64>(13);
static const u64 CONFIG_ENABLE = BIT64(0);
static const u64 CONFIG_ENABLE = Bit<u64>(0);
//-----------------------------------------------------------------------------
@ -78,7 +78,10 @@ LibError CounterHPET::Activate()
void CounterHPET::Shutdown()
{
if(m_hpetRegisters)
{
mahaf_UnmapPhysicalMemory((void*)m_hpetRegisters);
m_hpetRegisters = 0;
}
acpi_Shutdown();
mahaf_Shutdown();
@ -119,6 +122,7 @@ double CounterHPET::NominalFrequency() const
{
const u64 caps = m_hpetRegisters->capabilities;
const u32 timerPeriod_fs = (u32)bits(caps, 32, 63);
debug_assert(timerPeriod_fs != 0); // guaranteed by HPET spec
const double frequency = 1e15 / timerPeriod_fs;
return frequency;
}

View File

@ -27,7 +27,7 @@ struct FADT
};
#pragma pack(pop)
static const u32 TMR_VAL_EXT = BIT(8);
static const u32 TMR_VAL_EXT = Bit<u32>(8);
//-----------------------------------------------------------------------------

View File

@ -243,8 +243,8 @@ static unsigned __stdcall UpdateThread(void* UNUSED(data))
static inline LibError InitUpdateThread()
{
// make sure our interval isn't too long
// (counterBits can be 64 => BIT64 would overflow => calculate period/2)
const double period_2 = BIT64(counterBits-1) / nominalFrequency;
// (counterBits can be 64 => Bit() would overflow => calculate period/2)
const double period_2 = Bit<u64>(counterBits-1) / nominalFrequency;
const size_t rolloversPerInterval = UPDATE_INTERVAL_MS / cpu_i64FromDouble(period_2*2.0*1000.0);
debug_assert(rolloversPerInterval <= 1);

View File

@ -2,63 +2,137 @@
#include "lib/bits.h"
#define EQUALS(actual, expected) debug_assert((actual) == (expected))
class TestBits : public CxxTest::TestSuite
{
public:
void test_Bit()
{
EQUALS(Bit<unsigned>(0), 1);
EQUALS(Bit<unsigned>(8), 0x100);
EQUALS(Bit<u32>(31), u32(0x80000000ul));
EQUALS(Bit<u64>(1), u64(2));
EQUALS(Bit<u64>(32), u64(0x100000000ull));
EQUALS(Bit<u64>(63), u64(0x8000000000000000ull));
}
void test_IsBitSet()
{
EQUALS(IsBitSet(0u, 1), false);
EQUALS(IsBitSet(1u, 1), false);
EQUALS(IsBitSet(2u, 1), true);
EQUALS(IsBitSet<u32>(0xFFFFFFFFul, 0), true);
EQUALS(IsBitSet<u32>(0xFFFFFFFFul, 31), true);
EQUALS(IsBitSet<u64>(0xFFFFFFFFFFFFFFFFull, 0), true);
EQUALS(IsBitSet<u64>(0xFFFFFFFFFFFFFFFFull, 31), true);
EQUALS(IsBitSet<u64>(0xFFFFFFFFFFFFFFFFull, 32), true);
EQUALS(IsBitSet<u64>(0xFFFFFFFFFFFFFFFFull, 63), true);
}
void test_bit_mask()
{
EQUALS(bit_mask<u16>(0), 0);
EQUALS(bit_mask<u16>(2), 0x3);
EQUALS(bit_mask<u16>(16), 0xFFFF);
EQUALS(bit_mask<u32>(0), 0);
EQUALS(bit_mask<u32>(2), 0x3);
EQUALS(bit_mask<u32>(32), 0xFFFFFFFFul);
EQUALS(bit_mask<u64>(0), 0);
EQUALS(bit_mask<u64>(2), 0x3);
EQUALS(bit_mask<u64>(32), 0xFFFFFFFFull);
EQUALS(bit_mask<u64>(64), 0xFFFFFFFFFFFFFFFFull);
}
void test_bits()
{
EQUALS(bits<u16>(0xFFFF, 0, 15), 0xFFFF);
EQUALS(bits<u16>(0xFFFF, 0, 7), 0xFF);
EQUALS(bits<u16>(0xFFFF, 8, 15), 0xFF);
EQUALS(bits<u16>(0xFFFF, 14, 15), 0x3);
EQUALS(bits<u16>(0xAA55, 4, 11), 0xA5);
EQUALS(bits<u16>(0xAA55, 14, 15), 0x2);
EQUALS(bits<u32>(0ul, 0, 31), 0ul);
EQUALS(bits<u32>(0xFFFFFFFFul, 0, 31), 0xFFFFFFFFul);
EQUALS(bits<u64>(0ull, 0, 63), 0ull);
EQUALS(bits<u64>(0xFFFFFFFFull, 0, 31), 0xFFFFFFFFull);
EQUALS(bits<u64>(0x0000FFFFFFFF0000ull, 16, 47), 0xFFFFFFFFull);
EQUALS(bits<u64>(0xFFFFFFFFFFFFFFFFull, 0, 63), 0xFFFFFFFFFFFFFFFFull);
EQUALS(bits<u64>(0xA5A5A5A5A5A5A5A5ull, 32, 63), 0xA5A5A5A5ull);
}
void test_PopulationCount()
{
EQUALS(PopulationCount<u8>(0), 0);
EQUALS(PopulationCount<u8>(4), 1);
EQUALS(PopulationCount<u8>(0x28), 2);
EQUALS(PopulationCount<u8>(0xFF), 8);
EQUALS(PopulationCount<u32>(0x0ul), 0);
EQUALS(PopulationCount<u32>(0x8ul), 1);
EQUALS(PopulationCount<u32>(0xFFFFul), 16);
EQUALS(PopulationCount<u32>(0xFFFFFFFFul), 32);
EQUALS(PopulationCount<u64>(0x0ull), 0);
EQUALS(PopulationCount<u64>(0x10ull), 1);
EQUALS(PopulationCount<u64>(0xFFFFull), 16);
EQUALS(PopulationCount<u64>(0xFFFFFFFFull), 32);
EQUALS(PopulationCount<u64>(0xFFFFFFFFFFFFFFFEull), 63);
EQUALS(PopulationCount<u64>(0xFFFFFFFFFFFFFFFFull), 64);
}
void test_is_pow2()
{
TS_ASSERT_EQUALS(is_pow2(0u), false);
TS_ASSERT_EQUALS(is_pow2(~0u), false);
TS_ASSERT_EQUALS(is_pow2(0x80000001), false);
TS_ASSERT_EQUALS(is_pow2(1), true);
TS_ASSERT_EQUALS(is_pow2(1u << 31), true);
EQUALS(is_pow2(0u), false);
EQUALS(is_pow2(~0u), false);
EQUALS(is_pow2(0x80000001), false);
EQUALS(is_pow2(1), true);
EQUALS(is_pow2(1u << 31), true);
}
void test_ceil_log2()
{
TS_ASSERT_EQUALS(ceil_log2(3u), 2u);
TS_ASSERT_EQUALS(ceil_log2(0xffffffffu), 32u);
TS_ASSERT_EQUALS(ceil_log2(1u), 0u);
TS_ASSERT_EQUALS(ceil_log2(256u), 8u);
TS_ASSERT_EQUALS(ceil_log2(0x80000000u), 31u);
EQUALS(ceil_log2(3u), 2u);
EQUALS(ceil_log2(0xffffffffu), 32u);
EQUALS(ceil_log2(1u), 0u);
EQUALS(ceil_log2(256u), 8u);
EQUALS(ceil_log2(0x80000000u), 31u);
}
void test_floor_log2()
{
TS_ASSERT_EQUALS(floor_log2(1.f), 0);
TS_ASSERT_EQUALS(floor_log2(3.f), 1);
TS_ASSERT_EQUALS(floor_log2(256.f), 8);
EQUALS(floor_log2(1.f), 0);
EQUALS(floor_log2(3.f), 1);
EQUALS(floor_log2(256.f), 8);
}
void test_round_up_to_pow2()
{
TS_ASSERT_EQUALS(round_up_to_pow2(0u), 1u);
TS_ASSERT_EQUALS(round_up_to_pow2(1u), 1u);
TS_ASSERT_EQUALS(round_up_to_pow2(127u), 128u);
TS_ASSERT_EQUALS(round_up_to_pow2(128u), 128u);
TS_ASSERT_EQUALS(round_up_to_pow2(129u), 256u);
EQUALS(round_up_to_pow2(0u), 1u);
EQUALS(round_up_to_pow2(1u), 1u);
EQUALS(round_up_to_pow2(127u), 128u);
EQUALS(round_up_to_pow2(128u), 128u);
EQUALS(round_up_to_pow2(129u), 256u);
}
void test_round_up()
{
TS_ASSERT_EQUALS(round_up( 0u, 16u), 0u);
TS_ASSERT_EQUALS(round_up( 4u, 16u), 16u);
TS_ASSERT_EQUALS(round_up(15u, 16u), 16u);
TS_ASSERT_EQUALS(round_up(20u, 32u), 32u);
TS_ASSERT_EQUALS(round_up(29u, 32u), 32u);
TS_ASSERT_EQUALS(round_up(0x1000u, 0x1000u), 0x1000u);
TS_ASSERT_EQUALS(round_up(0x1001u, 0x1000u), 0x2000u);
TS_ASSERT_EQUALS(round_up(0x1900u, 0x1000u), 0x2000u);
EQUALS(round_up( 0u, 16u), 0u);
EQUALS(round_up( 4u, 16u), 16u);
EQUALS(round_up(15u, 16u), 16u);
EQUALS(round_up(20u, 32u), 32u);
EQUALS(round_up(29u, 32u), 32u);
EQUALS(round_up(0x1000u, 0x1000u), 0x1000u);
EQUALS(round_up(0x1001u, 0x1000u), 0x2000u);
EQUALS(round_up(0x1900u, 0x1000u), 0x2000u);
}
void test_round_down()
{
TS_ASSERT_EQUALS(round_down( 0u, 16u), 0u);
TS_ASSERT_EQUALS(round_down( 4u, 16u), 0u);
TS_ASSERT_EQUALS(round_down(15u, 16u), 0u);
TS_ASSERT_EQUALS(round_down(20u, 16u), 16u);
TS_ASSERT_EQUALS(round_down(29u, 16u), 16u);
TS_ASSERT_EQUALS(round_down(0x1900u, 0x1000u), 0x1000u);
TS_ASSERT_EQUALS(round_down(0x2001u, 0x2000u), 0x2000u);
EQUALS(round_down( 0u, 16u), 0u);
EQUALS(round_down( 4u, 16u), 0u);
EQUALS(round_down(15u, 16u), 0u);
EQUALS(round_down(20u, 16u), 16u);
EQUALS(round_down(29u, 16u), 16u);
EQUALS(round_down(0x1900u, 0x1000u), 0x1000u);
EQUALS(round_down(0x2001u, 0x2000u), 0x2000u);
}
};

View File

@ -126,7 +126,7 @@ public:
void StopPropagation( JSContext* cx, uintN argc, jsval* argv );
public:
CScriptEvent( const CStrW& Type, size_t TypeCode = ~0, bool Cancelable = true, bool Blockable = true );
CScriptEvent( const CStrW& Type, size_t TypeCode = ~size_t(0), bool Cancelable = true, bool Blockable = true );
static void ScriptingInit();
};