Merge branch 'development' into memory/overrideshim_removal

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2022-01-20 13:43:12 -08:00
1545 changed files with 24982 additions and 22444 deletions
@@ -558,10 +558,6 @@ namespace AZ
m_entityActivatedEvent.DisconnectAllHandlers();
m_entityDeactivatedEvent.DisconnectAllHandlers();
#if !defined(_RELEASE)
m_budgetTracker.Reset();
#endif
DestroyAllocator();
}
@@ -751,6 +747,12 @@ namespace AZ
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearNotifiers();
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearMergeEvents();
#if !defined(_RELEASE)
// the budget tracker must be cleaned up prior to module unloading to ensure
// budgets initialized cross boundary are freed properly
m_budgetTracker.Reset();
#endif
// Uninit and unload any dynamic modules.
m_moduleManager->UnloadModules();
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsUnloaded", R"({})");
@@ -361,7 +361,7 @@ namespace AZ::Dom::Json
bool RapidJsonReadHandler::String(const char* str, rapidjson::SizeType length, bool copy)
{
const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary;
const Lifetime lifetime = !copy ? m_stringLifetime : Lifetime::Temporary;
return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime));
}
@@ -373,11 +373,7 @@ namespace AZ::Dom::Json
bool RapidJsonReadHandler::Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy)
{
AZStd::string_view key = AZStd::string_view(str, length);
if (!m_visitor->SupportsRawKeys())
{
m_visitor->Key(AZ::Name(key));
}
const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary;
const Lifetime lifetime = !copy ? m_stringLifetime : Lifetime::Temporary;
return CheckResult(m_visitor->RawKey(key, lifetime));
}
+161 -1
View File
@@ -21,4 +21,164 @@ namespace AZ::Dom::Utils
{
return backend.ReadFromBufferInPlace(string.data(), string.size(), visitor);
}
}
AZ::Outcome<Value, AZStd::string> WriteToValue(const Backend::WriteCallback& writeCallback)
{
Value value;
AZStd::unique_ptr<Visitor> writer = value.GetWriteHandler();
Visitor::Result result = writeCallback(*writer);
if (!result.IsSuccess())
{
return AZ::Failure(result.GetError().FormatVisitorErrorMessage());
}
return AZ::Success(AZStd::move(value));
}
bool DeepCompareIsEqual(const Value& lhs, const Value& rhs)
{
const Value::ValueType& lhsValue = lhs.GetInternalValue();
const Value::ValueType& rhsValue = rhs.GetInternalValue();
if (lhs.IsString() && rhs.IsString())
{
// If we both hold the same ref counted string we don't need to do a full comparison
if (AZStd::holds_alternative<Value::SharedStringType>(lhsValue) && lhsValue == rhsValue)
{
return true;
}
return lhs.GetString() == rhs.GetString();
}
return AZStd::visit(
[&](auto&& ourValue) -> bool
{
using Alternative = AZStd::decay_t<decltype(ourValue)>;
if constexpr (AZStd::is_same_v<Alternative, ObjectPtr>)
{
if (!rhs.IsObject())
{
return false;
}
auto&& theirValue = AZStd::get<AZStd::remove_cvref_t<decltype(ourValue)>>(rhsValue);
if (ourValue == theirValue)
{
return true;
}
const Object::ContainerType& ourValues = ourValue->GetValues();
const Object::ContainerType& theirValues = theirValue->GetValues();
if (ourValues.size() != theirValues.size())
{
return false;
}
for (size_t i = 0; i < ourValues.size(); ++i)
{
const Object::EntryType& lhsChild = ourValues[i];
auto rhsIt = rhs.FindMember(lhsChild.first);
if (rhsIt == rhs.MemberEnd() || !DeepCompareIsEqual(lhsChild.second, rhsIt->second))
{
return false;
}
}
return true;
}
else if constexpr (AZStd::is_same_v<Alternative, ArrayPtr>)
{
if (!rhs.IsArray())
{
return false;
}
auto&& theirValue = AZStd::get<AZStd::remove_cvref_t<decltype(ourValue)>>(rhsValue);
if (ourValue == theirValue)
{
return true;
}
const Array::ContainerType& ourValues = ourValue->GetValues();
const Array::ContainerType& theirValues = theirValue->GetValues();
if (ourValues.size() != theirValues.size())
{
return false;
}
for (size_t i = 0; i < ourValues.size(); ++i)
{
const Value& lhsChild = ourValues[i];
const Value& rhsChild = theirValues[i];
if (!DeepCompareIsEqual(lhsChild, rhsChild))
{
return false;
}
}
return true;
}
else if constexpr (AZStd::is_same_v<Alternative, NodePtr>)
{
if (!rhs.IsNode())
{
return false;
}
auto&& theirValue = AZStd::get<AZStd::remove_cvref_t<decltype(ourValue)>>(rhsValue);
if (ourValue == theirValue)
{
return true;
}
const Node& ourNode = *ourValue;
const Node& theirNode = *theirValue;
const Object::ContainerType& ourProperties = ourNode.GetProperties();
const Object::ContainerType& theirProperties = theirNode.GetProperties();
if (ourProperties.size() != theirProperties.size())
{
return false;
}
for (size_t i = 0; i < ourProperties.size(); ++i)
{
const Object::EntryType& lhsChild = ourProperties[i];
auto rhsIt = rhs.FindMember(lhsChild.first);
if (rhsIt == rhs.MemberEnd() || !DeepCompareIsEqual(lhsChild.second, rhsIt->second))
{
return false;
}
}
const Array::ContainerType& ourChildren = ourNode.GetChildren();
const Array::ContainerType& theirChildren = theirNode.GetChildren();
for (size_t i = 0; i < ourChildren.size(); ++i)
{
const Value& lhsChild = ourChildren[i];
const Value& rhsChild = theirChildren[i];
if (!DeepCompareIsEqual(lhsChild, rhsChild))
{
return false;
}
}
return true;
}
else
{
return lhs == rhs;
}
},
lhsValue);
}
Value DeepCopy(const Value& value, bool copyStrings)
{
Value copiedValue;
AZStd::unique_ptr<Visitor> writer = copiedValue.GetWriteHandler();
value.Accept(*writer, copyStrings);
return copiedValue;
}
} // namespace AZ::Dom::Utils
@@ -9,9 +9,15 @@
#pragma once
#include <AzCore/DOM/DomBackend.h>
#include <AzCore/DOM/DomValue.h>
namespace AZ::Dom::Utils
{
Visitor::Result ReadFromString(Backend& backend, AZStd::string_view string, AZ::Dom::Lifetime lifetime, Visitor& visitor);
Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor);
AZ::Outcome<Value, AZStd::string> WriteToValue(const Backend::WriteCallback& writeCallback);
bool DeepCompareIsEqual(const Value& lhs, const Value& rhs);
Value DeepCopy(const Value& value, bool copyStrings = true);
} // namespace AZ::Dom::Utils
File diff suppressed because it is too large Load Diff
+402
View File
@@ -0,0 +1,402 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/DOM/DomBackend.h>
#include <AzCore/DOM/DomVisitor.h>
#include <AzCore/Memory/HphaSchema.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/std/containers/stack.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
namespace AZ::Dom
{
using KeyType = AZ::Name;
//! The type of underlying value stored in a value. \see Value
enum class Type
{
Null,
Bool,
Object,
Array,
String,
Int64,
Uint64,
Double,
Node,
Opaque,
};
//! The allocator used by Value.
//! Value heap allocates shared_ptrs for its container storage (Array / Object / Node) alongside
class ValueAllocator final : public SimpleSchemaAllocator<AZ::HphaSchema, AZ::HphaSchema::Descriptor, false, false>
{
public:
AZ_TYPE_INFO(ValueAllocator, "{5BC8B389-72C7-459E-B502-12E74D61869F}");
using Base = SimpleSchemaAllocator<AZ::HphaSchema, AZ::HphaSchema::Descriptor, false, false>;
ValueAllocator()
: Base("DomValueAllocator", "Allocator for AZ::Dom::Value")
{
DisableOverriding();
}
};
using StdValueAllocator = AZStdAlloc<ValueAllocator>;
class Value;
//! Internal storage for a Value array: an ordered list of Values.
class Array
{
public:
using ContainerType = AZStd::vector<Value, StdValueAllocator>;
using Iterator = ContainerType::iterator;
using ConstIterator = ContainerType::const_iterator;
static constexpr const size_t ReserveIncrement = 4;
static_assert((ReserveIncrement & (ReserveIncrement - 1)) == 0, "ReserveIncremenet must be a power of 2");
const ContainerType& GetValues() const;
private:
ContainerType m_values;
friend class Value;
};
using ArrayPtr = AZStd::shared_ptr<Array>;
using ConstArrayPtr = AZStd::shared_ptr<const Array>;
//! Internal storage for a Value object: an ordered list of Name / Value pairs.
class Object
{
public:
using EntryType = AZStd::pair<KeyType, Value>;
using ContainerType = AZStd::vector<EntryType, StdValueAllocator>;
using Iterator = ContainerType::iterator;
using ConstIterator = ContainerType::const_iterator;
static constexpr const size_t ReserveIncrement = 8;
static_assert((ReserveIncrement & (ReserveIncrement - 1)) == 0, "ReserveIncremenet must be a power of 2");
const ContainerType& GetValues() const;
private:
ContainerType m_values;
friend class Value;
};
using ObjectPtr = AZStd::shared_ptr<Object>;
using ConstObjectPtr = AZStd::shared_ptr<const Object>;
//! Storage for a Value node: a named Value with both properties and children.
//! Properties are stored as an ordered list of Name / Value pairs.
//! Children are stored as an oredered list of Values.
class Node
{
public:
Node() = default;
Node(const Node&) = default;
Node(Node&&) = default;
explicit Node(AZ::Name name);
Node& operator=(const Node&) = default;
Node& operator=(Node&&) = default;
AZ::Name GetName() const;
void SetName(AZ::Name name);
Object::ContainerType& GetProperties();
const Object::ContainerType& GetProperties() const;
Array::ContainerType& GetChildren();
const Array::ContainerType& GetChildren() const;
private:
AZ::Name m_name;
Object::ContainerType m_properties;
Array::ContainerType m_children;
friend class Value;
};
using NodePtr = AZStd::shared_ptr<Node>;
using ConstNodePtr = AZStd::shared_ptr<Node>;
//! Value is a typed union of Dom types that can represent the types provdied by AZ::Dom::Visitor.
//! Value can be one of the following types:
//! - Null: a type with no value, this is the default type for Value
//! - Bool: a true or false boolean value
//! - Object: a container with an ordered list of Name/Value pairs, analagous to a JSON object
//! - Array: a container with an ordered list of Values, analagous to a JSON array
//! - String: a UTF-8 string
//! - Int64: a signed, 64-bit integer
//! - Uint64: an unsigned, 64-bit integer
//! - Double: a double precision floating point value
//! - Node: a container with a Name, an ordered list of Name/Values pairs (attributes), and an ordered list of Values (children),
//! analagous to an XML node
//! - Opaque: an arbitrary value stored in an AZStd::any. This is a non-serializable representation of an entry used only for in-memory
//! options. This is intended to be used as an intermediate value over the course of DOM transformation and as a proxy to pass through
//! types of which the DOM has no knowledge to other systems.
//! \note Value is a copy-on-write data structure and may be cheaply returned by value. Heap allocated data larger than the size of the
//! value itself (objects, arrays, and nodes) are copied by new Values only when their contents change, so care should be taken in
//! performance critical code to avoid mutation operations such as operator[] to avoid copies. It is recommended that an immutable Value
//! be explicitly be stored as a `const Value` to avoid accidental detach and copy operations.
class Value final
{
public:
// Determine the short string buffer size based on the size of our largest internal type (string_view)
// minus the size of the short string size field.
static constexpr const size_t ShortStringSize = sizeof(AZStd::string_view) - 2;
using ShortStringType = AZStd::fixed_string<ShortStringSize>;
using SharedStringContainer = AZStd::vector<char>;
using SharedStringType = AZStd::shared_ptr<const SharedStringContainer>;
using OpaqueStorageType = AZStd::shared_ptr<AZStd::any>;
//! The internal storage type for Value.
//! These types do not correspond one-to-one with the Value's external Type as there may be multiple storage classes
//! for the same type in some instances, such as string storage.
using ValueType = AZStd::variant<
// Null
AZStd::monostate,
// Int64
int64_t,
// Uint64
uint64_t,
// Double
double,
// Bool
bool,
// String
AZStd::string_view,
SharedStringType,
ShortStringType,
// Object
ObjectPtr,
// Array
ArrayPtr,
// Node
NodePtr,
// Opaque
OpaqueStorageType>;
// Constructors...
Value() = default;
Value(const Value&);
Value(Value&&) noexcept;
Value(AZStd::string_view stringView, bool copy);
explicit Value(const ValueType&);
explicit Value(ValueType&&);
explicit Value(SharedStringType sharedString);
explicit Value(int8_t value);
explicit Value(uint8_t value);
explicit Value(int16_t value);
explicit Value(uint16_t value);
explicit Value(int32_t value);
explicit Value(uint32_t value);
explicit Value(int64_t value);
explicit Value(uint64_t value);
explicit Value(float value);
explicit Value(double value);
explicit Value(bool value);
explicit Value(Type type);
// Disable accidental calls to Value(bool) with pointer types
template<class T>
explicit Value(T*) = delete;
static Value FromOpaqueValue(const AZStd::any& value);
// Equality / comparison / swap...
Value& operator=(const Value&);
Value& operator=(Value&&) noexcept;
//! Assignment operator to allow forwarding types constructible via Value(T) to be assigned
template<class T>
auto operator=(T&& arg)
-> AZStd::enable_if_t<!AZStd::is_same_v<AZStd::remove_cvref_t<T>, Value> && AZStd::is_constructible_v<Value, T>, Value&>
{
return operator=(Value(AZStd::forward<T>(arg)));
}
bool operator==(const Value& rhs) const;
bool operator!=(const Value& rhs) const;
void Swap(Value& other) noexcept;
// Type info...
Type GetType() const;
bool IsNull() const;
bool IsFalse() const;
bool IsTrue() const;
bool IsBool() const;
bool IsNode() const;
bool IsObject() const;
bool IsArray() const;
bool IsOpaqueValue() const;
bool IsNumber() const;
bool IsInt() const;
bool IsUint() const;
bool IsDouble() const;
bool IsString() const;
// Object API (also used by Node)...
Value& SetObject();
size_t MemberCount() const;
size_t MemberCapacity() const;
bool ObjectEmpty() const;
Value& operator[](KeyType name);
const Value& operator[](KeyType name) const;
Value& operator[](AZStd::string_view name);
const Value& operator[](AZStd::string_view name) const;
Object::ConstIterator MemberBegin() const;
Object::ConstIterator MemberEnd() const;
Object::Iterator MutableMemberBegin();
Object::Iterator MutableMemberEnd();
Object::Iterator FindMutableMember(KeyType name);
Object::Iterator FindMutableMember(AZStd::string_view name);
Object::ConstIterator FindMember(KeyType name) const;
Object::ConstIterator FindMember(AZStd::string_view name) const;
Value& MemberReserve(size_t newCapacity);
bool HasMember(KeyType name) const;
bool HasMember(AZStd::string_view name) const;
Value& AddMember(KeyType name, const Value& value);
Value& AddMember(AZStd::string_view name, const Value& value);
Value& AddMember(KeyType name, Value&& value);
Value& AddMember(AZStd::string_view name, Value&& value);
void RemoveAllMembers();
void RemoveMember(KeyType name);
void RemoveMember(AZStd::string_view name);
Object::Iterator RemoveMember(Object::Iterator pos);
Object::Iterator EraseMember(Object::Iterator pos);
Object::Iterator EraseMember(Object::Iterator first, Object::Iterator last);
Object::Iterator EraseMember(KeyType name);
Object::Iterator EraseMember(AZStd::string_view name);
Object::ContainerType& GetMutableObject();
const Object::ContainerType& GetObject() const;
// Array API (also used by Node)...
Value& SetArray();
size_t ArraySize() const;
size_t ArrayCapacity() const;
bool IsArrayEmpty() const;
void ClearArray();
Value& operator[](size_t index);
const Value& operator[](size_t index) const;
Value& MutableArrayAt(size_t index);
const Value& ArrayAt(size_t index) const;
Array::ConstIterator ArrayBegin() const;
Array::ConstIterator ArrayEnd() const;
Array::Iterator MutableArrayBegin();
Array::Iterator MutableArrayEnd();
Value& ArrayReserve(size_t newCapacity);
Value& ArrayPushBack(Value value);
Value& ArrayPopBack();
Array::Iterator ArrayErase(Array::Iterator pos);
Array::Iterator ArrayErase(Array::Iterator first, Array::Iterator last);
Array::ContainerType& GetMutableArray();
const Array::ContainerType& GetArray() const;
// Node API (supports both object + array API, plus a dedicated NodeName)...
void SetNode(AZ::Name name);
void SetNode(AZStd::string_view name);
AZ::Name GetNodeName() const;
void SetNodeName(AZ::Name name);
void SetNodeName(AZStd::string_view name);
//! Convenience method, sets the first non-node element of a Node.
void SetNodeValue(Value value);
//! Convenience method, gets the first non-node element of a Node.
Value GetNodeValue() const;
Node& GetMutableNode();
const Node& GetNode() const;
// int API...
int64_t GetInt64() const;
void SetInt64(int64_t);
// uint API...
uint64_t GetUint64() const;
void SetUint64(uint64_t);
// bool API...
bool GetBool() const;
void SetBool(bool);
// double API...
double GetDouble() const;
void SetDouble(double);
// String API...
AZStd::string_view GetString() const;
size_t GetStringLength() const;
void SetString(AZStd::string_view);
void SetString(SharedStringType sharedString);
void CopyFromString(AZStd::string_view);
// Opaque type API...
const AZStd::any& GetOpaqueValue() const;
//! This sets this Value to represent a value of an type that the DOM has
//! no formal knowledge of. Where possible, it should be preferred to
//! serialize an opaque type into a DOM value instead, as serializers
//! and other systems will have no means of dealing with fully arbitrary
//! values.
void SetOpaqueValue(AZStd::any);
// Null API...
void SetNull();
// Visitor API...
Visitor::Result Accept(Visitor& visitor, bool copyStrings) const;
AZStd::unique_ptr<Visitor> GetWriteHandler();
//! Gets the internal value of this Value. Note that this value's types may not correspond one-to-one with the Type enumeration,
//! as internally the same type might have different storage mechanisms. Where possible, prefer using the typed API.
const ValueType& GetInternalValue() const;
private:
const Node& GetNodeInternal() const;
Node& GetNodeInternal();
const Object::ContainerType& GetObjectInternal() const;
Object::ContainerType& GetObjectInternal();
const Array::ContainerType& GetArrayInternal() const;
Array::ContainerType& GetArrayInternal();
explicit Value(AZStd::any opaqueValue);
static_assert(
sizeof(ValueType) == sizeof(ShortStringType) + sizeof(size_t), "ValueType should have no members larger than ShortStringType");
ValueType m_value;
};
} // namespace AZ::Dom
@@ -0,0 +1,262 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/DOM/DomValueWriter.h>
namespace AZ::Dom
{
ValueWriter::ValueWriter(Value& outputValue)
: m_result(outputValue)
{
}
VisitorFlags ValueWriter::GetVisitorFlags() const
{
return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes;
}
ValueWriter::ValueInfo::ValueInfo(Value& container)
: m_container(container)
{
}
Visitor::Result ValueWriter::Null()
{
CurrentValue().SetNull();
return FinishWrite();
}
Visitor::Result ValueWriter::Bool(bool value)
{
CurrentValue().SetBool(value);
return FinishWrite();
}
Visitor::Result ValueWriter::Int64(AZ::s64 value)
{
CurrentValue().SetInt64(value);
return FinishWrite();
}
Visitor::Result ValueWriter::Uint64(AZ::u64 value)
{
CurrentValue().SetUint64(value);
return FinishWrite();
}
Visitor::Result ValueWriter::Double(double value)
{
CurrentValue().SetDouble(value);
return FinishWrite();
}
Visitor::Result ValueWriter::String(AZStd::string_view value, Lifetime lifetime)
{
if (lifetime == Lifetime::Persistent)
{
CurrentValue().SetString(value);
}
else
{
CurrentValue().CopyFromString(value);
}
return FinishWrite();
}
Visitor::Result ValueWriter::RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, [[maybe_unused]] Lifetime lifetime)
{
CurrentValue().SetString(AZStd::move(value));
return FinishWrite();
}
Visitor::Result ValueWriter::StartObject()
{
CurrentValue().SetObject();
m_entryStack.emplace(CurrentValue());
return VisitorSuccess();
}
template <class T, class A>
void MoveVectorMemory(AZStd::vector<T, A>& dest, AZStd::vector<T, A>& source)
{
dest.resize_no_construct(source.size());
const size_t size = sizeof(T) * source.size();
memcpy(dest.data(), source.data(), size);
memset(source.data(), 0, size);
source.resize(0);
}
Visitor::Result ValueWriter::EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount)
{
const char* endMethodName;
switch (containerType)
{
case Type::Object:
endMethodName = "EndObject";
break;
case Type::Array:
endMethodName = "EndArray";
break;
case Type::Node:
endMethodName = "EndNode";
break;
default:
AZ_Assert(false, "Invalid container type specified");
return VisitorFailure(VisitorErrorCode::InternalError, "AZ::Dom::ValueWriter: EndContainer called with invalid container type");
}
if (m_entryStack.empty())
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format("AZ::Dom::ValueWriter: %s called without a matching call", endMethodName));
}
const ValueInfo& topEntry = m_entryStack.top();
Value& container = topEntry.m_container;
ValueBuffer& buffer = GetValueBuffer();
if (container.GetType() != containerType)
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format("AZ::Dom::ValueWriter: %s called from within a different container type", endMethodName));
}
if (aznumeric_cast<AZ::u64>(buffer.m_attributes.size()) != attributeCount)
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format(
"AZ::Dom::ValueWriter: %s expected %llu attributes but received %zu attributes instead", endMethodName, attributeCount,
buffer.m_attributes.size()));
}
if (aznumeric_cast<AZ::u64>(buffer.m_elements.size()) != elementCount)
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format(
"AZ::Dom::ValueWriter: %s expected %llu elements but received %zu elements instead", endMethodName, elementCount,
buffer.m_elements.size()));
}
if (buffer.m_attributes.size() > 0)
{
MoveVectorMemory(container.GetMutableObject(), buffer.m_attributes);
}
if(buffer.m_elements.size() > 0)
{
MoveVectorMemory(container.GetMutableArray(), buffer.m_elements);
}
m_entryStack.pop();
return FinishWrite();
}
ValueWriter::ValueBuffer& ValueWriter::GetValueBuffer()
{
if (m_entryStack.size() <= m_valueBuffers.size())
{
return m_valueBuffers[m_entryStack.size() - 1];
}
m_valueBuffers.resize(m_entryStack.size());
return m_valueBuffers[m_entryStack.size() - 1];
}
Visitor::Result ValueWriter::EndObject(AZ::u64 attributeCount)
{
return EndContainer(Type::Object, attributeCount, 0);
}
Visitor::Result ValueWriter::Key(AZ::Name key)
{
AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object");
AZ_Assert(!m_entryStack.top().m_container.IsArray(), "Attempted to push a key to an array");
m_entryStack.top().m_key = AZStd::move(key);
return VisitorSuccess();
}
Visitor::Result ValueWriter::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime)
{
return Key(AZ::Name(key));
}
Visitor::Result ValueWriter::StartArray()
{
CurrentValue().SetArray();
m_entryStack.emplace(CurrentValue());
return VisitorSuccess();
}
Visitor::Result ValueWriter::EndArray(AZ::u64 elementCount)
{
return EndContainer(Type::Array, 0, elementCount);
}
Visitor::Result ValueWriter::StartNode(AZ::Name name)
{
CurrentValue().SetNode(name);
m_entryStack.emplace(CurrentValue());
return VisitorSuccess();
}
Visitor::Result ValueWriter::RawStartNode(AZStd::string_view name, [[maybe_unused]] Lifetime lifetime)
{
return StartNode(AZ::Name(name));
}
Visitor::Result ValueWriter::EndNode(AZ::u64 attributeCount, AZ::u64 elementCount)
{
return EndContainer(Type::Node, attributeCount, elementCount);
}
Visitor::Result ValueWriter::OpaqueValue(OpaqueType& value)
{
CurrentValue().SetOpaqueValue(value);
return FinishWrite();
}
Visitor::Result ValueWriter::FinishWrite()
{
if (m_entryStack.empty())
{
return VisitorSuccess();
}
Value value;
m_entryStack.top().m_value.Swap(value);
ValueInfo& newEntry = m_entryStack.top();
if (!newEntry.m_key.IsEmpty())
{
GetValueBuffer().m_attributes.emplace_back(AZStd::move(newEntry.m_key), AZStd::move(value));
newEntry.m_key = AZ::Name();
}
else
{
GetValueBuffer().m_elements.emplace_back(AZStd::move(value));
}
return VisitorSuccess();
}
Value& ValueWriter::CurrentValue()
{
if (m_entryStack.empty())
{
return m_result;
}
return m_entryStack.top().m_value;
}
} // namespace AZ::Dom
@@ -0,0 +1,72 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/DOM/DomValue.h>
#include <AzCore/std/containers/stack.h>
namespace AZ::Dom
{
//! Visitor that writes to a Value.
//! Supports all Visitor operations.
class ValueWriter : public Visitor
{
public:
ValueWriter(Value& outputValue);
VisitorFlags GetVisitorFlags() const override;
Result Null() override;
Result Bool(bool value) override;
Result Int64(AZ::s64 value) override;
Result Uint64(AZ::u64 value) override;
Result Double(double value) override;
Result String(AZStd::string_view value, Lifetime lifetime) override;
Result RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, Lifetime lifetime) override;
Result StartObject() override;
Result EndObject(AZ::u64 attributeCount) override;
Result Key(AZ::Name key) override;
Result RawKey(AZStd::string_view key, Lifetime lifetime) override;
Result StartArray() override;
Result EndArray(AZ::u64 elementCount) override;
Result StartNode(AZ::Name name) override;
Result RawStartNode(AZStd::string_view name, Lifetime lifetime) override;
Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) override;
Result OpaqueValue(OpaqueType& value) override;
private:
Result FinishWrite();
Value& CurrentValue();
Visitor::Result EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount);
struct ValueInfo
{
ValueInfo(Value& container);
KeyType m_key;
Value m_value;
Value& m_container;
};
struct ValueBuffer
{
Array::ContainerType m_elements;
Object::ContainerType m_attributes;
};
ValueBuffer& GetValueBuffer();
Value& m_result;
// Stores info about the current value being processed
AZStd::stack<ValueInfo, AZStd::deque<ValueInfo, AZStdAlloc<ValueAllocator>>> m_entryStack;
// Provides temporary storage for elements and attributes to prevent extra heap allocations
// These buffers persist to be reused even as the entry stack changes
AZStd::vector<ValueBuffer, AZStdAlloc<ValueAllocator>> m_valueBuffers;
};
} // namespace AZ::Dom
@@ -105,7 +105,12 @@ namespace AZ::Dom
return VisitorSuccess();
}
Visitor::Result Visitor::OpaqueValue([[maybe_unused]] const OpaqueType& value, [[maybe_unused]] Lifetime lifetime)
Visitor::Result Visitor::RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, Lifetime lifetime)
{
return String({ value->data(), value->size() }, lifetime);
}
Visitor::Result Visitor::OpaqueValue([[maybe_unused]] OpaqueType& value)
{
if (!SupportsOpaqueValues())
{
+11 -4
View File
@@ -11,6 +11,8 @@
#include <AzCore/Name/Name.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/any.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/string/string.h>
namespace AZ::Dom
@@ -167,15 +169,20 @@ namespace AZ::Dom
virtual Result Uint64(AZ::u64 value);
//! Operates on a double precision, 64 bit floating point value.
virtual Result Double(double value);
//! Operates on a string value. As strings are a reference type.
//! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
//! Operates on a string value. As strings are a reference type,
//! storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
//! \param lifetime Specifies the lifetime of this string - if the string has a temporary lifetime, it cannot
//! safely be stored as a reference.
virtual Result String(AZStd::string_view value, Lifetime lifetime);
//! Operates on a ref-counted string value. S
//! \param lifetime Specifies the lifetime of this string. If the string has a temporary lifetime, it may not
//! be safely stored as a reference, but may still be safely stored as a ref-counted shared_ptr.
virtual Result RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, Lifetime lifetime);
//! Operates on an opaque value. As opaque values are a reference type, storage semantics are provided to
//! indicate where the value may be stored persistently or requires a copy.
//! The base implementation of OpaqueValue rejects the operation, as opaque values are meant for special
//! cases with specific implementations, not generic usage.
//! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
virtual Result OpaqueValue(const OpaqueType& value, Lifetime lifetime);
virtual Result OpaqueValue(OpaqueType& value);
//! Operates on a raw value encoded as a UTF-8 string that hasn't had its type deduced.
//! Visitors that support raw values (\see VisitorFlags::SupportsRawValues) may parse the raw value and
//! forward it to the corresponding value call or calls of their choice.
+10 -6
View File
@@ -62,12 +62,16 @@ namespace AZ::Debug
//
// Anywhere the budget is used, the budget must be declared (either in a header or in the source file itself)
// AZ_DECLARE_BUDGET(AzCore);
#define AZ_DEFINE_BUDGET(name) \
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
{ \
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
static ::AZ::Debug::Budget* budget = ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name, crc); \
return budget; \
#define AZ_DEFINE_BUDGET(name) \
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
{ \
static ::AZ::Debug::Budget* budget = nullptr; \
if (budget == nullptr) \
{ \
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(budget, #name, crc); \
} \
return budget; \
}
#endif
@@ -13,23 +13,24 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/parallel/scoped_lock.h>
namespace AZ::Debug
{
struct BudgetTracker::BudgetTrackerImpl
{
AZStd::unordered_map<const char*, Budget> m_budgets;
AZStd::unordered_map<AZStd::string_view, Budget> m_budgets;
AZStd::unordered_set<Budget**> m_externalBudgetRefs;
};
Budget* BudgetTracker::GetBudgetFromEnvironment(const char* budgetName, uint32_t crc)
void BudgetTracker::GetBudgetFromEnvironment(Budget*& extBudgetRef, const char* budgetName, uint32_t crc)
{
BudgetTracker* tracker = Interface<BudgetTracker>::Get();
if (tracker)
{
return &tracker->GetBudget(budgetName, crc);
tracker->GetBudget(extBudgetRef, budgetName, crc);
}
return nullptr;
}
BudgetTracker::~BudgetTracker()
@@ -54,17 +55,24 @@ namespace AZ::Debug
if (m_impl)
{
Interface<BudgetTracker>::Unregister(this);
for (auto budgetRef : m_impl->m_externalBudgetRefs)
{
*budgetRef = nullptr;
}
delete m_impl;
m_impl = nullptr;
}
}
Budget& BudgetTracker::GetBudget(const char* budgetName, uint32_t crc)
void BudgetTracker::GetBudget(Budget*& extBudgetRef, const char* budgetName, uint32_t crc)
{
AZStd::scoped_lock lock{ m_mutex };
auto it = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
m_impl->m_externalBudgetRefs.insert(&extBudgetRef);
return it->second;
auto iter = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
extBudgetRef = &iter->second;
}
} // namespace AZ::Debug
@@ -20,7 +20,7 @@ namespace AZ::Debug
{
public:
AZ_TYPE_INFO(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc);
static void GetBudgetFromEnvironment(Budget*& extBudgetRef, const char* budgetName, uint32_t crc);
~BudgetTracker();
@@ -28,7 +28,7 @@ namespace AZ::Debug
bool Init();
void Reset();
Budget& GetBudget(const char* budgetName, uint32_t crc);
void GetBudget(Budget*& extBudgetRef, const char* budgetName, uint32_t crc);
private:
struct BudgetTrackerImpl;
+7 -2
View File
@@ -23,6 +23,11 @@
#include <AzCore/EBus/Results.h>
#include <AzCore/EBus/Internal/Debug.h>
// Included for backwards compatibility purposes
#include <AzCore/std/typetraits/typetraits.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/utils.h>
@@ -515,7 +520,7 @@ namespace AZ
* This is not EBus Context Mutex when LocklessDispatch is set
*/
template <typename DispatchMutex>
using DispatchLockGuard = typename ImplTraits::template DispatchLockGuard<DispatchMutex>;
using DispatchLockGuardTemplate = typename ImplTraits::template DispatchLockGuard<DispatchMutex>;
//////////////////////////////////////////////////////////////////////////
// Check to help identify common mistakes
@@ -645,7 +650,7 @@ namespace AZ
* during broadcast/event dispatch.
* @see EBusTraits::LocklessDispatch
*/
using DispatchLockGuard = DispatchLockGuard<ContextMutexType>;
using DispatchLockGuard = DispatchLockGuardTemplate<ContextMutexType>;
/**
* The scoped lock guard to use during connection. Some specialized policies execute handler methods which
@@ -93,14 +93,14 @@ namespace AZ
// This struct will hold the handlers per address
struct HandlerHolder;
// This struct will hold each handler
using HandlerNode = HandlerNode<Interface, Traits, HandlerHolder>;
using HandlerNode = AZ::Internal::HandlerNode<Interface, Traits, HandlerHolder>;
// Defines how handler holders are stored (will be some sort of map-like structure from id -> handler holder)
using AddressStorage = AddressStoragePolicy<Traits, HandlerHolder>;
// Defines how handlers are stored per address (will be some sort of list)
using HandlerStorage = HandlerStoragePolicy<Interface, Traits, HandlerNode>;
using Handler = IdHandler<Interface, Traits, ContainerType>;
using MultiHandler = MultiHandler<Interface, Traits, ContainerType>;
using MultiHandler = AZ::Internal::MultiHandler<Interface, Traits, ContainerType>;
using BusPtr = AZStd::intrusive_ptr<HandlerHolder>;
EBusContainer() = default;
@@ -774,13 +774,13 @@ namespace AZ
// This struct will hold the handler per address
struct HandlerHolder;
// This struct will hold each handler
using HandlerNode = HandlerNode<Interface, Traits, HandlerHolder>;
using HandlerNode = AZ::Internal::HandlerNode<Interface, Traits, HandlerHolder>;
// Defines how handler holders are stored (will be some sort of map-like structure from id -> handler holder)
using AddressStorage = AddressStoragePolicy<Traits, HandlerHolder>;
// No need for HandlerStorage, there's only 1 so it will always just be a HandlerNode*
using Handler = IdHandler<Interface, Traits, ContainerType>;
using MultiHandler = MultiHandler<Interface, Traits, ContainerType>;
using MultiHandler = AZ::Internal::MultiHandler<Interface, Traits, ContainerType>;
using BusPtr = AZStd::intrusive_ptr<HandlerHolder>;
EBusContainer() = default;
@@ -1316,7 +1316,7 @@ namespace AZ
// This struct will hold the handlers per address
struct HandlerHolder;
// This struct will hold each handler
using HandlerNode = HandlerNode<Interface, Traits, HandlerHolder>;
using HandlerNode = AZ::Internal::HandlerNode<Interface, Traits, HandlerHolder>;
// Defines how handlers are stored per address (will be some sort of list)
using HandlerStorage = HandlerStoragePolicy<Interface, Traits, HandlerNode>;
// No need for AddressStorage, there's only 1
@@ -161,7 +161,7 @@ namespace AZ
template <class C>
struct EBusCallstackStorage<C, true>
{
AZ_THREAD_LOCAL static C* s_entry;
static AZ_THREAD_LOCAL C* s_entry;
EBusCallstackStorage() = default;
~EBusCallstackStorage() = default;
+43 -51
View File
@@ -13,50 +13,6 @@
#include <AzCore/IO/Path/PathIterable.inl>
// extern instantiations of Path templates to prevent implicit instantiations
namespace AZ::IO
{
// Class templates explicit declarations
extern template class BasicPath<AZStd::string>;
extern template class BasicPath<FixedMaxPathString>;
extern template class PathIterator<PathView>;
extern template class PathIterator<Path>;
extern template class PathIterator<FixedMaxPath>;
// Swap function explicit declarations
extern template void swap<AZStd::string>(Path& lhs, Path& rhs) noexcept;
extern template void swap<FixedMaxPathString>(FixedMaxPath& lhs, FixedMaxPath& rhs) noexcept;
// Hash function explicit declarations
extern template size_t hash_value<AZStd::string>(const Path& pathToHash);
extern template size_t hash_value<FixedMaxPathString>(const FixedMaxPath& pathToHash);
// Append operator explicit declarations
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, const PathView& rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, const PathView& rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, AZStd::string_view rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, AZStd::string_view rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs,
const typename BasicPath<AZStd::string>::value_type* rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs,
const typename BasicPath<FixedMaxPathString>::value_type* rhs);
// Iterator compare explicit declarations
extern template bool operator==<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator==<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator==<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
extern template bool operator!=<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator!=<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator!=<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
}
//! PathView implementation
namespace AZ::IO
{
@@ -939,13 +895,13 @@ namespace AZ::IO
// then it has no root directory nor filename
if (rootNameView.end() == m_path.end())
{
// has_root_directory || has_filename = false
// If the root name is of the form
// # C: - then it isn't absolute unless it has a root directory C:\
// # \\?\ = is a UNC path that can't exist without a root directory
// # \\server - Is absolute, but has no root directory
// Therefore if the rootName is larger than three characters
// then append the path separator
/* has_root_directory || has_filename = false
If the root name is of the form
C: - then it isn't absolute unless it has a root directory C:\.
\\?\ = is a UNC path that can't exist without a root directory.
\\server - Is absolute, but has no root directory.
Therefore if the rootName is larger than three characters
then append the path separator. */
if (rootNameView.size() >= 3)
{
m_path.push_back(m_preferred_separator);
@@ -1550,3 +1506,39 @@ namespace AZ::IO
return AZStd::hash<PathView>{}(pathToHash);
}
}
// extern instantiations of Path templates to prevent implicit instantiations
namespace AZ::IO
{
// Swap function explicit declarations
extern template void swap<AZStd::string>(Path& lhs, Path& rhs) noexcept;
extern template void swap<FixedMaxPathString>(FixedMaxPath& lhs, FixedMaxPath& rhs) noexcept;
// Hash function explicit declarations
extern template size_t hash_value<AZStd::string>(const Path& pathToHash);
extern template size_t hash_value<FixedMaxPathString>(const FixedMaxPath& pathToHash);
// Append operator explicit declarations
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, const PathView& rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, const PathView& rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, AZStd::string_view rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, AZStd::string_view rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs,
const typename BasicPath<AZStd::string>::value_type* rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs,
const typename BasicPath<FixedMaxPathString>::value_type* rhs);
// Iterator compare explicit declarations
extern template bool operator==<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator==<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator==<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
extern template bool operator!=<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator!=<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator!=<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
}
@@ -14,7 +14,7 @@
#define az_clz_u64(x) _lzcnt_u64(x)
#define az_popcnt_u32(x) __popcnt(x)
#define az_popcnt_u64(x) __popcnt64(x)
#elif defined(AZ_COMPILER_CLANG)
#elif defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
#define az_ctz_u32(x) __builtin_ctz(x)
#define az_ctz_u64(x) __builtin_ctzll(x)
#define az_clz_u32(x) __builtin_clz(x)
@@ -22,5 +22,5 @@
#define az_popcnt_u32(x) __builtin_popcount(x)
#define az_popcnt_u64(x) __builtin_popcountll(x)
#else
#error Count Leading Zeros, Count Trailing Zeros and Pop Count intrinsics isn't supported for this compiler
#error Count Leading Zeros, Count Trailing Zeros and Pop Count intrinsics isnt supported for this compiler
#endif
+3 -5
View File
@@ -26,7 +26,6 @@ namespace AZ
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndDistance(const Vector3& normal, float dist)
{
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
Plane result;
result.Set(normal, dist);
return result;
@@ -35,7 +34,6 @@ namespace AZ
AZ_MATH_INLINE Plane Plane::CreateFromCoefficients(const float a, const float b, const float c, const float d)
{
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
Plane result;
result.Set(a, b, c, d);
return result;
@@ -68,21 +66,21 @@ namespace AZ
AZ_MATH_INLINE void Plane::Set(const Vector3& normal, float d)
{
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
m_plane.Set(normal, d);
}
AZ_MATH_INLINE void Plane::Set(float a, float b, float c, float d)
{
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is not normalized");
m_plane.Set(a, b, c, d);
}
AZ_MATH_INLINE void Plane::SetNormal(const Vector3& normal)
{
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
m_plane.SetX(normal.GetX());
m_plane.SetY(normal.GetY());
m_plane.SetZ(normal.GetZ());
@@ -39,6 +39,9 @@ namespace AZ
template<typename T> constexpr friend void AZStd::destroy_at(T*);
public:
AllocatorManager();
typedef AZStd::function<void (IAllocator* allocator, size_t /*byteSize*/, size_t /*alignment*/, int/* flags*/, const char* /*name*/, const char* /*fileName*/, int lineNum /*=0*/)> OutOfMemoryCBType;
static void PreRegisterAllocator(IAllocator* allocator); // Only call if the environment is not yet attached
@@ -166,7 +169,6 @@ namespace AZ
AZ::Debug::AllocationRecords::Mode m_defaultTrackingRecordMode;
AZStd::unique_ptr<AZ::MallocSchema, void(*)(AZ::MallocSchema*)> m_mallocSchema;
AllocatorManager();
~AllocatorManager();
static AllocatorManager g_allocMgr; ///< The single instance of the allocator manager
@@ -45,7 +45,9 @@ namespace AZ
//! that already exist.
class NameDictionary final
{
public:
AZ_CLASS_ALLOCATOR(NameDictionary, AZ::OSAllocator, 0);
private:
friend Module;
friend Name;
@@ -75,8 +77,8 @@ namespace AZ
//! @return A Name instance. If the hash was not found, the Name will be empty.
Name FindName(Name::Hash hash) const;
private:
NameDictionary();
private:
~NameDictionary();
void ReportStats() const;
+161 -7
View File
@@ -10,10 +10,17 @@
//////////////////////////////////////////////////////////////////////////
// Platforms
#include <AzCore/variadic.h>
#include "PlatformRestrictedFileDef.h"
#if defined(__clang__)
#define AZ_COMPILER_CLANG __clang_major__
#elif defined(__GNUC__)
// Assign AZ_COMPILER_GCC to a number that represents the major+minor (2 digits) + path level (2 digits) i.e. 3.2.0 == 30200
#define AZ_COMPILER_GCC (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#elif defined(_MSC_VER)
#define AZ_COMPILER_MSVC _MSC_VER
#else
@@ -29,7 +36,7 @@
#define AZ_DYNAMIC_LIBRARY_PREFIX AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX
#define AZ_DYNAMIC_LIBRARY_EXTENSION AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION
#if defined(AZ_COMPILER_CLANG)
#if defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
#define AZ_DLL_EXPORT AZ_TRAIT_OS_DLL_EXPORT_CLANG
#define AZ_DLL_IMPORT AZ_TRAIT_OS_DLL_IMPORT_CLANG
#elif defined(AZ_COMPILER_MSVC)
@@ -67,12 +74,36 @@
#if defined(AZ_COMPILER_MSVC)
/// Disables a warning using push style. For use matched with an AZ_POP_WARNING
#define AZ_PUSH_DISABLE_WARNING(_msvcOption, __) \
__pragma(warning(push)) \
// Compiler specific AZ_PUSH_DISABLE_WARNING
#define AZ_PUSH_DISABLE_WARNING_MSVC(_msvcOption) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
#define AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
#define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
/// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
#define AZ_POP_DISABLE_WARNING_CLANG
#define AZ_POP_DISABLE_WARNING_MSVC \
__pragma(warning(pop))
#define AZ_POP_DISABLE_WARNING_GCC
// Variadic definitions for AZ_PUSH_DISABLE_WARNING for the current compiler
#define AZ_PUSH_DISABLE_WARNING_1(_msvcOption) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
#define AZ_PUSH_DISABLE_WARNING_2(_msvcOption, _2) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
#define AZ_PUSH_DISABLE_WARNING_3(_msvcOption, _2, _3) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
/// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
#define AZ_POP_DISABLE_WARNING \
#define AZ_POP_DISABLE_WARNING \
__pragma(warning(pop))
@@ -94,17 +125,62 @@
# define AZ_FUNCTION_SIGNATURE __FUNCSIG__
//////////////////////////////////////////////////////////////////////////
#elif defined(AZ_COMPILER_CLANG)
#elif defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
#if defined(AZ_COMPILER_CLANG)
/// Disables a single warning using push style. For use matched with an AZ_POP_WARNING
#define AZ_PUSH_DISABLE_WARNING(__, _clangOption) \
_Pragma("clang diagnostic push") \
// Compiler specific AZ_PUSH_DISABLE_WARNING
#define AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption) \
_Pragma("clang diagnostic push") \
_Pragma(AZ_STRINGIZE(clang diagnostic ignored _clangOption))
#define AZ_PUSH_DISABLE_WARNING_MSVC(_msvcOption)
#define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
/// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
#define AZ_POP_DISABLE_WARNING_CLANG \
_Pragma("clang diagnostic pop")
#define AZ_POP_DISABLE_WARNING_MSVC
#define AZ_POP_DISABLE_WARNING_GCC
// Variadic definitions for AZ_PUSH_DISABLE_WARNING for the current compiler
#define AZ_PUSH_DISABLE_WARNING_1(_1)
#define AZ_PUSH_DISABLE_WARNING_2(_1, _clangOption) AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
#define AZ_PUSH_DISABLE_WARNING_3(_1, _clangOption, _2) AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
/// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
#define AZ_POP_DISABLE_WARNING \
_Pragma("clang diagnostic pop")
#else
/// Disables a single warning using push style. For use matched with an AZ_POP_WARNING
// Compiler specific AZ_PUSH_DISABLE_WARNING
#define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption) \
_Pragma("GCC diagnostic push") \
_Pragma(AZ_STRINGIZE(GCC diagnostic ignored _gccOption))
#define AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
#define AZ_PUSH_DISABLE_WARNING_MSVC(_msvcOption)
/// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
#define AZ_POP_DISABLE_WARNING_CLANG
#define AZ_POP_DISABLE_WARNING_MSVC
#define AZ_POP_DISABLE_WARNING_GCC \
_Pragma("GCC diagnostic pop")
// Variadic definitions for AZ_PUSH_DISABLE_WARNING for the current compiler
#define AZ_PUSH_DISABLE_WARNING_1(_1)
#define AZ_PUSH_DISABLE_WARNING_2(_1, _2)
#define AZ_PUSH_DISABLE_WARNING_3(_1, _2, _gccOption) AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
/// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
#define AZ_POP_DISABLE_WARNING
_Pragma("GCC diagnostic pop")
#endif // defined(AZ_COMPILER_CLANG)
#define AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
#define AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
#define AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
@@ -121,6 +197,8 @@
#error Compiler not supported
#endif
#define AZ_PUSH_DISABLE_WARNING(...) AZ_MACRO_SPECIALIZE(AZ_PUSH_DISABLE_WARNING_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
// We need to define AZ_DEBUG_BUILD in debug mode. We can also define it in debug optimized mode (left up to the user).
// note that _DEBUG is not in fact always defined on all platforms, and only AZ_DEBUG_BUILD should be relied on.
#if !defined(AZ_DEBUG_BUILD) && defined(_DEBUG)
@@ -149,3 +227,79 @@
#if !defined(AZ_COMMAND_LINE_LEN)
# define AZ_COMMAND_LINE_LEN 2048
#endif
#include <type_traits>
#include <utility>
#include <memory>
#include <cstdint>
#include <cstring>
// First check if the feature if is_constant_evaluated is available via the feature test macro
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros#C.2B.2B20
#if __cpp_lib_is_constant_evaluated
#define az_builtin_is_constant_evaluated() std::is_constant_evaluated()
#endif
// Next check if there is a __builtin_is_constant_evaluated that can be used
// This works on MSVC 19.28+ toolsets when using C++17, as well as
// clang 9.0.0+ when using C++17.
// Finally it works on gcc 9.0+ when using C++17
#if !defined(az_builtin_is_constant_evaluated)
#if defined(__has_builtin)
#if __has_builtin(__builtin_is_constant_evaluated)
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() true
#endif
#elif AZ_COMPILER_MSVC >= 1928
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() true
#elif AZ_COMPILER_GCC
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() true
#endif
#endif
// In this case no support for the determining whether an operation is occuring
// at compile time is supported so assume that evaluation is always occuring at compile time
// in order to make sure the "safe" operation is being performed
#if !defined(az_builtin_is_constant_evaluated)
namespace AZ::Internal
{
constexpr bool builtin_is_constant_evaluated()
{
return true;
}
}
#define az_builtin_is_constant_evaluated() AZ::Internal::builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() false
#endif
// define builtin functions used by char_traits class for efficient compile time and runtime
// operations
#if defined(__has_builtin)
#if __has_builtin(__builtin_memcpy)
#define az_has_builtin_memcpy true
#endif
#if __has_builtin(__builtin_wmemcpy)
#define az_has_builtin_wmemcpy true
#endif
#if __has_builtin(__builtin_memmove)
#define az_has_builtin_memmove true
#endif
#if __has_builtin(__builtin_wmemmove)
#define az_has_builtin_wmemmove true
#endif
#endif
#if !defined(az_has_builtin_memcpy)
#define az_has_builtin_memcpy false
#endif
#if !defined(az_has_builtin_wmemcpy)
#define az_has_builtin_wmemcpy false
#endif
#if !defined(az_has_builtin_memmove)
#define az_has_builtin_memmove false
#endif
#if !defined(az_has_builtin_wmemmove)
#define az_has_builtin_wmemmove false
#endif
@@ -1541,7 +1541,7 @@ namespace AZ
}
template<class T>
static bool SetClassEqualityComparer(BehaviorClass* behaviorClass, const T*)
static void SetClassEqualityComparer(BehaviorClass* behaviorClass, const T*)
{
behaviorClass->m_equalityComparer = &DefaultEqualityComparer<T>;
}
@@ -2341,8 +2341,6 @@ namespace AZ
// For some reason the Script.cpp test validates that an incomplete type can be used with the SetResult struct
template<typename T, typename U, typename = void>
static constexpr bool IsCopyAssignable = false;
template<typename T, typename U>
static constexpr bool IsCopyAssignable<T, U, AZStd::void_t<decltype(AZStd::declval<T>() = AZStd::declval<U>())>> = true;
template<class T>
static bool Set(BehaviorValueParameter& param, T&& result, bool IsValueCopy)
@@ -2402,6 +2400,9 @@ namespace AZ
}
};
template<typename T, typename U>
constexpr bool SetResult::IsCopyAssignable<T, U, AZStd::void_t<decltype(AZStd::declval<T>() = AZStd::declval<U>())>> = true;
AZ_FORCE_INLINE BehaviorValueParameter& BehaviorValueParameter::operator=(BehaviorValueParameter&& other)
{
*static_cast<BehaviorParameter*>(this) = AZStd::move(static_cast<BehaviorParameter&&>(other));
+21 -8
View File
@@ -977,26 +977,32 @@ namespace AZ
{
return AzGenericTypeInfo::Uuid<U>();
}
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class U, typename = void>
#else
template<template<auto...> class U, typename = void>
#endif // defined(AZ_COMPILER_MSVC)
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
}
template<template<typename, AZStd::size_t> class U, typename = void>
template<template<typename, auto> class U, typename = void>
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
}
template<template<typename, typename, AZStd::size_t> class U, typename = void>
template<template<typename, typename, auto> class U, typename = void>
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
}
template<template<typename, typename, typename, AZStd::size_t> class U, typename = void>
template<template<typename, typename, typename, auto> class U, typename = void>
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
@@ -1027,15 +1033,22 @@ namespace AZ
}
// Returns true if the type is contained, otherwise false. Safe to call for type not supporting AZRtti (returns false unless type fully match).
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class T, class U>
inline bool RttiIsTypeOf(const U&)
#else
template<template<auto...> class T, class U>
#endif // defined(AZ_COMPILER_MSVC)
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
return AzGenericTypeInfo::Uuid<T>() == RttiTypeId<CheckType, AZ::GenericTypeIdTag>();
}
// Returns true if the type is contained, otherwise false. Safe to call for type not supporting AZRtti (returns false unless type fully match).
template<template<typename, AZStd::size_t> class T, class U>
template<template<typename, auto> class T, class U>
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
@@ -1043,7 +1056,7 @@ namespace AZ
}
// Returns true if the type is contained, otherwise false.Safe to call for type not supporting AZRtti(returns false unless type fully match).
template<template<typename, typename, AZStd::size_t> class T, class U>
template<template<typename, typename, auto> class T, class U>
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
@@ -1051,7 +1064,7 @@ namespace AZ
}
// Returns true if the type is contained, otherwise false.Safe to call for type not supporting AZRtti(returns false unless type fully match).
template<template<typename, typename, typename, AZStd::size_t> class T, class U>
template<template<typename, typename, typename, auto> class T, class U>
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
+24 -12
View File
@@ -148,11 +148,18 @@ namespace AZ
{
/// Needs to match declared parameter type.
template <template <typename...> class> constexpr bool false_v1 = false;
template <template <AZStd::size_t...> class> constexpr bool false_v2 = false;
template <template <typename, AZStd::size_t> class> constexpr bool false_v3 = false;
template <template <typename, typename, AZStd::size_t> class> constexpr bool false_v4 = false;
template <template <typename, typename, typename, AZStd::size_t> class> constexpr bool false_v5 = false;
template <template <typename, AZStd::size_t, typename> class> constexpr bool false_v6 = false;
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class> constexpr bool false_v2 = false;
#else
template<template<auto...> class> constexpr bool false_v2 = false;
#endif // defined(AZ_COMPILER_MSVC)
template<template<typename, auto> class>
constexpr bool false_v3 = false;
template <template <typename, typename, auto> class> constexpr bool false_v4 = false;
template <template <typename, typename, typename, auto> class> constexpr bool false_v5 = false;
template <template <typename, auto, typename> class> constexpr bool false_v6 = false;
template<typename T>
inline const AZ::TypeId& Uuid()
@@ -167,8 +174,13 @@ namespace AZ
static const AZ::TypeId s_uuid = AZ::TypeId::CreateNull();
return s_uuid;
}
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class T>
#else
template<template<auto...> class T>
#endif // defined(AZ_COMPILER_MSVC)
inline const AZ::TypeId& Uuid()
{
static_assert(false_v2<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -176,7 +188,8 @@ namespace AZ
return s_uuid;
}
template<template<typename, AZStd::size_t> class T>
template<template<typename, auto> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v3<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -184,7 +197,7 @@ namespace AZ
return s_uuid;
}
template<template<typename, typename, AZStd::size_t> class T>
template<template<typename, typename, auto> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v4<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -192,7 +205,7 @@ namespace AZ
return s_uuid;
}
template<template<typename, typename, typename, AZStd::size_t> class T>
template<template<typename, typename, typename, auto> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v5<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -200,7 +213,7 @@ namespace AZ
return s_uuid;
}
template<template<typename, AZStd::size_t, typename> class T>
template<template<typename, auto, typename> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v6<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -689,8 +702,7 @@ namespace AZ
#define AZ_TYPE_INFO_INTERNAL_CLASS_VARARGS__UUID(Tag, A) AZ::Internal::AggregateTypes< A... >::template Uuid< Tag >()
#define AZ_TYPE_INFO_INTERNAL_CLASS_VARARGS__NAME(A) AZ::Internal::AggregateTypes< A... >::TypeName(typeName, AZ_ARRAY_SIZE(typeName));
// Once C++17 has been introduced size_t can be replaced with auto for all integer non-type arguments
#define AZ_TYPE_INFO_INTERNAL_AUTO__TYPE AZStd::size_t
#define AZ_TYPE_INFO_INTERNAL_AUTO__TYPE auto
#define AZ_TYPE_INFO_INTERNAL_AUTO__ARG(A) A
#define AZ_TYPE_INFO_INTERNAL_AUTO__UUID(Tag, A) AZ::Internal::GetTypeId< A , Tag >()
#define AZ_TYPE_INFO_INTERNAL_AUTO__NAME(A) AZ::Internal::AzTypeInfoSafeCat(typeName, AZ_ARRAY_SIZE(typeName), AZ::Internal::GetTypeName< A >())
@@ -796,7 +796,7 @@ namespace AZ
// Note: Always use l over context->NativeContext(), as require may be called from a thread.
using RequireHook = AZStd::function<int(lua_State* lua, ScriptContext* context, const char* module)>;
using StackVariableAllocator = StackVariableAllocator;
using StackVariableAllocator = AZ::StackVariableAllocator;
/// Stack temporary memory
/**
@@ -69,7 +69,13 @@ namespace AZ
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
}
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class T>
#else
template<template<auto...> class T>
#endif // defined(AZ_COMPILER_MSVC)
SerializerBuilder* HandlesType(bool overwriteExisting = false)
{
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
@@ -17,16 +17,9 @@
#if defined(HAVE_BENCHMARK)
#if defined(AZ_COMPILER_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif // clang
AZ_PUSH_DISABLE_WARNING(, "-Wdeprecated-declarations", "-Wdeprecated-declarations")
#include <benchmark/benchmark.h>
#if defined(AZ_COMPILER_CLANG)
#pragma clang diagnostic pop
#endif // clang
AZ_POP_DISABLE_WARNING
#endif // HAVE_BENCHMARK
@@ -71,18 +64,35 @@ namespace UnitTest
};
/**
* RAII wrapper of AllocatorBase.
* The benefit of using this wrapper instead of AllocatorsTestFixture is that SetUp/TearDown of the allocator is managed
* on construction/destruction, allowing member variables of derived classes to exist as value (and do heap allocation).
*/
class ScopedAllocatorSetupFixture
: public ::testing::Test
, AllocatorsBase
* RAII wrapper of AllocatorBase.
* The benefit of using this wrapper instead of AllocatorsTestFixture is that SetUp/TearDown of the allocator is managed
* on construction/destruction, allowing member variables of derived classes to exist as value (and do heap allocation).
*/
class ScopedAllocatorFixture : AllocatorsBase
{
public:
ScopedAllocatorSetupFixture() { SetupAllocator(); }
explicit ScopedAllocatorSetupFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) { SetupAllocator(allocatorDesc); }
~ScopedAllocatorSetupFixture() { TeardownAllocator(); }
ScopedAllocatorFixture()
{
SetupAllocator();
}
explicit ScopedAllocatorFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc)
{
SetupAllocator(allocatorDesc);
}
~ScopedAllocatorFixture() override
{
TeardownAllocator();
}
};
// Like ScopedAllocatorFixture, but includes the Test base class
class ScopedAllocatorSetupFixture
: public ::testing::Test
, public ScopedAllocatorFixture
{
public:
ScopedAllocatorSetupFixture() = default;
explicit ScopedAllocatorSetupFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) : ScopedAllocatorFixture(allocatorDesc){}
};
/**
@@ -114,6 +124,7 @@ namespace UnitTest
using AllocatorsFixture = AllocatorsTestFixture;
#if defined(HAVE_BENCHMARK)
/**
* Helper class to handle the boiler plate of setting up a benchmark fixture that uses the system allocators
* If you wish to do additional setup and tear down be sure to call the base class SetUp first and TearDown
@@ -218,7 +229,7 @@ namespace UnitTest
static constexpr bool sHasPadding = size < alignment;
AZStd::enable_if<sHasPadding, char[(alignment - size) % alignment]> mPadding;
};
template <AZ::u32 size, AZ::u8 instance, size_t alignment>
int CreationCounter<size, instance, alignment>::s_count = 0;
template <AZ::u32 size, AZ::u8 instance, size_t alignment>
@@ -9,6 +9,7 @@
set(FILES
base.h
Docs.h
variadic.h
Platform.cpp
Platform.h
PlatformDef.h
@@ -117,6 +118,10 @@ set(FILES
DOM/DomBackend.h
DOM/DomUtils.cpp
DOM/DomUtils.h
DOM/DomValue.cpp
DOM/DomValue.h
DOM/DomValueWriter.cpp
DOM/DomValueWriter.h
DOM/DomVisitor.cpp
DOM/DomVisitor.h
DOM/Backends/JSON/JsonBackend.h
+1 -60
View File
@@ -7,6 +7,7 @@
*/
#pragma once
#include <AzCore/variadic.h>
#include <AzCore/PlatformDef.h> ///< Platform/compiler specific defines
#include <AzCore/base_Platform.h>
@@ -135,66 +136,6 @@
#define AZ_INVALID_POINTER reinterpret_cast<void*>(0x0badf00dul)
// Variadic MACROS util functions
/**
* AZ_VA_NUM_ARGS
* counts number of parameters (up to 10).
* example. AZ_VA_NUM_ARGS(x,y,z) -> expands to 3
*/
#ifndef AZ_VA_NUM_ARGS
# define AZ_VA_HAS_ARGS(...) ""#__VA_ARGS__[0] != 0
// we add the zero to avoid the case when we require at least 1 param at the end...
# define AZ_VA_NUM_ARGS(...) AZ_VA_NUM_ARGS_IMPL_((__VA_ARGS__, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
# define AZ_VA_NUM_ARGS_IMPL_(tuple) AZ_VA_NUM_ARGS_IMPL tuple
# define AZ_VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, N, ...) N
// Expands a macro and calls a different macro based on the number of arguments.
//
// Example: We need to specialize a macro for 1 and 2 arguments
// #define AZ_MY_MACRO(...) AZ_MACRO_SPECIALIZE(AZ_MY_MACRO_,AZ_VA_NUM_ARGS(__VA_ARGS__),(__VA_ARGS__))
//
// #define AZ_MY_MACRO_1(_1) /* code for 1 param */
// #define AZ_MY_MACRO_2(_1,_2) /* code for 2 params */
// ... etc.
//
//
// We have 3 levels of macro expansion...
# define AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS) MACRO_NAME##NPARAMS PARAMS
# define AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS)
# define AZ_MACRO_SPECIALIZE(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS)
#endif // AZ_VA_NUM_ARGS
// Out of all supported compilers, mwerks is the only one
// that requires variadic macros to have at least 1 param.
// This is a pain they we use macros to call functions (with no params).
// we implement functions for up to 10 params
#define AZ_FUNCTION_CALL_1(_1) _1()
#define AZ_FUNCTION_CALL_2(_1, _2) _1(_2)
#define AZ_FUNCTION_CALL_3(_1, _2, _3) _1(_2, _3)
#define AZ_FUNCTION_CALL_4(_1, _2, _3, _4) _1(_2, _3, _4)
#define AZ_FUNCTION_CALL_5(_1, _2, _3, _4, _5) _1(_2, _3, _4, _5)
#define AZ_FUNCTION_CALL_6(_1, _2, _3, _4, _5, _6) _1(_2, _3, _4, _5, _6)
#define AZ_FUNCTION_CALL_7(_1, _2, _3, _4, _5, _6, _7) _1(_2, _3, _4, _5, _6, _7)
#define AZ_FUNCTION_CALL_8(_1, _2, _3, _4, _5, _6, _7, _8) _1(_2, _3, _4, _5, _6, _7, _8)
#define AZ_FUNCTION_CALL_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) _1(_2, _3, _4, _5, _6, _7, _8, _9)
#define AZ_FUNCTION_CALL_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) _1(_2, _3, _4, _5, _6, _7, _8, _9, _10)
// We require at least 1 param FunctionName
#define AZ_FUNCTION_CALL(...) AZ_MACRO_SPECIALIZE(AZ_FUNCTION_CALL_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
// Based on boost macro expansion fix...
#define AZ_PREVENT_MACRO_SUBSTITUTION
//////////////////////////////////////////////////////////////////////////
#include <cstddef> // the macros NULL and offsetof as well as the types ptrdiff_t, wchar_t, and size_t.
@@ -11,17 +11,17 @@
namespace AZStd
{
stateless_allocator::stateless_allocator(const char* name)
: m_name(name) {}
stateless_allocator::stateless_allocator() = default;
stateless_allocator::stateless_allocator(const char*)
{}
const char* stateless_allocator::get_name() const
{
return m_name;
return "AZStd::stateless_allocator";
}
void stateless_allocator::set_name(const char* name)
void stateless_allocator::set_name(const char*)
{
m_name = name;
}
auto stateless_allocator::allocate(size_type byteSize) -> pointer_type
@@ -26,7 +26,8 @@ namespace AZStd
using difference_type = ptrdiff_t;
using allow_memory_leaks = AZStd::true_type;
stateless_allocator(const char* name = "AZStd::stateless_allocator");
stateless_allocator();
explicit stateless_allocator(const char*); // Stateless allocator does not store a name
stateless_allocator(const stateless_allocator& rhs) = default;
stateless_allocator& operator=(const stateless_allocator& rhs) = default;
@@ -51,9 +52,6 @@ namespace AZStd
bool is_lock_free();
bool is_stale_read_allowed();
bool is_delayed_recycling();
private:
const char* m_name;
};
bool operator==(const stateless_allocator& left, const stateless_allocator& right);
@@ -64,6 +64,8 @@ set(FILES
containers/rbtree.h
containers/ring_buffer.h
containers/set.h
containers/span.h
containers/span.inl
containers/stack.h
containers/unordered_map.h
containers/unordered_set.h
@@ -8,6 +8,8 @@
#pragma once
#include <AzCore/std/utils.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/typetraits/is_constructible.h>
#include <AzCore/std/typetraits/remove_cvref.h>
/* Microsoft C++ ABI puts 1 byte of padding between each empty base class when multiple inheritance is being used
@@ -20,7 +22,7 @@
#if defined(AZ_COMPILER_MSVC)
#define AZSTD_COMPRESSED_PAIR_EMPTY_BASE_OPTIMIZATION __declspec(empty_bases)
#else
#define AZSTD_COMPRESSED_PAIR_EMPTY_BASE_OPTIMIZATION
#define AZSTD_COMPRESSED_PAIR_EMPTY_BASE_OPTIMIZATION
#endif
namespace AZStd
@@ -97,16 +99,14 @@ namespace AZStd
using second_base_value_type = typename second_base_type::value_type;
public:
// First template argument is a placeholder argument of void as MSVC examines the types
// of a templated function to determine if they are the same template
// Due to the "template <class T> compressed_pair(skip_element_tag, T&&)"
// constructor below, the default constructor template types needs to be distinguished from it
template <typename = void, typename = AZStd::enable_if_t<
AZStd::is_default_constructible<first_base_value_type>::value
&& AZStd::is_default_constructible<second_base_value_type>::value>>
// First template argument is used to perform a substitution into AZStd::enable_if_t
// so that SFINAE can trigger
template <typename Unused = void, typename = AZStd::enable_if_t<
AZStd::is_default_constructible_v<first_base_value_type>
&& AZStd::is_default_constructible_v<second_base_value_type>, Unused>>
constexpr compressed_pair();
template <typename T, AZStd::enable_if_t<!is_same<remove_cvref_t<T>, compressed_pair>::value, bool> = true>
template <typename T, AZStd::enable_if_t<!is_same_v<remove_cvref_t<T>, compressed_pair>, bool> = true>
constexpr explicit compressed_pair(T&& firstElement);
template <typename T>
@@ -75,7 +75,7 @@ namespace AZStd
}
template <typename T1, typename T2>
template <typename T, AZStd::enable_if_t<!is_same<remove_cvref_t<T>, compressed_pair<T1, T2>>::value, bool>>
template <typename T, AZStd::enable_if_t<!is_same_v<remove_cvref_t<T>, compressed_pair<T1, T2>>, bool>>
inline constexpr compressed_pair<T1, T2>::compressed_pair(T&& firstElement)
: first_base_type{ AZStd::forward<T>(firstElement) }
, second_base_type{}
@@ -117,7 +117,7 @@ namespace AZStd
{
return static_cast<const first_base_type&>(*this).get();
}
template <typename T1, typename T2>
inline constexpr auto compressed_pair<T1, T2>::second() -> second_base_value_type&
{
@@ -253,7 +253,7 @@ namespace AZStd::Internal
}
template <typename U, typename = enable_if_t<is_convertible_v<U, T>>>
fixed_non_trivial_storage(AZStd::initializer_list<U> ilist) noexcept(noexcept(emplace_back(AZStd::declval<U>())))
fixed_non_trivial_storage(AZStd::initializer_list<U> ilist) noexcept(noexcept(this->emplace_back(AZStd::declval<U>())))
{
AZSTD_CONTAINER_ASSERT(ilist.size() <= capacity(), "Initializer list cannot be larger than storage capacity");
for (const U& element : ilist)
@@ -79,7 +79,7 @@ namespace AZStd
typedef typename tree_type::const_reverse_iterator const_reverse_iterator;
using node_type = map_node_handle<map_node_traits<key_type, mapped_type, allocator_type, typename tree_type::node_type, typename tree_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE explicit map(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: m_tree(comp, alloc) {}
@@ -123,7 +123,8 @@ namespace AZStd
}
}
friend void swap(node_handle& lhs, node_handle& rhs);
template <typename SwapNodeTraits, template <typename, typename> class SwapMapOrSetNodeHandleBase>
friend void swap(node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& lhs, node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& rhs);
private:
node_handle(node_pointer_type node, const allocator_type& allocator)
@@ -152,8 +153,8 @@ namespace AZStd
optional<allocator_type> m_allocator;
};
template <typename NodeTraits, template <typename, typename> class MapOrSetNodeHandleBase>
void swap(node_handle<NodeTraits, MapOrSetNodeHandleBase>& lhs, node_handle<NodeTraits, MapOrSetNodeHandleBase>& rhs)
template <typename SwapNodeTraits, template <typename, typename> class SwapMapOrSetNodeHandleBase>
void swap(node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& lhs, node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& rhs)
{
lhs.swap(rhs);
}
@@ -68,7 +68,7 @@ namespace AZStd
typedef typename tree_type::const_reverse_iterator const_reverse_iterator;
using node_type = set_node_handle<set_node_traits<value_type, allocator_type, typename tree_type::node_type, typename tree_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE explicit set(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: m_tree(comp, alloc) {}
@@ -0,0 +1,129 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/fixed_vector.h>
#include <AzCore/std/containers/array.h>
namespace AZStd
{
/**
* First pass partial implementation of span copied over from array_view. It
* returns non-const iterator/pointers. first(), last(), and subspan()
* are yet to be implemented. It does not maintain storage for the data,
* but just holds pointers to mark the beginning and end of the array.
* It can be conveniently constructed from a variety of other container
* types like array, vector, and fixed_vector.
*
* Example:
* Given "void Func(AZStd::span<int> a) {...}" you can call...
* - Func({1,2,3});
* - AZStd::array<int,3> a = {1,2,3};
* Func(a);
* - AZStd::vector<int> v = {1,2,3};
* Func(v);
* - AZStd::fixed_vector<int,10> fv = {1,2,3};
* Func(fv);
*
* Since the span does not copy and store any data, it is only valid as long as the data used to create it is valid.
*/
template <class T>
class span final
{
public:
using element_type = T;
using value_type = AZStd::remove_cv_t<T>;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = AZStd::size_t;
using difference_type = AZStd::ptrdiff_t;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = AZStd::reverse_iterator<iterator>;
using const_reverse_iterator = AZStd::reverse_iterator<const_iterator>;
constexpr span();
~span() = default;
constexpr span(pointer s, size_type length);
constexpr span(pointer first, pointer last);
// We explicitly delete this constructor because it's too easy to accidentally
// create a span to just the first element instead of an entire array.
constexpr span(const_pointer s) = delete;
template<typename Container>
constexpr span(Container& data);
template<typename Container>
constexpr span(const Container& data);
constexpr span(const span&) = default;
constexpr span(span&& other);
constexpr span& operator=(const span& other) = default;
constexpr span& operator=(span&& other);
constexpr size_type size() const;
constexpr bool empty() const;
constexpr pointer data();
constexpr const_pointer data() const;
constexpr const_reference operator[](size_type index) const;
constexpr reference operator[](size_type index);
constexpr void erase();
constexpr iterator begin();
constexpr iterator end();
constexpr const_iterator begin() const;
constexpr const_iterator end() const;
constexpr const_iterator cbegin() const;
constexpr const_iterator cend() const;
constexpr reverse_iterator rbegin();
constexpr reverse_iterator rend();
constexpr const_reverse_iterator rbegin() const;
constexpr const_reverse_iterator rend() const;
constexpr const_reverse_iterator crbegin() const;
constexpr const_reverse_iterator crend() const;
friend bool operator==(span lhs, span rhs)
{
return lhs.m_begin == rhs.m_begin && lhs.m_end == rhs.m_end;
}
friend bool operator!=(span lhs, span rhs) { return !(lhs == rhs); }
friend bool operator< (span lhs, span rhs) { return lhs.m_begin < rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end < rhs.m_end; }
friend bool operator> (span lhs, span rhs) { return lhs.m_begin > rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end > rhs.m_end; }
friend bool operator<=(span lhs, span rhs) { return lhs == rhs || lhs < rhs; }
friend bool operator>=(span lhs, span rhs) { return lhs == rhs || lhs > rhs; }
private:
pointer m_begin;
pointer m_end;
};
} // namespace AZStd
#include <AzCore/std/containers/span.inl>
@@ -0,0 +1,124 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AZStd
{
template <class Element>
inline constexpr span<Element>::span()
: m_begin(nullptr)
, m_end(nullptr)
{ }
template <class Element>
inline constexpr span<Element>::span(pointer s, size_type length)
: m_begin(s)
, m_end(m_begin + length)
{
if (length == 0) erase();
}
template <class Element>
inline constexpr span<Element>::span(pointer first, pointer last)
: m_begin(first)
, m_end(last)
{ }
template<class Element>
template<typename Container>
inline constexpr span<Element>::span(Container& data)
: m_begin(data.data())
, m_end(m_begin + data.size())
{ }
template<class Element>
template<typename Container>
inline constexpr span<Element>::span(const Container& data)
: m_begin(data.data())
, m_end(m_begin + data.size())
{ }
template <class Element>
inline constexpr span<Element>::span(span&& other)
: span(other.m_begin, other.m_end)
{
#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging
other.m_begin = nullptr;
other.m_end = nullptr;
#endif
}
template <class Element>
inline constexpr AZStd::size_t span<Element>::size() const { return m_end - m_begin; }
template <class Element>
inline constexpr bool span<Element>::empty() const { return m_end == m_begin; }
template <class Element>
inline constexpr Element* span<Element>::data() { return m_begin; }
template <class Element>
inline constexpr const Element* span<Element>::data() const { return m_begin; }
template <class Element>
inline constexpr span<Element>& span<Element>::operator=(span<Element>&& other)
{
m_begin = other.m_begin;
m_end = other.m_end;
#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging
other.m_begin = nullptr;
other.m_end = nullptr;
#endif
return *this;
}
template <class Element>
inline constexpr const Element& span<Element>::operator[](AZStd::size_t index) const
{
AZ_Assert(index < size(), "index value is out of range");
return m_begin[index];
}
template <class Element>
inline constexpr Element& span<Element>::operator[](AZStd::size_t index)
{
AZ_Assert(index < size(), "index value is out of range");
return m_begin[index];
}
template <class Element>
inline constexpr void span<Element>::erase() { m_begin = m_end = nullptr; }
template <class Element>
inline constexpr Element* span<Element>::begin() { return m_begin; }
template <class Element>
inline constexpr Element* span<Element>::end() { return m_end; }
template <class Element>
inline constexpr const Element* span<Element>::begin() const { return m_begin; }
template <class Element>
inline constexpr const Element* span<Element>::end() const { return m_end; }
template <class Element>
inline constexpr const Element* span<Element>::cbegin() const { return m_begin; }
template <class Element>
inline constexpr const Element* span<Element>::cend() const { return m_end; }
template <class Element>
inline constexpr AZStd::reverse_iterator<Element*> span<Element>::rbegin() { return AZStd::reverse_iterator<Element*>(m_end); }
template <class Element>
inline constexpr AZStd::reverse_iterator<Element*> span<Element>::rend() { return AZStd::reverse_iterator<Element*>(m_begin); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::rbegin() const { return AZStd::reverse_iterator<const Element*>(m_end); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::rend() const { return AZStd::reverse_iterator<const Element*>(m_begin); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::crbegin() const { return AZStd::reverse_iterator<const Element*>(cend()); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::crend() const { return AZStd::reverse_iterator<const Element*>(cbegin()); }
} // namespace AZStd
@@ -102,7 +102,7 @@ namespace AZStd
typedef typename base_type::pair_iter_bool pair_iter_bool;
using node_type = map_node_handle<map_node_traits<key_type, mapped_type, allocator_type, typename base_type::list_node_type, typename base_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE unordered_map()
: base_type(hasher(), key_eq(), allocator_type()) {}
@@ -87,7 +87,7 @@ namespace AZStd
typedef typename base_type::const_local_iterator const_local_iterator;
using node_type = set_node_handle<set_node_traits<value_type, allocator_type, typename base_type::list_node_type, typename base_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE unordered_set()
: base_type(hasher(), key_eq(), allocator_type()) {}
@@ -954,25 +954,6 @@ namespace AZStd
return true;
}
/// Validates an iter iterator. Returns a combination of \ref iterator_status_flag.
AZ_FORCE_INLINE int validate_iterator(const iterator& iter) const
{
#ifdef AZSTD_HAS_CHECKED_ITERATORS
AZ_Assert(iter.m_container == this, "Iterator doesn't belong to this container");
pointer iterPtr = iter.m_iter;
#else
pointer iterPtr = iter;
#endif
if (iterPtr < m_start || iterPtr > m_last)
{
return isf_none;
}
else if (iterPtr == m_last)
{
return isf_valid;
}
return isf_valid | isf_can_dereference;
}
AZ_FORCE_INLINE int validate_iterator(const const_iterator& iter) const
{
#ifdef AZSTD_HAS_CHECKED_ITERATORS
@@ -992,7 +973,6 @@ namespace AZStd
return isf_valid | isf_can_dereference;
}
AZ_FORCE_INLINE int validate_iterator(const reverse_iterator& iter) const { return validate_iterator(iter.base()); }
AZ_FORCE_INLINE int validate_iterator(const const_reverse_iterator& iter) const { return validate_iterator(iter.base()); }
/**
@@ -279,11 +279,11 @@ namespace AZStd
reinterpret_cast<functor_type*>(&in_buffer.data);
if (op == clone_functor_tag)
{
new ((void*)&out_buffer.data)functor_type(*in_functor);
AZStd::construct_at(reinterpret_cast<functor_type*>(&out_buffer), functor_type(*in_functor));
}
else if (op == move_functor_tag)
{
new ((void*)&out_buffer.data)functor_type(AZStd::move(*in_functor));
AZStd::construct_at(reinterpret_cast<functor_type*>(&out_buffer), functor_type(AZStd::move(*in_functor)));
// Casting via union to get around compiler warnings (strict type on GCC, unused variable on MSVC)
union
{
@@ -291,7 +291,7 @@ namespace AZStd
assign_functor(FunctionObj&& f, function_buffer& functor, AZStd::true_type)
{
using RawFunctorObjType = AZStd::decay_t<FunctionObj>;
new ((void*)&functor.data)RawFunctorObjType(AZStd::forward<FunctionObj>(f));
AZStd::construct_at(reinterpret_cast<RawFunctorObjType*>(&functor), RawFunctorObjType(AZStd::forward<FunctionObj>(f)));
}
template<typename FunctionObj, typename Allocator>
void
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/std/typetraits/typetraits.h>
#include <AzCore/std/typetraits/invoke_traits.h>
namespace AZStd
@@ -343,26 +343,6 @@ namespace AZStd
static decltype(auto) format(const wchar_t* format, ...);
protected:
template<class InputIt>
constexpr auto append_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
template<class InputIt>
constexpr auto construct_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>>;
template<class InputIt>
constexpr auto assign_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
template<class InputIt>
constexpr auto insert_iter(const_iterator insertPos, InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>;
template<class InputIt>
constexpr auto replace_iter(const_iterator first, const_iterator last, InputIt first2, InputIt last2)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
constexpr auto fits_in_capacity(size_type newSize) -> bool;
inline static constexpr size_type Capacity = MaxElementCount; // current storage reserved for string not including null-terminator
@@ -30,9 +30,8 @@ namespace AZStd
// #3
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const basic_fixed_string& rhs,
size_type rhsOffset)
size_type rhsOffset) : basic_fixed_string(rhs, rhsOffset, npos)
{ // construct from rhs [rhsOffset, npos)
assign(rhs, rhsOffset, npos);
}
// #3
@@ -40,7 +39,15 @@ namespace AZStd
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const basic_fixed_string& rhs,
size_type rhsOffset, size_type count)
{ // construct from rhs [rhsOffset, rhsOffset + count)
assign(rhs, rhsOffset, count);
AZSTD_CONTAINER_ASSERT(rhs.size() >= rhsOffset, "Invalid offset");
size_type num = AZStd::min(count, rhs.size() - rhsOffset);
// make room and assign new stuff
pointer data = m_buffer;
const_pointer rhsData = rhs.m_buffer;
Traits::copy(data, rhsData + rhsOffset, num);
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
// #4
@@ -62,28 +69,24 @@ namespace AZStd
template<class InputIt, typename>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(InputIt first, InputIt last)
{ // construct from [first, last)
if (first == last)
{
Traits::assign(m_buffer[0], Element()); // terminate
}
else
{
construct_iter(first, last);
}
assign(first, last);
}
// #7
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const basic_fixed_string& rhs)
: basic_fixed_string(rhs, size_type(0), npos)
{
assign(rhs, size_type(0), npos);
}
// #8
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(basic_fixed_string&& rhs)
{
assign(AZStd::move(rhs));
Traits::copy(m_buffer, rhs.m_buffer, rhs.size() + 1);
m_size = rhs.m_size;
rhs.m_size = 0;
Traits::assign(rhs.m_buffer[0], Element{});
}
// #9
@@ -98,8 +101,7 @@ namespace AZStd
template<typename T, typename>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const T& convertibleToView)
{
AZStd::basic_string_view<Element, Traits> view = convertibleToView;
assign(view.begin(), view.end());
assign(convertibleToView);
}
// #11
@@ -313,15 +315,7 @@ namespace AZStd
if (count > 0 && fits_in_capacity(num))
{
pointer data = m_buffer;
// make room and append new stuff using assign
if (count == 1)
{
Traits::assign(*(data + m_size), ch);
}
else
{
Traits::assign(data + m_size, count, ch);
}
Traits::assign(data + m_size, count, ch);
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
@@ -332,13 +326,47 @@ namespace AZStd
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // append [first, last)
return append_iter(first, last);
{
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
return append(AZStd::to_address(first), AZStd::distance(first, last));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be appended one by one into the buffer
size_type newSize = m_size + AZStd::distance(first, last);
if (fits_in_capacity(newSize))
{
for (size_t updateIndex = m_size; first != last; ++first, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*first));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
return *this;
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; first != last; ++first)
{
inputCopy.push_back(static_cast<Element>(*first));
}
return append(inputCopy.c_str(), inputCopy.size());
}
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append(AZStd::initializer_list<Element> ilist) -> basic_fixed_string&
{ // append [first, last)
return append_iter(ilist.begin(), ilist.end());
{
return append(ilist.begin(), ilist.size());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -420,18 +448,10 @@ namespace AZStd
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(size_type count, Element ch) -> basic_fixed_string&
{
// assign count * ch
AZSTD_CONTAINER_ASSERT(count != npos, "result is too long!");
if (fits_in_capacity(count))
{ // make room and assign new stuff
pointer data = m_buffer;
if (count == 1)
{
Traits::assign(*(data), ch);
}
else
{
Traits::assign(data, count, ch);
}
Traits::assign(data, count, ch);
m_size = static_cast<internal_size_type>(count);
Traits::assign(data[count], Element()); // terminate
}
@@ -443,12 +463,46 @@ namespace AZStd
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{
return assign_iter(first, last);
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
return assign(AZStd::to_address(first), AZStd::distance(first, last));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be assigned one by one into the buffer
size_type newSize = AZStd::distance(first, last);
if (fits_in_capacity(newSize))
{
for (size_t updateIndex = 0; first != last; ++first, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*first));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
return *this;
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; first != last; ++first)
{
inputCopy.push_back(static_cast<Element>(*first));
}
return assign(inputCopy.c_str(), inputCopy.size());
}
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(AZStd::initializer_list<Element> ilist) -> basic_fixed_string&
{
return assign_iter(ilist.begin(), ilist.end());
return assign(ilist.begin(), ilist.size());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -536,14 +590,7 @@ namespace AZStd
pointer data = m_buffer;
// make room and insert new stuff
Traits::copy_backward(data + offset + count, data + offset, m_size - offset); // empty out hole
if (count == 1)
{
Traits::assign(*(data + offset), ch);
}
else
{
Traits::assign(data + offset, count, ch);
}
Traits::assign(data + offset, count, ch);
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
@@ -582,14 +629,51 @@ namespace AZStd
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert(const_iterator insertPos,
InputIt first, InputIt last)-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
{ // insert [_First, _Last) at _Where
return insert_iter(insertPos, first, last);
size_type insertOffset = AZStd::distance(cbegin(), insertPos);
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
insert(insertOffset, AZStd::to_address(first), AZStd::distance(first, last));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be inserted one by one into the buffer
size_type count = AZStd::distance(first, last);
size_type newSize = m_size + count;
if (fits_in_capacity(newSize))
{
Traits::copy_backward(m_buffer + insertOffset + count, m_buffer + insertOffset, m_size - insertOffset); // empty out hole
for (size_t updateIndex = insertOffset; first != last; ++first, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*first));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; first != last; ++first)
{
inputCopy.push_back(static_cast<Element>(*first));
}
insert(insertOffset, inputCopy.c_str(), inputCopy.size());
}
return begin() + insertOffset;
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert(const_iterator insertPos,
AZStd::initializer_list<Element> ilist) -> iterator
{ // insert [_First, _Last) at _Where
return insert_iter(insertPos, ilist.begin(), ilist.end());
return insert(insertPos, ilist.begin(), ilist.end());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -604,7 +688,7 @@ namespace AZStd
{
// move elements down
pointer data = m_buffer;
Traits::copy(data + offset, data + offset + count, m_size - offset - count);
Traits::move(data + offset, data + offset + count, m_size - offset - count);
m_size = static_cast<internal_size_type>(m_size - count);
Traits::assign(data[m_size], Element()); // terminate
}
@@ -643,7 +727,7 @@ namespace AZStd
const basic_fixed_string& rhs) -> basic_fixed_string&
{
// replace [offset, offset + count) with rhs
return replace(offset, count, rhs, size_type(0), npos);
return replace(offset, count, rhs.c_str(), rhs.size());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -651,56 +735,7 @@ namespace AZStd
const basic_fixed_string& rhs, size_type rhsOffset, size_type rhsCount) -> basic_fixed_string&
{
// replace [offset, offset + count) with rhs [rhsOffset, rhsOffset + rhsCount)
AZSTD_CONTAINER_ASSERT(m_size >= offset && rhs.m_size >= rhsOffset, "Invalid offsets");
if (m_size - offset < count)
{
count = m_size - offset; // trim count to size
}
size_type num = rhs.m_size - rhsOffset;
if (num < rhsCount)
{
rhsCount = num; // trim rhsCount to size
}
AZSTD_CONTAINER_ASSERT(npos - rhsCount > m_size - count, "Result is too long");
size_type nm = m_size - count - offset; // length of preserved tail
size_type newSize = m_size + rhsCount - count;
if (fits_in_capacity(newSize))
{
pointer data = m_buffer;
const_pointer rhsData = rhs.m_buffer;
if (this != &rhs)
{ // no overlap, just move down and copy in new stuff
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // empty hole
Traits::copy(data + offset, rhsData + rhsOffset, rhsCount); // fill hole
}
else if (rhsCount <= count)
{ // hole doesn't get larger, just copy in substring
Traits::copy(data + offset, data + rhsOffset, rhsCount); // fill hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
}
else if (rhsOffset <= offset)
{ // hole gets larger, substring begins before hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
Traits::copy(data + offset, data + rhsOffset, rhsCount); // fill hole
}
else if (offset + count <= rhsOffset)
{ // hole gets larger, substring begins after hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
Traits::copy(data + offset, data + (rhsOffset + rhsCount - count), rhsCount); // fill hole
}
else
{ // hole gets larger, substring begins in hole
Traits::copy(data + offset, data + rhsOffset, count); // fill old hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
Traits::copy(data + offset + count, data + rhsOffset + rhsCount, rhsCount - count); // fill rest of new hole
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(data[newSize], Element()); // terminate
}
return *this;
return replace(offset, count, rhs.c_str() + rhsOffset, AZStd::min(rhsCount, rhs.size() - rhsOffset));
}
template<class Element, size_t MaxElementCount, class Traits>
template<typename T>
@@ -720,35 +755,83 @@ namespace AZStd
pointer data = m_buffer;
// replace [offset, offset + count) with [ptr, ptr + ptrCount)
AZSTD_CONTAINER_ASSERT(m_size >= offset, "Invalid offset");
if (m_size - offset < count)
{
count = m_size - offset; // trim _N0 to size
}
AZSTD_CONTAINER_ASSERT(npos - ptrCount > m_size - count, "Result too long");
// Make sure count is within is no larger than the distance from the offset
// to the end of this string
count = AZStd::min(count, m_size - offset);
size_type nm = m_size - count - offset;
if (ptrCount < count)
size_type newSize = m_size + ptrCount - count;
if (fits_in_capacity(newSize))
{
Traits::copy(data + offset + ptrCount, data + offset + count, nm); // smaller hole, move tail up
}
size_type num = m_size + ptrCount - count;
if ((0 != ptrCount || 0 != count) && fits_in_capacity(num))
{
data = m_buffer;
// make room and rearrange
if (count < ptrCount)
// The code assumes that compile time evaluation will not need to deal with overlapping input
size_type charsAfterCountToMove = m_size - count - offset;
if (az_builtin_is_constant_evaluated() || !((ptr >= data + offset && ptr < data + offset + count)
|| (ptr + ptrCount > data + offset && ptr + ptrCount <= data + offset + count)))
{
Traits::copy_backward(data + offset + ptrCount, data + offset + count, nm); // move tail down
// Ex1. this = "ABCDEFG", offset = 1, count = 4
// Input string is "CDE"
// First the text post offset + count is moved to right after the input string will be copied
// "ABCDFG"
// ^^^
// Next the input string is copied into the buffer
// "ACDEFG"
//
// Ex2. this = "ABCDEFG", offset = 1, count = 2
// Input string is "CDE"
// Performing the same two steps above, the string transform as follows
// "ABCDEFG" -> "ABCDDEFG" -> "ACDEDEFG"
// ^^^
if (count != ptrCount)
{
Traits::move(data + offset + ptrCount, data + offset + count, charsAfterCountToMove);
}
if (ptrCount > 0)
{
// Copy bytes up to the minimum of this string count and input string count
Traits::copy(data + offset, ptr, ptrCount);
}
}
if (ptrCount > 0)
else
{
Traits::copy(data + offset, ptr, ptrCount); // fill hole
// Overlap checks for fixed_string only needs to check between this string
// [offset, offset + count) due to fixed_string never moving memory
//
// Ex. this = "ABCDEFG", offset = 1, count=4
// substring is "CDE"
// The text from offset 1 for 4 chars "BCDE": should be replaced with "CDE"
// making a whole for the bytes results in output = "ABCDFG"
// Afterwards output = "ACDEFG"
// The input string overlaps with this string in this case
// So the string is copied piecewise
if (ptrCount <= count)
{ // hole doesn't get larger, just copy in substring
Traits::move(data + offset, ptr, ptrCount); // fill hole
Traits::copy(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
}
else
{
if (ptr <= data + offset)
{ // hole gets larger, substring begins before hole
Traits::copy_backward(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
Traits::copy(data + offset, ptr, ptrCount); // fill hole
}
else if (data + offset + count <= ptr)
{ // hole gets larger, substring begins after hole
Traits::copy_backward(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
Traits::copy(data + offset, ptr + (ptrCount - count), ptrCount); // fill hole
}
else
{ // hole gets larger, substring begins in hole
Traits::copy(data + offset, ptr, count); // fill old hole
Traits::copy_backward(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
Traits::copy(data + offset + count, ptr + ptrCount, ptrCount - count); // fill rest of new hole
}
}
}
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(data[newSize], Element()); // terminate
return *this;
}
@@ -793,14 +876,7 @@ namespace AZStd
{
Traits::copy_backward(data + offset + num, data + offset + count, nm); // move tail down
}
if (count == 1)
{
Traits::assign(*(data + offset), ch);
}
else
{
Traits::assign(data + offset, num, ch);
}
Traits::assign(data + offset, num, ch);
m_size = static_cast<internal_size_type>(numToGrow);
Traits::assign(data[numToGrow], Element()); // terminate
}
@@ -851,15 +927,54 @@ namespace AZStd
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace(const_iterator first, const_iterator last,
InputIt first2, InputIt last2) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // replace [first, last) with [first2,last2)
return replace_iter(first, last, first2, last2);
InputIt replaceFirst, InputIt replaceLast) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // replace [first, last) with [replaceFirst,replaceLast)
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
return replace(first, last, AZStd::to_address(replaceFirst), AZStd::distance(replaceFirst, replaceLast));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be appended one by one into the buffer
size_type insertOffset = AZStd::distance(cbegin(), first);
size_type postInsertOffset = AZStd::distance(cbegin(), last);
size_type count = AZStd::distance(replaceFirst, replaceLast);
size_type newSize = m_size + count - AZStd::distance(first, last);
if (fits_in_capacity(newSize))
{
Traits::move(first + count, last, m_size - postInsertOffset); // empty out hole
for (size_t updateIndex = insertOffset; replaceFirst != replaceLast; ++replaceFirst, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*replaceFirst));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
return *this;
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; replaceFirst != replaceLast; ++replaceFirst)
{
inputCopy.push_back(static_cast<Element>(*replaceFirst));
}
return replace(first, last, inputCopy.c_str(), inputCopy.size());
}
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace(const_iterator first, const_iterator last,
AZStd::initializer_list<Element> ilist) -> basic_fixed_string&
{ // replace [first, last) with [first2,last2)
return replace_iter(first, last, ilist.begin(), ilist.end());
{
return replace(first, last, ilist.begin(), ilist.end());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -1411,54 +1526,6 @@ namespace AZStd
return result;
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::construct_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>>
{
// initialize from [first, last), input iterators
for (; first != last; ++first)
{
append((size_type)1, (Element)* first);
}
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // append [first, last), input iterators
return replace(end(), end(), first, last);
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{
return replace(begin(), end(), first, last);
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert_iter(const_iterator insertPos, InputIt first,
InputIt last) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
{ // insert [first, last) at insertPos, input iterators
difference_type offset = insertPos - cbegin();
replace(insertPos, insertPos, first, last);
return iterator(m_buffer + offset);
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace_iter(const_iterator first, const_iterator last,
InputIt first2, InputIt last2) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // replace [first, last) with [first2, last2), input iterators
basic_fixed_string rhs(first2, last2);
replace(first, last, rhs);
return *this;
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::fits_in_capacity(size_type newSize)-> bool
{
@@ -1703,7 +1770,8 @@ namespace AZStd
template<class Element, size_t MaxElementCount, class Traits>
struct hash<basic_fixed_string<Element, MaxElementCount, Traits>>
{
inline constexpr size_t operator()(const basic_fixed_string<Element, MaxElementCount, Traits>& value) const
using is_transparent = void;
inline constexpr size_t operator()(const basic_string_view<Element, Traits>& value) const
{
return hash_string(value.begin(), value.length());
}
File diff suppressed because it is too large Load Diff
@@ -280,45 +280,99 @@ namespace AZStd
static constexpr char_type* assign(char_type* dest, size_t count, char_type ch) noexcept
{
AZ_Assert(dest, "Invalid input!");
for (char_type* iter = dest; count; --count, ++iter)
if constexpr (AZStd::is_same_v<char_type, char>)
{
assign(*iter, ch);
// Use builtin_memset if available for char type
if (az_builtin_is_constant_evaluated())
{
for (char_type* iter = dest; count; --count, ++iter)
{
assign(*iter, ch);
}
}
else
{
::memset(dest, ch, count);
}
}
else
{
for (char_type* iter = dest; count; --count, ++iter)
{
assign(*iter, ch);
}
}
return dest;
}
static constexpr bool eq(char_type left, char_type right) noexcept { return left == right; }
static constexpr bool lt(char_type left, char_type right) noexcept { return left < right; }
static constexpr int compare(const char_type* s1, const char_type* s2, size_t count) noexcept
static constexpr int compare(const char_type* s1, const char_type* s2, size_t count) noexcept
{
// In GCC versions prior to major version 10, __builtin_memcmp fails in valid checks in constexpr evaluation
#if !defined(AZ_COMPILER_GCC) || AZ_COMPILER_GCC >= 100000
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_memcmp(s1, s2, count);
}
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
return __builtin_wmemcmp(s1, s2, count);
} else
#endif
{
if (az_builtin_is_constant_evaluated())
{
for (; count; --count, ++s1, ++s2)
{
if (lt(*s1, *s2))
{
return -1;
}
else if (lt(*s2, *s1))
{
return 1;
}
}
return 0;
}
else
{
return ::memcmp(s1, s2, count * sizeof(char_type));
}
}
}
static constexpr size_t length(const char_type* s) noexcept
{
// Regression in VS2017 15.8 and 15.9 where __builtin_memcmp fails in valid checks in constexpr evaluation
#if !defined(AZ_COMPILER_MSVC) || AZ_COMPILER_MSVC < 1915 || AZ_COMPILER_MSVC > 1916
// For GCC versions less than 10, __builtin_strlen and __builtin_wcslen is not supported as const expressions
// so for that case it will need to manually count the characters (at compile time) instead
#if defined(AZ_COMPILER_GCC) && AZ_COMPILER_GCC < 100000
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_memcmp(s1, s2, count);
if (!az_builtin_is_constant_evaluated())
{
return strlen(s);
}
}
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
return __builtin_wmemcmp(s1, s2, count);
}
else
#endif
{
for (; count; --count, ++s1, ++s2)
if (!az_builtin_is_constant_evaluated())
{
if (lt(*s1, *s2))
{
return -1;
}
else if (lt(*s2, *s1))
{
return 1;
}
return wcslen(s);
}
return 0;
}
}
static constexpr size_t length(const char_type* s) noexcept
{
size_t strLength{};
for (; *s; ++s, ++strLength)
{
;
}
return strLength;
#else
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_strlen(s);
@@ -336,13 +390,39 @@ namespace AZStd
}
return strLength;
}
#endif // defined(AZ_COMPILER_GCC) && AZ_COMPILER_GCC < 100000
}
static constexpr const char_type* find(const char_type* s, size_t count, const char_type& ch) noexcept
{
// There is a bug with the __builtin_char_memchr intrinsic in Visual Studio 2017 15.8.x and 15.9.x
// It reads in one more additional character than the value of count.
// This is probably due to assuming null-termination
#if !defined(AZ_COMPILER_MSVC) || AZ_COMPILER_MSVC < 1915 || AZ_COMPILER_MSVC > 1916
// For GCC versions less than 10, __builtin_char_memchr and __builtin_wmemchr is not supported, and
// __builtin_memchr is not supported as const expressions. In those cases we will manually locate and
// return the pointer to 's' (at compile time)
#if defined(AZ_COMPILER_GCC) && AZ_COMPILER_GCC < 100000
if constexpr (AZStd::is_same_v<char_type, char>)
{
if (!az_builtin_is_constant_evaluated())
{
return static_cast<const char_type*>(__builtin_memchr(s, ch, count));
}
}
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
if (!az_builtin_is_constant_evaluated())
{
return wmemchr(s, ch, count);
}
}
for (; count; --count, ++s)
{
if (eq(*s, ch))
{
return s;
}
}
return nullptr;
#else
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_char_memchr(s, ch, count);
@@ -350,10 +430,8 @@ namespace AZStd
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
return __builtin_wmemchr(s, ch, count);
}
else
#endif
{
for (; count; --count, ++s)
{
@@ -364,68 +442,116 @@ namespace AZStd
}
return nullptr;
}
#endif
}
static constexpr char_type* move(char_type* dest, const char_type* src, size_t count) noexcept
{
AZ_Assert(dest != nullptr && src != nullptr, "Invalid input!");
if (count == 0)
if (count == 0 || src == dest)
{
return dest;
}
char_type* result = dest;
// The less than(<), greater than(>) and other variants(<=, >=)
// Cannot be compare pointers within a constexpr due to the potential for undefined behavior
// per the bullet linked in the C++ standard at http://eel.is/c++draft/expr.compound#expr.rel-5
// Now clang and gcc compilers allow the use of this relation operators in a constexpr, but
// msvc is not so forgiving
// So a workaround of iterating the src pointer, checking for equality with the dest pointer
// is used to check for overlap
auto should_copy_forward = [](const char_type* dest1, const char_type* src2, size_t count2) constexpr -> bool
#if az_has_builtin_memmove
__builtin_memmove(dest, src, count * sizeof(char_type));
#else
auto NonBuiltinMove = [](char_type* dest1, const char_type* src1, size_t count1) constexpr
-> char_type*
{
bool dest_less_than_src{ true };
for(const char_type* src_iter = src2; src_iter != src2 + count2; ++src_iter)
if (az_builtin_is_constant_evaluated())
{
if (src_iter == dest1)
// The less than(<), greater than(>) and other variants(<=, >=)
// Cannot be compare pointers within a constexpr due to the potential for undefined behavior
// per the bullet linked in the C++ standard at http://eel.is/c++draft/expr.compound#expr.rel-5
// Now clang and gcc compilers allow the use of this relation operators in a constexpr, but
// msvc is not so forgiving
// So a workaround of iterating the src pointer, checking for equality with the dest pointer
// is used to check for overlap
auto should_copy_forward = [](const char_type* dest2, const char_type* src2, size_t count2) constexpr -> bool
{
dest_less_than_src = false;
break;
bool dest_less_than_src{ true };
for (const char_type* src_iter = src2; src_iter != src2 + count2; ++src_iter)
{
if (src_iter == dest2)
{
dest_less_than_src = false;
break;
}
}
return dest_less_than_src;
};
if (should_copy_forward(dest1, src1, count1))
{
copy(dest1, src1, count1);
}
else
{
copy_backward(dest1, src1, count1);
}
}
return dest_less_than_src;
else
{
// Use the faster ::memmove operation at runtime
::memmove(dest1, src1, count1 * sizeof(char_type));
}
return dest1;
};
NonBuiltinMove(dest, src, count);
#endif
if (should_copy_forward(dest, src, count))
{
copy(dest, src, count);
}
else
{
copy_backward(dest, src, count);
}
return result;
return dest;
}
static constexpr char_type* copy(char_type* dest, const char_type* src, size_t count) noexcept
{
AZ_Assert(dest != nullptr && src != nullptr, "Invalid input!");
char_type* result = dest;
for(; count; --count, ++dest, ++src)
#if az_has_builtin_memcpy
__builtin_memcpy(dest, src, count * sizeof(char_type));
#else
auto NonBuiltinCopy = [](char_type* dest1, const char_type* src1, size_t count1) constexpr
-> char_type*
{
assign(*dest, *src);
}
return result;
if (az_builtin_is_constant_evaluated())
{
for (; count1; --count1, ++dest1, ++src1)
{
assign(*dest1, *src1);
}
}
else
{
AZ_Assert(dest1 != nullptr && src1 != nullptr, "Invalid input!");
::memcpy(dest1, src1, count1 * sizeof(char_type));
}
return dest1;
};
NonBuiltinCopy(dest, src, count);
#endif
return dest;
}
// Extension for constexpr workarounds: Addresses of a string literal cannot be compared at compile time and MSVC and clang will just refuse to compile the constexpr
// Adding a copy_backwards overload that always copies backwards.
static constexpr char_type* copy_backward(char_type* dest, const char_type*src, size_t count) noexcept
static constexpr char_type* copy_backward(char_type* dest, const char_type* src, size_t count) noexcept
{
char_type* result = dest;
dest += count;
src += count;
for (; count; --count)
#if az_has_builtin_memmove
__builtin_memmove(dest, src, count * sizeof(char_type));
#else
if (az_builtin_is_constant_evaluated())
{
assign(*--dest, *--src);
dest += count;
src += count;
for (; count; --count)
{
assign(*--dest, *--src);
}
}
else
{
::memmove(dest, src, count);
}
#endif
return result;
}
@@ -7,6 +7,7 @@
*/
#pragma once
#include <AzCore/std/typetraits/typetraits.h>
#include <AzCore/std/typetraits/conditional.h>
#include <AzCore/std/typetraits/integral_constant.h> // for true_type
@@ -58,14 +58,13 @@
# define AZSTD_IS_ABSTRACT(T) __is_abstract(T)
# define AZSTD_IS_BASE_OF(T, U) (__is_base_of(T, U) && !is_same<T, U>::value)
# define AZSTD_IS_CLASS(T) __is_class(T)
// This one doesn't quite always do the right thing:
# define AZSTD_IS_CONVERTIBLE(_From, _To) __is_convertible_to(_From, _To)
# define AZSTD_IS_ENUM(T) __is_enum(T)
// This one doesn't quite always do the right thing:
# define AZSTD_IS_CONVERTIBLE(_From, _To) __is_convertible_to(_From, _To)
// # define AZSTD_IS_POLYMORPHIC(T) __is_polymorphic(T)
#endif
#if defined(AZ_COMPILER_CLANG)
#if defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
# include <AzCore/std/typetraits/is_same.h>
# include <AzCore/std/typetraits/is_reference.h>
# include <AzCore/std/typetraits/is_volatile.h>
@@ -86,8 +85,8 @@
# define AZSTD_IS_ABSTRACT(T) __is_abstract(T)
# define AZSTD_IS_BASE_OF(T, U) (__is_base_of(T, U) && !is_same<T, U>::value)
# define AZSTD_IS_CLASS(T) __is_class(T)
# define AZSTD_IS_CONVERTIBLE(_From, _To) __is_convertible_to(_From, _To)
# define AZSTD_IS_ENUM(T) __is_enum(T)
# define AZSTD_IS_CONVERTIBLE(_From, _To) AZStd::is_convertible_v<_From, _To>
# define AZSTD_IS_POLYMORPHIC(T) __is_polymorphic(T)
#endif
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
// Variadic MACROS util functions
/**
* AZ_VA_NUM_ARGS
* counts number of parameters (up to 10).
* example. AZ_VA_NUM_ARGS(x,y,z) -> expands to 3
*/
#ifndef AZ_VA_NUM_ARGS
# define AZ_VA_HAS_ARGS(...) ""#__VA_ARGS__[0] != 0
// we add the zero to avoid the case when we require at least 1 param at the end...
# define AZ_VA_NUM_ARGS(...) AZ_VA_NUM_ARGS_IMPL_((__VA_ARGS__, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
# define AZ_VA_NUM_ARGS_IMPL_(tuple) AZ_VA_NUM_ARGS_IMPL tuple
# define AZ_VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, N, ...) N
// Expands a macro and calls a different macro based on the number of arguments.
//
// Example: We need to specialize a macro for 1 and 2 arguments
// #define AZ_MY_MACRO(...) AZ_MACRO_SPECIALIZE(AZ_MY_MACRO_,AZ_VA_NUM_ARGS(__VA_ARGS__),(__VA_ARGS__))
//
// #define AZ_MY_MACRO_1(_1) /* code for 1 param */
// #define AZ_MY_MACRO_2(_1,_2) /* code for 2 params */
// ... etc.
//
//
// We have 3 levels of macro expansion...
# define AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS) MACRO_NAME##NPARAMS PARAMS
# define AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS)
# define AZ_MACRO_SPECIALIZE(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS)
#endif // AZ_VA_NUM_ARGS
// Out of all supported compilers, mwerks is the only one
// that requires variadic macros to have at least 1 param.
// This is a pain they we use macros to call functions (with no params).
// we implement functions for up to 10 params
#define AZ_FUNCTION_CALL_1(_1) _1()
#define AZ_FUNCTION_CALL_2(_1, _2) _1(_2)
#define AZ_FUNCTION_CALL_3(_1, _2, _3) _1(_2, _3)
#define AZ_FUNCTION_CALL_4(_1, _2, _3, _4) _1(_2, _3, _4)
#define AZ_FUNCTION_CALL_5(_1, _2, _3, _4, _5) _1(_2, _3, _4, _5)
#define AZ_FUNCTION_CALL_6(_1, _2, _3, _4, _5, _6) _1(_2, _3, _4, _5, _6)
#define AZ_FUNCTION_CALL_7(_1, _2, _3, _4, _5, _6, _7) _1(_2, _3, _4, _5, _6, _7)
#define AZ_FUNCTION_CALL_8(_1, _2, _3, _4, _5, _6, _7, _8) _1(_2, _3, _4, _5, _6, _7, _8)
#define AZ_FUNCTION_CALL_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) _1(_2, _3, _4, _5, _6, _7, _8, _9)
#define AZ_FUNCTION_CALL_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) _1(_2, _3, _4, _5, _6, _7, _8, _9, _10)
// We require at least 1 param FunctionName
#define AZ_FUNCTION_CALL(...) AZ_MACRO_SPECIALIZE(AZ_FUNCTION_CALL_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
// Based on boost macro expansion fix...
#define AZ_PREVENT_MACRO_SUBSTITUTION
+5 -5
View File
@@ -9,8 +9,8 @@
# TODO: would like to be able to build from this path, however, the whole setup is done at the workspace's root
# we also dont want to drop cmake output files everywhere.
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER})
set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
if(PAL_TRAIT_PROF_PIX_SUPPORTED)
set(LY_PIX_ENABLED OFF CACHE BOOL "Enables PIX profiler integration.")
@@ -110,15 +110,15 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
AZ::AzTest
)
ly_get_list_relative_pal_filename(pal_test_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME})
o3de_pal_dir(pal_tests_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER})
ly_add_target(
NAME AzCore.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
Tests/azcoretests_files.cmake
${pal_test_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
${pal_tests_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
${pal_test_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
${pal_tests_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
@@ -98,7 +98,6 @@
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_ONLN));
#define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0
#define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 1
#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 0
#define AZ_TRAIT_USE_POSIX_STRERROR_R 1
#define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0
#define AZ_TRAIT_USE_WINDOWS_FILE_API 0
@@ -23,7 +23,7 @@ namespace AZ
public:
virtual SystemInformation GetSystemInformation() override
{
SystemInformation result;
SystemInformation result {0, 0};
return result;
}
@@ -6,74 +6,121 @@
*
*/
#include <AzCore/Debug/StackTracer.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/string/string_view.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
namespace AZ::Debug::Platform
namespace AZ::Debug
{
#if defined(AZ_ENABLE_DEBUG_TOOLS)
bool performDebuggerDetection()
void ExceptionHandler(int signal);
#endif
constexpr int MaxMessageLength = 4096;
constexpr int MaxStackLines = 100;
namespace Platform
{
AZ::IO::SystemFile processStatusFile;
if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY))
#if defined(AZ_ENABLE_DEBUG_TOOLS)
bool performDebuggerDetection()
{
return false;
}
char buffer[4096];
AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer);
const AZStd::string_view processStatusView(buffer, buffer + numRead);
constexpr AZStd::string_view tracerPidString = "TracerPid:";
const size_t tracerPidOffset = processStatusView.find(tracerPidString);
if (tracerPidOffset == AZStd::string_view::npos)
{
return false;
}
for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i)
{
if (!::isspace(processStatusView[i]))
AZ::IO::SystemFile processStatusFile;
if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY))
{
return processStatusView[i] != '0';
return false;
}
char buffer[MaxMessageLength];
AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer);
const AZStd::string_view processStatusView(buffer, buffer + numRead);
constexpr AZStd::string_view tracerPidString = "TracerPid:";
const size_t tracerPidOffset = processStatusView.find(tracerPidString);
if (tracerPidOffset == AZStd::string_view::npos)
{
return false;
}
for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i)
{
if (processStatusView[i] != ' ')
{
return processStatusView[i] != '0';
}
}
return false;
}
bool IsDebuggerPresent()
{
static bool s_detectionPerformed = false;
static bool s_debuggerDetected = false;
if (!s_detectionPerformed)
{
s_debuggerDetected = performDebuggerDetection();
s_detectionPerformed = true;
}
return s_debuggerDetected;
}
bool AttachDebugger()
{
// Not supported yet
AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet");
return false;
}
void HandleExceptions(bool isEnabled)
{
if (isEnabled)
{
signal(SIGSEGV, ExceptionHandler);
signal(SIGTRAP, ExceptionHandler);
signal(SIGILL, ExceptionHandler);
}
else
{
signal(SIGSEGV, SIG_DFL);
signal(SIGTRAP, SIG_DFL);
signal(SIGILL, SIG_DFL);
}
}
return false;
}
bool IsDebuggerPresent()
{
static bool s_detectionPerformed = false;
static bool s_debuggerDetected = false;
if (!s_detectionPerformed)
void DebugBreak()
{
s_debuggerDetected = performDebuggerDetection();
s_detectionPerformed = true;
raise(SIGINT);
}
return s_debuggerDetected;
}
bool AttachDebugger()
{
// Not supported yet
AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet");
return false;
}
void HandleExceptions(bool)
{}
void DebugBreak()
{
raise(SIGINT);
}
#endif // AZ_ENABLE_DEBUG_TOOLS
void Terminate(int exitCode)
void Terminate(int exitCode)
{
_exit(exitCode);
}
} // namespace Platform
#if defined(AZ_ENABLE_DEBUG_TOOLS)
void ExceptionHandler(int signal)
{
_exit(exitCode);
char message[MaxMessageLength];
// Trace::RawOutput
Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n");
azsnprintf(message, MaxMessageLength, "Error: signal %s: \n", strsignal(signal));
Debug::Trace::Instance().RawOutput(nullptr, message);
StackFrame frames[MaxStackLines];
SymbolStorage::StackLine stackLines[MaxStackLines];
SymbolStorage decoder;
const unsigned int numberOfFrames = StackRecorder::Record(frames, MaxStackLines);
decoder.DecodeFrames(frames, numberOfFrames, stackLines);
for (int i = 0; i < numberOfFrames; ++i)
{
azsnprintf(message, MaxMessageLength, "%s \n", stackLines[i]);
Debug::Trace::Instance().RawOutput(nullptr, message);
}
Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n");
}
} // namespace AZ::Debug::Platform
#endif
} // namespace AZ::Debug
@@ -10,6 +10,13 @@
</Expand>
</Type>
<Type Name="AZStd::compressed_pair_element&lt;*,*,*&gt;">
<DisplayString>{m_element}</DisplayString>
</Type>
<Type Name="AZStd::compressed_pair_element&lt;*,*,1&gt;">
<DisplayString>{$T1} is empty</DisplayString>
</Type>
<Type Name="AZStd::reverse_iterator&lt;*&gt;" Priority="Medium">
<DisplayString>reverse_iterator base() {m_current}</DisplayString>
<Expand>
@@ -388,35 +395,41 @@
<!-- -->
<Type Name="AZStd::basic_string&lt;char,*&gt;">
<DisplayString Condition="m_capacity &lt; SSO_BUF_SIZE">{m_buffer,s}</DisplayString>
<DisplayString Condition="m_capacity &gt;= SSO_BUF_SIZE">{m_data,s}</DisplayString>
<StringView Condition="m_capacity &lt; SSO_BUF_SIZE">m_buffer,s</StringView>
<StringView Condition="m_capacity &gt;= SSO_BUF_SIZE">m_data,s</StringView>
<Type Name="AZStd::basic_string&lt;char,*,*&gt;">
<DisplayString Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_buffer,s}</DisplayString>
<DisplayString Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_data,s}</DisplayString>
<StringView Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_buffer,s</StringView>
<StringView Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_data,s</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<Item Name="[size]" Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">(size_t)((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_size</Item>
<Item Name="[size]" Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_size</Item>
<Item Name="[capacity]" Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.Capacity</Item>
<Item Name="[capacity]" Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer Condition="m_capacity &lt; SSO_BUF_SIZE">m_buffer</ValuePointer>
<ValuePointer Condition="m_capacity &gt;= SSO_BUF_SIZE">m_data</ValuePointer>
<Size Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_size,u</Size>
<Size Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_size</Size>
<ValuePointer Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_buffer</ValuePointer>
<ValuePointer Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;char,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="AZStd::basic_string&lt;wchar_t,*&gt;">
<AlternativeType Name="AZStd::basic_string&lt;unsigned short,*&gt;" />
<DisplayString Condition="m_capacity &lt; SSO_BUF_SIZE">{m_buffer,su}</DisplayString>
<DisplayString Condition="m_capacity &gt;= SSO_BUF_SIZE">{m_data,su}</DisplayString>
<StringView Condition="m_capacity &lt; SSO_BUF_SIZE">m_buffer,su</StringView>
<StringView Condition="m_capacity &gt;= SSO_BUF_SIZE">m_data,su</StringView>
<DisplayString Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_buffer,su}</DisplayString>
<DisplayString Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_data,su}</DisplayString>
<StringView Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_buffer,su</StringView>
<StringView Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_data,su</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<Item Name="[size]" Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">(size_t)((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_size</Item>
<Item Name="[size]" Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_size</Item>
<Item Name="[capacity]" Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.Capacity</Item>
<Item Name="[capacity]" Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer Condition="m_capacity &lt; SSO_BUF_SIZE">m_buffer</ValuePointer>
<ValuePointer Condition="m_capacity &gt;= SSO_BUF_SIZE">m_data</ValuePointer>
<Size Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_size,u</Size>
<Size Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_size</Size>
<ValuePointer Condition="((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_buffer</ValuePointer>
<ValuePointer Condition="!((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element&lt;AZStd::basic_string&lt;wchar_t,$T1,$T2&gt;::Storage,0,0&gt;&amp;)m_storage).m_element.m_allocatedData.m_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
@@ -98,7 +98,6 @@
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_ONLN));
#define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0
#define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0
#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1
#define AZ_TRAIT_USE_POSIX_STRERROR_R 1
#define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0
#define AZ_TRAIT_USE_WINDOWS_FILE_API 0
@@ -16,6 +16,7 @@ set(LY_BUILD_DEPENDENCIES
PRIVATE
pthread
3rdParty::unwind
dl
atomic
PUBLIC
${CMAKE_DL_LIBS}
)
@@ -98,7 +98,6 @@
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_ONLN));
#define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0
#define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0
#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1
#define AZ_TRAIT_USE_POSIX_STRERROR_R 1
#define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0
#define AZ_TRAIT_USE_WINDOWS_FILE_API 0
@@ -98,7 +98,6 @@
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE INVALID_RETURN_VALUE
#define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 1
#define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0
#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 0
#define AZ_TRAIT_USE_POSIX_STRERROR_R 0
#define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 1
#define AZ_TRAIT_USE_WINDOWS_FILE_API 1
@@ -99,7 +99,6 @@
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_ONLN));
#define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0
#define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0
#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1
#define AZ_TRAIT_USE_POSIX_STRERROR_R 1
#define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0
#define AZ_TRAIT_USE_WINDOWS_FILE_API 0
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,189 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/DOM/DomValue.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Tests/DOM/DomFixtures.h>
namespace AZ::Dom::Tests
{
void DomTestHarness::SetUpHarness()
{
NameDictionary::Create();
AZ::AllocatorInstance<ValueAllocator>::Create();
}
void DomTestHarness::TearDownHarness()
{
AZ::AllocatorInstance<ValueAllocator>::Destroy();
NameDictionary::Destroy();
}
void DomBenchmarkFixture::SetUp(const ::benchmark::State& st)
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
SetUpHarness();
}
void DomBenchmarkFixture::SetUp(::benchmark::State& st)
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
SetUpHarness();
}
void DomBenchmarkFixture::TearDown(::benchmark::State& st)
{
TearDownHarness();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
void DomBenchmarkFixture::TearDown(const ::benchmark::State& st)
{
TearDownHarness();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
rapidjson::Document DomBenchmarkFixture::GenerateDomJsonBenchmarkDocument(int64_t entryCount, int64_t stringTemplateLength)
{
rapidjson::Document document;
document.SetObject();
AZStd::string entryTemplate;
while (entryTemplate.size() < aznumeric_cast<size_t>(stringTemplateLength))
{
entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ";
}
entryTemplate.resize(stringTemplateLength);
AZStd::string buffer;
auto createString = [&](int n) -> rapidjson::Value
{
buffer = AZStd::string::format("#%i %s", n, entryTemplate.c_str());
return rapidjson::Value(buffer.data(), aznumeric_cast<rapidjson::SizeType>(buffer.size()), document.GetAllocator());
};
auto createEntry = [&](int n) -> rapidjson::Value
{
rapidjson::Value entry(rapidjson::kObjectType);
entry.AddMember("string", createString(n), document.GetAllocator());
entry.AddMember("int", rapidjson::Value(n), document.GetAllocator());
entry.AddMember("double", rapidjson::Value(aznumeric_cast<double>(n) * 0.5), document.GetAllocator());
entry.AddMember("bool", rapidjson::Value(n % 2 == 0), document.GetAllocator());
entry.AddMember("null", rapidjson::Value(rapidjson::kNullType), document.GetAllocator());
return entry;
};
auto createArray = [&]() -> rapidjson::Value
{
rapidjson::Value array;
array.SetArray();
for (int i = 0; i < entryCount; ++i)
{
array.PushBack(createEntry(i), document.GetAllocator());
}
return array;
};
auto createObject = [&]() -> rapidjson::Value
{
rapidjson::Value object;
object.SetObject();
for (int i = 0; i < entryCount; ++i)
{
buffer = AZStd::string::format("Key%i", i);
rapidjson::Value key;
key.SetString(buffer.data(), aznumeric_cast<rapidjson::SizeType>(buffer.length()), document.GetAllocator());
object.AddMember(key.Move(), createArray(), document.GetAllocator());
}
return object;
};
document.SetObject();
document.AddMember("entries", createObject(), document.GetAllocator());
return document;
}
AZStd::string DomBenchmarkFixture::GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength)
{
rapidjson::Document document = GenerateDomJsonBenchmarkDocument(entryCount, stringTemplateLength);
AZStd::string serializedJson;
auto result = AZ::JsonSerializationUtils::WriteJsonString(document, serializedJson);
AZ_Assert(result.IsSuccess(), "Failed to serialize generated JSON");
return serializedJson;
}
Value DomBenchmarkFixture::GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength)
{
Value root(Type::Object);
AZStd::string entryTemplate;
while (entryTemplate.size() < aznumeric_cast<size_t>(stringTemplateLength))
{
entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ";
}
entryTemplate.resize(stringTemplateLength);
AZStd::string buffer;
auto createString = [&](int n) -> Value
{
return Value(AZStd::string::format("#%i %s", n, entryTemplate.c_str()), true);
};
auto createEntry = [&](int n) -> Value
{
Value entry(Type::Object);
entry.AddMember("string", createString(n));
entry.AddMember("int", Value(n));
entry.AddMember("double", Value(aznumeric_cast<double>(n) * 0.5));
entry.AddMember("bool", Value(n % 2 == 0));
entry.AddMember("null", Value(Type::Null));
return entry;
};
auto createArray = [&]() -> Value
{
Value array(Type::Array);
for (int i = 0; i < entryCount; ++i)
{
array.ArrayPushBack(createEntry(i));
}
return array;
};
auto createObject = [&]() -> Value
{
Value object;
object.SetObject();
for (int i = 0; i < entryCount; ++i)
{
buffer = AZStd::string::format("Key%i", i);
object.AddMember(AZ::Name(buffer), createArray());
}
return object;
};
root["entries"] = createObject();
return root;
}
void DomTestFixture::SetUp()
{
UnitTest::AllocatorsFixture::SetUp();
SetUpHarness();
}
void DomTestFixture::TearDown()
{
TearDownHarness();
UnitTest::AllocatorsFixture::TearDown();
}
} // namespace AZ::Dom::Tests
@@ -0,0 +1,66 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/JSON/document.h>
#include <AzCore/UnitTest/TestTypes.h>
#define DOM_REGISTER_SERIALIZATION_BENCHMARK(BaseClass, Method) \
BENCHMARK_REGISTER_F(BaseClass, Method)->Args({ 10, 5 })->Args({ 10, 500 })->Args({ 100, 5 })->Args({ 100, 500 })
#define DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(BaseClass, Method) \
DOM_REGISTER_SERIALIZATION_BENCHMARK(BaseClass, Method)->Unit(benchmark::kMillisecond);
#define DOM_REGISTER_SERIALIZATION_BENCHMARK_NS(BaseClass, Method) \
DOM_REGISTER_SERIALIZATION_BENCHMARK(BaseClass, Method)->Unit(benchmark::kNanosecond);
namespace AZ::Dom::Tests
{
class DomTestHarness
{
public:
virtual ~DomTestHarness() = default;
virtual void SetUpHarness();
virtual void TearDownHarness();
};
class DomBenchmarkFixture
: public DomTestHarness
, public UnitTest::AllocatorsBenchmarkFixture
{
public:
void SetUp(const ::benchmark::State& st) override;
void SetUp(::benchmark::State& st) override;
void TearDown(::benchmark::State& st) override;
void TearDown(const ::benchmark::State& st) override;
rapidjson::Document GenerateDomJsonBenchmarkDocument(int64_t entryCount, int64_t stringTemplateLength);
AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength);
Value GenerateDomBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength);
template<class T>
static void TakeAndDiscardWithoutTimingDtor(T&& value, benchmark::State& state)
{
{
T instance = AZStd::move(value);
state.PauseTiming();
}
state.ResumeTiming();
}
};
class DomTestFixture
: public DomTestHarness
, public UnitTest::AllocatorsFixture
{
public:
void SetUp() override;
void TearDown() override;
};
} // namespace AZ::Dom::Tests
@@ -8,118 +8,23 @@
#if defined(HAVE_BENCHMARK)
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/DOM/Backends/JSON/JsonBackend.h>
#include <AzCore/DOM/Backends/JSON/JsonSerializationUtils.h>
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/DOM/DomValue.h>
#include <AzCore/JSON/document.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <Tests/DOM/DomFixtures.h>
namespace Benchmark
namespace AZ::Dom::Benchmark
{
class DomJsonBenchmark : public UnitTest::AllocatorsBenchmarkFixture
class DomJsonBenchmark : public Tests::DomBenchmarkFixture
{
public:
void SetUp(const ::benchmark::State& st) override
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
AZ::NameDictionary::Create();
}
void SetUp(::benchmark::State& st) override
{
UnitTest::AllocatorsBenchmarkFixture::SetUp(st);
AZ::NameDictionary::Create();
}
void TearDown(::benchmark::State& st) override
{
AZ::NameDictionary::Destroy();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
void TearDown(const ::benchmark::State& st) override
{
AZ::NameDictionary::Destroy();
UnitTest::AllocatorsBenchmarkFixture::TearDown(st);
}
AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength)
{
rapidjson::Document document;
document.SetObject();
AZStd::string entryTemplate;
while (entryTemplate.size() < static_cast<size_t>(stringTemplateLength))
{
entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ";
}
entryTemplate.resize(stringTemplateLength);
AZStd::string buffer;
auto createString = [&](int n) -> rapidjson::Value
{
buffer = AZStd::string::format("#%i %s", n, entryTemplate.c_str());
return rapidjson::Value(buffer.data(), static_cast<rapidjson::SizeType>(buffer.size()), document.GetAllocator());
};
auto createEntry = [&](int n) -> rapidjson::Value
{
rapidjson::Value entry(rapidjson::kObjectType);
entry.AddMember("string", createString(n), document.GetAllocator());
entry.AddMember("int", rapidjson::Value(n), document.GetAllocator());
entry.AddMember("double", rapidjson::Value(static_cast<double>(n) * 0.5), document.GetAllocator());
entry.AddMember("bool", rapidjson::Value(n % 2 == 0), document.GetAllocator());
entry.AddMember("null", rapidjson::Value(rapidjson::kNullType), document.GetAllocator());
return entry;
};
auto createArray = [&]() -> rapidjson::Value
{
rapidjson::Value array;
array.SetArray();
for (int i = 0; i < entryCount; ++i)
{
array.PushBack(createEntry(i), document.GetAllocator());
}
return array;
};
auto createObject = [&]() -> rapidjson::Value
{
rapidjson::Value object;
object.SetObject();
for (int i = 0; i < entryCount; ++i)
{
buffer = AZStd::string::format("Key%i", i);
rapidjson::Value key;
key.SetString(buffer.data(), static_cast<rapidjson::SizeType>(buffer.length()), document.GetAllocator());
object.AddMember(key.Move(), createArray(), document.GetAllocator());
}
return object;
};
document.SetObject();
document.AddMember("entries", createObject(), document.GetAllocator());
AZStd::string serializedJson;
auto result = AZ::JsonSerializationUtils::WriteJsonString(document, serializedJson);
AZ_Assert(result.IsSuccess(), "Failed to serialize generated JSON");
return serializedJson;
}
};
// Helper macro for registering JSON benchmarks
#define BENCHMARK_REGISTER_JSON(BaseClass, Method) \
BENCHMARK_REGISTER_F(BaseClass, Method) \
->Args({ 10, 5 }) \
->Args({ 10, 500 }) \
->Args({ 100, 5 }) \
->Args({ 100, 500 }) \
->Unit(benchmark::kMillisecond);
BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocumentInPlace)(benchmark::State& state)
BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1));
@@ -136,14 +41,38 @@ namespace Benchmark
return AZ::Dom::Utils::ReadFromStringInPlace(backend, payloadCopy, visitor);
});
benchmark::DoNotOptimize(result.GetValue());
TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state);
}
state.SetBytesProcessed(serializedPayload.size() * state.iterations());
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocumentInPlace)
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToRapidjsonInPlace)
BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocument)(benchmark::State& state)
BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1));
for (auto _ : state)
{
state.PauseTiming();
AZStd::string payloadCopy = serializedPayload;
state.ResumeTiming();
auto result = AZ::Dom::Utils::WriteToValue(
[&](AZ::Dom::Visitor& visitor)
{
return AZ::Dom::Utils::ReadFromStringInPlace(backend, payloadCopy, visitor);
});
TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state);
}
state.SetBytesProcessed(serializedPayload.size() * state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToAzDomValueInPlace)
BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToRapidjson)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1));
@@ -156,14 +85,34 @@ namespace Benchmark
return AZ::Dom::Utils::ReadFromString(backend, serializedPayload, AZ::Dom::Lifetime::Temporary, visitor);
});
benchmark::DoNotOptimize(result.GetValue());
TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state);
}
state.SetBytesProcessed(serializedPayload.size() * state.iterations());
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocument)
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToRapidjson)
BENCHMARK_DEFINE_F(DomJsonBenchmark, JsonUtilsDeserializeToDocument)(benchmark::State& state)
BENCHMARK_DEFINE_F(DomJsonBenchmark, AzDomDeserializeToAzDomValue)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1));
for (auto _ : state)
{
auto result = AZ::Dom::Utils::WriteToValue(
[&](AZ::Dom::Visitor& visitor)
{
return AZ::Dom::Utils::ReadFromString(backend, serializedPayload, AZ::Dom::Lifetime::Temporary, visitor);
});
TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state);
}
state.SetBytesProcessed(serializedPayload.size() * state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, AzDomDeserializeToAzDomValue)
BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonDeserializeToRapidjson)(benchmark::State& state)
{
AZ::Dom::JsonBackend backend;
AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1));
@@ -172,14 +121,81 @@ namespace Benchmark
{
auto result = AZ::JsonSerializationUtils::ReadJsonString(serializedPayload);
benchmark::DoNotOptimize(result.GetValue());
TakeAndDiscardWithoutTimingDtor(result.TakeValue(), state);
}
state.SetBytesProcessed(serializedPayload.size() * state.iterations());
}
BENCHMARK_REGISTER_JSON(DomJsonBenchmark, JsonUtilsDeserializeToDocument)
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonDeserializeToRapidjson)
#undef BENCHMARK_REGISTER_JSON
} // namespace Benchmark
BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonMakeComplexObject)(benchmark::State& state)
{
for (auto _ : state)
{
TakeAndDiscardWithoutTimingDtor(GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)), state);
}
state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonMakeComplexObject)
BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonLookupMemberByString)(benchmark::State& state)
{
rapidjson::Document document(rapidjson::kObjectType);
AZStd::vector<AZStd::string> keys;
for (int64_t i = 0; i < state.range(0); ++i)
{
AZStd::string key(AZStd::string::format("key%" PRId64, i));
keys.push_back(key);
document.AddMember(
rapidjson::Value(key.data(), static_cast<rapidjson::SizeType>(key.size()), document.GetAllocator()), rapidjson::Value(i),
document.GetAllocator());
}
for (auto _ : state)
{
for (const AZStd::string& key : keys)
{
benchmark::DoNotOptimize(document.FindMember(key.data()));
}
}
state.SetItemsProcessed(state.iterations() * state.range(0));
}
BENCHMARK_REGISTER_F(DomJsonBenchmark, RapidjsonLookupMemberByString)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond);
BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonDeepCopy)(benchmark::State& state)
{
rapidjson::Document original = GenerateDomJsonBenchmarkDocument(state.range(0), state.range(1));
for (auto _ : state)
{
rapidjson::Document copy;
copy.CopyFrom(original, copy.GetAllocator(), true);
TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state);
}
state.SetItemsProcessed(state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonDeepCopy)
BENCHMARK_DEFINE_F(DomJsonBenchmark, RapidjsonCopyAndMutate)(benchmark::State& state)
{
rapidjson::Document original = GenerateDomJsonBenchmarkDocument(state.range(0), state.range(1));
for (auto _ : state)
{
rapidjson::Document copy;
copy.CopyFrom(original, copy.GetAllocator(), true);
copy["entries"]["Key0"].PushBack(42, copy.GetAllocator());
TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state);
}
state.SetItemsProcessed(state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomJsonBenchmark, RapidjsonCopyAndMutate)
} // namespace AZ::Dom::Benchmark
#endif // defined(HAVE_BENCHMARK)
@@ -13,24 +13,23 @@
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <Tests/DOM/DomFixtures.h>
namespace AZ::Dom::Tests
{
class DomJsonTests : public UnitTest::AllocatorsFixture
class DomJsonTests : public DomTestFixture
{
public:
void SetUp() override
{
UnitTest::AllocatorsFixture::SetUp();
NameDictionary::Create();
DomTestFixture::SetUp();
m_document = AZStd::make_unique<rapidjson::Document>();
}
void TearDown() override
{
m_document.reset();
NameDictionary::Destroy();
UnitTest::AllocatorsFixture::TearDown();
DomTestFixture::TearDown();
}
rapidjson::Value CreateString(const AZStd::string& text)
@@ -0,0 +1,266 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/DOM/DomValue.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <Tests/DOM/DomFixtures.h>
namespace AZ::Dom::Benchmark
{
class DomValueBenchmark : public Tests::DomBenchmarkFixture
{
};
BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueGetType_UsingVariantIndex)(benchmark::State& state)
{
Value intValue(5);
Value boolValue(true);
Value objValue(Type::Object);
Value nodeValue(Type::Node);
Value arrValue(Type::Array);
Value uintValue(5u);
Value doubleValue(4.0);
Value stringValue("foo", true);
for (auto _ : state)
{
(intValue.GetType());
(boolValue.GetType());
(objValue.GetType());
(nodeValue.GetType());
(arrValue.GetType());
(uintValue.GetType());
(doubleValue.GetType());
(stringValue.GetType());
}
state.SetItemsProcessed(8 * state.iterations());
}
BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueGetType_UsingVariantIndex);
BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueGetType_UsingVariantVisit)(benchmark::State& state)
{
Value intValue(5);
Value boolValue(true);
Value objValue(Type::Object);
Value nodeValue(Type::Node);
Value arrValue(Type::Array);
Value uintValue(5u);
Value doubleValue(4.0);
Value stringValue("foo", true);
auto getTypeViaVisit = [](const Value& value)
{
return AZStd::visit(
[](auto&& value) constexpr -> Type
{
using CurrentType = AZStd::decay_t<decltype(value)>;
if constexpr (AZStd::is_same_v<CurrentType, AZStd::monostate>)
{
return Type::Null;
}
else if constexpr (AZStd::is_same_v<CurrentType, int64_t>)
{
return Type::Int64;
}
else if constexpr (AZStd::is_same_v<CurrentType, uint64_t>)
{
return Type::Uint64;
}
else if constexpr (AZStd::is_same_v<CurrentType, double>)
{
return Type::Double;
}
else if constexpr (AZStd::is_same_v<CurrentType, bool>)
{
return Type::Bool;
}
else if constexpr (AZStd::is_same_v<CurrentType, AZStd::string_view>)
{
return Type::String;
}
else if constexpr (AZStd::is_same_v<CurrentType, Value::SharedStringType>)
{
return Type::String;
}
else if constexpr (AZStd::is_same_v<CurrentType, Value::ShortStringType>)
{
return Type::String;
}
else if constexpr (AZStd::is_same_v<CurrentType, ObjectPtr>)
{
return Type::Object;
}
else if constexpr (AZStd::is_same_v<CurrentType, ArrayPtr>)
{
return Type::Array;
}
else if constexpr (AZStd::is_same_v<CurrentType, NodePtr>)
{
return Type::Node;
}
else if constexpr (AZStd::is_same_v<CurrentType, Value::OpaqueStorageType>)
{
return Type::Opaque;
}
else
{
AZ_Assert(false, "AZ::Dom::Value::GetType: m_value has an unexpected type");
}
},
value.GetInternalValue());
};
for (auto _ : state)
{
(getTypeViaVisit(intValue));
(getTypeViaVisit(boolValue));
(getTypeViaVisit(objValue));
(getTypeViaVisit(nodeValue));
(getTypeViaVisit(arrValue));
(getTypeViaVisit(uintValue));
(getTypeViaVisit(doubleValue));
(getTypeViaVisit(stringValue));
}
state.SetItemsProcessed(8 * state.iterations());
}
BENCHMARK_REGISTER_F(DomValueBenchmark, AzDomValueGetType_UsingVariantVisit);
BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueMakeComplexObject)(benchmark::State& state)
{
for (auto _ : state)
{
TakeAndDiscardWithoutTimingDtor(GenerateDomBenchmarkPayload(state.range(0), state.range(1)), state);
}
state.SetItemsProcessed(state.range(0) * state.range(0) * state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomValueBenchmark, AzDomValueMakeComplexObject)
BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueShallowCopy)(benchmark::State& state)
{
Value original = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
for (auto _ : state)
{
Value copy = original;
benchmark::DoNotOptimize(copy);
}
state.SetItemsProcessed(state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_NS(DomValueBenchmark, AzDomValueShallowCopy)
BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueCopyAndMutate)(benchmark::State& state)
{
Value original = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
for (auto _ : state)
{
Value copy = original;
copy["entries"]["Key0"].ArrayPushBack(Value(42));
TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state);
}
state.SetItemsProcessed(state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomValueBenchmark, AzDomValueCopyAndMutate)
BENCHMARK_DEFINE_F(DomValueBenchmark, AzDomValueDeepCopy)(benchmark::State& state)
{
Value original = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
for (auto _ : state)
{
Value copy = Utils::DeepCopy(original);
TakeAndDiscardWithoutTimingDtor(AZStd::move(copy), state);
}
state.SetItemsProcessed(state.iterations());
}
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomValueBenchmark, AzDomValueDeepCopy)
BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByName)(benchmark::State& state)
{
Value value(Type::Object);
AZStd::vector<AZ::Name> keys;
for (int64_t i = 0; i < state.range(0); ++i)
{
AZ::Name key(AZStd::string::format("key%" PRId64, i));
keys.push_back(key);
value[key] = i;
}
for (auto _ : state)
{
for (const AZ::Name& key : keys)
{
benchmark::DoNotOptimize(value[key]);
}
}
state.SetItemsProcessed(state.iterations() * state.range(0));
}
BENCHMARK_REGISTER_F(DomValueBenchmark, LookupMemberByName)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond);
BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByString)(benchmark::State& state)
{
Value value(Type::Object);
AZStd::vector<AZStd::string> keys;
for (int64_t i = 0; i < state.range(0); ++i)
{
AZStd::string key(AZStd::string::format("key%" PRId64, i));
keys.push_back(key);
value[key] = i;
}
for (auto _ : state)
{
for (const AZStd::string& key : keys)
{
benchmark::DoNotOptimize(value[key]);
}
}
state.SetItemsProcessed(state.iterations() * state.range(0));
}
BENCHMARK_REGISTER_F(DomValueBenchmark, LookupMemberByString)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond);
BENCHMARK_DEFINE_F(DomValueBenchmark, LookupMemberByStringComparison)(benchmark::State& state)
{
Value value(Type::Object);
AZStd::vector<AZStd::string> keys;
for (int64_t i = 0; i < state.range(0); ++i)
{
AZStd::string key(AZStd::string::format("key%" PRId64, i));
keys.push_back(key);
value[key] = i;
}
for (auto _ : state)
{
for (const AZStd::string& key : keys)
{
const Object::ContainerType& object = value.GetObject();
benchmark::DoNotOptimize(AZStd::find_if(
object.cbegin(), object.cend(),
[&key](const Object::EntryType& entry)
{
return key == entry.first.GetStringView();
}));
}
}
state.SetItemsProcessed(state.iterations() * state.range(0));
}
BENCHMARK_REGISTER_F(DomValueBenchmark, LookupMemberByStringComparison)->Arg(100)->Arg(1000)->Arg(10000)->Unit(benchmark::kMillisecond);
} // namespace AZ::Dom::Benchmark
@@ -0,0 +1,384 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/DOM/Backends/JSON/JsonBackend.h>
#include <AzCore/DOM/Backends/JSON/JsonSerializationUtils.h>
#include <AzCore/DOM/DomUtils.h>
#include <AzCore/DOM/DomValue.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/numeric.h>
#include <Tests/DOM/DomFixtures.h>
namespace AZ::Dom::Tests
{
class DomValueTests : public DomTestFixture
{
public:
void TearDown() override
{
m_value = Value();
DomTestFixture::TearDown();
}
void PerformValueChecks()
{
Value shallowCopy = m_value;
EXPECT_EQ(m_value, shallowCopy);
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_value, shallowCopy));
Value deepCopy = Utils::DeepCopy(m_value);
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_value, deepCopy));
}
Value m_value;
};
TEST_F(DomValueTests, EmptyArray)
{
m_value.SetArray();
EXPECT_TRUE(m_value.IsArray());
EXPECT_EQ(m_value.ArraySize(), 0);
PerformValueChecks();
}
TEST_F(DomValueTests, SimpleArray)
{
m_value.SetArray();
for (int i = 0; i < 5; ++i)
{
m_value.ArrayPushBack(Value(i));
EXPECT_EQ(m_value.ArraySize(), i + 1);
EXPECT_EQ(m_value[i].GetInt64(), i);
}
PerformValueChecks();
}
TEST_F(DomValueTests, NestedArrays)
{
Value x(5);
m_value.SetArray();
for (int j = 0; j < 5; ++j)
{
Value nestedArray(Type::Array);
for (int i = 0; i < 5; ++i)
{
nestedArray.ArrayPushBack(Value(i));
}
m_value.ArrayPushBack(AZStd::move(nestedArray));
}
EXPECT_EQ(m_value.ArraySize(), 5);
for (int i = 0; i < 3; ++i)
{
EXPECT_EQ(m_value[i].ArraySize(), 5);
for (int j = 0; j < 5; ++j)
{
EXPECT_EQ(m_value[i][j].GetInt64(), j);
}
}
PerformValueChecks();
}
TEST_F(DomValueTests, EmptyObject)
{
m_value.SetObject();
EXPECT_EQ(m_value.MemberCount(), 0);
PerformValueChecks();
}
TEST_F(DomValueTests, SimpleObject)
{
m_value.SetObject();
for (int i = 0; i < 5; ++i)
{
AZStd::string key = AZStd::string::format("Key%i", i);
m_value.AddMember(key, Value(i));
EXPECT_EQ(m_value.MemberCount(), i + 1);
EXPECT_EQ(m_value[key].GetInt64(), i);
}
PerformValueChecks();
}
TEST_F(DomValueTests, NestedObjects)
{
m_value.SetObject();
for (int j = 0; j < 3; ++j)
{
Value nestedObject(Type::Object);
for (int i = 0; i < 5; ++i)
{
nestedObject.AddMember(AZStd::string::format("Key%i", i), Value(i));
}
m_value.AddMember(AZStd::string::format("Obj%i", j), AZStd::move(nestedObject));
}
EXPECT_EQ(m_value.MemberCount(), 3);
for (int j = 0; j < 3; ++j)
{
const Value& nestedObject = m_value[AZStd::string::format("Obj%i", j)];
EXPECT_EQ(nestedObject.MemberCount(), 5);
for (int i = 0; i < 5; ++i)
{
EXPECT_EQ(nestedObject[AZStd::string::format("Key%i", i)].GetInt64(), i);
}
}
PerformValueChecks();
}
TEST_F(DomValueTests, EmptyNode)
{
m_value.SetNode("Test");
EXPECT_EQ(m_value.GetNodeName(), AZ::Name("Test"));
EXPECT_EQ(m_value.MemberCount(), 0);
EXPECT_EQ(m_value.ArraySize(), 0);
PerformValueChecks();
}
TEST_F(DomValueTests, SimpleNode)
{
m_value.SetNode("Test");
for (int i = 0; i < 10; ++i)
{
m_value.ArrayPushBack(Value(i));
EXPECT_EQ(m_value.ArraySize(), i + 1);
EXPECT_EQ(m_value[i].GetInt64(), i);
if (i < 5)
{
AZ::Name key = AZ::Name(AZStd::string::format("TwoTimes%i", i));
m_value.AddMember(key, Value(i * 2));
EXPECT_EQ(m_value.MemberCount(), i + 1);
EXPECT_EQ(m_value[key].GetInt64(), i * 2);
}
}
PerformValueChecks();
}
TEST_F(DomValueTests, NestedNodes)
{
m_value.SetNode("TopLevel");
const AZ::Name childNodeName("ChildNode");
for (int i = 0; i < 5; ++i)
{
Value childNode(Type::Node);
childNode.SetNodeName(childNodeName);
childNode.SetNodeValue(Value(i));
childNode.AddMember("foo", Value(i));
childNode.AddMember("bar", Value("test", false));
m_value.ArrayPushBack(childNode);
}
EXPECT_EQ(m_value.ArraySize(), 5);
for (int i = 0; i < 5; ++i)
{
const Value& childNode = m_value[i];
EXPECT_EQ(childNode.GetNodeName(), childNodeName);
EXPECT_EQ(childNode.GetNodeValue().GetInt64(), i);
EXPECT_EQ(childNode["foo"].GetInt64(), i);
EXPECT_EQ(childNode["bar"].GetString(), "test");
}
PerformValueChecks();
}
TEST_F(DomValueTests, Int64)
{
m_value.SetObject();
m_value["int64_min"] = AZStd::numeric_limits<int64_t>::min();
m_value["int64_max"] = AZStd::numeric_limits<int64_t>::max();
EXPECT_EQ(m_value["int64_min"].GetType(), Type::Int64);
EXPECT_EQ(m_value["int64_min"].GetInt64(), AZStd::numeric_limits<int64_t>::min());
EXPECT_EQ(m_value["int64_max"].GetType(), Type::Int64);
EXPECT_EQ(m_value["int64_max"].GetInt64(), AZStd::numeric_limits<int64_t>::max());
PerformValueChecks();
}
TEST_F(DomValueTests, Uint64)
{
m_value.SetObject();
m_value["uint64_min"] = AZStd::numeric_limits<uint64_t>::min();
m_value["uint64_max"] = AZStd::numeric_limits<uint64_t>::max();
EXPECT_EQ(m_value["uint64_min"].GetType(), Type::Uint64);
EXPECT_EQ(m_value["uint64_min"].GetInt64(), AZStd::numeric_limits<uint64_t>::min());
EXPECT_EQ(m_value["uint64_max"].GetType(), Type::Uint64);
EXPECT_EQ(m_value["uint64_max"].GetInt64(), AZStd::numeric_limits<uint64_t>::max());
PerformValueChecks();
}
TEST_F(DomValueTests, Double)
{
m_value.SetObject();
m_value["double_min"] = AZStd::numeric_limits<double>::min();
m_value["double_max"] = AZStd::numeric_limits<double>::max();
EXPECT_EQ(m_value["double_min"].GetType(), Type::Double);
EXPECT_EQ(m_value["double_min"].GetDouble(), AZStd::numeric_limits<double>::min());
EXPECT_EQ(m_value["double_max"].GetType(), Type::Double);
EXPECT_EQ(m_value["double_max"].GetDouble(), AZStd::numeric_limits<double>::max());
PerformValueChecks();
}
TEST_F(DomValueTests, Null)
{
m_value.SetObject();
m_value["null_value"] = Value(Type::Null);
EXPECT_EQ(m_value["null_value"].GetType(), Type::Null);
EXPECT_EQ(m_value["null_type"], Value());
PerformValueChecks();
}
TEST_F(DomValueTests, Bool)
{
m_value.SetObject();
m_value["true_value"] = true;
m_value["false_value"] = false;
EXPECT_EQ(m_value["true_value"].GetType(), Type::Bool);
EXPECT_EQ(m_value["true_value"].GetBool(), true);
EXPECT_EQ(m_value["false_value"].GetType(), Type::Bool);
EXPECT_EQ(m_value["false_value"].GetBool(), false);
PerformValueChecks();
}
TEST_F(DomValueTests, String)
{
const char* s1 = "reference string long enough to avoid SSO";
const char* s2 = "copy string long enough to avoid SSO";
m_value.SetObject();
AZStd::string stringToReference = s1;
m_value["no_copy"] = Value(stringToReference, false);
AZStd::string stringToCopy = s2;
m_value["copy"] = Value(stringToCopy, true);
EXPECT_EQ(m_value["no_copy"].GetType(), Type::String);
EXPECT_EQ(m_value["no_copy"].GetString(), s1);
stringToReference.at(0) = 'F';
EXPECT_NE(m_value["no_copy"].GetString(), s1);
EXPECT_EQ(m_value["copy"].GetType(), Type::String);
EXPECT_EQ(m_value["copy"].GetString(), s2);
stringToCopy.at(0) = 'F';
EXPECT_EQ(m_value["copy"].GetString(), s2);
PerformValueChecks();
}
TEST_F(DomValueTests, CopyOnWrite_Object)
{
Value v1(Type::Object);
v1["foo"] = 5;
Value nestedObject(Type::Object);
v1["obj"] = nestedObject;
Value v2 = v1;
EXPECT_EQ(&v1.GetObject(), &v2.GetObject());
EXPECT_EQ(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject());
v2["foo"] = 0;
EXPECT_NE(&v1.GetObject(), &v2.GetObject());
EXPECT_EQ(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject());
v2["obj"]["key"] = true;
EXPECT_NE(&v1.GetObject(), &v2.GetObject());
EXPECT_NE(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject());
v2 = v1;
EXPECT_EQ(&v1.GetObject(), &v2.GetObject());
EXPECT_EQ(&v1.FindMember("obj")->second.GetObject(), &v2.FindMember("obj")->second.GetObject());
}
TEST_F(DomValueTests, CopyOnWrite_Array)
{
Value v1(Type::Array);
v1.ArrayPushBack(Value(1));
v1.ArrayPushBack(Value(2));
Value nestedArray(Type::Array);
v1.ArrayPushBack(nestedArray);
Value v2 = v1;
EXPECT_EQ(&v1.GetArray(), &v2.GetArray());
EXPECT_EQ(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray());
v2[0] = 0;
EXPECT_NE(&v1.GetArray(), &v2.GetArray());
EXPECT_EQ(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray());
v2[2].ArrayPushBack(Value(42));
EXPECT_NE(&v1.GetArray(), &v2.GetArray());
EXPECT_NE(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray());
v2 = v1;
EXPECT_EQ(&v1.GetArray(), &v2.GetArray());
EXPECT_EQ(&v1.ArrayAt(2).GetArray(), &v2.ArrayAt(2).GetArray());
}
TEST_F(DomValueTests, CopyOnWrite_Node)
{
Value v1;
v1.SetNode("TopLevel");
v1.ArrayPushBack(Value(1));
v1.ArrayPushBack(Value(2));
v1["obj"].SetNode("Nested");
Value v2 = v1;
EXPECT_EQ(&v1.GetNode(), &v2.GetNode());
EXPECT_EQ(&v1["obj"].GetNode(), &v2["obj"].GetNode());
v2[0] = 0;
EXPECT_NE(&v1.GetNode(), &v2.GetNode());
EXPECT_EQ(&v1["obj"].GetNode(), &v2["obj"].GetNode());
v2["obj"].ArrayPushBack(Value(42));
EXPECT_NE(&v1.GetNode(), &v2.GetNode());
EXPECT_NE(&v1["obj"].GetNode(), &v2["obj"].GetNode());
v2 = v1;
EXPECT_EQ(&v1.GetNode(), &v2.GetNode());
EXPECT_EQ(&v1["obj"].GetNode(), &v2["obj"].GetNode());
}
} // namespace AZ::Dom::Tests
+15 -15
View File
@@ -373,8 +373,8 @@ namespace UnitTest
: public AllocatorsFixture
{
public:
using Handler = Handler<Bus>;
using MultiHandlerById = MultiHandlerById<Bus>;
using BusHandler = Handler<Bus>;
using BusMultiHandlerById = MultiHandlerById<Bus>;
EBusTestAll()
{
@@ -402,7 +402,7 @@ namespace UnitTest
{
for (int handler = 0; handler < numHandlersPerAddress; ++handler)
{
m_handlers[address].emplace_back(aznew Handler(address, connectOnConstruct));
m_handlers[address].emplace_back(aznew BusHandler(address, connectOnConstruct));
++m_numHandlers;
}
}
@@ -429,7 +429,7 @@ namespace UnitTest
{
for (const auto& handlerPair : m_handlers)
{
for (Handler* handler : handlerPair.second)
for (BusHandler* handler : handlerPair.second)
{
delete handler;
}
@@ -452,7 +452,7 @@ namespace UnitTest
if (AddressesAreOrdered())
{
// Collect the first handler from each address
using PairType = AZStd::pair<int, Handler*>;
using PairType = AZStd::pair<int, BusHandler*>;
AZStd::vector<PairType> sortedHandlers;
for (const auto& handlerPair : m_handlers)
{
@@ -495,7 +495,7 @@ namespace UnitTest
{
auto& handlers = m_handlers[id];
for (Handler* handler : handlers)
for (BusHandler* handler : handlers)
{
EXPECT_EQ(expected, handler->m_eventCalls);
}
@@ -505,11 +505,11 @@ namespace UnitTest
{
// Sort the handlers the same way we expect the bus to sort them
auto sortedHandlers = handlers;
AZStd::sort(sortedHandlers.begin(), sortedHandlers.end(), AZStd::bind(&Handler::Compare, AZStd::placeholders::_1, AZStd::placeholders::_2));
AZStd::sort(sortedHandlers.begin(), sortedHandlers.end(), AZStd::bind(&BusHandler::Compare, AZStd::placeholders::_1, AZStd::placeholders::_2));
// Iterate over the list, and validate that they were called in the correct order
unsigned int lastExecuted = 0;
for (const Handler* handler : sortedHandlers)
for (const BusHandler* handler : sortedHandlers)
{
if (lastExecuted > 0)
{
@@ -550,7 +550,7 @@ namespace UnitTest
}
protected:
AZStd::unordered_map<int, AZStd::vector<Handler*>> m_handlers;
AZStd::unordered_map<int, AZStd::vector<BusHandler*>> m_handlers;
int m_numHandlers = 0;
};
TYPED_TEST_CASE(EBusTestAll, BusTypesAll);
@@ -578,7 +578,7 @@ namespace UnitTest
TYPED_TEST(EBusTestAll, ConnectDisconnect)
{
using Bus = TypeParam;
using Handler = typename EBusTestAll<Bus>::Handler;
using Handler = typename EBusTestAll<Bus>::BusHandler;
constexpr bool connectOnConstruct{ true };
Handler meh(0, connectOnConstruct);
@@ -602,13 +602,13 @@ namespace UnitTest
TYPED_TEST(EBusTestIdMultiHandlers, EnumerateHandlers_MultiHandler)
{
using Bus = TypeParam;
using MultiHandlerById = typename EBusTestAll<Bus>::MultiHandlerById;
using BusMultiHandlerById = typename EBusTestAll<Bus>::BusMultiHandlerById;
MultiHandlerById sourceMultiHandler{ 0, 1, 2 };
MultiHandlerById multiHandlerWithOverlappingIds{ 1, 3, 5 };
BusMultiHandlerById sourceMultiHandler{ 0, 1, 2 };
BusMultiHandlerById multiHandlerWithOverlappingIds{ 1, 3, 5 };
// Test handlers' enumeration functionality
Bus::EnumerateHandlers([](typename MultiHandlerById::Interface* interfaceInst) -> bool
Bus::EnumerateHandlers([](typename BusMultiHandlerById::Interface* interfaceInst) -> bool
{
interfaceInst->OnEvent();
return true;
@@ -618,7 +618,7 @@ namespace UnitTest
TYPED_TEST(EBusTestId, FindFirstHandler)
{
using Bus = TypeParam;
using Handler = typename EBusTestAll<Bus>::Handler;
using Handler = typename EBusTestAll<Bus>::BusHandler;
constexpr bool connectOnConstruct{ true };
Handler meh0(0, connectOnConstruct); /// <-- Bind to bus 0
Handler meh1(1, connectOnConstruct); /// <-- Bind to bus 1
@@ -0,0 +1,19 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/UnitTest/TestTypes.h>
#if AZ_DEBUG_BUILD
#define AZ_MATH_TEST_START_TRACE_SUPPRESSION AZ_TEST_START_TRACE_SUPPRESSION
#define AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(x) AZ_TEST_STOP_TRACE_SUPPRESSION(x)
#else
#define AZ_MATH_TEST_START_TRACE_SUPPRESSION
#define AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(x)
#endif
@@ -12,6 +12,7 @@
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <Math/MathTest.h>
using namespace AZ;
@@ -47,7 +48,9 @@ namespace UnitTest
TEST(MATH_Plane, TestSet)
{
Plane pl;
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
pl.Set(12.0f, 13.0f, 14.0f, 15.0f);
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetDistance(), 15.0f);
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetX(), 12.0f);
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetY(), 13.0f);
@@ -57,7 +60,9 @@ namespace UnitTest
TEST(MATH_Plane, TestSetVector3)
{
Plane pl;
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
pl.Set(Vector3(22.0f, 23.0f, 24.0f), 25.0f);
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetDistance(), 25.0f);
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetX(), 22.0f);
AZ_TEST_ASSERT_FLOAT_CLOSE(pl.GetNormal().GetY(), 23.0f);
@@ -177,17 +182,21 @@ namespace UnitTest
pl.Set(1.0f, 0.0f, 0.0f, 0.0f);
AZ_TEST_ASSERT(pl.IsFinite());
const float infinity = std::numeric_limits<float>::infinity();
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
pl.Set(infinity, infinity, infinity, infinity);
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
AZ_TEST_ASSERT(!pl.IsFinite());
}
TEST(MATH_Plane, CreateFromVectorCoefficients_IsEquivalentToCreateFromCoefficients)
{
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
Plane planeFromCoefficients = Plane::CreateFromCoefficients(1.0, 2.0, 3.0, 4.0);
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
Vector4 coefficients(1.0, 2.0, 3.0, 4.0);
Plane planeFromVectorCoefficients = Plane::CreateFromVectorCoefficients(coefficients);
EXPECT_EQ(planeFromVectorCoefficients, planeFromCoefficients);
}
}
@@ -15,6 +15,8 @@
#include <AzCore/Math/Obb.h>
#include <AzCore/Math/Aabb.h>
#include <Math/MathTest.h>
using namespace AZ;
namespace UnitTest
@@ -1409,13 +1411,17 @@ namespace UnitTest
script->Execute("AZTestAssertFloatClose(pl:GetNormal().y,-1)");
script->Execute("AZTestAssertFloatClose(pl:GetNormal().z,0)");
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
script->Execute("pl:Set(12, 13, 14, 15)");
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
script->Execute("AZTestAssertFloatClose(pl:GetDistance(), 15)");
script->Execute("AZTestAssertFloatClose(pl:GetNormal().x, 12)");
script->Execute("AZTestAssertFloatClose(pl:GetNormal().y, 13)");
script->Execute("AZTestAssertFloatClose(pl:GetNormal().z, 14)");
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
script->Execute("pl:Set(Vector3(22, 23, 24), 25)");
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
script->Execute("AZTestAssertFloatClose(pl:GetDistance(), 25)");
script->Execute("AZTestAssertFloatClose(pl:GetNormal().x, 22)");
script->Execute("AZTestAssertFloatClose(pl:GetNormal().y, 23)");
@@ -1493,7 +1499,9 @@ namespace UnitTest
script->Execute("pl:Set(1, 0, 0, 0)");
script->Execute("AZTestAssert(pl:IsFinite())");
AZ_MATH_TEST_START_TRACE_SUPPRESSION;
script->Execute("pl:Set(math.huge, math.huge, math.huge, math.huge)");
AZ_MATH_TEST_STOP_TRACE_SUPPRESSION(1);
script->Execute("AZTestAssert( not pl:IsFinite())");
}
+11 -6
View File
@@ -4014,9 +4014,12 @@ TEST_F(SerializeBasicTest, BasicTypeTest_Succeed)
};
}
} // namespace UnitTest
AZ_TYPE_INFO_SPECIALIZE(UnitTest::EditTest::MyEditStruct3::EditEnum, "{4AF433C2-055E-4E34-921A-A7D16AB548CA}");
AZ_TYPE_INFO_SPECIALIZE(UnitTest::EditTest::MyEditStruct3::EditEnumClass, "{4FEC2F0B-A599-4FCD-836B-89E066791793}");
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(UnitTest::EditTest::MyEditStruct3::EditEnum, "{4AF433C2-055E-4E34-921A-A7D16AB548CA}");
AZ_TYPE_INFO_SPECIALIZE(UnitTest::EditTest::MyEditStruct3::EditEnumClass, "{4FEC2F0B-A599-4FCD-836B-89E066791793}");
}
namespace UnitTest
{
@@ -7798,10 +7801,12 @@ namespace UnitTest
};
}
AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestUnscopedSerializationEnum, "{83383BFA-F6DA-4124-BE4F-2FAAB7C594E7}");
AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestScopedSerializationEnum, "{17341C5E-81C3-44CB-A40D-F97D49C2531D}");
AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestUnsignedEnum, "{0F91A5AE-DADA-4455-B158-8DB79D277495}");
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestUnscopedSerializationEnum, "{83383BFA-F6DA-4124-BE4F-2FAAB7C594E7}");
AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestScopedSerializationEnum, "{17341C5E-81C3-44CB-A40D-F97D49C2531D}");
AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestUnsignedEnum, "{0F91A5AE-DADA-4455-B158-8DB79D277495}");
}
namespace UnitTest
{
@@ -148,6 +148,7 @@ set(FILES
Math/Matrix4x4PerformanceTests.cpp
Math/Matrix4x4Tests.cpp
Math/MatrixUtilsTests.cpp
Math/MathTest.h
Math/MathTestData.h
Math/ObbPerformanceTests.cpp
Math/ObbTests.cpp
@@ -214,8 +215,12 @@ set(FILES
AZStd/Variant.cpp
AZStd/VariantSerialization.cpp
AZStd/VectorAndArray.cpp
DOM/DomFixtures.cpp
DOM/DomFixtures.h
DOM/DomJsonTests.cpp
DOM/DomJsonBenchmarks.cpp
DOM/DomValueTests.cpp
DOM/DomValueBenchmarks.cpp
)
# Prevent the following files from being grouped in UNITY builds
@@ -129,6 +129,32 @@ namespace Camera
GetFrustumHeight()
};
}
//! Unprojects a position in screen space pixel coordinates to world space.
//! With a depth of zero, the position returned will be on the near clip plane of the camera
//! in world space.
//! @param screenPosition The absolute screen position
//! @param depth The depth offset into the world relative to the near clip plane of the camera
//! @return the position in world space
virtual AZ::Vector3 ScreenToWorld(const AZ::Vector2& screenPosition, float depth) = 0;
//! Unprojects a position in screen space normalized device coordinates to world space.
//! With a depth of zero, the position returned will be on the near clip plane of the camera
//! in world space.
//! @param screenNdcPosition The normalized device coordinates in the range [0,1]
//! @param depth The depth offset into the world relative to the near clip plane of the camera
//! @return the position in world space
virtual AZ::Vector3 ScreenNdcToWorld(const AZ::Vector2& screenNdcPosition, float depth) = 0;
//! Projects a position in world space to screen space for the given camera.
//! @param worldPosition The world position
//! @return The absolute screen position
virtual AZ::Vector2 WorldToScreen(const AZ::Vector3& worldPosition) = 0;
//! Projects a position in world space to screen space normalized device coordinates.
//! @param worldPosition The world position
//! @return The normalized device coordinates in the range [0,1]
virtual AZ::Vector2 WorldToScreenNdc(const AZ::Vector3& worldPosition) = 0;
};
using CameraRequestBus = AZ::EBus<CameraComponentRequests>;
@@ -97,19 +97,38 @@ namespace AzFramework
AZStd::vector<AZStd::string> registeredAssetPaths;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(registeredAssetPaths, &AZ::Data::AssetCatalogRequests::GetRegisteredAssetPaths);
const char* dependencyXmlPattern = "*_dependencies.xml";
constexpr const char* dependencyXmlPattern = "_dependencies.xml";
for (const AZStd::string& assetPath : registeredAssetPaths)
{
if (!AZStd::wildcard_match(dependencyXmlPattern, assetPath.c_str()))
if (assetPath.ends_with(dependencyXmlPattern))
{
continue;
}
if (!m_excludeFileQueryManager.get()->LoadEngineDependencies(assetPath))
{
AZ_Error("ExcludeFileComponent", false, "Failed to add assets referenced from %s to the blocked list", assetPath.c_str());
AZ_VerifyError("ExcludeFileComponent", m_excludeFileQueryManager.get()->LoadEngineDependencies(assetPath),
"Failed to add assets referenced from %s to the blocked list", assetPath.c_str());
}
}
}
void ExcludeFileComponent::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
{
// Reload any modified "<name>_dependencies.xml" files
AZ::IO::Path assetPath;
auto GetAssetPath = [&assetId, &assetPath](AZ::Data::AssetCatalogRequests* assetCatalogRequests)
{
assetPath = assetCatalogRequests->GetAssetPathById(assetId);
};
AZ::Data::AssetCatalogRequestBus::Broadcast(AZStd::move(GetAssetPath));
constexpr const char* dependencyXmlPattern = "_dependencies.xml";
if (assetPath.Native().ends_with(dependencyXmlPattern))
{
AZ_VerifyError("ExcludeFileComponent", m_excludeFileQueryManager.get()->LoadEngineDependencies(assetPath.Native()),
"Failed to add assets referenced from %s to the blocked list", assetPath.c_str());
}
}
void ExcludeFileComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
{
OnCatalogAssetChanged(assetId);
}
}
}
@@ -65,6 +65,8 @@ namespace AzFramework
void Deactivate() override;
void OnCatalogLoaded(const char* catalogFile) override;
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override;
static void Reflect(AZ::ReflectContext* context);
@@ -10,6 +10,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/std/functional.h>
#include <AzFramework/Spawnable/Spawnable.h>
@@ -164,6 +165,8 @@ namespace AzFramework
public:
friend class SpawnableEntitiesDefinition;
AZ_CLASS_ALLOCATOR(AzFramework::EntitySpawnTicket, AZ::SystemAllocator, 0);
using Id = uint32_t;
EntitySpawnTicket() = default;
@@ -499,12 +499,8 @@ namespace AzFramework
for (auto it = newEntitiesBegin; it != newEntitiesEnd; ++it)
{
AZ::Entity* clone = (*it);
// The entity component framework doesn't handle entities without TransformComponent safely.
if (!clone->GetComponents().empty())
{
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, clone);
}
// Let other systems know about newly spawned entities for any post-processing after adding to the scene/game context.
@@ -636,12 +632,8 @@ namespace AzFramework
for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it)
{
AZ::Entity* clone = (*it);
// The entity component framework doesn't handle entities without TransformComponent safely.
if (!clone->GetComponents().empty())
{
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
if (request.m_completionCallback)
@@ -668,7 +660,7 @@ namespace AzFramework
{
if (entity != nullptr)
{
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
// Setting it to 0 is needed to avoid the infinite loop between GameEntityContext and SpawnableEntitiesManager.
entity->SetSpawnTicketId(0);
GameEntityContextRequestBus::Broadcast(
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
@@ -702,7 +694,7 @@ namespace AzFramework
{
if (*entityIterator != nullptr && (*entityIterator)->GetId() == request.m_entityId)
{
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
// Setting it to 0 is needed to avoid the infinite loop between GameEntityContext and SpawnableEntitiesManager.
(*entityIterator)->SetSpawnTicketId(0);
GameEntityContextRequestBus::Broadcast(
&GameEntityContextRequestBus::Events::DestroyGameEntity, (*entityIterator)->GetId());
@@ -949,11 +941,6 @@ namespace AzFramework
GameEntityContextRequestBus::Broadcast(
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
}
else
{
// Entities without components wouldn't have been send to the GameEntityContext.
delete entity;
}
}
delete request.m_ticket;
@@ -8,6 +8,7 @@
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Component/ComponentApplicationLifecycle.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Spawnable/SpawnableMetaData.h>
@@ -61,15 +62,6 @@ namespace AzFramework
m_entitiesManager.ProcessQueue(SpawnableEntitiesManager::CommandQueuePriority::High);
}
void SpawnableSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
{
if (!m_catalogAvailable)
{
m_catalogAvailable = true;
LoadRootSpawnableFromSettingsRegistry();
}
}
uint64_t SpawnableSystemComponent::AssignRootSpawnable(AZ::Data::Asset<Spawnable> rootSpawnable)
{
uint32_t generation = 0;
@@ -157,20 +149,29 @@ namespace AzFramework
// Register with AssetDatabase
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Spawnables can't be registered because the Asset Manager is not ready yet.");
AZ::Data::AssetManager::Instance().RegisterHandler(&m_assetHandler, AZ::AzTypeInfo<Spawnable>::Uuid());
// Register with AssetCatalog
AZ::Data::AssetCatalogRequestBus::Broadcast(
&AZ::Data::AssetCatalogRequestBus::Events::EnableCatalogForAsset, AZ::AzTypeInfo<Spawnable>::Uuid());
AZ::Data::AssetCatalogRequestBus::Broadcast(
&AZ::Data::AssetCatalogRequestBus::Events::AddExtension, Spawnable::FileExtension);
AssetCatalogEventBus::Handler::BusConnect();
// Register for the CriticalAssetsCompiled lifecycle event to trigger the loading of the root spawnable
auto settingsRegistry = AZ::SettingsRegistry::Get();
AZ_Assert(settingsRegistry, "Unable to change root spawnable callback because Settings Registry is not available.");
auto LifecycleCallback = [this](AZStd::string_view, AZ::SettingsRegistryInterface::Type)
{
LoadRootSpawnableFromSettingsRegistry();
};
AZ::ComponentApplicationLifecycle::RegisterHandler(*settingsRegistry, m_criticalAssetsHandler,
AZStd::move(LifecycleCallback), "CriticalAssetsCompiled");
RootSpawnableNotificationBus::Handler::BusConnect();
AZ::TickBus::Handler::BusConnect();
auto registry = AZ::SettingsRegistry::Get();
AZ_Assert(registry, "Unable to change root spawnable callback because Settings Registry is not available.");
m_registryChangeHandler = registry->RegisterNotifier([this](AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/)
m_registryChangeHandler = settingsRegistry->RegisterNotifier([this](AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/)
{
if (path.starts_with(RootSpawnableRegistryKey))
{
@@ -187,13 +188,14 @@ namespace AzFramework
AZ::TickBus::Handler::BusDisconnect();
RootSpawnableNotificationBus::Handler::BusDisconnect();
AssetCatalogEventBus::Handler::BusDisconnect();
// Unregister Lifecycle event handler
m_criticalAssetsHandler = {};
if (m_catalogAvailable)
if (m_rootSpawnableId.IsValid())
{
ReleaseRootSpawnable();
// The SpawnalbleSystemComponent needs to guarantee there's no more processing left to do by the
// The SpawnableSystemComponent needs to guarantee there's no more processing left to do by the
// entity manager before it can safely destroy it on shutdown, but also to make sure that are no
// more calls to the callback registered to the root spawnable as that accesses this component.
m_rootSpawnableContainer.Clear();
@@ -210,8 +212,6 @@ namespace AzFramework
void SpawnableSystemComponent::LoadRootSpawnableFromSettingsRegistry()
{
AZ_Assert(m_catalogAvailable, "Attempting to load root spawnable while the catalog is not available yet.");
auto registry = AZ::SettingsRegistry::Get();
AZ_Assert(registry, "Unable to check for root spawnable because the Settings Registry is not available.");
@@ -12,7 +12,6 @@
#include <AzCore/Component/TickBus.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/std/parallel/atomic.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
@@ -25,7 +24,6 @@ namespace AzFramework
: public AZ::Component
, public AZ::TickBus::Handler
, public AZ::SystemTickBus::Handler
, public AssetCatalogEventBus::Handler
, public RootSpawnableInterface::Registrar
, public RootSpawnableNotificationBus::Handler
{
@@ -63,12 +61,6 @@ namespace AzFramework
void OnSystemTick() override;
//
// AssetCatalogEventBus
//
void OnCatalogLoaded(const char* catalogFile) override;
//
// RootSpawnableInterface
//
@@ -97,6 +89,6 @@ namespace AzFramework
AZ::SettingsRegistryInterface::NotifyEventHandler m_registryChangeHandler;
AZ::Data::AssetId m_rootSpawnableId;
bool m_catalogAvailable{ false };
AZ::SettingsRegistryInterface::NotifyEventHandler m_criticalAssetsHandler;
};
} // namespace AzFramework
@@ -11,12 +11,15 @@
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/std/containers/span.h>
#include <AzFramework/SurfaceData/SurfaceData.h>
namespace AzFramework
{
namespace Terrain
{
typedef AZStd::function<void(size_t xIndex, size_t yIndex, const SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)> SurfacePointRegionFillCallback;
typedef AZStd::function<void(const SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)> SurfacePointListFillCallback;
//! Shared interface for terrain system implementations
class TerrainDataRequests
@@ -131,6 +134,58 @@ namespace AzFramework
Sampler sampleFilter = Sampler::DEFAULT,
bool* terrainExistsPtr = nullptr) const = 0;
//! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each
//! XY coordinate in the list.
virtual void ProcessHeightsFromList(const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessNormalsFromList(const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfacePointsFromList(const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
//! Returns the number of samples for a given region and step size. The first and second
//! elements of the pair correspond to the X and Y sample counts respectively.
virtual AZStd::pair<size_t, size_t> GetNumSamplesFromRegion(const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize) const = 0;
//! Given a region(aabb) and a step size, call the provided callback function with surface data corresponding to the
//! coordinates in the region.
virtual void ProcessHeightsFromRegion(const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessNormalsFromRegion(const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfaceWeightsFromRegion(const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
virtual void ProcessSurfacePointsFromRegion(const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
private:
// Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of
// using an "out" parameter. The "out" parameter is useful for reusing memory allocated in SurfacePoint when
+6 -6
View File
@@ -8,8 +8,8 @@
include(AzFramework/feature_options.cmake)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER})
set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
ly_add_target(
NAME AzFramework STATIC
@@ -44,7 +44,7 @@ ly_add_source_properties(
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME})
o3de_pal_dir(test_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER})
ly_add_target(
NAME AzFrameworkTestShared STATIC
@@ -86,11 +86,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
NAMESPACE AZ
FILES_CMAKE
Tests/frameworktests_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
${test_pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
${pal_dir}
${test_pal_dir}
BUILD_DEPENDENCIES
PRIVATE
AZ::AzFramework
@@ -104,7 +104,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
NAME AZ::AzFramework.Tests
)
include(${pal_dir}/platform_specific_test_targets.cmake)
include(${test_pal_dir}/platform_specific_test_targets.cmake)
endif()
@@ -76,5 +76,31 @@ namespace UnitTest
GetSurfacePointFromVector2, void(const AZ::Vector2&, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*));
MOCK_CONST_METHOD5(
GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*));
MOCK_CONST_METHOD3(
ProcessHeightsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessNormalsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessSurfaceWeightsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessSurfacePointsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessHeightsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessNormalsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessSurfaceWeightsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD3(
ProcessSurfacePointsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
MOCK_CONST_METHOD2(
GetNumSamplesFromRegion, AZStd::pair<size_t, size_t>(const AZ::Aabb&, const AZ::Vector2&));
MOCK_CONST_METHOD4(
ProcessHeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
MOCK_CONST_METHOD4(
ProcessNormalsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
MOCK_CONST_METHOD4(
ProcessSurfaceWeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
MOCK_CONST_METHOD4(
ProcessSurfacePointsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
};
} // namespace UnitTest
@@ -77,6 +77,12 @@ namespace UnitTest
public:
AZ_COMPONENT(TargetSpawnableComponent, "{B4041561-63A7-4E1E-80F1-78C08D497960}");
TargetSpawnableComponent() = default;
explicit TargetSpawnableComponent(AZ::EntityId parent)
: m_parent(parent)
{
}
void Activate() override {}
void Deactivate() override {}
@@ -84,14 +90,19 @@ namespace UnitTest
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<TargetSpawnableComponent, AZ::Component>();
serializeContext->Class<TargetSpawnableComponent, AZ::Component>()
->Field("Parent", &TargetSpawnableComponent::m_parent);
}
}
AZ::EntityId m_parent;
};
class SpawnableEntitiesManagerTest : public AllocatorsFixture
{
public:
constexpr static AZ::u64 EntityIdStartId = 40;
void SetUp() override
{
AllocatorsFixture::SetUp();
@@ -111,7 +122,7 @@ namespace UnitTest
m_spawnable = aznew AzFramework::Spawnable(
AZ::Data::AssetId::CreateString("{EB2E8A2B-F253-4A90-BBF4-55F2EED786B8}:0"), AZ::Data::AssetData::AssetStatus::Ready);
m_spawnableAsset = new AZ::Data::Asset<AzFramework::Spawnable>(m_spawnable, AZ::Data::AssetLoadBehavior::Default);
m_ticket = new AzFramework::EntitySpawnTicket(*m_spawnableAsset);
m_ticket = aznew AzFramework::EntitySpawnTicket(*m_spawnableAsset);
auto managerInterface = AzFramework::SpawnableEntitiesInterface::Get();
m_manager = azrtti_cast<AzFramework::SpawnableEntitiesManager*>(managerInterface);
@@ -147,22 +158,43 @@ namespace UnitTest
{
auto entry = AZStd::make_unique<AZ::Entity>();
entry->AddComponent(aznew SourceSpawnableComponent());
entry->SetId(AZ::EntityId(EntityIdStartId + i));
entities.push_back(AZStd::move(entry));
}
}
AZ::Data::Asset<AzFramework::Spawnable> CreateTargetSpawnable(size_t numElements)
AZ::Data::Asset<AzFramework::Spawnable> CreateTargetSpawnable(size_t numElements, bool requiresMatchingEntityIds)
{
auto target = aznew AzFramework::Spawnable(
AZ::Data::AssetId(AZ::Uuid("{716CD8C3-0BA8-4F32-B579-0EC7C967796F}")), AZ::Data::AssetData::AssetStatus::Ready);
AzFramework::Spawnable::EntityList& entities = target->GetEntities();
entities.reserve(numElements);
for (size_t i = 0; i < numElements; ++i)
if (requiresMatchingEntityIds)
{
auto entry = AZStd::make_unique<AZ::Entity>();
entry->AddComponent(aznew TargetSpawnableComponent());
entities.push_back(AZStd::move(entry));
for (size_t i = 0; i < numElements; ++i)
{
auto entry = AZStd::make_unique<AZ::Entity>();
if (i != 0)
{
entry->AddComponent(aznew TargetSpawnableComponent(AZ::EntityId(EntityIdStartId + i - 1)));
}
else
{
entry->AddComponent(aznew TargetSpawnableComponent());
}
entry->SetId(AZ::EntityId(EntityIdStartId + i));
entities.push_back(AZStd::move(entry));
}
}
else
{
for (size_t i = 0; i < numElements; ++i)
{
auto entry = AZStd::make_unique<AZ::Entity>();
entry->AddComponent(aznew TargetSpawnableComponent());
entities.push_back(AZStd::move(entry));
}
}
return AZ::Data::Asset<AzFramework::Spawnable>(target, AZ::Data::AssetLoadBehavior::NoLoad);
@@ -212,6 +244,38 @@ namespace UnitTest
return true;
}
static bool DoParentEntityIdsMatch(AzFramework::SpawnableConstEntityContainerView entities)
{
if (entities.empty())
{
return false;
}
const AZ::Entity* previous = nullptr;
for (const AZ::Entity* entity : entities)
{
if (entity)
{
if (previous)
{
if (TargetSpawnableComponent* link = entity->FindComponent<TargetSpawnableComponent>(); link != nullptr)
{
if (link->m_parent != previous->GetId())
{
return false;
}
}
previous = entity;
}
}
else
{
return false;
}
}
return true;
}
static bool IsEveryOtherEntityAReplacement(AzFramework::SpawnableConstEntityContainerView entities)
{
bool onAlternative = true;
@@ -516,7 +580,7 @@ namespace UnitTest
// Make sure we start with a fresh ticket each time, or else each iteration through this loop would continue to build up
// more and more entities.
delete m_ticket;
m_ticket = new AzFramework::EntitySpawnTicket(*m_spawnableAsset);
m_ticket = aznew AzFramework::EntitySpawnTicket(*m_spawnableAsset);
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
@@ -599,7 +663,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace,
@@ -608,11 +673,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allReplaced = false;
auto callback = [&spawnedEntitiesCount, &allReplaced](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allReplaced, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allReplaced = AreAllEntitiesReplaced(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -621,6 +688,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allReplaced);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_AllAliasesWithAdditional_SourceAndTargetComponentsMerged)
@@ -628,7 +696,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = false;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional,
@@ -637,11 +706,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allAdded = false;
auto callback = [&spawnedEntitiesCount, &allAdded](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allAdded, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allAdded = IsEveryOtherEntityAReplacement(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -650,6 +721,7 @@ namespace UnitTest
EXPECT_EQ(8, spawnedEntitiesCount);
EXPECT_TRUE(allAdded);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_AllAliasesWithMerge_SourceAndTargetComponentsMerged)
@@ -657,7 +729,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge,
@@ -666,11 +739,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allMerged = false;
auto callback = [&spawnedEntitiesCount, &allMerged](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allMerged, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allMerged = AreAllMerged(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -679,6 +754,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allMerged);
EXPECT_TRUE(allEntityIdsPatched);
}
//
@@ -1095,7 +1171,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace,
@@ -1106,11 +1183,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allReplaced = false;
auto callback = [&spawnedEntitiesCount, &allReplaced](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allReplaced, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allReplaced = AreAllEntitiesReplaced(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -1119,6 +1198,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allReplaced);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllAliasesWithAdditional_SourceAndTargetComponentsMerged)
@@ -1126,7 +1206,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = false;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional,
@@ -1137,12 +1218,14 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allAdded = false;
bool allEntityIdsPatched = false;
auto callback =
[&spawnedEntitiesCount, &allAdded](
[&spawnedEntitiesCount, &allAdded, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allAdded = IsEveryOtherEntityAReplacement(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -1151,6 +1234,7 @@ namespace UnitTest
EXPECT_EQ(8, spawnedEntitiesCount);
EXPECT_TRUE(allAdded);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllAliasesWithMerge_SourceAndTargetComponentsMerged)
@@ -1158,7 +1242,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge,
@@ -1169,11 +1254,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allMerged = false;
auto callback = [&spawnedEntitiesCount, &allMerged](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allMerged, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allMerged = AreAllMerged(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -1182,6 +1269,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allMerged);
EXPECT_TRUE(allEntityIdsPatched);
}
//
@@ -1302,6 +1390,36 @@ namespace UnitTest
// ClaimEntities
//
TEST_F(SpawnableEntitiesManagerTest, ClaimEntities_Call_AllEntitiesWereClaimedAndNotDeleted)
{
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZStd::vector<AZ::Entity*> claimedEntities;
auto callback = [&claimedEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView container)
{
for (AZ::Entity* entity : container)
{
claimedEntities.push_back(entity);
}
};
{
AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset);
m_manager->SpawnAllEntities(ticket);
m_manager->ClaimEntities(ticket, AZStd::move(callback));
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
EXPECT_EQ(NumEntities, claimedEntities.size());
// If these calls fail it means that the ticket has still deleted the entities, so they weren't properly claimed.
for (AZ::Entity* entity : claimedEntities)
{
delete entity;
}
}
TEST_F(SpawnableEntitiesManagerTest, ClaimEntities_DeleteTicketBeforeCall_NoCrash)
{
auto callback = [](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView) {};
@@ -383,7 +383,7 @@ namespace AzNetworking
if (compErr != CompressorError::Ok)
{
AZLOG_ERROR("Decompress failed with error %d this will lead to data read errors!", compErr);
AZLOG_ERROR("Decompress failed with error %d this will lead to data read errors!", aznumeric_cast<int32_t>(compErr));
return false;
}
@@ -35,7 +35,7 @@ namespace AzNetworking
bool TcpConnectionSet::DeleteConnection(SocketFd socketFd)
{
AZLOG(TcpConnectionSet, "Deleting Tcp connection by socketId (%u)", socketFd);
AZLOG(TcpConnectionSet, "Deleting Tcp connection by socketId (%u)", aznumeric_cast<int32_t>(socketFd));
TcpConnection* connection = GetConnection(socketFd);
if (connection == nullptr)
{
@@ -446,7 +446,7 @@ namespace AzNetworking
if (compErr != CompressorError::Ok)
{
AZLOG_ERROR("Decompress failed with error %d this will lead to data read errors!", compErr);
AZLOG_ERROR("Decompress failed with error %d this will lead to data read errors!", aznumeric_cast<int32_t>(compErr));
return false;
}
+2 -2
View File
@@ -6,8 +6,8 @@
#
#
ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER})
set(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common)
ly_add_target(
NAME AzNetworking STATIC
@@ -12,6 +12,8 @@
#include <QLabel>
#include <QPainter>
#include <QStyle>
#include <QTextCursor>
#include <QTextDocument>
namespace AzQtComponents
{
@@ -35,6 +37,7 @@ namespace AzQtComponents
m_text = text;
m_metricsLabel->setText(m_text);
m_elidedText.clear();
elide();
updateGeometry();
@@ -65,7 +68,62 @@ namespace AzQtComponents
void ElidingLabel::elide()
{
ensurePolished();
m_elidedText = fontMetrics().elidedText(m_text, m_elideMode, TextRect().width());
if (Qt::mightBeRichText(m_text))
{
// If RichText tags are elided using fontMetrics.elidedText(), they will break.
// A TextDocument is used to produce elided text that takes this into account.
const QString ellipsis("...");
const int maxLineWidth = TextRect().width();
QTextDocument doc;
doc.setHtml(m_text);
doc.setDefaultFont(font());
doc.setDocumentMargin(0.0);
// Turn off wrapping so the document uses a single line.
QTextOption option = doc.defaultTextOption();
option.setWrapMode(QTextOption::WrapMode::NoWrap);
doc.setDefaultTextOption(option);
doc.adjustSize();
if (doc.size().width() <= maxLineWidth)
{
m_elidedText = m_text;
}
else
{
QTextCursor textCursor(&doc);
textCursor.movePosition(QTextCursor::End);
int ellipsisWidth = 0;
// At the moment only ElideRight and ElideNone are ever used. This will need expanding if other elision modes are used.
if (m_elideMode == Qt::ElideRight)
{
ellipsisWidth = fontMetrics().horizontalAdvance(ellipsis);
}
// Move the cursor back until the text fits or the start of the text is reached.
while (doc.size().width() + ellipsisWidth > maxLineWidth && !textCursor.atStart())
{
textCursor.deletePreviousChar();
doc.adjustSize();
}
if (m_elideMode == Qt::ElideRight)
{
textCursor.insertText(ellipsis);
}
m_elidedText = doc.toHtml();
}
}
else
{
m_elidedText = fontMetrics().elidedText(m_text, m_elideMode, TextRect().width());
}
QLabel::setText(m_elidedText);
if (m_elidedText != m_text)
@@ -870,8 +870,7 @@ void SliderDouble::setCurveMidpoint(double midpoint)
QString SliderDouble::hoverValueText(int sliderValue) const
{
// maybe format this, max number of digits?
QString valueText = locale().toString(calculateRealSliderValue(sliderValue), 'f', m_decimals);
QString valueText = toString(calculateRealSliderValue(sliderValue), m_decimals, locale(), false, true);
return QStringLiteral("%1").arg(valueText);
}
@@ -14,6 +14,7 @@
#include <QHBoxLayout>
#include <QSignalBlocker>
#include <QTimer>
namespace AzQtComponents
{
@@ -254,11 +255,12 @@ SliderDoubleCombo::~SliderDoubleCombo()
{
}
bool m_fromSlider{ false };
void SliderDoubleCombo::setValueSlider(double value)
{
const bool doEmit = m_value != value;
m_value = value;
updateSpinBox();
updateSlider();
@@ -267,6 +269,8 @@ void SliderDoubleCombo::setValueSlider(double value)
// We don't want to update the slider from setValue as this
// causes rounding errors in the tooltip hint.
m_fromSlider = true;
QTimer::singleShot( 10, []() { m_fromSlider = false; });
Q_EMIT valueChanged();
}
}
@@ -286,10 +290,6 @@ void SliderDoubleCombo::setValue(double value)
Q_EMIT valueChanged();
}
}
else
{
m_fromSlider = false;
}
}
SliderDouble* SliderDoubleCombo::slider() const
@@ -237,6 +237,5 @@ namespace AzQtComponents
double m_softMinimum = 0.0;
double m_softMaximum = 100.0;
double m_value = 0.0;
bool m_fromSlider{ false };
};
} // namespace AzQtComponents
@@ -1460,7 +1460,7 @@ QString DoubleSpinBox::stringValue(double value, bool truncated) const
numDecimals = 0;
}
return toString(value, numDecimals, locale(), isGroupSeparatorShown());
return toString(value, numDecimals, locale(), isGroupSeparatorShown(), true);
}
void DoubleSpinBox::updateToolTip(double value)
@@ -9,6 +9,8 @@
#include <AzTest/AzTest.h>
#include <AzCore/Math/Color.h>
#include <AzQtComponents/Components/Widgets/ColorPicker/Palette.h>
#include <AzQtComponents/Utilities/Conversions.h>
#include <QLocale>
// Environments subclass from AZ::Test::ITestEnvironment
class AzQtComponentsTestEnvironment : public AZ::Test::ITestEnvironment
@@ -34,3 +36,17 @@ protected:
};
AZ_UNIT_TEST_HOOK(new AzQtComponentsTestEnvironment);
TEST(AzQtComponents, ToStringReturnsTruncatedString)
{
double testVal = 1.2399999;
QString result = AzQtComponents::toString(testVal, 3, QLocale(), false, false);
EXPECT_TRUE(result == "1.239");
}
TEST(AzQtComponents, ToStringReturnsRoundedString)
{
double testVal = 1.2399999;
QString result = AzQtComponents::toString(testVal, 3, QLocale(), false, true);
EXPECT_TRUE(result == "1.24");
}
@@ -39,15 +39,23 @@ namespace AzQtComponents
return AZ::Color(static_cast<float>(rgb.redF()), static_cast<float>(rgb.greenF()), static_cast<float>(rgb.blueF()), static_cast<float>(rgb.alphaF()));
}
QString toString(double value, int numDecimals, const QLocale& locale, bool showGroupSeparator)
QString toString(double value, int numDecimals, const QLocale& locale, bool showGroupSeparator, bool round)
{
const QChar decimalPoint = locale.decimalPoint();
const QChar zeroDigit = locale.zeroDigit();
const int numToStringDecimals = AZStd::max(numDecimals, 20);
QString retValue;
// We want to truncate, not round. toString will round, so we add extra decimal places to the formatting
// so we can remove the last values
QString retValue = locale.toString(value, 'f', (numDecimals > 0) ? numToStringDecimals : 0);
// If we want to truncate, not round, we add extra decimal places to the formatting
// so we can remove the last values otherwise we allow rounding
if (round)
{
retValue = locale.toString(value, 'f', (numDecimals > 0) ? numDecimals : 0);
}
else
{
retValue = locale.toString(value, 'f', (numDecimals > 0) ? numToStringDecimals : 0);
}
// Handle special cases when we have decimals in our value
if (numDecimals > 0)
@@ -22,7 +22,7 @@ namespace AzQtComponents
AZ_QT_COMPONENTS_API AZ::Color fromQColor(const QColor& color);
AZ_QT_COMPONENTS_API QString toString(double value, int numDecimals, const QLocale& locale, bool showGroupSeparator = false);
AZ_QT_COMPONENTS_API QString toString(double value, int numDecimals, const QLocale& locale, bool showGroupSeparator = false, bool round = false);
// Maintained for backwards compile compatibility
inline QColor ToQColor(const AZ::Color& color)

Some files were not shown because too many files have changed in this diff Show More