Merge branch 'development' into cmake/warn_virtual
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
namespace AZ {
|
||||
struct Uuid;
|
||||
|
||||
@@ -8,14 +8,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// This is disabled by default because it puts in costly runtime checking of casted values.
|
||||
// You can either change it here to enable it across the engine, or use push/pop_macro to enable per file/feature.
|
||||
// Note that if using push/pop_macro, you may get some of the functions not inline and the definition coming from
|
||||
// another compilation unit, in such case, you will have to push/pop_macro on that compilation unit as well.
|
||||
// #define AZ_NUMERICCAST_ENABLED 1
|
||||
|
||||
#if !AZ_NUMERICCAST_ENABLED
|
||||
|
||||
#define aznumeric_cast static_cast
|
||||
|
||||
#else
|
||||
|
||||
#include <AzCore/Casting/numeric_cast_internal.h>
|
||||
#include <AzCore/std/typetraits/is_arithmetic.h>
|
||||
#include <AzCore/std/typetraits/is_class.h>
|
||||
#include <AzCore/std/typetraits/is_enum.h>
|
||||
#include <AzCore/std/typetraits/is_floating_point.h>
|
||||
#include <AzCore/std/typetraits/is_integral.h>
|
||||
#include <AzCore/std/typetraits/is_same.h>
|
||||
#include <AzCore/std/typetraits/is_signed.h>
|
||||
#include <AzCore/std/typetraits/is_unsigned.h>
|
||||
#include <AzCore/std/typetraits/remove_cvref.h>
|
||||
#include <AzCore/std/typetraits/underlying_type.h>
|
||||
#include <AzCore/std/utils.h>
|
||||
@@ -28,7 +39,7 @@
|
||||
// enabled.
|
||||
//
|
||||
// Because we can't do partial function specialization, I'm using enable_if to chop up the implementation into one of these
|
||||
// implementations. If none of these fit, then we will get a compile error because it is an unknown conversionr.
|
||||
// implementations. If none of these fit, then we will get a compile error because it is an unknown conversion.
|
||||
//
|
||||
//--------------------------------------------
|
||||
// TYPE <- TYPE DigitLoss
|
||||
@@ -51,85 +62,7 @@
|
||||
// (K) Floating Floating Y
|
||||
*/
|
||||
|
||||
// This is disabled by default because it puts in costly runtime checking of casted values.
|
||||
// You can either change it here to enable it across the engine, or use push/pop_macro to enable per file/feature.
|
||||
// Note that if using push/pop_macro, you may get some of the functions not inline and the definition coming from
|
||||
// another compilation unit, in such case, you will have to push/pop_macro on that compilation unit as well.
|
||||
// #define AZ_NUMERICCAST_ENABLED 1
|
||||
|
||||
#if AZ_NUMERICCAST_ENABLED
|
||||
#define AZ_NUMERIC_ASSERT(expr, ...) AZ_Assert(expr, __VA_ARGS__)
|
||||
#else
|
||||
#define AZ_NUMERIC_ASSERT(expr, ...) void(0)
|
||||
#endif
|
||||
|
||||
#pragma push_macro("max")
|
||||
#undef max
|
||||
|
||||
namespace NumericCastInternal
|
||||
{
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value
|
||||
, bool> ::type UnderflowsToType(const FromType& value)
|
||||
{
|
||||
return (value < static_cast<FromType>(std::numeric_limits<ToType>::lowest()));
|
||||
}
|
||||
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value
|
||||
, bool> ::type UnderflowsToType(const FromType& value)
|
||||
{
|
||||
return (static_cast<ToType>(value) < std::numeric_limits<ToType>::lowest());
|
||||
}
|
||||
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value
|
||||
, bool> ::type OverflowsToType(const FromType& value)
|
||||
{
|
||||
return (value > static_cast<FromType>(std::numeric_limits<ToType>::max()));
|
||||
}
|
||||
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value
|
||||
, bool> ::type OverflowsToType(const FromType& value)
|
||||
{
|
||||
return (static_cast<ToType>(value) > std::numeric_limits<ToType>::max());
|
||||
}
|
||||
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value
|
||||
&& std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits
|
||||
&& AZStd::is_signed<FromType>::value && AZStd::is_unsigned<ToType>::value
|
||||
, bool> ::type FitsInToType(const FromType& value)
|
||||
{
|
||||
return !NumericCastInternal::UnderflowsToType<ToType>(value);
|
||||
}
|
||||
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value
|
||||
&& (std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits)
|
||||
&& AZStd::is_unsigned<FromType>::value
|
||||
, bool> ::type FitsInToType(const FromType& value)
|
||||
{
|
||||
return !NumericCastInternal::OverflowsToType<ToType>(value);
|
||||
}
|
||||
|
||||
template <typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
(!AZStd::is_integral<FromType>::value || !AZStd::is_integral<ToType>::value)
|
||||
|| ((std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits) && (AZStd::is_unsigned<FromType>::value || AZStd::is_signed<ToType>::value))
|
||||
|| ((std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits) && AZStd::is_signed<FromType>::value)
|
||||
, bool> ::type FitsInToType(const FromType& value)
|
||||
{
|
||||
return !NumericCastInternal::OverflowsToType<ToType>(value) && !NumericCastInternal::UnderflowsToType<ToType>(value);
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
// INTEGER -> INTEGER
|
||||
// (A) Not losing digits or risking sign loss
|
||||
@@ -276,8 +209,10 @@ inline constexpr auto aznumeric_cast(FromType&& value) ->
|
||||
return static_cast<ToType>(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// This is a helper class that lets us induce the destination type of a numeric cast
|
||||
// It should never be directly used by anything other than azlossy_caster.
|
||||
// It should never be directly used by anything other than aznumeric_caster.
|
||||
namespace AZ
|
||||
{
|
||||
template <typename FromType>
|
||||
@@ -295,7 +230,7 @@ namespace AZ
|
||||
|
||||
FromType m_value;
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
// This is the primary function we should use when doing numeric casting, since it induces the
|
||||
// type we need to cast to from the code rather than requiring an explicit coupling in the source.
|
||||
@@ -305,4 +240,3 @@ inline constexpr AZ::NumericCasted<FromType> aznumeric_caster(FromType value)
|
||||
return AZ::NumericCasted<FromType>(value);
|
||||
}
|
||||
|
||||
#pragma pop_macro("max")
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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/typetraits/conditional.h>
|
||||
#include <AzCore/std/typetraits/is_floating_point.h>
|
||||
#include <AzCore/std/typetraits/is_integral.h>
|
||||
#include <AzCore/std/typetraits/is_signed.h>
|
||||
#include <AzCore/std/typetraits/is_unsigned.h>
|
||||
#include <limits>
|
||||
|
||||
namespace NumericCastInternal
|
||||
{
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value, bool>::type
|
||||
UnderflowsToType(const FromType& value)
|
||||
{
|
||||
return (value < static_cast<FromType>(std::numeric_limits<ToType>::lowest()));
|
||||
}
|
||||
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value, bool>::type
|
||||
UnderflowsToType(const FromType& value)
|
||||
{
|
||||
return (static_cast<ToType>(value) < std::numeric_limits<ToType>::lowest());
|
||||
}
|
||||
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<!AZStd::is_integral<FromType>::value || !AZStd::is_floating_point<ToType>::value, bool>::type
|
||||
OverflowsToType(const FromType& value)
|
||||
{
|
||||
return (value > static_cast<FromType>(std::numeric_limits<ToType>::max()));
|
||||
}
|
||||
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<AZStd::is_integral<FromType>::value && AZStd::is_floating_point<ToType>::value, bool>::type
|
||||
OverflowsToType(const FromType& value)
|
||||
{
|
||||
return (static_cast<ToType>(value) > std::numeric_limits<ToType>::max());
|
||||
}
|
||||
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value &&
|
||||
std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits && AZStd::is_signed<FromType>::value &&
|
||||
AZStd::is_unsigned<ToType>::value,
|
||||
bool>::type
|
||||
FitsInToType(const FromType& value)
|
||||
{
|
||||
return !NumericCastInternal::UnderflowsToType<ToType>(value);
|
||||
}
|
||||
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
AZStd::is_integral<FromType>::value && AZStd::is_integral<ToType>::value &&
|
||||
(std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits) && AZStd::is_unsigned<FromType>::value,
|
||||
bool>::type
|
||||
FitsInToType(const FromType& value)
|
||||
{
|
||||
return !NumericCastInternal::OverflowsToType<ToType>(value);
|
||||
}
|
||||
|
||||
template<typename ToType, typename FromType>
|
||||
inline constexpr typename AZStd::enable_if<
|
||||
(!AZStd::is_integral<FromType>::value || !AZStd::is_integral<ToType>::value) ||
|
||||
((std::numeric_limits<FromType>::digits <= std::numeric_limits<ToType>::digits) &&
|
||||
(AZStd::is_unsigned<FromType>::value || AZStd::is_signed<ToType>::value)) ||
|
||||
((std::numeric_limits<FromType>::digits > std::numeric_limits<ToType>::digits) && AZStd::is_signed<FromType>::value),
|
||||
bool>::type
|
||||
FitsInToType(const FromType& value)
|
||||
{
|
||||
return !NumericCastInternal::OverflowsToType<ToType>(value) && !NumericCastInternal::UnderflowsToType<ToType>(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,8 +84,9 @@ namespace AZ
|
||||
static TypeId genericComponentWrapperTypeId("{68D358CA-89B9-4730-8BA6-E181DEA28FDE}");
|
||||
for (auto& [componentKey, component] : componentMap)
|
||||
{
|
||||
// if underlying type is genericComponentWrapperTypeId, the template is null and the component should not be addded
|
||||
if (component->GetUnderlyingComponentType() != genericComponentWrapperTypeId)
|
||||
// if the component didn't serialize (i.e. is null) or the underlying type is genericComponentWrapperTypeId, the
|
||||
// template is null and the component should not be addded
|
||||
if (component && (component->GetUnderlyingComponentType() != genericComponentWrapperTypeId))
|
||||
{
|
||||
entityInstance->m_components.emplace_back(component);
|
||||
}
|
||||
|
||||
@@ -256,8 +256,22 @@ namespace AZ::IO
|
||||
|
||||
template <typename PathResultType>
|
||||
static constexpr void MakeRelativeTo(PathResultType& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base);
|
||||
template <typename PathResultType>
|
||||
static constexpr void LexicallyNormalInplace(PathResultType& pathResult, const AZ::IO::PathView& path);
|
||||
|
||||
struct PathIterable;
|
||||
//! Returns a structure that provides a view of the path parts which can be used for iteration
|
||||
//! Only the path parts that correspond to creating an normalized path is returned
|
||||
//! This function is useful for returning a "view" into a normalized path without the need
|
||||
//! to allocate memory for the heap
|
||||
static constexpr PathIterable GetNormalPathParts(const AZ::IO::PathView& path) noexcept;
|
||||
// joins the input path to the Path Iterable structure using similiar logic to Path::Append
|
||||
// If the input path is absolute it will replace the current PathIterable otherwise
|
||||
// the input path will be appended to the Path Iterable structure
|
||||
// For example a PathIterable with parts = ['C:', '/', 'foo']
|
||||
// If the path input = 'bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar']
|
||||
// If the path input = 'C:/bar', then the new PathIterable parts = [C:', '/', 'bar']
|
||||
// If the path input = 'C:bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar' ]
|
||||
// If the path input = 'D:bar', then the new PathIterable parts = [D:, 'bar' ]
|
||||
static constexpr void AppendNormalPathParts(PathIterable& pathIterableResult, const AZ::IO::PathView& path) noexcept;
|
||||
|
||||
constexpr int compare_string_view(AZStd::string_view other) const;
|
||||
constexpr AZStd::string_view root_name_view() const;
|
||||
@@ -442,14 +456,15 @@ namespace AZ::IO
|
||||
constexpr void swap(BasicPath& rhs) noexcept;
|
||||
|
||||
// native format observers
|
||||
constexpr const string_type& Native() const noexcept;
|
||||
constexpr const string_type& Native() const& noexcept;
|
||||
constexpr const string_type&& Native() const&& noexcept;
|
||||
constexpr const value_type* c_str() const noexcept;
|
||||
constexpr explicit operator string_type() const;
|
||||
|
||||
// Adds support for retrieving a modifiable copy of the underlying string
|
||||
// Any modifications to the string invalidates existing PathIterators
|
||||
constexpr string_type& Native() noexcept;
|
||||
constexpr explicit operator string_type&() noexcept;
|
||||
constexpr string_type& Native() & noexcept;
|
||||
constexpr string_type&& Native() && noexcept;
|
||||
|
||||
//! The string and wstring functions cannot be constexpr until AZStd::basic_string is made constexpr.
|
||||
//! This cannot occur until C++20 as operator new/delete cannot be used within constexpr functions
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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/array.h>
|
||||
#include <AzCore/IO/Path/PathParser.inl>
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
struct PathView::PathIterable
|
||||
{
|
||||
inline static constexpr size_t MaxPathParts = 64;
|
||||
using PartKindPair = AZStd::pair<AZStd::string_view, AZ::IO::parser::PathPartKind>;
|
||||
using PartKindArray = AZStd::array<PartKindPair, MaxPathParts>;
|
||||
constexpr PathIterable() = default;
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept;
|
||||
constexpr auto size() const noexcept-> size_t;
|
||||
constexpr auto begin() noexcept-> PartKindArray::iterator;
|
||||
constexpr auto begin() const noexcept -> PartKindArray::const_iterator;
|
||||
constexpr auto cbegin() const noexcept -> PartKindArray::const_iterator;
|
||||
constexpr auto end() noexcept -> PartKindArray::iterator;
|
||||
constexpr auto end() const noexcept -> PartKindArray::const_iterator;
|
||||
constexpr auto cend() const noexcept -> PartKindArray::const_iterator;
|
||||
constexpr auto rbegin() noexcept -> PartKindArray::reverse_iterator;
|
||||
constexpr auto rbegin() const noexcept -> PartKindArray::const_reverse_iterator;
|
||||
constexpr auto crbegin() const noexcept -> PartKindArray::const_reverse_iterator;
|
||||
constexpr auto rend() noexcept -> PartKindArray::reverse_iterator;
|
||||
constexpr auto rend() const noexcept -> PartKindArray::const_reverse_iterator;
|
||||
constexpr auto crend() const noexcept -> PartKindArray::const_reverse_iterator;
|
||||
|
||||
[[nodiscard]] constexpr bool IsAbsolute() const noexcept;
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
constexpr PartKindPair& emplace_back(Args&&... args) noexcept;
|
||||
constexpr void pop_back() noexcept;
|
||||
constexpr const PartKindPair& back() const noexcept;
|
||||
constexpr PartKindPair& back() noexcept;
|
||||
|
||||
constexpr const PartKindPair& front() const noexcept;
|
||||
constexpr PartKindPair& front() noexcept;
|
||||
|
||||
constexpr void clear() noexcept;
|
||||
|
||||
friend constexpr auto PathView::GetNormalPathParts(const AZ::IO::PathView&) noexcept -> PathIterable;
|
||||
friend constexpr auto PathView::AppendNormalPathParts(PathIterable& pathIterable, const AZ::IO::PathView&) noexcept -> void;
|
||||
PartKindArray m_parts{};
|
||||
size_t m_size{};
|
||||
};
|
||||
|
||||
// public
|
||||
[[nodiscard]] constexpr auto PathView::PathIterable::empty() const noexcept -> bool
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
constexpr auto PathView::PathIterable::size() const noexcept -> size_t
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
constexpr auto PathView::PathIterable::begin() noexcept -> PartKindArray::iterator
|
||||
{
|
||||
return m_parts.begin();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::begin() const noexcept -> PartKindArray::const_iterator
|
||||
{
|
||||
return m_parts.begin();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::cbegin() const noexcept -> PartKindArray::const_iterator
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::end() noexcept -> PartKindArray::iterator
|
||||
{
|
||||
return begin() + size();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::end() const noexcept -> PartKindArray::const_iterator
|
||||
{
|
||||
return begin() + size();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::cend() const noexcept -> PartKindArray::const_iterator
|
||||
{
|
||||
return end();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::rbegin() noexcept -> PartKindArray::reverse_iterator
|
||||
{
|
||||
return PartKindArray::reverse_iterator(begin() + size());
|
||||
}
|
||||
constexpr auto PathView::PathIterable::rbegin() const noexcept -> PartKindArray::const_reverse_iterator
|
||||
{
|
||||
return PartKindArray::const_reverse_iterator(begin() + size());
|
||||
}
|
||||
constexpr auto PathView::PathIterable::crbegin() const noexcept -> PartKindArray::const_reverse_iterator
|
||||
{
|
||||
return rbegin();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::rend() noexcept -> PartKindArray::reverse_iterator
|
||||
{
|
||||
return PartKindArray::reverse_iterator(begin());
|
||||
}
|
||||
constexpr auto PathView::PathIterable::rend() const noexcept -> PartKindArray::const_reverse_iterator
|
||||
{
|
||||
return PartKindArray::const_reverse_iterator(begin());
|
||||
}
|
||||
constexpr auto PathView::PathIterable::crend() const noexcept -> PartKindArray::const_reverse_iterator
|
||||
{
|
||||
return rend();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto PathView::PathIterable::IsAbsolute() const noexcept -> bool
|
||||
{
|
||||
return !empty() && (front().second == parser::PathPartKind::PK_RootSep
|
||||
|| (size() > 1 && front().second == parser::PathPartKind::PK_RootName && m_parts[1].second == parser::PathPartKind::PK_RootSep));
|
||||
}
|
||||
|
||||
// private
|
||||
template <typename... Args>
|
||||
constexpr auto PathView::PathIterable::emplace_back(Args&&... args) noexcept -> PartKindPair&
|
||||
{
|
||||
AZ_Assert(m_size < MaxPathParts, "PathIterable cannot be made out of a path with more than %zu parts", MaxPathParts);
|
||||
m_parts[m_size++] = PartKindPair{ AZStd::forward<Args>(args)... };
|
||||
return back();
|
||||
}
|
||||
constexpr auto PathView::PathIterable::pop_back() noexcept -> void
|
||||
{
|
||||
AZ_Assert(m_size > 0, "Cannot pop_back() from a PathIterable with 0 parts");
|
||||
--m_size;
|
||||
}
|
||||
constexpr auto PathView::PathIterable::back() const noexcept -> const PartKindPair&
|
||||
{
|
||||
AZ_Assert(!empty(), "back() was invoked on PathIterable with 0 parts");
|
||||
return m_parts[m_size - 1];
|
||||
}
|
||||
constexpr auto PathView::PathIterable::back() noexcept -> PartKindPair&
|
||||
{
|
||||
AZ_Assert(!empty(), "back() was invoked on PathIterable with 0 parts");
|
||||
return m_parts[m_size - 1];
|
||||
}
|
||||
|
||||
constexpr auto PathView::PathIterable::front() const noexcept -> const PartKindPair&
|
||||
{
|
||||
AZ_Assert(!empty(), "front() was invoked on PathIterable with 0 parts");
|
||||
return m_parts[0];
|
||||
}
|
||||
constexpr auto PathView::PathIterable::front() noexcept -> PartKindPair&
|
||||
{
|
||||
AZ_Assert(!empty(), "front() was invoked on PathIterable with 0 parts");
|
||||
return m_parts[0];
|
||||
}
|
||||
|
||||
constexpr auto PathView::PathIterable::clear() noexcept -> void
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
* 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/AzCore_Traits_Platform.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
namespace AZ::IO::Internal
|
||||
{
|
||||
constexpr bool IsSeparator(const char elem)
|
||||
{
|
||||
return elem == '/' || elem == '\\';
|
||||
}
|
||||
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::Internal::is_input_iterator_v<InputIt>>>
|
||||
static constexpr bool HasDrivePrefix(InputIt first, EndIt last)
|
||||
{
|
||||
size_t prefixSize = AZStd::distance(first, last);
|
||||
if (prefixSize < 2 || *AZStd::next(first, 1) != ':')
|
||||
{
|
||||
// Drive prefix must be at least two characters and have a colon for the second character
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr size_t ValidDrivePrefixRange = 26;
|
||||
// Uppercase the drive letter by bitwise and'ing out the the 2^5 bit
|
||||
unsigned char driveLetter = static_cast<unsigned char>(*first);
|
||||
|
||||
driveLetter &= 0b1101'1111;
|
||||
// normalize the character value in the range of A-Z -> 0-25
|
||||
driveLetter -= 'A';
|
||||
return driveLetter < ValidDrivePrefixRange;
|
||||
}
|
||||
|
||||
static constexpr bool HasDrivePrefix(AZStd::string_view prefix)
|
||||
{
|
||||
return HasDrivePrefix(prefix.begin(), prefix.end());
|
||||
}
|
||||
|
||||
//! Returns an iterator past the end of the consumed root name
|
||||
//! Windows root names can have include drive letter within them
|
||||
template <typename InputIt>
|
||||
constexpr auto ConsumeRootName(InputIt entryBeginIter, InputIt entryEndIter, const char preferredSeparator)
|
||||
-> AZStd::enable_if_t<AZStd::Internal::is_forward_iterator_v<InputIt>, InputIt>
|
||||
{
|
||||
if (preferredSeparator == PosixPathSeparator)
|
||||
{
|
||||
// If the preferred separator is forward slash the parser is in posix path
|
||||
// parsing mode, which doesn't have a root name,
|
||||
// unless we're on a posix platform that uses a custom path root separator
|
||||
#if defined(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR)
|
||||
const AZStd::string_view path{ entryBeginIter, entryEndIter };
|
||||
const auto positionOfPathSeparator = path.find(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR);
|
||||
if (positionOfPathSeparator != AZStd::string_view::npos)
|
||||
{
|
||||
return AZStd::next(entryBeginIter, positionOfPathSeparator + 1);
|
||||
}
|
||||
#endif
|
||||
return entryBeginIter;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Information for GetRootName has been gathered from Microsoft <filesystem> header
|
||||
// Below are examples of paths and what there root-name will return
|
||||
// "/" - returns ""
|
||||
// "foo/" - returns ""
|
||||
// "C:DriveRelative" - returns "C:"
|
||||
// "C:\\DriveAbsolute" - returns "C:"
|
||||
// "C://DriveAbsolute" - returns "C:"
|
||||
// "\\server\share" - returns "\\server"
|
||||
// The following paths are based on the UNC specification to work with paths longer than the 260 character path limit
|
||||
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#maximum-path-length-limitation
|
||||
// \\?\device - returns "\\?"
|
||||
// \??\device - returns "\??"
|
||||
// \\.\device - returns "\\."
|
||||
|
||||
|
||||
AZStd::string_view path{ entryBeginIter, entryEndIter };
|
||||
|
||||
if (path.size() < 2)
|
||||
{
|
||||
// A root name is either <drive letter><colon> or a network path
|
||||
// therefore it has a least two characters
|
||||
return entryBeginIter;
|
||||
}
|
||||
|
||||
if (HasDrivePrefix(path))
|
||||
{
|
||||
// If the path has a drive prefix, then it has a root name of <driver letter><colon>
|
||||
return AZStd::next(entryBeginIter, 2);
|
||||
}
|
||||
|
||||
if (!Internal::IsSeparator(path[0]))
|
||||
{
|
||||
// At this point all other root names start with a path separator
|
||||
return entryBeginIter;
|
||||
}
|
||||
|
||||
// Check if the path has the form of "\\?\, "\??\" or "\\.\"
|
||||
const bool pathInUncForm = path.size() >= 4 && Internal::IsSeparator(path[3])
|
||||
&& (path.size() == 4 || !Internal::IsSeparator(path[4]));
|
||||
if (pathInUncForm)
|
||||
{
|
||||
// \\?\<0 or more> or \\.\$<zero or more>
|
||||
const bool slashQuestionMark = Internal::IsSeparator(path[1]) && (path[2] == '?' || path[2] == '.');
|
||||
// \??\<0 or more>
|
||||
const bool questionMarkTwice = path[1] == '?' && path[2] == '?';
|
||||
if (slashQuestionMark || questionMarkTwice)
|
||||
{
|
||||
// Return the root value root slash - i.e "\\?"
|
||||
return AZStd::next(entryBeginIter, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (path.size() >= 3 && Internal::IsSeparator(path[1]) && !Internal::IsSeparator(path[2]))
|
||||
{
|
||||
// Find the next path separator for network paths that have the form of \\server\share
|
||||
constexpr AZStd::string_view PathSeparators = { "/\\" };
|
||||
size_t nextPathSeparatorOffset = path.find_first_of(PathSeparators, 3);
|
||||
return AZStd::next(entryBeginIter, nextPathSeparatorOffset != AZStd::string_view::npos ? nextPathSeparatorOffset : path.size());
|
||||
}
|
||||
|
||||
return entryBeginIter;
|
||||
}
|
||||
}
|
||||
|
||||
//! Returns an iterator past the end of the consumed path separator(s)
|
||||
template <typename InputIt>
|
||||
constexpr InputIt ConsumeSeparator(InputIt entryBeginIter, InputIt entryEndIter) noexcept
|
||||
{
|
||||
return AZStd::find_if_not(entryBeginIter, entryEndIter, [](const char elem) { return Internal::IsSeparator(elem); });
|
||||
}
|
||||
|
||||
//! Returns an iterator past the end of the consumed filename
|
||||
template <typename InputIt>
|
||||
constexpr InputIt ConsumeName(InputIt entryBeginIter, InputIt entryEndIter) noexcept
|
||||
{
|
||||
return AZStd::find_if(entryBeginIter, entryEndIter, [](const char elem) { return Internal::IsSeparator(elem); });
|
||||
}
|
||||
|
||||
//! Check if a path is absolute on a OS basis
|
||||
//! If the preferred separator is '/' just checks if the path starts with a '/
|
||||
//! Otherwise a check for a Windows absolute path occurs
|
||||
//! Windows absolute paths can include a RootName
|
||||
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::Internal::is_input_iterator_v<InputIt>>>
|
||||
static constexpr bool IsAbsolute(InputIt first, EndIt last, const char preferredSeparator)
|
||||
{
|
||||
size_t pathSize = AZStd::distance(first, last);
|
||||
|
||||
// If the preferred separator is a forward slash
|
||||
// than an absolute path is simply one that starts with a forward slash,
|
||||
// unless we're on a posix platform that uses a custom path root separator
|
||||
if (preferredSeparator == PosixPathSeparator)
|
||||
{
|
||||
#if defined(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR)
|
||||
const AZStd::string_view path{ first, last };
|
||||
return path.find(AZ_TRAIT_CUSTOM_PATH_ROOT_SEPARATOR) != AZStd::string_view::npos;
|
||||
#else
|
||||
return pathSize > 0 && IsSeparator(*first);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Internal::HasDrivePrefix(first, last))
|
||||
{
|
||||
// If a windows path ends starts with C:foo it is a root relative path
|
||||
// A path is absolute root absolute on windows if it starts with <drive_letter><colon><path_separator>
|
||||
return pathSize > 2 && Internal::IsSeparator(*AZStd::next(first, 2));
|
||||
}
|
||||
|
||||
return first != ConsumeRootName(first, last, preferredSeparator);
|
||||
}
|
||||
}
|
||||
static constexpr bool IsAbsolute(AZStd::string_view pathView, const char preferredSeparator)
|
||||
{
|
||||
// Uses the template preferred to branch on the absolute path check
|
||||
// logic
|
||||
return IsAbsolute(pathView.begin(), pathView.end(), preferredSeparator);
|
||||
}
|
||||
|
||||
// Compares path segments using either Posix or Windows path rules based on the path separator in use
|
||||
// Posix paths perform a case-sensitive comparison, while Windows paths perform a case-insensitive comparison
|
||||
static int ComparePathSegment(AZStd::string_view left, AZStd::string_view right, char pathSeparator)
|
||||
{
|
||||
const size_t maxCharsToCompare = (AZStd::min)(left.size(), right.size());
|
||||
|
||||
int charCompareResult = pathSeparator == PosixPathSeparator
|
||||
? maxCharsToCompare ? strncmp(left.data(), right.data(), maxCharsToCompare) : 0
|
||||
: maxCharsToCompare ? azstrnicmp(left.data(), right.data(), maxCharsToCompare) : 0;
|
||||
return charCompareResult == 0
|
||||
? static_cast<int>(aznumeric_cast<ptrdiff_t>(left.size()) - aznumeric_cast<ptrdiff_t>(right.size()))
|
||||
: charCompareResult;
|
||||
}
|
||||
}
|
||||
|
||||
//! PathParser implementation
|
||||
//! For internal use only
|
||||
namespace AZ::IO::parser
|
||||
{
|
||||
using parser_path_type = PathView;
|
||||
using string_view_pair = AZStd::pair<AZStd::string_view, AZStd::string_view>;
|
||||
using PosPtr = const typename parser_path_type::value_type*;
|
||||
|
||||
enum ParserState : uint8_t
|
||||
{
|
||||
// Zero is a special sentinel value used by default constructed iterators.
|
||||
PS_BeforeBegin = PathIterator<PathView>::BeforeBegin,
|
||||
PS_InRootName = PathIterator<PathView>::InRootName,
|
||||
PS_InRootDir = PathIterator<PathView>::InRootDir,
|
||||
PS_InFilenames = PathIterator<PathView>::InFilenames,
|
||||
PS_AtEnd = PathIterator<PathView>::AtEnd
|
||||
};
|
||||
|
||||
struct PathParser
|
||||
{
|
||||
AZStd::string_view m_path_view;
|
||||
AZStd::string_view m_path_raw_entry;
|
||||
ParserState m_parser_state{};
|
||||
const char m_preferred_separator{ AZ_TRAIT_OS_PATH_SEPARATOR };
|
||||
|
||||
constexpr PathParser(AZStd::string_view path, ParserState state, const char preferredSeparator) noexcept
|
||||
: m_path_view(path)
|
||||
, m_parser_state(state)
|
||||
, m_preferred_separator(preferredSeparator)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr PathParser(AZStd::string_view path, AZStd::string_view entry, ParserState state, const char preferredSeparator) noexcept
|
||||
: m_path_view(path)
|
||||
, m_path_raw_entry(entry)
|
||||
, m_parser_state(static_cast<ParserState>(state))
|
||||
, m_preferred_separator(preferredSeparator)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr static PathParser CreateBegin(AZStd::string_view path, const char preferredSeparator) noexcept
|
||||
{
|
||||
PathParser pathParser(path, PS_BeforeBegin, preferredSeparator);
|
||||
pathParser.Increment();
|
||||
return pathParser;
|
||||
}
|
||||
|
||||
constexpr static PathParser CreateEnd(AZStd::string_view path, const char preferredSeparator) noexcept
|
||||
{
|
||||
PathParser pathParser(path, PS_AtEnd, preferredSeparator);
|
||||
return pathParser;
|
||||
}
|
||||
|
||||
constexpr PosPtr Peek() const noexcept
|
||||
{
|
||||
auto tokenEnd = getNextTokenStartPos();
|
||||
auto End = m_path_view.end();
|
||||
return tokenEnd == End ? nullptr : tokenEnd;
|
||||
}
|
||||
|
||||
constexpr void Increment() noexcept
|
||||
{
|
||||
const PosPtr pathEnd = m_path_view.end();
|
||||
const PosPtr currentPathEntry = getNextTokenStartPos();
|
||||
if (currentPathEntry == pathEnd)
|
||||
{
|
||||
return MakeState(PS_AtEnd);
|
||||
}
|
||||
|
||||
switch (m_parser_state)
|
||||
{
|
||||
case PS_BeforeBegin:
|
||||
{
|
||||
/*
|
||||
* First the determine if the path contains only a root-name such as "C:" or is a filename such as "foo"
|
||||
* root-relative path(Windows only) - C:foo
|
||||
* root-absolute path - C:\foo
|
||||
* root-absolute path - /foo
|
||||
* relative path - foo
|
||||
*
|
||||
* Try to consume the root-name then the root directory to determine if path entry
|
||||
* being parsed is a root-name or filename
|
||||
* The State transitions from BeforeBegin are
|
||||
* "C:", "\\server\", "\\?\", "\??\", "\\.\" -> Root Name
|
||||
* "/", "\" -> Root Directory
|
||||
* "path/foo", "foo" -> Filename
|
||||
*/
|
||||
auto rootNameEnd = Internal::ConsumeRootName(currentPathEntry, pathEnd, m_preferred_separator);
|
||||
if (currentPathEntry != rootNameEnd)
|
||||
{
|
||||
// Transition to the Root Name state
|
||||
return MakeState(PS_InRootName, currentPathEntry, rootNameEnd);
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case PS_InRootName:
|
||||
{
|
||||
auto rootDirEnd = Internal::ConsumeSeparator(currentPathEntry, pathEnd);
|
||||
if (currentPathEntry != rootDirEnd)
|
||||
{
|
||||
// Transition to Root Directory state
|
||||
return MakeState(PS_InRootDir, currentPathEntry, rootDirEnd);
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case PS_InRootDir:
|
||||
{
|
||||
auto filenameEnd = Internal::ConsumeName(currentPathEntry, pathEnd);
|
||||
if (currentPathEntry != filenameEnd)
|
||||
{
|
||||
return MakeState(PS_InFilenames, currentPathEntry, filenameEnd);
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case PS_InFilenames:
|
||||
{
|
||||
auto separatorEnd = Internal::ConsumeSeparator(currentPathEntry, pathEnd);
|
||||
if (separatorEnd != pathEnd)
|
||||
{
|
||||
// find the end of the current filename entry
|
||||
auto filenameEnd = Internal::ConsumeName(separatorEnd, pathEnd);
|
||||
return MakeState(PS_InFilenames, separatorEnd, filenameEnd);
|
||||
}
|
||||
// If after consuming the separator that path entry is at the end iterator
|
||||
// move the path state to AtEnd
|
||||
return MakeState(PS_AtEnd);
|
||||
}
|
||||
case PS_AtEnd:
|
||||
AZ_Assert(false, "Path Parser cannot be incremented when it is in the AtEnd state");
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void Decrement() noexcept
|
||||
{
|
||||
auto pathStart = m_path_view.begin();
|
||||
auto currentPathEntry = getCurrentTokenStartPos();
|
||||
|
||||
if (currentPathEntry == pathStart)
|
||||
{
|
||||
// we're decrementing the begin
|
||||
return MakeState(PS_BeforeBegin);
|
||||
}
|
||||
switch (m_parser_state)
|
||||
{
|
||||
case PS_AtEnd:
|
||||
{
|
||||
/*
|
||||
* First the determine if the path contains only a root-name such as "C:" or is a filename such as "foo"
|
||||
* root-relative path(Windows only) - C:foo
|
||||
* root-absolute path - C:\foo
|
||||
* root-absolute path - /foo
|
||||
* relative path - foo
|
||||
* Try to consume the root-name then the root directory to determine if path entry
|
||||
* being parsed is a root-name or filename
|
||||
* The State transitions from AtEnd are
|
||||
* "/path/foo/", "foo/", "C:foo\", "C:\foo\" -> Trailing Separator
|
||||
* "/path/foo", "foo", "C:foo", "C:\foo" -> Filename
|
||||
* "/", "C:\" or "\\server\" -> Root Directory
|
||||
* "C:", "\\server", "\\?", "\??", "\\." -> Root Name
|
||||
*/
|
||||
auto rootNameEnd = Internal::ConsumeRootName(pathStart, currentPathEntry, m_preferred_separator);
|
||||
if (pathStart != rootNameEnd && currentPathEntry == rootNameEnd)
|
||||
{
|
||||
// Transition to the Root Name state
|
||||
return MakeState(PS_InRootName, pathStart, currentPathEntry);
|
||||
}
|
||||
|
||||
auto rootDirEnd = Internal::ConsumeSeparator(rootNameEnd, currentPathEntry);
|
||||
if (rootNameEnd != rootDirEnd && currentPathEntry == rootDirEnd)
|
||||
{
|
||||
// Transition to Root Directory state
|
||||
return MakeState(PS_InRootDir, rootNameEnd, currentPathEntry);
|
||||
}
|
||||
|
||||
auto filenameEnd = currentPathEntry;
|
||||
if (Internal::IsSeparator(*(filenameEnd - 1)))
|
||||
{
|
||||
// The last character a path separator that isn't root directory
|
||||
// consume all the preceding path separators
|
||||
filenameEnd = Internal::ConsumeSeparator(AZStd::make_reverse_iterator(filenameEnd),
|
||||
AZStd::make_reverse_iterator(rootDirEnd)).base();
|
||||
}
|
||||
|
||||
// The previous state will be Filename, so the beginning of the filename is searched found
|
||||
auto filenameBegin = Internal::ConsumeName(AZStd::make_reverse_iterator(filenameEnd),
|
||||
AZStd::make_reverse_iterator(rootDirEnd)).base();
|
||||
return MakeState(PS_InFilenames, filenameBegin, filenameEnd);
|
||||
}
|
||||
case PS_InFilenames:
|
||||
{
|
||||
/* The State transitions from Filename are
|
||||
* "/path/foo" -> Filename
|
||||
* ^
|
||||
* "C:\foo" -> Root Directory
|
||||
* ^
|
||||
* "C:foo" -> Root Name
|
||||
* ^
|
||||
* "foo" -> This case has been taken care of by the current path entry != path start check
|
||||
* ^
|
||||
*/
|
||||
auto rootNameEnd = Internal::ConsumeRootName(pathStart, currentPathEntry, m_preferred_separator);
|
||||
if (pathStart != rootNameEnd && currentPathEntry == rootNameEnd)
|
||||
{
|
||||
// Transition to the Root Name state
|
||||
return MakeState(PS_InRootName, pathStart, rootNameEnd);
|
||||
}
|
||||
|
||||
auto rootDirEnd = Internal::ConsumeSeparator(rootNameEnd, currentPathEntry);
|
||||
if (rootNameEnd != rootDirEnd && currentPathEntry == rootDirEnd)
|
||||
{
|
||||
// Transition to Root Directory state
|
||||
return MakeState(PS_InRootDir, rootNameEnd, rootDirEnd);
|
||||
}
|
||||
// The previous state will be Filename again, so first the end of that filename is found
|
||||
// proceeded by finding the beginning of that filename
|
||||
auto filenameEnd = Internal::ConsumeSeparator(AZStd::make_reverse_iterator(currentPathEntry),
|
||||
AZStd::make_reverse_iterator(rootDirEnd)).base();
|
||||
auto filenameBegin = Internal::ConsumeName(AZStd::make_reverse_iterator(filenameEnd),
|
||||
AZStd::make_reverse_iterator(rootDirEnd)).base();
|
||||
return MakeState(PS_InFilenames, filenameBegin, filenameEnd);
|
||||
}
|
||||
case PS_InRootDir:
|
||||
{
|
||||
/* The State transitions from Root Directory are
|
||||
* "C:\" "\\server\", "\\?\", "\??\", "\\.\" -> Root Name
|
||||
* ^ ^ ^ ^ ^
|
||||
* "/" -> This case has been taken care of by the current path entry != path start check
|
||||
* ^
|
||||
*/
|
||||
return MakeState(PS_InRootName, pathStart, currentPathEntry);
|
||||
}
|
||||
case PS_InRootName:
|
||||
// The only valid state transition from Root Name is BeforeBegin
|
||||
return MakeState(PS_BeforeBegin);
|
||||
case PS_BeforeBegin:
|
||||
AZ_Assert(false, "Path Parser cannot be decremented when it is in the BeforeBegin State");
|
||||
}
|
||||
}
|
||||
|
||||
//! Return a view of the current element in the path processor state
|
||||
constexpr AZStd::string_view operator*() const noexcept
|
||||
{
|
||||
switch (m_parser_state)
|
||||
{
|
||||
case PS_BeforeBegin:
|
||||
[[fallthrough]];
|
||||
case PS_AtEnd:
|
||||
[[fallthrough]];
|
||||
case PS_InRootDir:
|
||||
return m_preferred_separator == '/' ? "/" : "\\";
|
||||
case PS_InRootName:
|
||||
case PS_InFilenames:
|
||||
return m_path_raw_entry;
|
||||
default:
|
||||
AZ_Assert(false, "Path Parser is in an invalid state");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept
|
||||
{
|
||||
return m_parser_state != PS_BeforeBegin && m_parser_state != PS_AtEnd;
|
||||
}
|
||||
|
||||
constexpr PathParser& operator++() noexcept
|
||||
{
|
||||
Increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr PathParser& operator--() noexcept
|
||||
{
|
||||
Decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool AtEnd() const noexcept
|
||||
{
|
||||
return m_parser_state == PS_AtEnd;
|
||||
}
|
||||
|
||||
constexpr bool InRootDir() const noexcept
|
||||
{
|
||||
return m_parser_state == PS_InRootDir;
|
||||
}
|
||||
|
||||
constexpr bool InRootName() const noexcept
|
||||
{
|
||||
return m_parser_state == PS_InRootName;
|
||||
}
|
||||
|
||||
constexpr bool InRootPath() const noexcept
|
||||
{
|
||||
return InRootName() || InRootDir();
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void MakeState(ParserState newState, typename AZStd::string_view::iterator start, typename AZStd::string_view::iterator end) noexcept
|
||||
{
|
||||
m_parser_state = newState;
|
||||
m_path_raw_entry = AZStd::string_view(start, end);
|
||||
}
|
||||
constexpr void MakeState(ParserState newState) noexcept
|
||||
{
|
||||
m_parser_state = newState;
|
||||
m_path_raw_entry = {};
|
||||
}
|
||||
|
||||
//! Return a pointer to the first character after the currently lexed element.
|
||||
constexpr typename AZStd::string_view::iterator getNextTokenStartPos() const noexcept
|
||||
{
|
||||
switch (m_parser_state)
|
||||
{
|
||||
case PS_BeforeBegin:
|
||||
return m_path_view.begin();
|
||||
case PS_InRootName:
|
||||
case PS_InRootDir:
|
||||
case PS_InFilenames:
|
||||
return m_path_raw_entry.end();
|
||||
case PS_AtEnd:
|
||||
return m_path_view.end();
|
||||
default:
|
||||
AZ_Assert(false, "Path Parser is in an invalid state");
|
||||
}
|
||||
return m_path_view.end();
|
||||
}
|
||||
|
||||
//! Return a pointer to the first character in the currently lexed element.
|
||||
constexpr typename AZStd::string_view::iterator getCurrentTokenStartPos() const noexcept
|
||||
{
|
||||
switch (m_parser_state)
|
||||
{
|
||||
case PS_BeforeBegin:
|
||||
case PS_InRootName:
|
||||
return m_path_view.begin();
|
||||
case PS_InRootDir:
|
||||
case PS_InFilenames:
|
||||
return m_path_raw_entry.begin();
|
||||
case PS_AtEnd:
|
||||
return m_path_view.end();
|
||||
default:
|
||||
AZ_Assert(false, "Path Parser is in an invalid state");
|
||||
}
|
||||
return m_path_view.end();
|
||||
}
|
||||
};
|
||||
|
||||
constexpr string_view_pair SeparateFilename(const AZStd::string_view& srcView)
|
||||
{
|
||||
if (srcView == "." || srcView == ".." || srcView.empty())
|
||||
{
|
||||
return string_view_pair{ srcView, "" };
|
||||
}
|
||||
auto pos = srcView.find_last_of('.');
|
||||
if (pos == AZStd::string_view::npos || pos == 0)
|
||||
{
|
||||
return string_view_pair{ srcView, AZStd::string_view{} };
|
||||
}
|
||||
return string_view_pair{ srcView.substr(0, pos), srcView.substr(pos) };
|
||||
}
|
||||
|
||||
|
||||
// path part consumption
|
||||
constexpr bool ConsumeRootName(PathParser* pathParser)
|
||||
{
|
||||
static_assert(PS_BeforeBegin == 1 && PS_InRootName == 2,
|
||||
"PathParser must be in state before begin or in the root name in order to consume the root name");
|
||||
while (pathParser->m_parser_state <= PS_InRootName)
|
||||
{
|
||||
++(*pathParser);
|
||||
}
|
||||
return pathParser->m_parser_state == PS_AtEnd;
|
||||
}
|
||||
constexpr bool ConsumeRootDir(PathParser* pathParser)
|
||||
{
|
||||
static_assert(PS_BeforeBegin == 1 && PS_InRootName == 2 && PS_InRootDir == 3,
|
||||
"PathParser must be in state before begin, in the root name or in the root directory in order to consume the root directory");
|
||||
while (pathParser->m_parser_state <= PS_InRootDir)
|
||||
{
|
||||
++(*pathParser);
|
||||
}
|
||||
return pathParser->m_parser_state == PS_AtEnd;
|
||||
}
|
||||
|
||||
// path.comparisons
|
||||
constexpr int CompareRootName(PathParser* lhsPathParser, PathParser* rhsPathParser)
|
||||
{
|
||||
if (!lhsPathParser->InRootName() && !rhsPathParser->InRootName())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto GetRootName = [](PathParser* pathParser) constexpr -> AZStd::string_view
|
||||
{
|
||||
return pathParser->InRootName() ? **pathParser : "";
|
||||
};
|
||||
int res = Internal::ComparePathSegment(GetRootName(lhsPathParser), GetRootName(rhsPathParser), lhsPathParser->m_preferred_separator);
|
||||
ConsumeRootName(lhsPathParser);
|
||||
ConsumeRootName(rhsPathParser);
|
||||
return res;
|
||||
}
|
||||
constexpr int CompareRootDir(PathParser* lhsPathParser, PathParser* rhsPathParser)
|
||||
{
|
||||
if (!lhsPathParser->InRootDir() && rhsPathParser->InRootDir())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (lhsPathParser->InRootDir() && !rhsPathParser->InRootDir())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsumeRootDir(lhsPathParser);
|
||||
ConsumeRootDir(rhsPathParser);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
constexpr int CompareRelative(PathParser* lhsPathParserPtr, PathParser* rhsPathParserPtr)
|
||||
{
|
||||
auto& lhsPathParser = *lhsPathParserPtr;
|
||||
auto& rhsPathParser = *rhsPathParserPtr;
|
||||
|
||||
while (lhsPathParser && rhsPathParser)
|
||||
{
|
||||
if (int res = Internal::ComparePathSegment(*lhsPathParser, *rhsPathParser, lhsPathParser.m_preferred_separator);
|
||||
res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
++lhsPathParser;
|
||||
++rhsPathParser;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
constexpr int CompareEndState(PathParser* lhsPathParser, PathParser* rhsPathParser)
|
||||
{
|
||||
if (lhsPathParser->AtEnd() && !rhsPathParser->AtEnd())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (!lhsPathParser->AtEnd() && rhsPathParser->AtEnd())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr int DetermineLexicalElementCount(PathParser pathParser)
|
||||
{
|
||||
int count = 0;
|
||||
for (; pathParser; ++pathParser)
|
||||
{
|
||||
auto pathElement = *pathParser;
|
||||
if (pathElement == "..")
|
||||
{
|
||||
--count;
|
||||
}
|
||||
else if (pathElement != "." && pathElement != "")
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
enum class PathPartKind : uint8_t
|
||||
{
|
||||
PK_None,
|
||||
PK_RootName,
|
||||
PK_RootSep,
|
||||
PK_Filename,
|
||||
PK_Dot,
|
||||
PK_DotDot,
|
||||
};
|
||||
|
||||
constexpr PathPartKind ClassifyPathPart(const PathParser& parser)
|
||||
{
|
||||
// Check each parser state to determine the PathPartKind
|
||||
if (parser.m_parser_state == PS_InRootDir)
|
||||
{
|
||||
return PathPartKind::PK_RootSep;
|
||||
}
|
||||
if (parser.m_parser_state == PS_InRootName)
|
||||
{
|
||||
return PathPartKind::PK_RootName;
|
||||
}
|
||||
|
||||
// Fallback to checking parser pathEntry view value
|
||||
// to determine if the special "." or ".." values are being used
|
||||
AZStd::string_view pathPart = *parser;
|
||||
if (pathPart == ".")
|
||||
{
|
||||
return PathPartKind::PK_Dot;
|
||||
}
|
||||
if (pathPart == "..")
|
||||
{
|
||||
return PathPartKind::PK_DotDot;
|
||||
}
|
||||
|
||||
// Return PathPartKind of PK_ilename if the parser state doesn't match
|
||||
// the states of InRootDir or InRootName and the filename
|
||||
// isn't made up of the special directory values of "." and ".."
|
||||
return PathPartKind::PK_Filename;
|
||||
}
|
||||
}
|
||||
@@ -7,18 +7,17 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Script/ScriptContext.h>
|
||||
#include <AzCore/Script/ScriptContextAttributes.h>
|
||||
#include <AzCore/ScriptCanvas/ScriptCanvasAttributes.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/string/tokenize.h>
|
||||
#include <AzCore/ScriptCanvas/ScriptCanvasOnDemandNames.h>
|
||||
#include <AzCore/RTTI/AzStdOnDemandPrettyName.inl>
|
||||
#include <AzCore/RTTI/AzStdOnDemandReflectionLuaFunctions.inl>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
|
||||
#ifndef AZ_USE_CUSTOM_SCRIPT_BIND
|
||||
struct lua_State;
|
||||
struct lua_Debug;
|
||||
#endif // AZ_USE_CUSTOM_SCRIPT_BIND
|
||||
|
||||
// forward declare specialized types
|
||||
namespace AZStd
|
||||
@@ -59,6 +58,26 @@ namespace AZ
|
||||
class BehaviorContext;
|
||||
class ScriptDataContext;
|
||||
|
||||
namespace OnDemandLuaFunctions
|
||||
{
|
||||
inline void AnyToLua(lua_State* lua, BehaviorValueParameter& param);
|
||||
}
|
||||
namespace ScriptCanvasOnDemandReflection
|
||||
{
|
||||
template<typename T>
|
||||
struct OnDemandPrettyName;
|
||||
template<typename T>
|
||||
struct OnDemandToolTip;
|
||||
template<typename T>
|
||||
struct OnDemandCategoryName;
|
||||
}
|
||||
namespace CommonOnDemandReflections
|
||||
{
|
||||
void ReflectCommonString(ReflectContext* context);
|
||||
void ReflectCommonStringView(ReflectContext* context);
|
||||
void ReflectStdAny(ReflectContext* context);
|
||||
void ReflectVoidOutcome(ReflectContext* context);
|
||||
}
|
||||
/// OnDemand reflection for AZStd::basic_string
|
||||
template<class Element, class Traits, class Allocator>
|
||||
struct OnDemandReflection< AZStd::basic_string<Element, Traits, Allocator> >
|
||||
@@ -66,108 +85,16 @@ namespace AZ
|
||||
using ContainerType = AZStd::basic_string<Element, Traits, Allocator>;
|
||||
using SizeType = typename ContainerType::size_type;
|
||||
using ValueType = typename ContainerType::value_type;
|
||||
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
constexpr bool is_string = AZStd::is_same_v<Element, char> && AZStd::is_same_v<Traits, AZStd::char_traits<char>>
|
||||
&& AZStd::is_same_v<Allocator, AZStd::allocator>;
|
||||
if constexpr(is_string)
|
||||
{
|
||||
behaviorContext->Class<ContainerType>()
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->template Constructor<typename ContainerType::value_type*>()
|
||||
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructBasicString<Element, Traits, Allocator>)
|
||||
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
|
||||
->template WrappingMember<const char*>(&ContainerType::c_str)
|
||||
->Method("c_str", &ContainerType::c_str)
|
||||
->Method("Length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); })
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
|
||||
->Method("Equal", [](const ContainerType& lhs, const ContainerType& rhs)
|
||||
{
|
||||
return lhs == rhs;
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
|
||||
->Method("Find", [](ContainerType* thisPtr, const ContainerType& stringToFind, const int& startPos)
|
||||
{
|
||||
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
|
||||
})
|
||||
->Method("Substring", [](ContainerType* thisPtr, const int& pos, const int& len)
|
||||
{
|
||||
return thisPtr->substr(pos, len);
|
||||
})
|
||||
->Method("Replace", [](ContainerType* thisPtr, const ContainerType& stringToReplace, const ContainerType& replacementString)
|
||||
{
|
||||
SizeType startPos = 0;
|
||||
while ((startPos = thisPtr->find(stringToReplace, startPos)) != ContainerType::npos && !stringToReplace.empty())
|
||||
{
|
||||
thisPtr->replace(startPos, stringToReplace.length(), replacementString);
|
||||
startPos += replacementString.length();
|
||||
}
|
||||
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("ReplaceByIndex", [](ContainerType* thisPtr, const int& beginIndex, const int& endIndex, const ContainerType& replacementString)
|
||||
{
|
||||
thisPtr->replace(beginIndex, endIndex - beginIndex + 1, replacementString);
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("Add", [](ContainerType* thisPtr, const ContainerType& addend)
|
||||
{
|
||||
return *thisPtr + addend;
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Concat)
|
||||
->Method("TrimLeft", [](ContainerType* thisPtr)
|
||||
{
|
||||
auto wsfront = AZStd::find_if_not(thisPtr->begin(), thisPtr->end(), [](char c) {return AZStd::is_space(c);});
|
||||
thisPtr->erase(thisPtr->begin(), wsfront);
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("TrimRight", [](ContainerType* thisPtr)
|
||||
{
|
||||
auto wsend = AZStd::find_if_not(thisPtr->rbegin(), thisPtr->rend(), [](char c) {return AZStd::is_space(c);});
|
||||
thisPtr->erase(wsend.base(), thisPtr->end());
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("ToLower", [](ContainerType* thisPtr)
|
||||
{
|
||||
ContainerType toLowerString;
|
||||
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
|
||||
{
|
||||
toLowerString.push_back(static_cast<ValueType>(tolower(*itr)));
|
||||
}
|
||||
return toLowerString;
|
||||
})
|
||||
->Method("ToUpper", [](ContainerType* thisPtr)
|
||||
{
|
||||
ContainerType toUpperString;
|
||||
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
|
||||
{
|
||||
toUpperString.push_back(static_cast<ValueType>(toupper(*itr)));
|
||||
}
|
||||
return toUpperString;
|
||||
})
|
||||
->Method("Join", [](AZStd::vector<ContainerType>* stringsToJoinPtr, const ContainerType& joinStr)
|
||||
{
|
||||
ContainerType joinString;
|
||||
for (auto& stringToJoin : *stringsToJoinPtr)
|
||||
{
|
||||
joinString.append(stringToJoin).append(joinStr);
|
||||
}
|
||||
//Cut off the last join str
|
||||
if (!stringsToJoinPtr->empty())
|
||||
{
|
||||
joinString = joinString.substr(0, joinString.length() - joinStr.length());
|
||||
}
|
||||
return joinString;
|
||||
})
|
||||
|
||||
->Method("Split", [](ContainerType* thisPtr, const ContainerType& splitter)
|
||||
{
|
||||
AZStd::vector<ContainerType> splitStringList;
|
||||
AZStd::tokenize(*thisPtr, splitter, splitStringList);
|
||||
return splitStringList;
|
||||
})
|
||||
;
|
||||
CommonOnDemandReflections::ReflectCommonString(context);
|
||||
}
|
||||
static_assert (is_string, "Unspecialized basic_string<> template reflection requested.");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,44 +108,9 @@ namespace AZ
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<ContainerType>()
|
||||
->Attribute(AZ::Script::Attributes::Category, "Core")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->template Constructor<typename ContainerType::value_type*>()
|
||||
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructStringView<Element, Traits>)
|
||||
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
|
||||
->Method("ToString", [](const ContainerType& stringView) { return static_cast<AZStd::string>(stringView).c_str(); }, { { { "Reference", "String view object being converted to string" } } })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Converts string_view to string")
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
->template WrappingMember<const char*>(&ContainerType::data)
|
||||
->Method("data", &ContainerType::data)
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Returns reference to raw string data")
|
||||
->Method("length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); }, { { { "This", "Reference to the object the method is being performed on" } } })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
|
||||
->Method("size", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->size()); }, { { { "This", "Reference to the object the method is being performed on" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
|
||||
->Method("find", [](ContainerType* thisPtr, ContainerType stringToFind, int startPos)
|
||||
{
|
||||
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
|
||||
}, { { { "This", "Reference to the object the method is being performed on" }, { "View", "View to search " }, { "Position", "Index in view to start search" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Searches for supplied string within this string")
|
||||
->Method("substr", [](ContainerType* thisPtr, int pos, int len)
|
||||
{
|
||||
return thisPtr->substr(pos, len);
|
||||
}, { {{"This", "Reference to the object the method is being performed on"}, {"Position", "Index in view that indicates the beginning of the sub string"}, {"Count", "Length of characters that sub string view occupies" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Creates a sub view of this string view. The string data is not actually modified")
|
||||
->Method("remove_prefix", [](ContainerType* thisPtr, int n) {thisPtr->remove_prefix(n); },
|
||||
{ { { "This", "Reference to the object the method is being performed on" }, { "Count", "Number of characters to remove from start of view" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the beginning of this sub view")
|
||||
->Method("remove_suffix", [](ContainerType* thisPtr, int n) {thisPtr->remove_suffix(n); },
|
||||
{ { { "This", "Reference to the object the method is being performed on" } ,{ "Count", "Number of characters to remove from end of view" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the end of this sub view")
|
||||
;
|
||||
}
|
||||
constexpr bool is_common = AZStd::is_same_v<Element,char> && AZStd::is_same_v<Traits,AZStd::char_traits<char>>;
|
||||
static_assert (is_common, "Unspecialized basic_string_view<> template reflection requested.");
|
||||
CommonOnDemandReflections::ReflectCommonStringView(context);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -228,7 +120,7 @@ namespace AZ
|
||||
{
|
||||
using ContainerType = AZStd::intrusive_ptr<T>;
|
||||
|
||||
// TODO: Count reflection types for a proper un-reflect
|
||||
// TODO: Count reflection types for a proper un-reflect
|
||||
|
||||
static void CustomConstructor(ContainerType* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
@@ -276,7 +168,7 @@ namespace AZ
|
||||
{
|
||||
using ContainerType = AZStd::shared_ptr<T>;
|
||||
|
||||
// TODO: Count reflection types for a proper un-reflect
|
||||
// TODO: Count reflection types for a proper un-reflect
|
||||
|
||||
static void CustomConstructor(ContainerType* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
@@ -435,7 +327,7 @@ namespace AZ
|
||||
thisPtr[uindex] = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool EraseCheck_VM(ContainerType& thisPtr, AZ::u64 index)
|
||||
{
|
||||
if (index < thisPtr.size())
|
||||
@@ -448,7 +340,7 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ContainerType& ErasePost_VM(ContainerType& thisPtr, AZ::u64 /*index*/)
|
||||
{
|
||||
return thisPtr;
|
||||
@@ -604,7 +496,7 @@ namespace AZ
|
||||
return AZ::Failure(AZStd::string::format("Index out of bounds: %zu (size: %zu)", index, thisContainer.size()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static AZ::Outcome<void, void> Replace(ContainerType& thisContainer, size_t index, T& value)
|
||||
{
|
||||
if (index >= 0 && index < thisContainer.size())
|
||||
@@ -634,7 +526,7 @@ namespace AZ
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Deprecated, true)
|
||||
|
||||
|
||||
->Method(k_accessElementName, &At, {{ {}, { "Index", "The index to read from", nullptr, BehaviorParameter::Traits::TR_INDEX }}})
|
||||
->Method(k_sizeName, [](ContainerType*) { return aznumeric_cast<int>(N); })
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
|
||||
@@ -743,27 +635,8 @@ namespace AZ
|
||||
template<> // in case someone has an issue with bool
|
||||
struct OnDemandReflection<AZ::Outcome<void, void>>
|
||||
{
|
||||
using OutcomeType = AZ::Outcome<void, void>;
|
||||
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
// note we can reflect iterator types and support iterators, as of know we want to keep it simple
|
||||
behaviorContext->Class<OutcomeType>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, true)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::PrettyName, &ScriptCanvasOnDemandReflection::OnDemandPrettyName<OutcomeType>::Get)
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, &ScriptCanvasOnDemandReflection::OnDemandToolTip<OutcomeType>::Get)
|
||||
->Attribute(AZ::Script::Attributes::Category, &ScriptCanvasOnDemandReflection::OnDemandCategoryName<OutcomeType>::Get)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, AttributeIsValid::IfPresent)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AttributeIsValid::IfPresent)
|
||||
->Method("Failure", []() -> OutcomeType { return AZ::Failure(); })
|
||||
->Method("Success", []() -> OutcomeType { return AZ::Success(); })
|
||||
->Method("IsSuccess", &OutcomeType::IsSuccess)
|
||||
;
|
||||
}
|
||||
static void Reflect(ReflectContext* context) {
|
||||
CommonOnDemandReflections::ReflectVoidOutcome(context);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1179,16 +1052,8 @@ namespace AZ
|
||||
template <>
|
||||
struct OnDemandReflection<AZStd::any>
|
||||
{
|
||||
static void Reflect(ReflectContext* context)
|
||||
{
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AZStd::any>()
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(Script::Attributes::Ignore, true) // Don't reflect any type to script (there should never be an any instance in script)
|
||||
->Attribute(Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&AZ::OnDemandLuaFunctions::AnyToLua, &OnDemandLuaFunctions::AnyFromLua))
|
||||
;
|
||||
}
|
||||
static void Reflect(ReflectContext* context) {
|
||||
CommonOnDemandReflections::ReflectStdAny(context);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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/Math/Uuid.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/std/string/alphanum.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/tokenize.h>
|
||||
|
||||
#include <AzCore/RTTI/AzStdOnDemandReflection.inl>
|
||||
#include <AzCore/RTTI/AzStdOnDemandReflectionLuaFunctions.inl>
|
||||
namespace AZ::CommonOnDemandReflections
|
||||
{
|
||||
void ReflectCommonString(ReflectContext* context)
|
||||
{
|
||||
using ContainerType = AZStd::string;
|
||||
using SizeType = typename ContainerType::size_type;
|
||||
using ValueType = typename ContainerType::value_type;
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<ContainerType>()
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->template Constructor<typename ContainerType::value_type*>()
|
||||
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructBasicString<ContainerType::value_type, ContainerType::traits_type, ContainerType::allocator_type>)
|
||||
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
|
||||
->template WrappingMember<const char*>(&ContainerType::c_str)
|
||||
->Method("c_str", &ContainerType::c_str)
|
||||
->Method("Length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); })
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
|
||||
->Method("Equal", [](const ContainerType& lhs, const ContainerType& rhs)
|
||||
{
|
||||
return lhs == rhs;
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
|
||||
->Method("Find", [](ContainerType* thisPtr, const ContainerType& stringToFind, const int& startPos)
|
||||
{
|
||||
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
|
||||
})
|
||||
->Method("Substring", [](ContainerType* thisPtr, const int& pos, const int& len)
|
||||
{
|
||||
return thisPtr->substr(pos, len);
|
||||
})
|
||||
->Method("Replace", [](ContainerType* thisPtr, const ContainerType& stringToReplace, const ContainerType& replacementString)
|
||||
{
|
||||
SizeType startPos = 0;
|
||||
while ((startPos = thisPtr->find(stringToReplace, startPos)) != ContainerType::npos && !stringToReplace.empty())
|
||||
{
|
||||
thisPtr->replace(startPos, stringToReplace.length(), replacementString);
|
||||
startPos += replacementString.length();
|
||||
}
|
||||
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("ReplaceByIndex", [](ContainerType* thisPtr, const int& beginIndex, const int& endIndex, const ContainerType& replacementString)
|
||||
{
|
||||
thisPtr->replace(beginIndex, endIndex - beginIndex + 1, replacementString);
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("Add", [](ContainerType* thisPtr, const ContainerType& addend)
|
||||
{
|
||||
return *thisPtr + addend;
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Concat)
|
||||
->Method("TrimLeft", [](ContainerType* thisPtr)
|
||||
{
|
||||
auto wsfront = AZStd::find_if_not(thisPtr->begin(), thisPtr->end(), [](char c) {return AZStd::is_space(c);});
|
||||
thisPtr->erase(thisPtr->begin(), wsfront);
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("TrimRight", [](ContainerType* thisPtr)
|
||||
{
|
||||
auto wsend = AZStd::find_if_not(thisPtr->rbegin(), thisPtr->rend(), [](char c) {return AZStd::is_space(c);});
|
||||
thisPtr->erase(wsend.base(), thisPtr->end());
|
||||
return *thisPtr;
|
||||
})
|
||||
->Method("ToLower", [](ContainerType* thisPtr)
|
||||
{
|
||||
ContainerType toLowerString;
|
||||
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
|
||||
{
|
||||
toLowerString.push_back(static_cast<ValueType>(tolower(*itr)));
|
||||
}
|
||||
return toLowerString;
|
||||
})
|
||||
->Method("ToUpper", [](ContainerType* thisPtr)
|
||||
{
|
||||
ContainerType toUpperString;
|
||||
for (auto itr = thisPtr->begin(); itr < thisPtr->end(); itr++)
|
||||
{
|
||||
toUpperString.push_back(static_cast<ValueType>(toupper(*itr)));
|
||||
}
|
||||
return toUpperString;
|
||||
})
|
||||
->Method("Join", [](AZStd::vector<ContainerType>* stringsToJoinPtr, const ContainerType& joinStr)
|
||||
{
|
||||
ContainerType joinString;
|
||||
for (auto& stringToJoin : *stringsToJoinPtr)
|
||||
{
|
||||
joinString.append(stringToJoin).append(joinStr);
|
||||
}
|
||||
//Cut off the last join str
|
||||
if (!stringsToJoinPtr->empty())
|
||||
{
|
||||
joinString = joinString.substr(0, joinString.length() - joinStr.length());
|
||||
}
|
||||
return joinString;
|
||||
})
|
||||
|
||||
->Method("Split", [](ContainerType* thisPtr, const ContainerType& splitter)
|
||||
{
|
||||
AZStd::vector<ContainerType> splitStringList;
|
||||
AZStd::tokenize(*thisPtr, splitter, splitStringList);
|
||||
return splitStringList;
|
||||
})
|
||||
;
|
||||
}
|
||||
}
|
||||
void ReflectCommonStringView(ReflectContext* context)
|
||||
{
|
||||
using ContainerType = AZStd::string_view;
|
||||
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<ContainerType>()
|
||||
->Attribute(AZ::Script::Attributes::Category, "Core")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->template Constructor<typename ContainerType::value_type*>()
|
||||
->Attribute(AZ::Script::Attributes::ConstructorOverride, &OnDemandLuaFunctions::ConstructStringView<ContainerType::value_type, ContainerType::traits_type>)
|
||||
->Attribute(AZ::Script::Attributes::ReaderWriterOverride, ScriptContext::CustomReaderWriter(&OnDemandLuaFunctions::StringTypeToLua<ContainerType>, &OnDemandLuaFunctions::StringTypeFromLua<ContainerType>))
|
||||
->Method("ToString", [](const ContainerType& stringView) { return static_cast<AZStd::string>(stringView).c_str(); }, { { { "Reference", "String view object being converted to string" } } })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Converts string_view to string")
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
->template WrappingMember<const char*>(&ContainerType::data)
|
||||
->Method("data", &ContainerType::data)
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Returns reference to raw string data")
|
||||
->Method("length", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->length()); }, { { { "This", "Reference to the object the method is being performed on" } } })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
|
||||
->Method("size", [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->size()); }, { { { "This", "Reference to the object the method is being performed on" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Returns length of string view")
|
||||
->Method("find", [](ContainerType* thisPtr, ContainerType stringToFind, int startPos)
|
||||
{
|
||||
return aznumeric_cast<int>(thisPtr->find(stringToFind, startPos));
|
||||
}, { { { "This", "Reference to the object the method is being performed on" }, { "View", "View to search " }, { "Position", "Index in view to start search" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Searches for supplied string within this string")
|
||||
->Method("substr", [](ContainerType* thisPtr, int pos, int len)
|
||||
{
|
||||
return thisPtr->substr(pos, len);
|
||||
}, { {{"This", "Reference to the object the method is being performed on"}, {"Position", "Index in view that indicates the beginning of the sub string"}, {"Count", "Length of characters that sub string view occupies" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Creates a sub view of this string view. The string data is not actually modified")
|
||||
->Method("remove_prefix", [](ContainerType* thisPtr, int n) {thisPtr->remove_prefix(n); },
|
||||
{ { { "This", "Reference to the object the method is being performed on" }, { "Count", "Number of characters to remove from start of view" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the beginning of this sub view")
|
||||
->Method("remove_suffix", [](ContainerType* thisPtr, int n) {thisPtr->remove_suffix(n); },
|
||||
{ { { "This", "Reference to the object the method is being performed on" } ,{ "Count", "Number of characters to remove from end of view" }} })
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, "Moves the supplied number of characters from the end of this sub view")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ReflectVoidOutcome(ReflectContext* context)
|
||||
{
|
||||
using OutcomeType = AZ::Outcome<void, void>;
|
||||
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
// note we can reflect iterator types and support iterators, as of know we want to keep it simple
|
||||
behaviorContext->Class<OutcomeType>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, true)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::PrettyName, &ScriptCanvasOnDemandReflection::OnDemandPrettyName<OutcomeType>::Get)
|
||||
->Attribute(AZ::Script::Attributes::ToolTip, &ScriptCanvasOnDemandReflection::OnDemandToolTip<OutcomeType>::Get)
|
||||
->Attribute(AZ::Script::Attributes::Category, &ScriptCanvasOnDemandReflection::OnDemandCategoryName<OutcomeType>::Get)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::AllowInternalCreation, AttributeIsValid::IfPresent)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AttributeIsValid::IfPresent)
|
||||
->Method("Failure", []() -> OutcomeType { return AZ::Failure(); })
|
||||
->Method("Success", []() -> OutcomeType { return AZ::Success(); })
|
||||
->Method("IsSuccess", &OutcomeType::IsSuccess)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectStdAny(ReflectContext* context)
|
||||
{
|
||||
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AZStd::any>()
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(
|
||||
Script::Attributes::Ignore, true) // Don't reflect any type to script (there should never be an any instance in script)
|
||||
->Attribute(
|
||||
Script::Attributes::ReaderWriterOverride,
|
||||
ScriptContext::CustomReaderWriter(&AZ::OnDemandLuaFunctions::AnyToLua, &OnDemandLuaFunctions::AnyFromLua));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
@@ -8,14 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Casting/numeric_cast_internal.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzCore/std/string/osstring.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
//! A helper function to casts between numeric types, and consider the data which is being converted comse from user data.
|
||||
//! A helper function to casts between numeric types, and consider the data which is being converted comes from user data.
|
||||
//! If a conversion from FromType to ToType will not cause overflow or underflow, the result is stored in result, and the function returns Success
|
||||
//! Otherwise, the target is left untouched.
|
||||
template <typename ToType, typename FromType>
|
||||
@@ -24,9 +24,9 @@ namespace AZ
|
||||
{
|
||||
using namespace JsonSerializationResult;
|
||||
|
||||
if (NumericCastInternal::FitsInToType<ToType>(value))
|
||||
if (NumericCastInternal::template FitsInToType<ToType>(value))
|
||||
{
|
||||
result = aznumeric_cast<ToType>(value);
|
||||
result = static_cast<ToType>(value);
|
||||
return reporting("Successfully cast number.", ResultCode(Tasks::Convert, Outcomes::Success), path);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/ByteContainerStream.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
|
||||
@@ -35,6 +35,7 @@ set(FILES
|
||||
Asset/AssetInternal/WeakAsset.h
|
||||
Casting/lossy_cast.h
|
||||
Casting/numeric_cast.h
|
||||
Casting/numeric_cast_internal.h
|
||||
Component/Component.cpp
|
||||
Component/Component.h
|
||||
Component/ComponentApplication.cpp
|
||||
@@ -176,6 +177,8 @@ set(FILES
|
||||
IO/Path/Path.cpp
|
||||
IO/Path/Path.h
|
||||
IO/Path/Path.inl
|
||||
IO/Path/PathIterable.inl
|
||||
IO/Path/PathParser.inl
|
||||
IO/Path/Path_fwd.h
|
||||
IO/SystemFile.cpp
|
||||
IO/SystemFile.h
|
||||
@@ -440,6 +443,7 @@ set(FILES
|
||||
RTTI/AttributeReader.h
|
||||
RTTI/AzStdOnDemandPrettyName.inl
|
||||
RTTI/AzStdOnDemandReflection.inl
|
||||
RTTI/AzStdOnDemandReflectionSpecializations.cpp
|
||||
RTTI/AzStdOnDemandReflectionLuaFunctions.inl
|
||||
RTTI/BehaviorContext.cpp
|
||||
RTTI/BehaviorContext.h
|
||||
|
||||
@@ -9,16 +9,3 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
// types like AZ::u64 require an usigned long long, but inttypes.h has it as unsigned long
|
||||
#undef PRIX64
|
||||
#undef PRIx64
|
||||
#undef PRId64
|
||||
#undef PRIu64
|
||||
#define PRIX64 "llX"
|
||||
#define PRIx64 "llx"
|
||||
#define PRId64 "lld"
|
||||
#define PRIu64 "llu"
|
||||
|
||||
+2
-4
@@ -15,7 +15,7 @@ namespace AZStd
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void PostThreadRun();
|
||||
unsigned __stdcall PostThreadRun();
|
||||
HANDLE CreateThread(unsigned stackSize, unsigned (__stdcall* threadRunFunction)(void*), AZStd::Internal::thread_info* ti, unsigned int* id);
|
||||
unsigned HardwareConcurrency();
|
||||
void SetThreadName(HANDLE hThread, const char* threadName);
|
||||
@@ -40,9 +40,7 @@ namespace AZStd
|
||||
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to client listeners
|
||||
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to the profiler.
|
||||
|
||||
Platform::PostThreadRun();
|
||||
|
||||
return 0;
|
||||
return Platform::PostThreadRun();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -16,9 +16,10 @@ namespace AZStd
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void PostThreadRun()
|
||||
unsigned __stdcall PostThreadRun()
|
||||
{
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE CreateThread(unsigned stackSize, unsigned (__stdcall* threadRunFunction)(void*), AZStd::Internal::thread_info* ti, unsigned int* id)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
|
||||
// filesystem::path::is_absolute test
|
||||
// PathView::IsAbsolute test
|
||||
TEST_F(PathFixture, IsAbsolute_ReturnsTrue)
|
||||
{
|
||||
using fixed_max_path = AZ::IO::FixedMaxPath;
|
||||
@@ -88,7 +88,7 @@ namespace UnitTest
|
||||
static_assert(IsAbsolute());
|
||||
}
|
||||
|
||||
// filesystem::path::is_relative test
|
||||
// PathView::isRelative test
|
||||
TEST_F(PathFixture, IsRelative_ReturnsTrue)
|
||||
{
|
||||
using fixed_max_path = AZ::IO::FixedMaxPath;
|
||||
@@ -573,7 +573,16 @@ namespace UnitTest
|
||||
PathLexicallyNormalParams{ '/', "foo/./bar/..", "foo" },
|
||||
PathLexicallyNormalParams{ '/', "foo/.///bar/../", "foo" },
|
||||
PathLexicallyNormalParams{ '/', R"(/foo\./bar\..\)", "/foo" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/O3DE/dev/Cache\game/../pc)", R"(C:\O3DE\dev\Cache\pc)" }
|
||||
PathLexicallyNormalParams{ '/', R"(/..)", "/" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/O3DE/dev/Cache\game/../pc)", R"(C:\O3DE\dev\Cache\pc)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:bar)", R"(C:\foo\bar)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:foo/C:bar)", R"(C:foo\bar)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:/bar)", R"(C:\bar)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:)", R"(C:\foo)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/foo/C:/)", R"(C:\)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(C:/foo/D:bar)", R"(D:bar)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(..)", R"(..)" },
|
||||
PathLexicallyNormalParams{ '\\', R"(foo/../../bar)", R"(..\bar)" }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -641,7 +650,12 @@ namespace UnitTest
|
||||
PathViewLexicallyProximateParams{ '\\', "C:\\a\\b", "C:\\a\\d\\c", "..\\..\\b", false },
|
||||
PathViewLexicallyProximateParams{ '\\', "C:a\\b", "C:\\a\\b", "C:a\\b", false },
|
||||
PathViewLexicallyProximateParams{ '\\', "C:\\a\\b", "C:a\\b", "C:\\a\\b", false },
|
||||
PathViewLexicallyProximateParams{ '\\', "E:\\a\\b", "F:\\a\\b", "E:\\a\\b", false }
|
||||
PathViewLexicallyProximateParams{ '\\', "E:\\a\\b", "F:\\a\\b", "E:\\a\\b", false },
|
||||
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/asset.txt", "d:\\o3de\\Project\\Cache", "asset.txt", true },
|
||||
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/pc/..", "d:\\o3de\\Project\\Cache", "pc\\..", true },
|
||||
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/pc/asset.txt/..", "d:\\o3de\\Project\\Cache\\", "pc\\asset.txt\\..", true },
|
||||
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache\\", "D:\\o3de\\Project\\Cache/", ".", true },
|
||||
PathViewLexicallyProximateParams{ '\\', "D:/o3de/proJECT/cache/../foo", "D:\\o3de\\Project\\Cache", "..\\foo", false }
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/Settings/SettingsRegistryScriptUtils.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
|
||||
namespace SettingsRegistryScriptUtilsTests
|
||||
{
|
||||
static constexpr const char* SettingsRegistryScriptClassName = "SettingsRegistryInterface";
|
||||
|
||||
|
||||
|
||||
class SettingsRegistryBehaviorContextFixture
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
@@ -77,7 +78,7 @@ namespace SettingsRegistryScriptUtilsTests
|
||||
// so the invoking the getter on global Settings Registry should succeed, but return nullptr
|
||||
EXPECT_TRUE(globalSettingsRegistryGetter->InvokeResult(settingsRegistryObject));
|
||||
EXPECT_EQ(nullptr, settingsRegistryObject.m_settingsRegistry);
|
||||
|
||||
|
||||
// Register the Settings Registry stored on the fixture with the SettingsRegistry Interface<T>
|
||||
AZ::SettingsRegistry::Register(m_registry.get());
|
||||
EXPECT_TRUE(globalSettingsRegistryGetter->InvokeResult(settingsRegistryObject));
|
||||
@@ -227,7 +228,7 @@ namespace SettingsRegistryScriptUtilsTests
|
||||
R"( "intIndex": -55)" "\n"
|
||||
R"( })" "\n"
|
||||
R"(])";
|
||||
|
||||
|
||||
// Populate the settings registry to match the expected json values
|
||||
m_registry->Set("/TestObject/boolValue", false);
|
||||
m_registry->Set("/TestObject/intValue", aznumeric_cast<AZ::s64>(17));
|
||||
@@ -562,4 +563,4 @@ namespace SettingsRegistryScriptUtilsTests
|
||||
SettingsRegistryBehaviorContextParams{ "/TestObject/stringValue", AZStd::string_view{"Hello World"}, "GetString", "SetString" }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user