Merge branch 'development' into cmake/SPEC-7484
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Code/Editor/CryEditDoc.cpp # Code/Editor/CryEditDoc.h # Code/Legacy/CryCommon/CryArray.h # Code/Legacy/CryCommon/CryString.h # Code/Legacy/CryCommon/UnicodeBinding.h # Code/Legacy/CrySystem/LocalizedStringManager.cpp # Gems/LyShine/Code/Source/StringUtfUtils.h # Gems/PhysXDebug/Code/Source/SystemComponent.cpp
This commit is contained in:
@@ -47,7 +47,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
auto stackEntry = AZStd::make_shared<BlockCache>(
|
||||
cacheSize, blockSize, aznumeric_caster(hardware.m_maxPhysicalSectorSize), false);
|
||||
cacheSize, aznumeric_cast<AZ::u32>(blockSize), aznumeric_cast<AZ::u32>(hardware.m_maxPhysicalSectorSize), false);
|
||||
stackEntry->SetNext(AZStd::move(parent));
|
||||
return stackEntry;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
auto stackEntry = AZStd::make_shared<DedicatedCache>(
|
||||
cacheSize, blockSize, aznumeric_caster(hardware.m_maxPhysicalSectorSize), m_writeOnlyEpilog);
|
||||
cacheSize, aznumeric_cast<AZ::u32>(blockSize), aznumeric_cast<AZ::u32>(hardware.m_maxPhysicalSectorSize), m_writeOnlyEpilog);
|
||||
stackEntry->SetNext(AZStd::move(parent));
|
||||
return stackEntry;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace AZ
|
||||
static Aabb CreateCenterRadius(const Vector3& center, float radius);
|
||||
|
||||
//! Creates an AABB which contains the specified points.
|
||||
static Aabb CreatePoints(const Vector3* pts, int numPts);
|
||||
static Aabb CreatePoints(const Vector3* pts, size_t numPts);
|
||||
|
||||
//! Creates an AABB which contains the specified OBB.
|
||||
static Aabb CreateFromObb(const Obb& obb);
|
||||
|
||||
@@ -60,10 +60,10 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Aabb Aabb::CreatePoints(const Vector3* pts, int numPts)
|
||||
AZ_MATH_INLINE Aabb Aabb::CreatePoints(const Vector3* pts, size_t numPts)
|
||||
{
|
||||
Aabb aabb = Aabb::CreateFromPoint(pts[0]);
|
||||
for (int i = 1; i < numPts; ++i)
|
||||
for (size_t i = 1; i < numPts; ++i)
|
||||
{
|
||||
aabb.AddPoint(pts[i]);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -75,6 +76,42 @@ namespace AZ
|
||||
bool operator==(const OSStdAllocator& a, const OSStdAllocator& b) { (void)a; (void)b; return true; }
|
||||
bool operator!=(const OSStdAllocator& a, const OSStdAllocator& b) { (void)a; (void)b; return false; }
|
||||
|
||||
void EnvironmentVariableHolderBase::UnregisterAndDestroy(DestructFunc destruct, bool moduleRelease)
|
||||
{
|
||||
const bool releaseByUseCount = (--m_useCount == 0);
|
||||
// We take over the lock, and release it before potentially destroying/freeing ourselves
|
||||
{
|
||||
AZStd::scoped_lock envLockHolder(AZStd::adopt_lock, m_mutex);
|
||||
const bool releaseByModule = (moduleRelease && !m_canTransferOwnership && m_moduleOwner == AZ::Environment::GetModuleId());
|
||||
|
||||
if (!releaseByModule && !releaseByUseCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// if the environment that created us is gone the owner can be null
|
||||
// which means (assuming intermodule allocator) that the variable is still alive
|
||||
// but can't be found as it's not part of any environment.
|
||||
if (m_environmentOwner)
|
||||
{
|
||||
m_environmentOwner->RemoveVariable(m_guid);
|
||||
m_environmentOwner = nullptr;
|
||||
}
|
||||
if (m_isConstructed)
|
||||
{
|
||||
destruct(this, DestroyTarget::Member); // destruct the value
|
||||
}
|
||||
}
|
||||
// m_mutex is no longer held here, envLockHolder has released it above.
|
||||
if (releaseByUseCount)
|
||||
{
|
||||
// m_mutex is unlocked before this is deleted
|
||||
Environment::AllocatorInterface* allocator = m_allocator;
|
||||
// Call child class dtor and clear the memory
|
||||
destruct(this, DestroyTarget::Self);
|
||||
allocator->DeAllocate(this);
|
||||
}
|
||||
}
|
||||
|
||||
// instance of the environment
|
||||
EnvironmentInterface* EnvironmentInterface::s_environment = nullptr;
|
||||
|
||||
@@ -110,7 +147,7 @@ namespace AZ
|
||||
#ifdef AZ_ENVIRONMENT_VALIDATE_ON_EXIT
|
||||
AZ_Assert(m_numAttached == 0, "We should not delete an environment while there are %d modules attached! Unload all DLLs first!", m_numAttached);
|
||||
#endif
|
||||
|
||||
|
||||
for (auto variableIt : m_variableMap)
|
||||
{
|
||||
EnvironmentVariableHolderBase* holder = reinterpret_cast<EnvironmentVariableHolderBase*>(variableIt.second);
|
||||
|
||||
@@ -200,6 +200,11 @@ namespace AZ
|
||||
class EnvironmentVariableHolderBase
|
||||
{
|
||||
friend class EnvironmentImpl;
|
||||
protected:
|
||||
enum class DestroyTarget {
|
||||
Member,
|
||||
Self
|
||||
};
|
||||
public:
|
||||
EnvironmentVariableHolderBase(u32 guid, AZ::Internal::EnvironmentInterface* environmentOwner, bool canOwnershipTransfer, Environment::AllocatorInterface* allocator)
|
||||
: m_environmentOwner(environmentOwner)
|
||||
@@ -217,12 +222,21 @@ namespace AZ
|
||||
return m_isConstructed;
|
||||
}
|
||||
|
||||
bool IsOwner() const
|
||||
{
|
||||
return m_moduleOwner == Environment::GetModuleId();
|
||||
}
|
||||
|
||||
u32 GetId() const
|
||||
{
|
||||
return m_guid;
|
||||
}
|
||||
|
||||
protected:
|
||||
using DestructFunc = void (*)(EnvironmentVariableHolderBase *, DestroyTarget);
|
||||
// Assumes the m_mutex is already locked.
|
||||
// On return m_mutex is in an unlocked state.
|
||||
void UnregisterAndDestroy(DestructFunc destruct, bool moduleRelease);
|
||||
|
||||
AZ::Internal::EnvironmentInterface* m_environmentOwner; ///< Used to know which environment we should use to free the variable if we can't transfer ownership
|
||||
void* m_moduleOwner; ///< Used when the variable can't transfered across module and we need to destruct the variable when the module is going away
|
||||
bool m_canTransferOwnership; ///< True if variable can be allocated in one module and freed in other. Usually true for POD types when they share allocator.
|
||||
@@ -242,41 +256,29 @@ namespace AZ
|
||||
memset(&m_value, 0, sizeof(T));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
template<class... Args>
|
||||
void ConstructImpl(const AZStd::false_type& /* AZStd::has_trivial_constructor<T> */, Args&&... args)
|
||||
{
|
||||
// Construction of non-trivial types is left up to the type's constructor.
|
||||
new(&m_value) T(AZStd::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void DestructImpl(const AZStd::true_type& /* AZStd::is_trivially_destructible<T> */)
|
||||
static void DestructDispatchNoLock(EnvironmentVariableHolderBase *base, DestroyTarget selfDestruct)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void DestructImpl(const AZStd::false_type& /* AZStd::is_trivially_destructible<T> */)
|
||||
{
|
||||
reinterpret_cast<T*>(&m_value)->~T();
|
||||
}
|
||||
|
||||
// Assumes the lock is already held
|
||||
void UnregisterAndDestruct()
|
||||
{
|
||||
// if the environment that created us is gone the owner can be null
|
||||
// which means (assuming intermodule allocator) that the variable is still alive
|
||||
// but can't be found as it's not part of any environment.
|
||||
if (m_environmentOwner)
|
||||
auto *self = reinterpret_cast<EnvironmentVariableHolder *>(base);
|
||||
if (selfDestruct == DestroyTarget::Self)
|
||||
{
|
||||
m_environmentOwner->RemoveVariable(m_guid);
|
||||
m_environmentOwner = nullptr;
|
||||
self->~EnvironmentVariableHolder();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_isConstructed)
|
||||
AZ_Assert(self->m_isConstructed, "Variable is not constructed. Please check your logic and guard if needed!");
|
||||
self->m_isConstructed = false;
|
||||
self->m_moduleOwner = nullptr;
|
||||
if constexpr(!AZStd::is_trivially_destructible_v<T>)
|
||||
{
|
||||
DestructNoLock();
|
||||
reinterpret_cast<T*>(&self->m_value)->~T();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
EnvironmentVariableHolder(u32 guid, bool isOwnershipTransfer, Environment::AllocatorInterface* allocator)
|
||||
: EnvironmentVariableHolderBase(guid, Environment::GetInstance(), isOwnershipTransfer, allocator)
|
||||
@@ -287,12 +289,6 @@ namespace AZ
|
||||
{
|
||||
AZ_Assert(!m_isConstructed, "To get the destructor we should have already destructed the variable!");
|
||||
}
|
||||
|
||||
bool IsOwner() const
|
||||
{
|
||||
return m_moduleOwner == Environment::GetModuleId();
|
||||
}
|
||||
|
||||
void AddRef()
|
||||
{
|
||||
AZStd::lock_guard<AZStd::spin_mutex> lock(m_mutex);
|
||||
@@ -303,30 +299,8 @@ namespace AZ
|
||||
void Release()
|
||||
{
|
||||
m_mutex.lock();
|
||||
|
||||
if (--s_moduleUseCount == 0)
|
||||
{
|
||||
if (!m_canTransferOwnership && m_moduleOwner == AZ::Environment::GetModuleId())
|
||||
{
|
||||
UnregisterAndDestruct();
|
||||
}
|
||||
}
|
||||
|
||||
if (--m_useCount == 0)
|
||||
{
|
||||
UnregisterAndDestruct();
|
||||
|
||||
// unlock before this is deleted
|
||||
m_mutex.unlock();
|
||||
|
||||
Environment::AllocatorInterface* allocator = m_allocator;
|
||||
// Call dtor and clear the memory
|
||||
this->~EnvironmentVariableHolder();
|
||||
allocator->DeAllocate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
const bool moduleRelease = (--s_moduleUseCount == 0);
|
||||
UnregisterAndDestroy(DestructDispatchNoLock, moduleRelease);
|
||||
}
|
||||
|
||||
void Construct()
|
||||
@@ -352,18 +326,10 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void DestructNoLock()
|
||||
{
|
||||
AZ_Assert(m_isConstructed, "Variable is not constructed. Please check your logic and guard if needed!");
|
||||
m_isConstructed = false;
|
||||
m_moduleOwner = nullptr;
|
||||
DestructImpl(typename AZStd::is_trivially_destructible<T>::type());
|
||||
}
|
||||
|
||||
void Destruct()
|
||||
{
|
||||
AZStd::lock_guard<AZStd::spin_mutex> lock(m_mutex);
|
||||
DestructNoLock();
|
||||
DestructDispatchNoLock(this, DestroyTarget::Member);
|
||||
}
|
||||
|
||||
// variable storage
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace AZ
|
||||
if (context.ShouldKeepDefaults() || !defaultValue || (valAsByteStream != *static_cast<const JsonByteStream*>(defaultValue)))
|
||||
{
|
||||
const auto base64ByteStream = AZ::StringFunc::Base64::Encode(valAsByteStream.data(), valAsByteStream.size());
|
||||
outputValue.SetString(base64ByteStream.c_str(), base64ByteStream.size(), context.GetJsonAllocator());
|
||||
outputValue.SetString(base64ByteStream.c_str(), static_cast<rapidjson::SizeType>(base64ByteStream.size()), context.GetJsonAllocator());
|
||||
return context.Report(Tasks::WriteValue, Outcomes::Success, "ByteStream successfully stored.");
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace AZStd
|
||||
// 20.9.3.2, observer:
|
||||
constexpr rep count() const { return m_rep; }
|
||||
// 20.9.3.3, arithmetic:
|
||||
constexpr duration operator+() const { *this; }
|
||||
constexpr duration operator+() const { return *this; }
|
||||
constexpr duration operator-() const { return duration(-m_rep); }
|
||||
constexpr duration& operator++() { ++m_rep; return *this; }
|
||||
constexpr duration operator++(int) { return duration(m_rep++); }
|
||||
|
||||
@@ -1056,7 +1056,7 @@ namespace AZStd
|
||||
inline void insert(const iterator& pos, ForwardIterator first, ForwardIterator last, const AZStd::forward_iterator_tag&)
|
||||
{
|
||||
size_type size = AZStd::distance(first, last);
|
||||
AZSTD_CONTAINER_ASSERT(size >= 0, "AZStd::ring_buffer::insert - there are no elements to insert!");
|
||||
AZSTD_CONTAINER_ASSERT(first > last, "AZStd::ring_buffer::insert - there are no elements to insert!");
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace AZStd
|
||||
1610612741ul, 3221225473ul, 4294967291ul
|
||||
};
|
||||
|
||||
// Bucket size suitable to hold n elements.
|
||||
AZStd::size_t hash_next_bucket_size(AZStd::size_t n)
|
||||
{
|
||||
const AZStd::size_t* first = prime_list;
|
||||
|
||||
@@ -134,6 +134,7 @@ namespace AZStd
|
||||
void rehash(HashTable* table, size_type numBucketsMin)
|
||||
{
|
||||
size_type num_buckets = 0;
|
||||
|
||||
numBucketsMin = (AZStd::max)(numBucketsMin, (size_type)ceilf((float)m_list.size() / m_max_load_factor));
|
||||
|
||||
if (numBucketsMin != 0)
|
||||
@@ -143,7 +144,7 @@ namespace AZStd
|
||||
|
||||
if (num_buckets == m_numBuckets)
|
||||
{
|
||||
return; // no point
|
||||
return; // no need yet to rehash
|
||||
}
|
||||
m_numBuckets = num_buckets;
|
||||
|
||||
@@ -165,32 +166,43 @@ namespace AZStd
|
||||
while (!m_list.empty())
|
||||
{
|
||||
cur = m_list.begin();
|
||||
typename list_type::iterator insertIter, curEnd(cur);
|
||||
const typename HashTable::key_type& valueKey = Traits::key_from_value(*cur);
|
||||
|
||||
typename list_type::iterator newIter, iter(cur);
|
||||
size_type numValues = 1;
|
||||
for (++iter; iter != last && table->m_keyEqual(Traits::key_from_value(*cur), Traits::key_from_value(*iter)); ++iter, ++numValues)
|
||||
// Get the number of same consecutive elements in the table with same key,
|
||||
// this allows range insertion of elements at once
|
||||
for (++curEnd; curEnd != last && table->m_keyEqual(valueKey, Traits::key_from_value(*curEnd)); ++curEnd, ++numValues)
|
||||
{
|
||||
}
|
||||
;
|
||||
|
||||
const typename HashTable::key_type& valueKey = Traits::key_from_value(*cur);
|
||||
size_type newBucketIndex = table->bucket_from_hash(table->m_hasher(valueKey));
|
||||
|
||||
// newBucket.first holds the total number of elements in the bucket
|
||||
// newBucket.second contains the pointer to the first element in the bucket
|
||||
vector_value_type& newBucket = newBuckets[newBucketIndex];
|
||||
size_type numElements = newBucket.first;
|
||||
newIter = newBucket.second;
|
||||
insertIter = newBucket.second;
|
||||
|
||||
// If we don't have elements in the bucket yet, transfer the elements directly
|
||||
if (numElements == 0)
|
||||
{
|
||||
newList.splice(newList.begin(), m_list, cur, iter);
|
||||
newList.splice(newList.begin(), m_list, cur, curEnd);
|
||||
newBucket.second = newList.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!table->find_insert_position(valueKey, table->m_keyEqual, newIter, numElements, integral_constant<bool, Traits::has_multi_elements>()))
|
||||
// Since there are elements already in the bucket, update `insertIter` to where the elements will need to be inserted.
|
||||
if (!table->find_insert_position(valueKey, table->m_keyEqual, insertIter, numElements, integral_constant<bool, Traits::has_multi_elements>()))
|
||||
{
|
||||
continue;
|
||||
// An element was found but we don't allow for duplicate elements in this table.
|
||||
// This happens when there was an insertion of two elements that are equal but have different hashes,
|
||||
// which is undefined behavior for a hash table: ISO C++ N4713, section 23.14.15 - 5.3
|
||||
AZ_Assert(false, "Found a duplicate element when rehashing. "
|
||||
"Review the hashing function for this type and make sure two equal elements always have the same hash");
|
||||
}
|
||||
|
||||
newList.splice(newIter, m_list, cur, iter);
|
||||
newList.splice(insertIter, m_list, cur, curEnd);
|
||||
}
|
||||
|
||||
newBucket.first += numValues;
|
||||
@@ -251,15 +263,15 @@ namespace AZStd
|
||||
m_vector.set_allocator(typename vector_type::allocator_type(&m_allocator));
|
||||
}
|
||||
|
||||
allocator_type m_allocator; ///< The single instance of the allocator shared between list and vector containers.
|
||||
list_type m_list; ///< List with elements.
|
||||
vector_type m_vector; ///< Buckets with list iterators.
|
||||
allocator_type m_allocator; //!< The single instance of the allocator shared between list and vector containers.
|
||||
list_type m_list; //!< List with elements.
|
||||
vector_type m_vector; //!< Buckets with list iterators.
|
||||
|
||||
private:
|
||||
vector_value_type* m_buckets; ///< Current buckets array. (can point to the m_vector or m_startBucket).
|
||||
size_type m_numBuckets; ///< Current number of buckets.
|
||||
float m_max_load_factor;
|
||||
vector_value_type m_startBucket; ///< Start bucket used for before we start dynamically allocate memory from m_vector.
|
||||
vector_value_type* m_buckets; //!< Current buckets array. (can point to the m_vector or m_startBucket).
|
||||
size_type m_numBuckets; //!< Current number of buckets.
|
||||
float m_max_load_factor; //!< Maximum load (elements/buckets) before rehashing.
|
||||
vector_value_type m_startBucket; //!< Start bucket used for before we start dynamically allocate memory from m_vector.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -321,8 +333,8 @@ namespace AZStd
|
||||
template<class HashTable>
|
||||
AZ_FORCE_INLINE void rehash(HashTable*, size_type) {}
|
||||
|
||||
vector_type m_vector; ///< Buckets with list iterators.
|
||||
list_type m_list; ///< List with elements.
|
||||
vector_type m_vector; //!< Buckets with list iterators.
|
||||
list_type m_list; //!< List with elements.
|
||||
};
|
||||
}
|
||||
|
||||
@@ -972,28 +984,32 @@ namespace AZStd
|
||||
rhs.clear();
|
||||
}
|
||||
|
||||
// find_insert_position sets insertIter to where the element should be inserted
|
||||
// and returns true if the element should be inserted, otherwise false
|
||||
template<class ComparableToKey, class KeyEq>
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& iter, size_type numElements, const true_type& /* is multi elements */)
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& insertIter, size_type numElements, const true_type& /* is multi elements */)
|
||||
{
|
||||
for (size_type i = 0; i < numElements; ++i, ++iter)
|
||||
for (size_type i = 0; i < numElements; ++i, ++insertIter)
|
||||
{
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*iter)))
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*insertIter)))
|
||||
{
|
||||
++iter;
|
||||
++insertIter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// always return true since multi elements (like multiset) allow repeated elements
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class ComparableToKey, class KeyEq>
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& iter, size_type numElements, const false_type& /* !is multi elements */)
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& insertIter, size_type numElements, const false_type& /* !is multi elements */)
|
||||
{
|
||||
for (size_type i = 0; i < numElements; ++i, ++iter)
|
||||
for (size_type i = 0; i < numElements; ++i, ++insertIter)
|
||||
{
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*iter)))
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*insertIter)))
|
||||
{
|
||||
// Element already exists, it shouldn't be inserted as we don't allow more than one repeated element for this specialization
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace AZStd
|
||||
T& m_v;
|
||||
constexpr addr_impl_ref(T& v)
|
||||
: m_v(v) {}
|
||||
constexpr addr_impl_ref& operator=(const addr_impl_ref& v) { m_v = v; }
|
||||
constexpr addr_impl_ref& operator=(const addr_impl_ref& v) { m_v = v; return *this; }
|
||||
constexpr operator T& () const { return m_v; }
|
||||
};
|
||||
|
||||
|
||||
@@ -287,6 +287,55 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(HashedContainers, HashTable_InsertionDuplicateOnRehash)
|
||||
{
|
||||
struct TwoPtrs
|
||||
{
|
||||
void* m_ptr1;
|
||||
void* m_ptr2;
|
||||
|
||||
bool operator==(const TwoPtrs& other) const
|
||||
{
|
||||
if (m_ptr1 == other.m_ptr1)
|
||||
{
|
||||
return m_ptr2 == other.m_ptr2;
|
||||
}
|
||||
else if (m_ptr1 == other.m_ptr2)
|
||||
{
|
||||
return m_ptr2 == other.m_ptr1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// This hashing function produces different hashes for two equal values,
|
||||
// which violates the requirement for hashing functions.
|
||||
// The test makes sure that this does not reproduce an issue that caused the insert() function to loop infinitely.
|
||||
struct TwoPtrsHasher
|
||||
{
|
||||
size_t operator()(const TwoPtrs& p) const
|
||||
{
|
||||
size_t hash{ 0 };
|
||||
AZStd::hash_combine(hash, p.m_ptr1, p.m_ptr2);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
using PairSet = AZStd::unordered_set<TwoPtrs, TwoPtrsHasher>;
|
||||
PairSet set;
|
||||
set.insert({ (void*)1, (void*)2 });
|
||||
set.insert({ (void*)3, (void*)4 });
|
||||
set.insert({ (void*)5, (void*)6 });
|
||||
set.insert({ (void*)7, (void*)8 });
|
||||
// Elements with different hashes, but equal
|
||||
set.insert({ (void*)0x000001ceddd9ca20, (void*)0x000001ceddd9cba0 }); // hash(148335135725641)
|
||||
set.insert({ (void*)0x000001ceddd9cba0, (void*)0x000001ceddd9ca20 }); // hash(148335135764189)
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
// This will trigger the assertion of duplicated elements found
|
||||
// A bucket size of 23 since is where the collision between different hashes happens
|
||||
set.rehash(23);
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 assertion
|
||||
}
|
||||
|
||||
TEST_F(HashedContainers, HashTable_Fixed)
|
||||
{
|
||||
array<int, 5> elements = {
|
||||
|
||||
@@ -1150,7 +1150,7 @@ namespace UnitTest
|
||||
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
#else
|
||||
TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
{
|
||||
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
|
||||
|
||||
Reference in New Issue
Block a user