Merge branch 'development' into memory/overrideshim_removal
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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,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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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<*,*,*>">
|
||||
<DisplayString>{m_element}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="AZStd::compressed_pair_element<*,*,1>">
|
||||
<DisplayString>{$T1} is empty</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="AZStd::reverse_iterator<*>" Priority="Medium">
|
||||
<DisplayString>reverse_iterator base() {m_current}</DisplayString>
|
||||
<Expand>
|
||||
@@ -388,35 +395,41 @@
|
||||
|
||||
<!-- -->
|
||||
|
||||
<Type Name="AZStd::basic_string<char,*>">
|
||||
<DisplayString Condition="m_capacity < SSO_BUF_SIZE">{m_buffer,s}</DisplayString>
|
||||
<DisplayString Condition="m_capacity >= SSO_BUF_SIZE">{m_data,s}</DisplayString>
|
||||
<StringView Condition="m_capacity < SSO_BUF_SIZE">m_buffer,s</StringView>
|
||||
<StringView Condition="m_capacity >= SSO_BUF_SIZE">m_data,s</StringView>
|
||||
<Type Name="AZStd::basic_string<char,*,*>">
|
||||
<DisplayString Condition="((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_buffer,s}</DisplayString>
|
||||
<DisplayString Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_data,s}</DisplayString>
|
||||
<StringView Condition="((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_buffer,s</StringView>
|
||||
<StringView Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)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<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">(size_t)((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_size</Item>
|
||||
<Item Name="[size]" Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_size</Item>
|
||||
<Item Name="[capacity]" Condition="((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.Capacity</Item>
|
||||
<Item Name="[capacity]" Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_capacity</Item>
|
||||
<ArrayItems>
|
||||
<Size>m_size</Size>
|
||||
<ValuePointer Condition="m_capacity < SSO_BUF_SIZE">m_buffer</ValuePointer>
|
||||
<ValuePointer Condition="m_capacity >= SSO_BUF_SIZE">m_data</ValuePointer>
|
||||
<Size Condition="((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_size,u</Size>
|
||||
<Size Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_size</Size>
|
||||
<ValuePointer Condition="((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_buffer</ValuePointer>
|
||||
<ValuePointer Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<char,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_data</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="AZStd::basic_string<wchar_t,*>">
|
||||
<AlternativeType Name="AZStd::basic_string<unsigned short,*>" />
|
||||
<DisplayString Condition="m_capacity < SSO_BUF_SIZE">{m_buffer,su}</DisplayString>
|
||||
<DisplayString Condition="m_capacity >= SSO_BUF_SIZE">{m_data,su}</DisplayString>
|
||||
<StringView Condition="m_capacity < SSO_BUF_SIZE">m_buffer,su</StringView>
|
||||
<StringView Condition="m_capacity >= SSO_BUF_SIZE">m_data,su</StringView>
|
||||
<DisplayString Condition="((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_buffer,su}</DisplayString>
|
||||
<DisplayString Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">{((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_data,su}</DisplayString>
|
||||
<StringView Condition="((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_buffer,su</StringView>
|
||||
<StringView Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)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<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">(size_t)((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_size</Item>
|
||||
<Item Name="[size]" Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_size</Item>
|
||||
<Item Name="[capacity]" Condition="((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.Capacity</Item>
|
||||
<Item Name="[capacity]" Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_capacity</Item>
|
||||
<ArrayItems>
|
||||
<Size>m_size</Size>
|
||||
<ValuePointer Condition="m_capacity < SSO_BUF_SIZE">m_buffer</ValuePointer>
|
||||
<ValuePointer Condition="m_capacity >= SSO_BUF_SIZE">m_data</ValuePointer>
|
||||
<Size Condition="((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_size,u</Size>
|
||||
<Size Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_allocatedData.m_size</Size>
|
||||
<ValuePointer Condition="((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_buffer</ValuePointer>
|
||||
<ValuePointer Condition="!((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)m_storage).m_element.m_shortData.m_ssoActive">((AZStd::compressed_pair_element<AZStd::basic_string<wchar_t,$T1,$T2>::Storage,0,0>&)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
|
||||
@@ -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())");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user