mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
@ -7,164 +7,159 @@
|
||||
#include "Common/BitField.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
union TestUnion
|
||||
{
|
||||
u64 hex;
|
||||
union TestUnion {
|
||||
u64 hex;
|
||||
|
||||
BitField< 0,64,u64> full_u64; // spans whole storage
|
||||
BitField< 0,64,s64> full_s64; // spans whole storage
|
||||
BitField<0, 64, u64> full_u64; // spans whole storage
|
||||
BitField<0, 64, s64> full_s64; // spans whole storage
|
||||
|
||||
BitField< 9, 3,u64> regular_field_unsigned; // a plain bitfield
|
||||
BitField< 9, 3,u64> regular_field_unsigned2; // Just the very same bitfield again
|
||||
BitField< 9, 3,s64> regular_field_signed; // Same bitfield, but different sign
|
||||
BitField<9, 3, u64> regular_field_unsigned; // a plain bitfield
|
||||
BitField<9, 3, u64> regular_field_unsigned2; // Just the very same bitfield again
|
||||
BitField<9, 3, s64> regular_field_signed; // Same bitfield, but different sign
|
||||
|
||||
BitField<30, 4,s64> at_dword_boundary; // goes over the boundary of two u32 values
|
||||
BitField<30, 4, s64> at_dword_boundary; // goes over the boundary of two u32 values
|
||||
|
||||
BitField<15, 1,s64> signed_1bit; // allowed values: -1 and 0
|
||||
BitField<15, 1, s64> signed_1bit; // allowed values: -1 and 0
|
||||
};
|
||||
|
||||
// table of raw numbers to test with
|
||||
static u64 table[] =
|
||||
{
|
||||
0x0000000000000000ull, // all zero
|
||||
0xffffffffffffffffull, // all one
|
||||
0x7fffffffffffffffull, // all one apart from the sign bit
|
||||
0x8000000000000000ull, // all zero apart from the sign bit
|
||||
0x8000000000000048ull, // regular_field = 0b1001
|
||||
static u64 table[] = {
|
||||
0x0000000000000000ull, // all zero
|
||||
0xffffffffffffffffull, // all one
|
||||
0x7fffffffffffffffull, // all one apart from the sign bit
|
||||
0x8000000000000000ull, // all zero apart from the sign bit
|
||||
0x8000000000000048ull, // regular_field = 0b1001
|
||||
|
||||
// "random" numbers
|
||||
0x0F7B8B1ABD9B8D3Full,
|
||||
0xA8B86F73FDAADD2Dull,
|
||||
0x1B17A557BFEB351Dull,
|
||||
0xE3354268B0C2395Bull,
|
||||
// "random" numbers
|
||||
0x0F7B8B1ABD9B8D3Full, 0xA8B86F73FDAADD2Dull, 0x1B17A557BFEB351Dull, 0xE3354268B0C2395Bull,
|
||||
};
|
||||
|
||||
// Verify that bitfields in a union have the same underlying data
|
||||
TEST(BitField, Storage)
|
||||
{
|
||||
TestUnion object;
|
||||
TestUnion object;
|
||||
|
||||
EXPECT_EQ((void*)&object.hex, (void*)&object.regular_field_unsigned);
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_u64));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_s64));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_unsigned));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit));
|
||||
EXPECT_EQ((void*)&object.hex, (void*)&object.regular_field_unsigned);
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_u64));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_s64));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_unsigned));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary));
|
||||
EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit));
|
||||
|
||||
// Now write some values to one field and check if this reflects properly
|
||||
// in the others.
|
||||
for (u64 val : table)
|
||||
{
|
||||
object.hex = val;
|
||||
EXPECT_EQ(object.hex, object.full_u64);
|
||||
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
|
||||
// Now write some values to one field and check if this reflects properly
|
||||
// in the others.
|
||||
for (u64 val : table)
|
||||
{
|
||||
object.hex = val;
|
||||
EXPECT_EQ(object.hex, object.full_u64);
|
||||
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
|
||||
|
||||
object.regular_field_unsigned = val & 0x3;
|
||||
EXPECT_EQ(object.hex, object.full_u64);
|
||||
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
|
||||
}
|
||||
object.regular_field_unsigned = val & 0x3;
|
||||
EXPECT_EQ(object.hex, object.full_u64);
|
||||
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BitField, Read)
|
||||
{
|
||||
TestUnion object;
|
||||
TestUnion object;
|
||||
|
||||
for (u64 val : table)
|
||||
{
|
||||
object.hex = val;
|
||||
for (u64 val : table)
|
||||
{
|
||||
object.hex = val;
|
||||
|
||||
// Make sure reading/casting does not behave completely idiotic
|
||||
EXPECT_EQ(object.full_u64, (u64)object.full_u64);
|
||||
EXPECT_EQ(object.full_s64, (s64)object.full_s64);
|
||||
EXPECT_EQ(object.regular_field_unsigned, (u64)object.regular_field_unsigned);
|
||||
EXPECT_EQ(object.regular_field_unsigned2, (u64)object.regular_field_unsigned2);
|
||||
EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed);
|
||||
EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary);
|
||||
EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit);
|
||||
// Make sure reading/casting does not behave completely idiotic
|
||||
EXPECT_EQ(object.full_u64, (u64)object.full_u64);
|
||||
EXPECT_EQ(object.full_s64, (s64)object.full_s64);
|
||||
EXPECT_EQ(object.regular_field_unsigned, (u64)object.regular_field_unsigned);
|
||||
EXPECT_EQ(object.regular_field_unsigned2, (u64)object.regular_field_unsigned2);
|
||||
EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed);
|
||||
EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary);
|
||||
EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit);
|
||||
|
||||
// Now make sure the value is indeed correct
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
EXPECT_EQ(*(s64*)&val, object.full_s64);
|
||||
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned);
|
||||
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned2);
|
||||
EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed);
|
||||
EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary);
|
||||
EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit);
|
||||
}
|
||||
// Now make sure the value is indeed correct
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
EXPECT_EQ(*(s64*)&val, object.full_s64);
|
||||
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned);
|
||||
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned2);
|
||||
EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed);
|
||||
EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary);
|
||||
EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BitField, Assignment)
|
||||
{
|
||||
TestUnion object;
|
||||
TestUnion object;
|
||||
|
||||
for (u64 val : table)
|
||||
{
|
||||
// Assignments with fixed values
|
||||
object.full_u64 = val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
for (u64 val : table)
|
||||
{
|
||||
// Assignments with fixed values
|
||||
object.full_u64 = val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
|
||||
object.full_s64 = (s64)val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
object.full_s64 = (s64)val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
|
||||
object.regular_field_unsigned = val;
|
||||
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
|
||||
object.regular_field_unsigned = val;
|
||||
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
|
||||
|
||||
object.at_dword_boundary = val;
|
||||
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
|
||||
object.at_dword_boundary = val;
|
||||
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
|
||||
|
||||
object.signed_1bit = val;
|
||||
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
|
||||
object.signed_1bit = val;
|
||||
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
|
||||
|
||||
object.regular_field_signed = val;
|
||||
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
|
||||
object.regular_field_signed = val;
|
||||
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
|
||||
|
||||
// Assignment from other BitField
|
||||
object.at_dword_boundary = object.regular_field_signed;
|
||||
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
|
||||
}
|
||||
// Assignment from other BitField
|
||||
object.at_dword_boundary = object.regular_field_signed;
|
||||
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
// Test class behavior on oddly aligned structures.
|
||||
TEST(BitField, Alignment)
|
||||
{
|
||||
#pragma pack(1)
|
||||
struct OddlyAlignedTestStruct
|
||||
{
|
||||
u8 padding;
|
||||
TestUnion obj;
|
||||
};
|
||||
#pragma pack()
|
||||
#pragma pack(1)
|
||||
struct OddlyAlignedTestStruct
|
||||
{
|
||||
u8 padding;
|
||||
TestUnion obj;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
alignas(16) OddlyAlignedTestStruct test_struct;
|
||||
TestUnion& object = test_struct.obj;
|
||||
static_assert(alignof(decltype(test_struct.obj.signed_1bit)) == 1,
|
||||
"Incorrect variable alignment");
|
||||
alignas(16) OddlyAlignedTestStruct test_struct;
|
||||
TestUnion& object = test_struct.obj;
|
||||
static_assert(alignof(decltype(test_struct.obj.signed_1bit)) == 1,
|
||||
"Incorrect variable alignment");
|
||||
|
||||
for (u64 val : table)
|
||||
{
|
||||
// Assignments with fixed values
|
||||
object.full_u64 = val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
for (u64 val : table)
|
||||
{
|
||||
// Assignments with fixed values
|
||||
object.full_u64 = val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
|
||||
object.full_s64 = (s64)val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
object.full_s64 = (s64)val;
|
||||
EXPECT_EQ(val, object.full_u64);
|
||||
|
||||
object.regular_field_unsigned = val;
|
||||
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
|
||||
object.regular_field_unsigned = val;
|
||||
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
|
||||
|
||||
object.at_dword_boundary = val;
|
||||
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
|
||||
object.at_dword_boundary = val;
|
||||
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
|
||||
|
||||
object.signed_1bit = val;
|
||||
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
|
||||
object.signed_1bit = val;
|
||||
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
|
||||
|
||||
object.regular_field_signed = val;
|
||||
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
|
||||
object.regular_field_signed = val;
|
||||
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
|
||||
|
||||
// Assignment from other BitField
|
||||
object.at_dword_boundary = object.regular_field_signed;
|
||||
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
|
||||
}
|
||||
// Assignment from other BitField
|
||||
object.at_dword_boundary = object.regular_field_signed;
|
||||
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
|
||||
}
|
||||
}
|
||||
|
@ -8,77 +8,75 @@
|
||||
|
||||
TEST(BitSet, Basics)
|
||||
{
|
||||
BitSet32 bs;
|
||||
BitSet64 bs2(1);
|
||||
BitSet64 bs3(2);
|
||||
EXPECT_EQ(true, !!bs2);
|
||||
EXPECT_EQ(false, !!bs);
|
||||
EXPECT_EQ(bs2, bs2);
|
||||
EXPECT_NE(bs2, bs3);
|
||||
EXPECT_EQ(BitSet32(0xfff), BitSet32::AllTrue(12));
|
||||
EXPECT_EQ(BitSet64(0xffffffffffffffff), BitSet64::AllTrue(64));
|
||||
BitSet32 bs;
|
||||
BitSet64 bs2(1);
|
||||
BitSet64 bs3(2);
|
||||
EXPECT_EQ(true, !!bs2);
|
||||
EXPECT_EQ(false, !!bs);
|
||||
EXPECT_EQ(bs2, bs2);
|
||||
EXPECT_NE(bs2, bs3);
|
||||
EXPECT_EQ(BitSet32(0xfff), BitSet32::AllTrue(12));
|
||||
EXPECT_EQ(BitSet64(0xffffffffffffffff), BitSet64::AllTrue(64));
|
||||
}
|
||||
|
||||
TEST(BitSet, BitGetSet)
|
||||
{
|
||||
BitSet32 bs;
|
||||
bs[3] = bs[8] = bs[11] = true;
|
||||
EXPECT_EQ(true, bs[3]);
|
||||
EXPECT_EQ(false, bs[4]);
|
||||
EXPECT_EQ((u32)((1 << 3) | (1 << 8) | (1 << 11)), bs.m_val);
|
||||
BitSet32 bs;
|
||||
bs[3] = bs[8] = bs[11] = true;
|
||||
EXPECT_EQ(true, bs[3]);
|
||||
EXPECT_EQ(false, bs[4]);
|
||||
EXPECT_EQ((u32)((1 << 3) | (1 << 8) | (1 << 11)), bs.m_val);
|
||||
}
|
||||
|
||||
TEST(BitSet, Count)
|
||||
{
|
||||
u32 random_numbers[] = {
|
||||
0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3,
|
||||
0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074,
|
||||
0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694,
|
||||
0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136
|
||||
};
|
||||
u32 counts[] = {
|
||||
17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12
|
||||
};
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
{
|
||||
EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count());
|
||||
}
|
||||
u32 random_numbers[] = {0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3,
|
||||
0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074,
|
||||
0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694,
|
||||
0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136};
|
||||
u32 counts[] = {17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12};
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
{
|
||||
EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count());
|
||||
}
|
||||
|
||||
u64 random_numbers_64[] = {
|
||||
0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL,
|
||||
0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL,
|
||||
0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL
|
||||
};
|
||||
u32 counts_64[] = {
|
||||
39, 34, 31, 32, 33, 29, 27, 35, 43
|
||||
};
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
{
|
||||
EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count());
|
||||
}
|
||||
u64 random_numbers_64[] = {0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL,
|
||||
0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL,
|
||||
0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL};
|
||||
u32 counts_64[] = {39, 34, 31, 32, 33, 29, 27, 35, 43};
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
{
|
||||
EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BitSet, BitOps)
|
||||
{
|
||||
BitSet32 a(3), b(5), c;
|
||||
EXPECT_EQ(BitSet32(7), a | b);
|
||||
EXPECT_EQ(BitSet32(6), a ^ b);
|
||||
EXPECT_EQ(BitSet32(1), a & b);
|
||||
EXPECT_EQ(BitSet32(0xfffffffc), ~a);
|
||||
c = a; c |= b; EXPECT_EQ(BitSet32(7), c);
|
||||
c = a; c ^= b; EXPECT_EQ(BitSet32(6), c);
|
||||
c = a; c &= b; EXPECT_EQ(BitSet32(1), c);
|
||||
BitSet32 a(3), b(5), c;
|
||||
EXPECT_EQ(BitSet32(7), a | b);
|
||||
EXPECT_EQ(BitSet32(6), a ^ b);
|
||||
EXPECT_EQ(BitSet32(1), a & b);
|
||||
EXPECT_EQ(BitSet32(0xfffffffc), ~a);
|
||||
c = a;
|
||||
c |= b;
|
||||
EXPECT_EQ(BitSet32(7), c);
|
||||
c = a;
|
||||
c ^= b;
|
||||
EXPECT_EQ(BitSet32(6), c);
|
||||
c = a;
|
||||
c &= b;
|
||||
EXPECT_EQ(BitSet32(1), c);
|
||||
}
|
||||
|
||||
TEST(BitSet, InitializerListsAndIteration)
|
||||
{
|
||||
std::vector<int> bits { 1, 10, 15, 17, 20, 30 };
|
||||
BitSet32 bs { 1, 10, 15, 17, 20, 30 };
|
||||
auto vit = bits.begin();
|
||||
for (auto i : bs)
|
||||
{
|
||||
EXPECT_NE(vit, bits.end());
|
||||
EXPECT_EQ(i, *vit++);
|
||||
}
|
||||
EXPECT_EQ(vit, bits.end());
|
||||
std::vector<int> bits{1, 10, 15, 17, 20, 30};
|
||||
BitSet32 bs{1, 10, 15, 17, 20, 30};
|
||||
auto vit = bits.begin();
|
||||
for (auto i : bs)
|
||||
{
|
||||
EXPECT_NE(vit, bits.end());
|
||||
EXPECT_EQ(i, *vit++);
|
||||
}
|
||||
EXPECT_EQ(vit, bits.end());
|
||||
}
|
||||
|
@ -11,74 +11,70 @@
|
||||
|
||||
TEST(BlockingLoop, MultiThreaded)
|
||||
{
|
||||
Common::BlockingLoop loop;
|
||||
std::atomic<int> signaled_a(0);
|
||||
std::atomic<int> received_a(0);
|
||||
std::atomic<int> signaled_b(0);
|
||||
std::atomic<int> received_b(0);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Invalidate the current state.
|
||||
received_a.store(signaled_a.load() + 1);
|
||||
received_b.store(signaled_b.load() + 123);
|
||||
Common::BlockingLoop loop;
|
||||
std::atomic<int> signaled_a(0);
|
||||
std::atomic<int> received_a(0);
|
||||
std::atomic<int> signaled_b(0);
|
||||
std::atomic<int> received_b(0);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Invalidate the current state.
|
||||
received_a.store(signaled_a.load() + 1);
|
||||
received_b.store(signaled_b.load() + 123);
|
||||
|
||||
// Must not block as the loop is stopped.
|
||||
loop.Wait();
|
||||
// Must not block as the loop is stopped.
|
||||
loop.Wait();
|
||||
|
||||
std::thread loop_thread(
|
||||
[&]() {
|
||||
loop.Run(
|
||||
[&]() {
|
||||
received_a.store(signaled_a.load());
|
||||
received_b.store(signaled_b.load());
|
||||
});
|
||||
});
|
||||
std::thread loop_thread([&]() {
|
||||
loop.Run([&]() {
|
||||
received_a.store(signaled_a.load());
|
||||
received_b.store(signaled_b.load());
|
||||
});
|
||||
});
|
||||
|
||||
// Now Wait must block.
|
||||
loop.Prepare();
|
||||
// Now Wait must block.
|
||||
loop.Prepare();
|
||||
|
||||
// The payload must run at least once on startup.
|
||||
loop.Wait();
|
||||
EXPECT_EQ(signaled_a.load(), received_a.load());
|
||||
EXPECT_EQ(signaled_b.load(), received_b.load());
|
||||
// The payload must run at least once on startup.
|
||||
loop.Wait();
|
||||
EXPECT_EQ(signaled_a.load(), received_a.load());
|
||||
EXPECT_EQ(signaled_b.load(), received_b.load());
|
||||
|
||||
std::thread run_a_thread(
|
||||
[&]() {
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
for (int k = 0; k < 100; k++)
|
||||
{
|
||||
signaled_a++;
|
||||
loop.Wakeup();
|
||||
}
|
||||
std::thread run_a_thread([&]() {
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
for (int k = 0; k < 100; k++)
|
||||
{
|
||||
signaled_a++;
|
||||
loop.Wakeup();
|
||||
}
|
||||
|
||||
loop.Wait();
|
||||
EXPECT_EQ(signaled_a.load(), received_a.load());
|
||||
}
|
||||
});
|
||||
std::thread run_b_thread(
|
||||
[&]() {
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
for (int k = 0; k < 100; k++)
|
||||
{
|
||||
signaled_b++;
|
||||
loop.Wakeup();
|
||||
}
|
||||
loop.Wait();
|
||||
EXPECT_EQ(signaled_a.load(), received_a.load());
|
||||
}
|
||||
});
|
||||
std::thread run_b_thread([&]() {
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
for (int k = 0; k < 100; k++)
|
||||
{
|
||||
signaled_b++;
|
||||
loop.Wakeup();
|
||||
}
|
||||
|
||||
loop.Wait();
|
||||
EXPECT_EQ(signaled_b.load(), received_b.load());
|
||||
}
|
||||
});
|
||||
loop.Wait();
|
||||
EXPECT_EQ(signaled_b.load(), received_b.load());
|
||||
}
|
||||
});
|
||||
|
||||
run_a_thread.join();
|
||||
run_b_thread.join();
|
||||
run_a_thread.join();
|
||||
run_b_thread.join();
|
||||
|
||||
loop.Stop();
|
||||
loop.Stop();
|
||||
|
||||
// Must not block
|
||||
loop.Wait();
|
||||
// Must not block
|
||||
loop.Wait();
|
||||
|
||||
loop_thread.join();
|
||||
}
|
||||
loop_thread.join();
|
||||
}
|
||||
}
|
||||
|
@ -12,40 +12,34 @@
|
||||
|
||||
TEST(BusyLoopTest, MultiThreaded)
|
||||
{
|
||||
Common::BlockingLoop loop;
|
||||
Common::Event e;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
loop.Prepare();
|
||||
std::thread loop_thread(
|
||||
[&]() {
|
||||
loop.Run(
|
||||
[&]() {
|
||||
e.Set();
|
||||
});
|
||||
});
|
||||
Common::BlockingLoop loop;
|
||||
Common::Event e;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
loop.Prepare();
|
||||
std::thread loop_thread([&]() { loop.Run([&]() { e.Set(); }); });
|
||||
|
||||
// Ping - Pong
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
loop.Wakeup();
|
||||
e.Wait();
|
||||
// Ping - Pong
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
loop.Wakeup();
|
||||
e.Wait();
|
||||
|
||||
// Just waste some time. So the main loop did fall back to the sleep state much more likely.
|
||||
Common::SleepCurrentThread(1);
|
||||
}
|
||||
// Just waste some time. So the main loop did fall back to the sleep state much more likely.
|
||||
Common::SleepCurrentThread(1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
// We normally have to call Wakeup to assure the Event is triggered.
|
||||
// But this check is for an internal feature of the BlockingLoop.
|
||||
// It's implemented to fall back to a busy loop regulary.
|
||||
// If we're in the busy loop, the payload (and so the Event) is called all the time.
|
||||
//loop.Wakeup();
|
||||
e.Wait();
|
||||
}
|
||||
for (int j = 0; j < 100; j++)
|
||||
{
|
||||
// We normally have to call Wakeup to assure the Event is triggered.
|
||||
// But this check is for an internal feature of the BlockingLoop.
|
||||
// It's implemented to fall back to a busy loop regulary.
|
||||
// If we're in the busy loop, the payload (and so the Event) is called all the time.
|
||||
// loop.Wakeup();
|
||||
e.Wait();
|
||||
}
|
||||
|
||||
loop.Stop();
|
||||
loop_thread.join();
|
||||
}
|
||||
loop.Stop();
|
||||
loop_thread.join();
|
||||
}
|
||||
}
|
||||
|
@ -8,33 +8,33 @@
|
||||
|
||||
TEST(CommonFuncs, ArraySizeFunction)
|
||||
{
|
||||
char test[4];
|
||||
u32 test2[42];
|
||||
char test[4];
|
||||
u32 test2[42];
|
||||
|
||||
EXPECT_EQ(4u, ArraySize(test));
|
||||
EXPECT_EQ(42u, ArraySize(test2));
|
||||
EXPECT_EQ(4u, ArraySize(test));
|
||||
EXPECT_EQ(42u, ArraySize(test2));
|
||||
|
||||
(void)test;
|
||||
(void)test2;
|
||||
(void)test;
|
||||
(void)test2;
|
||||
}
|
||||
|
||||
TEST(CommonFuncs, RoundUpPow2Macro)
|
||||
{
|
||||
EXPECT_EQ(4, ROUND_UP_POW2(3));
|
||||
EXPECT_EQ(4, ROUND_UP_POW2(4));
|
||||
EXPECT_EQ(8, ROUND_UP_POW2(6));
|
||||
EXPECT_EQ(0x40000000, ROUND_UP_POW2(0x23456789));
|
||||
EXPECT_EQ(4, ROUND_UP_POW2(3));
|
||||
EXPECT_EQ(4, ROUND_UP_POW2(4));
|
||||
EXPECT_EQ(8, ROUND_UP_POW2(6));
|
||||
EXPECT_EQ(0x40000000, ROUND_UP_POW2(0x23456789));
|
||||
}
|
||||
|
||||
TEST(CommonFuncs, CrashMacro)
|
||||
{
|
||||
EXPECT_DEATH({ Crash(); }, "");
|
||||
EXPECT_DEATH({ Crash(); }, "");
|
||||
}
|
||||
|
||||
TEST(CommonFuncs, Swap)
|
||||
{
|
||||
EXPECT_EQ(0xf0, Common::swap8(0xf0));
|
||||
EXPECT_EQ(0x1234, Common::swap16(0x3412));
|
||||
EXPECT_EQ(0x12345678u, Common::swap32(0x78563412));
|
||||
EXPECT_EQ(0x123456789abcdef0ull, Common::swap64(0xf0debc9a78563412ull));
|
||||
EXPECT_EQ(0xf0, Common::swap8(0xf0));
|
||||
EXPECT_EQ(0x1234, Common::swap16(0x3412));
|
||||
EXPECT_EQ(0x12345678u, Common::swap32(0x78563412));
|
||||
EXPECT_EQ(0x123456789abcdef0ull, Common::swap64(0xf0debc9a78563412ull));
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <thread>
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/Event.h"
|
||||
|
||||
@ -11,32 +11,33 @@ using Common::Event;
|
||||
|
||||
TEST(Event, MultiThreaded)
|
||||
{
|
||||
Event has_sent, can_send;
|
||||
int shared_obj;
|
||||
const int ITERATIONS_COUNT = 100000;
|
||||
Event has_sent, can_send;
|
||||
int shared_obj;
|
||||
const int ITERATIONS_COUNT = 100000;
|
||||
|
||||
auto sender = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
can_send.Wait();
|
||||
shared_obj = i;
|
||||
has_sent.Set();
|
||||
}
|
||||
};
|
||||
auto sender = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
can_send.Wait();
|
||||
shared_obj = i;
|
||||
has_sent.Set();
|
||||
}
|
||||
};
|
||||
|
||||
auto receiver = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i) {
|
||||
has_sent.Wait();
|
||||
EXPECT_EQ(i, shared_obj);
|
||||
can_send.Set();
|
||||
}
|
||||
};
|
||||
auto receiver = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
has_sent.Wait();
|
||||
EXPECT_EQ(i, shared_obj);
|
||||
can_send.Set();
|
||||
}
|
||||
};
|
||||
|
||||
std::thread sender_thread(sender);
|
||||
std::thread receiver_thread(receiver);
|
||||
std::thread sender_thread(sender);
|
||||
std::thread receiver_thread(receiver);
|
||||
|
||||
can_send.Set();
|
||||
can_send.Set();
|
||||
|
||||
sender_thread.join();
|
||||
receiver_thread.join();
|
||||
sender_thread.join();
|
||||
receiver_thread.join();
|
||||
}
|
||||
|
@ -2,66 +2,70 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <thread>
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/FifoQueue.h"
|
||||
|
||||
TEST(FifoQueue, Simple)
|
||||
{
|
||||
Common::FifoQueue<u32> q;
|
||||
Common::FifoQueue<u32> q;
|
||||
|
||||
EXPECT_EQ(0u, q.Size());
|
||||
EXPECT_TRUE(q.Empty());
|
||||
EXPECT_EQ(0u, q.Size());
|
||||
EXPECT_TRUE(q.Empty());
|
||||
|
||||
q.Push(1);
|
||||
EXPECT_EQ(1u, q.Size());
|
||||
EXPECT_FALSE(q.Empty());
|
||||
q.Push(1);
|
||||
EXPECT_EQ(1u, q.Size());
|
||||
EXPECT_FALSE(q.Empty());
|
||||
|
||||
u32 v; q.Pop(v);
|
||||
EXPECT_EQ(1u, v);
|
||||
EXPECT_EQ(0u, q.Size());
|
||||
EXPECT_TRUE(q.Empty());
|
||||
u32 v;
|
||||
q.Pop(v);
|
||||
EXPECT_EQ(1u, v);
|
||||
EXPECT_EQ(0u, q.Size());
|
||||
EXPECT_TRUE(q.Empty());
|
||||
|
||||
// Test the FIFO order.
|
||||
for (u32 i = 0; i < 1000; ++i)
|
||||
q.Push(i);
|
||||
EXPECT_EQ(1000u, q.Size());
|
||||
for (u32 i = 0; i < 1000; ++i)
|
||||
{
|
||||
u32 v2; q.Pop(v2);
|
||||
EXPECT_EQ(i, v2);
|
||||
}
|
||||
EXPECT_TRUE(q.Empty());
|
||||
// Test the FIFO order.
|
||||
for (u32 i = 0; i < 1000; ++i)
|
||||
q.Push(i);
|
||||
EXPECT_EQ(1000u, q.Size());
|
||||
for (u32 i = 0; i < 1000; ++i)
|
||||
{
|
||||
u32 v2;
|
||||
q.Pop(v2);
|
||||
EXPECT_EQ(i, v2);
|
||||
}
|
||||
EXPECT_TRUE(q.Empty());
|
||||
|
||||
for (u32 i = 0; i < 1000; ++i)
|
||||
q.Push(i);
|
||||
EXPECT_FALSE(q.Empty());
|
||||
q.Clear();
|
||||
EXPECT_TRUE(q.Empty());
|
||||
for (u32 i = 0; i < 1000; ++i)
|
||||
q.Push(i);
|
||||
EXPECT_FALSE(q.Empty());
|
||||
q.Clear();
|
||||
EXPECT_TRUE(q.Empty());
|
||||
}
|
||||
|
||||
TEST(FifoQueue, MultiThreaded)
|
||||
{
|
||||
Common::FifoQueue<u32> q;
|
||||
Common::FifoQueue<u32> q;
|
||||
|
||||
auto inserter = [&q]() {
|
||||
for (u32 i = 0; i < 100000; ++i)
|
||||
q.Push(i);
|
||||
};
|
||||
auto inserter = [&q]() {
|
||||
for (u32 i = 0; i < 100000; ++i)
|
||||
q.Push(i);
|
||||
};
|
||||
|
||||
auto popper = [&q]() {
|
||||
for (u32 i = 0; i < 100000; ++i)
|
||||
{
|
||||
while (q.Empty());
|
||||
u32 v; q.Pop(v);
|
||||
EXPECT_EQ(i, v);
|
||||
}
|
||||
};
|
||||
auto popper = [&q]() {
|
||||
for (u32 i = 0; i < 100000; ++i)
|
||||
{
|
||||
while (q.Empty())
|
||||
;
|
||||
u32 v;
|
||||
q.Pop(v);
|
||||
EXPECT_EQ(i, v);
|
||||
}
|
||||
};
|
||||
|
||||
std::thread popper_thread(popper);
|
||||
std::thread inserter_thread(inserter);
|
||||
std::thread popper_thread(popper);
|
||||
std::thread inserter_thread(inserter);
|
||||
|
||||
popper_thread.join();
|
||||
inserter_thread.join();
|
||||
popper_thread.join();
|
||||
inserter_thread.join();
|
||||
}
|
||||
|
@ -8,26 +8,26 @@
|
||||
|
||||
TEST(FixedSizeQueue, Simple)
|
||||
{
|
||||
FixedSizeQueue<int, 5> q;
|
||||
FixedSizeQueue<int, 5> q;
|
||||
|
||||
EXPECT_EQ(0u, q.size());
|
||||
EXPECT_EQ(0u, q.size());
|
||||
|
||||
q.push(0);
|
||||
q.push(1);
|
||||
q.push(2);
|
||||
q.push(3);
|
||||
q.push(4);
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
EXPECT_EQ(i, q.front());
|
||||
EXPECT_EQ(i, q.pop_front());
|
||||
q.push(i + 5);
|
||||
}
|
||||
EXPECT_EQ(1000, q.pop_front());
|
||||
EXPECT_EQ(1001, q.pop_front());
|
||||
EXPECT_EQ(1002, q.pop_front());
|
||||
EXPECT_EQ(1003, q.pop_front());
|
||||
EXPECT_EQ(1004, q.pop_front());
|
||||
q.push(0);
|
||||
q.push(1);
|
||||
q.push(2);
|
||||
q.push(3);
|
||||
q.push(4);
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
EXPECT_EQ(i, q.front());
|
||||
EXPECT_EQ(i, q.pop_front());
|
||||
q.push(i + 5);
|
||||
}
|
||||
EXPECT_EQ(1000, q.pop_front());
|
||||
EXPECT_EQ(1001, q.pop_front());
|
||||
EXPECT_EQ(1002, q.pop_front());
|
||||
EXPECT_EQ(1003, q.pop_front());
|
||||
EXPECT_EQ(1004, q.pop_front());
|
||||
|
||||
EXPECT_EQ(0u, q.size());
|
||||
EXPECT_EQ(0u, q.size());
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <thread>
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/Flag.h"
|
||||
|
||||
@ -12,80 +12,83 @@ using Common::Flag;
|
||||
|
||||
TEST(Flag, Simple)
|
||||
{
|
||||
Flag f;
|
||||
EXPECT_FALSE(f.IsSet());
|
||||
Flag f;
|
||||
EXPECT_FALSE(f.IsSet());
|
||||
|
||||
f.Set();
|
||||
EXPECT_TRUE(f.IsSet());
|
||||
f.Set();
|
||||
EXPECT_TRUE(f.IsSet());
|
||||
|
||||
f.Clear();
|
||||
EXPECT_FALSE(f.IsSet());
|
||||
f.Clear();
|
||||
EXPECT_FALSE(f.IsSet());
|
||||
|
||||
f.Set(false);
|
||||
EXPECT_FALSE(f.IsSet());
|
||||
f.Set(false);
|
||||
EXPECT_FALSE(f.IsSet());
|
||||
|
||||
EXPECT_TRUE(f.TestAndSet());
|
||||
EXPECT_TRUE(f.TestAndClear());
|
||||
EXPECT_TRUE(f.TestAndSet());
|
||||
EXPECT_TRUE(f.TestAndClear());
|
||||
|
||||
Flag f2(true);
|
||||
EXPECT_TRUE(f2.IsSet());
|
||||
Flag f2(true);
|
||||
EXPECT_TRUE(f2.IsSet());
|
||||
}
|
||||
|
||||
TEST(Flag, MultiThreaded)
|
||||
{
|
||||
Flag f;
|
||||
int count = 0;
|
||||
const int ITERATIONS_COUNT = 100000;
|
||||
Flag f;
|
||||
int count = 0;
|
||||
const int ITERATIONS_COUNT = 100000;
|
||||
|
||||
auto setter = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
while (f.IsSet());
|
||||
f.Set();
|
||||
}
|
||||
};
|
||||
auto setter = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
while (f.IsSet())
|
||||
;
|
||||
f.Set();
|
||||
}
|
||||
};
|
||||
|
||||
auto clearer = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
while (!f.IsSet());
|
||||
count++;
|
||||
f.Clear();
|
||||
}
|
||||
};
|
||||
auto clearer = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
while (!f.IsSet())
|
||||
;
|
||||
count++;
|
||||
f.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
std::thread setter_thread(setter);
|
||||
std::thread clearer_thread(clearer);
|
||||
std::thread setter_thread(setter);
|
||||
std::thread clearer_thread(clearer);
|
||||
|
||||
setter_thread.join();
|
||||
clearer_thread.join();
|
||||
setter_thread.join();
|
||||
clearer_thread.join();
|
||||
|
||||
EXPECT_EQ(ITERATIONS_COUNT, count);
|
||||
EXPECT_EQ(ITERATIONS_COUNT, count);
|
||||
}
|
||||
|
||||
TEST(Flag, SpinLock)
|
||||
{
|
||||
// Uses a flag to implement basic spinlocking using TestAndSet.
|
||||
Flag f;
|
||||
int count = 0;
|
||||
const int ITERATIONS_COUNT = 5000;
|
||||
const int THREADS_COUNT = 50;
|
||||
// Uses a flag to implement basic spinlocking using TestAndSet.
|
||||
Flag f;
|
||||
int count = 0;
|
||||
const int ITERATIONS_COUNT = 5000;
|
||||
const int THREADS_COUNT = 50;
|
||||
|
||||
auto adder_func = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
// Acquire the spinlock.
|
||||
while (!f.TestAndSet());
|
||||
count++;
|
||||
f.Clear();
|
||||
}
|
||||
};
|
||||
auto adder_func = [&]() {
|
||||
for (int i = 0; i < ITERATIONS_COUNT; ++i)
|
||||
{
|
||||
// Acquire the spinlock.
|
||||
while (!f.TestAndSet())
|
||||
;
|
||||
count++;
|
||||
f.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
std::array<std::thread, THREADS_COUNT> threads;
|
||||
for (auto& th : threads)
|
||||
th = std::thread(adder_func);
|
||||
for (auto& th : threads)
|
||||
th.join();
|
||||
std::array<std::thread, THREADS_COUNT> threads;
|
||||
for (auto& th : threads)
|
||||
th = std::thread(adder_func);
|
||||
for (auto& th : threads)
|
||||
th.join();
|
||||
|
||||
EXPECT_EQ(ITERATIONS_COUNT * THREADS_COUNT, count);
|
||||
EXPECT_EQ(ITERATIONS_COUNT * THREADS_COUNT, count);
|
||||
}
|
||||
|
@ -2,87 +2,91 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
TEST(MathUtil, Clamp)
|
||||
{
|
||||
EXPECT_EQ(1, MathUtil::Clamp(1, 0, 2));
|
||||
EXPECT_EQ(1.0, MathUtil::Clamp(1.0, 0.0, 2.0));
|
||||
EXPECT_EQ(1, MathUtil::Clamp(1, 0, 2));
|
||||
EXPECT_EQ(1.0, MathUtil::Clamp(1.0, 0.0, 2.0));
|
||||
|
||||
EXPECT_EQ(2, MathUtil::Clamp(4, 0, 2));
|
||||
EXPECT_EQ(2.0, MathUtil::Clamp(4.0, 0.0, 2.0));
|
||||
EXPECT_EQ(2, MathUtil::Clamp(4, 0, 2));
|
||||
EXPECT_EQ(2.0, MathUtil::Clamp(4.0, 0.0, 2.0));
|
||||
|
||||
EXPECT_EQ(0, MathUtil::Clamp(-1, 0, 2));
|
||||
EXPECT_EQ(0.0, MathUtil::Clamp(-1.0, 0.0, 2.0));
|
||||
EXPECT_EQ(0, MathUtil::Clamp(-1, 0, 2));
|
||||
EXPECT_EQ(0.0, MathUtil::Clamp(-1.0, 0.0, 2.0));
|
||||
}
|
||||
|
||||
TEST(MathUtil, IsQNAN)
|
||||
{
|
||||
EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits<double>::quiet_NaN()));
|
||||
EXPECT_FALSE(MathUtil::IsQNAN(MathUtil::SNANConstant<double>()));
|
||||
EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits<double>::quiet_NaN()));
|
||||
EXPECT_FALSE(MathUtil::IsQNAN(MathUtil::SNANConstant<double>()));
|
||||
}
|
||||
|
||||
TEST(MathUtil, IsSNAN)
|
||||
{
|
||||
EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits<double>::quiet_NaN()));
|
||||
EXPECT_TRUE(MathUtil::IsSNAN(MathUtil::SNANConstant<double>()));
|
||||
EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits<double>::quiet_NaN()));
|
||||
EXPECT_TRUE(MathUtil::IsSNAN(MathUtil::SNANConstant<double>()));
|
||||
}
|
||||
|
||||
TEST(MathUtil, IntLog2)
|
||||
{
|
||||
EXPECT_EQ(0, IntLog2(1));
|
||||
EXPECT_EQ(1, IntLog2(2));
|
||||
EXPECT_EQ(2, IntLog2(4));
|
||||
EXPECT_EQ(3, IntLog2(8));
|
||||
EXPECT_EQ(63, IntLog2(0x8000000000000000ull));
|
||||
EXPECT_EQ(0, IntLog2(1));
|
||||
EXPECT_EQ(1, IntLog2(2));
|
||||
EXPECT_EQ(2, IntLog2(4));
|
||||
EXPECT_EQ(3, IntLog2(8));
|
||||
EXPECT_EQ(63, IntLog2(0x8000000000000000ull));
|
||||
|
||||
// Rounding behavior.
|
||||
EXPECT_EQ(3, IntLog2(15));
|
||||
EXPECT_EQ(63, IntLog2(0xFFFFFFFFFFFFFFFFull));
|
||||
// Rounding behavior.
|
||||
EXPECT_EQ(3, IntLog2(15));
|
||||
EXPECT_EQ(63, IntLog2(0xFFFFFFFFFFFFFFFFull));
|
||||
}
|
||||
|
||||
TEST(MathUtil, FlushToZero)
|
||||
{
|
||||
// To test the software implementation we need to make sure FTZ and DAZ are disabled.
|
||||
// Using volatile here to ensure the compiler doesn't constant-fold it,
|
||||
// we want the multiplication to occur at test runtime.
|
||||
volatile float s = std::numeric_limits<float>::denorm_min();
|
||||
volatile double d = std::numeric_limits<double>::denorm_min();
|
||||
// Casting away the volatile attribute is required in order for msvc to resolve this to the
|
||||
// correct instance of the comparison function.
|
||||
EXPECT_LT(0.f, (float)(s * 2));
|
||||
EXPECT_LT(0.0, (double)(d * 2));
|
||||
// To test the software implementation we need to make sure FTZ and DAZ are disabled.
|
||||
// Using volatile here to ensure the compiler doesn't constant-fold it,
|
||||
// we want the multiplication to occur at test runtime.
|
||||
volatile float s = std::numeric_limits<float>::denorm_min();
|
||||
volatile double d = std::numeric_limits<double>::denorm_min();
|
||||
// Casting away the volatile attribute is required in order for msvc to resolve this to the
|
||||
// correct instance of the comparison function.
|
||||
EXPECT_LT(0.f, (float)(s * 2));
|
||||
EXPECT_LT(0.0, (double)(d * 2));
|
||||
|
||||
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::denorm_min()));
|
||||
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::denorm_min()));
|
||||
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::min() / 2));
|
||||
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::min() / 2));
|
||||
EXPECT_EQ(std::numeric_limits<double>::min(), MathUtil::FlushToZero(std::numeric_limits<double>::min()));
|
||||
EXPECT_EQ(std::numeric_limits<double>::max(), MathUtil::FlushToZero(std::numeric_limits<double>::max()));
|
||||
EXPECT_EQ(+std::numeric_limits<double>::infinity(), MathUtil::FlushToZero(+std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), MathUtil::FlushToZero(-std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::denorm_min()));
|
||||
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::denorm_min()));
|
||||
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::min() / 2));
|
||||
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::min() / 2));
|
||||
EXPECT_EQ(std::numeric_limits<double>::min(),
|
||||
MathUtil::FlushToZero(std::numeric_limits<double>::min()));
|
||||
EXPECT_EQ(std::numeric_limits<double>::max(),
|
||||
MathUtil::FlushToZero(std::numeric_limits<double>::max()));
|
||||
EXPECT_EQ(+std::numeric_limits<double>::infinity(),
|
||||
MathUtil::FlushToZero(+std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(),
|
||||
MathUtil::FlushToZero(-std::numeric_limits<double>::infinity()));
|
||||
|
||||
// Test all subnormals as well as an equally large set of random normal floats.
|
||||
std::default_random_engine engine(0);
|
||||
std::uniform_int_distribution<u32> dist(0x00800000u, 0x7fffffffu);
|
||||
for (u32 i = 0; i <= 0x007fffffu; ++i)
|
||||
{
|
||||
MathUtil::IntFloat x(i);
|
||||
EXPECT_EQ(+0.f, MathUtil::FlushToZero(x.f));
|
||||
// Test all subnormals as well as an equally large set of random normal floats.
|
||||
std::default_random_engine engine(0);
|
||||
std::uniform_int_distribution<u32> dist(0x00800000u, 0x7fffffffu);
|
||||
for (u32 i = 0; i <= 0x007fffffu; ++i)
|
||||
{
|
||||
MathUtil::IntFloat x(i);
|
||||
EXPECT_EQ(+0.f, MathUtil::FlushToZero(x.f));
|
||||
|
||||
x.i = i | 0x80000000u;
|
||||
EXPECT_EQ(-0.f, MathUtil::FlushToZero(x.f));
|
||||
x.i = i | 0x80000000u;
|
||||
EXPECT_EQ(-0.f, MathUtil::FlushToZero(x.f));
|
||||
|
||||
x.i = dist(engine);
|
||||
MathUtil::IntFloat y(MathUtil::FlushToZero(x.f));
|
||||
EXPECT_EQ(x.i, y.i);
|
||||
x.i = dist(engine);
|
||||
MathUtil::IntFloat y(MathUtil::FlushToZero(x.f));
|
||||
EXPECT_EQ(x.i, y.i);
|
||||
|
||||
x.i |= 0x80000000u;
|
||||
y.f = MathUtil::FlushToZero(x.f);
|
||||
EXPECT_EQ(x.i, y.i);
|
||||
}
|
||||
x.i |= 0x80000000u;
|
||||
y.f = MathUtil::FlushToZero(x.f);
|
||||
EXPECT_EQ(x.i, y.i);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user