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