diff --git a/Source/Engine/Content/Assets/Animation.cpp b/Source/Engine/Content/Assets/Animation.cpp
index b2de85bee..226074a72 100644
--- a/Source/Engine/Content/Assets/Animation.cpp
+++ b/Source/Engine/Content/Assets/Animation.cpp
@@ -83,7 +83,7 @@ void Animation::ClearCache()
// Free memory
MappingCache.Clear();
- MappingCache.Cleanup();
+ MappingCache.SetCapacity(0);
}
const Animation::NodeToChannel* Animation::GetMapping(SkinnedModel* obj)
diff --git a/Source/Engine/Core/Collections/Dictionary.h b/Source/Engine/Core/Collections/Dictionary.h
index ae88d378b..2de3cecc9 100644
--- a/Source/Engine/Core/Collections/Dictionary.h
+++ b/Source/Engine/Core/Collections/Dictionary.h
@@ -378,10 +378,10 @@ public:
// Insert
ASSERT(pos.FreeSlotIndex != -1);
- auto bucket = &_allocation.Get()[pos.FreeSlotIndex];
- bucket->Occupy(key);
+ Bucket& bucket = _allocation.Get()[pos.FreeSlotIndex];
+ bucket.Occupy(key);
_elementsCount++;
- return bucket->Value;
+ return bucket.Value;
}
///
@@ -481,7 +481,7 @@ public:
#endif
void ClearDelete()
{
- for (auto i = Begin(); i.IsNotEnd(); ++i)
+ for (Iterator i = Begin(); i.IsNotEnd(); ++i)
{
if (i->Value)
Delete(i->Value);
@@ -555,14 +555,6 @@ public:
SetCapacity(capacity, preserveContents);
}
- ///
- /// Cleanup collection data (changes size to 0 without data preserving).
- ///
- FORCE_INLINE void Cleanup()
- {
- SetCapacity(0, false);
- }
-
///
/// Swaps the contents of collection with the other object without copy operation. Performs fast internal data exchange.
///
@@ -640,7 +632,7 @@ public:
void Add(const Iterator& i)
{
ASSERT(&i._collection != this && i);
- Bucket& bucket = *i;
+ const Bucket& bucket = *i;
Add(bucket.Key, bucket.Value);
}
@@ -693,7 +685,7 @@ public:
int32 RemoveValue(const ValueType& value)
{
int32 result = 0;
- for (auto i = Begin(); i.IsNotEnd(); ++i)
+ for (Iterator i = Begin(); i.IsNotEnd(); ++i)
{
if (i->Value == value)
{
@@ -714,16 +706,11 @@ public:
template
Iterator Find(const KeyComparableType& key) const
{
- if (HasItems())
- {
- const Bucket* data = _allocation.Get();
- for (int32 i = 0; i < _size; i++)
- {
- if (data[i].IsOccupied() && data[i].Key == key)
- return Iterator(*this, i);
- }
- }
- return End();
+ if (IsEmpty())
+ return End();
+ FindPositionResult pos;
+ FindPosition(key, pos);
+ return pos.ObjectIndex != -1 ? Iterator(*this, pos.ObjectIndex) : End();
}
///
@@ -794,7 +781,7 @@ public:
{
Clear();
SetCapacity(other.Capacity(), false);
- for (auto i = other.Begin(); i != other.End(); ++i)
+ for (Iterator i = other.Begin(); i != other.End(); ++i)
Add(i);
ASSERT(Count() == other.Count());
ASSERT(Capacity() == other.Capacity());
@@ -807,7 +794,7 @@ public:
template
void GetKeys(Array& result) const
{
- for (auto i = Begin(); i.IsNotEnd(); ++i)
+ for (Iterator i = Begin(); i.IsNotEnd(); ++i)
result.Add(i->Key);
}
@@ -818,7 +805,7 @@ public:
template
void GetValues(Array& result) const
{
- for (auto i = Begin(); i.IsNotEnd(); ++i)
+ for (Iterator i = Begin(); i.IsNotEnd(); ++i)
result.Add(i->Value);
}
@@ -893,7 +880,7 @@ protected:
while (checksCount < _size)
{
// Empty bucket
- auto& bucket = data[bucketIndex];
+ const Bucket& bucket = data[bucketIndex];
if (bucket.IsEmpty())
{
// Found place to insert
diff --git a/Source/Engine/Core/Collections/HashSet.h b/Source/Engine/Core/Collections/HashSet.h
index 5d105bcae..eb10a5015 100644
--- a/Source/Engine/Core/Collections/HashSet.h
+++ b/Source/Engine/Core/Collections/HashSet.h
@@ -2,78 +2,62 @@
#pragma once
-#include "Engine/Core/Core.h"
-#include "Engine/Core/Math/Math.h"
-#include "Engine/Platform/Platform.h"
-#include "HashFunctions.h"
-#include "Config.h"
+#include "Engine/Core/Memory/Memory.h"
+#include "Engine/Core/Memory/Allocation.h"
+#include "Engine/Core/Collections/HashFunctions.h"
+#include "Engine/Core/Collections/Config.h"
///
/// Template for unordered set of values (without duplicates with O(1) lookup access).
///
/// The type of elements in the set.
-template
+/// The type of memory allocator.
+template
API_CLASS(InBuild) class HashSet
{
friend HashSet;
-
public:
///
- /// Describes single portion of space for the item in a hash map
+ /// Describes single portion of space for the item in a hash map.
///
struct Bucket
{
friend HashSet;
- public:
-
enum State : byte
{
Empty,
Deleted,
Occupied,
};
-
- public:
-
+
+ /// The item.
T Item;
private:
-
State _state;
- public:
-
- Bucket()
- : _state(Empty)
- {
- }
-
- ~Bucket()
- {
- }
-
- public:
-
void Free()
{
+ if (_state == Occupied)
+ Memory::DestructItem(&Item);
_state = Empty;
}
void Delete()
{
_state = Deleted;
+ Memory::DestructItem(&Item);
}
- void Occupy(const T& item)
+ template
+ void Occupy(const ItemType& item)
{
- Item = item;
+ Memory::ConstructItems(&Item, &item, 1);
_state = Occupied;
}
- public:
-
FORCE_INLINE bool IsEmpty() const
{
return _state == Empty;
@@ -94,13 +78,15 @@ public:
return _state != Occupied;
}
};
+
+ typedef typename AllocationType::template Data AllocationData;
private:
int32 _elementsCount = 0;
int32 _deletedCount = 0;
- int32 _tableSize = 0;
- Bucket* _table = nullptr;
+ int32 _size = 0;
+ AllocationData _allocation;
public:
@@ -117,10 +103,27 @@ public:
/// The initial capacity.
HashSet(int32 capacity)
{
- ASSERT(capacity >= 0);
SetCapacity(capacity);
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The other collection to move.
+ HashSet(HashSet&& other) noexcept
+ : _elementsCount(other._elementsCount)
+ , _deletedCount(other._deletedCount)
+ , _size(other._size)
+ {
+ _elementsCount = other._elementsCount;
+ _deletedCount = other._deletedCount;
+ _size = other._size;
+ other._elementsCount = 0;
+ other._deletedCount = 0;
+ other._size = 0;
+ _allocation.Swap(other._allocation);
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -137,18 +140,39 @@ public:
/// The reference to this.
HashSet& operator=(const HashSet& other)
{
- // Ensure we're not trying to set to itself
if (this != &other)
Clone(other);
return *this;
}
+ ///
+ /// Moves the data from the other collection.
+ ///
+ /// The other collection to move.
+ /// The reference to this.
+ HashSet& operator=(HashSet&& other) noexcept
+ {
+ if (this != &other)
+ {
+ Clear();
+ _allocation.Free();
+ _elementsCount = other._elementsCount;
+ _deletedCount = other._deletedCount;
+ _size = other._size;
+ other._elementsCount = 0;
+ other._deletedCount = 0;
+ other._size = 0;
+ _allocation.Swap(other._allocation);
+ }
+ return *this;
+ }
+
///
/// Finalizes an instance of the class.
///
~HashSet()
{
- Cleanup();
+ SetCapacity(0, false);
}
public:
@@ -156,7 +180,6 @@ public:
///
/// Gets the amount of the elements in the collection.
///
- /// The amount of elements in the collection.
FORCE_INLINE int32 Count() const
{
return _elementsCount;
@@ -165,16 +188,14 @@ public:
///
/// Gets the amount of the elements that can be contained by the collection.
///
- /// The capacity of the collection.
FORCE_INLINE int32 Capacity() const
{
- return _tableSize;
+ return _size;
}
///
/// Returns true if collection is empty.
///
- /// True if is empty, otherwise false.
FORCE_INLINE bool IsEmpty() const
{
return _elementsCount == 0;
@@ -183,7 +204,6 @@ public:
///
/// Returns true if collection has one or more elements.
///
- /// True if isn't empty, otherwise false.
FORCE_INLINE bool HasItems() const
{
return _elementsCount != 0;
@@ -197,9 +217,7 @@ public:
struct Iterator
{
friend HashSet;
-
private:
-
HashSet& _collection;
int32 _index;
@@ -223,41 +241,37 @@ public:
{
}
+ Iterator(Iterator&& i)
+ : _collection(i._collection)
+ , _index(i._index)
+ {
+ }
+
public:
- ///
- /// Checks if iterator is in the end of the collection
- ///
- /// True if is in the end, otherwise false
FORCE_INLINE bool IsEnd() const
{
return _index == _collection.Capacity();
}
- ///
- /// Checks if iterator is not in the end of the collection
- ///
- /// True if is not in the end, otherwise false
FORCE_INLINE bool IsNotEnd() const
{
return _index != _collection.Capacity();
}
- public:
-
FORCE_INLINE Bucket& operator*() const
{
- return _collection._table[_index];
+ return _collection._allocation.Get()[_index];
}
FORCE_INLINE Bucket* operator->() const
{
- return &_collection._table[_index];
+ return &_collection._allocation.Get()[_index];
}
FORCE_INLINE explicit operator bool() const
{
- return _index >= 0 && _index < _collection._tableSize;
+ return _index >= 0 && _index < _collection._size;
}
FORCE_INLINE bool operator !() const
@@ -275,17 +289,16 @@ public:
return _index != v._index || &_collection != &v._collection;
}
- public:
-
Iterator& operator++()
{
const int32 capacity = _collection.Capacity();
if (_index != capacity)
{
+ const Bucket* data = _collection._allocation.Get();
do
{
_index++;
- } while (_index != capacity && _collection._table[_index].IsNotOccupied());
+ } while (_index != capacity && data[_index].IsNotOccupied());
}
return *this;
}
@@ -301,10 +314,11 @@ public:
{
if (_index > 0)
{
+ const Bucket* data = _collection._allocation.Get();
do
{
_index--;
- } while (_index > 0 && _collection._table[_index].IsNotOccupied());
+ } while (_index > 0 && data[_index].IsNotOccupied());
}
return *this;
}
@@ -324,22 +338,25 @@ public:
///
void Clear()
{
- if (_table)
+ if (_elementsCount + _deletedCount != 0)
{
- // Free all buckets
- // Note: this will not clear allocated objects space!
- for (int32 i = 0; i < _tableSize; i++)
- _table[i].Free();
+ Bucket* data = _allocation.Get();
+ for (int32 i = 0; i < _size; i++)
+ data[i].Free();
_elementsCount = _deletedCount = 0;
}
}
///
- /// Clear the collection and delete value objects.
+ /// Clears the collection and delete value objects.
+ /// Note: collection must contain pointers to the objects that have public destructor and be allocated using New method.
///
+#if defined(_MSC_VER)
+ template::Value>::Type>
+#endif
void ClearDelete()
{
- for (auto i = Begin(); i.IsNotEnd(); ++i)
+ for (Iterator i = Begin(); i.IsNotEnd(); ++i)
{
if (i->Value)
::Delete(i->Value);
@@ -354,86 +371,63 @@ public:
/// Enable/disable preserving collection contents during resizing
void SetCapacity(int32 capacity, bool preserveContents = true)
{
- // Validate input
- ASSERT(capacity >= 0);
-
- // Check if capacity won't change
if (capacity == Capacity())
return;
-
- // Cache previous state
- auto oldTable = _table;
- auto oldTableSize = _tableSize;
-
- // Clear elements counters
- const auto oldElementsCount = _elementsCount;
+ ASSERT(capacity >= 0);
+ AllocationData oldAllocation;
+ oldAllocation.Swap(_allocation);
+ const int32 oldSize = _size;
+ const int32 oldElementsCount = _elementsCount;
_deletedCount = _elementsCount = 0;
-
- // Check if need to create a new table
- if (capacity > 0)
+ if (capacity != 0 && (capacity & (capacity - 1)) != 0)
{
- // Align capacity value
- if (Math::IsPowerOfTwo(capacity) == false)
- capacity = Math::RoundUpToPowerOf2(capacity);
-
- // Allocate new table
- _table = NewArray(capacity);
- _tableSize = capacity;
-
- // Check if preserve content
- if (oldElementsCount != 0 && preserveContents)
+ // Align capacity value to the next power of two (if it's not)
+ capacity++;
+ capacity |= capacity >> 1;
+ capacity |= capacity >> 2;
+ capacity |= capacity >> 4;
+ capacity |= capacity >> 8;
+ capacity |= capacity >> 16;
+ capacity = capacity + 1;
+ }
+ if (capacity)
+ {
+ _allocation.Allocate(capacity);
+ Bucket* data = _allocation.Get();
+ for (int32 i = 0; i < capacity; i++)
+ data[i]._state = Bucket::Empty;
+ }
+ _size = capacity;
+ Bucket* oldData = oldAllocation.Get();
+ if (oldElementsCount != 0 && preserveContents)
+ {
+ // TODO; move keys and values on realloc
+ for (int32 i = 0; i < oldSize; i++)
{
- // Try to preserve all values in the collection
- for (int32 i = 0; i < oldTableSize; i++)
- {
- if (oldTable[i].IsOccupied())
- Add(oldTable[i].Item);
- }
+ if (oldData[i].IsOccupied())
+ Add(oldData[i].Item);
}
}
- else
+ if (oldElementsCount != 0)
{
- // Clear data
- _table = nullptr;
- _tableSize = 0;
- }
- ASSERT(preserveContents == false || _elementsCount == oldElementsCount);
-
- // Delete old table
- if (oldTable)
- {
- DeleteArray(oldTable, oldTableSize);
+ for (int32 i = 0; i < oldSize; i++)
+ oldData[i].Free();
}
}
///
- /// Increases collection capacity by given extra size (content will be preserved)
+ /// Ensures that collection has given capacity.
///
- /// Extra size to enlarge collection
- FORCE_INLINE void IncreaseCapacity(int32 extraSize)
- {
- ASSERT(extraSize >= 0);
- SetCapacity(Capacity() + extraSize);
- }
-
- ///
- /// Ensures that collection has given capacity
- ///
- /// Minimum required capacity
- void EnsureCapacity(int32 minCapacity)
+ /// The minimum required capacity.
+ /// True if preserve collection data when changing its size, otherwise collection after resize will be empty.
+ void EnsureCapacity(int32 minCapacity, bool preserveContents = true)
{
if (Capacity() >= minCapacity)
return;
- int32 num = Capacity() == 0 ? DICTIONARY_DEFAULT_CAPACITY : Capacity() * 2;
- SetCapacity(Math::Clamp(num, minCapacity, MAX_int32 - 1410));
- }
-
- ///
- /// Cleanup collection data (changes size to 0 without data preserving)
- ///
- FORCE_INLINE void Cleanup()
- {
- SetCapacity(0, false);
+ if (minCapacity < DICTIONARY_DEFAULT_CAPACITY)
+ minCapacity = DICTIONARY_DEFAULT_CAPACITY;
+ const int32 capacity = _allocation.CalculateCapacityGrow(_size, minCapacity);
+ SetCapacity(capacity, preserveContents);
}
public:
@@ -443,7 +437,8 @@ public:
///
/// The element to add to the set.
/// True if element has been added to the collection, otherwise false if the element is already present.
- bool Add(const T& item)
+ template
+ bool Add(const ItemType& item)
{
// Ensure to have enough memory for the next item (in case of new element insertion)
EnsureCapacity(_elementsCount + _deletedCount + 1);
@@ -453,12 +448,12 @@ public:
FindPosition(item, pos);
// Check if object has been already added
- if (pos.ObjectIndex != INVALID_INDEX)
+ if (pos.ObjectIndex != -1)
return false;
// Insert
- ASSERT(pos.FreeSlotIndex != INVALID_INDEX);
- auto bucket = &_table[pos.FreeSlotIndex];
+ ASSERT(pos.FreeSlotIndex != -1);
+ Bucket* bucket = &_allocation.Get()[pos.FreeSlotIndex];
bucket->Occupy(item);
_elementsCount++;
@@ -472,7 +467,7 @@ public:
void Add(const Iterator& i)
{
ASSERT(&i._collection != this && i);
- Bucket& bucket = *i;
+ const Bucket& bucket = *i;
Add(bucket.Item);
}
@@ -481,22 +476,20 @@ public:
///
/// The element to remove.
/// True if cannot remove item from the collection because cannot find it, otherwise false.
- bool Remove(const T& item)
+ template
+ bool Remove(const ItemType& item)
{
if (IsEmpty())
return true;
-
FindPositionResult pos;
FindPosition(item, pos);
-
- if (pos.ObjectIndex != INVALID_INDEX)
+ if (pos.ObjectIndex != -1)
{
- _table[pos.ObjectIndex].Delete();
+ _allocation.Get()[pos.ObjectIndex].Delete();
_elementsCount--;
_deletedCount++;
return true;
}
-
return false;
}
@@ -510,8 +503,8 @@ public:
ASSERT(&i._collection == this);
if (i)
{
- ASSERT(_table[i._index].IsOccupied());
- _table[i._index].Delete();
+ ASSERT(_allocation.Get()[i._index].IsOccupied());
+ _allocation.Get()[i._index].Delete();
_elementsCount--;
_deletedCount++;
return true;
@@ -526,15 +519,14 @@ public:
///
/// Item to find
/// Iterator for the found element or End if cannot find it
- Iterator Find(const T& item) const
+ template
+ Iterator Find(const ItemType& item) const
{
if (IsEmpty())
return End();
-
FindPositionResult pos;
FindPosition(item, pos);
-
- return pos.ObjectIndex != INVALID_INDEX ? Iterator(*this, pos.ObjectIndex) : End();
+ return pos.ObjectIndex != -1 ? Iterator(*this, pos.ObjectIndex) : End();
}
///
@@ -542,15 +534,14 @@ public:
///
/// The item to locate.
/// True if value has been found in a collection, otherwise false
- bool Contains(const T& item) const
+ template
+ bool Contains(const ItemType& item) const
{
if (IsEmpty())
return false;
-
FindPositionResult pos;
FindPosition(item, pos);
-
- return pos.ObjectIndex != INVALID_INDEX;
+ return pos.ObjectIndex != -1;
}
public:
@@ -561,41 +552,26 @@ public:
/// Other collection to clone
void Clone(const HashSet& other)
{
- // Clear previous data
Clear();
-
- // Update capacity
SetCapacity(other.Capacity(), false);
-
- // Clone items
- for (auto i = other.Begin(); i != other.End(); ++i)
+ for (Iterator i = other.Begin(); i != other.End(); ++i)
Add(i);
-
- // Check
ASSERT(Count() == other.Count());
ASSERT(Capacity() == other.Capacity());
}
public:
- ///
- /// Gets iterator for beginning of the collection.
- ///
- /// Iterator for beginning of the collection.
Iterator Begin() const
{
- Iterator i(*this, INVALID_INDEX);
+ Iterator i(*this, -1);
++i;
return i;
}
- ///
- /// Gets iterator for ending of the collection.
- ///
- /// Iterator for ending of the collection.
Iterator End() const
{
- return Iterator(*this, _tableSize);
+ return Iterator(*this, _size);
}
Iterator begin()
@@ -607,7 +583,7 @@ public:
FORCE_INLINE Iterator end()
{
- return Iterator(*this, _tableSize);
+ return Iterator(*this, _size);
}
const Iterator begin() const
@@ -619,11 +595,14 @@ public:
FORCE_INLINE const Iterator end() const
{
- return Iterator(*this, _tableSize);
+ return Iterator(*this, _size);
}
protected:
+ ///
+ /// The result container of the set item lookup searching.
+ ///
struct FindPositionResult
{
int32 ObjectIndex;
@@ -632,42 +611,43 @@ protected:
///
/// Returns a pair of positions: 1st where the object is, 2nd where
- /// it would go if you wanted to insert it. 1st is INVALID_INDEX
- /// if object is not found; 2nd is INVALID_INDEX if it is.
+ /// it would go if you wanted to insert it. 1st is -1
+ /// if object is not found; 2nd is -1 if it is.
/// Note: because of deletions where-to-insert is not trivial: it's the
/// first deleted bucket we see, as long as we don't find the item later
///
/// The item to find
/// Pair of values: where the object is and where it would go if you wanted to insert it
- void FindPosition(const T& item, FindPositionResult& result) const
+ template
+ void FindPosition(const ItemType& item, FindPositionResult& result) const
{
- ASSERT(_table);
-
- const int32 tableSizeMinusOne = _tableSize - 1;
+ ASSERT(_size);
+ const int32 tableSizeMinusOne = _size - 1;
int32 bucketIndex = GetHash(item) & tableSizeMinusOne;
- int32 insertPos = INVALID_INDEX;
+ int32 insertPos = -1;
int32 numChecks = 0;
- result.FreeSlotIndex = INVALID_INDEX;
-
- while (numChecks < _tableSize)
+ const Bucket* data = _allocation.Get();
+ result.FreeSlotIndex = -1;
+ while (numChecks < _size)
{
// Empty bucket
- if (_table[bucketIndex].IsEmpty())
+ const Bucket& bucket = data[bucketIndex];
+ if (bucket.IsEmpty())
{
// Found place to insert
- result.ObjectIndex = INVALID_INDEX;
- result.FreeSlotIndex = insertPos == INVALID_INDEX ? bucketIndex : insertPos;
+ result.ObjectIndex = -1;
+ result.FreeSlotIndex = insertPos == -1 ? bucketIndex : insertPos;
return;
}
// Deleted bucket
- if (_table[bucketIndex].IsDeleted())
+ if (bucket.IsDeleted())
{
// Keep searching but mark to insert
- if (insertPos == INVALID_INDEX)
+ if (insertPos == -1)
insertPos = bucketIndex;
}
// Occupied bucket by target item
- else if (_table[bucketIndex].Item == item)
+ else if (bucket.Item == item)
{
// Found item
result.ObjectIndex = bucketIndex;
@@ -675,10 +655,9 @@ protected:
}
numChecks++;
- bucketIndex = (bucketIndex + DICTIONARY_PROB_FUNC(_tableSize, numChecks)) & tableSizeMinusOne;
+ bucketIndex = (bucketIndex + DICTIONARY_PROB_FUNC(_size, numChecks)) & tableSizeMinusOne;
}
-
- result.ObjectIndex = INVALID_INDEX;
+ result.ObjectIndex = -1;
result.FreeSlotIndex = insertPos;
}
};
diff --git a/Source/Engine/Particles/ParticleSystem.cpp b/Source/Engine/Particles/ParticleSystem.cpp
index 6a1f32327..745bca545 100644
--- a/Source/Engine/Particles/ParticleSystem.cpp
+++ b/Source/Engine/Particles/ParticleSystem.cpp
@@ -461,7 +461,7 @@ void ParticleSystem::unload(bool isReloading)
FramesPerSecond = 0.0f;
DurationFrames = 0;
Emitters.Resize(0);
- EmittersParametersOverrides.Cleanup();
+ EmittersParametersOverrides.SetCapacity(0);
Tracks.Resize(0);
}
diff --git a/Source/flax.natvis b/Source/flax.natvis
index 4cc1397d8..a38626357 100644
--- a/Source/flax.natvis
+++ b/Source/flax.natvis
@@ -61,24 +61,24 @@
-
+
- {{ Size={_elementsCount} Capacity={_tableSize} }}
-
- - _elementsCount
- - _tableSize
-
-
- _elementsCount
-
-
-
- - _table[i]
-
- i++
-
-
-
+ {{ Size={_elementsCount} Capacity={_size} }}
+
+ - _elementsCount
+ - _size
+
+
+ _elementsCount
+
+
+
+ - _allocation._data[i].Item
+
+ i++
+
+
+