Merge branch 'development' into memory/overrideshim_removal

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2022-01-20 13:43:12 -08:00
1545 changed files with 24982 additions and 22444 deletions
@@ -558,10 +558,6 @@ namespace AZ
m_entityActivatedEvent.DisconnectAllHandlers();
m_entityDeactivatedEvent.DisconnectAllHandlers();
#if !defined(_RELEASE)
m_budgetTracker.Reset();
#endif
DestroyAllocator();
}
@@ -751,6 +747,12 @@ namespace AZ
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearNotifiers();
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearMergeEvents();
#if !defined(_RELEASE)
// the budget tracker must be cleaned up prior to module unloading to ensure
// budgets initialized cross boundary are freed properly
m_budgetTracker.Reset();
#endif
// Uninit and unload any dynamic modules.
m_moduleManager->UnloadModules();
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsUnloaded", R"({})");
@@ -361,7 +361,7 @@ namespace AZ::Dom::Json
bool RapidJsonReadHandler::String(const char* str, rapidjson::SizeType length, bool copy)
{
const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary;
const Lifetime lifetime = !copy ? m_stringLifetime : Lifetime::Temporary;
return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime));
}
@@ -373,11 +373,7 @@ namespace AZ::Dom::Json
bool RapidJsonReadHandler::Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy)
{
AZStd::string_view key = AZStd::string_view(str, length);
if (!m_visitor->SupportsRawKeys())
{
m_visitor->Key(AZ::Name(key));
}
const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary;
const Lifetime lifetime = !copy ? m_stringLifetime : Lifetime::Temporary;
return CheckResult(m_visitor->RawKey(key, lifetime));
}
+161 -1
View File
@@ -21,4 +21,164 @@ namespace AZ::Dom::Utils
{
return backend.ReadFromBufferInPlace(string.data(), string.size(), visitor);
}
}
AZ::Outcome<Value, AZStd::string> WriteToValue(const Backend::WriteCallback& writeCallback)
{
Value value;
AZStd::unique_ptr<Visitor> writer = value.GetWriteHandler();
Visitor::Result result = writeCallback(*writer);
if (!result.IsSuccess())
{
return AZ::Failure(result.GetError().FormatVisitorErrorMessage());
}
return AZ::Success(AZStd::move(value));
}
bool DeepCompareIsEqual(const Value& lhs, const Value& rhs)
{
const Value::ValueType& lhsValue = lhs.GetInternalValue();
const Value::ValueType& rhsValue = rhs.GetInternalValue();
if (lhs.IsString() && rhs.IsString())
{
// If we both hold the same ref counted string we don't need to do a full comparison
if (AZStd::holds_alternative<Value::SharedStringType>(lhsValue) && lhsValue == rhsValue)
{
return true;
}
return lhs.GetString() == rhs.GetString();
}
return AZStd::visit(
[&](auto&& ourValue) -> bool
{
using Alternative = AZStd::decay_t<decltype(ourValue)>;
if constexpr (AZStd::is_same_v<Alternative, ObjectPtr>)
{
if (!rhs.IsObject())
{
return false;
}
auto&& theirValue = AZStd::get<AZStd::remove_cvref_t<decltype(ourValue)>>(rhsValue);
if (ourValue == theirValue)
{
return true;
}
const Object::ContainerType& ourValues = ourValue->GetValues();
const Object::ContainerType& theirValues = theirValue->GetValues();
if (ourValues.size() != theirValues.size())
{
return false;
}
for (size_t i = 0; i < ourValues.size(); ++i)
{
const Object::EntryType& lhsChild = ourValues[i];
auto rhsIt = rhs.FindMember(lhsChild.first);
if (rhsIt == rhs.MemberEnd() || !DeepCompareIsEqual(lhsChild.second, rhsIt->second))
{
return false;
}
}
return true;
}
else if constexpr (AZStd::is_same_v<Alternative, ArrayPtr>)
{
if (!rhs.IsArray())
{
return false;
}
auto&& theirValue = AZStd::get<AZStd::remove_cvref_t<decltype(ourValue)>>(rhsValue);
if (ourValue == theirValue)
{
return true;
}
const Array::ContainerType& ourValues = ourValue->GetValues();
const Array::ContainerType& theirValues = theirValue->GetValues();
if (ourValues.size() != theirValues.size())
{
return false;
}
for (size_t i = 0; i < ourValues.size(); ++i)
{
const Value& lhsChild = ourValues[i];
const Value& rhsChild = theirValues[i];
if (!DeepCompareIsEqual(lhsChild, rhsChild))
{
return false;
}
}
return true;
}
else if constexpr (AZStd::is_same_v<Alternative, NodePtr>)
{
if (!rhs.IsNode())
{
return false;
}
auto&& theirValue = AZStd::get<AZStd::remove_cvref_t<decltype(ourValue)>>(rhsValue);
if (ourValue == theirValue)
{
return true;
}
const Node& ourNode = *ourValue;
const Node& theirNode = *theirValue;
const Object::ContainerType& ourProperties = ourNode.GetProperties();
const Object::ContainerType& theirProperties = theirNode.GetProperties();
if (ourProperties.size() != theirProperties.size())
{
return false;
}
for (size_t i = 0; i < ourProperties.size(); ++i)
{
const Object::EntryType& lhsChild = ourProperties[i];
auto rhsIt = rhs.FindMember(lhsChild.first);
if (rhsIt == rhs.MemberEnd() || !DeepCompareIsEqual(lhsChild.second, rhsIt->second))
{
return false;
}
}
const Array::ContainerType& ourChildren = ourNode.GetChildren();
const Array::ContainerType& theirChildren = theirNode.GetChildren();
for (size_t i = 0; i < ourChildren.size(); ++i)
{
const Value& lhsChild = ourChildren[i];
const Value& rhsChild = theirChildren[i];
if (!DeepCompareIsEqual(lhsChild, rhsChild))
{
return false;
}
}
return true;
}
else
{
return lhs == rhs;
}
},
lhsValue);
}
Value DeepCopy(const Value& value, bool copyStrings)
{
Value copiedValue;
AZStd::unique_ptr<Visitor> writer = copiedValue.GetWriteHandler();
value.Accept(*writer, copyStrings);
return copiedValue;
}
} // namespace AZ::Dom::Utils
@@ -9,9 +9,15 @@
#pragma once
#include <AzCore/DOM/DomBackend.h>
#include <AzCore/DOM/DomValue.h>
namespace AZ::Dom::Utils
{
Visitor::Result ReadFromString(Backend& backend, AZStd::string_view string, AZ::Dom::Lifetime lifetime, Visitor& visitor);
Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor);
AZ::Outcome<Value, AZStd::string> WriteToValue(const Backend::WriteCallback& writeCallback);
bool DeepCompareIsEqual(const Value& lhs, const Value& rhs);
Value DeepCopy(const Value& value, bool copyStrings = true);
} // namespace AZ::Dom::Utils
File diff suppressed because it is too large Load Diff
+402
View File
@@ -0,0 +1,402 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/DOM/DomBackend.h>
#include <AzCore/DOM/DomVisitor.h>
#include <AzCore/Memory/HphaSchema.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/std/containers/stack.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
namespace AZ::Dom
{
using KeyType = AZ::Name;
//! The type of underlying value stored in a value. \see Value
enum class Type
{
Null,
Bool,
Object,
Array,
String,
Int64,
Uint64,
Double,
Node,
Opaque,
};
//! The allocator used by Value.
//! Value heap allocates shared_ptrs for its container storage (Array / Object / Node) alongside
class ValueAllocator final : public SimpleSchemaAllocator<AZ::HphaSchema, AZ::HphaSchema::Descriptor, false, false>
{
public:
AZ_TYPE_INFO(ValueAllocator, "{5BC8B389-72C7-459E-B502-12E74D61869F}");
using Base = SimpleSchemaAllocator<AZ::HphaSchema, AZ::HphaSchema::Descriptor, false, false>;
ValueAllocator()
: Base("DomValueAllocator", "Allocator for AZ::Dom::Value")
{
DisableOverriding();
}
};
using StdValueAllocator = AZStdAlloc<ValueAllocator>;
class Value;
//! Internal storage for a Value array: an ordered list of Values.
class Array
{
public:
using ContainerType = AZStd::vector<Value, StdValueAllocator>;
using Iterator = ContainerType::iterator;
using ConstIterator = ContainerType::const_iterator;
static constexpr const size_t ReserveIncrement = 4;
static_assert((ReserveIncrement & (ReserveIncrement - 1)) == 0, "ReserveIncremenet must be a power of 2");
const ContainerType& GetValues() const;
private:
ContainerType m_values;
friend class Value;
};
using ArrayPtr = AZStd::shared_ptr<Array>;
using ConstArrayPtr = AZStd::shared_ptr<const Array>;
//! Internal storage for a Value object: an ordered list of Name / Value pairs.
class Object
{
public:
using EntryType = AZStd::pair<KeyType, Value>;
using ContainerType = AZStd::vector<EntryType, StdValueAllocator>;
using Iterator = ContainerType::iterator;
using ConstIterator = ContainerType::const_iterator;
static constexpr const size_t ReserveIncrement = 8;
static_assert((ReserveIncrement & (ReserveIncrement - 1)) == 0, "ReserveIncremenet must be a power of 2");
const ContainerType& GetValues() const;
private:
ContainerType m_values;
friend class Value;
};
using ObjectPtr = AZStd::shared_ptr<Object>;
using ConstObjectPtr = AZStd::shared_ptr<const Object>;
//! Storage for a Value node: a named Value with both properties and children.
//! Properties are stored as an ordered list of Name / Value pairs.
//! Children are stored as an oredered list of Values.
class Node
{
public:
Node() = default;
Node(const Node&) = default;
Node(Node&&) = default;
explicit Node(AZ::Name name);
Node& operator=(const Node&) = default;
Node& operator=(Node&&) = default;
AZ::Name GetName() const;
void SetName(AZ::Name name);
Object::ContainerType& GetProperties();
const Object::ContainerType& GetProperties() const;
Array::ContainerType& GetChildren();
const Array::ContainerType& GetChildren() const;
private:
AZ::Name m_name;
Object::ContainerType m_properties;
Array::ContainerType m_children;
friend class Value;
};
using NodePtr = AZStd::shared_ptr<Node>;
using ConstNodePtr = AZStd::shared_ptr<Node>;
//! Value is a typed union of Dom types that can represent the types provdied by AZ::Dom::Visitor.
//! Value can be one of the following types:
//! - Null: a type with no value, this is the default type for Value
//! - Bool: a true or false boolean value
//! - Object: a container with an ordered list of Name/Value pairs, analagous to a JSON object
//! - Array: a container with an ordered list of Values, analagous to a JSON array
//! - String: a UTF-8 string
//! - Int64: a signed, 64-bit integer
//! - Uint64: an unsigned, 64-bit integer
//! - Double: a double precision floating point value
//! - Node: a container with a Name, an ordered list of Name/Values pairs (attributes), and an ordered list of Values (children),
//! analagous to an XML node
//! - Opaque: an arbitrary value stored in an AZStd::any. This is a non-serializable representation of an entry used only for in-memory
//! options. This is intended to be used as an intermediate value over the course of DOM transformation and as a proxy to pass through
//! types of which the DOM has no knowledge to other systems.
//! \note Value is a copy-on-write data structure and may be cheaply returned by value. Heap allocated data larger than the size of the
//! value itself (objects, arrays, and nodes) are copied by new Values only when their contents change, so care should be taken in
//! performance critical code to avoid mutation operations such as operator[] to avoid copies. It is recommended that an immutable Value
//! be explicitly be stored as a `const Value` to avoid accidental detach and copy operations.
class Value final
{
public:
// Determine the short string buffer size based on the size of our largest internal type (string_view)
// minus the size of the short string size field.
static constexpr const size_t ShortStringSize = sizeof(AZStd::string_view) - 2;
using ShortStringType = AZStd::fixed_string<ShortStringSize>;
using SharedStringContainer = AZStd::vector<char>;
using SharedStringType = AZStd::shared_ptr<const SharedStringContainer>;
using OpaqueStorageType = AZStd::shared_ptr<AZStd::any>;
//! The internal storage type for Value.
//! These types do not correspond one-to-one with the Value's external Type as there may be multiple storage classes
//! for the same type in some instances, such as string storage.
using ValueType = AZStd::variant<
// Null
AZStd::monostate,
// Int64
int64_t,
// Uint64
uint64_t,
// Double
double,
// Bool
bool,
// String
AZStd::string_view,
SharedStringType,
ShortStringType,
// Object
ObjectPtr,
// Array
ArrayPtr,
// Node
NodePtr,
// Opaque
OpaqueStorageType>;
// Constructors...
Value() = default;
Value(const Value&);
Value(Value&&) noexcept;
Value(AZStd::string_view stringView, bool copy);
explicit Value(const ValueType&);
explicit Value(ValueType&&);
explicit Value(SharedStringType sharedString);
explicit Value(int8_t value);
explicit Value(uint8_t value);
explicit Value(int16_t value);
explicit Value(uint16_t value);
explicit Value(int32_t value);
explicit Value(uint32_t value);
explicit Value(int64_t value);
explicit Value(uint64_t value);
explicit Value(float value);
explicit Value(double value);
explicit Value(bool value);
explicit Value(Type type);
// Disable accidental calls to Value(bool) with pointer types
template<class T>
explicit Value(T*) = delete;
static Value FromOpaqueValue(const AZStd::any& value);
// Equality / comparison / swap...
Value& operator=(const Value&);
Value& operator=(Value&&) noexcept;
//! Assignment operator to allow forwarding types constructible via Value(T) to be assigned
template<class T>
auto operator=(T&& arg)
-> AZStd::enable_if_t<!AZStd::is_same_v<AZStd::remove_cvref_t<T>, Value> && AZStd::is_constructible_v<Value, T>, Value&>
{
return operator=(Value(AZStd::forward<T>(arg)));
}
bool operator==(const Value& rhs) const;
bool operator!=(const Value& rhs) const;
void Swap(Value& other) noexcept;
// Type info...
Type GetType() const;
bool IsNull() const;
bool IsFalse() const;
bool IsTrue() const;
bool IsBool() const;
bool IsNode() const;
bool IsObject() const;
bool IsArray() const;
bool IsOpaqueValue() const;
bool IsNumber() const;
bool IsInt() const;
bool IsUint() const;
bool IsDouble() const;
bool IsString() const;
// Object API (also used by Node)...
Value& SetObject();
size_t MemberCount() const;
size_t MemberCapacity() const;
bool ObjectEmpty() const;
Value& operator[](KeyType name);
const Value& operator[](KeyType name) const;
Value& operator[](AZStd::string_view name);
const Value& operator[](AZStd::string_view name) const;
Object::ConstIterator MemberBegin() const;
Object::ConstIterator MemberEnd() const;
Object::Iterator MutableMemberBegin();
Object::Iterator MutableMemberEnd();
Object::Iterator FindMutableMember(KeyType name);
Object::Iterator FindMutableMember(AZStd::string_view name);
Object::ConstIterator FindMember(KeyType name) const;
Object::ConstIterator FindMember(AZStd::string_view name) const;
Value& MemberReserve(size_t newCapacity);
bool HasMember(KeyType name) const;
bool HasMember(AZStd::string_view name) const;
Value& AddMember(KeyType name, const Value& value);
Value& AddMember(AZStd::string_view name, const Value& value);
Value& AddMember(KeyType name, Value&& value);
Value& AddMember(AZStd::string_view name, Value&& value);
void RemoveAllMembers();
void RemoveMember(KeyType name);
void RemoveMember(AZStd::string_view name);
Object::Iterator RemoveMember(Object::Iterator pos);
Object::Iterator EraseMember(Object::Iterator pos);
Object::Iterator EraseMember(Object::Iterator first, Object::Iterator last);
Object::Iterator EraseMember(KeyType name);
Object::Iterator EraseMember(AZStd::string_view name);
Object::ContainerType& GetMutableObject();
const Object::ContainerType& GetObject() const;
// Array API (also used by Node)...
Value& SetArray();
size_t ArraySize() const;
size_t ArrayCapacity() const;
bool IsArrayEmpty() const;
void ClearArray();
Value& operator[](size_t index);
const Value& operator[](size_t index) const;
Value& MutableArrayAt(size_t index);
const Value& ArrayAt(size_t index) const;
Array::ConstIterator ArrayBegin() const;
Array::ConstIterator ArrayEnd() const;
Array::Iterator MutableArrayBegin();
Array::Iterator MutableArrayEnd();
Value& ArrayReserve(size_t newCapacity);
Value& ArrayPushBack(Value value);
Value& ArrayPopBack();
Array::Iterator ArrayErase(Array::Iterator pos);
Array::Iterator ArrayErase(Array::Iterator first, Array::Iterator last);
Array::ContainerType& GetMutableArray();
const Array::ContainerType& GetArray() const;
// Node API (supports both object + array API, plus a dedicated NodeName)...
void SetNode(AZ::Name name);
void SetNode(AZStd::string_view name);
AZ::Name GetNodeName() const;
void SetNodeName(AZ::Name name);
void SetNodeName(AZStd::string_view name);
//! Convenience method, sets the first non-node element of a Node.
void SetNodeValue(Value value);
//! Convenience method, gets the first non-node element of a Node.
Value GetNodeValue() const;
Node& GetMutableNode();
const Node& GetNode() const;
// int API...
int64_t GetInt64() const;
void SetInt64(int64_t);
// uint API...
uint64_t GetUint64() const;
void SetUint64(uint64_t);
// bool API...
bool GetBool() const;
void SetBool(bool);
// double API...
double GetDouble() const;
void SetDouble(double);
// String API...
AZStd::string_view GetString() const;
size_t GetStringLength() const;
void SetString(AZStd::string_view);
void SetString(SharedStringType sharedString);
void CopyFromString(AZStd::string_view);
// Opaque type API...
const AZStd::any& GetOpaqueValue() const;
//! This sets this Value to represent a value of an type that the DOM has
//! no formal knowledge of. Where possible, it should be preferred to
//! serialize an opaque type into a DOM value instead, as serializers
//! and other systems will have no means of dealing with fully arbitrary
//! values.
void SetOpaqueValue(AZStd::any);
// Null API...
void SetNull();
// Visitor API...
Visitor::Result Accept(Visitor& visitor, bool copyStrings) const;
AZStd::unique_ptr<Visitor> GetWriteHandler();
//! Gets the internal value of this Value. Note that this value's types may not correspond one-to-one with the Type enumeration,
//! as internally the same type might have different storage mechanisms. Where possible, prefer using the typed API.
const ValueType& GetInternalValue() const;
private:
const Node& GetNodeInternal() const;
Node& GetNodeInternal();
const Object::ContainerType& GetObjectInternal() const;
Object::ContainerType& GetObjectInternal();
const Array::ContainerType& GetArrayInternal() const;
Array::ContainerType& GetArrayInternal();
explicit Value(AZStd::any opaqueValue);
static_assert(
sizeof(ValueType) == sizeof(ShortStringType) + sizeof(size_t), "ValueType should have no members larger than ShortStringType");
ValueType m_value;
};
} // namespace AZ::Dom
@@ -0,0 +1,262 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/DOM/DomValueWriter.h>
namespace AZ::Dom
{
ValueWriter::ValueWriter(Value& outputValue)
: m_result(outputValue)
{
}
VisitorFlags ValueWriter::GetVisitorFlags() const
{
return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes;
}
ValueWriter::ValueInfo::ValueInfo(Value& container)
: m_container(container)
{
}
Visitor::Result ValueWriter::Null()
{
CurrentValue().SetNull();
return FinishWrite();
}
Visitor::Result ValueWriter::Bool(bool value)
{
CurrentValue().SetBool(value);
return FinishWrite();
}
Visitor::Result ValueWriter::Int64(AZ::s64 value)
{
CurrentValue().SetInt64(value);
return FinishWrite();
}
Visitor::Result ValueWriter::Uint64(AZ::u64 value)
{
CurrentValue().SetUint64(value);
return FinishWrite();
}
Visitor::Result ValueWriter::Double(double value)
{
CurrentValue().SetDouble(value);
return FinishWrite();
}
Visitor::Result ValueWriter::String(AZStd::string_view value, Lifetime lifetime)
{
if (lifetime == Lifetime::Persistent)
{
CurrentValue().SetString(value);
}
else
{
CurrentValue().CopyFromString(value);
}
return FinishWrite();
}
Visitor::Result ValueWriter::RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, [[maybe_unused]] Lifetime lifetime)
{
CurrentValue().SetString(AZStd::move(value));
return FinishWrite();
}
Visitor::Result ValueWriter::StartObject()
{
CurrentValue().SetObject();
m_entryStack.emplace(CurrentValue());
return VisitorSuccess();
}
template <class T, class A>
void MoveVectorMemory(AZStd::vector<T, A>& dest, AZStd::vector<T, A>& source)
{
dest.resize_no_construct(source.size());
const size_t size = sizeof(T) * source.size();
memcpy(dest.data(), source.data(), size);
memset(source.data(), 0, size);
source.resize(0);
}
Visitor::Result ValueWriter::EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount)
{
const char* endMethodName;
switch (containerType)
{
case Type::Object:
endMethodName = "EndObject";
break;
case Type::Array:
endMethodName = "EndArray";
break;
case Type::Node:
endMethodName = "EndNode";
break;
default:
AZ_Assert(false, "Invalid container type specified");
return VisitorFailure(VisitorErrorCode::InternalError, "AZ::Dom::ValueWriter: EndContainer called with invalid container type");
}
if (m_entryStack.empty())
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format("AZ::Dom::ValueWriter: %s called without a matching call", endMethodName));
}
const ValueInfo& topEntry = m_entryStack.top();
Value& container = topEntry.m_container;
ValueBuffer& buffer = GetValueBuffer();
if (container.GetType() != containerType)
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format("AZ::Dom::ValueWriter: %s called from within a different container type", endMethodName));
}
if (aznumeric_cast<AZ::u64>(buffer.m_attributes.size()) != attributeCount)
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format(
"AZ::Dom::ValueWriter: %s expected %llu attributes but received %zu attributes instead", endMethodName, attributeCount,
buffer.m_attributes.size()));
}
if (aznumeric_cast<AZ::u64>(buffer.m_elements.size()) != elementCount)
{
return VisitorFailure(
VisitorErrorCode::InternalError,
AZStd::string::format(
"AZ::Dom::ValueWriter: %s expected %llu elements but received %zu elements instead", endMethodName, elementCount,
buffer.m_elements.size()));
}
if (buffer.m_attributes.size() > 0)
{
MoveVectorMemory(container.GetMutableObject(), buffer.m_attributes);
}
if(buffer.m_elements.size() > 0)
{
MoveVectorMemory(container.GetMutableArray(), buffer.m_elements);
}
m_entryStack.pop();
return FinishWrite();
}
ValueWriter::ValueBuffer& ValueWriter::GetValueBuffer()
{
if (m_entryStack.size() <= m_valueBuffers.size())
{
return m_valueBuffers[m_entryStack.size() - 1];
}
m_valueBuffers.resize(m_entryStack.size());
return m_valueBuffers[m_entryStack.size() - 1];
}
Visitor::Result ValueWriter::EndObject(AZ::u64 attributeCount)
{
return EndContainer(Type::Object, attributeCount, 0);
}
Visitor::Result ValueWriter::Key(AZ::Name key)
{
AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object");
AZ_Assert(!m_entryStack.top().m_container.IsArray(), "Attempted to push a key to an array");
m_entryStack.top().m_key = AZStd::move(key);
return VisitorSuccess();
}
Visitor::Result ValueWriter::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime)
{
return Key(AZ::Name(key));
}
Visitor::Result ValueWriter::StartArray()
{
CurrentValue().SetArray();
m_entryStack.emplace(CurrentValue());
return VisitorSuccess();
}
Visitor::Result ValueWriter::EndArray(AZ::u64 elementCount)
{
return EndContainer(Type::Array, 0, elementCount);
}
Visitor::Result ValueWriter::StartNode(AZ::Name name)
{
CurrentValue().SetNode(name);
m_entryStack.emplace(CurrentValue());
return VisitorSuccess();
}
Visitor::Result ValueWriter::RawStartNode(AZStd::string_view name, [[maybe_unused]] Lifetime lifetime)
{
return StartNode(AZ::Name(name));
}
Visitor::Result ValueWriter::EndNode(AZ::u64 attributeCount, AZ::u64 elementCount)
{
return EndContainer(Type::Node, attributeCount, elementCount);
}
Visitor::Result ValueWriter::OpaqueValue(OpaqueType& value)
{
CurrentValue().SetOpaqueValue(value);
return FinishWrite();
}
Visitor::Result ValueWriter::FinishWrite()
{
if (m_entryStack.empty())
{
return VisitorSuccess();
}
Value value;
m_entryStack.top().m_value.Swap(value);
ValueInfo& newEntry = m_entryStack.top();
if (!newEntry.m_key.IsEmpty())
{
GetValueBuffer().m_attributes.emplace_back(AZStd::move(newEntry.m_key), AZStd::move(value));
newEntry.m_key = AZ::Name();
}
else
{
GetValueBuffer().m_elements.emplace_back(AZStd::move(value));
}
return VisitorSuccess();
}
Value& ValueWriter::CurrentValue()
{
if (m_entryStack.empty())
{
return m_result;
}
return m_entryStack.top().m_value;
}
} // namespace AZ::Dom
@@ -0,0 +1,72 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/DOM/DomValue.h>
#include <AzCore/std/containers/stack.h>
namespace AZ::Dom
{
//! Visitor that writes to a Value.
//! Supports all Visitor operations.
class ValueWriter : public Visitor
{
public:
ValueWriter(Value& outputValue);
VisitorFlags GetVisitorFlags() const override;
Result Null() override;
Result Bool(bool value) override;
Result Int64(AZ::s64 value) override;
Result Uint64(AZ::u64 value) override;
Result Double(double value) override;
Result String(AZStd::string_view value, Lifetime lifetime) override;
Result RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, Lifetime lifetime) override;
Result StartObject() override;
Result EndObject(AZ::u64 attributeCount) override;
Result Key(AZ::Name key) override;
Result RawKey(AZStd::string_view key, Lifetime lifetime) override;
Result StartArray() override;
Result EndArray(AZ::u64 elementCount) override;
Result StartNode(AZ::Name name) override;
Result RawStartNode(AZStd::string_view name, Lifetime lifetime) override;
Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount) override;
Result OpaqueValue(OpaqueType& value) override;
private:
Result FinishWrite();
Value& CurrentValue();
Visitor::Result EndContainer(Type containerType, AZ::u64 attributeCount, AZ::u64 elementCount);
struct ValueInfo
{
ValueInfo(Value& container);
KeyType m_key;
Value m_value;
Value& m_container;
};
struct ValueBuffer
{
Array::ContainerType m_elements;
Object::ContainerType m_attributes;
};
ValueBuffer& GetValueBuffer();
Value& m_result;
// Stores info about the current value being processed
AZStd::stack<ValueInfo, AZStd::deque<ValueInfo, AZStdAlloc<ValueAllocator>>> m_entryStack;
// Provides temporary storage for elements and attributes to prevent extra heap allocations
// These buffers persist to be reused even as the entry stack changes
AZStd::vector<ValueBuffer, AZStdAlloc<ValueAllocator>> m_valueBuffers;
};
} // namespace AZ::Dom
@@ -105,7 +105,12 @@ namespace AZ::Dom
return VisitorSuccess();
}
Visitor::Result Visitor::OpaqueValue([[maybe_unused]] const OpaqueType& value, [[maybe_unused]] Lifetime lifetime)
Visitor::Result Visitor::RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, Lifetime lifetime)
{
return String({ value->data(), value->size() }, lifetime);
}
Visitor::Result Visitor::OpaqueValue([[maybe_unused]] OpaqueType& value)
{
if (!SupportsOpaqueValues())
{
+11 -4
View File
@@ -11,6 +11,8 @@
#include <AzCore/Name/Name.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/any.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/string/string.h>
namespace AZ::Dom
@@ -167,15 +169,20 @@ namespace AZ::Dom
virtual Result Uint64(AZ::u64 value);
//! Operates on a double precision, 64 bit floating point value.
virtual Result Double(double value);
//! Operates on a string value. As strings are a reference type.
//! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
//! Operates on a string value. As strings are a reference type,
//! storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
//! \param lifetime Specifies the lifetime of this string - if the string has a temporary lifetime, it cannot
//! safely be stored as a reference.
virtual Result String(AZStd::string_view value, Lifetime lifetime);
//! Operates on a ref-counted string value. S
//! \param lifetime Specifies the lifetime of this string. If the string has a temporary lifetime, it may not
//! be safely stored as a reference, but may still be safely stored as a ref-counted shared_ptr.
virtual Result RefCountedString(AZStd::shared_ptr<const AZStd::vector<char>> value, Lifetime lifetime);
//! Operates on an opaque value. As opaque values are a reference type, storage semantics are provided to
//! indicate where the value may be stored persistently or requires a copy.
//! The base implementation of OpaqueValue rejects the operation, as opaque values are meant for special
//! cases with specific implementations, not generic usage.
//! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
virtual Result OpaqueValue(const OpaqueType& value, Lifetime lifetime);
virtual Result OpaqueValue(OpaqueType& value);
//! Operates on a raw value encoded as a UTF-8 string that hasn't had its type deduced.
//! Visitors that support raw values (\see VisitorFlags::SupportsRawValues) may parse the raw value and
//! forward it to the corresponding value call or calls of their choice.
+10 -6
View File
@@ -62,12 +62,16 @@ namespace AZ::Debug
//
// Anywhere the budget is used, the budget must be declared (either in a header or in the source file itself)
// AZ_DECLARE_BUDGET(AzCore);
#define AZ_DEFINE_BUDGET(name) \
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
{ \
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
static ::AZ::Debug::Budget* budget = ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name, crc); \
return budget; \
#define AZ_DEFINE_BUDGET(name) \
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
{ \
static ::AZ::Debug::Budget* budget = nullptr; \
if (budget == nullptr) \
{ \
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(budget, #name, crc); \
} \
return budget; \
}
#endif
@@ -13,23 +13,24 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/parallel/scoped_lock.h>
namespace AZ::Debug
{
struct BudgetTracker::BudgetTrackerImpl
{
AZStd::unordered_map<const char*, Budget> m_budgets;
AZStd::unordered_map<AZStd::string_view, Budget> m_budgets;
AZStd::unordered_set<Budget**> m_externalBudgetRefs;
};
Budget* BudgetTracker::GetBudgetFromEnvironment(const char* budgetName, uint32_t crc)
void BudgetTracker::GetBudgetFromEnvironment(Budget*& extBudgetRef, const char* budgetName, uint32_t crc)
{
BudgetTracker* tracker = Interface<BudgetTracker>::Get();
if (tracker)
{
return &tracker->GetBudget(budgetName, crc);
tracker->GetBudget(extBudgetRef, budgetName, crc);
}
return nullptr;
}
BudgetTracker::~BudgetTracker()
@@ -54,17 +55,24 @@ namespace AZ::Debug
if (m_impl)
{
Interface<BudgetTracker>::Unregister(this);
for (auto budgetRef : m_impl->m_externalBudgetRefs)
{
*budgetRef = nullptr;
}
delete m_impl;
m_impl = nullptr;
}
}
Budget& BudgetTracker::GetBudget(const char* budgetName, uint32_t crc)
void BudgetTracker::GetBudget(Budget*& extBudgetRef, const char* budgetName, uint32_t crc)
{
AZStd::scoped_lock lock{ m_mutex };
auto it = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
m_impl->m_externalBudgetRefs.insert(&extBudgetRef);
return it->second;
auto iter = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
extBudgetRef = &iter->second;
}
} // namespace AZ::Debug
@@ -20,7 +20,7 @@ namespace AZ::Debug
{
public:
AZ_TYPE_INFO(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc);
static void GetBudgetFromEnvironment(Budget*& extBudgetRef, const char* budgetName, uint32_t crc);
~BudgetTracker();
@@ -28,7 +28,7 @@ namespace AZ::Debug
bool Init();
void Reset();
Budget& GetBudget(const char* budgetName, uint32_t crc);
void GetBudget(Budget*& extBudgetRef, const char* budgetName, uint32_t crc);
private:
struct BudgetTrackerImpl;
+7 -2
View File
@@ -23,6 +23,11 @@
#include <AzCore/EBus/Results.h>
#include <AzCore/EBus/Internal/Debug.h>
// Included for backwards compatibility purposes
#include <AzCore/std/typetraits/typetraits.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/utils.h>
@@ -515,7 +520,7 @@ namespace AZ
* This is not EBus Context Mutex when LocklessDispatch is set
*/
template <typename DispatchMutex>
using DispatchLockGuard = typename ImplTraits::template DispatchLockGuard<DispatchMutex>;
using DispatchLockGuardTemplate = typename ImplTraits::template DispatchLockGuard<DispatchMutex>;
//////////////////////////////////////////////////////////////////////////
// Check to help identify common mistakes
@@ -645,7 +650,7 @@ namespace AZ
* during broadcast/event dispatch.
* @see EBusTraits::LocklessDispatch
*/
using DispatchLockGuard = DispatchLockGuard<ContextMutexType>;
using DispatchLockGuard = DispatchLockGuardTemplate<ContextMutexType>;
/**
* The scoped lock guard to use during connection. Some specialized policies execute handler methods which
@@ -93,14 +93,14 @@ namespace AZ
// This struct will hold the handlers per address
struct HandlerHolder;
// This struct will hold each handler
using HandlerNode = HandlerNode<Interface, Traits, HandlerHolder>;
using HandlerNode = AZ::Internal::HandlerNode<Interface, Traits, HandlerHolder>;
// Defines how handler holders are stored (will be some sort of map-like structure from id -> handler holder)
using AddressStorage = AddressStoragePolicy<Traits, HandlerHolder>;
// Defines how handlers are stored per address (will be some sort of list)
using HandlerStorage = HandlerStoragePolicy<Interface, Traits, HandlerNode>;
using Handler = IdHandler<Interface, Traits, ContainerType>;
using MultiHandler = MultiHandler<Interface, Traits, ContainerType>;
using MultiHandler = AZ::Internal::MultiHandler<Interface, Traits, ContainerType>;
using BusPtr = AZStd::intrusive_ptr<HandlerHolder>;
EBusContainer() = default;
@@ -774,13 +774,13 @@ namespace AZ
// This struct will hold the handler per address
struct HandlerHolder;
// This struct will hold each handler
using HandlerNode = HandlerNode<Interface, Traits, HandlerHolder>;
using HandlerNode = AZ::Internal::HandlerNode<Interface, Traits, HandlerHolder>;
// Defines how handler holders are stored (will be some sort of map-like structure from id -> handler holder)
using AddressStorage = AddressStoragePolicy<Traits, HandlerHolder>;
// No need for HandlerStorage, there's only 1 so it will always just be a HandlerNode*
using Handler = IdHandler<Interface, Traits, ContainerType>;
using MultiHandler = MultiHandler<Interface, Traits, ContainerType>;
using MultiHandler = AZ::Internal::MultiHandler<Interface, Traits, ContainerType>;
using BusPtr = AZStd::intrusive_ptr<HandlerHolder>;
EBusContainer() = default;
@@ -1316,7 +1316,7 @@ namespace AZ
// This struct will hold the handlers per address
struct HandlerHolder;
// This struct will hold each handler
using HandlerNode = HandlerNode<Interface, Traits, HandlerHolder>;
using HandlerNode = AZ::Internal::HandlerNode<Interface, Traits, HandlerHolder>;
// Defines how handlers are stored per address (will be some sort of list)
using HandlerStorage = HandlerStoragePolicy<Interface, Traits, HandlerNode>;
// No need for AddressStorage, there's only 1
@@ -161,7 +161,7 @@ namespace AZ
template <class C>
struct EBusCallstackStorage<C, true>
{
AZ_THREAD_LOCAL static C* s_entry;
static AZ_THREAD_LOCAL C* s_entry;
EBusCallstackStorage() = default;
~EBusCallstackStorage() = default;
+43 -51
View File
@@ -13,50 +13,6 @@
#include <AzCore/IO/Path/PathIterable.inl>
// extern instantiations of Path templates to prevent implicit instantiations
namespace AZ::IO
{
// Class templates explicit declarations
extern template class BasicPath<AZStd::string>;
extern template class BasicPath<FixedMaxPathString>;
extern template class PathIterator<PathView>;
extern template class PathIterator<Path>;
extern template class PathIterator<FixedMaxPath>;
// Swap function explicit declarations
extern template void swap<AZStd::string>(Path& lhs, Path& rhs) noexcept;
extern template void swap<FixedMaxPathString>(FixedMaxPath& lhs, FixedMaxPath& rhs) noexcept;
// Hash function explicit declarations
extern template size_t hash_value<AZStd::string>(const Path& pathToHash);
extern template size_t hash_value<FixedMaxPathString>(const FixedMaxPath& pathToHash);
// Append operator explicit declarations
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, const PathView& rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, const PathView& rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, AZStd::string_view rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, AZStd::string_view rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs,
const typename BasicPath<AZStd::string>::value_type* rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs,
const typename BasicPath<FixedMaxPathString>::value_type* rhs);
// Iterator compare explicit declarations
extern template bool operator==<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator==<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator==<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
extern template bool operator!=<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator!=<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator!=<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
}
//! PathView implementation
namespace AZ::IO
{
@@ -939,13 +895,13 @@ namespace AZ::IO
// then it has no root directory nor filename
if (rootNameView.end() == m_path.end())
{
// has_root_directory || has_filename = false
// If the root name is of the form
// # C: - then it isn't absolute unless it has a root directory C:\
// # \\?\ = is a UNC path that can't exist without a root directory
// # \\server - Is absolute, but has no root directory
// Therefore if the rootName is larger than three characters
// then append the path separator
/* has_root_directory || has_filename = false
If the root name is of the form
C: - then it isn't absolute unless it has a root directory C:\.
\\?\ = is a UNC path that can't exist without a root directory.
\\server - Is absolute, but has no root directory.
Therefore if the rootName is larger than three characters
then append the path separator. */
if (rootNameView.size() >= 3)
{
m_path.push_back(m_preferred_separator);
@@ -1550,3 +1506,39 @@ namespace AZ::IO
return AZStd::hash<PathView>{}(pathToHash);
}
}
// extern instantiations of Path templates to prevent implicit instantiations
namespace AZ::IO
{
// Swap function explicit declarations
extern template void swap<AZStd::string>(Path& lhs, Path& rhs) noexcept;
extern template void swap<FixedMaxPathString>(FixedMaxPath& lhs, FixedMaxPath& rhs) noexcept;
// Hash function explicit declarations
extern template size_t hash_value<AZStd::string>(const Path& pathToHash);
extern template size_t hash_value<FixedMaxPathString>(const FixedMaxPath& pathToHash);
// Append operator explicit declarations
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, const PathView& rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, const PathView& rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs, AZStd::string_view rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs, AZStd::string_view rhs);
extern template BasicPath<AZStd::string> operator/<AZStd::string>(const BasicPath<AZStd::string>& lhs,
const typename BasicPath<AZStd::string>::value_type* rhs);
extern template BasicPath<FixedMaxPathString> operator/<FixedMaxPathString>(const BasicPath<FixedMaxPathString>& lhs,
const typename BasicPath<FixedMaxPathString>::value_type* rhs);
// Iterator compare explicit declarations
extern template bool operator==<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator==<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator==<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
extern template bool operator!=<PathView>(const PathIterator<PathView>& lhs,
const PathIterator<PathView>& rhs);
extern template bool operator!=<Path>(const PathIterator<Path>& lhs,
const PathIterator<Path>& rhs);
extern template bool operator!=<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
const PathIterator<FixedMaxPath>& rhs);
}
@@ -14,7 +14,7 @@
#define az_clz_u64(x) _lzcnt_u64(x)
#define az_popcnt_u32(x) __popcnt(x)
#define az_popcnt_u64(x) __popcnt64(x)
#elif defined(AZ_COMPILER_CLANG)
#elif defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
#define az_ctz_u32(x) __builtin_ctz(x)
#define az_ctz_u64(x) __builtin_ctzll(x)
#define az_clz_u32(x) __builtin_clz(x)
@@ -22,5 +22,5 @@
#define az_popcnt_u32(x) __builtin_popcount(x)
#define az_popcnt_u64(x) __builtin_popcountll(x)
#else
#error Count Leading Zeros, Count Trailing Zeros and Pop Count intrinsics isn't supported for this compiler
#error Count Leading Zeros, Count Trailing Zeros and Pop Count intrinsics isnt supported for this compiler
#endif
+3 -5
View File
@@ -26,7 +26,6 @@ namespace AZ
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndDistance(const Vector3& normal, float dist)
{
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
Plane result;
result.Set(normal, dist);
return result;
@@ -35,7 +34,6 @@ namespace AZ
AZ_MATH_INLINE Plane Plane::CreateFromCoefficients(const float a, const float b, const float c, const float d)
{
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
Plane result;
result.Set(a, b, c, d);
return result;
@@ -68,21 +66,21 @@ namespace AZ
AZ_MATH_INLINE void Plane::Set(const Vector3& normal, float d)
{
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
m_plane.Set(normal, d);
}
AZ_MATH_INLINE void Plane::Set(float a, float b, float c, float d)
{
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is not normalized");
m_plane.Set(a, b, c, d);
}
AZ_MATH_INLINE void Plane::SetNormal(const Vector3& normal)
{
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
m_plane.SetX(normal.GetX());
m_plane.SetY(normal.GetY());
m_plane.SetZ(normal.GetZ());
@@ -39,6 +39,9 @@ namespace AZ
template<typename T> constexpr friend void AZStd::destroy_at(T*);
public:
AllocatorManager();
typedef AZStd::function<void (IAllocator* allocator, size_t /*byteSize*/, size_t /*alignment*/, int/* flags*/, const char* /*name*/, const char* /*fileName*/, int lineNum /*=0*/)> OutOfMemoryCBType;
static void PreRegisterAllocator(IAllocator* allocator); // Only call if the environment is not yet attached
@@ -166,7 +169,6 @@ namespace AZ
AZ::Debug::AllocationRecords::Mode m_defaultTrackingRecordMode;
AZStd::unique_ptr<AZ::MallocSchema, void(*)(AZ::MallocSchema*)> m_mallocSchema;
AllocatorManager();
~AllocatorManager();
static AllocatorManager g_allocMgr; ///< The single instance of the allocator manager
@@ -45,7 +45,9 @@ namespace AZ
//! that already exist.
class NameDictionary final
{
public:
AZ_CLASS_ALLOCATOR(NameDictionary, AZ::OSAllocator, 0);
private:
friend Module;
friend Name;
@@ -75,8 +77,8 @@ namespace AZ
//! @return A Name instance. If the hash was not found, the Name will be empty.
Name FindName(Name::Hash hash) const;
private:
NameDictionary();
private:
~NameDictionary();
void ReportStats() const;
+161 -7
View File
@@ -10,10 +10,17 @@
//////////////////////////////////////////////////////////////////////////
// Platforms
#include <AzCore/variadic.h>
#include "PlatformRestrictedFileDef.h"
#if defined(__clang__)
#define AZ_COMPILER_CLANG __clang_major__
#elif defined(__GNUC__)
// Assign AZ_COMPILER_GCC to a number that represents the major+minor (2 digits) + path level (2 digits) i.e. 3.2.0 == 30200
#define AZ_COMPILER_GCC (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#elif defined(_MSC_VER)
#define AZ_COMPILER_MSVC _MSC_VER
#else
@@ -29,7 +36,7 @@
#define AZ_DYNAMIC_LIBRARY_PREFIX AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX
#define AZ_DYNAMIC_LIBRARY_EXTENSION AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION
#if defined(AZ_COMPILER_CLANG)
#if defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
#define AZ_DLL_EXPORT AZ_TRAIT_OS_DLL_EXPORT_CLANG
#define AZ_DLL_IMPORT AZ_TRAIT_OS_DLL_IMPORT_CLANG
#elif defined(AZ_COMPILER_MSVC)
@@ -67,12 +74,36 @@
#if defined(AZ_COMPILER_MSVC)
/// Disables a warning using push style. For use matched with an AZ_POP_WARNING
#define AZ_PUSH_DISABLE_WARNING(_msvcOption, __) \
__pragma(warning(push)) \
// Compiler specific AZ_PUSH_DISABLE_WARNING
#define AZ_PUSH_DISABLE_WARNING_MSVC(_msvcOption) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
#define AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
#define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
/// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
#define AZ_POP_DISABLE_WARNING_CLANG
#define AZ_POP_DISABLE_WARNING_MSVC \
__pragma(warning(pop))
#define AZ_POP_DISABLE_WARNING_GCC
// Variadic definitions for AZ_PUSH_DISABLE_WARNING for the current compiler
#define AZ_PUSH_DISABLE_WARNING_1(_msvcOption) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
#define AZ_PUSH_DISABLE_WARNING_2(_msvcOption, _2) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
#define AZ_PUSH_DISABLE_WARNING_3(_msvcOption, _2, _3) \
__pragma(warning(push)) \
__pragma(warning(disable : _msvcOption))
/// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
#define AZ_POP_DISABLE_WARNING \
#define AZ_POP_DISABLE_WARNING \
__pragma(warning(pop))
@@ -94,17 +125,62 @@
# define AZ_FUNCTION_SIGNATURE __FUNCSIG__
//////////////////////////////////////////////////////////////////////////
#elif defined(AZ_COMPILER_CLANG)
#elif defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
#if defined(AZ_COMPILER_CLANG)
/// Disables a single warning using push style. For use matched with an AZ_POP_WARNING
#define AZ_PUSH_DISABLE_WARNING(__, _clangOption) \
_Pragma("clang diagnostic push") \
// Compiler specific AZ_PUSH_DISABLE_WARNING
#define AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption) \
_Pragma("clang diagnostic push") \
_Pragma(AZ_STRINGIZE(clang diagnostic ignored _clangOption))
#define AZ_PUSH_DISABLE_WARNING_MSVC(_msvcOption)
#define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
/// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
#define AZ_POP_DISABLE_WARNING_CLANG \
_Pragma("clang diagnostic pop")
#define AZ_POP_DISABLE_WARNING_MSVC
#define AZ_POP_DISABLE_WARNING_GCC
// Variadic definitions for AZ_PUSH_DISABLE_WARNING for the current compiler
#define AZ_PUSH_DISABLE_WARNING_1(_1)
#define AZ_PUSH_DISABLE_WARNING_2(_1, _clangOption) AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
#define AZ_PUSH_DISABLE_WARNING_3(_1, _clangOption, _2) AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
/// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
#define AZ_POP_DISABLE_WARNING \
_Pragma("clang diagnostic pop")
#else
/// Disables a single warning using push style. For use matched with an AZ_POP_WARNING
// Compiler specific AZ_PUSH_DISABLE_WARNING
#define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption) \
_Pragma("GCC diagnostic push") \
_Pragma(AZ_STRINGIZE(GCC diagnostic ignored _gccOption))
#define AZ_PUSH_DISABLE_WARNING_CLANG(_clangOption)
#define AZ_PUSH_DISABLE_WARNING_MSVC(_msvcOption)
/// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
#define AZ_POP_DISABLE_WARNING_CLANG
#define AZ_POP_DISABLE_WARNING_MSVC
#define AZ_POP_DISABLE_WARNING_GCC \
_Pragma("GCC diagnostic pop")
// Variadic definitions for AZ_PUSH_DISABLE_WARNING for the current compiler
#define AZ_PUSH_DISABLE_WARNING_1(_1)
#define AZ_PUSH_DISABLE_WARNING_2(_1, _2)
#define AZ_PUSH_DISABLE_WARNING_3(_1, _2, _gccOption) AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
/// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
#define AZ_POP_DISABLE_WARNING
_Pragma("GCC diagnostic pop")
#endif // defined(AZ_COMPILER_CLANG)
#define AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
#define AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
#define AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
@@ -121,6 +197,8 @@
#error Compiler not supported
#endif
#define AZ_PUSH_DISABLE_WARNING(...) AZ_MACRO_SPECIALIZE(AZ_PUSH_DISABLE_WARNING_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
// We need to define AZ_DEBUG_BUILD in debug mode. We can also define it in debug optimized mode (left up to the user).
// note that _DEBUG is not in fact always defined on all platforms, and only AZ_DEBUG_BUILD should be relied on.
#if !defined(AZ_DEBUG_BUILD) && defined(_DEBUG)
@@ -149,3 +227,79 @@
#if !defined(AZ_COMMAND_LINE_LEN)
# define AZ_COMMAND_LINE_LEN 2048
#endif
#include <type_traits>
#include <utility>
#include <memory>
#include <cstdint>
#include <cstring>
// First check if the feature if is_constant_evaluated is available via the feature test macro
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros#C.2B.2B20
#if __cpp_lib_is_constant_evaluated
#define az_builtin_is_constant_evaluated() std::is_constant_evaluated()
#endif
// Next check if there is a __builtin_is_constant_evaluated that can be used
// This works on MSVC 19.28+ toolsets when using C++17, as well as
// clang 9.0.0+ when using C++17.
// Finally it works on gcc 9.0+ when using C++17
#if !defined(az_builtin_is_constant_evaluated)
#if defined(__has_builtin)
#if __has_builtin(__builtin_is_constant_evaluated)
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() true
#endif
#elif AZ_COMPILER_MSVC >= 1928
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() true
#elif AZ_COMPILER_GCC
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() true
#endif
#endif
// In this case no support for the determining whether an operation is occuring
// at compile time is supported so assume that evaluation is always occuring at compile time
// in order to make sure the "safe" operation is being performed
#if !defined(az_builtin_is_constant_evaluated)
namespace AZ::Internal
{
constexpr bool builtin_is_constant_evaluated()
{
return true;
}
}
#define az_builtin_is_constant_evaluated() AZ::Internal::builtin_is_constant_evaluated()
#define az_has_builtin_is_constant_evaluated() false
#endif
// define builtin functions used by char_traits class for efficient compile time and runtime
// operations
#if defined(__has_builtin)
#if __has_builtin(__builtin_memcpy)
#define az_has_builtin_memcpy true
#endif
#if __has_builtin(__builtin_wmemcpy)
#define az_has_builtin_wmemcpy true
#endif
#if __has_builtin(__builtin_memmove)
#define az_has_builtin_memmove true
#endif
#if __has_builtin(__builtin_wmemmove)
#define az_has_builtin_wmemmove true
#endif
#endif
#if !defined(az_has_builtin_memcpy)
#define az_has_builtin_memcpy false
#endif
#if !defined(az_has_builtin_wmemcpy)
#define az_has_builtin_wmemcpy false
#endif
#if !defined(az_has_builtin_memmove)
#define az_has_builtin_memmove false
#endif
#if !defined(az_has_builtin_wmemmove)
#define az_has_builtin_wmemmove false
#endif
@@ -1541,7 +1541,7 @@ namespace AZ
}
template<class T>
static bool SetClassEqualityComparer(BehaviorClass* behaviorClass, const T*)
static void SetClassEqualityComparer(BehaviorClass* behaviorClass, const T*)
{
behaviorClass->m_equalityComparer = &DefaultEqualityComparer<T>;
}
@@ -2341,8 +2341,6 @@ namespace AZ
// For some reason the Script.cpp test validates that an incomplete type can be used with the SetResult struct
template<typename T, typename U, typename = void>
static constexpr bool IsCopyAssignable = false;
template<typename T, typename U>
static constexpr bool IsCopyAssignable<T, U, AZStd::void_t<decltype(AZStd::declval<T>() = AZStd::declval<U>())>> = true;
template<class T>
static bool Set(BehaviorValueParameter& param, T&& result, bool IsValueCopy)
@@ -2402,6 +2400,9 @@ namespace AZ
}
};
template<typename T, typename U>
constexpr bool SetResult::IsCopyAssignable<T, U, AZStd::void_t<decltype(AZStd::declval<T>() = AZStd::declval<U>())>> = true;
AZ_FORCE_INLINE BehaviorValueParameter& BehaviorValueParameter::operator=(BehaviorValueParameter&& other)
{
*static_cast<BehaviorParameter*>(this) = AZStd::move(static_cast<BehaviorParameter&&>(other));
+21 -8
View File
@@ -977,26 +977,32 @@ namespace AZ
{
return AzGenericTypeInfo::Uuid<U>();
}
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class U, typename = void>
#else
template<template<auto...> class U, typename = void>
#endif // defined(AZ_COMPILER_MSVC)
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
}
template<template<typename, AZStd::size_t> class U, typename = void>
template<template<typename, auto> class U, typename = void>
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
}
template<template<typename, typename, AZStd::size_t> class U, typename = void>
template<template<typename, typename, auto> class U, typename = void>
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
}
template<template<typename, typename, typename, AZStd::size_t> class U, typename = void>
template<template<typename, typename, typename, auto> class U, typename = void>
inline const AZ::TypeId& RttiTypeId()
{
return AzGenericTypeInfo::Uuid<U>();
@@ -1027,15 +1033,22 @@ namespace AZ
}
// Returns true if the type is contained, otherwise false. Safe to call for type not supporting AZRtti (returns false unless type fully match).
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class T, class U>
inline bool RttiIsTypeOf(const U&)
#else
template<template<auto...> class T, class U>
#endif // defined(AZ_COMPILER_MSVC)
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
return AzGenericTypeInfo::Uuid<T>() == RttiTypeId<CheckType, AZ::GenericTypeIdTag>();
}
// Returns true if the type is contained, otherwise false. Safe to call for type not supporting AZRtti (returns false unless type fully match).
template<template<typename, AZStd::size_t> class T, class U>
template<template<typename, auto> class T, class U>
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
@@ -1043,7 +1056,7 @@ namespace AZ
}
// Returns true if the type is contained, otherwise false.Safe to call for type not supporting AZRtti(returns false unless type fully match).
template<template<typename, typename, AZStd::size_t> class T, class U>
template<template<typename, typename, auto> class T, class U>
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
@@ -1051,7 +1064,7 @@ namespace AZ
}
// Returns true if the type is contained, otherwise false.Safe to call for type not supporting AZRtti(returns false unless type fully match).
template<template<typename, typename, typename, AZStd::size_t> class T, class U>
template<template<typename, typename, typename, auto> class T, class U>
inline bool RttiIsTypeOf(const U&)
{
using CheckType = typename AZ::Internal::RttiRemoveQualifiers<U>::type;
+24 -12
View File
@@ -148,11 +148,18 @@ namespace AZ
{
/// Needs to match declared parameter type.
template <template <typename...> class> constexpr bool false_v1 = false;
template <template <AZStd::size_t...> class> constexpr bool false_v2 = false;
template <template <typename, AZStd::size_t> class> constexpr bool false_v3 = false;
template <template <typename, typename, AZStd::size_t> class> constexpr bool false_v4 = false;
template <template <typename, typename, typename, AZStd::size_t> class> constexpr bool false_v5 = false;
template <template <typename, AZStd::size_t, typename> class> constexpr bool false_v6 = false;
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class> constexpr bool false_v2 = false;
#else
template<template<auto...> class> constexpr bool false_v2 = false;
#endif // defined(AZ_COMPILER_MSVC)
template<template<typename, auto> class>
constexpr bool false_v3 = false;
template <template <typename, typename, auto> class> constexpr bool false_v4 = false;
template <template <typename, typename, typename, auto> class> constexpr bool false_v5 = false;
template <template <typename, auto, typename> class> constexpr bool false_v6 = false;
template<typename T>
inline const AZ::TypeId& Uuid()
@@ -167,8 +174,13 @@ namespace AZ
static const AZ::TypeId s_uuid = AZ::TypeId::CreateNull();
return s_uuid;
}
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class T>
#else
template<template<auto...> class T>
#endif // defined(AZ_COMPILER_MSVC)
inline const AZ::TypeId& Uuid()
{
static_assert(false_v2<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -176,7 +188,8 @@ namespace AZ
return s_uuid;
}
template<template<typename, AZStd::size_t> class T>
template<template<typename, auto> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v3<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -184,7 +197,7 @@ namespace AZ
return s_uuid;
}
template<template<typename, typename, AZStd::size_t> class T>
template<template<typename, typename, auto> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v4<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -192,7 +205,7 @@ namespace AZ
return s_uuid;
}
template<template<typename, typename, typename, AZStd::size_t> class T>
template<template<typename, typename, typename, auto> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v5<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -200,7 +213,7 @@ namespace AZ
return s_uuid;
}
template<template<typename, AZStd::size_t, typename> class T>
template<template<typename, auto, typename> class T>
inline const AZ::TypeId& Uuid()
{
static_assert(false_v6<T>, "Missing specialization for this template. Make sure it's registered for type info support.");
@@ -689,8 +702,7 @@ namespace AZ
#define AZ_TYPE_INFO_INTERNAL_CLASS_VARARGS__UUID(Tag, A) AZ::Internal::AggregateTypes< A... >::template Uuid< Tag >()
#define AZ_TYPE_INFO_INTERNAL_CLASS_VARARGS__NAME(A) AZ::Internal::AggregateTypes< A... >::TypeName(typeName, AZ_ARRAY_SIZE(typeName));
// Once C++17 has been introduced size_t can be replaced with auto for all integer non-type arguments
#define AZ_TYPE_INFO_INTERNAL_AUTO__TYPE AZStd::size_t
#define AZ_TYPE_INFO_INTERNAL_AUTO__TYPE auto
#define AZ_TYPE_INFO_INTERNAL_AUTO__ARG(A) A
#define AZ_TYPE_INFO_INTERNAL_AUTO__UUID(Tag, A) AZ::Internal::GetTypeId< A , Tag >()
#define AZ_TYPE_INFO_INTERNAL_AUTO__NAME(A) AZ::Internal::AzTypeInfoSafeCat(typeName, AZ_ARRAY_SIZE(typeName), AZ::Internal::GetTypeName< A >())
@@ -796,7 +796,7 @@ namespace AZ
// Note: Always use l over context->NativeContext(), as require may be called from a thread.
using RequireHook = AZStd::function<int(lua_State* lua, ScriptContext* context, const char* module)>;
using StackVariableAllocator = StackVariableAllocator;
using StackVariableAllocator = AZ::StackVariableAllocator;
/// Stack temporary memory
/**
@@ -69,7 +69,13 @@ namespace AZ
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
}
#if defined(AZ_COMPILER_MSVC)
// There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
// template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
template<template<AZStd::size_t...> class T>
#else
template<template<auto...> class T>
#endif // defined(AZ_COMPILER_MSVC)
SerializerBuilder* HandlesType(bool overwriteExisting = false)
{
return HandlesTypeId(azrtti_typeid<T>(), overwriteExisting);
@@ -17,16 +17,9 @@
#if defined(HAVE_BENCHMARK)
#if defined(AZ_COMPILER_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif // clang
AZ_PUSH_DISABLE_WARNING(, "-Wdeprecated-declarations", "-Wdeprecated-declarations")
#include <benchmark/benchmark.h>
#if defined(AZ_COMPILER_CLANG)
#pragma clang diagnostic pop
#endif // clang
AZ_POP_DISABLE_WARNING
#endif // HAVE_BENCHMARK
@@ -71,18 +64,35 @@ namespace UnitTest
};
/**
* RAII wrapper of AllocatorBase.
* The benefit of using this wrapper instead of AllocatorsTestFixture is that SetUp/TearDown of the allocator is managed
* on construction/destruction, allowing member variables of derived classes to exist as value (and do heap allocation).
*/
class ScopedAllocatorSetupFixture
: public ::testing::Test
, AllocatorsBase
* RAII wrapper of AllocatorBase.
* The benefit of using this wrapper instead of AllocatorsTestFixture is that SetUp/TearDown of the allocator is managed
* on construction/destruction, allowing member variables of derived classes to exist as value (and do heap allocation).
*/
class ScopedAllocatorFixture : AllocatorsBase
{
public:
ScopedAllocatorSetupFixture() { SetupAllocator(); }
explicit ScopedAllocatorSetupFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) { SetupAllocator(allocatorDesc); }
~ScopedAllocatorSetupFixture() { TeardownAllocator(); }
ScopedAllocatorFixture()
{
SetupAllocator();
}
explicit ScopedAllocatorFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc)
{
SetupAllocator(allocatorDesc);
}
~ScopedAllocatorFixture() override
{
TeardownAllocator();
}
};
// Like ScopedAllocatorFixture, but includes the Test base class
class ScopedAllocatorSetupFixture
: public ::testing::Test
, public ScopedAllocatorFixture
{
public:
ScopedAllocatorSetupFixture() = default;
explicit ScopedAllocatorSetupFixture(const AZ::SystemAllocator::Descriptor& allocatorDesc) : ScopedAllocatorFixture(allocatorDesc){}
};
/**
@@ -114,6 +124,7 @@ namespace UnitTest
using AllocatorsFixture = AllocatorsTestFixture;
#if defined(HAVE_BENCHMARK)
/**
* Helper class to handle the boiler plate of setting up a benchmark fixture that uses the system allocators
* If you wish to do additional setup and tear down be sure to call the base class SetUp first and TearDown
@@ -218,7 +229,7 @@ namespace UnitTest
static constexpr bool sHasPadding = size < alignment;
AZStd::enable_if<sHasPadding, char[(alignment - size) % alignment]> mPadding;
};
template <AZ::u32 size, AZ::u8 instance, size_t alignment>
int CreationCounter<size, instance, alignment>::s_count = 0;
template <AZ::u32 size, AZ::u8 instance, size_t alignment>
@@ -9,6 +9,7 @@
set(FILES
base.h
Docs.h
variadic.h
Platform.cpp
Platform.h
PlatformDef.h
@@ -117,6 +118,10 @@ set(FILES
DOM/DomBackend.h
DOM/DomUtils.cpp
DOM/DomUtils.h
DOM/DomValue.cpp
DOM/DomValue.h
DOM/DomValueWriter.cpp
DOM/DomValueWriter.h
DOM/DomVisitor.cpp
DOM/DomVisitor.h
DOM/Backends/JSON/JsonBackend.h
+1 -60
View File
@@ -7,6 +7,7 @@
*/
#pragma once
#include <AzCore/variadic.h>
#include <AzCore/PlatformDef.h> ///< Platform/compiler specific defines
#include <AzCore/base_Platform.h>
@@ -135,66 +136,6 @@
#define AZ_INVALID_POINTER reinterpret_cast<void*>(0x0badf00dul)
// Variadic MACROS util functions
/**
* AZ_VA_NUM_ARGS
* counts number of parameters (up to 10).
* example. AZ_VA_NUM_ARGS(x,y,z) -> expands to 3
*/
#ifndef AZ_VA_NUM_ARGS
# define AZ_VA_HAS_ARGS(...) ""#__VA_ARGS__[0] != 0
// we add the zero to avoid the case when we require at least 1 param at the end...
# define AZ_VA_NUM_ARGS(...) AZ_VA_NUM_ARGS_IMPL_((__VA_ARGS__, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
# define AZ_VA_NUM_ARGS_IMPL_(tuple) AZ_VA_NUM_ARGS_IMPL tuple
# define AZ_VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, N, ...) N
// Expands a macro and calls a different macro based on the number of arguments.
//
// Example: We need to specialize a macro for 1 and 2 arguments
// #define AZ_MY_MACRO(...) AZ_MACRO_SPECIALIZE(AZ_MY_MACRO_,AZ_VA_NUM_ARGS(__VA_ARGS__),(__VA_ARGS__))
//
// #define AZ_MY_MACRO_1(_1) /* code for 1 param */
// #define AZ_MY_MACRO_2(_1,_2) /* code for 2 params */
// ... etc.
//
//
// We have 3 levels of macro expansion...
# define AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS) MACRO_NAME##NPARAMS PARAMS
# define AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS)
# define AZ_MACRO_SPECIALIZE(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS)
#endif // AZ_VA_NUM_ARGS
// Out of all supported compilers, mwerks is the only one
// that requires variadic macros to have at least 1 param.
// This is a pain they we use macros to call functions (with no params).
// we implement functions for up to 10 params
#define AZ_FUNCTION_CALL_1(_1) _1()
#define AZ_FUNCTION_CALL_2(_1, _2) _1(_2)
#define AZ_FUNCTION_CALL_3(_1, _2, _3) _1(_2, _3)
#define AZ_FUNCTION_CALL_4(_1, _2, _3, _4) _1(_2, _3, _4)
#define AZ_FUNCTION_CALL_5(_1, _2, _3, _4, _5) _1(_2, _3, _4, _5)
#define AZ_FUNCTION_CALL_6(_1, _2, _3, _4, _5, _6) _1(_2, _3, _4, _5, _6)
#define AZ_FUNCTION_CALL_7(_1, _2, _3, _4, _5, _6, _7) _1(_2, _3, _4, _5, _6, _7)
#define AZ_FUNCTION_CALL_8(_1, _2, _3, _4, _5, _6, _7, _8) _1(_2, _3, _4, _5, _6, _7, _8)
#define AZ_FUNCTION_CALL_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) _1(_2, _3, _4, _5, _6, _7, _8, _9)
#define AZ_FUNCTION_CALL_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) _1(_2, _3, _4, _5, _6, _7, _8, _9, _10)
// We require at least 1 param FunctionName
#define AZ_FUNCTION_CALL(...) AZ_MACRO_SPECIALIZE(AZ_FUNCTION_CALL_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
// Based on boost macro expansion fix...
#define AZ_PREVENT_MACRO_SUBSTITUTION
//////////////////////////////////////////////////////////////////////////
#include <cstddef> // the macros NULL and offsetof as well as the types ptrdiff_t, wchar_t, and size_t.
@@ -11,17 +11,17 @@
namespace AZStd
{
stateless_allocator::stateless_allocator(const char* name)
: m_name(name) {}
stateless_allocator::stateless_allocator() = default;
stateless_allocator::stateless_allocator(const char*)
{}
const char* stateless_allocator::get_name() const
{
return m_name;
return "AZStd::stateless_allocator";
}
void stateless_allocator::set_name(const char* name)
void stateless_allocator::set_name(const char*)
{
m_name = name;
}
auto stateless_allocator::allocate(size_type byteSize) -> pointer_type
@@ -26,7 +26,8 @@ namespace AZStd
using difference_type = ptrdiff_t;
using allow_memory_leaks = AZStd::true_type;
stateless_allocator(const char* name = "AZStd::stateless_allocator");
stateless_allocator();
explicit stateless_allocator(const char*); // Stateless allocator does not store a name
stateless_allocator(const stateless_allocator& rhs) = default;
stateless_allocator& operator=(const stateless_allocator& rhs) = default;
@@ -51,9 +52,6 @@ namespace AZStd
bool is_lock_free();
bool is_stale_read_allowed();
bool is_delayed_recycling();
private:
const char* m_name;
};
bool operator==(const stateless_allocator& left, const stateless_allocator& right);
@@ -64,6 +64,8 @@ set(FILES
containers/rbtree.h
containers/ring_buffer.h
containers/set.h
containers/span.h
containers/span.inl
containers/stack.h
containers/unordered_map.h
containers/unordered_set.h
@@ -8,6 +8,8 @@
#pragma once
#include <AzCore/std/utils.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/typetraits/is_constructible.h>
#include <AzCore/std/typetraits/remove_cvref.h>
/* Microsoft C++ ABI puts 1 byte of padding between each empty base class when multiple inheritance is being used
@@ -20,7 +22,7 @@
#if defined(AZ_COMPILER_MSVC)
#define AZSTD_COMPRESSED_PAIR_EMPTY_BASE_OPTIMIZATION __declspec(empty_bases)
#else
#define AZSTD_COMPRESSED_PAIR_EMPTY_BASE_OPTIMIZATION
#define AZSTD_COMPRESSED_PAIR_EMPTY_BASE_OPTIMIZATION
#endif
namespace AZStd
@@ -97,16 +99,14 @@ namespace AZStd
using second_base_value_type = typename second_base_type::value_type;
public:
// First template argument is a placeholder argument of void as MSVC examines the types
// of a templated function to determine if they are the same template
// Due to the "template <class T> compressed_pair(skip_element_tag, T&&)"
// constructor below, the default constructor template types needs to be distinguished from it
template <typename = void, typename = AZStd::enable_if_t<
AZStd::is_default_constructible<first_base_value_type>::value
&& AZStd::is_default_constructible<second_base_value_type>::value>>
// First template argument is used to perform a substitution into AZStd::enable_if_t
// so that SFINAE can trigger
template <typename Unused = void, typename = AZStd::enable_if_t<
AZStd::is_default_constructible_v<first_base_value_type>
&& AZStd::is_default_constructible_v<second_base_value_type>, Unused>>
constexpr compressed_pair();
template <typename T, AZStd::enable_if_t<!is_same<remove_cvref_t<T>, compressed_pair>::value, bool> = true>
template <typename T, AZStd::enable_if_t<!is_same_v<remove_cvref_t<T>, compressed_pair>, bool> = true>
constexpr explicit compressed_pair(T&& firstElement);
template <typename T>
@@ -75,7 +75,7 @@ namespace AZStd
}
template <typename T1, typename T2>
template <typename T, AZStd::enable_if_t<!is_same<remove_cvref_t<T>, compressed_pair<T1, T2>>::value, bool>>
template <typename T, AZStd::enable_if_t<!is_same_v<remove_cvref_t<T>, compressed_pair<T1, T2>>, bool>>
inline constexpr compressed_pair<T1, T2>::compressed_pair(T&& firstElement)
: first_base_type{ AZStd::forward<T>(firstElement) }
, second_base_type{}
@@ -117,7 +117,7 @@ namespace AZStd
{
return static_cast<const first_base_type&>(*this).get();
}
template <typename T1, typename T2>
inline constexpr auto compressed_pair<T1, T2>::second() -> second_base_value_type&
{
@@ -253,7 +253,7 @@ namespace AZStd::Internal
}
template <typename U, typename = enable_if_t<is_convertible_v<U, T>>>
fixed_non_trivial_storage(AZStd::initializer_list<U> ilist) noexcept(noexcept(emplace_back(AZStd::declval<U>())))
fixed_non_trivial_storage(AZStd::initializer_list<U> ilist) noexcept(noexcept(this->emplace_back(AZStd::declval<U>())))
{
AZSTD_CONTAINER_ASSERT(ilist.size() <= capacity(), "Initializer list cannot be larger than storage capacity");
for (const U& element : ilist)
@@ -79,7 +79,7 @@ namespace AZStd
typedef typename tree_type::const_reverse_iterator const_reverse_iterator;
using node_type = map_node_handle<map_node_traits<key_type, mapped_type, allocator_type, typename tree_type::node_type, typename tree_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE explicit map(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: m_tree(comp, alloc) {}
@@ -123,7 +123,8 @@ namespace AZStd
}
}
friend void swap(node_handle& lhs, node_handle& rhs);
template <typename SwapNodeTraits, template <typename, typename> class SwapMapOrSetNodeHandleBase>
friend void swap(node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& lhs, node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& rhs);
private:
node_handle(node_pointer_type node, const allocator_type& allocator)
@@ -152,8 +153,8 @@ namespace AZStd
optional<allocator_type> m_allocator;
};
template <typename NodeTraits, template <typename, typename> class MapOrSetNodeHandleBase>
void swap(node_handle<NodeTraits, MapOrSetNodeHandleBase>& lhs, node_handle<NodeTraits, MapOrSetNodeHandleBase>& rhs)
template <typename SwapNodeTraits, template <typename, typename> class SwapMapOrSetNodeHandleBase>
void swap(node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& lhs, node_handle<SwapNodeTraits, SwapMapOrSetNodeHandleBase>& rhs)
{
lhs.swap(rhs);
}
@@ -68,7 +68,7 @@ namespace AZStd
typedef typename tree_type::const_reverse_iterator const_reverse_iterator;
using node_type = set_node_handle<set_node_traits<value_type, allocator_type, typename tree_type::node_type, typename tree_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE explicit set(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: m_tree(comp, alloc) {}
@@ -0,0 +1,129 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/fixed_vector.h>
#include <AzCore/std/containers/array.h>
namespace AZStd
{
/**
* First pass partial implementation of span copied over from array_view. It
* returns non-const iterator/pointers. first(), last(), and subspan()
* are yet to be implemented. It does not maintain storage for the data,
* but just holds pointers to mark the beginning and end of the array.
* It can be conveniently constructed from a variety of other container
* types like array, vector, and fixed_vector.
*
* Example:
* Given "void Func(AZStd::span<int> a) {...}" you can call...
* - Func({1,2,3});
* - AZStd::array<int,3> a = {1,2,3};
* Func(a);
* - AZStd::vector<int> v = {1,2,3};
* Func(v);
* - AZStd::fixed_vector<int,10> fv = {1,2,3};
* Func(fv);
*
* Since the span does not copy and store any data, it is only valid as long as the data used to create it is valid.
*/
template <class T>
class span final
{
public:
using element_type = T;
using value_type = AZStd::remove_cv_t<T>;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = AZStd::size_t;
using difference_type = AZStd::ptrdiff_t;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = AZStd::reverse_iterator<iterator>;
using const_reverse_iterator = AZStd::reverse_iterator<const_iterator>;
constexpr span();
~span() = default;
constexpr span(pointer s, size_type length);
constexpr span(pointer first, pointer last);
// We explicitly delete this constructor because it's too easy to accidentally
// create a span to just the first element instead of an entire array.
constexpr span(const_pointer s) = delete;
template<typename Container>
constexpr span(Container& data);
template<typename Container>
constexpr span(const Container& data);
constexpr span(const span&) = default;
constexpr span(span&& other);
constexpr span& operator=(const span& other) = default;
constexpr span& operator=(span&& other);
constexpr size_type size() const;
constexpr bool empty() const;
constexpr pointer data();
constexpr const_pointer data() const;
constexpr const_reference operator[](size_type index) const;
constexpr reference operator[](size_type index);
constexpr void erase();
constexpr iterator begin();
constexpr iterator end();
constexpr const_iterator begin() const;
constexpr const_iterator end() const;
constexpr const_iterator cbegin() const;
constexpr const_iterator cend() const;
constexpr reverse_iterator rbegin();
constexpr reverse_iterator rend();
constexpr const_reverse_iterator rbegin() const;
constexpr const_reverse_iterator rend() const;
constexpr const_reverse_iterator crbegin() const;
constexpr const_reverse_iterator crend() const;
friend bool operator==(span lhs, span rhs)
{
return lhs.m_begin == rhs.m_begin && lhs.m_end == rhs.m_end;
}
friend bool operator!=(span lhs, span rhs) { return !(lhs == rhs); }
friend bool operator< (span lhs, span rhs) { return lhs.m_begin < rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end < rhs.m_end; }
friend bool operator> (span lhs, span rhs) { return lhs.m_begin > rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end > rhs.m_end; }
friend bool operator<=(span lhs, span rhs) { return lhs == rhs || lhs < rhs; }
friend bool operator>=(span lhs, span rhs) { return lhs == rhs || lhs > rhs; }
private:
pointer m_begin;
pointer m_end;
};
} // namespace AZStd
#include <AzCore/std/containers/span.inl>
@@ -0,0 +1,124 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AZStd
{
template <class Element>
inline constexpr span<Element>::span()
: m_begin(nullptr)
, m_end(nullptr)
{ }
template <class Element>
inline constexpr span<Element>::span(pointer s, size_type length)
: m_begin(s)
, m_end(m_begin + length)
{
if (length == 0) erase();
}
template <class Element>
inline constexpr span<Element>::span(pointer first, pointer last)
: m_begin(first)
, m_end(last)
{ }
template<class Element>
template<typename Container>
inline constexpr span<Element>::span(Container& data)
: m_begin(data.data())
, m_end(m_begin + data.size())
{ }
template<class Element>
template<typename Container>
inline constexpr span<Element>::span(const Container& data)
: m_begin(data.data())
, m_end(m_begin + data.size())
{ }
template <class Element>
inline constexpr span<Element>::span(span&& other)
: span(other.m_begin, other.m_end)
{
#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging
other.m_begin = nullptr;
other.m_end = nullptr;
#endif
}
template <class Element>
inline constexpr AZStd::size_t span<Element>::size() const { return m_end - m_begin; }
template <class Element>
inline constexpr bool span<Element>::empty() const { return m_end == m_begin; }
template <class Element>
inline constexpr Element* span<Element>::data() { return m_begin; }
template <class Element>
inline constexpr const Element* span<Element>::data() const { return m_begin; }
template <class Element>
inline constexpr span<Element>& span<Element>::operator=(span<Element>&& other)
{
m_begin = other.m_begin;
m_end = other.m_end;
#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging
other.m_begin = nullptr;
other.m_end = nullptr;
#endif
return *this;
}
template <class Element>
inline constexpr const Element& span<Element>::operator[](AZStd::size_t index) const
{
AZ_Assert(index < size(), "index value is out of range");
return m_begin[index];
}
template <class Element>
inline constexpr Element& span<Element>::operator[](AZStd::size_t index)
{
AZ_Assert(index < size(), "index value is out of range");
return m_begin[index];
}
template <class Element>
inline constexpr void span<Element>::erase() { m_begin = m_end = nullptr; }
template <class Element>
inline constexpr Element* span<Element>::begin() { return m_begin; }
template <class Element>
inline constexpr Element* span<Element>::end() { return m_end; }
template <class Element>
inline constexpr const Element* span<Element>::begin() const { return m_begin; }
template <class Element>
inline constexpr const Element* span<Element>::end() const { return m_end; }
template <class Element>
inline constexpr const Element* span<Element>::cbegin() const { return m_begin; }
template <class Element>
inline constexpr const Element* span<Element>::cend() const { return m_end; }
template <class Element>
inline constexpr AZStd::reverse_iterator<Element*> span<Element>::rbegin() { return AZStd::reverse_iterator<Element*>(m_end); }
template <class Element>
inline constexpr AZStd::reverse_iterator<Element*> span<Element>::rend() { return AZStd::reverse_iterator<Element*>(m_begin); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::rbegin() const { return AZStd::reverse_iterator<const Element*>(m_end); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::rend() const { return AZStd::reverse_iterator<const Element*>(m_begin); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::crbegin() const { return AZStd::reverse_iterator<const Element*>(cend()); }
template <class Element>
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::crend() const { return AZStd::reverse_iterator<const Element*>(cbegin()); }
} // namespace AZStd
@@ -102,7 +102,7 @@ namespace AZStd
typedef typename base_type::pair_iter_bool pair_iter_bool;
using node_type = map_node_handle<map_node_traits<key_type, mapped_type, allocator_type, typename base_type::list_node_type, typename base_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE unordered_map()
: base_type(hasher(), key_eq(), allocator_type()) {}
@@ -87,7 +87,7 @@ namespace AZStd
typedef typename base_type::const_local_iterator const_local_iterator;
using node_type = set_node_handle<set_node_traits<value_type, allocator_type, typename base_type::list_node_type, typename base_type::node_deleter>>;
using insert_return_type = insert_return_type<iterator, node_type>;
using insert_return_type = AZStd::AssociativeInternal::insert_return_type<iterator, node_type>;
AZ_FORCE_INLINE unordered_set()
: base_type(hasher(), key_eq(), allocator_type()) {}
@@ -954,25 +954,6 @@ namespace AZStd
return true;
}
/// Validates an iter iterator. Returns a combination of \ref iterator_status_flag.
AZ_FORCE_INLINE int validate_iterator(const iterator& iter) const
{
#ifdef AZSTD_HAS_CHECKED_ITERATORS
AZ_Assert(iter.m_container == this, "Iterator doesn't belong to this container");
pointer iterPtr = iter.m_iter;
#else
pointer iterPtr = iter;
#endif
if (iterPtr < m_start || iterPtr > m_last)
{
return isf_none;
}
else if (iterPtr == m_last)
{
return isf_valid;
}
return isf_valid | isf_can_dereference;
}
AZ_FORCE_INLINE int validate_iterator(const const_iterator& iter) const
{
#ifdef AZSTD_HAS_CHECKED_ITERATORS
@@ -992,7 +973,6 @@ namespace AZStd
return isf_valid | isf_can_dereference;
}
AZ_FORCE_INLINE int validate_iterator(const reverse_iterator& iter) const { return validate_iterator(iter.base()); }
AZ_FORCE_INLINE int validate_iterator(const const_reverse_iterator& iter) const { return validate_iterator(iter.base()); }
/**
@@ -279,11 +279,11 @@ namespace AZStd
reinterpret_cast<functor_type*>(&in_buffer.data);
if (op == clone_functor_tag)
{
new ((void*)&out_buffer.data)functor_type(*in_functor);
AZStd::construct_at(reinterpret_cast<functor_type*>(&out_buffer), functor_type(*in_functor));
}
else if (op == move_functor_tag)
{
new ((void*)&out_buffer.data)functor_type(AZStd::move(*in_functor));
AZStd::construct_at(reinterpret_cast<functor_type*>(&out_buffer), functor_type(AZStd::move(*in_functor)));
// Casting via union to get around compiler warnings (strict type on GCC, unused variable on MSVC)
union
{
@@ -291,7 +291,7 @@ namespace AZStd
assign_functor(FunctionObj&& f, function_buffer& functor, AZStd::true_type)
{
using RawFunctorObjType = AZStd::decay_t<FunctionObj>;
new ((void*)&functor.data)RawFunctorObjType(AZStd::forward<FunctionObj>(f));
AZStd::construct_at(reinterpret_cast<RawFunctorObjType*>(&functor), RawFunctorObjType(AZStd::forward<FunctionObj>(f)));
}
template<typename FunctionObj, typename Allocator>
void
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/std/typetraits/typetraits.h>
#include <AzCore/std/typetraits/invoke_traits.h>
namespace AZStd
@@ -343,26 +343,6 @@ namespace AZStd
static decltype(auto) format(const wchar_t* format, ...);
protected:
template<class InputIt>
constexpr auto append_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
template<class InputIt>
constexpr auto construct_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>>;
template<class InputIt>
constexpr auto assign_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
template<class InputIt>
constexpr auto insert_iter(const_iterator insertPos, InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>;
template<class InputIt>
constexpr auto replace_iter(const_iterator first, const_iterator last, InputIt first2, InputIt last2)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
constexpr auto fits_in_capacity(size_type newSize) -> bool;
inline static constexpr size_type Capacity = MaxElementCount; // current storage reserved for string not including null-terminator
@@ -30,9 +30,8 @@ namespace AZStd
// #3
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const basic_fixed_string& rhs,
size_type rhsOffset)
size_type rhsOffset) : basic_fixed_string(rhs, rhsOffset, npos)
{ // construct from rhs [rhsOffset, npos)
assign(rhs, rhsOffset, npos);
}
// #3
@@ -40,7 +39,15 @@ namespace AZStd
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const basic_fixed_string& rhs,
size_type rhsOffset, size_type count)
{ // construct from rhs [rhsOffset, rhsOffset + count)
assign(rhs, rhsOffset, count);
AZSTD_CONTAINER_ASSERT(rhs.size() >= rhsOffset, "Invalid offset");
size_type num = AZStd::min(count, rhs.size() - rhsOffset);
// make room and assign new stuff
pointer data = m_buffer;
const_pointer rhsData = rhs.m_buffer;
Traits::copy(data, rhsData + rhsOffset, num);
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
// #4
@@ -62,28 +69,24 @@ namespace AZStd
template<class InputIt, typename>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(InputIt first, InputIt last)
{ // construct from [first, last)
if (first == last)
{
Traits::assign(m_buffer[0], Element()); // terminate
}
else
{
construct_iter(first, last);
}
assign(first, last);
}
// #7
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const basic_fixed_string& rhs)
: basic_fixed_string(rhs, size_type(0), npos)
{
assign(rhs, size_type(0), npos);
}
// #8
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(basic_fixed_string&& rhs)
{
assign(AZStd::move(rhs));
Traits::copy(m_buffer, rhs.m_buffer, rhs.size() + 1);
m_size = rhs.m_size;
rhs.m_size = 0;
Traits::assign(rhs.m_buffer[0], Element{});
}
// #9
@@ -98,8 +101,7 @@ namespace AZStd
template<typename T, typename>
inline constexpr basic_fixed_string<Element, MaxElementCount, Traits>::basic_fixed_string(const T& convertibleToView)
{
AZStd::basic_string_view<Element, Traits> view = convertibleToView;
assign(view.begin(), view.end());
assign(convertibleToView);
}
// #11
@@ -313,15 +315,7 @@ namespace AZStd
if (count > 0 && fits_in_capacity(num))
{
pointer data = m_buffer;
// make room and append new stuff using assign
if (count == 1)
{
Traits::assign(*(data + m_size), ch);
}
else
{
Traits::assign(data + m_size, count, ch);
}
Traits::assign(data + m_size, count, ch);
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
@@ -332,13 +326,47 @@ namespace AZStd
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // append [first, last)
return append_iter(first, last);
{
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
return append(AZStd::to_address(first), AZStd::distance(first, last));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be appended one by one into the buffer
size_type newSize = m_size + AZStd::distance(first, last);
if (fits_in_capacity(newSize))
{
for (size_t updateIndex = m_size; first != last; ++first, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*first));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
return *this;
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; first != last; ++first)
{
inputCopy.push_back(static_cast<Element>(*first));
}
return append(inputCopy.c_str(), inputCopy.size());
}
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append(AZStd::initializer_list<Element> ilist) -> basic_fixed_string&
{ // append [first, last)
return append_iter(ilist.begin(), ilist.end());
{
return append(ilist.begin(), ilist.size());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -420,18 +448,10 @@ namespace AZStd
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(size_type count, Element ch) -> basic_fixed_string&
{
// assign count * ch
AZSTD_CONTAINER_ASSERT(count != npos, "result is too long!");
if (fits_in_capacity(count))
{ // make room and assign new stuff
pointer data = m_buffer;
if (count == 1)
{
Traits::assign(*(data), ch);
}
else
{
Traits::assign(data, count, ch);
}
Traits::assign(data, count, ch);
m_size = static_cast<internal_size_type>(count);
Traits::assign(data[count], Element()); // terminate
}
@@ -443,12 +463,46 @@ namespace AZStd
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{
return assign_iter(first, last);
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
return assign(AZStd::to_address(first), AZStd::distance(first, last));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be assigned one by one into the buffer
size_type newSize = AZStd::distance(first, last);
if (fits_in_capacity(newSize))
{
for (size_t updateIndex = 0; first != last; ++first, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*first));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
return *this;
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; first != last; ++first)
{
inputCopy.push_back(static_cast<Element>(*first));
}
return assign(inputCopy.c_str(), inputCopy.size());
}
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(AZStd::initializer_list<Element> ilist) -> basic_fixed_string&
{
return assign_iter(ilist.begin(), ilist.end());
return assign(ilist.begin(), ilist.size());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -536,14 +590,7 @@ namespace AZStd
pointer data = m_buffer;
// make room and insert new stuff
Traits::copy_backward(data + offset + count, data + offset, m_size - offset); // empty out hole
if (count == 1)
{
Traits::assign(*(data + offset), ch);
}
else
{
Traits::assign(data + offset, count, ch);
}
Traits::assign(data + offset, count, ch);
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
@@ -582,14 +629,51 @@ namespace AZStd
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert(const_iterator insertPos,
InputIt first, InputIt last)-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
{ // insert [_First, _Last) at _Where
return insert_iter(insertPos, first, last);
size_type insertOffset = AZStd::distance(cbegin(), insertPos);
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
insert(insertOffset, AZStd::to_address(first), AZStd::distance(first, last));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be inserted one by one into the buffer
size_type count = AZStd::distance(first, last);
size_type newSize = m_size + count;
if (fits_in_capacity(newSize))
{
Traits::copy_backward(m_buffer + insertOffset + count, m_buffer + insertOffset, m_size - insertOffset); // empty out hole
for (size_t updateIndex = insertOffset; first != last; ++first, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*first));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; first != last; ++first)
{
inputCopy.push_back(static_cast<Element>(*first));
}
insert(insertOffset, inputCopy.c_str(), inputCopy.size());
}
return begin() + insertOffset;
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert(const_iterator insertPos,
AZStd::initializer_list<Element> ilist) -> iterator
{ // insert [_First, _Last) at _Where
return insert_iter(insertPos, ilist.begin(), ilist.end());
return insert(insertPos, ilist.begin(), ilist.end());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -604,7 +688,7 @@ namespace AZStd
{
// move elements down
pointer data = m_buffer;
Traits::copy(data + offset, data + offset + count, m_size - offset - count);
Traits::move(data + offset, data + offset + count, m_size - offset - count);
m_size = static_cast<internal_size_type>(m_size - count);
Traits::assign(data[m_size], Element()); // terminate
}
@@ -643,7 +727,7 @@ namespace AZStd
const basic_fixed_string& rhs) -> basic_fixed_string&
{
// replace [offset, offset + count) with rhs
return replace(offset, count, rhs, size_type(0), npos);
return replace(offset, count, rhs.c_str(), rhs.size());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -651,56 +735,7 @@ namespace AZStd
const basic_fixed_string& rhs, size_type rhsOffset, size_type rhsCount) -> basic_fixed_string&
{
// replace [offset, offset + count) with rhs [rhsOffset, rhsOffset + rhsCount)
AZSTD_CONTAINER_ASSERT(m_size >= offset && rhs.m_size >= rhsOffset, "Invalid offsets");
if (m_size - offset < count)
{
count = m_size - offset; // trim count to size
}
size_type num = rhs.m_size - rhsOffset;
if (num < rhsCount)
{
rhsCount = num; // trim rhsCount to size
}
AZSTD_CONTAINER_ASSERT(npos - rhsCount > m_size - count, "Result is too long");
size_type nm = m_size - count - offset; // length of preserved tail
size_type newSize = m_size + rhsCount - count;
if (fits_in_capacity(newSize))
{
pointer data = m_buffer;
const_pointer rhsData = rhs.m_buffer;
if (this != &rhs)
{ // no overlap, just move down and copy in new stuff
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // empty hole
Traits::copy(data + offset, rhsData + rhsOffset, rhsCount); // fill hole
}
else if (rhsCount <= count)
{ // hole doesn't get larger, just copy in substring
Traits::copy(data + offset, data + rhsOffset, rhsCount); // fill hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
}
else if (rhsOffset <= offset)
{ // hole gets larger, substring begins before hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
Traits::copy(data + offset, data + rhsOffset, rhsCount); // fill hole
}
else if (offset + count <= rhsOffset)
{ // hole gets larger, substring begins after hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
Traits::copy(data + offset, data + (rhsOffset + rhsCount - count), rhsCount); // fill hole
}
else
{ // hole gets larger, substring begins in hole
Traits::copy(data + offset, data + rhsOffset, count); // fill old hole
Traits::copy_backward(data + offset + rhsCount, data + offset + count, nm); // move tail down
Traits::copy(data + offset + count, data + rhsOffset + rhsCount, rhsCount - count); // fill rest of new hole
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(data[newSize], Element()); // terminate
}
return *this;
return replace(offset, count, rhs.c_str() + rhsOffset, AZStd::min(rhsCount, rhs.size() - rhsOffset));
}
template<class Element, size_t MaxElementCount, class Traits>
template<typename T>
@@ -720,35 +755,83 @@ namespace AZStd
pointer data = m_buffer;
// replace [offset, offset + count) with [ptr, ptr + ptrCount)
AZSTD_CONTAINER_ASSERT(m_size >= offset, "Invalid offset");
if (m_size - offset < count)
{
count = m_size - offset; // trim _N0 to size
}
AZSTD_CONTAINER_ASSERT(npos - ptrCount > m_size - count, "Result too long");
// Make sure count is within is no larger than the distance from the offset
// to the end of this string
count = AZStd::min(count, m_size - offset);
size_type nm = m_size - count - offset;
if (ptrCount < count)
size_type newSize = m_size + ptrCount - count;
if (fits_in_capacity(newSize))
{
Traits::copy(data + offset + ptrCount, data + offset + count, nm); // smaller hole, move tail up
}
size_type num = m_size + ptrCount - count;
if ((0 != ptrCount || 0 != count) && fits_in_capacity(num))
{
data = m_buffer;
// make room and rearrange
if (count < ptrCount)
// The code assumes that compile time evaluation will not need to deal with overlapping input
size_type charsAfterCountToMove = m_size - count - offset;
if (az_builtin_is_constant_evaluated() || !((ptr >= data + offset && ptr < data + offset + count)
|| (ptr + ptrCount > data + offset && ptr + ptrCount <= data + offset + count)))
{
Traits::copy_backward(data + offset + ptrCount, data + offset + count, nm); // move tail down
// Ex1. this = "ABCDEFG", offset = 1, count = 4
// Input string is "CDE"
// First the text post offset + count is moved to right after the input string will be copied
// "ABCDFG"
// ^^^
// Next the input string is copied into the buffer
// "ACDEFG"
//
// Ex2. this = "ABCDEFG", offset = 1, count = 2
// Input string is "CDE"
// Performing the same two steps above, the string transform as follows
// "ABCDEFG" -> "ABCDDEFG" -> "ACDEDEFG"
// ^^^
if (count != ptrCount)
{
Traits::move(data + offset + ptrCount, data + offset + count, charsAfterCountToMove);
}
if (ptrCount > 0)
{
// Copy bytes up to the minimum of this string count and input string count
Traits::copy(data + offset, ptr, ptrCount);
}
}
if (ptrCount > 0)
else
{
Traits::copy(data + offset, ptr, ptrCount); // fill hole
// Overlap checks for fixed_string only needs to check between this string
// [offset, offset + count) due to fixed_string never moving memory
//
// Ex. this = "ABCDEFG", offset = 1, count=4
// substring is "CDE"
// The text from offset 1 for 4 chars "BCDE": should be replaced with "CDE"
// making a whole for the bytes results in output = "ABCDFG"
// Afterwards output = "ACDEFG"
// The input string overlaps with this string in this case
// So the string is copied piecewise
if (ptrCount <= count)
{ // hole doesn't get larger, just copy in substring
Traits::move(data + offset, ptr, ptrCount); // fill hole
Traits::copy(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
}
else
{
if (ptr <= data + offset)
{ // hole gets larger, substring begins before hole
Traits::copy_backward(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
Traits::copy(data + offset, ptr, ptrCount); // fill hole
}
else if (data + offset + count <= ptr)
{ // hole gets larger, substring begins after hole
Traits::copy_backward(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
Traits::copy(data + offset, ptr + (ptrCount - count), ptrCount); // fill hole
}
else
{ // hole gets larger, substring begins in hole
Traits::copy(data + offset, ptr, count); // fill old hole
Traits::copy_backward(data + offset + ptrCount, data + offset + count, charsAfterCountToMove); // move tail down
Traits::copy(data + offset + count, ptr + ptrCount, ptrCount - count); // fill rest of new hole
}
}
}
m_size = static_cast<internal_size_type>(num);
Traits::assign(data[num], Element()); // terminate
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(data[newSize], Element()); // terminate
return *this;
}
@@ -793,14 +876,7 @@ namespace AZStd
{
Traits::copy_backward(data + offset + num, data + offset + count, nm); // move tail down
}
if (count == 1)
{
Traits::assign(*(data + offset), ch);
}
else
{
Traits::assign(data + offset, num, ch);
}
Traits::assign(data + offset, num, ch);
m_size = static_cast<internal_size_type>(numToGrow);
Traits::assign(data[numToGrow], Element()); // terminate
}
@@ -851,15 +927,54 @@ namespace AZStd
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace(const_iterator first, const_iterator last,
InputIt first2, InputIt last2) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // replace [first, last) with [first2,last2)
return replace_iter(first, last, first2, last2);
InputIt replaceFirst, InputIt replaceLast) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // replace [first, last) with [replaceFirst,replaceLast)
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
{
return replace(first, last, AZStd::to_address(replaceFirst), AZStd::distance(replaceFirst, replaceLast));
}
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
{
// Input Iterator pointer type doesn't match the const_pointer type
// So the elements need to be appended one by one into the buffer
size_type insertOffset = AZStd::distance(cbegin(), first);
size_type postInsertOffset = AZStd::distance(cbegin(), last);
size_type count = AZStd::distance(replaceFirst, replaceLast);
size_type newSize = m_size + count - AZStd::distance(first, last);
if (fits_in_capacity(newSize))
{
Traits::move(first + count, last, m_size - postInsertOffset); // empty out hole
for (size_t updateIndex = insertOffset; replaceFirst != replaceLast; ++replaceFirst, ++updateIndex)
{
Traits::assign(m_buffer[updateIndex], static_cast<Element>(*replaceFirst));
}
m_size = static_cast<internal_size_type>(newSize);
Traits::assign(m_buffer[newSize], Element()); // terminate
}
return *this;
}
else
{
// input iterator that aren't forward iterators can only be used in a single pass
// algorithm. Therefore AZStd::distance can't be used
// So the input is copied into a local string and then delegated
// to use the (const_pointer, size_type) overload
basic_fixed_string inputCopy;
for (; replaceFirst != replaceLast; ++replaceFirst)
{
inputCopy.push_back(static_cast<Element>(*replaceFirst));
}
return replace(first, last, inputCopy.c_str(), inputCopy.size());
}
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace(const_iterator first, const_iterator last,
AZStd::initializer_list<Element> ilist) -> basic_fixed_string&
{ // replace [first, last) with [first2,last2)
return replace_iter(first, last, ilist.begin(), ilist.end());
{
return replace(first, last, ilist.begin(), ilist.end());
}
template<class Element, size_t MaxElementCount, class Traits>
@@ -1411,54 +1526,6 @@ namespace AZStd
return result;
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::construct_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>>
{
// initialize from [first, last), input iterators
for (; first != last; ++first)
{
append((size_type)1, (Element)* first);
}
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // append [first, last), input iterators
return replace(end(), end(), first, last);
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign_iter(InputIt first, InputIt last)
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{
return replace(begin(), end(), first, last);
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert_iter(const_iterator insertPos, InputIt first,
InputIt last) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
{ // insert [first, last) at insertPos, input iterators
difference_type offset = insertPos - cbegin();
replace(insertPos, insertPos, first, last);
return iterator(m_buffer + offset);
}
template<class Element, size_t MaxElementCount, class Traits>
template<class InputIt>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace_iter(const_iterator first, const_iterator last,
InputIt first2, InputIt last2) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
{ // replace [first, last) with [first2, last2), input iterators
basic_fixed_string rhs(first2, last2);
replace(first, last, rhs);
return *this;
}
template<class Element, size_t MaxElementCount, class Traits>
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::fits_in_capacity(size_type newSize)-> bool
{
@@ -1703,7 +1770,8 @@ namespace AZStd
template<class Element, size_t MaxElementCount, class Traits>
struct hash<basic_fixed_string<Element, MaxElementCount, Traits>>
{
inline constexpr size_t operator()(const basic_fixed_string<Element, MaxElementCount, Traits>& value) const
using is_transparent = void;
inline constexpr size_t operator()(const basic_string_view<Element, Traits>& value) const
{
return hash_string(value.begin(), value.length());
}
File diff suppressed because it is too large Load Diff
@@ -280,45 +280,99 @@ namespace AZStd
static constexpr char_type* assign(char_type* dest, size_t count, char_type ch) noexcept
{
AZ_Assert(dest, "Invalid input!");
for (char_type* iter = dest; count; --count, ++iter)
if constexpr (AZStd::is_same_v<char_type, char>)
{
assign(*iter, ch);
// Use builtin_memset if available for char type
if (az_builtin_is_constant_evaluated())
{
for (char_type* iter = dest; count; --count, ++iter)
{
assign(*iter, ch);
}
}
else
{
::memset(dest, ch, count);
}
}
else
{
for (char_type* iter = dest; count; --count, ++iter)
{
assign(*iter, ch);
}
}
return dest;
}
static constexpr bool eq(char_type left, char_type right) noexcept { return left == right; }
static constexpr bool lt(char_type left, char_type right) noexcept { return left < right; }
static constexpr int compare(const char_type* s1, const char_type* s2, size_t count) noexcept
static constexpr int compare(const char_type* s1, const char_type* s2, size_t count) noexcept
{
// In GCC versions prior to major version 10, __builtin_memcmp fails in valid checks in constexpr evaluation
#if !defined(AZ_COMPILER_GCC) || AZ_COMPILER_GCC >= 100000
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_memcmp(s1, s2, count);
}
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
return __builtin_wmemcmp(s1, s2, count);
} else
#endif
{
if (az_builtin_is_constant_evaluated())
{
for (; count; --count, ++s1, ++s2)
{
if (lt(*s1, *s2))
{
return -1;
}
else if (lt(*s2, *s1))
{
return 1;
}
}
return 0;
}
else
{
return ::memcmp(s1, s2, count * sizeof(char_type));
}
}
}
static constexpr size_t length(const char_type* s) noexcept
{
// Regression in VS2017 15.8 and 15.9 where __builtin_memcmp fails in valid checks in constexpr evaluation
#if !defined(AZ_COMPILER_MSVC) || AZ_COMPILER_MSVC < 1915 || AZ_COMPILER_MSVC > 1916
// For GCC versions less than 10, __builtin_strlen and __builtin_wcslen is not supported as const expressions
// so for that case it will need to manually count the characters (at compile time) instead
#if defined(AZ_COMPILER_GCC) && AZ_COMPILER_GCC < 100000
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_memcmp(s1, s2, count);
if (!az_builtin_is_constant_evaluated())
{
return strlen(s);
}
}
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
return __builtin_wmemcmp(s1, s2, count);
}
else
#endif
{
for (; count; --count, ++s1, ++s2)
if (!az_builtin_is_constant_evaluated())
{
if (lt(*s1, *s2))
{
return -1;
}
else if (lt(*s2, *s1))
{
return 1;
}
return wcslen(s);
}
return 0;
}
}
static constexpr size_t length(const char_type* s) noexcept
{
size_t strLength{};
for (; *s; ++s, ++strLength)
{
;
}
return strLength;
#else
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_strlen(s);
@@ -336,13 +390,39 @@ namespace AZStd
}
return strLength;
}
#endif // defined(AZ_COMPILER_GCC) && AZ_COMPILER_GCC < 100000
}
static constexpr const char_type* find(const char_type* s, size_t count, const char_type& ch) noexcept
{
// There is a bug with the __builtin_char_memchr intrinsic in Visual Studio 2017 15.8.x and 15.9.x
// It reads in one more additional character than the value of count.
// This is probably due to assuming null-termination
#if !defined(AZ_COMPILER_MSVC) || AZ_COMPILER_MSVC < 1915 || AZ_COMPILER_MSVC > 1916
// For GCC versions less than 10, __builtin_char_memchr and __builtin_wmemchr is not supported, and
// __builtin_memchr is not supported as const expressions. In those cases we will manually locate and
// return the pointer to 's' (at compile time)
#if defined(AZ_COMPILER_GCC) && AZ_COMPILER_GCC < 100000
if constexpr (AZStd::is_same_v<char_type, char>)
{
if (!az_builtin_is_constant_evaluated())
{
return static_cast<const char_type*>(__builtin_memchr(s, ch, count));
}
}
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
if (!az_builtin_is_constant_evaluated())
{
return wmemchr(s, ch, count);
}
}
for (; count; --count, ++s)
{
if (eq(*s, ch))
{
return s;
}
}
return nullptr;
#else
if constexpr (AZStd::is_same_v<char_type, char>)
{
return __builtin_char_memchr(s, ch, count);
@@ -350,10 +430,8 @@ namespace AZStd
else if constexpr (AZStd::is_same_v<char_type, wchar_t>)
{
return __builtin_wmemchr(s, ch, count);
}
else
#endif
{
for (; count; --count, ++s)
{
@@ -364,68 +442,116 @@ namespace AZStd
}
return nullptr;
}
#endif
}
static constexpr char_type* move(char_type* dest, const char_type* src, size_t count) noexcept
{
AZ_Assert(dest != nullptr && src != nullptr, "Invalid input!");
if (count == 0)
if (count == 0 || src == dest)
{
return dest;
}
char_type* result = dest;
// The less than(<), greater than(>) and other variants(<=, >=)
// Cannot be compare pointers within a constexpr due to the potential for undefined behavior
// per the bullet linked in the C++ standard at http://eel.is/c++draft/expr.compound#expr.rel-5
// Now clang and gcc compilers allow the use of this relation operators in a constexpr, but
// msvc is not so forgiving
// So a workaround of iterating the src pointer, checking for equality with the dest pointer
// is used to check for overlap
auto should_copy_forward = [](const char_type* dest1, const char_type* src2, size_t count2) constexpr -> bool
#if az_has_builtin_memmove
__builtin_memmove(dest, src, count * sizeof(char_type));
#else
auto NonBuiltinMove = [](char_type* dest1, const char_type* src1, size_t count1) constexpr
-> char_type*
{
bool dest_less_than_src{ true };
for(const char_type* src_iter = src2; src_iter != src2 + count2; ++src_iter)
if (az_builtin_is_constant_evaluated())
{
if (src_iter == dest1)
// The less than(<), greater than(>) and other variants(<=, >=)
// Cannot be compare pointers within a constexpr due to the potential for undefined behavior
// per the bullet linked in the C++ standard at http://eel.is/c++draft/expr.compound#expr.rel-5
// Now clang and gcc compilers allow the use of this relation operators in a constexpr, but
// msvc is not so forgiving
// So a workaround of iterating the src pointer, checking for equality with the dest pointer
// is used to check for overlap
auto should_copy_forward = [](const char_type* dest2, const char_type* src2, size_t count2) constexpr -> bool
{
dest_less_than_src = false;
break;
bool dest_less_than_src{ true };
for (const char_type* src_iter = src2; src_iter != src2 + count2; ++src_iter)
{
if (src_iter == dest2)
{
dest_less_than_src = false;
break;
}
}
return dest_less_than_src;
};
if (should_copy_forward(dest1, src1, count1))
{
copy(dest1, src1, count1);
}
else
{
copy_backward(dest1, src1, count1);
}
}
return dest_less_than_src;
else
{
// Use the faster ::memmove operation at runtime
::memmove(dest1, src1, count1 * sizeof(char_type));
}
return dest1;
};
NonBuiltinMove(dest, src, count);
#endif
if (should_copy_forward(dest, src, count))
{
copy(dest, src, count);
}
else
{
copy_backward(dest, src, count);
}
return result;
return dest;
}
static constexpr char_type* copy(char_type* dest, const char_type* src, size_t count) noexcept
{
AZ_Assert(dest != nullptr && src != nullptr, "Invalid input!");
char_type* result = dest;
for(; count; --count, ++dest, ++src)
#if az_has_builtin_memcpy
__builtin_memcpy(dest, src, count * sizeof(char_type));
#else
auto NonBuiltinCopy = [](char_type* dest1, const char_type* src1, size_t count1) constexpr
-> char_type*
{
assign(*dest, *src);
}
return result;
if (az_builtin_is_constant_evaluated())
{
for (; count1; --count1, ++dest1, ++src1)
{
assign(*dest1, *src1);
}
}
else
{
AZ_Assert(dest1 != nullptr && src1 != nullptr, "Invalid input!");
::memcpy(dest1, src1, count1 * sizeof(char_type));
}
return dest1;
};
NonBuiltinCopy(dest, src, count);
#endif
return dest;
}
// Extension for constexpr workarounds: Addresses of a string literal cannot be compared at compile time and MSVC and clang will just refuse to compile the constexpr
// Adding a copy_backwards overload that always copies backwards.
static constexpr char_type* copy_backward(char_type* dest, const char_type*src, size_t count) noexcept
static constexpr char_type* copy_backward(char_type* dest, const char_type* src, size_t count) noexcept
{
char_type* result = dest;
dest += count;
src += count;
for (; count; --count)
#if az_has_builtin_memmove
__builtin_memmove(dest, src, count * sizeof(char_type));
#else
if (az_builtin_is_constant_evaluated())
{
assign(*--dest, *--src);
dest += count;
src += count;
for (; count; --count)
{
assign(*--dest, *--src);
}
}
else
{
::memmove(dest, src, count);
}
#endif
return result;
}
@@ -7,6 +7,7 @@
*/
#pragma once
#include <AzCore/std/typetraits/typetraits.h>
#include <AzCore/std/typetraits/conditional.h>
#include <AzCore/std/typetraits/integral_constant.h> // for true_type
@@ -58,14 +58,13 @@
# define AZSTD_IS_ABSTRACT(T) __is_abstract(T)
# define AZSTD_IS_BASE_OF(T, U) (__is_base_of(T, U) && !is_same<T, U>::value)
# define AZSTD_IS_CLASS(T) __is_class(T)
// This one doesn't quite always do the right thing:
# define AZSTD_IS_CONVERTIBLE(_From, _To) __is_convertible_to(_From, _To)
# define AZSTD_IS_ENUM(T) __is_enum(T)
// This one doesn't quite always do the right thing:
# define AZSTD_IS_CONVERTIBLE(_From, _To) __is_convertible_to(_From, _To)
// # define AZSTD_IS_POLYMORPHIC(T) __is_polymorphic(T)
#endif
#if defined(AZ_COMPILER_CLANG)
#if defined(AZ_COMPILER_CLANG) || defined(AZ_COMPILER_GCC)
# include <AzCore/std/typetraits/is_same.h>
# include <AzCore/std/typetraits/is_reference.h>
# include <AzCore/std/typetraits/is_volatile.h>
@@ -86,8 +85,8 @@
# define AZSTD_IS_ABSTRACT(T) __is_abstract(T)
# define AZSTD_IS_BASE_OF(T, U) (__is_base_of(T, U) && !is_same<T, U>::value)
# define AZSTD_IS_CLASS(T) __is_class(T)
# define AZSTD_IS_CONVERTIBLE(_From, _To) __is_convertible_to(_From, _To)
# define AZSTD_IS_ENUM(T) __is_enum(T)
# define AZSTD_IS_CONVERTIBLE(_From, _To) AZStd::is_convertible_v<_From, _To>
# define AZSTD_IS_POLYMORPHIC(T) __is_polymorphic(T)
#endif
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
// Variadic MACROS util functions
/**
* AZ_VA_NUM_ARGS
* counts number of parameters (up to 10).
* example. AZ_VA_NUM_ARGS(x,y,z) -> expands to 3
*/
#ifndef AZ_VA_NUM_ARGS
# define AZ_VA_HAS_ARGS(...) ""#__VA_ARGS__[0] != 0
// we add the zero to avoid the case when we require at least 1 param at the end...
# define AZ_VA_NUM_ARGS(...) AZ_VA_NUM_ARGS_IMPL_((__VA_ARGS__, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
# define AZ_VA_NUM_ARGS_IMPL_(tuple) AZ_VA_NUM_ARGS_IMPL tuple
# define AZ_VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, N, ...) N
// Expands a macro and calls a different macro based on the number of arguments.
//
// Example: We need to specialize a macro for 1 and 2 arguments
// #define AZ_MY_MACRO(...) AZ_MACRO_SPECIALIZE(AZ_MY_MACRO_,AZ_VA_NUM_ARGS(__VA_ARGS__),(__VA_ARGS__))
//
// #define AZ_MY_MACRO_1(_1) /* code for 1 param */
// #define AZ_MY_MACRO_2(_1,_2) /* code for 2 params */
// ... etc.
//
//
// We have 3 levels of macro expansion...
# define AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS) MACRO_NAME##NPARAMS PARAMS
# define AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_II(MACRO_NAME, NPARAMS, PARAMS)
# define AZ_MACRO_SPECIALIZE(MACRO_NAME, NPARAMS, PARAMS) AZ_MACRO_SPECIALIZE_I(MACRO_NAME, NPARAMS, PARAMS)
#endif // AZ_VA_NUM_ARGS
// Out of all supported compilers, mwerks is the only one
// that requires variadic macros to have at least 1 param.
// This is a pain they we use macros to call functions (with no params).
// we implement functions for up to 10 params
#define AZ_FUNCTION_CALL_1(_1) _1()
#define AZ_FUNCTION_CALL_2(_1, _2) _1(_2)
#define AZ_FUNCTION_CALL_3(_1, _2, _3) _1(_2, _3)
#define AZ_FUNCTION_CALL_4(_1, _2, _3, _4) _1(_2, _3, _4)
#define AZ_FUNCTION_CALL_5(_1, _2, _3, _4, _5) _1(_2, _3, _4, _5)
#define AZ_FUNCTION_CALL_6(_1, _2, _3, _4, _5, _6) _1(_2, _3, _4, _5, _6)
#define AZ_FUNCTION_CALL_7(_1, _2, _3, _4, _5, _6, _7) _1(_2, _3, _4, _5, _6, _7)
#define AZ_FUNCTION_CALL_8(_1, _2, _3, _4, _5, _6, _7, _8) _1(_2, _3, _4, _5, _6, _7, _8)
#define AZ_FUNCTION_CALL_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) _1(_2, _3, _4, _5, _6, _7, _8, _9)
#define AZ_FUNCTION_CALL_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) _1(_2, _3, _4, _5, _6, _7, _8, _9, _10)
// We require at least 1 param FunctionName
#define AZ_FUNCTION_CALL(...) AZ_MACRO_SPECIALIZE(AZ_FUNCTION_CALL_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
// Based on boost macro expansion fix...
#define AZ_PREVENT_MACRO_SUBSTITUTION