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:
Esteban Papp
2021-08-05 20:05:25 -07:00
389 changed files with 5267 additions and 3581 deletions
@@ -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;
}
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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;
+42 -26
View File
@@ -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;
}
}
+1 -1
View File
@@ -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();