Merge branch 'development' into cmake/warn_virtual

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-09-10 20:27:01 -07:00
156 changed files with 35196 additions and 34784 deletions
@@ -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);
}
+20 -5
View File
@@ -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"
@@ -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();
}
/**
@@ -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" }
)
);
}
}