Add Array/BitArray tests and fix some detected problems

This commit is contained in:
Wojciech Figat
2022-08-19 11:18:48 +02:00
parent ed7cc96889
commit bf30d7cd29
4 changed files with 185 additions and 41 deletions

View File

@@ -112,15 +112,15 @@ public:
/// Initializes a new instance of the <see cref="Array"/> class. /// Initializes a new instance of the <see cref="Array"/> class.
/// </summary> /// </summary>
/// <param name="other">The other collection to copy.</param> /// <param name="other">The other collection to copy.</param>
template<typename U> template<typename OtherT = T, typename OtherAllocationType = AllocationType>
explicit Array(const Array<U>& other) noexcept explicit Array(const Array<OtherT, OtherAllocationType>& other) noexcept
{ {
_capacity = other._count; _capacity = other.Capacity();
_count = other._count; _count = other.Count();
if (_capacity > 0) if (_capacity > 0)
{ {
_allocation.Allocate(_capacity); _allocation.Allocate(_capacity);
Memory::ConstructItems(_allocation.Get(), other._data, other._count); Memory::ConstructItems(_allocation.Get(), other.Get(), _count);
} }
} }
@@ -164,13 +164,13 @@ public:
if (this != &other) if (this != &other)
{ {
Memory::DestructItems(_allocation.Get(), _count); Memory::DestructItems(_allocation.Get(), _count);
if (_capacity < other._count) if (_capacity < other.Count())
{ {
_allocation.Free(); _allocation.Free();
_capacity = other._count; _capacity = other.Count();
_allocation.Allocate(_capacity); _allocation.Allocate(_capacity);
} }
_count = other._count; _count = other.Count();
Memory::ConstructItems(_allocation.Get(), other.Get(), _count); Memory::ConstructItems(_allocation.Get(), other.Get(), _count);
} }
return *this; return *this;
@@ -489,7 +489,7 @@ public:
/// Adds the other collection to the collection. /// Adds the other collection to the collection.
/// </summary> /// </summary>
/// <param name="other">The other collection to add.</param> /// <param name="other">The other collection to add.</param>
template<typename OtherT, typename OtherAllocationType = HeapAllocation> template<typename OtherT, typename OtherAllocationType = AllocationType>
FORCE_INLINE void Add(const Array<OtherT, OtherAllocationType>& other) FORCE_INLINE void Add(const Array<OtherT, OtherAllocationType>& other)
{ {
Add(other.Get(), other.Count()); Add(other.Get(), other.Count());
@@ -860,9 +860,10 @@ public:
} }
public: public:
bool operator==(const Array& other) const template<typename OtherT = T, typename OtherAllocationType = AllocationType>
bool operator==(const Array<OtherT, OtherAllocationType>& other) const
{ {
if (_count == other._count) if (_count == other.Count())
{ {
const T* data = _allocation.Get(); const T* data = _allocation.Get();
const T* otherData = other.Get(); const T* otherData = other.Get();
@@ -875,7 +876,8 @@ public:
return true; return true;
} }
bool operator!=(const Array& other) const template<typename OtherT = T, typename OtherAllocationType = AllocationType>
bool operator!=(const Array<OtherT, OtherAllocationType>& other) const
{ {
return !operator==(other); return !operator==(other);
} }

View File

@@ -13,7 +13,6 @@ template<typename AllocationType = HeapAllocation>
API_CLASS(InBuild) class BitArray API_CLASS(InBuild) class BitArray
{ {
friend BitArray; friend BitArray;
public: public:
typedef uint64 ItemType; typedef uint64 ItemType;
typedef typename AllocationType::template Data<ItemType> AllocationData; typedef typename AllocationType::template Data<ItemType> AllocationData;
@@ -49,11 +48,31 @@ public:
/// Initializes a new instance of the <see cref="BitArray"/> class. /// Initializes a new instance of the <see cref="BitArray"/> class.
/// </summary> /// </summary>
/// <param name="other">The other collection to copy.</param> /// <param name="other">The other collection to copy.</param>
BitArray(const BitArray& other) BitArray(const BitArray& other) noexcept
{ {
_count = _capacity = other._count; _count = _capacity = other.Count();
if (_capacity > 0) if (_capacity > 0)
_allocation.Allocate(Math::Max<ItemType>(_capacity / sizeof(ItemType), 1)); {
const uint64 itemsCapacity = Math::Max<ItemType>(_capacity / sizeof(ItemType), 1);
_allocation.Allocate(itemsCapacity);
Platform::MemoryCopy(Get(), other.Get(), itemsCapacity * sizeof(ItemType));
}
}
/// <summary>
/// Initializes a new instance of the <see cref="BitArray"/> class.
/// </summary>
/// <param name="other">The other collection to copy.</param>
template<typename OtherAllocationType = AllocationType>
explicit BitArray(const BitArray<OtherAllocationType>& other) noexcept
{
_count = _capacity = other.Count();
if (_capacity > 0)
{
const uint64 itemsCapacity = Math::Max<ItemType>(_capacity / sizeof(ItemType), 1);
_allocation.Allocate(itemsCapacity);
Platform::MemoryCopy(Get(), other.Get(), itemsCapacity * sizeof(ItemType));
}
} }
/// <summary> /// <summary>
@@ -82,7 +101,9 @@ public:
{ {
_allocation.Free(); _allocation.Free();
_capacity = other._count; _capacity = other._count;
_allocation.Allocate(Math::Max<ItemType>(_capacity / sizeof(ItemType), 1)); const uint64 itemsCapacity = Math::Max<ItemType>(_capacity / sizeof(ItemType), 1);
_allocation.Allocate(itemsCapacity);
Platform::MemoryCopy(Get(), other.Get(), itemsCapacity * sizeof(ItemType));
} }
_count = other._count; _count = other._count;
} }
@@ -119,7 +140,6 @@ public:
/// <summary> /// <summary>
/// Gets the pointer to the bits storage data (linear allocation). /// Gets the pointer to the bits storage data (linear allocation).
/// </summary> /// </summary>
/// <returns>The data pointer.</returns>
FORCE_INLINE ItemType* Get() FORCE_INLINE ItemType* Get()
{ {
return _allocation.Get(); return _allocation.Get();
@@ -128,7 +148,6 @@ public:
/// <summary> /// <summary>
/// Gets the pointer to the bits storage data (linear allocation). /// Gets the pointer to the bits storage data (linear allocation).
/// </summary> /// </summary>
/// <returns>The data pointer.</returns>
FORCE_INLINE const ItemType* Get() const FORCE_INLINE const ItemType* Get() const
{ {
return _allocation.Get(); return _allocation.Get();
@@ -137,7 +156,6 @@ public:
/// <summary> /// <summary>
/// Gets the amount of the items in the collection. /// Gets the amount of the items in the collection.
/// </summary> /// </summary>
/// <returns>The amount of items.</returns>
FORCE_INLINE int32 Count() const FORCE_INLINE int32 Count() const
{ {
return _count; return _count;
@@ -146,7 +164,6 @@ public:
/// <summary> /// <summary>
/// Gets the amount of the items that can be contained by collection without resizing. /// Gets the amount of the items that can be contained by collection without resizing.
/// </summary> /// </summary>
/// <returns>The collection capacity.</returns>
FORCE_INLINE int32 Capacity() const FORCE_INLINE int32 Capacity() const
{ {
return _capacity; return _capacity;
@@ -155,7 +172,6 @@ public:
/// <summary> /// <summary>
/// Returns true if collection isn't empty. /// Returns true if collection isn't empty.
/// </summary> /// </summary>
/// <returns>True if collection isn't empty, otherwise false.</returns>
FORCE_INLINE bool HasItems() const FORCE_INLINE bool HasItems() const
{ {
return _count != 0; return _count != 0;
@@ -164,7 +180,6 @@ public:
/// <summary> /// <summary>
/// Returns true if collection is empty. /// Returns true if collection is empty.
/// </summary> /// </summary>
/// <returns>True if collection is empty, otherwise false.</returns>
FORCE_INLINE bool IsEmpty() const FORCE_INLINE bool IsEmpty() const
{ {
return _count == 0; return _count == 0;
@@ -316,4 +331,25 @@ public:
::Swap(_capacity, other._capacity); ::Swap(_capacity, other._capacity);
_allocation.Swap(other._allocation); _allocation.Swap(other._allocation);
} }
public:
template<typename OtherAllocationType = AllocationType>
bool operator==(const BitArray<OtherAllocationType>& other) const
{
if (_count == other.Count())
{
for (int32 i = 0; i < _count; i++)
{
if (!(Get(i) == other.Get(i)))
return false;
}
}
return true;
}
template<typename OtherAllocationType = AllocationType>
bool operator!=(const BitArray<OtherAllocationType>& other) const
{
return !operator==(other);
}
}; };

View File

@@ -13,7 +13,6 @@
class FLAXENGINE_API RandomStream class FLAXENGINE_API RandomStream
{ {
private: private:
/// <summary> /// <summary>
/// Holds the initial seed. /// Holds the initial seed.
/// </summary> /// </summary>
@@ -25,7 +24,6 @@ private:
mutable int32 _seed; mutable int32 _seed;
public: public:
/// <summary> /// <summary>
/// Init /// Init
/// </summary> /// </summary>
@@ -46,22 +44,18 @@ public:
} }
public: public:
/// <summary> /// <summary>
/// Gets initial seed value /// Gets initial seed value
/// </summary> /// </summary>
/// <returns>Initial seed.</returns>
int32 GetInitialSeed() const int32 GetInitialSeed() const
{ {
return _initialSeed; return _initialSeed;
} }
public: public:
/// <summary> /// <summary>
/// Gets the current seed. /// Gets the current seed.
/// </summary> /// </summary>
/// <returns>Current seed value.</returns>
int32 GetCurrentSeed() const int32 GetCurrentSeed() const
{ {
return _seed; return _seed;
@@ -94,11 +88,18 @@ public:
} }
public: public:
/// <summary> /// <summary>
/// Returns a random number between 0 and MAXUINT. /// Returns a random boolean.
/// </summary>
bool GetBool() const
{
MutateSeed();
return *(uint32*)&_seed < (MAX_uint32 / 2);
}
/// <summary>
/// Returns a random number between 0 and MAX_uint32.
/// </summary> /// </summary>
/// <returns>Random number.</returns>
uint32 GetUnsignedInt() const uint32 GetUnsignedInt() const
{ {
MutateSeed(); MutateSeed();
@@ -108,7 +109,6 @@ public:
/// <summary> /// <summary>
/// Returns a random number between 0 and 1. /// Returns a random number between 0 and 1.
/// </summary> /// </summary>
/// <returns>Random number.</returns>
float GetFraction() const float GetFraction() const
{ {
MutateSeed(); MutateSeed();
@@ -121,7 +121,6 @@ public:
/// <summary> /// <summary>
/// Returns a random number between 0 and 1. /// Returns a random number between 0 and 1.
/// </summary> /// </summary>
/// <returns>Random number.</returns>
FORCE_INLINE float Rand() const FORCE_INLINE float Rand() const
{ {
return GetFraction(); return GetFraction();
@@ -130,7 +129,6 @@ public:
/// <summary> /// <summary>
/// Returns a random vector of unit size. /// Returns a random vector of unit size.
/// </summary> /// </summary>
/// <returns>Random unit length vector</returns>
Float3 GetUnitVector() const Float3 GetUnitVector() const
{ {
Float3 result; Float3 result;
@@ -144,11 +142,10 @@ public:
} while (l > 1.0f || l < ZeroTolerance); } while (l > 1.0f || l < ZeroTolerance);
return Float3::Normalize(result); return Float3::Normalize(result);
} }
/// <summary> /// <summary>
/// Gets a random <see cref="Vector3"/> with components in a range between [0;1]. /// Gets a random <see cref="Vector3"/> with components in a range between [0;1].
/// </summary> /// </summary>
/// <returns>A random <see cref="Vector3"/>.</returns>
Vector3 GetVector3() const Vector3 GetVector3() const
{ {
return Vector3(GetFraction(), GetFraction(), GetFraction()); return Vector3(GetFraction(), GetFraction(), GetFraction());
@@ -157,11 +154,11 @@ public:
/// <summary> /// <summary>
/// Helper function for rand implementations. /// Helper function for rand implementations.
/// </summary> /// </summary>
/// <param name="A">Top border</param> /// <param name="a">Top border</param>
/// <returns>A random number in [0..A)</returns> /// <returns>A random number in [0..A)</returns>
FORCE_INLINE int32 RandHelper(int32 A) const FORCE_INLINE int32 RandHelper(int32 a) const
{ {
return A > 0 ? Math::TruncToInt(GetFraction() * ((float)A - ZeroTolerance)) : 0; return a > 0 ? Math::TruncToInt(GetFraction() * ((float)a - ZeroTolerance)) : 0;
} }
/// <summary> /// <summary>
@@ -188,7 +185,6 @@ public:
} }
protected: protected:
/// <summary> /// <summary>
/// Mutates the current seed into the next seed. /// Mutates the current seed into the next seed.
/// </summary> /// </summary>

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "Engine/Core/RandomStream.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/BitArray.h"
#include <ThirdParty/catch2/catch.hpp>
TEST_CASE("Array")
{
SECTION("Test Allocators")
{
Array<int32> a1;
Array<int32, InlinedAllocation<8>> a2;
Array<int32, FixedAllocation<8>> a3;
for (int32 i = 0; i < 7; i++)
{
a1.Add(i);
a2.Add(i);
a3.Add(i);
}
CHECK(a1.Count() == 7);
CHECK(a2.Count() == 7);
CHECK(a3.Count() == 7);
for (int32 i = 0; i < 7; i++)
{
CHECK(a1[i] == i);
CHECK(a2[i] == i);
CHECK(a3[i] == i);
}
}
// Generate some random data for testing
Array<uint32> testData;
testData.Resize(32);
RandomStream rand(101);
for (int32 i = 0; i < testData.Count(); i++)
testData[i] = rand.GetUnsignedInt();
SECTION("Test Copy Constructor")
{
const Array<uint32> a1(testData);
const Array<uint32, InlinedAllocation<8>> a2(testData);
const Array<uint32, InlinedAllocation<64>> a3(testData);
const Array<uint32, FixedAllocation<64>> a4(testData);
CHECK(a1 == testData);
CHECK(a2 == testData);
CHECK(a3 == testData);
CHECK(a4 == testData);
}
SECTION("Test Copy Operator")
{
Array<uint32> a1;
a1 = testData;
CHECK(a1 == testData);
}
}
TEST_CASE("BitArray")
{
SECTION("Test Allocators")
{
BitArray<> a1;
BitArray<InlinedAllocation<8>> a2;
BitArray<FixedAllocation<8>> a3;
for (int32 i = 0; i < 7; i++)
{
const bool v = i & 2;
a1.Add(v);
a2.Add(v);
a3.Add(v);
}
CHECK(a1.Count() == 7);
CHECK(a2.Count() == 7);
CHECK(a3.Count() == 7);
for (int32 i = 0; i < 7; i++)
{
const bool v = i & 2;
CHECK(a1.Get(i) == v);
CHECK(a2.Get(i) == v);
CHECK(a3.Get(i) == v);
}
}
// Generate some random data for testing
BitArray<> testData;
testData.Resize(32);
RandomStream rand(101);
for (int32 i = 0; i < testData.Count(); i++)
testData.Set(i, rand.GetBool());
SECTION("Test Copy Constructor")
{
const BitArray<> a1(testData);
const BitArray<InlinedAllocation<8>> a2(testData);
const BitArray<InlinedAllocation<64>> a3(testData);
const BitArray<FixedAllocation<64>> a4(testData);
CHECK(a1 == testData);
CHECK(a2 == testData);
CHECK(a3 == testData);
CHECK(a4 == testData);
}
SECTION("Test Copy Operator")
{
BitArray<> a1;
a1 = testData;
CHECK(a1 == testData);
}
}