@@ -608,7 +608,7 @@ int32 Editor::LoadProduct()
|
|||||||
// Validate project min supported version (older engine may try to load newer project)
|
// Validate project min supported version (older engine may try to load newer project)
|
||||||
// Special check if project specifies only build number, then major/minor fields are set to 0
|
// Special check if project specifies only build number, then major/minor fields are set to 0
|
||||||
const auto engineVersion = FLAXENGINE_VERSION;
|
const auto engineVersion = FLAXENGINE_VERSION;
|
||||||
for (auto e : projects)
|
for (const auto& e : projects)
|
||||||
{
|
{
|
||||||
const auto project = e.Item;
|
const auto project = e.Item;
|
||||||
if (project->MinEngineVersion > engineVersion ||
|
if (project->MinEngineVersion > engineVersion ||
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ bool ScriptsBuilderService::Init()
|
|||||||
auto project = Editor::Project;
|
auto project = Editor::Project;
|
||||||
HashSet<ProjectInfo*> projects;
|
HashSet<ProjectInfo*> projects;
|
||||||
project->GetAllProjects(projects);
|
project->GetAllProjects(projects);
|
||||||
for (auto e : projects)
|
for (const auto& e : projects)
|
||||||
{
|
{
|
||||||
ProjectInfo* project = e.Item;
|
ProjectInfo* project = e.Item;
|
||||||
if (project->Name == TEXT("Flax"))
|
if (project->Name == TEXT("Flax"))
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Engine/Platform/Platform.h"
|
#include "Engine/Platform/Platform.h"
|
||||||
#include "Engine/Core/Memory/Memory.h"
|
#include "Engine/Core/Memory/Memory.h"
|
||||||
#include "Engine/Core/Memory/Allocation.h"
|
#include "Engine/Core/Memory/Allocation.h"
|
||||||
|
#include "Engine/Core/Memory/AllocationUtils.h"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Template for dynamic array with variable capacity.
|
/// Template for dynamic array with variable capacity.
|
||||||
@@ -25,22 +26,9 @@ private:
|
|||||||
int32 _capacity;
|
int32 _capacity;
|
||||||
AllocationData _allocation;
|
AllocationData _allocation;
|
||||||
|
|
||||||
FORCE_INLINE static void MoveToEmpty(AllocationData& to, AllocationData& from, const int32 fromCount, const int32 fromCapacity)
|
|
||||||
{
|
|
||||||
if IF_CONSTEXPR (AllocationType::HasSwap)
|
|
||||||
to.Swap(from);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
to.Allocate(fromCapacity);
|
|
||||||
Memory::MoveItems(to.Get(), from.Get(), fromCount);
|
|
||||||
Memory::DestructItems(from.Get(), fromCount);
|
|
||||||
from.Free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes an empty <see cref="Array"/> without reserving any space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE Array()
|
FORCE_INLINE Array()
|
||||||
: _count(0)
|
: _count(0)
|
||||||
@@ -49,10 +37,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes <see cref="Array"/> by reserving space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="capacity">The initial capacity.</param>
|
/// <param name="capacity">The number of elements that can be added without a need to allocate more memory.</param>
|
||||||
explicit Array(const int32 capacity)
|
FORCE_INLINE explicit Array(const int32 capacity)
|
||||||
: _count(0)
|
: _count(0)
|
||||||
, _capacity(capacity)
|
, _capacity(capacity)
|
||||||
{
|
{
|
||||||
@@ -61,21 +49,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes <see cref="Array"/> by copying elements.
|
||||||
/// </summary>
|
|
||||||
/// <param name="initList">The initial values defined in the array.</param>
|
|
||||||
Array(std::initializer_list<T> initList)
|
|
||||||
{
|
|
||||||
_count = _capacity = static_cast<int32>(initList.size());
|
|
||||||
if (_count > 0)
|
|
||||||
{
|
|
||||||
_allocation.Allocate(_count);
|
|
||||||
Memory::ConstructItems(_allocation.Get(), initList.begin(), _count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The initial data.</param>
|
/// <param name="data">The initial data.</param>
|
||||||
/// <param name="length">The amount of items.</param>
|
/// <param name="length">The amount of items.</param>
|
||||||
@@ -91,38 +65,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes <see cref="Array"/> by copying listed elements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The other collection to copy.</param>
|
/// <param name="initList">The initial values defined in the array.</param>
|
||||||
Array(const Array& other)
|
FORCE_INLINE Array(std::initializer_list<T> initList)
|
||||||
|
: Array(initList.begin(), (int32)initList.size())
|
||||||
{
|
{
|
||||||
_count = _capacity = other._count;
|
|
||||||
if (_capacity > 0)
|
|
||||||
{
|
|
||||||
_allocation.Allocate(_capacity);
|
|
||||||
Memory::ConstructItems(_allocation.Get(), other.Get(), other._count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes <see cref="Array"/> by copying the elements from the other collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The other collection to copy.</param>
|
/// <param name="other">The other collection to copy.</param>
|
||||||
/// <param name="extraSize">The additionally amount of items to add to the add.</param>
|
FORCE_INLINE Array(const Array& other)
|
||||||
Array(const Array& other, int32 extraSize)
|
: Array(other.Get(), other.Count())
|
||||||
{
|
{
|
||||||
ASSERT(extraSize >= 0);
|
|
||||||
_count = _capacity = other._count + extraSize;
|
|
||||||
if (_capacity > 0)
|
|
||||||
{
|
|
||||||
_allocation.Allocate(_capacity);
|
|
||||||
Memory::ConstructItems(_allocation.Get(), other.Get(), other._count);
|
|
||||||
Memory::ConstructItems(_allocation.Get() + other._count, extraSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes <see cref="Array"/> by copying the elements from the other collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The other collection to copy.</param>
|
/// <param name="other">The other collection to copy.</param>
|
||||||
template<typename Other = T, typename OtherAllocationType = AllocationType>
|
template<typename Other = T, typename OtherAllocationType = AllocationType>
|
||||||
@@ -138,7 +99,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
/// Initializes <see cref="Array"/> by moving the content of the other collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The other collection to move.</param>
|
/// <param name="other">The other collection to move.</param>
|
||||||
Array(Array&& other) noexcept
|
Array(Array&& other) noexcept
|
||||||
@@ -147,7 +108,7 @@ public:
|
|||||||
_capacity = other._capacity;
|
_capacity = other._capacity;
|
||||||
other._count = 0;
|
other._count = 0;
|
||||||
other._capacity = 0;
|
other._capacity = 0;
|
||||||
MoveToEmpty(_allocation, other._allocation, _count, _capacity);
|
AllocationUtils::MoveToEmpty<T, AllocationType>(_allocation, other._allocation, _count, _capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -204,7 +165,7 @@ public:
|
|||||||
_capacity = other._capacity;
|
_capacity = other._capacity;
|
||||||
other._count = 0;
|
other._count = 0;
|
||||||
other._capacity = 0;
|
other._capacity = 0;
|
||||||
MoveToEmpty(_allocation, other._allocation, _count, _capacity);
|
AllocationUtils::MoveToEmpty<T, AllocationType>(_allocation, other._allocation, _count, _capacity);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -377,10 +338,13 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clear the collection without changing its capacity.
|
/// Clear the collection without changing its capacity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
Memory::DestructItems(_allocation.Get(), _count);
|
if (_count != 0)
|
||||||
_count = 0;
|
{
|
||||||
|
Memory::DestructItems(_allocation.Get(), _count);
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BitArray"/> class.
|
/// Initializes an empty <see cref="BitArray"/> without reserving any space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE BitArray()
|
FORCE_INLINE BitArray()
|
||||||
: _count(0)
|
: _count(0)
|
||||||
@@ -43,9 +43,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BitArray"/> class.
|
/// Initializes <see cref="BitArray"/> by reserving space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="capacity">The initial capacity.</param>
|
/// <param name="capacity">The number of elements that can be added without a need to allocate more memory.</param>
|
||||||
explicit BitArray(const int32 capacity)
|
explicit BitArray(const int32 capacity)
|
||||||
: _count(0)
|
: _count(0)
|
||||||
, _capacity(capacity)
|
, _capacity(capacity)
|
||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BitArray"/> class.
|
/// Initializes <see cref="BitArray"/> by copying the elements from the other collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The other collection to copy.</param>
|
/// <param name="other">The other collection to copy.</param>
|
||||||
BitArray(const BitArray& other) noexcept
|
BitArray(const BitArray& other) noexcept
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "Engine/Core/Memory/Memory.h"
|
#include "Engine/Core/Memory/Memory.h"
|
||||||
#include "Engine/Core/Memory/Allocation.h"
|
#include "Engine/Core/Memory/Allocation.h"
|
||||||
|
#include "Engine/Core/Memory/AllocationUtils.h"
|
||||||
#include "Engine/Core/Collections/BucketState.h"
|
#include "Engine/Core/Collections/BucketState.h"
|
||||||
#include "Engine/Core/Collections/HashFunctions.h"
|
#include "Engine/Core/Collections/HashFunctions.h"
|
||||||
#include "Engine/Core/Collections/Config.h"
|
#include "Engine/Core/Collections/Config.h"
|
||||||
@@ -25,6 +26,7 @@ public:
|
|||||||
struct Bucket
|
struct Bucket
|
||||||
{
|
{
|
||||||
friend Dictionary;
|
friend Dictionary;
|
||||||
|
friend Memory;
|
||||||
|
|
||||||
/// <summary>The key.</summary>
|
/// <summary>The key.</summary>
|
||||||
KeyType Key;
|
KeyType Key;
|
||||||
@@ -34,6 +36,57 @@ public:
|
|||||||
private:
|
private:
|
||||||
BucketState _state;
|
BucketState _state;
|
||||||
|
|
||||||
|
Bucket()
|
||||||
|
: _state(BucketState::Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket(Bucket&& other) noexcept
|
||||||
|
{
|
||||||
|
_state = other._state;
|
||||||
|
if (other._state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::MoveItems(&Key, &other.Key, 1);
|
||||||
|
Memory::MoveItems(&Value, &other.Value, 1);
|
||||||
|
other._state = BucketState::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket& operator=(Bucket&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
if (_state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::DestructItem(&Key);
|
||||||
|
Memory::DestructItem(&Value);
|
||||||
|
}
|
||||||
|
_state = other._state;
|
||||||
|
if (other._state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::MoveItems(&Key, &other.Key, 1);
|
||||||
|
Memory::MoveItems(&Value, &other.Value, 1);
|
||||||
|
other._state = BucketState::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Copying a bucket is useless, because a key must be unique in the dictionary.</summary>
|
||||||
|
Bucket(const Bucket&) = delete;
|
||||||
|
|
||||||
|
/// <summary>Copying a bucket is useless, because a key must be unique in the dictionary.</summary>
|
||||||
|
Bucket& operator=(const Bucket&) = delete;
|
||||||
|
|
||||||
|
~Bucket()
|
||||||
|
{
|
||||||
|
if (_state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::DestructItem(&Key);
|
||||||
|
Memory::DestructItem(&Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Free()
|
FORCE_INLINE void Free()
|
||||||
{
|
{
|
||||||
if (_state == BucketState::Occupied)
|
if (_state == BucketState::Occupied)
|
||||||
@@ -104,46 +157,19 @@ private:
|
|||||||
int32 _size = 0;
|
int32 _size = 0;
|
||||||
AllocationData _allocation;
|
AllocationData _allocation;
|
||||||
|
|
||||||
FORCE_INLINE static void MoveToEmpty(AllocationData& to, AllocationData& from, const int32 fromSize)
|
|
||||||
{
|
|
||||||
if IF_CONSTEXPR (AllocationType::HasSwap)
|
|
||||||
to.Swap(from);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
to.Allocate(fromSize);
|
|
||||||
Bucket* toData = to.Get();
|
|
||||||
Bucket* fromData = from.Get();
|
|
||||||
for (int32 i = 0; i < fromSize; i++)
|
|
||||||
{
|
|
||||||
Bucket& fromBucket = fromData[i];
|
|
||||||
if (fromBucket.IsOccupied())
|
|
||||||
{
|
|
||||||
Bucket& toBucket = toData[i];
|
|
||||||
Memory::MoveItems(&toBucket.Key, &fromBucket.Key, 1);
|
|
||||||
Memory::MoveItems(&toBucket.Value, &fromBucket.Value, 1);
|
|
||||||
toBucket._state = BucketState::Occupied;
|
|
||||||
Memory::DestructItem(&fromBucket.Key);
|
|
||||||
Memory::DestructItem(&fromBucket.Value);
|
|
||||||
fromBucket._state = BucketState::Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
from.Free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Dictionary"/> class.
|
/// Initializes an empty <see cref="Dictionary"/> without reserving any space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary()
|
Dictionary()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Dictionary"/> class.
|
/// Initializes <see cref="Dictionary"/> by reserving space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="capacity">The initial capacity.</param>
|
/// <param name="capacity">The number of elements that can be added without a need to allocate more memory.</param>
|
||||||
explicit Dictionary(const int32 capacity)
|
FORCE_INLINE explicit Dictionary(const int32 capacity)
|
||||||
{
|
{
|
||||||
SetCapacity(capacity);
|
SetCapacity(capacity);
|
||||||
}
|
}
|
||||||
@@ -160,11 +186,11 @@ public:
|
|||||||
other._elementsCount = 0;
|
other._elementsCount = 0;
|
||||||
other._deletedCount = 0;
|
other._deletedCount = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
MoveToEmpty(_allocation, other._allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(_allocation, other._allocation, _size, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Dictionary"/> class.
|
/// Initializes <see cref="Dictionary"/> by copying the elements from the other collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">Other collection to copy</param>
|
/// <param name="other">Other collection to copy</param>
|
||||||
Dictionary(const Dictionary& other)
|
Dictionary(const Dictionary& other)
|
||||||
@@ -201,7 +227,7 @@ public:
|
|||||||
other._elementsCount = 0;
|
other._elementsCount = 0;
|
||||||
other._deletedCount = 0;
|
other._deletedCount = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
MoveToEmpty(_allocation, other._allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(_allocation, other._allocation, _size, _size);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -536,25 +562,16 @@ public:
|
|||||||
/// <param name="preserveContents">Enables preserving collection contents during resizing.</param>
|
/// <param name="preserveContents">Enables preserving collection contents during resizing.</param>
|
||||||
void SetCapacity(int32 capacity, const bool preserveContents = true)
|
void SetCapacity(int32 capacity, const bool preserveContents = true)
|
||||||
{
|
{
|
||||||
if (capacity == Capacity())
|
if (capacity == _size)
|
||||||
return;
|
return;
|
||||||
ASSERT(capacity >= 0);
|
ASSERT(capacity >= 0);
|
||||||
AllocationData oldAllocation;
|
AllocationData oldAllocation;
|
||||||
MoveToEmpty(oldAllocation, _allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(oldAllocation, _allocation, _size, _size);
|
||||||
const int32 oldSize = _size;
|
const int32 oldSize = _size;
|
||||||
const int32 oldElementsCount = _elementsCount;
|
const int32 oldElementsCount = _elementsCount;
|
||||||
_deletedCount = _elementsCount = 0;
|
_deletedCount = _elementsCount = 0;
|
||||||
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
||||||
{
|
capacity = AllocationUtils::AlignToPowerOf2(capacity);
|
||||||
// Align capacity value to the next power of two (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
|
|
||||||
capacity--;
|
|
||||||
capacity |= capacity >> 1;
|
|
||||||
capacity |= capacity >> 2;
|
|
||||||
capacity |= capacity >> 4;
|
|
||||||
capacity |= capacity >> 8;
|
|
||||||
capacity |= capacity >> 16;
|
|
||||||
capacity++;
|
|
||||||
}
|
|
||||||
if (capacity)
|
if (capacity)
|
||||||
{
|
{
|
||||||
_allocation.Allocate(capacity);
|
_allocation.Allocate(capacity);
|
||||||
@@ -574,11 +591,9 @@ public:
|
|||||||
{
|
{
|
||||||
FindPosition(oldBucket.Key, pos);
|
FindPosition(oldBucket.Key, pos);
|
||||||
ASSERT(pos.FreeSlotIndex != -1);
|
ASSERT(pos.FreeSlotIndex != -1);
|
||||||
Bucket* bucket = &_allocation.Get()[pos.FreeSlotIndex];
|
Bucket& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||||
Memory::MoveItems(&bucket->Key, &oldBucket.Key, 1);
|
bucket = MoveTemp(oldBucket);
|
||||||
Memory::MoveItems(&bucket->Value, &oldBucket.Value, 1);
|
_elementsCount++;
|
||||||
bucket->_state = BucketState::Occupied;
|
|
||||||
++_elementsCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -968,7 +983,7 @@ private:
|
|||||||
{
|
{
|
||||||
// Rebuild entire table completely
|
// Rebuild entire table completely
|
||||||
AllocationData oldAllocation;
|
AllocationData oldAllocation;
|
||||||
MoveToEmpty(oldAllocation, _allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(oldAllocation, _allocation, _size, _size);
|
||||||
_allocation.Allocate(_size);
|
_allocation.Allocate(_size);
|
||||||
Bucket* data = _allocation.Get();
|
Bucket* data = _allocation.Get();
|
||||||
for (int32 i = 0; i < _size; i++)
|
for (int32 i = 0; i < _size; i++)
|
||||||
@@ -982,10 +997,8 @@ private:
|
|||||||
{
|
{
|
||||||
FindPosition(oldBucket.Key, pos);
|
FindPosition(oldBucket.Key, pos);
|
||||||
ASSERT(pos.FreeSlotIndex != -1);
|
ASSERT(pos.FreeSlotIndex != -1);
|
||||||
Bucket* bucket = &_allocation.Get()[pos.FreeSlotIndex];
|
Bucket& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||||
Memory::MoveItems(&bucket->Key, &oldBucket.Key, 1);
|
bucket = MoveTemp(oldBucket);
|
||||||
Memory::MoveItems(&bucket->Value, &oldBucket.Value, 1);
|
|
||||||
bucket->_state = BucketState::Occupied;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int32 i = 0; i < _size; i++)
|
for (int32 i = 0; i < _size; i++)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "Engine/Core/Memory/Memory.h"
|
#include "Engine/Core/Memory/Memory.h"
|
||||||
#include "Engine/Core/Memory/Allocation.h"
|
#include "Engine/Core/Memory/Allocation.h"
|
||||||
|
#include "Engine/Core/Memory/AllocationUtils.h"
|
||||||
#include "Engine/Core/Collections/BucketState.h"
|
#include "Engine/Core/Collections/BucketState.h"
|
||||||
#include "Engine/Core/Collections/HashFunctions.h"
|
#include "Engine/Core/Collections/HashFunctions.h"
|
||||||
#include "Engine/Core/Collections/Config.h"
|
#include "Engine/Core/Collections/Config.h"
|
||||||
@@ -24,6 +25,7 @@ public:
|
|||||||
struct Bucket
|
struct Bucket
|
||||||
{
|
{
|
||||||
friend HashSet;
|
friend HashSet;
|
||||||
|
friend Memory;
|
||||||
|
|
||||||
/// <summary>The item.</summary>
|
/// <summary>The item.</summary>
|
||||||
T Item;
|
T Item;
|
||||||
@@ -31,6 +33,51 @@ public:
|
|||||||
private:
|
private:
|
||||||
BucketState _state;
|
BucketState _state;
|
||||||
|
|
||||||
|
Bucket()
|
||||||
|
: _state(BucketState::Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket(Bucket&& other) noexcept
|
||||||
|
{
|
||||||
|
_state = other._state;
|
||||||
|
if (other._state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::MoveItems(&Item, &other.Item, 1);
|
||||||
|
other._state = BucketState::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket& operator=(Bucket&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
if (_state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::DestructItem(&Item);
|
||||||
|
}
|
||||||
|
_state = other._state;
|
||||||
|
if (other._state == BucketState::Occupied)
|
||||||
|
{
|
||||||
|
Memory::MoveItems(&Item, &other.Item, 1);
|
||||||
|
other._state = BucketState::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Copying a bucket is useless, because a key must be unique in the dictionary.</summary>
|
||||||
|
Bucket(const Bucket&) = delete;
|
||||||
|
|
||||||
|
/// <summary>Copying a bucket is useless, because a key must be unique in the dictionary.</summary>
|
||||||
|
Bucket& operator=(const Bucket&) = delete;
|
||||||
|
|
||||||
|
~Bucket()
|
||||||
|
{
|
||||||
|
if (_state == BucketState::Occupied)
|
||||||
|
Memory::DestructItem(&Item);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Free()
|
FORCE_INLINE void Free()
|
||||||
{
|
{
|
||||||
if (_state == BucketState::Occupied)
|
if (_state == BucketState::Occupied)
|
||||||
@@ -87,44 +134,19 @@ private:
|
|||||||
int32 _size = 0;
|
int32 _size = 0;
|
||||||
AllocationData _allocation;
|
AllocationData _allocation;
|
||||||
|
|
||||||
FORCE_INLINE static void MoveToEmpty(AllocationData& to, AllocationData& from, const int32 fromSize)
|
|
||||||
{
|
|
||||||
if IF_CONSTEXPR (AllocationType::HasSwap)
|
|
||||||
to.Swap(from);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
to.Allocate(fromSize);
|
|
||||||
Bucket* toData = to.Get();
|
|
||||||
Bucket* fromData = from.Get();
|
|
||||||
for (int32 i = 0; i < fromSize; ++i)
|
|
||||||
{
|
|
||||||
Bucket& fromBucket = fromData[i];
|
|
||||||
if (fromBucket.IsOccupied())
|
|
||||||
{
|
|
||||||
Bucket& toBucket = toData[i];
|
|
||||||
Memory::MoveItems(&toBucket.Item, &fromBucket.Item, 1);
|
|
||||||
toBucket._state = BucketState::Occupied;
|
|
||||||
Memory::DestructItem(&fromBucket.Item);
|
|
||||||
fromBucket._state = BucketState::Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
from.Free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HashSet"/> class.
|
/// Initializes an empty <see cref="HashSet"/> without reserving any space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HashSet()
|
HashSet()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HashSet"/> class.
|
/// Initializes <see cref="HashSet"/> by reserving space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="capacity">The initial capacity.</param>
|
/// <param name="capacity">The number of elements that can be added without a need to allocate more memory.</param>
|
||||||
explicit HashSet(const int32 capacity)
|
FORCE_INLINE explicit HashSet(const int32 capacity)
|
||||||
{
|
{
|
||||||
SetCapacity(capacity);
|
SetCapacity(capacity);
|
||||||
}
|
}
|
||||||
@@ -141,11 +163,11 @@ public:
|
|||||||
other._elementsCount = 0;
|
other._elementsCount = 0;
|
||||||
other._deletedCount = 0;
|
other._deletedCount = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
MoveToEmpty(_allocation, other._allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(_allocation, other._allocation, _size, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HashSet"/> class.
|
/// Initializes <see cref="HashSet"/> by copying the elements from the other collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">Other collection to copy</param>
|
/// <param name="other">Other collection to copy</param>
|
||||||
HashSet(const HashSet& other)
|
HashSet(const HashSet& other)
|
||||||
@@ -182,7 +204,7 @@ public:
|
|||||||
other._elementsCount = 0;
|
other._elementsCount = 0;
|
||||||
other._deletedCount = 0;
|
other._deletedCount = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
MoveToEmpty(_allocation, other._allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(_allocation, other._allocation, _size, _size);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -413,25 +435,16 @@ public:
|
|||||||
/// <param name="preserveContents">Enable/disable preserving collection contents during resizing</param>
|
/// <param name="preserveContents">Enable/disable preserving collection contents during resizing</param>
|
||||||
void SetCapacity(int32 capacity, const bool preserveContents = true)
|
void SetCapacity(int32 capacity, const bool preserveContents = true)
|
||||||
{
|
{
|
||||||
if (capacity == Capacity())
|
if (capacity == _size)
|
||||||
return;
|
return;
|
||||||
ASSERT(capacity >= 0);
|
ASSERT(capacity >= 0);
|
||||||
AllocationData oldAllocation;
|
AllocationData oldAllocation;
|
||||||
MoveToEmpty(oldAllocation, _allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(oldAllocation, _allocation, _size, _size);
|
||||||
const int32 oldSize = _size;
|
const int32 oldSize = _size;
|
||||||
const int32 oldElementsCount = _elementsCount;
|
const int32 oldElementsCount = _elementsCount;
|
||||||
_deletedCount = _elementsCount = 0;
|
_deletedCount = _elementsCount = 0;
|
||||||
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
||||||
{
|
capacity = AllocationUtils::AlignToPowerOf2(capacity);
|
||||||
// Align capacity value to the next power of two (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
|
|
||||||
capacity--;
|
|
||||||
capacity |= capacity >> 1;
|
|
||||||
capacity |= capacity >> 2;
|
|
||||||
capacity |= capacity >> 4;
|
|
||||||
capacity |= capacity >> 8;
|
|
||||||
capacity |= capacity >> 16;
|
|
||||||
capacity++;
|
|
||||||
}
|
|
||||||
if (capacity)
|
if (capacity)
|
||||||
{
|
{
|
||||||
_allocation.Allocate(capacity);
|
_allocation.Allocate(capacity);
|
||||||
@@ -451,9 +464,8 @@ public:
|
|||||||
{
|
{
|
||||||
FindPosition(oldBucket.Item, pos);
|
FindPosition(oldBucket.Item, pos);
|
||||||
ASSERT(pos.FreeSlotIndex != -1);
|
ASSERT(pos.FreeSlotIndex != -1);
|
||||||
Bucket* bucket = &_allocation.Get()[pos.FreeSlotIndex];
|
Bucket& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||||
Memory::MoveItems(&bucket->Item, &oldBucket.Item, 1);
|
bucket = MoveTemp(oldBucket);
|
||||||
bucket->_state = BucketState::Occupied;
|
|
||||||
_elementsCount++;
|
_elementsCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -764,7 +776,7 @@ private:
|
|||||||
{
|
{
|
||||||
// Rebuild entire table completely
|
// Rebuild entire table completely
|
||||||
AllocationData oldAllocation;
|
AllocationData oldAllocation;
|
||||||
MoveToEmpty(oldAllocation, _allocation, _size);
|
AllocationUtils::MoveToEmpty<Bucket, AllocationType>(oldAllocation, _allocation, _size, _size);
|
||||||
_allocation.Allocate(_size);
|
_allocation.Allocate(_size);
|
||||||
Bucket* data = _allocation.Get();
|
Bucket* data = _allocation.Get();
|
||||||
for (int32 i = 0; i < _size; ++i)
|
for (int32 i = 0; i < _size; ++i)
|
||||||
@@ -778,9 +790,8 @@ private:
|
|||||||
{
|
{
|
||||||
FindPosition(oldBucket.Item, pos);
|
FindPosition(oldBucket.Item, pos);
|
||||||
ASSERT(pos.FreeSlotIndex != -1);
|
ASSERT(pos.FreeSlotIndex != -1);
|
||||||
Bucket* bucket = &_allocation.Get()[pos.FreeSlotIndex];
|
Bucket& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||||
Memory::MoveItems(&bucket->Item, &oldBucket.Item, 1);
|
bucket = MoveTemp(oldBucket);
|
||||||
bucket->_state = BucketState::Occupied;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int32 i = 0; i < _size; ++i)
|
for (int32 i = 0; i < _size; ++i)
|
||||||
|
|||||||
@@ -5,6 +5,39 @@
|
|||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Engine/Core/Core.h"
|
#include "Engine/Core/Core.h"
|
||||||
|
|
||||||
|
namespace AllocationUtils
|
||||||
|
{
|
||||||
|
// Rounds up the input value to the next power of 2 to be used as bigger memory allocation block. Handles overflow.
|
||||||
|
inline int32 RoundUpToPowerOf2(int32 capacity)
|
||||||
|
{
|
||||||
|
// Reference: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
|
capacity--;
|
||||||
|
capacity |= capacity >> 1;
|
||||||
|
capacity |= capacity >> 2;
|
||||||
|
capacity |= capacity >> 4;
|
||||||
|
capacity |= capacity >> 8;
|
||||||
|
capacity |= capacity >> 16;
|
||||||
|
uint64 capacity64 = (uint64)(capacity + 1) * 2;
|
||||||
|
if (capacity64 > MAX_int32)
|
||||||
|
capacity64 = MAX_int32;
|
||||||
|
return (int32)capacity64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aligns the input value to the next power of 2 to be used as bigger memory allocation block.
|
||||||
|
inline int32 AlignToPowerOf2(int32 capacity)
|
||||||
|
{
|
||||||
|
// Reference: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
|
capacity--;
|
||||||
|
capacity |= capacity >> 1;
|
||||||
|
capacity |= capacity >> 2;
|
||||||
|
capacity |= capacity >> 4;
|
||||||
|
capacity |= capacity >> 8;
|
||||||
|
capacity |= capacity >> 16;
|
||||||
|
capacity++;
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The memory allocation policy that uses inlined memory of the fixed size (no resize support, does not use heap allocations at all).
|
/// The memory allocation policy that uses inlined memory of the fixed size (no resize support, does not use heap allocations at all).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -47,16 +80,12 @@ public:
|
|||||||
|
|
||||||
FORCE_INLINE void Allocate(const int32 capacity)
|
FORCE_INLINE void Allocate(const int32 capacity)
|
||||||
{
|
{
|
||||||
#if ENABLE_ASSERTION_LOW_LAYERS
|
ASSERT_LOW_LAYER(capacity <= Capacity);
|
||||||
ASSERT(capacity <= Capacity);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Relocate(const int32 capacity, int32 oldCount, int32 newCount)
|
FORCE_INLINE void Relocate(const int32 capacity, int32 oldCount, int32 newCount)
|
||||||
{
|
{
|
||||||
#if ENABLE_ASSERTION_LOW_LAYERS
|
ASSERT_LOW_LAYER(capacity <= Capacity);
|
||||||
ASSERT(capacity <= Capacity);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Free()
|
FORCE_INLINE void Free()
|
||||||
@@ -71,7 +100,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The memory allocation policy that uses default heap allocator.
|
/// The memory allocation policy that uses default heap allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class HeapAllocation
|
class HeapAllocation
|
||||||
{
|
{
|
||||||
@@ -109,33 +138,17 @@ public:
|
|||||||
if (capacity < minCapacity)
|
if (capacity < minCapacity)
|
||||||
capacity = minCapacity;
|
capacity = minCapacity;
|
||||||
if (capacity < 8)
|
if (capacity < 8)
|
||||||
{
|
|
||||||
capacity = 8;
|
capacity = 8;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
capacity = AllocationUtils::RoundUpToPowerOf2(capacity);
|
||||||
// Round up to the next power of 2 and multiply by 2 (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
|
|
||||||
capacity--;
|
|
||||||
capacity |= capacity >> 1;
|
|
||||||
capacity |= capacity >> 2;
|
|
||||||
capacity |= capacity >> 4;
|
|
||||||
capacity |= capacity >> 8;
|
|
||||||
capacity |= capacity >> 16;
|
|
||||||
uint64 capacity64 = (uint64)(capacity + 1) * 2;
|
|
||||||
if (capacity64 > MAX_int32)
|
|
||||||
capacity64 = MAX_int32;
|
|
||||||
capacity = (int32)capacity64;
|
|
||||||
}
|
|
||||||
return capacity;
|
return capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Allocate(const int32 capacity)
|
FORCE_INLINE void Allocate(const int32 capacity)
|
||||||
{
|
{
|
||||||
#if ENABLE_ASSERTION_LOW_LAYERS
|
ASSERT_LOW_LAYER(!_data);
|
||||||
ASSERT(!_data);
|
|
||||||
#endif
|
|
||||||
_data = static_cast<T*>(Allocator::Allocate(capacity * sizeof(T)));
|
_data = static_cast<T*>(Allocator::Allocate(capacity * sizeof(T)));
|
||||||
#if !BUILD_RELEASE
|
#if ENABLE_ASSERTION
|
||||||
if (!_data)
|
if (!_data)
|
||||||
OUT_OF_MEMORY;
|
OUT_OF_MEMORY;
|
||||||
#endif
|
#endif
|
||||||
@@ -144,7 +157,7 @@ public:
|
|||||||
FORCE_INLINE void Relocate(const int32 capacity, int32 oldCount, int32 newCount)
|
FORCE_INLINE void Relocate(const int32 capacity, int32 oldCount, int32 newCount)
|
||||||
{
|
{
|
||||||
T* newData = capacity != 0 ? static_cast<T*>(Allocator::Allocate(capacity * sizeof(T))) : nullptr;
|
T* newData = capacity != 0 ? static_cast<T*>(Allocator::Allocate(capacity * sizeof(T))) : nullptr;
|
||||||
#if !BUILD_RELEASE
|
#if ENABLE_ASSERTION
|
||||||
if (!newData && capacity != 0)
|
if (!newData && capacity != 0)
|
||||||
OUT_OF_MEMORY;
|
OUT_OF_MEMORY;
|
||||||
#endif
|
#endif
|
||||||
@@ -176,7 +189,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The memory allocation policy that uses inlined memory of the fixed size and supports using additional allocation to increase its capacity (eg. via heap allocation).
|
/// The memory allocation policy that uses inlined memory of the fixed size and supports using additional allocation to increase its capacity (eg. via heap allocation).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
template<int Capacity, typename OtherAllocator = HeapAllocation>
|
template<int Capacity, typename FallbackAllocation = HeapAllocation>
|
||||||
class InlinedAllocation
|
class InlinedAllocation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -186,11 +199,11 @@ public:
|
|||||||
class alignas(sizeof(void*)) Data
|
class alignas(sizeof(void*)) Data
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef typename OtherAllocator::template Data<T> OtherData;
|
typedef typename FallbackAllocation::template Data<T> FallbackData;
|
||||||
|
|
||||||
bool _useOther = false;
|
bool _useFallback = false;
|
||||||
byte _data[Capacity * sizeof(T)];
|
byte _data[Capacity * sizeof(T)];
|
||||||
OtherData _other;
|
FallbackData _fallback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FORCE_INLINE Data()
|
FORCE_INLINE Data()
|
||||||
@@ -203,25 +216,25 @@ public:
|
|||||||
|
|
||||||
FORCE_INLINE T* Get()
|
FORCE_INLINE T* Get()
|
||||||
{
|
{
|
||||||
return _useOther ? _other.Get() : reinterpret_cast<T*>(_data);
|
return _useFallback ? _fallback.Get() : reinterpret_cast<T*>(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE const T* Get() const
|
FORCE_INLINE const T* Get() const
|
||||||
{
|
{
|
||||||
return _useOther ? _other.Get() : reinterpret_cast<const T*>(_data);
|
return _useFallback ? _fallback.Get() : reinterpret_cast<const T*>(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, int32 minCapacity) const
|
FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, int32 minCapacity) const
|
||||||
{
|
{
|
||||||
return minCapacity <= Capacity ? Capacity : _other.CalculateCapacityGrow(capacity, minCapacity);
|
return minCapacity <= Capacity ? Capacity : _fallback.CalculateCapacityGrow(capacity, minCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void Allocate(int32 capacity)
|
FORCE_INLINE void Allocate(int32 capacity)
|
||||||
{
|
{
|
||||||
if (capacity > Capacity)
|
if (capacity > Capacity)
|
||||||
{
|
{
|
||||||
_useOther = true;
|
_useFallback = true;
|
||||||
_other.Allocate(capacity);
|
_fallback.Allocate(capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,32 +245,32 @@ public:
|
|||||||
// Check if the new allocation will fit into inlined storage
|
// Check if the new allocation will fit into inlined storage
|
||||||
if (capacity <= Capacity)
|
if (capacity <= Capacity)
|
||||||
{
|
{
|
||||||
if (_useOther)
|
if (_useFallback)
|
||||||
{
|
{
|
||||||
// Move the items from other allocation to the inlined storage
|
// Move the items from other allocation to the inlined storage
|
||||||
Memory::MoveItems(data, _other.Get(), newCount);
|
Memory::MoveItems(data, _fallback.Get(), newCount);
|
||||||
|
|
||||||
// Free the other allocation
|
// Free the other allocation
|
||||||
Memory::DestructItems(_other.Get(), oldCount);
|
Memory::DestructItems(_fallback.Get(), oldCount);
|
||||||
_other.Free();
|
_fallback.Free();
|
||||||
_useOther = false;
|
_useFallback = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_useOther)
|
if (_useFallback)
|
||||||
{
|
{
|
||||||
// Resize other allocation
|
// Resize other allocation
|
||||||
_other.Relocate(capacity, oldCount, newCount);
|
_fallback.Relocate(capacity, oldCount, newCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Allocate other allocation
|
// Allocate other allocation
|
||||||
_other.Allocate(capacity);
|
_fallback.Allocate(capacity);
|
||||||
_useOther = true;
|
_useFallback = true;
|
||||||
|
|
||||||
// Move the items from the inlined storage to the other allocation
|
// Move the items from the inlined storage to the other allocation
|
||||||
Memory::MoveItems(_other.Get(), data, newCount);
|
Memory::MoveItems(_fallback.Get(), data, newCount);
|
||||||
Memory::DestructItems(data, oldCount);
|
Memory::DestructItems(data, oldCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,10 +278,10 @@ public:
|
|||||||
|
|
||||||
FORCE_INLINE void Free()
|
FORCE_INLINE void Free()
|
||||||
{
|
{
|
||||||
if (_useOther)
|
if (_useFallback)
|
||||||
{
|
{
|
||||||
_useOther = false;
|
_useFallback = false;
|
||||||
_other.Free();
|
_fallback.Free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
Source/Engine/Core/Memory/AllocationUtils.h
Normal file
24
Source/Engine/Core/Memory/AllocationUtils.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Allocation.h"
|
||||||
|
#include "Engine/Core/Templates.h"
|
||||||
|
|
||||||
|
namespace AllocationUtils
|
||||||
|
{
|
||||||
|
// Moves the data from the source allocation to the destination allocation.
|
||||||
|
template<typename T, typename AllocationType>
|
||||||
|
inline void MoveToEmpty(typename AllocationType::template Data<T>& to, typename AllocationType::template Data<T>& from, const int32 fromCount, const int32 fromCapacity)
|
||||||
|
{
|
||||||
|
if IF_CONSTEXPR (AllocationType::HasSwap)
|
||||||
|
to.Swap(from);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
to.Allocate(fromCapacity);
|
||||||
|
Memory::MoveItems(to.Get(), from.Get(), fromCount);
|
||||||
|
Memory::DestructItems(from.Get(), fromCount);
|
||||||
|
from.Free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,15 +91,16 @@ namespace AllocatorExt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Memory
|
class Memory
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs the item in the memory.
|
/// Constructs the item in the memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>The optimized version is noop.</remarks>
|
/// <remarks>The optimized version is noop.</remarks>
|
||||||
/// <param name="dst">The address of the memory location to construct.</param>
|
/// <param name="dst">The address of the memory location to construct.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsTriviallyConstructible<T>::Value>::Type ConstructItem(T* dst)
|
FORCE_INLINE static typename TEnableIf<!TIsTriviallyConstructible<T>::Value>::Type ConstructItem(T* dst)
|
||||||
{
|
{
|
||||||
new(dst) T();
|
new(dst) T();
|
||||||
}
|
}
|
||||||
@@ -110,7 +111,7 @@ namespace Memory
|
|||||||
/// <remarks>The optimized version is noop.</remarks>
|
/// <remarks>The optimized version is noop.</remarks>
|
||||||
/// <param name="dst">The address of the memory location to construct.</param>
|
/// <param name="dst">The address of the memory location to construct.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<TIsTriviallyConstructible<T>::Value>::Type ConstructItem(T* dst)
|
FORCE_INLINE static typename TEnableIf<TIsTriviallyConstructible<T>::Value>::Type ConstructItem(T* dst)
|
||||||
{
|
{
|
||||||
// More undefined behavior! No more clean memory! More performance! Yay!
|
// More undefined behavior! No more clean memory! More performance! Yay!
|
||||||
//Platform::MemoryClear(dst, sizeof(T));
|
//Platform::MemoryClear(dst, sizeof(T));
|
||||||
@@ -123,7 +124,7 @@ namespace Memory
|
|||||||
/// <param name="dst">The address of the first memory location to construct.</param>
|
/// <param name="dst">The address of the first memory location to construct.</param>
|
||||||
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsTriviallyConstructible<T>::Value>::Type ConstructItems(T* dst, int32 count)
|
FORCE_INLINE static typename TEnableIf<!TIsTriviallyConstructible<T>::Value>::Type ConstructItems(T* dst, int32 count)
|
||||||
{
|
{
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
@@ -139,7 +140,7 @@ namespace Memory
|
|||||||
/// <param name="dst">The address of the first memory location to construct.</param>
|
/// <param name="dst">The address of the first memory location to construct.</param>
|
||||||
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<TIsTriviallyConstructible<T>::Value>::Type ConstructItems(T* dst, int32 count)
|
FORCE_INLINE static typename TEnableIf<TIsTriviallyConstructible<T>::Value>::Type ConstructItems(T* dst, int32 count)
|
||||||
{
|
{
|
||||||
// More undefined behavior! No more clean memory! More performance! Yay!
|
// More undefined behavior! No more clean memory! More performance! Yay!
|
||||||
//Platform::MemoryClear(dst, count * sizeof(T));
|
//Platform::MemoryClear(dst, count * sizeof(T));
|
||||||
@@ -153,7 +154,7 @@ namespace Memory
|
|||||||
/// <param name="src">The address of the first memory location to pass to the constructor.</param>
|
/// <param name="src">The address of the first memory location to pass to the constructor.</param>
|
||||||
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsBitwiseConstructible<T, U>::Value>::Type ConstructItems(T* dst, const U* src, int32 count)
|
FORCE_INLINE static typename TEnableIf<!TIsBitwiseConstructible<T, U>::Value>::Type ConstructItems(T* dst, const U* src, int32 count)
|
||||||
{
|
{
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
@@ -171,7 +172,7 @@ namespace Memory
|
|||||||
/// <param name="src">The address of the first memory location to pass to the constructor.</param>
|
/// <param name="src">The address of the first memory location to pass to the constructor.</param>
|
||||||
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
/// <param name="count">The number of element to construct. Can be equal 0.</param>
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
FORCE_INLINE typename TEnableIf<TIsBitwiseConstructible<T, U>::Value>::Type ConstructItems(T* dst, const U* src, int32 count)
|
FORCE_INLINE static typename TEnableIf<TIsBitwiseConstructible<T, U>::Value>::Type ConstructItems(T* dst, const U* src, int32 count)
|
||||||
{
|
{
|
||||||
Platform::MemoryCopy(dst, src, count * sizeof(U));
|
Platform::MemoryCopy(dst, src, count * sizeof(U));
|
||||||
}
|
}
|
||||||
@@ -182,7 +183,7 @@ namespace Memory
|
|||||||
/// <remarks>The optimized version is noop.</remarks>
|
/// <remarks>The optimized version is noop.</remarks>
|
||||||
/// <param name="dst">The address of the memory location to destruct.</param>
|
/// <param name="dst">The address of the memory location to destruct.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsTriviallyDestructible<T>::Value>::Type DestructItem(T* dst)
|
FORCE_INLINE static typename TEnableIf<!TIsTriviallyDestructible<T>::Value>::Type DestructItem(T* dst)
|
||||||
{
|
{
|
||||||
dst->~T();
|
dst->~T();
|
||||||
}
|
}
|
||||||
@@ -193,7 +194,7 @@ namespace Memory
|
|||||||
/// <remarks>The optimized version is noop.</remarks>
|
/// <remarks>The optimized version is noop.</remarks>
|
||||||
/// <param name="dst">The address of the memory location to destruct.</param>
|
/// <param name="dst">The address of the memory location to destruct.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<TIsTriviallyDestructible<T>::Value>::Type DestructItem(T* dst)
|
FORCE_INLINE static typename TEnableIf<TIsTriviallyDestructible<T>::Value>::Type DestructItem(T* dst)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +205,7 @@ namespace Memory
|
|||||||
/// <param name="dst">The address of the first memory location to destruct.</param>
|
/// <param name="dst">The address of the first memory location to destruct.</param>
|
||||||
/// <param name="count">The number of element to destruct. Can be equal 0.</param>
|
/// <param name="count">The number of element to destruct. Can be equal 0.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsTriviallyDestructible<T>::Value>::Type DestructItems(T* dst, int32 count)
|
FORCE_INLINE static typename TEnableIf<!TIsTriviallyDestructible<T>::Value>::Type DestructItems(T* dst, int32 count)
|
||||||
{
|
{
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
@@ -220,7 +221,7 @@ namespace Memory
|
|||||||
/// <param name="dst">The address of the first memory location to destruct.</param>
|
/// <param name="dst">The address of the first memory location to destruct.</param>
|
||||||
/// <param name="count">The number of element to destruct. Can be equal 0.</param>
|
/// <param name="count">The number of element to destruct. Can be equal 0.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<TIsTriviallyDestructible<T>::Value>::Type DestructItems(T* dst, int32 count)
|
FORCE_INLINE static typename TEnableIf<TIsTriviallyDestructible<T>::Value>::Type DestructItems(T* dst, int32 count)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +233,7 @@ namespace Memory
|
|||||||
/// <param name="src">The address of the first memory location to assign from.</param>
|
/// <param name="src">The address of the first memory location to assign from.</param>
|
||||||
/// <param name="count">The number of element to assign. Can be equal 0.</param>
|
/// <param name="count">The number of element to assign. Can be equal 0.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsTriviallyCopyAssignable<T>::Value>::Type CopyItems(T* dst, const T* src, int32 count)
|
FORCE_INLINE static typename TEnableIf<!TIsTriviallyCopyAssignable<T>::Value>::Type CopyItems(T* dst, const T* src, int32 count)
|
||||||
{
|
{
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
@@ -250,7 +251,7 @@ namespace Memory
|
|||||||
/// <param name="src">The address of the first memory location to assign from.</param>
|
/// <param name="src">The address of the first memory location to assign from.</param>
|
||||||
/// <param name="count">The number of element to assign. Can be equal 0.</param>
|
/// <param name="count">The number of element to assign. Can be equal 0.</param>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
FORCE_INLINE typename TEnableIf<TIsTriviallyCopyAssignable<T>::Value>::Type CopyItems(T* dst, const T* src, int32 count)
|
FORCE_INLINE static typename TEnableIf<TIsTriviallyCopyAssignable<T>::Value>::Type CopyItems(T* dst, const T* src, int32 count)
|
||||||
{
|
{
|
||||||
Platform::MemoryCopy(dst, src, count * sizeof(T));
|
Platform::MemoryCopy(dst, src, count * sizeof(T));
|
||||||
}
|
}
|
||||||
@@ -263,11 +264,11 @@ namespace Memory
|
|||||||
/// <param name="src">The address of the first memory location to pass to the move constructor.</param>
|
/// <param name="src">The address of the first memory location to pass to the move constructor.</param>
|
||||||
/// <param name="count">The number of element to move. Can be equal 0.</param>
|
/// <param name="count">The number of element to move. Can be equal 0.</param>
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
FORCE_INLINE typename TEnableIf<!TIsBitwiseConstructible<T, U>::Value>::Type MoveItems(T* dst, const U* src, int32 count)
|
FORCE_INLINE static typename TEnableIf<!TIsBitwiseConstructible<T, U>::Value>::Type MoveItems(T* dst, U* src, int32 count)
|
||||||
{
|
{
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
new(dst) T((T&&)*src);
|
new(dst) T((U&&)*src);
|
||||||
++(T*&)dst;
|
++(T*&)dst;
|
||||||
++src;
|
++src;
|
||||||
}
|
}
|
||||||
@@ -281,11 +282,11 @@ namespace Memory
|
|||||||
/// <param name="src">The address of the first memory location to pass to the move constructor.</param>
|
/// <param name="src">The address of the first memory location to pass to the move constructor.</param>
|
||||||
/// <param name="count">The number of element to move. Can be equal 0.</param>
|
/// <param name="count">The number of element to move. Can be equal 0.</param>
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
FORCE_INLINE typename TEnableIf<TIsBitwiseConstructible<T, U>::Value>::Type MoveItems(T* dst, const U* src, int32 count)
|
FORCE_INLINE static typename TEnableIf<TIsBitwiseConstructible<T, U>::Value>::Type MoveItems(T* dst, U* src, int32 count)
|
||||||
{
|
{
|
||||||
Platform::MemoryCopy(dst, src, count * sizeof(U));
|
Platform::MemoryCopy(dst, src, count * sizeof(U));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new object of the given type.
|
/// Creates a new object of the given type.
|
||||||
|
|||||||
@@ -234,6 +234,12 @@ struct TIsCopyConstructible
|
|||||||
enum { Value = __is_constructible(T, typename TAddLValueReference<typename TAddConst<T>::Type>::Type) };
|
enum { Value = __is_constructible(T, typename TAddLValueReference<typename TAddConst<T>::Type>::Type) };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct TIsMoveConstructible
|
||||||
|
{
|
||||||
|
enum { Value = __is_constructible(T, typename TAddRValueReference<T>::Type) };
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Checks if a type has a trivial copy constructor.
|
// Checks if a type has a trivial copy constructor.
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ namespace
|
|||||||
const MClass* attribute = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEngine.DebugCommand");
|
const MClass* attribute = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEngine.DebugCommand");
|
||||||
ASSERT_LOW_LAYER(attribute);
|
ASSERT_LOW_LAYER(attribute);
|
||||||
const auto& classes = managedModule->Assembly->GetClasses();
|
const auto& classes = managedModule->Assembly->GetClasses();
|
||||||
for (auto e : classes)
|
for (const auto& e : classes)
|
||||||
{
|
{
|
||||||
MClass* mclass = e.Value;
|
MClass* mclass = e.Value;
|
||||||
if (mclass->IsGeneric() ||
|
if (mclass->IsGeneric() ||
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RenderListBuffer"/> class.
|
/// Initializes an empty <see cref="RenderListBuffer"/> without reserving any space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE RenderListBuffer()
|
FORCE_INLINE RenderListBuffer()
|
||||||
: _count(0)
|
: _count(0)
|
||||||
@@ -39,19 +39,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RenderListBuffer"/> class.
|
/// Initializes <see cref="Array"/> by copying elements.
|
||||||
/// </summary>
|
|
||||||
/// <param name="capacity">The initial capacity.</param>
|
|
||||||
explicit RenderListBuffer(const int32 capacity)
|
|
||||||
: _count(0)
|
|
||||||
, _capacity(capacity)
|
|
||||||
{
|
|
||||||
if (capacity > 0)
|
|
||||||
_allocation.Allocate(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="RenderListBuffer"/> class.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The initial data.</param>
|
/// <param name="data">The initial data.</param>
|
||||||
/// <param name="length">The amount of items.</param>
|
/// <param name="length">The amount of items.</param>
|
||||||
@@ -369,17 +357,6 @@ private:
|
|||||||
{
|
{
|
||||||
// Ensure there is a slack for others threads to reduce resize counts in highly multi-threaded environment
|
// Ensure there is a slack for others threads to reduce resize counts in highly multi-threaded environment
|
||||||
constexpr int32 slack = PLATFORM_THREADS_LIMIT * 8;
|
constexpr int32 slack = PLATFORM_THREADS_LIMIT * 8;
|
||||||
int32 capacity = count + slack;
|
return AllocationUtils::RoundUpToPowerOf2(count + slack);
|
||||||
{
|
|
||||||
// Round up to the next power of 2 and multiply by 2
|
|
||||||
capacity--;
|
|
||||||
capacity |= capacity >> 1;
|
|
||||||
capacity |= capacity >> 2;
|
|
||||||
capacity |= capacity >> 4;
|
|
||||||
capacity |= capacity >> 8;
|
|
||||||
capacity |= capacity >> 16;
|
|
||||||
capacity = (capacity + 1) * 2;
|
|
||||||
}
|
|
||||||
return capacity;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -335,17 +335,17 @@ void MCore::UnloadEngine()
|
|||||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
void MCore::ReloadScriptingAssemblyLoadContext()
|
||||||
{
|
{
|
||||||
// Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108)
|
// Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108)
|
||||||
for (auto e : CachedClassHandles)
|
for (const auto& e : CachedClassHandles)
|
||||||
{
|
{
|
||||||
e.Value->_hasCachedAttributes = false;
|
e.Value->_hasCachedAttributes = false;
|
||||||
e.Value->_attributes.Clear();
|
e.Value->_attributes.Clear();
|
||||||
}
|
}
|
||||||
for (auto e : CachedAssemblyHandles)
|
for (const auto& e : CachedAssemblyHandles)
|
||||||
{
|
{
|
||||||
MAssembly* a = e.Value;
|
MAssembly* a = e.Value;
|
||||||
if (!a->IsLoaded() || !a->_hasCachedClasses)
|
if (!a->IsLoaded() || !a->_hasCachedClasses)
|
||||||
continue;
|
continue;
|
||||||
for (auto q : a->GetClasses())
|
for (const auto& q : a->GetClasses())
|
||||||
{
|
{
|
||||||
MClass* c = q.Value;
|
MClass* c = q.Value;
|
||||||
c->_hasCachedAttributes = false;
|
c->_hasCachedAttributes = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user