Sfoglia il codice sorgente

Range adaptor support (#7388)

* Updated the SFINAE checks in concepts.h and range.h

To use conjunction and disjunction for short-circuiting behavior.

Replaced AZStd::optional implementation with std::optional alias

Added range adaptor support and the following views: ref_view,
owning_view

Added bitwise or(|) overload for chaining range adaptor closures together

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding indirectly invocable concepts.

These concepts are used to determine whether a callable can be invoked
with a dereferenced iterator instance.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Add implementation of range relational function objects

Add implementation of range min max functions which uses the range
relation function objects(ranges::less, ranges::equal_to, etc...)

This is needed to implement ranges::zip_view

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding interface for zip_view which compiles successfully

The implementation for the zip view functions still need to be filled.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding function definitions for zip_view classes.

Adding empty header of subrange.h for the ranges::subrange class

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding additional view implementations.

The following range and view classes have been added: empty_view,
single_view and subrange.

Moved the AZ_NO_UNIQUE_ADDRESS macro to PlatformDef.h to allow other
code to specify the [[no_unique_address]] attribute.

Added additional test for view structures.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding missing includes for non-unity builds

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Workaround for NDK21 clang 9.0.9 compile issue.

The AZStd::ranges::zip_view::iterator::iter_swap friend function is in the
AZStd::ranges namespace, while the customization point object of
`AZStd::ranges::customization_point_object::iter_swap` is in the regular
namespace of `AZStd::ranges` and the inline namespace of
`customization_point`.

This issue is fixed in NDK23, but as Jenkins uses NDK21 at the time, the
entire zip_view implementation has moved to inline namespace of
`zip_view_internal`

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Added iterator algorithm requiremetn concepts

Fixed the ambiguity in the ranges::iter_swap exchange overload to
exclude itself as a candidate if the iterator reference types are
swappable with each other.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding type alias for borrowed_subrange_t

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Fixed convertible to ref_view check in the ranges::all
customization_point

Updated SFINAE detection of whether AZStd::to_address is invocable

Moved the

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Fixed private variable access in ranges::subrange get specialization.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Removing ranges::view constraint from the ranges::views::single
customization_point.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding C++23 range overload for string_view.

It is detailed in the [C++draft strings](https://eel.is/c++draft/strings#lib:basic_string_view,constructor____) section

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding implementations of ranges, find, search, mismatch and equal
functions.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding implementation of ranges split_view along with test.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding const overloads to SceneAPI ProxyPointer container

The Proxy Pointer class operator* and operator-> was unable to be
invoked with a const instance before. Now it returns a const view of the
pointer it contains.
This allows it to be invoked in `AZStd::to_address` as part of an SINAE
context for the contiguous_iterator concept

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Refactored the to_address implementation to better work with SFINAE.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding general non-unity build fixes

This is unrelated to the RangeAdaptor changes.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Allow range algorithms to be used with rvalue ranges

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Workaround MSVC Internal Compiler erroy by removing enable_if
condition in the operator bool of the view_interface class.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Corrected the non_propagating_cache helper class to have public
functions

Fixed the order of creating the perfect forwarding call wrapper for an
outer closure around another closure.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Specialized the borrowed_range and view concepts

For the AZ PathView class, since it is a immutable view around a path.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Removed inline namespace around the zip_view class.

It was needed to workaround a clang 10 or below issue where a friend
function in a namespace and a variable within underneath an inline
namespace within the function namespace would cause an improper symbol
redefinition.

The workaround is to create a placeholder namespace containing the
inline namespace and then bring that placeholder namespace into the
parent scope.

https://bugs.llvm.org/show_bug.cgi?id=37556

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding implementation of the elemetns_view and join_view classes

It is up to date with the standard as of the current draft:
https://eel.is/c++draft/ranges.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Separated definitions of concepts out of concepts.h

This allows the ranges::iter_swap and ranges::swap customization point to be moved
outside of the concepts folder and into the ranges folder.

The concepts.h header previously had to define those objects to avoid
circular dependencies.

Added the work around for ranges::iter_swap and ranges::iter_move
customization_point causing an improper symbol redefinition in clang 10
or below: https://bugs.llvm.org/show_bug.cgi?id=37556

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Alias more std:: names into the AZStd namespace.

Removed our custom implementation of toaddress.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding more range view test.

The join_view and elements_view classes now have UnitTest.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Adding deduction guides for AZStd associative containers

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Moved zip_view::sentinel iterator accessor function to zip_view.inl

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Fixed variable shadowing issues with clang 12+

Signed-off-by: lumberyard-employee-dm <[email protected]>
lumberyard-employee-dm 3 anni fa
parent
commit
d7ee248df5
62 ha cambiato i file con 6484 aggiunte e 1856 eliminazioni
  1. 4 1
      Code/Framework/AzCore/AzCore/IO/Path/Path.h
  2. 10 6
      Code/Framework/AzCore/AzCore/IO/Path/Path.inl
  3. 9 2
      Code/Framework/AzCore/AzCore/PlatformDef.h
  4. 1 4
      Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl
  5. 6 8
      Code/Framework/AzCore/AzCore/RTTI/TypeInfo.h
  6. 1 3
      Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl
  7. 1 0
      Code/Framework/AzCore/AzCore/Threading/ThreadSafeObject.h
  8. 20 0
      Code/Framework/AzCore/AzCore/std/azstd_files.cmake
  9. 342 449
      Code/Framework/AzCore/AzCore/std/concepts/concepts.h
  10. 34 0
      Code/Framework/AzCore/AzCore/std/concepts/concepts_assignable.h
  11. 26 0
      Code/Framework/AzCore/AzCore/std/concepts/concepts_constructible.h
  12. 60 0
      Code/Framework/AzCore/AzCore/std/concepts/concepts_copyable.h
  13. 35 0
      Code/Framework/AzCore/AzCore/std/concepts/concepts_movable.h
  14. 43 5
      Code/Framework/AzCore/AzCore/std/containers/map.h
  15. 22 1
      Code/Framework/AzCore/AzCore/std/containers/node_handle.h
  16. 41 5
      Code/Framework/AzCore/AzCore/std/containers/set.h
  17. 119 4
      Code/Framework/AzCore/AzCore/std/containers/unordered_map.h
  18. 98 5
      Code/Framework/AzCore/AzCore/std/containers/unordered_set.h
  19. 1 1
      Code/Framework/AzCore/AzCore/std/function/identity.h
  20. 16 0
      Code/Framework/AzCore/AzCore/std/function/invoke.h
  21. 0 4
      Code/Framework/AzCore/AzCore/std/iterator.h
  22. 116 13
      Code/Framework/AzCore/AzCore/std/iterator/iterator_primitives.h
  23. 7 997
      Code/Framework/AzCore/AzCore/std/optional.h
  24. 67 0
      Code/Framework/AzCore/AzCore/std/ranges/all_view.h
  25. 475 0
      Code/Framework/AzCore/AzCore/std/ranges/elements_view.h
  26. 37 0
      Code/Framework/AzCore/AzCore/std/ranges/empty_view.h
  27. 10 2
      Code/Framework/AzCore/AzCore/std/ranges/iter_move.h
  28. 120 0
      Code/Framework/AzCore/AzCore/std/ranges/iter_swap.h
  29. 430 0
      Code/Framework/AzCore/AzCore/std/ranges/join_view.h
  30. 114 0
      Code/Framework/AzCore/AzCore/std/ranges/owning_view.h
  31. 290 139
      Code/Framework/AzCore/AzCore/std/ranges/ranges.h
  32. 333 0
      Code/Framework/AzCore/AzCore/std/ranges/ranges_adaptor.h
  33. 996 0
      Code/Framework/AzCore/AzCore/std/ranges/ranges_algorithm.h
  34. 121 0
      Code/Framework/AzCore/AzCore/std/ranges/ranges_functional.h
  35. 77 0
      Code/Framework/AzCore/AzCore/std/ranges/ref_view.h
  36. 89 0
      Code/Framework/AzCore/AzCore/std/ranges/single_view.h
  37. 235 0
      Code/Framework/AzCore/AzCore/std/ranges/split_view.h
  38. 290 0
      Code/Framework/AzCore/AzCore/std/ranges/subrange.h
  39. 116 0
      Code/Framework/AzCore/AzCore/std/ranges/swap.h
  40. 395 0
      Code/Framework/AzCore/AzCore/std/ranges/zip_view.h
  41. 308 0
      Code/Framework/AzCore/AzCore/std/ranges/zip_view.inl
  42. 41 0
      Code/Framework/AzCore/AzCore/std/string/string_view.h
  43. 6 14
      Code/Framework/AzCore/AzCore/std/tuple.h
  44. 3 23
      Code/Framework/AzCore/AzCore/std/typetraits/conjunction.h
  45. 3 22
      Code/Framework/AzCore/AzCore/std/typetraits/disjunction.h
  46. 12 31
      Code/Framework/AzCore/AzCore/std/typetraits/is_constructible.h
  47. 3 9
      Code/Framework/AzCore/AzCore/std/typetraits/negation.h
  48. 12 102
      Code/Framework/AzCore/AzCore/std/utils.h
  49. 119 0
      Code/Framework/AzCore/Tests/AZStd/ConceptsTests.cpp
  50. 250 0
      Code/Framework/AzCore/Tests/AZStd/RangesAlgorithmTests.cpp
  51. 483 0
      Code/Framework/AzCore/Tests/AZStd/RangesViewTests.cpp
  52. 1 0
      Code/Framework/AzCore/Tests/Main.cpp
  53. 2 0
      Code/Framework/AzCore/Tests/azcoretests_files.cmake
  54. 1 2
      Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
  55. 1 1
      Code/Tools/LuaIDE/Source/LUA/BreakpointPanel.cpp
  56. 5 1
      Code/Tools/SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.h
  57. 20 0
      Code/Tools/SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.inl
  58. 1 0
      Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactCommandLineOptions.h
  59. 2 1
      Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h
  60. 2 1
      Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h
  61. 1 0
      Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowserInteractions.h
  62. 1 0
      Gems/PythonAssetBuilder/Code/Source/PythonBuilderMessageSink.h

+ 4 - 1
Code/Framework/AzCore/AzCore/IO/Path/Path.h

@@ -709,7 +709,10 @@ namespace AZ::IO
 
         constexpr reference operator*() const;
 
-        constexpr pointer operator->() const;
+        constexpr pointer operator->() const
+        {
+            return &m_stashed_elem;
+        }
 
         constexpr PathIterator& operator++();
 

+ 10 - 6
Code/Framework/AzCore/AzCore/IO/Path/Path.inl

@@ -1397,12 +1397,6 @@ namespace AZ::IO
         return m_stashed_elem;
     }
 
-    template <typename PathType>
-    constexpr auto PathIterator<PathType>::operator->() const -> pointer
-    {
-        return &m_stashed_elem;
-    }
-
     template <typename PathType>
     constexpr auto PathIterator<PathType>::operator++() -> PathIterator&
     {
@@ -1542,3 +1536,13 @@ namespace AZ::IO
     extern template bool operator!=<const FixedMaxPath>(const PathIterator<const FixedMaxPath>& lhs,
         const PathIterator<const FixedMaxPath>& rhs);
 }
+
+namespace AZStd::ranges
+{
+    // A PathView is a borrowed range, it does not own the content of the Path it is viewing
+    template<>
+    inline constexpr bool enable_borrowed_range<AZ::IO::PathView> = true;
+
+    template<>
+    inline constexpr bool enable_view<AZ::IO::PathView> = true;
+}

+ 9 - 2
Code/Framework/AzCore/AzCore/PlatformDef.h

@@ -83,7 +83,7 @@
 #define AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
 
 /// Compiler specific AZ_POP_DISABLE_WARNING. This needs to be matched with the compiler specific AZ_PUSH_DISABLE_WARNINGs
-#define AZ_POP_DISABLE_WARNING_CLANG                     
+#define AZ_POP_DISABLE_WARNING_CLANG
 #define AZ_POP_DISABLE_WARNING_MSVC                     \
     __pragma(warning(pop))
 #define AZ_POP_DISABLE_WARNING_GCC
@@ -176,7 +176,7 @@
 #define AZ_PUSH_DISABLE_WARNING_3(_1, _2, _gccOption)   AZ_PUSH_DISABLE_WARNING_GCC(_gccOption)
 
 /// Pops the warning stack. For use matched with an AZ_PUSH_DISABLE_WARNING
-#define AZ_POP_DISABLE_WARNING                              
+#define AZ_POP_DISABLE_WARNING
     _Pragma("GCC diagnostic pop")
 
 #endif // defined(AZ_COMPILER_CLANG)
@@ -303,3 +303,10 @@
 #if !defined(az_has_builtin_wmemmove)
     #define az_has_builtin_wmemmove false
 #endif
+
+// no unique address attribute support in C++17
+#if __has_cpp_attribute(no_unique_address)
+    #define AZ_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#else
+    #define AZ_NO_UNIQUE_ADDRESS
+#endif

+ 1 - 4
Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl

@@ -13,6 +13,7 @@
 #include <AzCore/ScriptCanvas/ScriptCanvasOnDemandNames.h>
 #include <AzCore/RTTI/AzStdOnDemandPrettyName.inl>
 #include <AzCore/RTTI/AzStdOnDemandReflectionLuaFunctions.inl>
+#include <AzCore/std/optional.h>
 
 #ifndef AZ_USE_CUSTOM_SCRIPT_BIND
 struct lua_State;
@@ -47,10 +48,6 @@ namespace AZStd
     class intrusive_ptr;
     template<class T>
     class shared_ptr;
-
-    // Wrapper types
-    template <typename T>
-    class optional;
 }
 
 namespace AZ

+ 6 - 8
Code/Framework/AzCore/AzCore/RTTI/TypeInfo.h

@@ -18,6 +18,7 @@
 #include <AzCore/std/typetraits/has_member_function.h>
 #include <AzCore/std/typetraits/void_t.h>
 #include <AzCore/std/function/invoke.h>
+#include <AzCore/std/optional.h>
 
 #include <AzCore/Math/Uuid.h>
 #include <AzCore/Math/Crc.h>
@@ -89,9 +90,6 @@ namespace AZStd
     template<class Signature>
     class function;
 
-    template<class T>
-    class optional;
-
     struct monostate;
 
     template<class... Types>
@@ -150,7 +148,7 @@ namespace AZ
         template <template <typename...> class> constexpr bool false_v1 = false;
 #if defined(AZ_COMPILER_MSVC)
         // There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
-        // template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack. 
+        // template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
         template<template<AZStd::size_t...> class> constexpr bool false_v2 = false;
 #else
         template<template<auto...> class> constexpr bool false_v2 = false;
@@ -176,7 +174,7 @@ namespace AZ
         }
 #if defined(AZ_COMPILER_MSVC)
         // There is a bug with the MSVC compiler when using the 'auto' keyword here. It appears that MSVC is unable to distinguish between a template
-        // template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack. 
+        // template argument with a type variadic pack vs a template template argument with a non-type auto variadic pack.
         template<template<AZStd::size_t...> class T>
 #else
         template<template<auto...> class T>
@@ -326,7 +324,7 @@ namespace AZ
         using TypeIdHolder = AZ::TypeId;
 #endif
 
-        // Represents the "*" typeid that can be combined with non-pointer types T to form a unique T* typeid 
+        // Represents the "*" typeid that can be combined with non-pointer types T to form a unique T* typeid
         inline static const AZ::TypeId& PointerTypeId()
         {
             static TypeIdHolder s_uuid("{35C8A027-FE00-4769-AE36-6997CFFAF8AE}");
@@ -977,7 +975,7 @@ namespace AZ
     AZ_TYPE_INFO_INTERNAL_SPECIALIZE_CV(T, const T&, "const ", "&");
     AZ_TYPE_INFO_INTERNAL_SPECIALIZE_CV(T, const T&&, "const ", "&&");
     AZ_TYPE_INFO_INTERNAL_SPECIALIZE_CV(T, const T, "const ", "");
-    
+
     AZ_TYPE_INFO_INTERNAL_SPECIALIZED_TEMPLATE_POSTFIX_UUID(AZStd::less,                "{41B40AFC-68FD-4ED9-9EC7-BA9992802E1B}", AZ_TYPE_INFO_INTERNAL_TYPENAME);
     AZ_TYPE_INFO_INTERNAL_SPECIALIZED_TEMPLATE_POSTFIX_UUID(AZStd::less_equal,          "{91CC0BDC-FC46-4617-A405-D914EF1C1902}", AZ_TYPE_INFO_INTERNAL_TYPENAME);
     AZ_TYPE_INFO_INTERNAL_SPECIALIZED_TEMPLATE_POSTFIX_UUID(AZStd::greater,             "{907F012A-7A4F-4B57-AC23-48DC08D0782E}", AZ_TYPE_INFO_INTERNAL_TYPENAME);
@@ -1014,7 +1012,7 @@ namespace AZ
 
     static constexpr const char* s_variantTypeId{ "{1E8BB1E5-410A-4367-8FAA-D43A4DE14D4B}" };
     AZ_TYPE_INFO_INTERNAL_SPECIALIZED_TEMPLATE_PREFIX_UUID(AZStd::variant, "variant", s_variantTypeId, AZ_TYPE_INFO_INTERNAL_TYPENAME_VARARGS);
-    
+
     AZ_TYPE_INFO_INTERNAL_FUNCTION_VARIATION_SPECIALIZATION(AZStd::function, "{C9F9C644-CCC3-4F77-A792-F5B5DBCA746E}");
 } // namespace AZ
 

+ 1 - 3
Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl

@@ -11,6 +11,7 @@
 #include <AzCore/Outcome/Outcome.h>
 #include <AzCore/Memory/OSAllocator.h>
 #include <AzCore/std/containers/stack.h>
+#include <AzCore/std/optional.h>
 #include <AzCore/std/smart_ptr/unique_ptr.h>
 #include <AzCore/std/tuple.h>
 
@@ -47,9 +48,6 @@ namespace AZStd
     class intrusive_ptr;
     template<class T>
     class shared_ptr;
-
-    template<class T>
-    class optional;
 }
 
 namespace AZ

+ 1 - 0
Code/Framework/AzCore/AzCore/Threading/ThreadSafeObject.h

@@ -8,6 +8,7 @@
 
 #pragma once
 
+#include <AzCore/std/parallel/mutex.h>
 #include <AzCore/std/parallel/scoped_lock.h>
 
 namespace AZ

+ 20 - 0
Code/Framework/AzCore/AzCore/std/azstd_files.cmake

@@ -20,6 +20,10 @@ set(FILES
     base.h
     config.h
     concepts/concepts.h
+    concepts/concepts_assignable.h
+    concepts/concepts_constructible.h
+    concepts/concepts_copyable.h
+    concepts/concepts_movable.h
     createdestroy.h
     docs.h
     exceptions.h
@@ -34,8 +38,24 @@ set(FILES
     numeric.h
     math.h
     optional.h
+    ranges/all_view.h
+    ranges/elements_view.h
+    ranges/empty_view.h
     ranges/iter_move.h
+    ranges/iter_swap.h
+    ranges/join_view.h
+    ranges/owning_view.h
     ranges/ranges.h
+    ranges/ranges_adaptor.h
+    ranges/ranges_algorithm.h
+    ranges/ranges_functional.h
+    ranges/ref_view.h
+    ranges/single_view.h
+    ranges/subrange.h
+    ranges/split_view.h
+    ranges/swap.h
+    ranges/zip_view.h
+    ranges/zip_view.inl
     ratio.h
     reference_wrapper.h
     sort.h

+ 342 - 449
Code/Framework/AzCore/AzCore/std/concepts/concepts.h

@@ -7,20 +7,21 @@
  */
 #pragma once
 
+#include <AzCore/std/concepts/concepts_assignable.h>
+#include <AzCore/std/concepts/concepts_constructible.h>
+#include <AzCore/std/concepts/concepts_copyable.h>
+#include <AzCore/std/concepts/concepts_movable.h>
 #include <AzCore/std/function/invoke.h>
 #include <AzCore/std/iterator/iterator_primitives.h>
+#include <AzCore/std/ranges/swap.h>
 #include <AzCore/std/ranges/iter_move.h>
+#include <AzCore/std/ranges/iter_swap.h>
 
 #include <AzCore/std/typetraits/add_pointer.h>
 #include <AzCore/std/typetraits/common_reference.h>
-#include <AzCore/std/typetraits/extent.h>
 #include <AzCore/std/typetraits/is_array.h>
-#include <AzCore/std/typetraits/is_assignable.h>
 #include <AzCore/std/typetraits/is_class.h>
-#include <AzCore/std/typetraits/is_constructible.h>
-#include <AzCore/std/typetraits/is_destructible.h>
 #include <AzCore/std/typetraits/is_enum.h>
-#include <AzCore/std/typetraits/is_floating_point.h>
 #include <AzCore/std/typetraits/is_function.h>
 #include <AzCore/std/typetraits/is_integral.h>
 #include <AzCore/std/typetraits/is_object.h>
@@ -54,21 +55,11 @@ namespace AZStd
 
 namespace AZStd::Internal
 {
-    template <typename T, typename = void>
-    constexpr bool pointer_traits_has_to_address_v = false;
-
-    template <typename T>
-    constexpr bool pointer_traits_has_to_address_v<T, enable_if_t<
-        is_void_v<void_t<decltype(pointer_traits<T>::to_address(declval<const T&>()))>>> > = true;
-
-
-    // pointer_traits isn't SFINAE friendly https://cplusplus.github.io/LWG/lwg-active.html#3545
-    // So working around that by checking if type T has an element_type alias
-    template <typename T, typename = void>
-    constexpr bool pointer_traits_valid_and_has_to_address_v = false;
-    template <typename T>
-    constexpr bool pointer_traits_valid_and_has_to_address_v<T, enable_if_t<has_element_type_v<T>> >
-        = pointer_traits_has_to_address_v<T>;
+    // Variadic template which maps types to true For SFINAE
+    template <class... Args>
+    using sfinae_trigger = true_type;
+    template <class... Args>
+    constexpr bool sfinae_trigger_v = true;
 }
 
 namespace AZStd
@@ -76,60 +67,98 @@ namespace AZStd
     //! Implements the C++20 to_address function
     //! This obtains the address represented by ptr without forming a reference
     //! to the pointee type
-    template <typename T>
-    constexpr T* to_address(T* ptr) noexcept
-    {
-        static_assert(!AZStd::is_function_v<T>, "Invoking to address on a function pointer is not allowed");
-        return ptr;
-    }
-    //! Fancy pointer overload which delegates to using a specialization of pointer_traits<T>::to_address
-    //! if that is a well-formed expression, otherwise it returns ptr->operator->()
-    //! For example invoking `to_address(AZStd::reverse_iterator<const char*>(char_ptr))`
-    //! Returns an element of type const char*
-    template <typename T>
-    constexpr auto to_address(const T& ptr) noexcept
+    namespace Internal
     {
-        if constexpr (AZStd::Internal::pointer_traits_valid_and_has_to_address_v<T>)
+        template <class T, class = void, class = void>
+        constexpr bool pointer_traits_has_to_address_v = false;
+
+        // pointer_traits isn't SFINAE friendly https://cplusplus.github.io/LWG/lwg-active.html#3545
+        // working around that by checking if type T has an element_type alias
+        template <class T>
+        constexpr bool pointer_traits_has_to_address_v<T, enable_if_t<has_element_type_v<T>>,
+            void_t<decltype(pointer_traits<T>::to_address(declval<const T&>()))>> = true;
+
+        // fancy pointer helper
+        template <class T, class = void>
+        struct to_address_fancy_pointer_fn;
+
+        struct to_address_fn
         {
-            return pointer_traits<T>::to_address(ptr);
-        }
-        else
+        public:
+            template <class T>
+            constexpr T* operator()(T* ptr) const noexcept
+            {
+                static_assert(!AZStd::is_function_v<T>, "Invoking to address on a function pointer is not allowed");
+                return ptr;
+            }
+
+            //! Fancy pointer overload which delegates to using a specialization of pointer_traits<T>::to_address
+            //! if that is a well-formed expression, otherwise it returns ptr->operator->()
+            //! For example invoking `to_address(AZStd::reverse_iterator<const char*>(char_ptr))`
+            //! Returns an element of type const char*
+            template <class T, class = enable_if_t<conjunction_v<
+                bool_constant<!is_pointer_v<T>>,
+                bool_constant<!is_array_v<T>>,
+                bool_constant<!is_function_v<T>>,
+                sfinae_trigger<decltype(declval<to_address_fancy_pointer_fn<T>>().operator()(declval<T>()))>
+                >>>
+            constexpr auto operator()(const T& ptr) const noexcept;
+        };
+
+        template <class T>
+        struct to_address_fancy_pointer_fn<T, enable_if_t<
+            sfinae_trigger_v<decltype(declval<const T&>().operator->())>>>
         {
-            return to_address(ptr.operator->());
+            constexpr auto operator()(const T& ptr) const noexcept
+            {
+                return to_address_fn{}(ptr.operator->());
+            }
+        };
+
+        
+        template <class T>
+        struct to_address_fancy_pointer_fn<T, enable_if_t<
+            pointer_traits_has_to_address_v<T>>>
+        {
+            constexpr auto operator()(const T& ptr) const noexcept
+            {
+                return pointer_traits<T>::to_address(ptr);
+            }
+        };
+
+        template <class T, class>
+        constexpr auto to_address_fn::operator()(const T& ptr) const noexcept
+        {
+            return to_address_fancy_pointer_fn<T>{}(ptr);
         }
     }
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::to_address_fn to_address{};
+    }
 }
 
 namespace AZStd::Internal
 {
-    // Variadic template which maps types to true For SFINAE
-    template <class... Args>
-    constexpr bool sfinae_trigger_v = true;
-
     template <class It, class = void>
     constexpr bool is_class_or_enum = false;
     template <class It>
-    constexpr bool is_class_or_enum<It, enable_if_t<
-        (is_class_v<remove_cvref_t<It>> || is_enum_v<remove_cvref_t<It>>)>> = true;
-
-    template<class LHS, class RHS, class = void>
-    constexpr bool assignable_from_impl = false;
-    template<class LHS, class RHS>
-    constexpr bool assignable_from_impl<LHS, RHS, enable_if_t<is_lvalue_reference_v<LHS>
-        && common_reference_with<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&>
-        && same_as<decltype(declval<LHS>() = declval<RHS>()), LHS> >> = true;
+    constexpr bool is_class_or_enum<It, enable_if_t<disjunction_v<
+        is_class<remove_cvref_t<It>>, is_enum<remove_cvref_t<It>> >>> = true;
 
 
     template<class T, class U, class = void>
     constexpr bool common_with_impl = false;
     template<class T, class U>
-    constexpr bool common_with_impl<T, U, enable_if_t<
-        same_as<common_type_t<T, U>, common_type_t<U, T>>
-        && sfinae_trigger_v<decltype(static_cast<common_type_t<T, U>>(declval<T>()))>
-        && sfinae_trigger_v<decltype(static_cast<common_type_t<T, U>>(declval<U>()))>
-        && common_reference_with<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>
-        && common_reference_with<add_lvalue_reference_t<common_type_t<T, U>>, common_reference_t<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>>
-        >> = true;
+    constexpr bool common_with_impl<T, U, enable_if_t<conjunction_v<
+        bool_constant<same_as<common_type_t<T, U>, common_type_t<U, T>>>,
+        sfinae_trigger<decltype(static_cast<common_type_t<T, U>>(declval<T>()))>,
+        sfinae_trigger<decltype(static_cast<common_type_t<T, U>>(declval<U>()))>,
+        bool_constant<common_reference_with<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>>,
+        bool_constant<common_reference_with<add_lvalue_reference_t<common_type_t<T, U>>,
+            common_reference_t<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -137,99 +166,18 @@ namespace AZStd
     template<class T, class U>
     /*concept*/ constexpr bool common_with = Internal::common_with_impl<T, U>;
 
-    template<class LHS, class RHS>
-    /*concept*/ constexpr bool assignable_from = Internal::assignable_from_impl<LHS, RHS>;
-
-    template<class T, class... Args>
-    /*concept*/ constexpr bool constructible_from = destructible<T> && is_constructible_v<T, Args...>;
-
-    template<class T>
-    /*concept*/ constexpr bool move_constructible = constructible_from<T, T> && convertible_to<T, T>;
 
     template<class Derived, class Base>
-    /*concept*/ constexpr bool derived_from = is_base_of_v<Base, Derived> && is_convertible_v<const volatile Derived*, const volatile Base*>;
-}
-
-namespace AZStd::ranges::Internal
-{
-    template <class T, class U, class = void>
-    constexpr bool is_class_or_enum_with_swap_adl = false;
-    template <class T, class U>
-    constexpr bool is_class_or_enum_with_swap_adl<T, U, enable_if_t<
-        (is_class_v<remove_cvref_t<T>> || is_enum_v<remove_cvref_t<T>>
-            || is_class_v<remove_cvref_t<U>> || is_enum_v<remove_cvref_t<T>>)
-        && is_void_v<void_t<decltype(swap(declval<T&>(), declval<U&>()))>>
-        >> = true;
-
-    template <class T>
-    void swap(T&, T&) = delete;
-
-    struct swap_fn
-    {
-        template <class T, class U>
-        constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept(swap(AZStd::forward<T>(t), AZStd::forward<U>(u))))
-            ->enable_if_t<is_class_or_enum_with_swap_adl<T, U>>
-        {
-            swap(AZStd::forward<T>(t), AZStd::forward<U>(u));
-        }
-
-        // ranges::swap customization point https://eel.is/c++draft/concepts#concept.swappable-2.2
-        // Implemented in ranges.h as to prevent circular dependency.
-        // ranges::swap_ranges depends on the range concepts that can't be defined here
-        template <class T, class U>
-        constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept((*this)(*t, *u)))
-            ->enable_if_t<!is_class_or_enum_with_swap_adl<T, U>
-            && is_array_v<T> && is_array_v<U> && (extent_v<T> == extent_v<U>)
-            >;
-
-        template <class T>
-        constexpr auto operator()(T& t1, T& t2) const noexcept(noexcept(is_nothrow_move_constructible_v<T>&& is_nothrow_move_assignable_v<T>))
-            ->enable_if_t<move_constructible<T>&& assignable_from<T&, T>>
-        {
-            auto temp(AZStd::move(t1));
-            t1 = AZStd::move(t2);
-            t2 = AZStd::move(temp);
-        }
-    };
+    /*concept*/ constexpr bool derived_from = conjunction_v<is_base_of<Base, Derived>,
+        is_convertible<const volatile Derived*, const volatile Base*>>;
 }
 
-namespace AZStd::ranges
-{
-    inline namespace customization_point_object
-    {
-        inline constexpr auto swap = Internal::swap_fn{};
-    }
-}
-
-namespace AZStd::Internal
-{
-    template <class T, class = void>
-    constexpr bool swappable_impl = false;
-    template <class T>
-    constexpr bool swappable_impl<T, void_t<decltype(AZStd::ranges::swap(declval<T&>(), declval<T&>()))>> = true;
-
-    template <class T, class U, class = void>
-    constexpr bool swappable_with_impl = false;
-    template <class T, class U>
-    constexpr bool swappable_with_impl<T, U, enable_if_t<common_reference_with<T, U>
-        && sfinae_trigger_v<
-        decltype(AZStd::ranges::swap(declval<T&>(), declval<T&>())),
-        decltype(AZStd::ranges::swap(declval<U&>(), declval<U&>())),
-        decltype(AZStd::ranges::swap(declval<T&>(), declval<U&>())),
-        decltype(AZStd::ranges::swap(declval<U&>(), declval<T&>()))>>> = true;
-}
 namespace AZStd
 {
     template <class T>
-    /*concept*/ constexpr bool signed_integral = integral<T> && is_signed_v<T>;
+    /*concept*/ constexpr bool signed_integral = conjunction_v<bool_constant<integral<T>>, is_signed<T>>;
     template <class T>
-    /*concept*/ constexpr bool unsigned_integral = integral<T> && !signed_integral<T>;
-
-    template<class T>
-    /*concept*/ constexpr bool swappable = Internal::swappable_impl<T>;
-
-    template<class T, class U>
-    /*concept*/ constexpr bool swappable_with = Internal::swappable_with_impl<T, U>;
+    /*concept*/ constexpr bool unsigned_integral = conjunction_v<bool_constant<integral<T>>, bool_constant<!signed_integral<T>>>;
 }
 
 
@@ -242,33 +190,34 @@ namespace AZStd::Internal
     template<class T, class = void>
     constexpr bool boolean_testable = false;
     template<class T>
-    constexpr bool boolean_testable<T, enable_if_t<boolean_testable_impl<T> && boolean_testable_impl<decltype(!declval<T>())>>> = true;
+    constexpr bool boolean_testable<T, enable_if_t<conjunction_v<bool_constant<boolean_testable_impl<T>>,
+        bool_constant<boolean_testable_impl<decltype(!declval<T>())>> >>> = true;
 
     // weakly comparable ==, !=
     template<class T, class U, class = void>
     constexpr bool weakly_equality_comparable_with = false;
     template<class T, class U>
-    constexpr bool weakly_equality_comparable_with<T, U, enable_if_t<
-        boolean_testable<decltype(declval<AZStd::remove_reference_t<T>&>() == declval<AZStd::remove_reference_t<U>&>())>
-        && boolean_testable<decltype(declval<AZStd::remove_reference_t<T>&>() != declval<AZStd::remove_reference_t<U>&>())>
-        && boolean_testable<decltype(declval<AZStd::remove_reference_t<U>&>() == declval<AZStd::remove_reference_t<T>&>())>
-        && boolean_testable<decltype(declval<AZStd::remove_reference_t<U>&>() != declval<AZStd::remove_reference_t<T>&>())>
-        >> = true;
+    constexpr bool weakly_equality_comparable_with<T, U, enable_if_t<conjunction_v<
+        bool_constant<boolean_testable<decltype(declval<const AZStd::remove_reference_t<T>&>() == declval<const AZStd::remove_reference_t<U>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const AZStd::remove_reference_t<T>&>() != declval<const AZStd::remove_reference_t<U>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const AZStd::remove_reference_t<U>&>() == declval<const AZStd::remove_reference_t<T>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const AZStd::remove_reference_t<U>&>() != declval<const AZStd::remove_reference_t<T>&>())>>
+        >>> = true;
 
     // partially ordered <, >, <=, >=
     template<class, class U, class = void>
     constexpr bool partially_ordered_with_impl = false;
     template<class T, class U>
-    constexpr bool partially_ordered_with_impl<T, U, enable_if_t<
-        boolean_testable<decltype(declval<const remove_reference_t<T>&>() < declval<const remove_reference_t<U>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<T>&>() > declval<const remove_reference_t<U>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<T>&>() <= declval<const remove_reference_t<U>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<T>&>() >= declval<const remove_reference_t<U>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<U>&>() < declval<const remove_reference_t<T>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<U>&>() > declval<const remove_reference_t<T>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<U>&>() <= declval<const remove_reference_t<T>&>())>
-        && boolean_testable<decltype(declval<const remove_reference_t<U>&>() >= declval<const remove_reference_t<T>&>())>
-        >> = true;
+    constexpr bool partially_ordered_with_impl<T, U, enable_if_t<conjunction_v<
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<T>&>() < declval<const remove_reference_t<U>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<T>&>() > declval<const remove_reference_t<U>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<T>&>() <= declval<const remove_reference_t<U>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<T>&>() >= declval<const remove_reference_t<U>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<U>&>() < declval<const remove_reference_t<T>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<U>&>() > declval<const remove_reference_t<T>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<U>&>() <= declval<const remove_reference_t<T>&>())>>,
+        bool_constant<boolean_testable<decltype(declval<const remove_reference_t<U>&>() >= declval<const remove_reference_t<T>&>())>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -283,12 +232,13 @@ namespace AZStd::Internal
     template<class, class U, class = void>
     constexpr bool equally_comparable_with_impl = false;
     template<class T, class U>
-    constexpr bool equally_comparable_with_impl<T, U, enable_if_t<equality_comparable<T>
-        && equality_comparable<U>
-        && common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&>
-        && equality_comparable<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>
-        && Internal::weakly_equality_comparable_with<T, U>
-        >> = true;
+    constexpr bool equally_comparable_with_impl<T, U, enable_if_t<conjunction_v<
+        bool_constant<equality_comparable<T>>,
+        bool_constant<equality_comparable<U>>,
+        bool_constant<common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&>>,
+        bool_constant<equality_comparable<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>>,
+        bool_constant<Internal::weakly_equality_comparable_with<T, U>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -300,7 +250,8 @@ namespace AZStd
     /*concept*/ constexpr bool partially_ordered_with = Internal::partially_ordered_with_impl<T, U>;
 
     template<class T>
-    /*concept*/ constexpr bool totally_ordered = equality_comparable<T> && partially_ordered_with<T, T>;
+    /*concept*/ constexpr bool totally_ordered = conjunction_v<bool_constant<equality_comparable<T>>,
+        bool_constant<partially_ordered_with<T, T>>>;
 }
 
 namespace AZStd::Internal
@@ -309,11 +260,13 @@ namespace AZStd::Internal
     template<class, class U, class = void>
     constexpr bool totally_ordered_with_impl = false;
     template<class T, class U>
-    constexpr bool totally_ordered_with_impl<T, U, enable_if_t<totally_ordered<T>&& totally_ordered<U>
-        && equality_comparable_with<T, U>
-        && totally_ordered<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>
-        && partially_ordered_with<T, U>
-        >> = true;
+    constexpr bool totally_ordered_with_impl<T, U, enable_if_t<conjunction_v<
+        bool_constant<totally_ordered<T>>,
+        bool_constant<totally_ordered<U>>,
+        bool_constant<equality_comparable_with<T, U>>,
+        bool_constant<totally_ordered<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>>,
+        bool_constant<partially_ordered_with<T, U>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -332,68 +285,37 @@ namespace AZStd::Internal
     template<class T, class = void>
     constexpr bool default_initializable_impl = false;
     template<class T>
-    constexpr bool default_initializable_impl < T, enable_if_t < constructible_from<T>
-        && sfinae_trigger_v<decltype(T{}) > && Internal::is_default_initializable<T> >> = true;
-
-    template <class T, class = void>
-    constexpr bool movable_impl = false;
-    template <class T>
-    constexpr bool movable_impl<T, enable_if_t<is_object_v<T> && move_constructible<T> &&
-        assignable_from<T&, T> && swappable<T>> > = true;
-
-    template <class T, class = void>
-    constexpr bool copy_constructible_impl = false;
-    template <class T>
-    constexpr bool copy_constructible_impl<T, enable_if_t<move_constructible<T> &&
-        constructible_from<T, T&> && convertible_to<T&, T> &&
-        constructible_from<T, const T&> && convertible_to<const T&, T> &&
-        constructible_from<T, const T> && convertible_to<const T, T>> > = true;
+    constexpr bool default_initializable_impl<T, enable_if_t<conjunction_v<
+        bool_constant<constructible_from<T>>,
+        sfinae_trigger<decltype(T{})>,
+        bool_constant<is_default_initializable<T>>
+        >>> = true;
 }
 
 namespace AZStd
 {
-    // movable
-    template <class T>
-    /*concept*/ constexpr bool movable = Internal::movable_impl<T>;
-
     // default_initializable
     template<class T>
     /*concept*/ constexpr bool default_initializable = Internal::default_initializable_impl<T>;
-
-    //  copy constructible
-    template<class T>
-    /*concept*/ constexpr bool copy_constructible = Internal::copy_constructible_impl<T>;
 }
 
-namespace AZStd::Internal
-{
-    template <class T, class = void>
-    constexpr bool copyable_impl = false;
-    template <class T>
-    constexpr bool copyable_impl<T, enable_if_t<copy_constructible<T> && movable<T> && assignable_from<T&, T&> &&
-        assignable_from<T&, const T&> && assignable_from<T&, const T>> > = true;
-}
 
 namespace AZStd
 {
-    // copyable
-    template<class T>
-    /*concept*/ constexpr bool copyable = Internal::copyable_impl<T>;
-
     // semiregular
     template<class T>
-    /*concept*/ constexpr bool semiregular = copyable<T> && default_initializable<T>;
+    /*concept*/ constexpr bool semiregular = conjunction_v<bool_constant<copyable<T>>, bool_constant<default_initializable<T>>>;
 
     // regular
     template<class T>
-    /*concept*/ constexpr bool regular = semiregular<T> && equality_comparable<T>;
+    /*concept*/ constexpr bool regular = conjunction_v<bool_constant<semiregular<T>>, bool_constant<equality_comparable<T>>>;
 }
 
 // Iterator Concepts
 namespace AZStd::Internal
 {
     template <class T>
-    constexpr bool is_integer_like = integral<T> && !same_as<T, bool>;
+    constexpr bool is_integer_like = conjunction_v<bool_constant<integral<T>>, bool_constant<!same_as<T, bool>>>;
 
     template <class T>
     constexpr bool is_signed_integer_like = signed_integral<T>;
@@ -401,10 +323,12 @@ namespace AZStd::Internal
     template <class T, class = void>
     constexpr bool weakly_incrementable_impl = false;
     template <class T>
-    constexpr bool weakly_incrementable_impl<T, enable_if_t<movable<T>
-        && is_signed_integer_like<iter_difference_t<T>>
-        && same_as<decltype(++declval<T&>()), T&>
-        && sfinae_trigger_v<decltype(declval<T&>()++)> >> = true;
+    constexpr bool weakly_incrementable_impl<T, enable_if_t<conjunction_v<
+        bool_constant<movable<T>>,
+        bool_constant<is_signed_integer_like<iter_difference_t<T>>>,
+        bool_constant<same_as<decltype(++declval<T&>()), T&>>,
+        sfinae_trigger<decltype(declval<T&>()++)>
+        >>> = true;
 }
 
 namespace AZStd
@@ -415,8 +339,8 @@ namespace AZStd
 
     // models input_or_output_iterator concept
     template <class T>
-    /*concept*/ constexpr bool input_or_output_iterator = !is_void_v<T>
-        && weakly_incrementable<T>;
+    /*concept*/ constexpr bool input_or_output_iterator = conjunction_v<bool_constant<!is_void_v<T>>,
+        bool_constant<weakly_incrementable<T>>>;
 }
 
 namespace AZStd::Internal
@@ -424,9 +348,11 @@ namespace AZStd::Internal
     template <class T, class = void>
     constexpr bool incrementable_impl = false;
     template <class T>
-    constexpr bool incrementable_impl<T, enable_if_t<regular<T>
-        && weakly_incrementable<T>
-        && same_as<decltype(declval<T&>()++), T> >> = true;
+    constexpr bool incrementable_impl<T, enable_if_t<conjunction_v<
+        bool_constant<regular<T>>,
+        bool_constant<weakly_incrementable<T>>,
+        bool_constant<same_as<decltype(declval<T&>()++), T>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -438,9 +364,11 @@ namespace AZStd
 namespace AZStd
 {
     template<class S, class I>
-    /*concept*/ constexpr bool sentinel_for = semiregular<S> &&
-        input_or_output_iterator<I> &&
-        Internal::weakly_equality_comparable_with<S, I>;
+    /*concept*/ constexpr bool sentinel_for = conjunction_v<
+        bool_constant<semiregular<S>>,
+        bool_constant<input_or_output_iterator<I>>,
+        bool_constant<Internal::weakly_equality_comparable_with<S, I>>>;
+
     template<class S, class I>
     inline constexpr bool disable_sized_sentinel_for = false;
 }
@@ -450,11 +378,12 @@ namespace AZStd::Internal
     template<class S, class I, class = void>
     /*concept*/ constexpr bool sized_sentinel_for_impl = false;
     template<class S, class I>
-    /*concept*/ constexpr bool sized_sentinel_for_impl<S, I, enable_if_t<
-        sentinel_for<S, I>
-        && !disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>>
-        && same_as<decltype(declval<S>() - declval<I>()), iter_difference_t<I>>
-        && same_as<decltype(declval<I>() - declval<S>()), iter_difference_t<I>> >> = true;
+    /*concept*/ constexpr bool sized_sentinel_for_impl<S, I, enable_if_t<conjunction_v<
+        bool_constant<sentinel_for<S, I>>,
+        bool_constant<!disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>>>,
+        bool_constant<same_as<decltype(declval<S>() - declval<I>()), iter_difference_t<I>>>,
+        bool_constant<same_as<decltype(declval<I>() - declval<S>()), iter_difference_t<I>>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -477,15 +406,17 @@ namespace AZStd::Internal
     template<class I, class = void>
     constexpr bool use_traits_iterator_category_for_concept = false;
     template<class I>
-    constexpr bool use_traits_iterator_category_for_concept<I,
-        void_t<typename iterator_traits<I>::iterator_category>> = !use_traits_iterator_concept_for_concept<I>;
+    constexpr bool use_traits_iterator_category_for_concept<I, enable_if_t<conjunction_v<
+        sfinae_trigger<typename iterator_traits<I>::iterator_category>,
+        bool_constant<!use_traits_iterator_concept_for_concept<I>> >>> = true;
 
     template<class I, class = void>
     constexpr bool use_random_access_iterator_tag_for_concept = false;
     template<class I>
-    constexpr bool use_random_access_iterator_tag_for_concept<I,
-        void_t<iterator_traits<I>>> = !use_traits_iterator_concept_for_concept<I>
-        && !use_traits_iterator_category_for_concept<I>;
+    constexpr bool use_random_access_iterator_tag_for_concept<I, enable_if_t<conjunction_v<
+        sfinae_trigger<iterator_traits<I>>,
+        bool_constant<!use_traits_iterator_concept_for_concept<I>>,
+        bool_constant<!use_traits_iterator_category_for_concept<I>> >>> = true;
 
     template<class I, class = void>
     struct iter_concept;
@@ -510,197 +441,18 @@ namespace AZStd::Internal
     using iter_concept_t = typename iter_concept<I>::type;
 }
 
-namespace AZStd
-{
-    // indirectly readable
-    template <class In>
-    /*concept*/ constexpr bool indirectly_readable = Internal::indirectly_readable_impl<remove_cvref_t<In>>;
-}
-
-namespace AZStd::Internal
-{
-    // model the indirectly writable concept
-    template <class Out, class T, class = void>
-    constexpr bool indirectly_writable_impl = false;
-
-    template <class Out, class T>
-    constexpr bool indirectly_writable_impl<Out, T, void_t<
-        decltype(*declval<Out&>() = declval<T>()),
-        decltype(*declval<Out>() = declval<T>()),
-        decltype(const_cast<const iter_reference_t<Out>&&>(*declval<Out&>()) = declval<T>()),
-        decltype(const_cast<const iter_reference_t<Out>&&>(*declval<Out>()) = declval<T>())>
-        > = true;
-}
-namespace AZStd
-{
-    // indirectly writable
-    template <class Out, class T>
-    /*concept*/ constexpr bool indirectly_writable = Internal::indirectly_writable_impl<Out, T>;
-
-    // indirectly movable
-    template<class In, class Out>
-    /*concept*/ constexpr bool indirectly_movable = indirectly_readable<In> && indirectly_writable<Out, iter_rvalue_reference_t<In>>;
-}
-
-namespace AZStd::Internal
-{
-    template<class In, class Out, class = void>
-    constexpr bool indirectly_movable_storage_impl = false;
-
-    template<class In, class Out>
-    constexpr bool indirectly_movable_storage_impl<In, Out, enable_if_t<
-        indirectly_movable<In, Out> &&
-        indirectly_writable<Out, iter_value_t<In>> &&
-        movable<iter_value_t<In>> &&
-        constructible_from<iter_value_t<In>, iter_rvalue_reference_t<In>> &&
-        assignable_from<iter_value_t<In>&, iter_rvalue_reference_t<In>>> > = true;
-}
-
-namespace AZStd
-{
-    template<class In, class Out>
-    /*concept*/ constexpr bool indirectly_movable_storable = Internal::indirectly_movable_storage_impl<In, Out>;
-}
-
-namespace AZStd::Internal
-{
-    template<class In, class Out, class = void>
-    constexpr bool indirectly_copyable_impl = false;
-
-    template<class In, class Out>
-    constexpr bool indirectly_copyable_impl<In, Out, enable_if_t<
-        indirectly_readable<In> &&
-        indirectly_writable<Out, iter_reference_t<In>>> > = true;
-}
-
-namespace AZStd
-{
-    // indirectly copyable
-    template<class In, class Out>
-    /*concept*/ constexpr bool indirectly_copyable = Internal::indirectly_copyable_impl<In, Out>;
-}
-namespace AZStd::Internal
-{
-    template<class In, class Out, class = void>
-    constexpr bool indirectly_copyable_storable_impl = false;
-
-    template<class In, class Out>
-    constexpr bool indirectly_copyable_storable_impl<In, Out, enable_if_t<
-        indirectly_copyable<In, Out> &&
-        indirectly_writable<Out, iter_value_t<In>&> &&
-        indirectly_writable<Out, const iter_value_t<In>&> &&
-        indirectly_writable<Out, iter_value_t<In>&&> &&
-        indirectly_writable<Out, const iter_value_t<In>&&> &&
-        copyable<iter_value_t<In>> &&
-        constructible_from<iter_value_t<In>, iter_reference_t<In>> &&
-        assignable_from<iter_value_t<In>&, iter_reference_t<In>>> > = true;
-}
-
-namespace AZStd
-{
-    template<class In, class Out>
-    /*concept*/ constexpr bool indirectly_copyable_storable = Internal::indirectly_copyable_storable_impl<In, Out>;
-}
-
-namespace AZStd::ranges::Internal
-{
-    template<class I1, class I2>
-    void iter_swap(I1, I2) = delete;
-
-    template <class I1, class I2, class = void>
-    constexpr bool iter_swap_adl = false;
-
-    template <class I1, class I2>
-    constexpr bool iter_swap_adl<I1, I2, void_t<decltype(iter_swap(declval<I1>(), declval<I2>()))>> = true;
-
-    template <class I1, class I2, class = void>
-    constexpr bool is_class_or_enum_with_iter_swap_adl = false;
-
-    template <class I1, class I2>
-    constexpr bool is_class_or_enum_with_iter_swap_adl<I1, I2, enable_if_t<iter_swap_adl<I1, I2>
-        && (is_class_v<remove_cvref_t<I1>> || is_enum_v<remove_cvref_t<I1>>)
-        && (is_class_v<remove_cvref_t<I2>> || is_enum_v<remove_cvref_t<I2>>)>> = true;
-
-    struct iter_swap_fn
-    {
-        template <class I1, class I2>
-        constexpr auto operator()(I1&& i1, I2&& i2) const
-            ->enable_if_t<is_class_or_enum_with_iter_swap_adl<I1, I2>
-            >
-        {
-            iter_swap(AZStd::forward<I1>(i1), AZStd::forward<I1>(i2));
-        }
-        template <class I1, class I2>
-        constexpr auto operator()(I1&& i1, I2&& i2) const
-            ->enable_if_t<!is_class_or_enum_with_iter_swap_adl<I1, I2>
-            && indirectly_readable<I1>
-            && indirectly_readable<I2>
-            && swappable_with<iter_reference_t<I1>, iter_reference_t<I2>>
-            >
-        {
-            ranges::swap(*i1, *i2);
-        }
-
-        template <class I1, class I2>
-        constexpr auto operator()(I1&& i1, I2&& i2) const
-            ->enable_if_t<!is_class_or_enum_with_iter_swap_adl<I1, I2>
-            && indirectly_movable_storable<I1, I2>
-            && indirectly_movable_storable<I2, I1>
-            >
-        {
-            *AZStd::forward<I1>(i1) = iter_exchange_move(AZStd::forward<I2>(i2), AZStd::forward<I1>(i1));
-        }
-
-    private:
-        template<class X, class Y>
-        static constexpr iter_value_t<X> iter_exchange_move(X&& x, Y&& y)
-            noexcept(noexcept(iter_value_t<X>(iter_move(x))) && noexcept(*x = iter_move(y)))
-        {
-            iter_value_t<X> old_value(iter_move(x));
-            *x = iter_move(y);
-            return old_value;
-        }
-    };
-}
-
-namespace AZStd::ranges
-{
-    inline namespace customization_point_object
-    {
-        inline constexpr Internal::iter_swap_fn iter_swap{};
-    }
-}
 
 
-namespace AZStd::Internal
-{
-    template <class I1, class I2, class = void>
-    constexpr bool indirectly_swappable_impl = false;
-    template <class I1, class I2>
-    constexpr bool indirectly_swappable_impl<I1, I2, enable_if_t<
-        indirectly_readable<I1>&& indirectly_readable<I2>
-        && sfinae_trigger_v<
-        decltype(AZStd::ranges::iter_swap(declval<I1>(), declval<I1>())),
-        decltype(AZStd::ranges::iter_swap(declval<I2>(), declval<I2>())),
-        decltype(AZStd::ranges::iter_swap(declval<I1>(), declval<I2>())),
-        decltype(AZStd::ranges::iter_swap(declval<I2>(), declval<I1>()))>>> = true;
-}
-
-namespace AZStd
-{
-    template<class I1, class I2 = I1>
-    /*concept*/ constexpr bool indirectly_swappable = Internal::indirectly_swappable_impl<I1, I2>;
-}
-
 namespace AZStd::Internal
 {
     template<class I, class = void>
     constexpr bool input_iterator_impl = false;
     template<class I>
-    constexpr bool input_iterator_impl<I, enable_if_t<input_or_output_iterator<I>
-        && derived_from<iter_concept_t<I>, input_iterator_tag>
-        && indirectly_readable<I>
-        >> = true;
+    constexpr bool input_iterator_impl<I, enable_if_t<conjunction_v<
+        bool_constant<input_or_output_iterator<I>>,
+        bool_constant<derived_from<iter_concept_t<I>, input_iterator_tag>>,
+        bool_constant<indirectly_readable<I>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -715,10 +467,11 @@ namespace AZStd::Internal
     template<class I, class T, class = void>
     constexpr bool output_iterator_impl = false;
     template<class I, class T>
-    constexpr bool output_iterator_impl<I, T, enable_if_t<input_or_output_iterator<I>
-        && indirectly_writable<I, T>
-        && sfinae_trigger_v<decltype(*declval<I&>()++ = AZStd::declval<T>())>
-        >> = true;
+    constexpr bool output_iterator_impl<I, T, enable_if_t<conjunction_v<
+        bool_constant<input_or_output_iterator<I>>,
+        bool_constant<indirectly_writable<I, T>>,
+        sfinae_trigger<decltype(*declval<I&>()++ = AZStd::declval<T>())>
+        >>> = true;
 }
 
 namespace AZStd
@@ -733,10 +486,11 @@ namespace AZStd::Internal
     template<class I, class = void>
     constexpr bool forward_iterator_impl = false;
     template<class I>
-    constexpr bool forward_iterator_impl<I, enable_if_t<input_iterator<I>
-        && derived_from<Internal::iter_concept_t<I>, forward_iterator_tag>
-        && incrementable<I>
-        && sentinel_for<I, I>> > = true;
+    constexpr bool forward_iterator_impl<I, enable_if_t<conjunction_v<
+        bool_constant<input_iterator<I>>,
+        bool_constant<derived_from<Internal::iter_concept_t<I>, forward_iterator_tag>>,
+        bool_constant<incrementable<I>>,
+        bool_constant<sentinel_for<I, I>> >>> = true;
 }
 
 namespace AZStd
@@ -751,10 +505,11 @@ namespace AZStd::Internal
     template<class I, class = void>
     constexpr bool bidirectional_iterator_impl = false;
     template<class I>
-    constexpr bool bidirectional_iterator_impl<I, enable_if_t<forward_iterator<I>
-        && derived_from<iter_concept_t<I>, bidirectional_iterator_tag>
-        && same_as<decltype(--declval<I&>()), I&>
-        && same_as<decltype(declval<I&>()--), I> >> = true;
+    constexpr bool bidirectional_iterator_impl<I, enable_if_t<conjunction_v<
+        bool_constant<forward_iterator<I>>,
+        bool_constant<derived_from<iter_concept_t<I>, bidirectional_iterator_tag>>,
+        bool_constant<same_as<decltype(--declval<I&>()), I&>>,
+        bool_constant<same_as<decltype(declval<I&>()--), I>> >>> = true;
 }
 
 namespace AZStd
@@ -769,17 +524,18 @@ namespace AZStd::Internal
     template<class I, class = void>
     constexpr bool random_access_iterator_impl = false;
     template<class I>
-    constexpr bool random_access_iterator_impl<I, enable_if_t<bidirectional_iterator<I>
-        && derived_from<iter_concept_t<I>, random_access_iterator_tag>
-        && totally_ordered<I>
-        && sized_sentinel_for<I, I>
-        && same_as<decltype(declval<I&>() += declval<const iter_difference_t<I>>()), I&>
-        && same_as<decltype(declval<const I>() + declval<const iter_difference_t<I>>()), I>
-        && same_as<decltype(declval<iter_difference_t<I>>() + declval<const I>()), I>
-        && same_as<decltype(declval<I&>() -= declval<const iter_difference_t<I>>()), I&>
-        && same_as<decltype(declval<const I>() - declval<const iter_difference_t<I>>()), I>
-        && same_as<decltype(declval<const I&>()[declval<iter_difference_t<I>>()]), iter_reference_t<I>>>>
-        = true;
+    constexpr bool random_access_iterator_impl<I, enable_if_t < conjunction_v <
+        bool_constant<bidirectional_iterator<I>>,
+        bool_constant<derived_from<iter_concept_t<I>, random_access_iterator_tag>>,
+        bool_constant<totally_ordered<I>>,
+        bool_constant<sized_sentinel_for<I, I>>,
+        bool_constant<same_as<decltype(declval<I&>() += declval<const iter_difference_t<I>>()), I&>>,
+        bool_constant<same_as<decltype(declval<const I>() + declval<const iter_difference_t<I>>()), I>>,
+        bool_constant<same_as<decltype(declval<iter_difference_t<I>>() + declval<const I>()), I>>,
+        bool_constant<same_as<decltype(declval<I&>() -= declval<const iter_difference_t<I>>()), I&>>,
+        bool_constant<same_as<decltype(declval<const I>() - declval<const iter_difference_t<I>>()), I>>,
+        bool_constant<same_as<decltype(declval<const I&>()[declval<iter_difference_t<I>>()]), iter_reference_t<I>>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -793,13 +549,14 @@ namespace AZStd::Internal
     template<class I, class = void>
     constexpr bool contiguous_iterator_impl = false;
     template<class I>
-    constexpr bool contiguous_iterator_impl<I, enable_if_t<random_access_iterator<I>
-        && derived_from<iter_concept_t<I>, contiguous_iterator_tag>
-        && is_lvalue_reference_v<iter_reference_t<I>>
-        && indirectly_readable<I>
-        && same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>>
-        > >
-        = same_as<decltype(to_address(declval<const I&>())), add_pointer_t<iter_reference_t<I>>>;
+    constexpr bool contiguous_iterator_impl<I, enable_if_t<conjunction_v<
+        bool_constant<random_access_iterator<I>>,
+        bool_constant<derived_from<iter_concept_t<I>, contiguous_iterator_tag>>,
+        bool_constant<is_lvalue_reference_v<iter_reference_t<I>>>,
+        bool_constant<indirectly_readable<I>>,
+        bool_constant<same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>>>,
+        bool_constant<same_as<decltype(to_address(declval<const I&>())), add_pointer_t<iter_reference_t<I>>>>
+        >>> = true;
 }
 
 namespace AZStd
@@ -826,15 +583,151 @@ namespace AZStd
 
     // models the relation concept
     template <class R, class T, class U>
-    /*concept*/ constexpr bool relation = predicate<R, T, T> && predicate<R, U, U>
-        && predicate<R, T, U> && predicate<R, U, T>;
+    /*concept*/ constexpr bool relation = conjunction_v<
+        bool_constant<predicate<R, T, T>>,
+        bool_constant<predicate<R, U, U>>,
+        bool_constant<predicate<R, T, U>>,
+        bool_constant<predicate<R, U, T>>>;
 
     // models the equivalence_relation concept
+    // Note: semantically this is different than relation
+    // since it can't be enforced at compile time
     template <class R, class T, class U>
     /*concept*/ constexpr bool equivalence_relation = relation<R, T, U>;
 
     // models the strict_weak_order concept
-    // Note: semantically this is different than equivalence_relation
+    // Note: semantically this is different than relation
+    // since it can't be enforced at compile time
     template <class R, class T, class U>
     /*concept*/ constexpr bool strict_weak_order = relation<R, T, U>;
 }
+
+namespace AZStd
+{
+    // https://eel.is/c++draft/iterators#indirectcallable.indirectinvocable
+    template<class F, class I, class = void>
+    /*concept*/ constexpr bool indirectly_unary_invocable = false;
+    template<class F, class I>
+    /*concept*/ constexpr bool indirectly_unary_invocable<F, I, enable_if_t<conjunction_v<
+        bool_constant<indirectly_readable<I>>,
+        bool_constant<copy_constructible<F>>,
+        bool_constant<invocable<F&, iter_value_t<I>&>>,
+        bool_constant<invocable<F&, iter_reference_t<I>>>,
+        bool_constant<invocable<F&, iter_common_reference_t<I>>>,
+        bool_constant<common_reference_with<invoke_result_t<F&, iter_value_t<I>&>, invoke_result_t<F&, iter_reference_t<I>>>>
+        >>> = true;
+
+    template<class F, class I, class = void>
+    /*concept*/ constexpr bool indirectly_regular_unary_invocable = false;
+    template<class F, class I>
+    /*concept*/ constexpr bool indirectly_regular_unary_invocable<
+        F,
+        I,
+        enable_if_t<conjunction_v<
+            bool_constant<indirectly_readable<I>>,
+            bool_constant<copy_constructible<F>>,
+            bool_constant<regular_invocable<F&, iter_value_t<I>&>>,
+            bool_constant<regular_invocable<F&, iter_reference_t<I>>>,
+            bool_constant<regular_invocable<F&, iter_common_reference_t<I>>>,
+            bool_constant<common_reference_with<invoke_result_t<F&, iter_value_t<I>&>, invoke_result_t<F&, iter_reference_t<I>>>>>>> = true;
+
+    template<class F, class I, class = void>
+    /*concept*/ constexpr bool indirect_unary_predicate = false;
+    template<class F, class I>
+    /*concept*/ constexpr bool indirect_unary_predicate<
+        F,
+        I,
+        enable_if_t<conjunction_v<
+            bool_constant<indirectly_readable<I>>,
+            bool_constant<copy_constructible<F>>,
+            bool_constant<predicate<F&, iter_value_t<I>&>>,
+            bool_constant<predicate<F&, iter_reference_t<I>>>,
+            bool_constant<predicate<F&, iter_common_reference_t<I>>>>>> = true;
+
+    template<class F, class I1, class I2, class = void>
+    /*concept*/ constexpr bool indirect_binary_predicate = false;
+    template<class F, class I1, class I2>
+    /*concept*/ constexpr bool indirect_binary_predicate<
+        F,
+        I1,
+        I2,
+        enable_if_t<conjunction_v<
+            bool_constant<indirectly_readable<I1>>,
+            bool_constant<indirectly_readable<I2>>,
+            bool_constant<copy_constructible<F>>,
+            bool_constant<predicate<F&, iter_value_t<I1>&, iter_value_t<I2>&>>,
+            bool_constant<predicate<F&, iter_value_t<I1>&, iter_reference_t<I2>>>,
+            bool_constant<predicate<F&, iter_reference_t<I1>, iter_value_t<I2>&>>,
+            bool_constant<predicate<F&, iter_reference_t<I1>, iter_reference_t<I2>>>,
+            bool_constant<predicate<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>>>>> = true;
+
+    template<class F, class I1, class I2 = I1, class = void>
+    /*concept*/ constexpr bool indirect_equivalence_relation = false;
+    template<class F, class I1, class I2>
+    /*concept*/ constexpr bool indirect_equivalence_relation<
+        F,
+        I1,
+        I2,
+        enable_if_t<conjunction_v<
+            bool_constant<indirectly_readable<I1>>,
+            bool_constant<indirectly_readable<I2>>,
+            bool_constant<copy_constructible<F>>,
+            bool_constant<equivalence_relation<F&, iter_value_t<I1>&, iter_value_t<I2>&>>,
+            bool_constant<equivalence_relation<F&, iter_value_t<I1>&, iter_reference_t<I2>>>,
+            bool_constant<equivalence_relation<F&, iter_reference_t<I1>, iter_value_t<I2>&>>,
+            bool_constant<equivalence_relation<F&, iter_reference_t<I1>, iter_reference_t<I2>>>,
+            bool_constant<equivalence_relation<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>>>>> = true;
+
+    template<class F, class I1, class I2 = I1, class = void>
+    /*concept*/ constexpr bool indirect_strict_weak_order = false;
+    template<class F, class I1, class I2>
+    /*concept*/ constexpr bool indirect_strict_weak_order<
+        F,
+        I1,
+        I2,
+        enable_if_t<conjunction_v<
+            bool_constant<indirectly_readable<I1>>,
+            bool_constant<indirectly_readable<I2>>,
+            bool_constant<copy_constructible<F>>,
+            bool_constant<strict_weak_order<F&, iter_value_t<I1>&, iter_value_t<I2>&>>,
+            bool_constant<strict_weak_order<F&, iter_value_t<I1>&, iter_reference_t<I2>>>,
+            bool_constant<strict_weak_order<F&, iter_reference_t<I1>, iter_value_t<I2>&>>,
+            bool_constant<strict_weak_order<F&, iter_reference_t<I1>, iter_reference_t<I2>>>,
+            bool_constant<strict_weak_order<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>>>>> = true;
+
+    namespace Internal
+    {
+        template<bool Invocable, class F, class... Is>
+        struct indirect_result;
+        template<class F, class... Is>
+        struct indirect_result<true, F, Is...>
+        {
+            using type = invoke_result_t<F, iter_reference_t<Is>...>;
+        };
+    }
+    template<class F, class... Is>
+    using indirect_result_t = typename Internal::indirect_result<conjunction_v<
+            bool_constant<indirectly_readable<Is>>...,
+            bool_constant<AZStd::invocable<F, iter_reference_t<Is>...>>>,
+        F, Is...>::type;
+
+    // https://eel.is/c++draft/iterators#projected
+    template<class I, class Proj, class = void>
+    struct projected;
+
+    template<class I, class Proj>
+    struct projected<
+        I,
+        Proj,
+        enable_if_t<conjunction_v<bool_constant<indirectly_readable<I>>, bool_constant<indirectly_regular_unary_invocable<Proj, I>>>>>
+    {
+        using value_type = remove_cvref_t<indirect_result_t<Proj&, I>>;
+        indirect_result_t<Proj&, I> operator*() const; // not defined
+    };
+
+    template <class I, class Proj>
+    struct incrementable_traits<projected<I, Proj>, enable_if_t<weakly_incrementable<I>>>
+    {
+        using difference_type = iter_difference_t<I>;
+    };
+}

+ 34 - 0
Code/Framework/AzCore/AzCore/std/concepts/concepts_assignable.h

@@ -0,0 +1,34 @@
+/*
+ * 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/common_reference.h>
+#include <AzCore/std/typetraits/conjunction.h>
+#include <AzCore/std/typetraits/integral_constant.h>
+#include <AzCore/std/typetraits/is_same.h>
+#include <AzCore/std/typetraits/remove_cvref.h>
+#include <AzCore/std/utility/declval.h>
+
+namespace AZStd::Internal
+{
+
+    template<class LHS, class RHS, class = void>
+    constexpr bool assignable_from_impl = false;
+    template<class LHS, class RHS>
+    constexpr bool assignable_from_impl<LHS, RHS, enable_if_t<conjunction_v<
+        is_lvalue_reference<LHS>,
+        bool_constant<common_reference_with<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&>>,
+        bool_constant<same_as<decltype(declval<LHS>() = declval<RHS>()), LHS>> >>> = true;
+}
+
+namespace AZStd
+{
+    template<class LHS, class RHS>
+    /*concept*/ constexpr bool assignable_from = Internal::assignable_from_impl<LHS, RHS>;
+}

+ 26 - 0
Code/Framework/AzCore/AzCore/std/concepts/concepts_constructible.h

@@ -0,0 +1,26 @@
+/*
+ * 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/conjunction.h>
+#include <AzCore/std/typetraits/integral_constant.h>
+#include <AzCore/std/typetraits/is_constructible.h>
+#include <AzCore/std/typetraits/is_convertible.h>
+#include <AzCore/std/typetraits/is_destructible.h>
+
+namespace AZStd
+{
+
+    template<class T, class... Args>
+    /*concept*/ constexpr bool constructible_from = conjunction_v<bool_constant<destructible<T>>,
+        is_constructible<T, Args...> >;
+
+    template<class T>
+    /*concept*/ constexpr bool move_constructible = conjunction_v<bool_constant<constructible_from<T, T>>,
+        bool_constant<convertible_to<T, T>>>;
+}

+ 60 - 0
Code/Framework/AzCore/AzCore/std/concepts/concepts_copyable.h

@@ -0,0 +1,60 @@
+/*
+ * 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/concepts/concepts_assignable.h>
+#include <AzCore/std/concepts/concepts_constructible.h>
+#include <AzCore/std/concepts/concepts_movable.h>
+#include <AzCore/std/typetraits/integral_constant.h>
+#include <AzCore/std/typetraits/is_convertible.h>
+#include <AzCore/std/typetraits/conjunction.h>
+
+namespace AZStd::Internal
+{
+    template <class T, class = void>
+    constexpr bool copy_constructible_impl = false;
+    template <class T>
+    constexpr bool copy_constructible_impl<T, enable_if_t<conjunction_v<
+        bool_constant<move_constructible<T>>,
+        bool_constant<constructible_from<T, T&>>,
+        bool_constant<convertible_to<T&, T>>,
+        bool_constant<constructible_from<T, const T&>>,
+        bool_constant<convertible_to<const T&, T>>,
+        bool_constant<constructible_from<T, const T>>,
+        bool_constant<convertible_to<const T, T>>
+        >>> = true;
+}
+
+namespace AZStd
+{
+    //  copy constructible
+    template<class T>
+    /*concept*/ constexpr bool copy_constructible = Internal::copy_constructible_impl<T>;
+}
+
+namespace AZStd::Internal
+{
+    template <class T, class = void>
+    constexpr bool copyable_impl = false;
+    template <class T>
+    constexpr bool copyable_impl<T, enable_if_t<conjunction_v<
+        bool_constant<copy_constructible<T>>,
+        bool_constant<movable<T>>,
+        bool_constant<assignable_from<T&, T&>>,
+        bool_constant<assignable_from<T&, const T&>>,
+        bool_constant<assignable_from<T&, const T>>
+        >>> = true;
+}
+
+namespace AZStd
+{
+    // copyable
+    template<class T>
+    /*concept*/ constexpr bool copyable = Internal::copyable_impl<T>;
+
+}

+ 35 - 0
Code/Framework/AzCore/AzCore/std/concepts/concepts_movable.h

@@ -0,0 +1,35 @@
+/*
+ * 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/concepts/concepts_assignable.h>
+#include <AzCore/std/concepts/concepts_constructible.h>
+#include <AzCore/std/typetraits/integral_constant.h>
+#include <AzCore/std/ranges/swap.h>
+#include <AzCore/std/typetraits/conjunction.h>
+#include <AzCore/std/typetraits/is_object.h>
+
+namespace AZStd::Internal
+{
+    template <class T, class = void>
+    constexpr bool movable_impl = false;
+    template <class T>
+    constexpr bool movable_impl<T, enable_if_t<conjunction_v<
+        is_object<T>,
+        bool_constant<move_constructible<T>>,
+        bool_constant<assignable_from<T&, T>>,
+        bool_constant<swappable<T>>
+        >>> = true;
+}
+
+namespace AZStd
+{
+    // movable
+    template <class T>
+    /*concept*/ constexpr bool movable = Internal::movable_impl<T>;
+}

+ 43 - 5
Code/Framework/AzCore/AzCore/std/containers/map.h

@@ -5,8 +5,7 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
-#ifndef AZSTD_ORDERED_MAP_H
-#define AZSTD_ORDERED_MAP_H 1
+#pragma once
 
 #include <AzCore/std/containers/rbtree.h>
 #include <AzCore/std/containers/node_handle.h>
@@ -392,6 +391,26 @@ namespace AZStd
         return originalSize - container.size();
     }
 
+
+    // deduction guides
+    template<class InputIterator, class Compare = less<iter_key_type<InputIterator>>,
+        class Allocator = allocator>
+        map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
+        ->map<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>, Compare, Allocator>;
+
+    template<class Key, class T, class Compare = less<Key>,
+        class Allocator = allocator>
+        map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
+        ->map<Key, T, Compare, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    map(InputIterator, InputIterator, Allocator)
+        ->map<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        less<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class Key, class T, class Allocator>
+    map(initializer_list<pair<Key, T>>, Allocator)->map<Key, T, less<Key>, Allocator>;
+
     /**
     * Ordered multimap container is complaint with \ref C++0x (23.4.2)
     * This is an associative container, key can be equivalent (multiple copies of the same key value).
@@ -684,7 +703,26 @@ namespace AZStd
 
         return originalSize - container.size();
     }
-}
 
-#endif // AZSTD_ORDERED_MAP_H
-#pragma once
+    // deduction guides
+    template<class InputIterator, class Compare = less<iter_key_type<InputIterator>>,
+        class Allocator = allocator>
+        multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
+        ->multimap<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        Compare, Allocator>;
+
+    template<class Key, class T, class Compare = less<Key>,
+        class Allocator = allocator>
+        multimap(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
+        ->multimap<Key, T, Compare, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    multimap(InputIterator, InputIterator, Allocator)
+        ->multimap<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        less<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class Key, class T, class Allocator>
+    multimap(initializer_list<pair<Key, T>>, Allocator)
+        ->multimap<Key, T, less<Key>, Allocator>;
+
+}

+ 22 - 1
Code/Framework/AzCore/AzCore/std/containers/node_handle.h

@@ -7,8 +7,10 @@
  */
 #pragma once
 
-#include <AzCore/std/optional.h>
 #include <AzCore/std/allocator_traits.h>
+#include <AzCore/std/iterator.h>
+#include <AzCore/std/optional.h>
+#include <AzCore/std/utils.h>
 
 namespace AZStd
 {
@@ -193,4 +195,23 @@ namespace AZStd
         template <typename NodeTraits>
         using map_node_handle = node_handle<NodeTraits, map_node_base>;
     }
+
+    inline namespace AssociativeInternal
+    {
+        // deduction guide helpers
+        template<class InputIterator>
+        using iter_value_type = typename iterator_traits<InputIterator>::value_type::second_type;
+
+        template<class InputIterator>
+        using iter_key_type = remove_const_t<typename iterator_traits<InputIterator>::value_type::first_type>;
+
+        template<class InputIterator>
+        using iter_mapped_type = typename iterator_traits<InputIterator>::value_type::second_type;
+
+        template<class InputIterator>
+        using iter_to_alloc_type = pair<
+            add_const_t<typename iterator_traits<InputIterator>::value_type::first_type>,
+            typename iterator_traits<InputIterator>::value_type::second_type
+        >;
+    }
 }

+ 41 - 5
Code/Framework/AzCore/AzCore/std/containers/set.h

@@ -5,8 +5,7 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
-#ifndef AZSTD_ORDERED_SET_H
-#define AZSTD_ORDERED_SET_H 1
+#pragma once
 
 #include <AzCore/std/containers/node_handle.h>
 #include <AzCore/std/containers/rbtree.h>
@@ -300,6 +299,26 @@ namespace AZStd
         return originalSize - container.size();
     }
 
+    // deduction guides
+    template<class InputIterator,
+        class Compare = less<iter_value_type<InputIterator>>,
+        class Allocator = allocator>
+        set(InputIterator, InputIterator,
+            Compare = Compare(), Allocator = Allocator())
+        ->set<iter_value_type<InputIterator>, Compare, Allocator>;
+
+    template<class Key, class Compare = less<Key>, class Allocator = allocator>
+    set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+        ->set<Key, Compare, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    set(InputIterator, InputIterator, Allocator)
+        ->set<iter_value_type<InputIterator>,
+        less<iter_value_type<InputIterator>>, Allocator>;
+
+    template<class Key, class Allocator>
+    set(initializer_list<Key>, Allocator)->set<Key, less<Key>, Allocator>;
+
     /**
     * Ordered multiset container is complaint with \ref C++0x (23.4.4)
     * This is an associative container, key can be equivalent (multiple copies of the same key value).
@@ -573,7 +592,24 @@ namespace AZStd
 
         return originalSize - container.size();
     }
-}
 
-#endif // AZSTD_ORDERED_SET_H
-#pragma once
+    // deduction guides
+    template<class InputIterator,
+        class Compare = less<iter_value_type<InputIterator>>,
+        class Allocator = allocator>
+        multiset(InputIterator, InputIterator,
+            Compare = Compare(), Allocator = Allocator())
+        ->multiset<iter_value_type<InputIterator>, Compare, Allocator>;
+
+    template<class Key, class Compare = less<Key>, class Allocator = allocator>
+    multiset(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+        ->multiset<Key, Compare, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    multiset(InputIterator, InputIterator, Allocator)
+        ->multiset<iter_value_type<InputIterator>,
+        less<iter_value_type<InputIterator>>, Allocator>;
+
+    template<class Key, class Allocator>
+    multiset(initializer_list<Key>, Allocator)->multiset<Key, less<Key>, Allocator>;
+}

+ 119 - 4
Code/Framework/AzCore/AzCore/std/containers/unordered_map.h

@@ -5,8 +5,7 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
-#ifndef AZSTD_UNORDERED_MAP_H
-#define AZSTD_UNORDERED_MAP_H 1
+#pragma once
 
 #include <AzCore/std/containers/node_handle.h>
 #include <AzCore/std/hash_table.h>
@@ -344,6 +343,66 @@ namespace AZStd
         return originalSize - container.size();
     }
 
+    // deduction guides
+    template<class InputIterator,
+        class Hash = hash<iter_key_type<InputIterator>>,
+        class Pred = equal_to<iter_key_type<InputIterator>>,
+        class Allocator = allocator>
+        unordered_map(InputIterator, InputIterator,
+            typename Internal::UnorderedMapTableTraits<iter_key_type<InputIterator>,
+                iter_mapped_type<InputIterator>, Hash, Pred, Allocator, false>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_map<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>, Hash, Pred,
+        Allocator>;
+
+    template<class Key, class T, class Hash = hash<Key>,
+        class Pred = equal_to<Key>, class Allocator = allocator>
+        unordered_map(initializer_list<pair<Key, T>>,
+            typename Internal::UnorderedMapTableTraits<Key, T, Hash, Pred, Allocator, false>::size_type = {},
+            Hash = Hash(),
+            Pred = Pred(), Allocator = Allocator())
+        ->unordered_map<Key, T, Hash, Pred, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    unordered_map(InputIterator, InputIterator,
+        typename Internal::UnorderedMapTableTraits<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+            hash<iter_key_type<InputIterator>>, equal_to<iter_key_type<InputIterator>>, Allocator, false>::size_type,
+        Allocator)
+        ->unordered_map<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        hash<iter_key_type<InputIterator>>,
+        equal_to<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    unordered_map(InputIterator, InputIterator, Allocator)
+        ->unordered_map<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        hash<iter_key_type<InputIterator>>,
+        equal_to<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class InputIterator, class Hash, class Allocator>
+    unordered_map(InputIterator, InputIterator,
+        typename Internal::UnorderedMapTableTraits<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+            Hash, equal_to<iter_key_type<InputIterator>>, Allocator, false>::size_type,
+        Hash, Allocator)
+        ->unordered_map<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>, Hash,
+        equal_to<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class Key, class T, class Allocator>
+    unordered_map(initializer_list<pair<Key, T>>, typename Internal::UnorderedMapTableTraits<Key, T,
+        hash<Key>, equal_to<Key>, Allocator, false>::size_type,
+        Allocator)
+        ->unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+
+    template<class Key, class T, class Allocator>
+    unordered_map(initializer_list<pair<Key, T>>, Allocator)
+        ->unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+
+    template<class Key, class T, class Hash, class Allocator>
+    unordered_map(initializer_list<pair<Key, T>>, typename Internal::UnorderedMapTableTraits<Key, T,
+        Hash, equal_to<Key>, Allocator, true>::size_type,
+        Hash, Allocator)
+        ->unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
+
+
     /**
      * Unordered multi map container is complaint with \ref CTR1 (6.2.4.6)
      * The only difference from the unordered_map is that we allow multiple entries with
@@ -560,7 +619,63 @@ namespace AZStd
 
         return originalSize - container.size();
     }
+
+    // deduction guides
+    template<class InputIterator,
+        class Hash = hash<iter_key_type<InputIterator>>,
+        class Pred = equal_to<iter_key_type<InputIterator>>,
+        class Allocator = allocator>
+        unordered_multimap(InputIterator, InputIterator,
+            typename Internal::UnorderedMapTableTraits<iter_key_type<InputIterator>,
+                iter_mapped_type<InputIterator>, Hash, Pred, Allocator, true>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_multimap<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        Hash, Pred, Allocator>;
+
+    template<class Key, class T, class Hash = hash<Key>,
+        class Pred = equal_to<Key>, class Allocator = allocator>
+        unordered_multimap(initializer_list<pair<Key, T>>,
+            typename Internal::UnorderedMapTableTraits<Key, T, Hash, Pred, Allocator, true>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_multimap<Key, T, Hash, Pred, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    unordered_multimap(InputIterator, InputIterator,
+        typename Internal::UnorderedMapTableTraits<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+            hash<iter_key_type<InputIterator>>, equal_to<iter_key_type<InputIterator>>, Allocator, true>::size_type,
+        Allocator)
+        ->unordered_multimap<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        hash<iter_key_type<InputIterator>>,
+        equal_to<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    unordered_multimap(InputIterator, InputIterator, Allocator)
+        ->unordered_multimap<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+        hash<iter_key_type<InputIterator>>,
+        equal_to<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class InputIterator, class Hash, class Allocator>
+    unordered_multimap(InputIterator, InputIterator,
+        typename Internal::UnorderedMapTableTraits<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>,
+            Hash, equal_to<iter_key_type<InputIterator>>, Allocator, true>::size_type,
+        Hash, Allocator)
+        ->unordered_multimap<iter_key_type<InputIterator>, iter_mapped_type<InputIterator>, Hash,
+        equal_to<iter_key_type<InputIterator>>, Allocator>;
+
+    template<class Key, class T, class Allocator>
+    unordered_multimap(initializer_list<pair<Key, T>>, typename Internal::UnorderedMapTableTraits<Key, T,
+            hash<Key>, equal_to<Key>, Allocator, true>::size_type,
+        Allocator)
+        ->unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+
+    template<class Key, class T, class Allocator>
+    unordered_multimap(initializer_list<pair<Key, T>>, Allocator)
+        ->unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
+
+    template<class Key, class T, class Hash, class Allocator>
+    unordered_multimap(initializer_list<pair<Key, T>>, typename Internal::UnorderedMapTableTraits<Key, T,
+        Hash, equal_to<Key>, Allocator, true>::size_type,
+        Hash, Allocator)
+        ->unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
 }
 
-#endif // AZSTD_UNORDERED_MAP_H
-#pragma once

+ 98 - 5
Code/Framework/AzCore/AzCore/std/containers/unordered_set.h

@@ -5,8 +5,7 @@
  * SPDX-License-Identifier: Apache-2.0 OR MIT
  *
  */
-#ifndef AZSTD_UNORDERED_SET_H
-#define AZSTD_UNORDERED_SET_H 1
+#pragma once
 
 #include <AzCore/std/containers/node_handle.h>
 #include <AzCore/std/hash_table.h>
@@ -253,6 +252,55 @@ namespace AZStd
         return originalSize - container.size();
     }
 
+    // deduction guides
+    template<class InputIterator,
+        class Hash = hash<iter_value_type<InputIterator>>,
+        class Pred = equal_to<iter_value_type<InputIterator>>,
+        class Allocator = allocator>
+        unordered_set(InputIterator, InputIterator,
+            typename Internal::UnorderedSetTableTraits<iter_value_type<InputIterator>, Hash, Pred, Allocator, false>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_set<iter_value_type<InputIterator>,
+        Hash, Pred, Allocator>;
+
+    template<class T, class Hash = hash<T>,
+        class Pred = equal_to<T>, class Allocator = allocator>
+        unordered_set(initializer_list<T>,
+            typename Internal::UnorderedSetTableTraits<T, Hash, Pred, Allocator, false>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_set<T, Hash, Pred, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    unordered_set(InputIterator, InputIterator,
+        typename Internal::UnorderedSetTableTraits<iter_value_type<InputIterator>, hash<iter_value_type<InputIterator>>,
+        equal_to<iter_value_type<InputIterator>>, Allocator, false>::size_type,
+        Allocator)
+        ->unordered_set<iter_value_type<InputIterator>,
+        hash<iter_value_type<InputIterator>>,
+        equal_to<iter_value_type<InputIterator>>,
+        Allocator>;
+
+    template<class InputIterator, class Hash, class Allocator>
+    unordered_set(InputIterator, InputIterator,
+        typename Internal::UnorderedSetTableTraits<iter_value_type<InputIterator>, Hash,
+        equal_to<iter_value_type<InputIterator>>, Allocator, false>::size_type,
+        Hash, Allocator)
+        ->unordered_set<iter_value_type<InputIterator>, Hash,
+        equal_to<iter_value_type<InputIterator>>,
+        Allocator>;
+
+    template<class T, class Allocator>
+    unordered_set(initializer_list<T>,
+        typename Internal::UnorderedSetTableTraits<T, hash<T>, equal_to<T>, Allocator, false>::size_type,
+        Allocator)
+        ->unordered_set<T, hash<T>, equal_to<T>, Allocator>;
+
+    template<class T, class Hash, class Allocator>
+    unordered_set(initializer_list<T>,
+        typename Internal::UnorderedSetTableTraits<T, Hash, equal_to<T>, Allocator, false>::size_type,
+        Hash, Allocator)
+        ->unordered_set<T, Hash, equal_to<T>, Allocator>;
+
     /**
     * Unordered multi set container is complaint with \ref CTR1 (6.2.4.5)
     * The only difference from the unordered_set is that we allow multiple entries with
@@ -448,7 +496,52 @@ namespace AZStd
         return originalSize - container.size();
     }
 
+    // deduction guides
+    template<class InputIterator,
+        class Hash = hash<iter_value_type<InputIterator>>,
+        class Pred = equal_to<iter_value_type<InputIterator>>,
+        class Allocator = allocator>
+        unordered_multiset(InputIterator, InputIterator,
+            typename Internal::UnorderedSetTableTraits<iter_value_type<InputIterator>, Hash, Pred, Allocator, true>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_multiset<iter_value_type<InputIterator>,
+        Hash, Pred, Allocator>;
+
+    template<class T, class Hash = hash<T>,
+        class Pred = equal_to<T>, class Allocator = allocator>
+        unordered_multiset(initializer_list<T>,
+            typename Internal::UnorderedSetTableTraits<T, Hash, Pred, Allocator, true>::size_type = {},
+            Hash = Hash(), Pred = Pred(), Allocator = Allocator())
+        ->unordered_multiset<T, Hash, Pred, Allocator>;
+
+    template<class InputIterator, class Allocator>
+    unordered_multiset(InputIterator, InputIterator,
+        typename Internal::UnorderedSetTableTraits<iter_value_type<InputIterator>, hash<iter_value_type<InputIterator>>,
+        equal_to<iter_value_type<InputIterator>>, Allocator, true>::size_type,
+        Allocator)
+        ->unordered_multiset<iter_value_type<InputIterator>,
+        hash<iter_value_type<InputIterator>>,
+        equal_to<iter_value_type<InputIterator>>,
+        Allocator>;
+
+    template<class InputIterator, class Hash, class Allocator>
+    unordered_multiset(InputIterator, InputIterator,
+        typename Internal::UnorderedSetTableTraits<iter_value_type<InputIterator>, Hash,
+        equal_to<iter_value_type<InputIterator>>, Allocator, true>::size_type,
+        Hash, Allocator)
+        ->unordered_multiset<iter_value_type<InputIterator>, Hash,
+        equal_to<iter_value_type<InputIterator>>,
+        Allocator>;
+
+    template<class T, class Allocator>
+    unordered_multiset(initializer_list<T>,
+        typename Internal::UnorderedSetTableTraits<T, hash<T>, equal_to<T>, Allocator, true>::size_type,
+        Allocator)
+        ->unordered_multiset<T, hash<T>, equal_to<T>, Allocator>;
+
+    template<class T, class Hash, class Allocator>
+    unordered_multiset(initializer_list<T>,
+        typename Internal::UnorderedSetTableTraits<T, Hash, equal_to<T>, Allocator, true>::size_type,
+        Hash, Allocator)
+        ->unordered_multiset<T, Hash, equal_to<T>, Allocator>;
 }
-
-#endif // AZSTD_UNORDERED_SET_H
-#pragma once

+ 1 - 1
Code/Framework/AzCore/AzCore/std/function/identity.h

@@ -20,7 +20,7 @@ namespace AZStd
         using is_transparent = void;
 
         template <typename T>
-        T&& operator()(T&& t) const
+        constexpr T&& operator()(T&& t) const
         {
             return AZStd::forward<T>(t);
         }

+ 16 - 0
Code/Framework/AzCore/AzCore/std/function/invoke.h

@@ -19,12 +19,28 @@ namespace AZStd
     template <class R, class Fn, class... ArgTypes>
     struct is_invocable_r : Internal::invocable_r<R, Fn, ArgTypes...>::type {};
 
+    template <class Fn, class... ArgTypes>
+    struct is_nothrow_invocable
+        : bool_constant<noexcept(Internal::invocable<Fn, ArgTypes...>::value)>
+    {};
+
+    template <class R, class Fn, class... ArgTypes>
+    struct is_nothrow_invocable_r
+        : bool_constant<noexcept(Internal::invocable_r<R, Fn, ArgTypes...>::value)>
+    {};
+
     template <class Fn, class... ArgTypes>
     constexpr bool is_invocable_v = is_invocable<Fn, ArgTypes...>::value;
 
     template <class R, class Fn, class ...ArgTypes>
     constexpr bool is_invocable_r_v = is_invocable_r<R, Fn, ArgTypes...>::value;
 
+    template <class Fn, class... ArgTypes>
+    constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<Fn, ArgTypes...>::value;
+
+    template <class R, class Fn, class ...ArgTypes>
+    constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;
+
     template<class Fn, class... ArgTypes>
     struct invoke_result
         : AZStd::enable_if<Internal::invocable<Fn, ArgTypes...>::value, typename Internal::invocable<Fn, ArgTypes...>::result_type>

+ 0 - 4
Code/Framework/AzCore/AzCore/std/iterator.h

@@ -197,9 +197,5 @@ namespace AZStd
             return *reinterpret_cast<Iterator*>(&iter);
         }
     }
-
-    using std::size;
-    using std::empty;
-    using std::data;
 } // namespace AZStd
 

+ 116 - 13
Code/Framework/AzCore/AzCore/std/iterator/iterator_primitives.h

@@ -9,9 +9,14 @@
 
 #include <AzCore/std/base.h>
 
+#include <AzCore/std/concepts/concepts_constructible.h>
+#include <AzCore/std/concepts/concepts_copyable.h>
+#include <AzCore/std/concepts/concepts_movable.h>
 #include <AzCore/std/ranges/iter_move.h>
 #include <AzCore/std/typetraits/common_reference.h>
 #include <AzCore/std/typetraits/conditional.h>
+#include <AzCore/std/typetraits/conjunction.h>
+#include <AzCore/std/typetraits/integral_constant.h>
 #include <AzCore/std/typetraits/is_array.h>
 #include <AzCore/std/typetraits/is_class.h>
 #include <AzCore/std/typetraits/is_enum.h>
@@ -124,21 +129,24 @@ namespace AZStd::Internal
     struct incrementable_requires {};
     // iterator_traits has been specialized
     template <typename T>
-    struct incrementable_requires<T, enable_if_t<!is_primary_template_v<iterator_traits<T>>
-        && is_void_v<void_t<typename iterator_traits<T>::difference_type>> >>
+    struct incrementable_requires<T, enable_if_t<conjunction_v<
+        bool_constant<!is_primary_template_v<iterator_traits<T>>>,
+        bool_constant<is_void_v<void_t<typename iterator_traits<T>::difference_type>>>> >>
     {
         using difference_type = typename iterator_traits<T>::difference_type;
     };
     template <typename T>
-    struct incrementable_requires<T, enable_if_t<is_primary_template_v<iterator_traits<T>>
-        && has_difference_type_v<T>>>
+    struct incrementable_requires<T, enable_if_t<conjunction_v<
+        bool_constant<is_primary_template_v<iterator_traits<T>>>,
+        bool_constant<has_difference_type_v<T>>> >>
     {
         using difference_type = typename T::difference_type;
     };
     template <typename T>
-    struct incrementable_requires<T, enable_if_t<is_primary_template_v<iterator_traits<T>>
-        && !has_difference_type_v<T>
-        && integral<decltype(declval<T>() - declval<T>())> >>
+    struct incrementable_requires<T, enable_if_t< conjunction_v<
+        bool_constant<is_primary_template_v<iterator_traits<T>>>,
+        bool_constant<!has_difference_type_v<T>>,
+        bool_constant<integral<decltype(declval<T>() - declval<T>())>>> >>
     {
         using difference_type = make_signed_t<decltype(declval<T>() - declval<T>())>;
     };
@@ -164,7 +172,7 @@ namespace AZStd
     using iter_reference_t = enable_if_t<Internal::dereferenceable<T>, decltype(*declval<T&>())>;
 
     // incrementable_traits for iter_difference_t
-    template <typename T>
+    template <typename T, class = void>
     struct incrementable_traits
         : Internal::incrementable_requires<T> {};
     template <typename T>
@@ -187,14 +195,109 @@ namespace AZStd
         constexpr bool indirectly_readable_impl = false;
 
         template <class In>
-        constexpr bool indirectly_readable_impl<In, enable_if_t<same_as<decltype(*declval<In>()), iter_reference_t<In>>
-            && same_as<decltype(AZStd::ranges::iter_move(declval<In>())), iter_rvalue_reference_t<In>>
-            && common_reference_with<iter_reference_t<In>&&, iter_value_t<In>&>
-            && common_reference_with<iter_reference_t<In>&&, iter_rvalue_reference_t<In>&>
-            && common_reference_with<iter_rvalue_reference_t<In>&&, const iter_value_t<In>&>>> = true;
+        constexpr bool indirectly_readable_impl<In, enable_if_t<conjunction_v<
+            bool_constant<same_as<decltype(*declval<In>()), iter_reference_t<In>>>,
+            bool_constant<same_as<decltype(AZStd::ranges::iter_move(declval<In>())), iter_rvalue_reference_t<In>>>,
+            bool_constant<common_reference_with<iter_reference_t<In>&&, iter_value_t<In>&>>,
+            bool_constant<common_reference_with<iter_reference_t<In>&&, iter_rvalue_reference_t<In>&>>,
+            bool_constant<common_reference_with<iter_rvalue_reference_t<In>&&, const iter_value_t<In>&>> >>> = true;
     }
 
     template <typename T>
     using iter_common_reference_t = enable_if_t<Internal::indirectly_readable_impl<T>,
         common_reference_t<iter_reference_t<T>, iter_value_t<T>&>>;
 }
+
+namespace AZStd
+{
+    // indirectly readable
+    template <class In>
+    /*concept*/ constexpr bool indirectly_readable = Internal::indirectly_readable_impl<remove_cvref_t<In>>;
+}
+
+namespace AZStd::Internal
+{
+    // model the indirectly writable concept
+    template <class Out, class T, class = void>
+    constexpr bool indirectly_writable_impl = false;
+
+    template <class Out, class T>
+    constexpr bool indirectly_writable_impl<Out, T, void_t<
+        decltype(*declval<Out&>() = declval<T>()),
+        decltype(*declval<Out>() = declval<T>()),
+        decltype(const_cast<const iter_reference_t<Out>&&>(*declval<Out&>()) = declval<T>()),
+        decltype(const_cast<const iter_reference_t<Out>&&>(*declval<Out>()) = declval<T>())>
+    > = true;
+}
+namespace AZStd
+{
+    // indirectly writable
+    template <class Out, class T>
+    /*concept*/ constexpr bool indirectly_writable = Internal::indirectly_writable_impl<Out, T>;
+
+    // indirectly movable
+    template<class In, class Out>
+    /*concept*/ constexpr bool indirectly_movable = conjunction_v<bool_constant<indirectly_readable<In>>,
+        bool_constant<indirectly_writable<Out, iter_rvalue_reference_t<In>>>>;
+}
+
+namespace AZStd::Internal
+{
+    template<class In, class Out, class = void>
+    constexpr bool indirectly_movable_storage_impl = false;
+
+    template<class In, class Out>
+    constexpr bool indirectly_movable_storage_impl<In, Out, enable_if_t<conjunction_v<
+        bool_constant<indirectly_movable<In, Out>>,
+        bool_constant<indirectly_writable<Out, iter_value_t<In>>>,
+        bool_constant<movable<iter_value_t<In>>>,
+        bool_constant<constructible_from<iter_value_t<In>, iter_rvalue_reference_t<In>>>,
+        bool_constant<assignable_from<iter_value_t<In>&, iter_rvalue_reference_t<In>>> >>> = true;
+}
+
+namespace AZStd
+{
+    template<class In, class Out>
+    /*concept*/ constexpr bool indirectly_movable_storable = Internal::indirectly_movable_storage_impl<In, Out>;
+}
+
+namespace AZStd::Internal
+{
+    template<class In, class Out, class = void>
+    constexpr bool indirectly_copyable_impl = false;
+
+    template<class In, class Out>
+    constexpr bool indirectly_copyable_impl<In, Out, enable_if_t<conjunction_v<
+        bool_constant<indirectly_readable<In>>,
+        bool_constant<indirectly_writable<Out, iter_reference_t<In>>> >>> = true;
+}
+
+namespace AZStd
+{
+    // indirectly copyable
+    template<class In, class Out>
+    /*concept*/ constexpr bool indirectly_copyable = Internal::indirectly_copyable_impl<In, Out>;
+}
+namespace AZStd::Internal
+{
+    template<class In, class Out, class = void>
+    constexpr bool indirectly_copyable_storable_impl = false;
+
+    template<class In, class Out>
+    constexpr bool indirectly_copyable_storable_impl<In, Out, enable_if_t < conjunction_v <
+        bool_constant<indirectly_copyable<In, Out>>,
+        bool_constant<indirectly_writable<Out, iter_value_t<In>&>>,
+        bool_constant<indirectly_writable<Out, const iter_value_t<In>&>>,
+        bool_constant<indirectly_writable<Out, iter_value_t<In>&&>>,
+        bool_constant<indirectly_writable<Out, const iter_value_t<In>&&>>,
+        bool_constant<copyable<iter_value_t<In>>>,
+        bool_constant<constructible_from<iter_value_t<In>, iter_reference_t<In>>>,
+        bool_constant<assignable_from<iter_value_t<In>&, iter_reference_t<In>>>
+        >>> = true;
+}
+
+namespace AZStd
+{
+    template<class In, class Out>
+    /*concept*/ constexpr bool indirectly_copyable_storable = Internal::indirectly_copyable_storable_impl<In, Out>;
+}

+ 7 - 997
Code/Framework/AzCore/AzCore/std/optional.h

@@ -8,1012 +8,22 @@
 
 #pragma once
 
-#include <initializer_list>
-#include <AzCore/std/typetraits/is_scalar.h>
+#include <optional>
 #include <AzCore/std/utils.h>
-#include <AzCore/Memory/Memory.h>
-#include <AzCore/Memory/SystemAllocator.h>
 
 namespace AZStd
 {
-    // 23.6.4, no-value state indicator
-    struct nullopt_t{
-        struct UniqueTag {};
-        // nullopt_t does not have a default constructor, and is not an
-        // aggregate
-        constexpr explicit nullopt_t(UniqueTag) {}
-    };
-    static constexpr nullopt_t nullopt {nullopt_t::UniqueTag()};
-
-    namespace Internal
-    {
-        template<class T, bool = std::is_trivially_destructible<T>::value>
-        class OptionalDestructBase
-        {
-        public:
-            union
-            {
-                char m_empty;
-                T m_object;
-            };
-            bool m_engaged;
-
-            constexpr OptionalDestructBase()
-                : m_empty()
-                , m_engaged(false)
-            {
-            }
-
-            template<class... Args>
-            constexpr explicit OptionalDestructBase(in_place_t, Args&&... args)
-                : m_object(forward<Args>(args)...)
-                , m_engaged(true)
-            {
-            }
-
-            void reset()
-            {
-                m_engaged = false;
-            }
-        };
-
-        template<class T>
-        class OptionalDestructBase<T, false>
-        {
-        public:
-            union
-            {
-                char m_empty;
-                T m_object;
-            };
-            bool m_engaged;
-
-            constexpr OptionalDestructBase()
-                : m_empty()
-                , m_engaged(false)
-            {
-            }
-
-            template<class... Args>
-            constexpr explicit OptionalDestructBase(in_place_t, Args&&... args)
-                : m_object(forward<Args>(args)...)
-                , m_engaged(true)
-            {
-            }
-
-            ~OptionalDestructBase()
-            {
-                reset();
-            }
-
-            void reset()
-            {
-                if (m_engaged)
-                {
-                    m_object.T::~T();
-                    m_engaged = false;
-                }
-            }
-        };
-
-        template<class T>
-        class OptionalImplBase
-            : public OptionalDestructBase<T>
-        {
-            using base = OptionalDestructBase<T>;
-        public:
-            using base::base;
-
-            constexpr bool has_value() const
-            {
-                return this->m_engaged;
-            }
-
-            constexpr const T& value() const&
-            {
-                AZ_Assert(this->m_engaged, "Optional does not have a value");
-                return this->m_object;
-            }
-            /*constexpr*/ T& value()&
-            {
-                AZ_Assert(this->m_engaged, "Optional does not have a value");
-                return this->m_object;
-            }
-
-            constexpr const T&& value() const&&
-            {
-                AZ_Assert(this->m_engaged, "Optional does not have a value");
-                return AZStd::move(this->m_object);
-            }
-            /*constexpr*/ T&& value()&&
-            {
-                AZ_Assert(this->m_engaged, "Optional does not have a value");
-                return AZStd::move(this->m_object);
-            }
-
-            template<class... Args>
-            void construct(Args&&... args)
-            {
-                ::new((void*)AZStd::addressof(this->m_object)) T(forward<Args>(args)...);
-                this->m_engaged = true;
-            }
-
-            template<class U>
-            void construct_from(U&& that)
-            {
-                if (that.has_value())
-                {
-                    this->construct(forward<U>(that).value());
-                }
-            }
-
-            template<class U>
-            void assign_from(U&& that)
-            {
-                if (this->has_value() == that.has_value())
-                {
-                    if (this->has_value())
-                    {
-                        this->m_object = forward<U>(that).value();
-                    }
-                }
-                else
-                {
-                    if (this->has_value())
-                    {
-                        this->reset();
-                    }
-                    else
-                    {
-                        this->construct(forward<U>(that).value());
-                    }
-                }
-            }
-        };
-
-        template<class T, bool = std::is_trivially_copy_constructible<T>::value>
-        class OptionalCopyBase : public OptionalImplBase<T>
-        {
-            using base = OptionalImplBase<T>;
-        public:
-            using base::base;
-        };
 
-        template<class T>
-        class OptionalCopyBase<T, false> : public OptionalImplBase<T>
-        {
-            using base = OptionalImplBase<T>;
-        public:
-            using base::base;
-
-            OptionalCopyBase() = default;
-            OptionalCopyBase(const OptionalCopyBase& rhs)
-            {
-                this->construct_from(rhs);
-            }
-            OptionalCopyBase(OptionalCopyBase&&) = default;
-            OptionalCopyBase& operator=(const OptionalCopyBase&) = default;
-            OptionalCopyBase& operator=(OptionalCopyBase&&) = default;
-        };
-
-        template<class T, bool = std::is_trivially_move_constructible<T>::value>
-        class OptionalMoveBase : public OptionalCopyBase<T>
-        {
-            using base = OptionalCopyBase<T>;
-        public:
-            using base::base;
-        };
-
-        template<class T>
-        class OptionalMoveBase<T, false> : public OptionalCopyBase<T>
-        {
-            using base = OptionalCopyBase<T>;
-        public:
-            using base::base;
+    using std::nullopt_t;
+    using std::nullopt;
+    using std::optional;
+    using std::make_optional;
 
-            OptionalMoveBase() = default;
-            OptionalMoveBase(const OptionalMoveBase&) = default;
-            OptionalMoveBase(OptionalMoveBase&& rhs)
-            {
-                this->construct_from(AZStd::move(rhs));
-            }
-            OptionalMoveBase& operator=(const OptionalMoveBase&) = default;
-            OptionalMoveBase& operator=(OptionalMoveBase&&) = default;
-        };
-
-        template<class T, bool =
-               std::is_trivially_destructible<T>::value
-            && std::is_trivially_copy_constructible<T>::value
-            && std::is_trivially_copy_assignable<T>::value
-        >
-        class OptionalCopyAssignBase : public OptionalMoveBase<T>
-        {
-            using base = OptionalMoveBase<T>;
-        public:
-            using base::base;
-        };
-
-        template<class T>
-        class OptionalCopyAssignBase<T, false> : public OptionalMoveBase<T>
-        {
-            using base = OptionalMoveBase<T>;
-        public:
-            using base::base;
-
-            OptionalCopyAssignBase() = default;
-            OptionalCopyAssignBase(const OptionalCopyAssignBase&) = default;
-            OptionalCopyAssignBase(OptionalCopyAssignBase&&) = default;
-            OptionalCopyAssignBase& operator=(const OptionalCopyAssignBase& rhs)
-            {
-                this->assign_from(rhs);
-                return *this;
-            }
-            OptionalCopyAssignBase& operator=(OptionalCopyAssignBase&&) = default;
-        };
-
-        template<class T, bool =
-               std::is_trivially_destructible<T>::value
-            && std::is_trivially_move_constructible<T>::value
-            && std::is_trivially_move_assignable<T>::value
-        >
-        class OptionalMoveAssignBase : public OptionalCopyAssignBase<T>
-        {
-            using base = OptionalCopyAssignBase<T>;
-        public:
-            using base::base;
-        };
-
-        template<class T>
-        class OptionalMoveAssignBase<T, false> : public OptionalCopyAssignBase<T>
-        {
-            using base = OptionalCopyAssignBase<T>;
-        public:
-            using base::base;
-
-            OptionalMoveAssignBase() = default;
-            OptionalMoveAssignBase(const OptionalMoveAssignBase&) = default;
-            OptionalMoveAssignBase(OptionalMoveAssignBase&&) = default;
-            OptionalMoveAssignBase& operator=(const OptionalMoveAssignBase&) = default;
-            OptionalMoveAssignBase& operator=(OptionalMoveAssignBase&& rhs)
-            {
-                this->assign_from(AZStd::move(rhs));
-                return *this;
-            }
-        };
-
-        // The following templates define types with certain special
-        // constructors deleted. The deleted constructors are the same ones
-        // that are deleted in the source type T used in optional<T>. They
-        // trigger SFINAE so that type traits like
-        // AZStd::is_assignable<optional<T>&, optional<T>&> yield the same
-        // value as AZStd::is_assignable<T&, T&>
-        template <bool CanCopy, bool CanMove>
-        struct SFINAECtorBase {};
-        template <>
-        struct SFINAECtorBase<false, false> {
-          SFINAECtorBase() = default;
-          SFINAECtorBase(SFINAECtorBase const&) = delete;
-          SFINAECtorBase(SFINAECtorBase &&) = delete;
-          SFINAECtorBase& operator=(SFINAECtorBase const&) = default;
-          SFINAECtorBase& operator=(SFINAECtorBase&&) = default;
-        };
-        template <>
-        struct SFINAECtorBase<true, false> {
-          SFINAECtorBase() = default;
-          SFINAECtorBase(SFINAECtorBase const&) = default;
-          SFINAECtorBase(SFINAECtorBase &&) = delete;
-          SFINAECtorBase& operator=(SFINAECtorBase const&) = default;
-          SFINAECtorBase& operator=(SFINAECtorBase&&) = default;
-        };
-        template <>
-        struct SFINAECtorBase<false, true> {
-          SFINAECtorBase() = default;
-          SFINAECtorBase(SFINAECtorBase const&) = delete;
-          SFINAECtorBase(SFINAECtorBase &&) = default;
-          SFINAECtorBase& operator=(SFINAECtorBase const&) = default;
-          SFINAECtorBase& operator=(SFINAECtorBase&&) = default;
-        };
-
-        template <bool CanCopy, bool CanMove>
-        struct SFINAEAssignBase {};
-        template <>
-        struct SFINAEAssignBase<false, false> {
-          SFINAEAssignBase() = default;
-          SFINAEAssignBase(SFINAEAssignBase const&) = default;
-          SFINAEAssignBase(SFINAEAssignBase &&) = default;
-          SFINAEAssignBase& operator=(SFINAEAssignBase const&) = delete;
-          SFINAEAssignBase& operator=(SFINAEAssignBase&&) = delete;
-        };
-        template <>
-        struct SFINAEAssignBase<true, false> {
-          SFINAEAssignBase() = default;
-          SFINAEAssignBase(SFINAEAssignBase const&) = default;
-          SFINAEAssignBase(SFINAEAssignBase &&) = default;
-          SFINAEAssignBase& operator=(SFINAEAssignBase const&) = default;
-          SFINAEAssignBase& operator=(SFINAEAssignBase&&) = delete;
-        };
-        template <>
-        struct SFINAEAssignBase<false, true> {
-          SFINAEAssignBase() = default;
-          SFINAEAssignBase(SFINAEAssignBase const&) = default;
-          SFINAEAssignBase(SFINAEAssignBase &&) = default;
-          SFINAEAssignBase& operator=(SFINAEAssignBase const&) = delete;
-          SFINAEAssignBase& operator=(SFINAEAssignBase&&) = default;
-        };
-        template <class _Tp>
-        using OptionalSFINAECtorBase_t = SFINAECtorBase<
-            is_copy_constructible<_Tp>::value,
-            is_move_constructible<_Tp>::value
-        >;
-
-        template <class _Tp>
-        using OptionalSFINAEAssignBase_t = SFINAEAssignBase<
-            (is_copy_constructible<_Tp>::value && is_copy_assignable<_Tp>::value),
-            (is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value)
-        >;
-    }// end namespace Internal
 
+    // 23.6.10 Hash support
     template<class T>
-    class optional
-        : private Internal::OptionalMoveAssignBase<T>
-        , private Internal::OptionalSFINAECtorBase_t<T>
-        , private Internal::OptionalSFINAEAssignBase_t<T>
-    {
-        using base = Internal::OptionalMoveAssignBase<T>;
-    public:
-        AZ_CLASS_ALLOCATOR(optional, AZ::SystemAllocator, 0);
-
-        using value_type = T;
-
-        // 23.6.3.1, constructors
-        constexpr optional() = default;
-        constexpr optional(nullopt_t) {}
-        constexpr optional(const optional& rhs) = default;
-        constexpr optional(optional&& rhs) = default;
+    struct hash;
 
-        template<class... Args, class = typename enable_if<std::is_constructible<T, Args...>::value>::type>
-        constexpr explicit optional(in_place_t, Args&&... args)
-            : base(in_place, forward<Args>(args)...)
-        {
-        }
-
-        template<class U, class... Args, class = typename enable_if<std::is_constructible<T, std::initializer_list<U>&, Args...>::value>::type>
-        constexpr explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args)
-            : base(in_place, il, forward<Args>(args)...)
-        {
-        }
-
-        template<class U = T, typename enable_if<
-               std::is_constructible<T, U&&>::value
-            && !is_same<typename remove_cv<typename remove_reference<U>::type>::type, in_place_t>::value
-            && !is_same<typename remove_cv<typename remove_reference<U>::type>::type, optional>::value
-            && std::is_convertible<U&&, T>::value
-        >::type * = nullptr>
-        constexpr optional(U&& v)
-            : base(in_place, forward<U>(v))
-        {
-        }
-
-        template<class U = T, typename enable_if<
-               std::is_constructible<T, U&&>::value
-            && !is_same<typename remove_cv<typename remove_reference<U>::type>::type, in_place_t>::value
-            && !is_same<typename remove_cv<typename remove_reference<U>::type>::type, optional>::value
-            && !std::is_convertible<U&&, T>::value
-        >::type * = nullptr>
-        constexpr explicit optional(U&& v)
-            : base(in_place, forward<U>(v))
-        {
-        }
-
-        template<class U, typename enable_if<
-               std::is_constructible<T, const U&>::value
-            && !std::is_constructible<T, optional<U>&>::value
-            && !std::is_constructible<T, optional<U>&&>::value
-            && !std::is_constructible<T, const optional<U>&>::value
-            && !std::is_constructible<T, const optional<U>&&>::value
-            && !std::is_convertible<optional<U>&, T>::value
-            && !std::is_convertible<optional<U>&&, T>::value
-            && !std::is_convertible<const optional<U>&, T>::value
-            && !std::is_convertible<const optional<U>&&, T>::value
-            && std::is_convertible<const U&, T>::value
-        >::type * = nullptr>
-        optional(const optional<U>& rhs)
-        {
-            this->construct_from(rhs);
-        }
-
-        template<class U, typename enable_if<
-               std::is_constructible<T, const U&>::value
-            && !std::is_constructible<T, optional<U>&>::value
-            && !std::is_constructible<T, optional<U>&&>::value
-            && !std::is_constructible<T, const optional<U>&>::value
-            && !std::is_constructible<T, const optional<U>&&>::value
-            && !std::is_convertible<optional<U>&, T>::value
-            && !std::is_convertible<optional<U>&&, T>::value
-            && !std::is_convertible<const optional<U>&, T>::value
-            && !std::is_convertible<const optional<U>&&, T>::value
-            && !std::is_convertible<const U&, T>::value
-        >::type * = nullptr>
-        explicit optional(const optional<U>& rhs)
-        {
-            this->construct_from(rhs);
-        }
-
-        template<class U, typename enable_if<
-               std::is_constructible<T, U&&>::value
-            && !std::is_constructible<T, optional<U>&>::value
-            && !std::is_constructible<T, optional<U>&&>::value
-            && !std::is_constructible<T, const optional<U>&>::value
-            && !std::is_constructible<T, const optional<U>&&>::value
-            && !std::is_convertible<optional<U>&, T>::value
-            && !std::is_convertible<optional<U>&&, T>::value
-            && !std::is_convertible<const optional<U>&, T>::value
-            && !std::is_convertible<const optional<U>&&, T>::value
-            && std::is_convertible<const U&, T>::value
-        >::type * = nullptr>
-        optional(optional<U>&& rhs)
-        {
-            this->construct_from(AZStd::move(rhs));
-        }
-
-        template<class U, typename enable_if<
-               std::is_constructible<T, U&&>::value
-            && !std::is_constructible<T, optional<U>&>::value
-            && !std::is_constructible<T, optional<U>&&>::value
-            && !std::is_constructible<T, const optional<U>&>::value
-            && !std::is_constructible<T, const optional<U>&&>::value
-            && !std::is_convertible<optional<U>&, T>::value
-            && !std::is_convertible<optional<U>&&, T>::value
-            && !std::is_convertible<const optional<U>&, T>::value
-            && !std::is_convertible<const optional<U>&&, T>::value
-            && !std::is_convertible<const U&, T>::value
-        >::type * = nullptr>
-        explicit optional(optional<U>&& rhs)
-        {
-            this->construct_from(AZStd::move(rhs));
-        }
-
-        // 23.6.3.2 Destructor
-        // The destructor is conditionally trivial, and is handled by
-        // OptionalDestructBase
-
-        // 23.6.3.3 Assignment
-        optional<T>& operator=(nullopt_t)
-        {
-            this->reset();
-            return *this;
-        }
-
-        optional<T>& operator=(const optional& rhs) = default;
-        optional<T>& operator=(optional&& rhs) = default;
-
-        template<class U = T, class = typename enable_if<
-               !is_same<typename remove_cv<typename remove_reference<U>::type>::type, optional>::value
-               // !conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>>
-            && !(is_scalar<value_type>::value && is_same<T, typename decay<U>::type>::value)
-            && is_constructible<T, U>::value
-            && is_assignable<T&, U>::value
-        >::type>
-        optional<T>& operator=(U&& v)
-        {
-            if (this->has_value())
-            {
-                this->value() = forward<U>(v);
-            }
-            else
-            {
-                this->construct(forward<U>(v));
-            }
-            return *this;
-        }
-
-        template<class U, class = typename enable_if<
-               std::is_constructible<T, const U&>::value
-            && std::is_assignable<T, U&>::value
-            && !std::is_constructible<T, optional<U>&>::value
-            && !std::is_constructible<T, optional<U>&&>::value
-            && !std::is_constructible<T, const optional<U>&>::value
-            && !std::is_constructible<T, const optional<U>&&>::value
-            && !std::is_convertible<optional<U>&, T>::value
-            && !std::is_convertible<optional<U>&&, T>::value
-            && !std::is_convertible<const optional<U>&, T>::value
-            && !std::is_convertible<const optional<U>&&, T>::value
-            && !std::is_assignable<T&, optional<U>&>::value
-            && !std::is_assignable<T&, optional<U>&&>::value
-            && !std::is_assignable<T&, const optional<U>&>::value
-            && !std::is_assignable<T&, const optional<U>&&>::value
-        >::type>
-        optional<T>& operator=(const optional<U>& rhs)
-        {
-            this->assign_from(rhs);
-            return *this;
-        }
-
-        template<class U, class = typename enable_if<
-               std::is_constructible<T, U>::value
-            && std::is_assignable<T&, U>::value
-            && !std::is_constructible<T, optional<U>&>::value
-            && !std::is_constructible<T, optional<U>&&>::value
-            && !std::is_constructible<T, const optional<U>&>::value
-            && !std::is_constructible<T, const optional<U>&&>::value
-            && !std::is_convertible<optional<U>&, T>::value
-            && !std::is_convertible<optional<U>&&, T>::value
-            && !std::is_convertible<const optional<U>&, T>::value
-            && !std::is_convertible<const optional<U>&&, T>::value
-            && !std::is_assignable<T&, optional<U>&>::value
-            && !std::is_assignable<T&, optional<U>&&>::value
-            && !std::is_assignable<T&, const optional<U>&>::value
-            && !std::is_assignable<T&, const optional<U>&&>::value
-        >::type>
-        optional<T>& operator=(optional<U>&& rhs)
-        {
-            this->assign_from(AZStd::move(rhs));
-            return *this;
-        }
-
-        template<class... Args, class = typename enable_if<
-            std::is_constructible<T, Args&&...>::value
-        >::type>
-        T& emplace(Args&&... args)
-        {
-            this->reset();
-            this->construct(forward<Args>(args)...);
-            return this->value();
-        }
-
-        template<class U, class... Args, class = typename enable_if<
-            std::is_constructible<T, Args&&...>::value
-        >::type>
-        T& emplace(std::initializer_list<U> il, Args&&... args)
-        {
-            this->reset();
-            this->construct(il, forward<Args>(args)...);
-            return this->value();
-        }
-
-        // 23.6.3.4 Swap
-        void swap(optional& rhs)
-        {
-            using AZStd::swap;
-            if (this->has_value())
-            {
-                if (rhs.has_value())
-                {
-                    swap(this->value(), rhs.value());
-                }
-                else
-                {
-                    rhs.construct(AZStd::move(this->value()));
-                    this->reset();
-                }
-            }
-            else
-            {
-                if (rhs.has_value())
-                {
-                    this->construct(AZStd::move(rhs.value()));
-                    rhs.reset();
-                }
-            }
-        }
-
-        // 23.6.3.5 observers
-        constexpr const T* operator->() const
-        {
-            return AZStd::addressof(this->value());
-        }
-        /*constexpr*/ T* operator->() // not constexpr because constexpr implies const in c++11, yielding methods differing only by return type
-        {
-            return AZStd::addressof(this->value());
-        }
-
-        constexpr const T& operator*() const&
-        {
-            return this->value();
-        }
-        /*constexpr*/ T& operator*() &
-        {
-            return this->value();
-        }
-
-        constexpr const T&& operator*() const&&
-        {
-            return AZStd::move(this->value());
-        }
-        /*constexpr*/ T&& operator*() &&
-        {
-            return AZStd::move(this->value());
-        }
-
-        constexpr explicit operator bool() const
-        {
-            return has_value();
-        }
-
-        using base::has_value;
-        using base::value;
-
-        template<class U, class = typename enable_if<std::is_copy_constructible<T>::value && std::is_convertible<U, T>::value>::type>
-        constexpr T value_or(U&& v) const&
-        {
-            return this->m_engaged ? this->value() : static_cast<T>(forward<U>(v));
-        }
-
-        template<class U, class = typename enable_if<std::is_move_constructible<T>::value && std::is_convertible<U, T>::value>::type>
-        /*constexpr*/ T value_or(U&& v) &&
-        {
-            return this->m_engaged ? AZStd::move(this->value()) : static_cast<T>(forward<U>(v));
-        }
-
-        // 23.6.3.6 Modifiers
-        using base::reset;
-    };
-
-    // 23.6.6 Relational operators
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        // Template function is only enabled if the result of T() == U() is
-        // convertible to bool
-        is_convertible<
-            decltype(declval<T>() == declval<U>()), bool
-        >::value,
-        bool // bool is the return type of operator==
-    >::type
-    operator==(const optional<T>& lhs, const optional<U>& rhs)
-    {
-        // MSVC2015 says that constexpr functions can only have 1 return
-        // statement
-        return (static_cast<bool>(lhs) != static_cast<bool>(rhs))
-            ? false
-            : (!static_cast<bool>(lhs))
-                ? true
-                : *lhs == *rhs;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() != declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator!=(const optional<T>& lhs, const optional<U>& rhs)
-    {
-        return (static_cast<bool>(lhs) != static_cast<bool>(rhs))
-            ? true
-            : (!static_cast<bool>(lhs))
-                ? false
-                : *lhs != *rhs;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() < declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator<(const optional<T>& lhs, const optional<U>& rhs)
-    {
-        // MSVC2015 constexpr functions can only have one return statement
-        return (!static_cast<bool>(rhs))
-            ? false
-            : (!static_cast<bool>(lhs))
-                ? true
-                : *lhs < *rhs;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() > declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator>(const optional<T>& lhs, const optional<U>& rhs)
-    {
-        // MSVC2015 constexpr functions can only have one return statement
-        return (!static_cast<bool>(lhs))
-            ? false
-            : (!static_cast<bool>(rhs))
-                ? true
-                : *lhs > *rhs;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() <= declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator<=(const optional<T>& lhs, const optional<U>& rhs)
-    {
-        // MSVC2015 constexpr functions can only have one return statement
-        return (!static_cast<bool>(lhs))
-            ? true
-            : (!static_cast<bool>(rhs))
-                ? false
-                : *lhs <= *rhs;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() >= declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator>=(const optional<T>& lhs, const optional<U>& rhs)
-    {
-        // MSVC2015 constexpr functions can only have one return statement
-        return (!static_cast<bool>(rhs))
-            ? true
-            : (!static_cast<bool>(lhs))
-                ? false
-                : *lhs >= *rhs;
-    }
-
-    // 23.6.7 Comparison with nullopt
-    template <class T>
-    constexpr bool operator==(const optional<T>& lhs, nullopt_t)
-    {
-        return !static_cast<bool>(lhs);
-    }
-    template <class T>
-    constexpr bool operator==(nullopt_t, const optional<T>& rhs)
-    {
-        return !static_cast<bool>(rhs);
-    }
-
-    template <class T>
-    constexpr bool operator!=(const optional<T>& lhs, nullopt_t)
-    {
-        return static_cast<bool>(lhs);
-    }
-    template <class T>
-    constexpr bool operator!=(nullopt_t, const optional<T>& rhs)
-    {
-        return static_cast<bool>(rhs);
-    }
-
-    template <class T>
-    constexpr bool operator<(const optional<T>&, nullopt_t)
-    {
-        return false;
-    }
-    template <class T>
-    constexpr bool operator<(nullopt_t, const optional<T>& rhs)
-    {
-        return static_cast<bool>(rhs);
-    }
-
-    template <class T>
-    constexpr bool operator<=(const optional<T>& lhs, nullopt_t)
-    {
-        return !static_cast<bool>(lhs);
-    }
-    template <class T>
-    constexpr bool operator<=(nullopt_t, const optional<T>&)
-    {
-        return true;
-    }
-
-    template <class T>
-    constexpr bool operator>(const optional<T>& lhs, nullopt_t)
-    {
-        return static_cast<bool>(lhs);
-    }
-    template <class T>
-    constexpr bool operator>(nullopt_t, const optional<T>&)
-    {
-        return false;
-    }
-
-    template <class T>
-    constexpr bool operator>=(const optional<T>&, nullopt_t)
-    {
-        return true;
-    }
-    template <class T>
-    constexpr bool operator>=(nullopt_t, const optional<T>& rhs)
-    {
-        return !static_cast<bool>(rhs);
-    }
-
-    // 23.6.8 Comparison with T
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() == declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator==(const optional<T>& lhs, const U& rhs)
-    {
-        return static_cast<bool>(lhs) ? (*lhs == rhs) : false;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() == declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator==(const T& lhs, const optional<U>& rhs)
-    {
-        return static_cast<bool>(rhs) ? (lhs == *rhs) : false;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() != declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator!=(const optional<T>& lhs, const U& rhs)
-    {
-        return static_cast<bool>(lhs) ? (*lhs != rhs) : true;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() != declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator!=(const T& lhs, const optional<U>& rhs)
-    {
-        return static_cast<bool>(rhs) ? (lhs != *rhs) : true;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() < declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator<(const optional<T>& lhs, const U& rhs)
-    {
-        return static_cast<bool>(lhs) ? (*lhs < rhs) : true;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() < declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator<(const T& lhs, const optional<U>& rhs)
-    {
-        return static_cast<bool>(rhs) ? (lhs < *rhs) : false;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() <= declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator<=(const optional<T>& lhs, const U& rhs)
-    {
-        return static_cast<bool>(lhs) ? (*lhs <= rhs) : true;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() <= declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator<=(const T& lhs, const optional<U>& rhs)
-    {
-        return static_cast<bool>(rhs) ? (lhs <= *rhs) : false;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() > declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator>(const optional<T>& lhs, const U& rhs)
-    {
-        return static_cast<bool>(lhs) ? (*lhs > rhs) : false;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() > declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator>(const T& lhs, const optional<U>& rhs)
-    {
-        return static_cast<bool>(rhs) ? (lhs > *rhs) : true;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() >= declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator>=(const optional<T>& lhs, const U& rhs)
-    {
-        return static_cast<bool>(lhs) ? (*lhs >= rhs) : false;
-    }
-
-    template <class T, class U>
-    constexpr
-    typename enable_if<
-        is_convertible<
-            decltype(declval<T>() >= declval<U>()), bool
-        >::value,
-        bool
-    >::type
-    operator>=(const T& lhs, const optional<U>& rhs)
-    {
-        return static_cast<bool>(rhs) ? (lhs >= *rhs) : true;
-    }
-
-    // 23.6.9 Specialized algorithms
-    template <class T>
-    typename enable_if<
-        is_move_constructible<T>::value,// && std::is_swappable_v<T>,
-        void
-    >::type
-    swap(optional<T>& lhs, optional<T>& rhs)
-    {
-        lhs.swap(rhs);
-    }
-
-    template <class T>
-    constexpr optional<typename decay<T>::type> make_optional(T&& v)
-    {
-        return optional<typename decay<T>::type>(forward<T>(v));
-    }
-
-    template <class T, class... Args>
-    constexpr optional<T> make_optional(Args&&... args)
-    {
-        return optional<T>(in_place, forward<Args>(args)...);
-    }
-
-    template <class T, class U, class... Args>
-    constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args)
-    {
-        return optional<T>(in_place, il, forward<Args>(args)...);
-    }
-
-    // 23.6.10 Hash support
     template<class T>
     struct hash<optional<T>>
     {

+ 67 - 0
Code/Framework/AzCore/AzCore/std/ranges/all_view.h

@@ -0,0 +1,67 @@
+/*
+ * 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/ranges/owning_view.h>
+#include <AzCore/std/ranges/ref_view.h>
+
+namespace AZStd::ranges::views
+{
+    namespace Internal
+    {
+        template<class T, class = void>
+        constexpr bool convertible_to_ref_view = false;
+        template<class T>
+        constexpr bool convertible_to_ref_view<T, void_t<decltype(ranges::ref_view(declval<T>()))>> = true;
+
+        struct all_fn
+            : Internal::range_adaptor_closure<all_fn>
+        {
+            template<class View> 
+            constexpr auto operator()(View&& t) const noexcept(noexcept(static_cast<decay_t<View>>(AZStd::forward<View>(t))))
+                ->enable_if_t<ranges::view<decay_t<View>>, decltype(static_cast<decay_t<View>>(AZStd::forward<View>(t)))>
+            {
+                return static_cast<decay_t<View>>(AZStd::forward<View>(t));
+            }
+            template<class View>
+            constexpr auto operator()(View&& t) const noexcept(noexcept(ranges::ref_view(AZStd::forward<View>(t))))
+                ->enable_if_t<conjunction_v<
+                bool_constant<!ranges::view<decay_t<View>>>,
+                bool_constant<convertible_to_ref_view<View>>>, decltype(ranges::ref_view(AZStd::forward<View>(t)))>
+            {
+                return ranges::ref_view(AZStd::forward<View>(t));
+            }
+            template<class View>
+            constexpr auto operator()(View&& t) const noexcept(noexcept(ranges::owning_view(AZStd::forward<View>(t))))
+                ->enable_if_t<conjunction_v<
+                bool_constant<!ranges::view<decay_t<View>>>,
+                bool_constant<!convertible_to_ref_view<View>>>, decltype(ranges::owning_view(AZStd::forward<View>(t)))>
+            {
+                return ranges::owning_view(AZStd::forward<View>(t));
+            }
+        };
+    }
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::all_fn all{};
+    }
+
+    namespace Internal
+    {
+        template <class R, class = void>
+        struct all_t {};
+        template <class R>
+        struct all_t<R, enable_if_t<ranges::viewable_range<R>>>
+        {
+            using type = decltype(views::all(declval<R>()));
+        };
+    }
+    template<class R>
+    using all_t = typename Internal::all_t<R>::type;
+}

+ 475 - 0
Code/Framework/AzCore/AzCore/std/ranges/elements_view.h

@@ -0,0 +1,475 @@
+/*
+ * 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/ranges/all_view.h>
+#include <AzCore/std/ranges/ranges_adaptor.h>
+
+namespace AZStd::ranges
+{
+    namespace Internal
+    {
+        template<class T, size_t N, class = void>
+        /*concept*/ constexpr bool has_tuple_element = false;
+
+        template<class T, size_t N>
+        /*concept*/ constexpr bool has_tuple_element<T, N, enable_if_t<conjunction_v<
+            sfinae_trigger<typename tuple_size<T>::type>,
+            bool_constant<(N < tuple_size_v<T>)>,
+            sfinae_trigger<tuple_element_t<N, T>>,
+            bool_constant<convertible_to<decltype(AZStd::get<N>(declval<T>())), const tuple_element_t<N, T>&>> >
+        >> = true;
+
+        template<class T, size_t N, class = void>
+        /*concept*/ constexpr bool returnable_element = false;
+
+        template<class T, size_t N>
+        /*concept*/ constexpr bool returnable_element<T, N, enable_if_t<
+            is_reference_v<T>> > = true;
+
+        template<class T, size_t N>
+        /*concept*/ constexpr bool returnable_element<T, N, enable_if_t<
+            move_constructible<tuple_element_t<N, T>>> > = true;
+    }
+
+    template<class View, size_t N, class = enable_if_t<conjunction_v<
+        bool_constant<input_range<View>>,
+        bool_constant<view<View>>,
+        bool_constant<Internal::has_tuple_element<range_value_t<View>, N>>,
+        bool_constant<Internal::has_tuple_element<remove_reference_t<range_reference_t<View>>, N>>,
+        bool_constant<Internal::returnable_element<range_reference_t<View>, N>> >
+        >>
+    class elements_view;
+
+    // Alias for elements_view which is useful for extracting keys from associative containers
+    template<class View>
+    using keys_view = elements_view<View, 0>;
+    // Alias for elements_view which is useful for extracting values from associative containers
+    template<class View>
+    using values_view = elements_view<View, 1>;
+
+    template<class T, size_t N>
+    inline constexpr bool enable_borrowed_range<elements_view<T, N>> = enable_borrowed_range<T>;
+
+    // views::elements customization point
+    namespace views
+    {
+        namespace Internal
+        {
+            template<size_t N>
+            struct elements_fn
+                : Internal::range_adaptor_closure<elements_fn<N>>
+            {
+                template <class View, class = enable_if_t<conjunction_v<
+                    bool_constant<viewable_range<View>>
+                    >>>
+                constexpr auto operator()(View&& view) const
+                {
+                    return elements_view<views::all_t<View>, N>(AZStd::forward<View>(view));
+                }
+            };
+        }
+        inline namespace customization_point_object
+        {
+            template<size_t N>
+            constexpr Internal::elements_fn<N> elements{};
+
+            constexpr auto keys = elements<0>;
+            constexpr auto values = elements<1>;
+        }
+    }
+
+    template<class View, size_t N, class>
+    class elements_view
+        : public view_interface<elements_view<View, N>>
+    {
+        template<bool>
+        struct iterator;
+        template<bool>
+        struct sentinel;
+
+    public:
+        template <bool Enable = default_initializable<View>,
+            class = enable_if_t<Enable>>
+        elements_view() {}
+
+        explicit constexpr elements_view(View base)
+            : m_base(AZStd::move(base))
+        {
+        }
+
+        template <bool Enable = copy_constructible<View>, class = enable_if_t<Enable>>
+        constexpr View base() const&
+        {
+            return m_base;
+        }
+        constexpr View base()&&
+        {
+            return AZStd::move(m_base);
+        }
+
+        template<bool Enable = !Internal::simple_view<View>, class = enable_if_t<Enable>>
+        constexpr auto begin()
+        {
+            return iterator<false>{ ranges::begin(m_base) };
+        }
+
+        template<bool Enable = range<const View>, class = enable_if_t<Enable>>
+        constexpr auto begin() const
+        {
+            return iterator<true>{ ranges::begin(m_base) };
+        }
+
+        template<bool Enable = !Internal::simple_view<View>, class = enable_if_t<Enable>>
+        constexpr auto end()
+        {
+            if constexpr (!common_range<View>)
+            {
+                return sentinel<false>{ ranges::end(m_base) };
+            }
+            else
+            {
+                return iterator<false>{ ranges::end(m_base) };
+            }
+        }
+
+        template<bool Enable = range<const View>>
+        constexpr auto end() const
+        {
+            if constexpr (!common_range<const View>)
+            {
+                return sentinel<true>{ ranges::end(m_base) };
+            }
+            else
+            {
+                return iterator<true>{ ranges::end(m_base) };
+            }
+        }
+
+        template<bool Enable = sized_range<View>, class = enable_if_t<Enable>>
+        constexpr auto size()
+        {
+            return ranges::size(m_base);
+        }
+
+        template<bool Enable = sized_range<const View>, class = enable_if_t<Enable>>
+        constexpr auto size() const
+        {
+            return ranges::size(m_base);
+        }
+
+    private:
+        View m_base{};
+    };
+
+    template<class View, size_t N, bool Const, class = void>
+    struct elements_view_iterator_category {};
+
+    template<class View, size_t N, bool Const>
+    struct elements_view_iterator_category<View, N, Const, enable_if_t<forward_range<Internal::maybe_const<Const, View>> >>
+    {
+    private:
+        using Base = Internal::maybe_const<Const, View>;
+        using IterCategory = typename iterator_traits<iterator_t<Base>>::iterator_category;
+    public:
+        using iterator_category = conditional_t<
+            !is_lvalue_reference_v<decltype(AZStd::get<N>(*declval<iterator_t<Base>>()))>,
+            input_iterator_tag,
+            conditional_t<derived_from<IterCategory, random_access_iterator_tag>,
+                random_access_iterator_tag,
+                IterCategory>>;
+    };
+
+    template<class View, size_t N, class ViewEnable>
+    template<bool Const>
+    struct elements_view<View, N, ViewEnable>::iterator
+        : enable_if_t<conjunction_v<
+        bool_constant<input_range<View>>,
+        bool_constant<view<View>>,
+        bool_constant<Internal::has_tuple_element<range_value_t<View>, N>>,
+        bool_constant<Internal::has_tuple_element<remove_reference_t<range_reference_t<View>>, N>>,
+        bool_constant<Internal::returnable_element<range_reference_t<View>, N>> >
+        , elements_view_iterator_category<View, N, Const>
+       >
+    {
+    private:
+        template <bool>
+        friend struct sentinel;
+
+        using Base = Internal::maybe_const<Const, View>;
+    public:
+
+        using iterator_concept = conditional_t<random_access_range<Base>,
+            random_access_iterator_tag,
+            conditional_t<bidirectional_range<Base>,
+                bidirectional_iterator_tag,
+                conditional_t<forward_range<Base>,
+                    forward_iterator_tag,
+                    input_iterator_tag>>>;
+
+        using value_type = remove_cvref_t<tuple_element_t<N, range_value_t<Base>>>;
+        using difference_type = range_difference_t<Base>;
+
+        template<class BaseIter = iterator_t<Base>, class = enable_if_t<default_initializable<BaseIter>>>
+        iterator() {}
+
+        constexpr iterator(iterator_t<Base> current)
+            : m_current(AZStd::move(current))
+        {
+        }
+        template<class ViewIter = iterator_t<View>, class BaseIter = iterator_t<Base>,
+            class = enable_if_t<Const && convertible_to<ViewIter, BaseIter>>>
+        iterator(iterator<!Const> i)
+            : m_current(i.m_current)
+        {
+        }
+
+        constexpr iterator_t<View> base() const& noexcept
+        {
+            return m_current;
+        }
+
+        constexpr iterator_t<View> base() &&
+        {
+            return AZStd::move(m_current);
+        }
+
+        constexpr decltype(auto) operator*() const
+        {
+            return get_element(m_current);
+        }
+
+        constexpr iterator& operator++()
+        {
+            ++m_current;
+            return *this;
+        }
+
+        constexpr decltype(auto) operator++(int)
+        {
+            if constexpr (!forward_range<Base>)
+            {
+                ++m_current;
+            }
+            else
+            {
+                auto tmp = *this;
+                ++(*this);
+                return tmp;
+            }
+        }
+
+        template<bool Enable = bidirectional_range<Base>, class = enable_if_t<Enable>>
+        constexpr iterator& operator--() const
+        {
+            --m_current;
+            return *this;
+        }
+
+        template<bool Enable = bidirectional_range<Base>, class = enable_if_t<Enable>>
+        constexpr iterator operator--(int) const
+        {
+            auto tmp = *this;
+            --(*this);
+            return tmp;
+        }
+
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        constexpr iterator& operator+=(difference_type n)
+        {
+            m_current += n;
+            return *this;
+        }
+
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        constexpr iterator& operator-=(difference_type n)
+        {
+            m_current -= n;
+            return *this;
+        }
+
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        constexpr decltype(auto) operator[](difference_type n) const
+        {
+            return get_element(m_current + n);
+        }
+
+        // equality_comparable
+        template<class BaseIter = iterator_t<Base>, class = enable_if_t<equality_comparable<BaseIter>>>
+        friend constexpr bool operator==(const iterator& x, const iterator& y)
+        {
+            return x.m_current == y.m_current;
+        }
+        friend constexpr bool operator!=(const iterator& y, const iterator& x)
+        {
+            return !operator==(x, y);
+        }
+
+        // strict_weak_order
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr bool operator<(const iterator& x, const iterator& y)
+        {
+            return x.m_current < y.m_current;
+        }
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr bool operator>(const iterator& x, const iterator& y)
+        {
+            return y < x;
+        }
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr bool operator<=(const iterator& x, const iterator& y)
+        {
+            return !(y < x);
+        }
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr bool operator>=(const iterator& x, const iterator& y)
+        {
+            return !(x < y);
+        }
+
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr iterator operator+(const iterator& x, difference_type n)
+        {
+            iterator iterCopy(x);
+            iterCopy += n;
+            return iterCopy;
+        }
+
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr iterator operator+(difference_type n, const iterator& x)
+        {
+            return n + x;
+        }
+
+        template<bool Enable = random_access_range<Base>, class = enable_if_t<Enable>>
+        friend constexpr iterator operator-(const iterator& x, difference_type n)
+        {
+            iterator iterCopy(x);
+            iterCopy -= n;
+            return iterCopy;
+        }
+
+        template<class BaseIter = iterator_t<Base>, class = enable_if_t<sized_sentinel_for<BaseIter, BaseIter>>>
+        friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+        {
+            return x.m_current - y.m_current;
+        }
+    private:
+        static constexpr decltype(auto) get_element(const iterator_t<Base>& i)
+        {
+            if constexpr (is_reference_v<range_reference_t<Base>>)
+            {
+                // Return a reference to the element of the tuple like type
+                return AZStd::get<N>(*i);
+            }
+            else
+            {
+                // Cast the result of calling AZStd::get on value type reference
+                using E = remove_cv_t<tuple_element_t<N, range_reference_t<Base>>>;
+                return static_cast<E>(AZStd::get<N>(*i));
+            }
+        }
+
+        //! iterator to range being viewed
+        iterator_t<Base> m_current{};
+    };
+
+    namespace ElementsViewInternal
+    {
+        struct requirements_fulfilled {};
+    }
+
+    template<class View, size_t N, class ViewEnable>
+    template<bool Const>
+    struct elements_view<View, N, ViewEnable>::sentinel
+        : enable_if_t<conjunction_v<
+        bool_constant<input_range<View>>,
+        bool_constant<view<View>>,
+        bool_constant<Internal::has_tuple_element<range_value_t<View>, N>>,
+        bool_constant<Internal::has_tuple_element<remove_reference_t<range_reference_t<View>>, N>>,
+        bool_constant<Internal::returnable_element<range_reference_t<View>, N>> >
+        , ElementsViewInternal::requirements_fulfilled>
+    {
+    private:
+        using Base = Internal::maybe_const<Const, View>;
+
+    public:
+        sentinel() = default;
+
+        explicit constexpr sentinel(sentinel_t<View> end)
+            : m_end(end)
+        {
+        }
+        template<class SentinelView = sentinel_t<View>, class SentinelBase = sentinel_t<Base>,
+            class = enable_if_t<Const && convertible_to<SentinelView, SentinelBase>>>
+        constexpr sentinel(sentinel<!Const> s)
+            : m_end(AZStd::move(s.m_end))
+        {
+        }
+
+        constexpr sentinel_t<View> base() const
+        {
+            return m_end;
+        }
+
+        // comparison operators
+        template<bool OtherConst, class = enable_if_t<
+            sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+        >>
+        friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y)
+        {
+            return iterator_accessor(x) == y.m_end;
+        }
+        template<bool OtherConst>
+        friend constexpr bool operator==(const sentinel& y, const iterator<OtherConst>& x)
+        {
+            return operator==(x, y);
+        }
+        template<bool OtherConst>
+        friend constexpr bool operator!=(const iterator<OtherConst>& x, const sentinel& y)
+        {
+            return !operator==(x, y);
+        }
+        template<bool OtherConst>
+        friend constexpr bool operator!=(const sentinel& y, const iterator<OtherConst>& x)
+        {
+            return !operator==(x, y);
+        }
+
+        // difference operator
+        template<bool OtherConst, class = enable_if_t<
+            sized_sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+            >>
+        friend constexpr range_difference_t<Internal::maybe_const<OtherConst, Base >>
+            operator-(const iterator<OtherConst>& x, const sentinel& y)
+        {
+            return iterator_accessor(x) - y.m_end;
+        }
+
+        template<bool OtherConst, class = enable_if_t<
+            sized_sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+            >>
+        friend constexpr range_difference_t<Internal::maybe_const<OtherConst, Base>>
+            operator-(const sentinel& x, const iterator<OtherConst>& y)
+        {
+            return x.m_end - iterator_accessor(y);
+        }
+    private:
+        // On MSVC The friend functions are can only access the sentinel struct members
+        // The iterator struct which is a friend of the sentinel struct is NOT a friend
+        // of the friend functions
+        // So a shim is added to provide access to the iterator m_current member
+        template<bool OtherConst>
+        static constexpr auto iterator_accessor(const iterator<OtherConst>& it)
+        {
+            return it.m_current;
+        }
+
+        sentinel_t<Base> m_end{};
+    };
+}

+ 37 - 0
Code/Framework/AzCore/AzCore/std/ranges/empty_view.h

@@ -0,0 +1,37 @@
+/*
+ * 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/ranges/ranges.h>
+
+namespace AZStd::ranges
+{
+    template<class T, class = void>
+    class empty_view;
+
+    template<class T>
+    class empty_view<T, enable_if_t<is_object_v<T>>>
+        : public view_interface<empty_view<T>>
+    {
+    public:
+        static constexpr T* begin() noexcept { return nullptr; }
+        static constexpr T* end() noexcept { return nullptr; }
+        static constexpr T* data() noexcept { return nullptr; }
+        static constexpr size_t size() noexcept { return 0; }
+        static constexpr bool empty() noexcept { return true; }
+    };
+
+    namespace views
+    {
+        template<class T>
+        constexpr empty_view<T> empty{};
+    }
+
+    template<class T>
+    inline constexpr bool enable_borrowed_range<empty_view<T>> = true;
+}

+ 10 - 2
Code/Framework/AzCore/AzCore/std/ranges/iter_move.h

@@ -74,8 +74,16 @@ namespace AZStd::ranges::Internal
 
 namespace AZStd::ranges
 {
-    inline namespace customization_point_object
+    // Workaround for clang bug https://bugs.llvm.org/show_bug.cgi?id=37556
+    // Adding placing the inline customization_point_object namespace
+    // under a regular namespace and then aliasing that into the AZStd::ranges namespace
+    namespace workaround
     {
-        inline constexpr auto iter_move = Internal::iter_move_fn{};
+        inline namespace customization_point_object
+        {
+            inline constexpr auto iter_move = Internal::iter_move_fn{};
+        }
     }
+
+    using namespace workaround;
 }

+ 120 - 0
Code/Framework/AzCore/AzCore/std/ranges/iter_swap.h

@@ -0,0 +1,120 @@
+/*
+ * 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/base.h>
+
+#include <AzCore/std/iterator/iterator_primitives.h>
+#include <AzCore/std/ranges/swap.h>
+#include <AzCore/std/typetraits/conjunction.h>
+#include <AzCore/std/typetraits/disjunction.h>
+#include <AzCore/std/typetraits/extent.h>
+#include <AzCore/std/typetraits/integral_constant.h>
+#include <AzCore/std/typetraits/is_class.h>
+#include <AzCore/std/typetraits/is_enum.h>
+#include <AzCore/std/typetraits/is_void.h>
+#include <AzCore/std/typetraits/remove_cvref.h>
+#include <AzCore/std/typetraits/void_t.h>
+#include <AzCore/std/utility/declval.h>
+
+
+namespace AZStd::ranges::Internal
+{
+    template<class I1, class I2>
+    void iter_swap(I1, I2) = delete;
+
+    template <class I1, class I2, class = void>
+    constexpr bool is_class_or_enum_with_iter_swap_adl = false;
+
+    template <class I1, class I2>
+    constexpr bool is_class_or_enum_with_iter_swap_adl<I1, I2, enable_if_t<conjunction_v<
+        disjunction<
+        disjunction<is_class<remove_cvref_t<I1>>, is_enum<remove_cvref_t<I1>>>,
+        disjunction<is_class<remove_cvref_t<I2>>, is_enum<remove_cvref_t<I2>>>>,
+        is_void<void_t<decltype(iter_swap(declval<I1>(), declval<I2>()))>>
+        >>> = true;
+
+    struct iter_swap_fn
+    {
+        template <class I1, class I2>
+        constexpr auto operator()(I1&& i1, I2&& i2) const
+            ->enable_if_t<is_class_or_enum_with_iter_swap_adl<I1, I2>
+            >
+        {
+            iter_swap(AZStd::forward<I1>(i1), AZStd::forward<I1>(i2));
+        }
+        template <class I1, class I2>
+        constexpr auto operator()(I1&& i1, I2&& i2) const
+            ->enable_if_t<conjunction_v<bool_constant<!is_class_or_enum_with_iter_swap_adl<I1, I2>>,
+            bool_constant<indirectly_readable<I1>>,
+            bool_constant<indirectly_readable<I2>>,
+            bool_constant<swappable_with<iter_reference_t<I1>, iter_reference_t<I2>>>
+            >>
+        {
+            ranges::swap(*i1, *i2);
+        }
+
+        template <class I1, class I2>
+        constexpr auto operator()(I1&& i1, I2&& i2) const
+            ->enable_if_t<conjunction_v<bool_constant<!is_class_or_enum_with_iter_swap_adl<I1, I2>>,
+            bool_constant<!swappable_with<iter_reference_t<I1>, iter_reference_t<I2>>>,
+            bool_constant<indirectly_movable_storable<I1, I2>>,
+            bool_constant<indirectly_movable_storable<I2, I1>>
+            >>
+        {
+            *AZStd::forward<I1>(i1) = iter_exchange_move(AZStd::forward<I2>(i2), AZStd::forward<I1>(i1));
+        }
+
+    private:
+        template<class X, class Y>
+        static constexpr iter_value_t<X> iter_exchange_move(X&& x, Y&& y)
+            noexcept(noexcept(iter_value_t<X>(iter_move(x))) && noexcept(*x = iter_move(y)))
+        {
+            iter_value_t<X> old_value(iter_move(x));
+            *x = iter_move(y);
+            return old_value;
+        }
+    };
+}
+
+namespace AZStd::ranges
+{
+    // Workaround for clang bug https://bugs.llvm.org/show_bug.cgi?id=37556
+    // Using a placeholder namespace to wrap the customization point object
+    // inline namespce and then bring that placeholder namespace into scope
+    namespace workaround
+    {
+        inline namespace customization_point_object
+        {
+            inline constexpr Internal::iter_swap_fn iter_swap{};
+        }
+    }
+}
+
+namespace AZStd::Internal
+{
+    template <class I1, class I2, class = void>
+    constexpr bool indirectly_swappable_impl = false;
+    template <class I1, class I2>
+    constexpr bool indirectly_swappable_impl<I1, I2, enable_if_t<conjunction_v<
+        bool_constant<indirectly_readable<I1>>,
+        bool_constant<indirectly_readable<I2>>,
+        is_void<void_t<
+        decltype(AZStd::ranges::iter_swap(declval<I1>(), declval<I1>())),
+        decltype(AZStd::ranges::iter_swap(declval<I2>(), declval<I2>())),
+        decltype(AZStd::ranges::iter_swap(declval<I1>(), declval<I2>())),
+        decltype(AZStd::ranges::iter_swap(declval<I2>(), declval<I1>()))>>
+        >>> = true;
+}
+
+namespace AZStd
+{
+    template<class I1, class I2 = I1>
+    /*concept*/ constexpr bool indirectly_swappable = Internal::indirectly_swappable_impl<I1, I2>;
+}
+

+ 430 - 0
Code/Framework/AzCore/AzCore/std/ranges/join_view.h

@@ -0,0 +1,430 @@
+/*
+ * 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/ranges/all_view.h>
+#include <AzCore/std/ranges/ranges_adaptor.h>
+#include <AzCore/std/ranges/ranges_functional.h>
+
+namespace AZStd::ranges
+{
+    template<class View, class = enable_if_t<conjunction_v<
+        bool_constant<input_range<View>>,
+        bool_constant<view<View>>,
+        bool_constant<input_range<range_reference_t<View>>>
+        >>>
+        class join_view;
+
+    // views::join customization point
+    namespace views
+    {
+        namespace Internal
+        {
+            struct join_view_fn
+                : Internal::range_adaptor_closure<join_view_fn>
+            {
+                template <class View, class = enable_if_t<conjunction_v<
+                    bool_constant<viewable_range<View>>
+                    >>>
+                constexpr auto operator()(View&& view) const
+                {
+                    return join_view(views::all(AZStd::forward<View>(view)));
+                }
+            };
+        }
+        inline namespace customization_point_object
+        {
+            constexpr Internal::join_view_fn join{};
+        }
+    }
+
+    template<class View, class>
+    class join_view
+        : public view_interface<join_view<View>>
+    {
+        template<bool>
+        struct iterator;
+        template<bool>
+        struct sentinel;
+
+    public:
+        template <bool Enable = default_initializable<View>,
+            class = enable_if_t<Enable>>
+        join_view() {}
+
+        explicit constexpr join_view(View base)
+            : m_base(AZStd::move(base))
+        {}
+
+
+        template <bool Enable = copy_constructible<View>, class = enable_if_t<Enable>>
+        constexpr View base() const&
+        {
+            return m_base;
+        }
+        constexpr View base() &&
+        {
+            return AZStd::move(m_base);
+        }
+
+        constexpr auto begin()
+        {
+            constexpr bool UseConst = Internal::simple_view<View> && is_reference_v<range_reference_t<View>>;
+            return iterator<UseConst>{ *this, ranges::begin(m_base) };
+        }
+
+        template<class ConstView = const View,
+            class = enable_if_t<input_range<ConstView> && is_reference_v<range_reference_t<ConstView>>>>
+        constexpr auto begin() const
+        {
+            return iterator<true>{ *this, ranges::begin(m_base) };
+        }
+
+        constexpr decltype(auto) end()
+        {
+            if constexpr (forward_range<View> && is_reference_v<InnerRange> &&
+                forward_range<InnerRange> && common_range<View> && common_range<InnerRange>)
+            {
+                return iterator<Internal::simple_view<View>>{ *this, ranges::end(m_base) };
+            }
+            else
+            {
+                return sentinel<Internal::simple_view<View>>{ *this };
+            }
+        }
+        template<class ConstView = const View,
+            class = enable_if_t<input_range<ConstView> && is_reference_v<range_reference_t<ConstView>>>>
+        constexpr auto end() const
+        {
+            if constexpr (forward_range<const View> && forward_range<range_reference_t<const View>> &&
+                common_range<const View> && common_range<range_reference_t<const View>>)
+            {
+                return iterator<true>{ *this, ranges::end(m_base) };
+            }
+            else
+            {
+                return sentinel<true>{ *this };
+            }
+        }
+    private:
+        View m_base{};
+
+        using InnerRange = range_reference_t<View>;
+        // When the inner range for the view is a reference it doesn't need to be stored
+        struct InnerRangeIsReference {};
+        using InnerRange_t = conditional_t<is_reference_v<InnerRange>, InnerRangeIsReference,
+            Internal::non_propagating_cache<remove_cv_t<InnerRange>>>;
+        AZ_NO_UNIQUE_ADDRESS InnerRange_t m_inner{};
+    };
+
+    template<class View, bool Const, class = void>
+    struct join_view_iterator_category {};
+    template<class View, bool Const>
+    struct join_view_iterator_category<View, Const, enable_if_t<conjunction_v<
+        is_reference<range_reference_t<Internal::maybe_const<Const, View>>>,
+        bool_constant<forward_range<Internal::maybe_const<Const, View>>>,
+        bool_constant<forward_range<range_reference_t<Internal::maybe_const<Const, View>>>>
+        >>>
+    {
+    private:
+        using Base = Internal::maybe_const<Const, View>;
+        using OuterC = typename iterator_traits<iterator_t<Base>>::iterator_category;
+        using InnerC = typename iterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category;
+    public:
+        using iterator_category = conditional_t<conjunction_v<
+                bool_constant<derived_from<OuterC, bidirectional_iterator_tag>>,
+                bool_constant<derived_from<InnerC, bidirectional_iterator_tag>>,
+                bool_constant<common_range<range_reference_t<Base>>> >,
+                bidirectional_iterator_tag,
+                conditional_t<conjunction_v<
+                    bool_constant<derived_from<OuterC, forward_iterator_tag>>,
+                    bool_constant<derived_from<InnerC, forward_iterator_tag>> >,
+                    forward_iterator_tag,
+                    input_iterator_tag>>;
+    };
+
+
+    template<class R>
+    join_view(R&&) -> join_view<views::all_t<R>>;
+
+    template<class View, class ViewEnable>
+    template<bool Const>
+    struct join_view<View, ViewEnable>::iterator
+        : enable_if_t<conjunction_v<
+        bool_constant<input_range<View>>,
+        bool_constant<view<View>>,
+        bool_constant<input_range<range_reference_t<View>>>
+        >, join_view_iterator_category<View, Const>
+       >
+    {
+    private:
+        template<bool>
+        friend struct sentinel;
+
+        using Parent = Internal::maybe_const<Const, join_view>;
+        using Base = Internal::maybe_const<Const, View>;
+        using OuterIter = iterator_t<Base>;
+        using InnerIter = iterator_t<range_reference_t<Base>>;
+        static constexpr bool ref_is_glvalue = is_reference_v<range_reference_t<Base>>;
+    public:
+
+        using iterator_concept = conditional_t<ref_is_glvalue && bidirectional_range<Base>
+            && common_range<Base>, bidirectional_iterator_tag,
+            conditional_t<ref_is_glvalue && forward_range<Base> && forward_range<range_reference_t<Base>>,
+            forward_iterator_tag,
+            input_iterator_tag>>;
+
+        using value_type = range_value_t<range_reference_t<Base>>;
+        using difference_type = common_type_t<range_difference_t<Base>,
+            range_difference_t<range_reference_t<Base>>>;
+
+        template<bool Enable = default_initializable<OuterIter> && default_initializable<InnerIter>,
+            class = enable_if_t<Enable>>
+        iterator() {}
+
+        constexpr iterator(join_view& parent, OuterIter outer)
+            : m_parent(addressof(parent))
+            , m_outer(AZStd::move(outer))
+        {
+            satisfy();
+        }
+        template<bool Enable = convertible_to<iterator_t<View>, OuterIter> &&
+            convertible_to<iterator_t<InnerRange>, InnerIter>,
+            class = enable_if_t<Enable>>
+        iterator(iterator<!Const> i)
+            : m_parent(i.m_parent)
+            , m_outer(i.m_outer)
+            , m_inner(i.m_inner)
+        {}
+
+        constexpr iterator_t<View> base() const
+        {
+            return m_inner;
+        }
+
+        constexpr decltype(auto) operator*() const
+        {
+            return *m_inner;
+        }
+
+        template<bool Enable = Internal::has_arrow<InnerIter> && copyable<InnerIter>,
+            class = enable_if_t<Enable>>
+        constexpr InnerIter operator->() const
+        {
+            return m_inner;
+        }
+
+        constexpr iterator& operator++()
+        {
+            if constexpr (ref_is_glvalue)
+            {
+                auto&& innerRange = *m_outer;
+                if (++m_inner == ranges::end(innerRange))
+                {
+                    ++m_outer;
+                    satisfy();
+                }
+            }
+            else
+            {
+                auto&& innerRange = *m_parent->m_inner;
+                if (++m_inner == ranges::end(innerRange))
+                {
+                    ++m_outer;
+                    satisfy();
+
+                }
+            }
+            return *this;
+        }
+
+        constexpr void operator++(int)
+        {
+            ++(*this);
+        }
+
+        template<bool Enable = ref_is_glvalue && bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>>,
+            class = enable_if_t<Enable && common_range<range_reference_t<Base>>>>
+        constexpr iterator& operator--() const
+        {
+            if (m_outer == ranges::end(m_parent->m_base))
+            {
+                m_inner = ranges::end(*--m_outer);
+            }
+            // Move inner iterator backwards to the last element of the first non-empty outer iterator
+            // by iterating backwards
+            while (m_inner == ranges::begin(*m_outer))
+            {
+                m_inner = ranges::end(*--m_outer);
+                --m_inner;
+            }
+            return *this;
+        }
+
+        template<bool Enable = ref_is_glvalue && bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>>,
+            class = enable_if_t<Enable && common_range<range_reference_t<Base>>>>
+        constexpr iterator operator--(int) const
+        {
+            auto tmp = *this;
+            --(*this);
+            return tmp;
+        }
+
+        template<class OtherBase = Base,
+            class = enable_if_t<ref_is_glvalue && equality_comparable<iterator_t<OtherBase>> &&
+            equality_comparable<iterator_t<range_reference_t<OtherBase>>>>>
+        friend constexpr bool operator==(const iterator& x, const iterator& y)
+        {
+            return x.m_outer == y.m_outer && x.m_inner == y.m_inner;
+        }
+        template<class OtherBase = Base,
+            class = enable_if_t<ref_is_glvalue && equality_comparable<iterator_t<OtherBase>>&&
+            equality_comparable<iterator_t<range_reference_t<OtherBase>>>>>
+        friend constexpr bool operator!=(const iterator& x, const iterator& y)
+        {
+            return !operator==(x, y);
+        }
+
+        // customization of iter_move and iter_swap
+
+        friend constexpr decltype(auto) iter_move(
+            iterator& i)
+            noexcept(noexcept(ranges::iter_move(i.m_inner)))
+        {
+            return ranges::iter_move(i.m_inner);
+        }
+
+
+        friend constexpr void iter_swap(
+            iterator& x,
+            iterator& y)
+            noexcept(noexcept(ranges::iter_swap(x.m_inner, y.m_inner)))
+        {
+            return ranges::iter_swap(x.m_inner, y.m_inner);
+        }
+
+    private:
+        constexpr void satisfy()
+        {
+            // dereference the outer iterator if the inner iterato is a reference
+            // or make a copy of deref ference of outer iterator
+            auto update_inner = [this](const iterator_t<Base>& x) constexpr -> auto&&
+            {
+                if constexpr (ref_is_glvalue)     // *x is a reference
+                {
+                    // workaround clang 9.0.0 bug where this is unused because
+                    // of not being used in one block of the if constexpr
+                    (void)this;
+                    return *x;
+                }
+                else
+                {
+                    return m_parent->m_inner.emplace_deref(x);
+                }
+            };
+
+            for (; m_outer != ranges::end(m_parent->m_base); ++m_outer)
+            {
+
+                auto&& inner = update_inner(m_outer);
+                m_inner = ranges::begin(inner);
+                // m_inner is end then the inner range is empty
+                // and the next outer element is iterated over
+                if (m_inner != ranges::end(inner))
+                {
+                    return;
+                }
+            }
+            if constexpr (ref_is_glvalue)
+            {
+                m_inner = InnerIter();
+            }
+        }
+
+        //! iterator to the outer view element of the view wrapped by the join view
+        OuterIter m_outer{};
+        //! iterator to the actually range element which is wrapped by the view
+        InnerIter m_inner{};
+        //! reference to parent join_view
+        join_view<View>* m_parent{};
+    };
+
+
+    // sentinel type for iterator
+    namespace JoinViewInternal
+    {
+        struct requirements_fulfilled {};
+    }
+
+    template<class View, class ViewEnable>
+    template<bool Const>
+    struct join_view<View, ViewEnable>::sentinel
+        : enable_if_t<conjunction_v<
+        bool_constant<input_range<View>>,
+        bool_constant<view<View>>,
+        bool_constant<input_range<range_reference_t<View>>>
+        >, JoinViewInternal::requirements_fulfilled>
+    {
+    private:
+        using Parent = Internal::maybe_const<Const, join_view>;
+        using Base = Internal::maybe_const<Const, View>;
+
+    public:
+        sentinel() = default;
+        explicit constexpr sentinel(Parent& parent)
+            : m_end(ranges::end(parent.m_base))
+        {}
+        template<bool Enable = Const,
+            class = enable_if_t<Enable && convertible_to<sentinel_t<View>, sentinel_t<Base>>>>
+        constexpr sentinel(sentinel<!Const> s)
+            : m_end(AZStd::move(s.m_end))
+        {
+        }
+
+        // comparison operators
+        template<bool OtherConst, class = enable_if_t<
+            sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+        >>
+        friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y)
+        {
+            return iterator_accessor(x) == y.m_end;
+        }
+        template<bool OtherConst, class = enable_if_t<
+            sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+        >>
+        friend constexpr bool operator==(const sentinel& y, const iterator<OtherConst>& x)
+        {
+            return operator==(x, y);
+        }
+        template<bool OtherConst, class = enable_if_t<
+            sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+        >>
+        friend constexpr bool operator!=(const iterator<OtherConst>& x, const sentinel& y)
+        {
+            return !operator==(x, y);
+        }
+        template<bool OtherConst, class = enable_if_t<
+            sentinel_for<sentinel_t<Base>, iterator_t<Internal::maybe_const<OtherConst, Base>>>
+        >>
+        friend constexpr bool operator!=(const sentinel& y, const iterator<OtherConst>& x)
+        {
+            return !operator==(x, y);
+        }
+    private:
+        // On MSVC The friend functions are can only access the sentinel struct members
+        // The iterator struct which is a friend of the sentinel struct is NOT a friend
+        // of the friend functions
+        // So a shim is added to provide access to the iterator m_current member
+        template<bool OtherConst>
+        static constexpr auto iterator_accessor(const iterator<OtherConst>& it)
+        {
+            return it.m_outer;
+        }
+        sentinel_t<Base> m_end{};
+    };
+}

+ 114 - 0
Code/Framework/AzCore/AzCore/std/ranges/owning_view.h

@@ -0,0 +1,114 @@
+/*
+ * 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/ranges/ranges_adaptor.h>
+
+namespace AZStd::ranges
+{
+    template<class R, class = void>
+    class owning_view;
+
+    template<class R>
+    class owning_view<R, enable_if_t<ranges::range<R> && movable<R> &&
+        !Internal::is_initializer_list<remove_cvref_t<R>> >>
+        : public ranges::view_interface<owning_view<R>>
+    {
+    public:
+
+        template<class T = R, enable_if_t<default_initializable<T>>>
+        constexpr owning_view() {}
+
+        constexpr owning_view(R&& t)
+            : m_range{ AZStd::move(t) }
+        {}
+
+        constexpr owning_view(owning_view&&) = default;
+        constexpr owning_view& operator=(owning_view&&) = default;
+
+        constexpr R& base() & noexcept
+        {
+            return m_range;
+        }
+        constexpr const R& base() const& noexcept
+        {
+            return m_range;
+        }
+        constexpr R&& base() && noexcept
+        {
+            return AZStd::move(m_range);
+        }
+        constexpr const R&& base() const&& noexcept
+        {
+            return AZStd::move(m_range);
+        }
+
+        constexpr iterator_t<R> begin()
+        {
+            return ranges::begin(m_range);
+        }
+        constexpr sentinel_t<R> end()
+        {
+            return ranges::end(m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto begin() const -> enable_if_t<range<const R>, decltype(ranges::begin(declval<Rn>()))>
+        {
+            return ranges::begin(m_range);
+        }
+        template<class Rn = R>
+        constexpr auto end() const -> enable_if_t<range<const R>, decltype(ranges::end(declval<Rn>()))>
+        {
+            return ranges::end(m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto empty() -> enable_if_t<Internal::sfinae_trigger_v<decltype(ranges::empty(declval<Rn>()))>, bool>
+        {
+            return ranges::empty(m_range);
+        }
+        template<class Rn = R>
+        constexpr auto empty() const -> enable_if_t<Internal::sfinae_trigger_v<decltype(ranges::empty(declval<Rn>()))>, bool>
+        {
+            return ranges::empty(m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto size() -> enable_if_t<sized_range<R>, decltype(ranges::size(declval<Rn>()))>
+        {
+            return ranges::size(m_range);
+        }
+        template<class Rn = R>
+        constexpr auto size() const -> enable_if_t<sized_range<const R>, decltype(ranges::size(declval<Rn>()))>
+        {
+            return ranges::size(m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto data() -> enable_if_t<contiguous_range<R>, decltype(ranges::data(declval<Rn>()))>
+        {
+            return ranges::data(m_range);
+        }
+        template<class Rn = R>
+        constexpr auto data() const -> enable_if_t<contiguous_range<const R>, decltype(ranges::data(declval<Rn>()))>
+        {
+            return ranges::data(m_range);
+        }
+
+    private:
+        R m_range;
+    };
+
+    //! deduction guides
+    template<class R>
+    owning_view(R&&) -> owning_view<R>;
+
+    template<class T>
+    inline constexpr bool enable_borrowed_range<owning_view<T>> = enable_borrowed_range<T>;
+}

+ 290 - 139
Code/Framework/AzCore/AzCore/std/ranges/ranges.h

@@ -36,10 +36,12 @@ namespace AZStd::ranges
     {
         // Variadic template which maps types to true For SFINAE
         template <class... Args>
+        using sfinae_trigger = true_type;
+        template <class... Args>
         constexpr bool sfinae_trigger_v = true;
 
         template <class T>
-        constexpr bool is_lvalue_or_borrowable = is_lvalue_reference_v<T> || enable_borrowed_range<remove_cv_t<T>>;
+        constexpr bool is_lvalue_or_borrowable = disjunction_v<is_lvalue_reference<T>, bool_constant<enable_borrowed_range<remove_cv_t<T>>>>;
 
         //! begin
         template <class T, typename = void>
@@ -50,8 +52,11 @@ namespace AZStd::ranges
         template <class T, typename = void>
         constexpr bool has_unqualified_begin = false;
         template <class T>
-        constexpr bool has_unqualified_begin<T, void_t<decltype(begin(declval<T&>()))>>
-            = !has_member_begin<T> && AZStd::Internal::is_class_or_enum<T>;
+        constexpr bool has_unqualified_begin<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_begin<T>>,
+            bool_constant<AZStd::Internal::is_class_or_enum<T>>,
+            sfinae_trigger<decltype(begin(declval<T&>()))>
+            >>> = true;
 
         template<class T>
         void begin(T&) = delete;
@@ -62,7 +67,7 @@ namespace AZStd::ranges
         {
             template<class T>
             constexpr auto operator()(T& t) const noexcept ->
-                enable_if_t<is_array_v<T> && sfinae_trigger_v<remove_all_extents_t<T>>,
+                enable_if_t<conjunction_v<is_array<T>, sfinae_trigger<remove_all_extents_t<T>>>,
                 decltype(t + 0)>
             {
                 return t + 0;
@@ -70,8 +75,11 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).begin())) ->
-                enable_if_t<input_or_output_iterator<decltype(t.begin())>&& is_lvalue_or_borrowable<T>
-                && !is_array_v<T>&& has_member_begin<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<input_or_output_iterator<decltype(AZStd::forward<T>(t).begin())>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<!is_array_v<T>>,
+                bool_constant<has_member_begin<T>>>,
                 decltype(AZStd::forward<T>(t).begin())>
             {
                 return AZStd::forward<T>(t).begin();
@@ -79,8 +87,11 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(begin(AZStd::forward<T>(t)))) ->
-                enable_if_t<input_or_output_iterator<decltype(begin(t))>&& is_lvalue_or_borrowable<T>
-                && !is_array_v<T> && has_unqualified_begin<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<input_or_output_iterator<decltype(begin(AZStd::forward<T>(t)))>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<!is_array_v<T>>,
+                bool_constant<has_unqualified_begin<T>>>,
                 decltype(begin(AZStd::forward<T>(t)))>
             {
                 return begin(AZStd::forward<T>(t));
@@ -109,8 +120,11 @@ namespace AZStd::ranges
         template <class T, typename = void>
         constexpr bool has_unqualified_end = false;
         template <class T>
-        constexpr bool has_unqualified_end<T, void_t<decltype(end(declval<T&>()))>>
-            = !has_member_end<T> && AZStd::Internal::is_class_or_enum<T>;
+        constexpr bool has_unqualified_end<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_end<T>>,
+            bool_constant<AZStd::Internal::is_class_or_enum<T>>,
+            sfinae_trigger<decltype(end(declval<T&>()))>
+            >>> = true;
 
         template<class T>
         void end(T&) = delete;
@@ -121,7 +135,7 @@ namespace AZStd::ranges
         {
             template<class T>
             constexpr auto operator()(T& t) const noexcept ->
-                enable_if_t<is_array_v<T> && extent_v<T> != 0,
+                enable_if_t<conjunction_v<is_array<T>, bool_constant<extent_v<T> != 0>>,
                 decltype(t + extent_v<T>)>
             {
                 return t + extent_v<T>;
@@ -129,8 +143,11 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).end())) ->
-                enable_if_t<sentinel_for<decltype(t.end()), iterator_t<T>>&& is_lvalue_or_borrowable<T>
-                && !is_array_v<T> && has_member_end<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<sentinel_for<decltype(AZStd::forward<T>(t).end()), iterator_t<T>>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<!is_array_v<T>>,
+                bool_constant<has_member_end<T>>>,
                 decltype(AZStd::forward<T>(t).end())>
             {
                 return AZStd::forward<T>(t).end();
@@ -138,8 +155,11 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(end(AZStd::forward<T>(t)))) ->
-                enable_if_t<sentinel_for<decltype(end(t)), iterator_t<T>>&& is_lvalue_or_borrowable<T>
-                && !is_array_v<T> && has_unqualified_end<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<sentinel_for<decltype(end(AZStd::forward<T>(t))), iterator_t<T>>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<!is_array_v<T>>,
+                bool_constant<has_unqualified_end<T>>>,
                 decltype(end(AZStd::forward<T>(t)))>
             {
                 return end(AZStd::forward<T>(t));
@@ -212,17 +232,22 @@ namespace AZStd::ranges
         template <class T, class = void>
         constexpr bool has_unqualified_rbegin = false;
         template <class T>
-        constexpr bool has_unqualified_rbegin<T, void_t<decltype(rbegin(declval<T&>()))>>
-            = !has_member_rbegin<T> && AZStd::Internal::is_class_or_enum<T>;
+        constexpr bool has_unqualified_rbegin<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_rbegin<T>>,
+            sfinae_trigger<decltype(rbegin(declval<T&>()))>,
+            bool_constant<::AZStd::Internal::is_class_or_enum<T>>
+            >>> = true;
 
         template <class T, class = void>
         constexpr bool has_bidirectional_rbegin = false;
         template <class T>
-        constexpr bool has_bidirectional_rbegin<T, enable_if_t<
-            same_as<decltype(ranges::begin(declval<T&>())), decltype(ranges::end(declval<T&>()))>
-            && bidirectional_iterator<decltype(ranges::begin(declval<T&>()))>
-            && bidirectional_iterator<decltype(ranges::end(declval<T&>()))>
-            >> = !has_member_rbegin<T> && !has_unqualified_rbegin<T>;
+        constexpr bool has_bidirectional_rbegin<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_rbegin<T>>,
+            bool_constant<!has_unqualified_rbegin<T>>,
+            bool_constant<same_as<decltype(ranges::begin(declval<T&>())), decltype(ranges::end(declval<T&>()))>>,
+            bool_constant<bidirectional_iterator<decltype(ranges::begin(declval<T&>()))>>,
+            bool_constant<bidirectional_iterator<decltype(ranges::end(declval<T&>()))>>
+            >>> = true;
 
 
         template<class T>
@@ -234,8 +259,10 @@ namespace AZStd::ranges
         {
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).rbegin())) ->
-                enable_if_t<input_or_output_iterator<decltype(t.rbegin())> && is_lvalue_or_borrowable<T>
-                && has_member_rbegin<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<input_or_output_iterator<decltype(AZStd::forward<T>(t).rbegin())>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<has_member_rbegin<T>>>,
                 decltype(AZStd::forward<T>(t).rbegin())>
             {
                 return AZStd::forward<T>(t).rbegin();
@@ -243,8 +270,10 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(rbegin(AZStd::forward<T>(t)))) ->
-                enable_if_t<input_or_output_iterator<decltype(rbegin(t))> && is_lvalue_or_borrowable<T>
-                && has_unqualified_rbegin<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<input_or_output_iterator<decltype(rbegin(AZStd::forward<T>(t)))>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<has_unqualified_rbegin<T>>>,
                 decltype(rbegin(AZStd::forward<T>(t)))>
             {
                 return rbegin(AZStd::forward<T>(t));
@@ -276,17 +305,22 @@ namespace AZStd::ranges
         template <class T, class = void>
         constexpr bool has_unqualified_rend = false;
         template <class T>
-        constexpr bool has_unqualified_rend<T, void_t<decltype(rend(declval<T&>()))>>
-            = !has_member_rend<T> && AZStd::Internal::is_class_or_enum<T>;
+        constexpr bool has_unqualified_rend<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_rend<T>>,
+            sfinae_trigger<decltype(rend(declval<T&>()))>,
+            bool_constant<::AZStd::Internal::is_class_or_enum<T>>
+            >>> = true;
 
         template <class T, class = void>
         constexpr bool has_bidirectional_rend = false;
         template <class T>
-        constexpr bool has_bidirectional_rend<T, enable_if_t<
-            same_as<decltype(ranges::begin(declval<T&>())), decltype(ranges::end(declval<T&>()))>
-            && bidirectional_iterator<decltype(ranges::begin(declval<T&>()))>
-            && bidirectional_iterator<decltype(ranges::end(declval<T&>()))>
-            >> = !has_member_rend<T> && !has_unqualified_rend<T>;
+        constexpr bool has_bidirectional_rend<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_rend<T>>,
+            bool_constant<!has_unqualified_rend<T>>,
+            bool_constant<same_as<decltype(ranges::begin(declval<T&>())), decltype(ranges::end(declval<T&>()))>>,
+            bool_constant<bidirectional_iterator<decltype(ranges::begin(declval<T&>()))>>,
+            bool_constant<bidirectional_iterator<decltype(ranges::end(declval<T&>()))>>
+            >>> = true;
 
         template<class T>
         void rend(T&) = delete;
@@ -297,8 +331,10 @@ namespace AZStd::ranges
         {
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).rend())) ->
-                enable_if_t<sentinel_for<decltype(t.rend()), decltype(ranges::rbegin(t))> && is_lvalue_or_borrowable<T>
-                && has_member_rend<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<sentinel_for<decltype(t.rend()), decltype(ranges::rbegin(AZStd::forward<T>(t)))>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<has_member_rend<T>>>,
                 decltype(AZStd::forward<T>(t).rend())>
             {
                 return AZStd::forward<T>(t).rend();
@@ -306,8 +342,10 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(rend(AZStd::forward<T>(t)))) ->
-                enable_if_t<sentinel_for<decltype(rend(t)), decltype(ranges::rbegin(t))> && is_lvalue_or_borrowable<T>
-                && has_unqualified_rend<T>,
+                enable_if_t<conjunction_v<
+                bool_constant<sentinel_for<decltype(rend(t)), decltype(ranges::rbegin(AZStd::forward<T>(t)))>>,
+                bool_constant<is_lvalue_or_borrowable<T>>,
+                bool_constant<has_unqualified_rend<T>>>,
                 decltype(rend(AZStd::forward<T>(t)))>
             {
                 return rend(AZStd::forward<T>(t));
@@ -389,14 +427,20 @@ namespace AZStd::ranges
         template <class T, class = void>
         constexpr bool has_unqualified_size = false;
         template <class T>
-        constexpr bool has_unqualified_size<T, void_t<decltype(size(declval<T&>()))>>
-            = !has_member_size<T> && AZStd::Internal::is_class_or_enum<T>;
+        constexpr bool has_unqualified_size<T, enable_if_t<conjunction_v<
+            sfinae_trigger<decltype(size(declval<T&>()))>,
+            bool_constant<!has_member_size<T>>,
+            bool_constant<::AZStd::Internal::is_class_or_enum<T>>
+            >>> = true;
 
         template <class T, class = void>
         constexpr bool has_end_subtract_begin = false;
         template <class T>
-        constexpr bool has_end_subtract_begin<T, void_t<decltype(ranges::end(declval<T&>()) - ranges::begin(declval<T&>()))>>
-            = !has_member_size<T> && !has_unqualified_size<T>;
+        constexpr bool has_end_subtract_begin<T, enable_if_t<conjunction_v<
+            sfinae_trigger<decltype(ranges::end(declval<T&>()) - ranges::begin(declval<T&>()))>,
+            bool_constant<!has_member_size<T>>,
+            bool_constant<!has_unqualified_size<T>>
+            >>> = true;
 
         template<class T>
         void size(T&) = delete;
@@ -407,7 +451,7 @@ namespace AZStd::ranges
         {
             template<class T>
             constexpr auto operator()(T&) const noexcept ->
-                enable_if_t<is_array_v<T> && extent_v<T> != 0,
+                enable_if_t<conjunction_v<is_array<T>, bool_constant<extent_v<T> != 0>>,
                 decltype(extent_v<T>)>
             {
                 return extent_v<T>;
@@ -415,8 +459,9 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).size())) ->
-                enable_if_t<!disable_sized_range<remove_cv_t<T>> && has_member_size<T>
-                && AZStd::Internal::is_integer_like<decltype(AZStd::forward<T>(t).size())>,
+                enable_if_t<conjunction_v<bool_constant<!disable_sized_range<remove_cv_t<T>>>,
+                bool_constant<has_member_size<T>>,
+                bool_constant<::AZStd::Internal::is_integer_like<decltype(AZStd::forward<T>(t).size())>>>,
                 decltype(AZStd::forward<T>(t).size())>
             {
                 return AZStd::forward<T>(t).size();
@@ -424,9 +469,9 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(size(AZStd::forward<T>(t)))) ->
-                enable_if_t<!disable_sized_range<remove_cv_t<T>>
-                && has_unqualified_size<T>
-                && AZStd::Internal::is_integer_like<decltype(size(AZStd::forward<T>(t)))>,
+                enable_if_t<conjunction_v<bool_constant<!disable_sized_range<remove_cv_t<T>>>,
+                bool_constant<has_unqualified_size<T>>,
+                bool_constant<::AZStd::Internal::is_integer_like<decltype(size(AZStd::forward<T>(t)))>>>,
                 decltype(size(AZStd::forward<T>(t)))>
             {
                 return size(AZStd::forward<T>(t));
@@ -434,10 +479,10 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::end(AZStd::forward<T>(t)) - ranges::begin(AZStd::forward<T>(t)))) ->
-                enable_if_t<
-                has_end_subtract_begin<T>
-                && sized_sentinel_for<decltype(ranges::end(AZStd::forward<T>(t))), decltype(ranges::begin(AZStd::forward<T>(t)))>
-                && forward_iterator<decltype(ranges::begin(AZStd::forward<T>(t)))>,
+                enable_if_t<conjunction_v<
+                bool_constant<has_end_subtract_begin<T>>,
+                bool_constant<sized_sentinel_for<decltype(ranges::end(AZStd::forward<T>(t))), decltype(ranges::begin(AZStd::forward<T>(t)))>>,
+                bool_constant<forward_iterator<decltype(ranges::begin(AZStd::forward<T>(t)))>>>,
                 AZStd::make_unsigned_t<decltype(ranges::end(AZStd::forward<T>(t)) - ranges::begin(AZStd::forward<T>(t)))>>
             {
                 using size_type = AZStd::make_unsigned_t<decltype(ranges::end(AZStd::forward<T>(t)) - ranges::begin(AZStd::forward<T>(t)))>;
@@ -456,17 +501,17 @@ namespace AZStd::ranges
         struct ssize_fn
         {
             template<class T>
-            constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(t))) ->
-                enable_if_t<(sizeof(ptrdiff_t) > sizeof(make_signed_t<decltype(ranges::size(t))>)), ptrdiff_t>
+            constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(AZStd::forward<T>(t)))) ->
+                enable_if_t<(sizeof(ptrdiff_t) > sizeof(make_signed_t<decltype(ranges::size(AZStd::forward<T>(t)))>)), ptrdiff_t>
             {
-                return static_cast<ptrdiff_t>(ranges::size(t));
+                return static_cast<ptrdiff_t>(ranges::size(AZStd::forward<T>(t)));
             }
 
             template<class T>
-            constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(t))) ->
-                enable_if_t<sizeof(ptrdiff_t) <= sizeof(make_signed_t<decltype(ranges::size(t))>), make_signed_t<decltype(ranges::size(t))>>
+            constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(AZStd::forward<T>(t)))) ->
+                enable_if_t<sizeof(ptrdiff_t) <= sizeof(make_signed_t<decltype(ranges::size(AZStd::forward<T>(t)))>), make_signed_t<decltype(ranges::size(t))>>
             {
-                using ssize_type = make_signed_t<decltype(ranges::size(t))>;
+                using ssize_type = make_signed_t<decltype(ranges::size(AZStd::forward<T>(t)))>;
                 return static_cast<ssize_type>(ranges::size(t));
             }
         };
@@ -487,36 +532,41 @@ namespace AZStd::ranges
         template <class T, class = void>
         constexpr bool has_size_compare_to_0 = false;
         template <class T>
-        constexpr bool has_size_compare_to_0<T, enable_if_t<convertible_to<decltype(ranges::size(declval<T&>()) == 0), bool> >>
-            = !has_member_empty<T>;
+        constexpr bool has_size_compare_to_0<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_empty<T>>,
+            bool_constant<convertible_to<decltype(ranges::size(declval<T&>()) == 0), bool>>
+            >>> = true;
 
         template <class T, class = void>
         constexpr bool has_begin_compare_to_end = false;
 
         template <class T>
         constexpr bool has_begin_compare_to_end<T,
-            enable_if_t<convertible_to<decltype(ranges::begin(declval<T&>()) == ranges::end(declval<T&>())), bool> >>
-            = !has_member_empty<T> && !has_size_compare_to_0<T>;
+            enable_if_t<conjunction_v<
+            bool_constant<!has_member_empty<T>>,
+            bool_constant<!has_size_compare_to_0<T>>,
+            bool_constant<convertible_to<decltype(ranges::begin(declval<T&>()) == ranges::end(declval<T&>())), bool>>
+            >>> = true;
 
         struct empty_fn
         {
             template<class T>
             [[nodiscard]] constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).empty())) ->
-                enable_if_t<is_lvalue_or_borrowable<T> && has_member_empty<T>, bool>
+                enable_if_t<conjunction_v<bool_constant<is_lvalue_or_borrowable<T>>, bool_constant<has_member_empty<T>>>, bool>
             {
                 return AZStd::forward<T>(t).empty();
             }
 
             template<class T>
             [[nodiscard]] constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(AZStd::forward<T>(t)) == 0)) ->
-                enable_if_t<is_lvalue_or_borrowable<T> && has_size_compare_to_0<T>, bool>
+                enable_if_t<conjunction_v<bool_constant<is_lvalue_or_borrowable<T>>, bool_constant<has_size_compare_to_0<T>>>, bool>
             {
                 return ranges::size(AZStd::forward<T>(t)) == 0;
             }
 
             template<class T>
             [[nodiscard]] constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::begin(AZStd::forward<T>(t)) == ranges::end(AZStd::forward<T>(t)))) ->
-                enable_if_t<is_lvalue_or_borrowable<T> && has_begin_compare_to_end<T>, bool>
+                enable_if_t<conjunction_v<bool_constant<is_lvalue_or_borrowable<T>>, bool_constant<has_begin_compare_to_end<T>>>, bool>
             {
                 return ranges::begin(AZStd::forward<T>(t)) == ranges::end(AZStd::forward<T>(t));
             }
@@ -538,14 +588,16 @@ namespace AZStd::ranges
         template <class T, class = void>
         constexpr bool has_qualified_ranges_begin = false;
         template <class T>
-        constexpr bool has_qualified_ranges_begin<T, enable_if_t<contiguous_iterator<decltype(ranges::begin(declval<T&>()))>> >
-            = !has_member_data<T>;
+        constexpr bool has_qualified_ranges_begin<T, enable_if_t<conjunction_v<
+            bool_constant<!has_member_data<T>>,
+            bool_constant<contiguous_iterator<decltype(ranges::begin(declval<T&>()))>>
+            >>> = true;
 
         struct data_fn
         {
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward<T>(t).data())) ->
-                enable_if_t<is_lvalue_or_borrowable<T> && has_member_data<T>,
+                enable_if_t<conjunction_v<bool_constant<is_lvalue_or_borrowable<T>>, bool_constant<has_member_data<T>>>,
                 decltype(AZStd::forward<T>(t).data())>
             {
                 return AZStd::forward<T>(t).data();
@@ -553,7 +605,7 @@ namespace AZStd::ranges
 
             template<class T>
             constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::to_address(ranges::begin(AZStd::forward<T>(t))))) ->
-                enable_if_t<is_lvalue_or_borrowable<T> && has_qualified_ranges_begin<T>,
+                enable_if_t<conjunction_v<bool_constant<is_lvalue_or_borrowable<T>>, bool_constant<has_qualified_ranges_begin<T>>>,
                 decltype(AZStd::to_address(ranges::begin(AZStd::forward<T>(t))))>
             {
                 return AZStd::to_address(ranges::begin(AZStd::forward<T>(t)));
@@ -612,8 +664,8 @@ namespace AZStd::ranges
 
     // Models borrowed range concept
     template<class T>
-    /*concept*/ constexpr bool borrowed_range = range<T>
-        && (is_lvalue_reference_v<T> || enable_borrowed_range<remove_cvref_t<T>>);
+    /*concept*/ constexpr bool borrowed_range = conjunction_v<bool_constant<range<T>>,
+        disjunction<is_lvalue_reference<T>, bool_constant<enable_borrowed_range<remove_cvref_t<T>>>>>;
 
     struct dangling
     {
@@ -622,9 +674,23 @@ namespace AZStd::ranges
         constexpr dangling(T&&...) noexcept {}
     };
 
+
+    enum class subrange_kind : bool
+    {
+        unsized,
+        sized
+    };
+    template<class I, class S = I,
+        subrange_kind K = sized_sentinel_for<S, I> ? subrange_kind::sized : subrange_kind::unsized,
+        class = void>
+        class subrange;
+
     template<class R>
     using borrowed_iterator_t = conditional_t<borrowed_range<R>, iterator_t<R>, dangling>;
 
+    template<class R>
+    using borrowed_subrange_t = conditional_t<borrowed_range<R>, subrange<iterator_t<R>>, dangling>;
+
     // Models sized range concept
     namespace Internal
     {
@@ -643,7 +709,11 @@ namespace AZStd::ranges
         template<class R, class T, class = void>
         constexpr bool output_range_impl = false;
         template<class R, class T>
-        constexpr bool output_range_impl<R, T, enable_if_t<has_iterator_t<R>>> = range<R> && output_iterator<iterator_t<R>, T>;
+        constexpr bool output_range_impl<R, T, enable_if_t<conjunction_v<
+            bool_constant<has_iterator_t<R>>,
+            bool_constant<range<R>>,
+            bool_constant<output_iterator<iterator_t<R>, T>>
+            >>> = true;
     }
 
     template<class R, class T>
@@ -654,7 +724,11 @@ namespace AZStd::ranges
         template<class T, class = void>
         constexpr bool input_range_impl = false;
         template<class T>
-        constexpr bool input_range_impl<T, enable_if_t<has_iterator_t<T>>> = range<T> && input_iterator<iterator_t<T>>;
+        constexpr bool input_range_impl<T, enable_if_t<conjunction_v<
+            bool_constant<has_iterator_t<T>>,
+            bool_constant<range<T>>,
+            bool_constant<input_iterator<iterator_t<T>>>
+            >>> = true;
     }
 
     template<class T>
@@ -665,7 +739,11 @@ namespace AZStd::ranges
         template<class T, class = void>
         constexpr bool forward_range_impl = false;
         template<class T>
-        constexpr bool forward_range_impl<T, enable_if_t<has_iterator_t<T>>> = input_range<T> && forward_iterator<iterator_t<T>>;
+        constexpr bool forward_range_impl<T, enable_if_t<conjunction_v<
+            bool_constant<has_iterator_t<T>>,
+            bool_constant<input_range<T>>,
+            bool_constant<forward_iterator<iterator_t<T>>>
+            >>> = true;
     }
 
     template<class T>
@@ -676,7 +754,11 @@ namespace AZStd::ranges
         template<class T, class = void>
         constexpr bool bidirectional_range_impl = false;
         template<class T>
-        constexpr bool bidirectional_range_impl<T, enable_if_t<has_iterator_t<T>>> = forward_range<T> && bidirectional_iterator<iterator_t<T>>;
+        constexpr bool bidirectional_range_impl<T, enable_if_t<conjunction_v<
+            bool_constant<has_iterator_t<T>>,
+            bool_constant<forward_range<T>>,
+            bool_constant<bidirectional_iterator<iterator_t<T>>>
+            >>> = true;
     }
 
     template<class T>
@@ -687,7 +769,11 @@ namespace AZStd::ranges
         template<class T, class = void>
         constexpr bool random_access_range_impl = false;
         template<class T>
-        constexpr bool random_access_range_impl<T, enable_if_t<has_iterator_t<T>>> = bidirectional_range<T> && random_access_iterator<iterator_t<T>>;
+        constexpr bool random_access_range_impl<T, enable_if_t<conjunction_v<
+            bool_constant<has_iterator_t<T>>,
+            bool_constant<bidirectional_range<T>>,
+            bool_constant<random_access_iterator<iterator_t<T>>>
+            >>> = true;
     }
 
     template<class T>
@@ -710,16 +796,19 @@ namespace AZStd::ranges
         template<class T, class = void>
         constexpr bool contiguous_range_impl = false;
         template<class T>
-        constexpr bool contiguous_range_impl<T, enable_if_t<random_access_range<T>
-            && contiguous_iterator<iterator_t<T>>
-            && same_as<decltype(ranges::data(declval<T&>())), add_pointer_t<range_reference_t<T>>> >> = true;
+        constexpr bool contiguous_range_impl<T, enable_if_t<conjunction_v<
+            bool_constant<random_access_range<T>>,
+            bool_constant<contiguous_iterator<iterator_t<T>>>,
+            bool_constant<same_as<decltype(ranges::data(declval<T&>())), add_pointer_t<range_reference_t<T>>>>
+            >>> = true;
     }
 
     template<class T>
     /*concept*/ constexpr bool contiguous_range = Internal::contiguous_range_impl<T>;
 
     template<class T>
-    /*concept*/ constexpr bool common_range = range<T> && same_as<iterator_t<T>, sentinel_t<T>>;
+    /*concept*/ constexpr bool common_range = conjunction_v<bool_constant<range<T>>,
+        bool_constant<same_as<iterator_t<T>, sentinel_t<T>>>>;
 }
 
 namespace AZStd::ranges
@@ -752,7 +841,7 @@ namespace AZStd::ranges
 
             template<class I, class S>
             constexpr auto operator()(I& i, S bound) const ->
-                enable_if_t<input_or_output_iterator<I>&& sentinel_for<S, I>>
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>, bool_constant<sentinel_for<S, I>>>>
             {
                 if constexpr (assignable_from<I&, S>)
                 {
@@ -770,7 +859,8 @@ namespace AZStd::ranges
 
             template<class I, class S>
             constexpr auto operator()(I& i, iter_difference_t<I> n, S bound) const ->
-                enable_if_t<input_or_output_iterator<I>&& sentinel_for<S, I>, iter_difference_t<I>>
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>, bool_constant<sentinel_for<S, I>>>,
+                iter_difference_t<I>>
             {
                 if constexpr (sized_sentinel_for<S, I>)
                 {
@@ -816,7 +906,9 @@ namespace AZStd::ranges
         {
             template<class I, class S>
             constexpr auto operator()(I first, S last) const ->
-                enable_if_t<input_or_output_iterator<I> && sentinel_for<S, I> && !sized_sentinel_for<S, I>,
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<!sized_sentinel_for<S, I>>>,
                 iter_difference_t<I>>
             {
                 // Since S is not a sized sentinel, can only increment from first to last
@@ -828,7 +920,9 @@ namespace AZStd::ranges
 
             template<class I, class S>
             constexpr auto operator()(const I& first, const S& last) const ->
-                enable_if_t<input_or_output_iterator<I> && sentinel_for<S, I> && sized_sentinel_for<S, I>,
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<sized_sentinel_for<S, I>>>,
                 iter_difference_t<I>>
             {
                 return last - first;
@@ -878,7 +972,7 @@ namespace AZStd::ranges
 
             template<class I, class S>
             constexpr auto operator()(I x, S bound) const ->
-                enable_if_t<input_or_output_iterator<I>&& sentinel_for<S, I>, I>
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>, bool_constant<sentinel_for<S, I>>>, I>
             {
                 ranges::advance(x, bound);
                 return x;
@@ -886,7 +980,7 @@ namespace AZStd::ranges
 
             template<class I, class S>
             constexpr auto operator()(I x, iter_difference_t<I> n, S bound) const ->
-                enable_if_t<input_or_output_iterator<I>&& sentinel_for<S, I>, I>
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>, bool_constant<sentinel_for<S, I>>>, I>
             {
                 ranges::advance(x, n, bound);
                 return x;
@@ -922,7 +1016,7 @@ namespace AZStd::ranges
 
             template<class I, class S>
             constexpr auto operator()(I x, iter_difference_t<I> n, S bound) const ->
-                enable_if_t<input_or_output_iterator<I>&& sentinel_for<S, I>, I>
+                enable_if_t<conjunction_v<bool_constant<input_or_output_iterator<I>>, bool_constant<sentinel_for<S, I>>>, I>
             {
                 ranges::advance(x, -n, bound);
                 return x;
@@ -950,16 +1044,51 @@ namespace AZStd::ranges
     // view interface can be used with non-constant class types
     template<class D, class = void>
     class view_interface;
+
+    struct view_base {};
+    namespace Internal
+    {
+        template<class D>
+        void derived_from_view_interface_template(view_interface<D>&);
+        template<class T, class = void>
+        inline constexpr bool is_derived_from_view_interface = false;
+        template<class T>
+        inline constexpr bool is_derived_from_view_interface<T,
+            decltype(derived_from_view_interface_template(declval<remove_cvref_t<T>&>()))> = true;
+    }
+    template<class T>
+    inline constexpr bool enable_view = derived_from<T, view_base> || Internal::is_derived_from_view_interface<T>;
+
+    template<class T>
+    /*concept*/ constexpr bool view = conjunction_v<bool_constant<range<T>>, bool_constant<movable<T>>, bool_constant<enable_view<T>>>;
+
+    template<class T>
+    /*concept*/ constexpr bool viewable_range = conjunction_v<bool_constant<range<T>>,
+        disjunction<
+            conjunction<bool_constant<view<remove_cvref_t<T>>>, bool_constant<constructible_from<remove_cvref_t<T>, T>>>,
+            conjunction<bool_constant<!view<remove_cvref_t<T>>>,
+                disjunction<is_lvalue_reference<T>,
+                    conjunction<bool_constant<movable<remove_reference_t<T>>>,
+                    bool_constant<!Internal::is_initializer_list<T>>
+                    >
+                >
+            >
+        >
+    >;
+
     template<class D>
-    class view_interface< D, enable_if_t<is_class_v<D> && same_as<D, remove_cv_t<D>> >>
+    class view_interface<D, enable_if_t<is_class_v<D> && same_as<D, remove_cv_t<D>> >>
     {
     private:
         constexpr D& derived() noexcept
         {
+            // Make sure that the derived type is complete
+            static_assert(sizeof(D) > 0 && derived_from<D, view_interface> && view<D>);
             return static_cast<D&>(*this);
         }
         constexpr const D& derived() const noexcept
         {
+            static_assert(sizeof(D) > 0 && derived_from<D, view_interface> && view<D>);
             return static_cast<const D&>(*this);
         }
 
@@ -975,134 +1104,141 @@ namespace AZStd::ranges
             return ranges::begin(derived()) == ranges::end(derived());
         }
 
-        template <class Derived = D, class = void_t<decltype(ranges::empty(declval<Derived>()))>>
-        constexpr explicit operator bool() const noexcept(noexcept(ranges::empty(derived())))
+        template <class Derived = D>
+        constexpr explicit operator bool() const noexcept(noexcept(ranges::empty(static_cast<const Derived&>(*this))))
         {
             return !ranges::empty(derived());
         }
 
         template <class Derived = D>
         constexpr auto data() ->
-            enable_if_t<contiguous_iterator<iterator_t<Derived>>, decltype(to_address(ranges::begin(derived())))>
+            enable_if_t<contiguous_iterator<iterator_t<Derived>>, decltype(to_address(ranges::begin(static_cast<Derived&>(*this))))>
         {
             return to_address(ranges::begin(derived()));
         }
         template <class Derived = D>
         constexpr auto data() const ->
-            enable_if_t<contiguous_iterator<iterator_t<const Derived>>, decltype(to_address(ranges::begin(derived())))>
+            enable_if_t<range<const Derived> && contiguous_iterator<iterator_t<const Derived>>,
+            decltype(to_address(ranges::begin(static_cast<const Derived&>(*this))))>
         {
             return to_address(ranges::begin(derived()));
         }
 
         template <class Derived = D>
         constexpr auto size() ->
-            enable_if_t<forward_range<Derived> && sized_sentinel_for<sentinel_t<Derived>, iterator_t<Derived>>,
-            decltype(ranges::end(derived()) - ranges::begin(derived()))>
+            enable_if_t<conjunction_v<bool_constant<forward_range<Derived>>,
+            bool_constant<sized_sentinel_for<sentinel_t<Derived>, iterator_t<Derived>>>>,
+            decltype(ranges::end(static_cast<Derived&>(*this)) - ranges::begin(static_cast<Derived&>(*this)))>
         {
             return ranges::end(derived()) - ranges::begin(derived());
         }
         template <class Derived = D>
         constexpr auto size() const ->
-            enable_if_t<forward_range<const Derived>&& sized_sentinel_for<sentinel_t<const Derived>, iterator_t<const Derived>>,
-            decltype(ranges::end(derived()) - ranges::begin(derived()))>
+            enable_if_t<conjunction_v<bool_constant<forward_range<const Derived>>,
+            bool_constant<sized_sentinel_for<sentinel_t<const Derived>, iterator_t<const Derived>>>>,
+            decltype(ranges::end(static_cast<const Derived&>(*this)) - ranges::begin(static_cast<const Derived&>(*this)))>
         {
             return ranges::end(derived()) - ranges::begin(derived());
         }
 
         template <class Derived = D>
         constexpr auto front() ->
-            enable_if_t<forward_range<Derived>, decltype(*ranges::begin(derived()))>
+            enable_if_t<forward_range<Derived>, decltype(*ranges::begin(static_cast<Derived&>(*this)))>
         {
             return *ranges::begin(derived());
         }
         template <class Derived = D>
         constexpr auto front() const ->
-            enable_if_t<forward_range<const Derived>, decltype(*ranges::begin(derived()))>
+            enable_if_t<forward_range<const Derived>, decltype(*ranges::begin(static_cast<const Derived&>(*this)))>
         {
             return *ranges::begin(derived());
         }
 
         template <class Derived = D>
         constexpr auto back() ->
-            enable_if_t<bidirectional_range<Derived> && common_range<Derived>, decltype(*ranges::prev(ranges::end(derived())))>
+            enable_if_t<conjunction_v<bool_constant<bidirectional_range<Derived>>,
+            bool_constant<common_range<Derived>>>,
+            decltype(*ranges::prev(ranges::end(static_cast<Derived&>(*this))))>
         {
             return *ranges::prev(ranges::end(derived()));
         }
 
         template <class Derived = D>
         constexpr auto back() const ->
-            enable_if_t<bidirectional_range<const Derived>&& common_range<const Derived>, decltype(*ranges::prev(ranges::end(derived())))>
+            enable_if_t<conjunction_v<bool_constant<bidirectional_range<const Derived>>,
+            bool_constant<common_range<const Derived>>>,
+            decltype(*ranges::prev(ranges::end(static_cast<const Derived&>(*this))))>
         {
             return *ranges::prev(ranges::end(derived()));
         }
 
         template<class R = D>
         constexpr auto operator[](range_difference_t<R> n) ->
-            enable_if_t<random_access_range<R>, decltype(ranges::begin(derived())[n])>
+            enable_if_t<random_access_range<R>, decltype(ranges::begin(static_cast<R&>(*this))[n])>
         {
             return ranges::begin(derived())[n];
         }
         template<class R = const D>
         constexpr auto operator[](range_difference_t<R> n) const ->
-            enable_if_t<random_access_range<R>, decltype(ranges::begin(derived())[n])>
+            enable_if_t<random_access_range<R>, decltype(ranges::begin(static_cast<R&>(*this))[n])>
         {
             return ranges::begin(derived())[n];
         }
     };
 
-    struct view_base {};
+    // Helper Concepts - https://eel.is/c++draft/ranges#range.utility.helpers
     namespace Internal
     {
-        template<class D>
-        void derived_from_view_interface_template(view_interface<D>&);
-        template<class T, class = void>
-        inline constexpr bool is_derived_from_view_interface = false;
-        template<class T>
-        inline constexpr bool is_derived_from_view_interface<T,
-            decltype(derived_from_view_interface_template(declval<T&>()))> = true;
+        // Helper concepts that are used by range adaptor classes
+        template<bool Const, class T>
+        using maybe_const = conditional_t<Const, const T, T>;
+
+        template<class R, class = void>
+        /*concept*/ constexpr bool simple_view = false;
+        template<class R>
+        /*concept*/ inline constexpr bool simple_view<R, enable_if_t<conjunction_v<
+            bool_constant<view<R>>,
+            bool_constant<range<const R>>,
+            bool_constant<same_as<iterator_t<R>, iterator_t<const R>>>,
+            bool_constant<same_as<sentinel_t<R>, sentinel_t<const R>>> >>> = true;
+
+        template<class I, class = void>
+        /*concept*/ constexpr bool has_arrow = false;
+        template<class I>
+        /*concept*/ inline constexpr bool has_arrow<I, enable_if_t<conjunction_v<
+            bool_constant<input_iterator<I>>,
+            disjunction<is_pointer<I>, sfinae_trigger<decltype(declval<I>().operator->())>>
+            >>> = true;
+
+        template<class T, class U>
+        /*concept*/ constexpr bool different_from = !same_as<remove_cvref_t<T>, remove_cvref_t<U>>;
     }
-    template<class T>
-    inline constexpr bool enable_view = derived_from<T, view_base> || Internal::is_derived_from_view_interface<T>;
-
-    template<class T>
-    /*concept*/ constexpr bool view = range<T> && movable<T> && enable_view<T>;
-
-    template<class T>
-    /*concept*/ constexpr bool viewable_range = range<T> &&
-        ((view<remove_cvref_t<T>> && constructible_from<remove_cvref_t<T>, T>) ||
-            (!view<remove_cvref_t<T>> &&
-                (is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !Internal::is_initializer_list<T>))));
 }
 
 
 namespace AZStd::ranges
 {
-#if __has_cpp_attribute(no_unique_address)
-#define az_no_unique_address [[no_unique_address]]
-#else
-#define az_no_unique_address
-#endif
     template<class I1, class I2>
     struct in_in_result
     {
-        az_no_unique_address I1 in1;
-        az_no_unique_address I2 in2;
+        AZ_NO_UNIQUE_ADDRESS I1 in1;
+        AZ_NO_UNIQUE_ADDRESS I2 in2;
 
-        template<class II1, class II2, class = enable_if_t<convertible_to<const I1&, II1>&& convertible_to<const I2&, II2>> >
+        template<class II1, class II2, class = enable_if_t<conjunction_v<
+            bool_constant<convertible_to<const I1&, II1>>, bool_constant<convertible_to<const I2&, II2>>>> >
         constexpr operator in_in_result<II1, II2>() const&
         {
             return { in1, in2 };
         }
 
-        template<class II1, class II2, class = enable_if_t<convertible_to<I1, II1>&& convertible_to<I2, II2>> >
+        template<class II1, class II2, class = enable_if_t<conjunction_v<
+            bool_constant<convertible_to<I1, II1>>, bool_constant<convertible_to<I2, II2>>>> >
         constexpr operator in_in_result<II1, II2>()&&
         {
             return { AZStd::move(in1), AZStd::move(in2) };
         }
     };
 
-#undef az_no_unique_address
-
     template<class I1, class I2>
     using swap_ranges_result = in_in_result<I1, I2>;
 
@@ -1112,9 +1248,11 @@ namespace AZStd::ranges
         {
             template<class I1, class S1, class I2, class S2>
             constexpr auto operator()(I1 first1, S1 last1, I2 first2, S2 last2) const ->
-                enable_if_t<input_iterator<I1>&& sentinel_for<S1, I1>
-                && input_iterator<I2>&& sentinel_for<S2, I2>
-                && indirectly_swappable<I1, I2>,
+                enable_if_t<conjunction_v<bool_constant<input_iterator<I1>>,
+                bool_constant<sentinel_for<S1, I1>>,
+                bool_constant<input_iterator<I2>>,
+                bool_constant<sentinel_for<S2, I2>>,
+                bool_constant<indirectly_swappable<I1, I2>>>,
                 swap_ranges_result<I1, I2>>
             {
                 for (; !(first1 == last1 or first2 == last2); ++first1, ++first2)
@@ -1126,8 +1264,10 @@ namespace AZStd::ranges
 
             template<class R1, class R2>
             constexpr auto operator()(R1&& r1, R2&& r2) const ->
-                enable_if_t<input_range<R1>&& input_range<R2>
-                && indirectly_swappable<iterator_t<R1>, iterator_t<R2>>,
+                enable_if_t<conjunction_v<
+                bool_constant<input_range<R1>>,
+                bool_constant<input_range<R2>>,
+                bool_constant<indirectly_swappable<iterator_t<R1>, iterator_t<R2>>>>,
                 swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>>
             {
                 return operator()(ranges::begin(r1), ranges::end(r1),
@@ -1148,10 +1288,21 @@ namespace AZStd::ranges::Internal
     // ranges::swap customization point https://eel.is/c++draft/concepts#concept.swappable-2.2
     template <class T, class U>
     constexpr auto swap_fn::operator()(T&& t, U&& u) const noexcept(noexcept((*this)(*t, *u)))
-        ->enable_if_t<!is_class_or_enum_with_swap_adl<T, U>
-        && is_array_v<T> && is_array_v<U> && (extent_v<T> == extent_v<U>)
-        >
+        ->enable_if_t<conjunction_v<
+        bool_constant<!is_class_or_enum_with_swap_adl<T, U>>,
+        is_array<T>,
+        is_array<U>,
+        bool_constant<extent_v<T> == extent_v<U>>
+        >>
     {
         ranges::swap_ranges(t, u);
     }
 }
+
+// Opening AZStd::ranges::views namespace to provide access to it in AZStd
+namespace AZStd::ranges::views{}
+
+namespace AZStd
+{
+      namespace views = ranges::views;
+}

+ 333 - 0
Code/Framework/AzCore/AzCore/std/ranges/ranges_adaptor.h

@@ -0,0 +1,333 @@
+/*
+ * 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/ranges/ranges.h>
+#include <AzCore/std/optional.h>
+
+namespace AZStd::ranges::views::Internal
+{
+    // Call wrapping that performs perfecting forwarding of arguments
+    // and take const and ref function qualifiers into account(rvalue functions will move)
+    template<class Outer, class Inner>
+    struct perfect_forwarding_call_wrapper
+    {
+        perfect_forwarding_call_wrapper(Outer&& outer, Inner&& inner)
+            : m_outer{ AZStd::forward<Outer>(outer) }
+            , m_inner{ AZStd::forward<Inner>(inner) }
+        {}
+        template<class... Args>
+        constexpr decltype(auto) operator()(Args&&... args) &
+            noexcept(noexcept(AZStd::invoke(m_outer, AZStd::invoke(m_inner, AZStd::forward<Args>(args)...))))
+        {
+            return AZStd::invoke(m_outer, AZStd::invoke(m_inner, AZStd::forward<Args>(args)...));
+        }
+        template<class... Args>
+        constexpr decltype(auto) operator()(Args&&... args) const&
+            noexcept(noexcept(AZStd::invoke(m_outer, AZStd::invoke(m_inner, AZStd::forward<Args>(args)...))))
+        {
+            return AZStd::invoke(m_outer, AZStd::invoke(m_inner, AZStd::forward<Args>(args)...));
+        }
+        //
+        template<class... Args>
+        constexpr decltype(auto) operator()(Args&&... args) &&
+            noexcept(noexcept(AZStd::invoke(AZStd::move(m_outer),
+                AZStd::invoke(AZStd::move(m_inner), AZStd::forward<Args>(args)...))))
+        {
+            return AZStd::invoke(AZStd::move(m_outer), AZStd::invoke(AZStd::move(m_inner), AZStd::forward<Args>(args)...));
+        }
+        template<class... Args>
+        constexpr decltype(auto) operator()(Args&&... args) const&&
+            noexcept(noexcept(AZStd::invoke(AZStd::move(m_outer),
+                AZStd::invoke(AZStd::move(m_inner), AZStd::forward<Args>(args)...))))
+        {
+            return AZStd::invoke(AZStd::move(m_outer), AZStd::invoke(AZStd::move(m_inner), AZStd::forward<Args>(args)...));
+        }
+    private:
+        Outer m_outer;
+        Inner m_inner;
+    };
+
+    // base class which provides the bitwise OR operator to
+    // any derived classes
+    // This can be used by inherited by range adaptor classes
+    // to implement their to allow for changing
+    // https://eel.is/c++draft/ranges#range.adaptor.object-1.3
+    template<class RangeAdaptor>
+    struct range_adaptor_closure;
+
+    // Return a closure new in which the outer range adaptor invokes the inner range adaptor
+    template<class RangeAdaptorFunctor>
+    struct range_adaptor_closure_forwarder
+        : RangeAdaptorFunctor
+        , range_adaptor_closure_forwarder<range_adaptor_closure<RangeAdaptorFunctor>>
+    {
+        constexpr explicit range_adaptor_closure_forwarder(RangeAdaptorFunctor&& closure)
+            : RangeAdaptorFunctor{ AZStd::forward<RangeAdaptorFunctor>(closure) }
+        {}
+    };
+
+    template<class RangeAdaptor>
+    using is_range_closure_t = bool_constant<derived_from<remove_cvref_t<RangeAdaptor>,
+        range_adaptor_closure<remove_cvref_t<RangeAdaptor>>>>;
+
+    template<class T>
+    struct range_adaptor_closure
+    {
+        template<class View, class U>
+        friend constexpr auto operator|(View&& view, U&& closure) noexcept(is_nothrow_invocable_v<View, U>)
+            -> enable_if_t<conjunction_v<
+            bool_constant<viewable_range<View>>,
+            is_range_closure_t<U>,
+            bool_constant<same_as<T, remove_cvref_t<U>>>,
+            bool_constant<invocable<U, View>>>,
+            decltype(AZStd::invoke(AZStd::forward<U>(closure), AZStd::forward<View>(view)))>
+        {
+            return AZStd::invoke(AZStd::forward<U>(closure), AZStd::forward<View>(view));
+        }
+
+        template<class U, class Target>
+        friend constexpr auto operator|(U&& closure, Target&& outerClosure)
+            noexcept(is_nothrow_constructible_v<remove_cvref_t<U>> && is_nothrow_constructible_v<remove_cvref_t<Target>>)
+            ->enable_if_t<conjunction_v<
+            is_range_closure_t<U>,
+            is_range_closure_t<Target>,
+            bool_constant<same_as<T, remove_cvref_t<U>>>,
+            bool_constant<constructible_from<decay_t<U>, U>>,
+            bool_constant<constructible_from<decay_t<Target>, Target>>>,
+            decltype(range_adaptor_closure_forwarder{
+                perfect_forwarding_call_wrapper{AZStd::forward<Target>(outerClosure), AZStd::forward<U>(closure) }
+                })>
+        {
+            // Create a perfect_forwarding_wrapper that wraps the outer adaptor around the inner adaptor
+            // and then pass that to the range_adaptor_closure_forward struct which inherits from
+            // range_adaptor_closure class template so that it is_range_closure_t template succeeds
+            return range_adaptor_closure_forwarder{
+                perfect_forwarding_call_wrapper{AZStd::forward<Target>(outerClosure), AZStd::forward<U>(closure) }
+            };
+        }
+    };
+} // namespace AZStd::ranges::views::Internal
+
+namespace AZStd::ranges::Internal
+{
+    // Copyable Wrapper - https://eel.is/c++draft/ranges#range.copy.wrap
+    // Used to wrap a class that copy constructible, but not necessarily copy assignable
+    // and implements a copy assignment operator using the optional emplace function
+    // to construct in place
+    template<class T, class = void>
+    class copyable_box;
+
+    template<class T>
+    class copyable_box<T, enable_if_t<is_copy_constructible_v<T>&& is_object_v<T>>>
+    {
+    public:
+        template<class U = T, class = enable_if_t<default_initializable<U>>>
+        constexpr copyable_box() noexcept(is_nothrow_constructible_v<T>)
+            : copyable_box{ in_place }
+        {}
+
+        template<class... Args>
+        explicit constexpr copyable_box(in_place_t, Args&&... args) noexcept(is_nothrow_constructible_v<T>)
+            : m_copyable_wrapper{ in_place, AZStd::forward<Args>(args)... }
+        {}
+
+        constexpr copyable_box(const copyable_box&) = default;
+        constexpr copyable_box(copyable_box&&) = default;
+
+        constexpr copyable_box& operator=(const copyable_box& other) noexcept(is_nothrow_copy_constructible_v<T>)
+        {
+            if (this != &other)
+            {
+                if constexpr (copyable<T>)
+                {
+                    m_copyable_wrapper = other.m_copyable_wrapper;
+                }
+                else
+                {
+                    if (other)
+                    {
+                        emplace(other.m_copyable_wrapper);
+                    }
+                    else
+                    {
+                        reset();
+                    }
+                }
+            }
+
+            return *this;
+        }
+
+        constexpr copyable_box& operator=(copyable_box&& other) noexcept(is_nothrow_move_constructible_v<T>)
+        {
+            if (this != &other)
+            {
+                if constexpr (movable<T>)
+                {
+                    m_copyable_wrapper = AZStd::move(other.m_copyable_wrapper);
+                }
+                else
+                {
+                    if (other)
+                    {
+                        emplace(AZStd::move(other.m_copyable_wrapper));
+                    }
+                    else
+                    {
+                        reset();
+                    }
+                }
+            }
+
+            return *this;
+        }
+        constexpr T& operator*() & noexcept
+        {
+            return *m_copyable_wrapper;
+        }
+        constexpr const T& operator*() const& noexcept
+        {
+            return *m_copyable_wrapper;
+        }
+        constexpr T&& operator*() && noexcept
+        {
+            return AZStd::move(*m_copyable_wrapper);
+        }
+        constexpr const T&& operator*() const&& noexcept
+        {
+            return AZStd::move(*m_copyable_wrapper);
+        }
+
+        constexpr T* operator->() noexcept
+        {
+            return m_copyable_wrapper.operator->();
+        }
+        constexpr const T* operator->() const noexcept
+        {
+            return m_copyable_wrapper.operator->();
+        }
+
+        constexpr explicit operator bool()
+        {
+            return m_copyable_wrapper.has_value();
+        }
+
+        template<class... Args>
+        constexpr T& emplace(Args&&... args)
+        {
+            return m_copyable_wrapper.emplace(AZStd::forward<Args>(args)...);
+        }
+
+        constexpr void reset() noexcept
+        {
+            m_copyable_wrapper.reset();
+        }
+    private:
+        optional<T> m_copyable_wrapper;
+    };
+
+    // Non-propagating cache - https://eel.is/c++draft/ranges#range.nonprop.cache
+    // Enables an input view to temporarily cache values over as it is iterated over.
+    // For copy construction, a current instance is default initialized
+    // For move construction, the input object is reset
+    // On copy assignment, the current instance is reset
+    // Onmove assignment, both the current and input are reset
+
+    template<class T, class = void>
+    class non_propagating_cache;
+
+    template<class T>
+    class non_propagating_cache<T, enable_if_t<is_object_v<T>>>
+    {
+    public:
+        template<class U = T, class = enable_if_t<default_initializable<U>>>
+        constexpr non_propagating_cache() noexcept(is_nothrow_constructible_v<T>)
+            : non_propagating_cache{ in_place }
+        {}
+
+        template<class... Args>
+        explicit constexpr non_propagating_cache(in_place_t, Args&&... args) noexcept
+            : m_cache{ in_place, AZStd::forward<Args>(args)... }
+        {}
+
+        // Purposely does not initialize the wrapper
+        constexpr non_propagating_cache(const non_propagating_cache&)
+        {}
+        constexpr non_propagating_cache(non_propagating_cache&& other)
+        {
+            other.reset();
+        }
+
+        constexpr auto operator=(const non_propagating_cache& other) noexcept
+        {
+            if (this != &other)
+            {
+                reset();
+            }
+
+            return *this;
+        }
+
+        constexpr auto operator=(non_propagating_cache&& other) noexcept
+        {
+            reset();
+            other.reset();
+            return *this;
+        }
+
+        constexpr T& operator*() & noexcept
+        {
+            return *m_cache;
+        }
+        constexpr const T& operator*() const& noexcept
+        {
+            return *m_cache;
+        }
+        constexpr T&& operator*() && noexcept
+        {
+            return AZStd::move(*m_cache);
+        }
+        constexpr const T&& operator*() const&& noexcept
+        {
+            return AZStd::move(*m_cache);
+        }
+
+        constexpr T* operator->() noexcept
+        {
+            return m_cache.operator->();
+        }
+        constexpr const T* operator->() const noexcept
+        {
+            return m_cache.operator->();
+        }
+
+        constexpr explicit operator bool()
+        {
+            return m_cache.has_value();
+        }
+
+        template<class... Args>
+        constexpr T& emplace(Args&&... args)
+        {
+            return m_cache.emplace(AZStd::forward<Args>(args)...);
+        }
+        template<class I>
+        constexpr auto emplace_deref(const I& i) -> enable_if_t<constructible_from<T, decltype(*i)>, T&>
+        {
+            return m_cache.emplace(*i);
+        }
+
+        constexpr void reset() noexcept
+        {
+            m_cache.reset();
+        }
+    private:
+        optional<T> m_cache;
+    };
+}  // namespace AZStd::ranges::Internal

+ 996 - 0
Code/Framework/AzCore/AzCore/std/ranges/ranges_algorithm.h

@@ -0,0 +1,996 @@
+/*
+ * 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/function/identity.h>
+#include <AzCore/std/ranges/ranges.h>
+#include <AzCore/std/ranges/ranges_functional.h>
+#include <AzCore/std/ranges/subrange.h>
+
+namespace AZStd::ranges
+{
+    template<class T>
+    struct min_max_result
+    {
+        AZ_NO_UNIQUE_ADDRESS T min;
+        AZ_NO_UNIQUE_ADDRESS T max;
+
+        template<class T2, class = enable_if_t<convertible_to<const T&, T2>>>
+        constexpr operator min_max_result<T2>() const&
+        {
+            return { min, max };
+        }
+
+        template<class T2, class = enable_if_t<convertible_to<T, T2>>>
+        constexpr operator min_max_result<T2>()&&
+        {
+            return { std::move(min), std::move(max) };
+        }
+    };
+    template<class T>
+    using minmax_result = min_max_result<T>;
+
+    template<class I>
+    using minmax_element_result = min_max_result<I>;
+
+    namespace Internal
+    {
+        struct min_fn
+        {
+            template<class T, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
+                -> enable_if_t<indirect_strict_weak_order<Comp, projected<const T*, Proj>>, const T&>
+            {
+                return AZStd::invoke(comp, AZStd::invoke(proj, b), AZStd::invoke(proj, a)) ? b : a;
+            }
+
+            template<class T, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<copyable<T>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<const T*, Proj>>>>, T>
+            {
+                AZ_Assert(r.size() > 0, "ranges::min cannot be invoked with an empty initializer_list");
+                auto it = r.begin();
+                auto last = r.end();
+                T result{ *it };
+                for (; it != last; ++it)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, *it), AZStd::invoke(proj, result)))
+                    {
+                        result = *it;
+                    }
+                }
+                return result;
+            }
+
+            template<class R, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(R&& r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<input_range<R>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<iterator_t<R>, Proj>>>,
+                bool_constant<indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>>>, range_value_t<R>>
+            {
+                AZ_Assert(ranges::distance(r) > 0, "ranges::min cannot be invoked with an empty range");
+                auto it = ranges::begin(r);
+                auto last = ranges::end(r);
+                range_value_t<R> result{ *it };
+                for (; it != last; ++it)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, *it), AZStd::invoke(proj, result)))
+                    {
+                        result = *it;
+                    }
+                }
+                return result;
+            }
+        };
+    } // namespace Internal
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::min_fn min{};
+    }
+
+    namespace Internal
+    {
+        struct max_fn
+        {
+            template<class T, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
+                -> enable_if_t<indirect_strict_weak_order<Comp, projected<const T*, Proj>>, const T&>
+            {
+                return AZStd::invoke(comp, AZStd::invoke(proj, a), AZStd::invoke(proj, b)) ? b : a;
+            }
+
+            template<class T, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<copyable<T>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<const T*, Proj>>>>, T>
+            {
+                AZ_Assert(r.size() > 0, "ranges::max cannot be invoked with an empty initializer_list");
+                auto it = r.begin();
+                auto last = r.end();
+                T result{ *it };
+                for (; it != last; ++it)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, result), AZStd::invoke(proj, *it)))
+                    {
+                        result = *it;
+                    }
+                }
+                return result;
+            }
+
+            template<class R, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(R&& r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<input_range<R>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<iterator_t<R>, Proj>>>,
+                bool_constant<indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>>>, range_value_t<R>>
+            {
+                AZ_Assert(ranges::distance(r) > 0, "ranges::max cannot be invoked with an empty range");
+                auto it = ranges::begin(r);
+                auto last = ranges::end(r);
+                range_value_t<R> result{ *it };
+                for (; it != last; ++it)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, result), AZStd::invoke(proj, *it)))
+                    {
+                        result = *it;
+                    }
+                }
+                return result;
+            }
+        };
+    } // namespace Internal
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::max_fn max{};
+    }
+
+
+    namespace Internal
+    {
+        struct minmax_fn
+        {
+            template<class T, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
+                -> enable_if_t<indirect_strict_weak_order<Comp, projected<const T*, Proj>>, minmax_result<const T&>>
+            {
+                return AZStd::invoke(comp, AZStd::invoke(proj, b), AZStd::invoke(proj, a)) ?
+                    minmax_result<const T&>{b, a} : minmax_result<const T&>{a, b};
+            }
+
+            template<class T, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<copyable<T>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<const T*, Proj>>>>,
+                minmax_result<T>>
+            {
+                AZ_Assert(r.size() > 0, "ranges::minmax cannot be invoked with an empty initializer_list");
+                auto first = r.begin();
+                minmax_result<T> result{ *first, *first };
+                auto last = r.end();
+                for (; first != last; ++first)
+                {
+                    // Algorithm requires at most (3/2 * ranges::distance(r)) comparisons
+                    if (auto prevIt = first++; first == last)
+                    {
+                        // Find the leftmost smallest element
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.min)))
+                        {
+                            result.min = *prevIt;
+                        }
+                        // Find the rightmost largest element
+                        else if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.max)))
+                        {
+                            result.max = *prevIt;
+                        }
+                        break;
+                    }
+                    else
+                    {
+                        // For every two elements performs a transitive comparisons to calculate either new
+                        // leftmost min or rightmost max using at most three comparisons
+                        // (*first < *prevIt) && (*first < result.min), then *first = leftmost min
+                        // (*first < *prevIt) && (*prevIt >= result.max), then *prevIt = rightmost max
+                        // else
+                        // (*first >= *prevIt) && (*prevIt < result.min), then *prevIt = leftmost min
+                        // (*first >= *prevIt) && (*first >= result.max), then *first = rightmost max
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *prevIt)))
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, result.min)))
+                            {
+                                result.min = *first;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.max)))
+                            {
+                                result.max = *prevIt;
+                            }
+                        }
+                        else
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.min)))
+                            {
+                                result.min = *prevIt;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, result.max)))
+                            {
+                                result.max = *first;
+                            }
+                        }
+                    }
+                }
+                return result;
+            }
+            template<class R, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(R&& r, Comp comp = {}, Proj proj = {}) const
+                -> enable_if_t<conjunction_v<
+                bool_constant<input_range<R>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<iterator_t<R>, Proj>>>,
+                bool_constant<indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>>>,
+                minmax_result<range_value_t<R>>>
+            {
+                AZ_Assert(ranges::distance(r) > 0, "ranges::minmax cannot be invoked with an empty range");
+                auto first = ranges::begin(r);
+                minmax_result<range_value_t<R>> result{ *first, *first };
+                auto last = ranges::end(r);
+                for (; first != last; ++first)
+                {
+                    // Algorithm requires at most (3/2 * ranges::distance(r)) comparisons
+                    if (auto prevIt = first++; first == last)
+                    {
+                        // Find the leftmost smallest element
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.min)))
+                        {
+                            result.min = *prevIt;
+                        }
+                        // Find the rightmost largest element
+                        else if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.max)))
+                        {
+                            result.max = *prevIt;
+                        }
+                        break;
+                    }
+                    else
+                    {
+                        // For every two elements performs a transitive comparisons to calculate either new
+                        // leftmost min or rightmost max using at most three comparisons
+                        // (*first < *prevIt) && (*first < result.min), then *first = leftmost min
+                        // (*first < *prevIt) && (*prevIt >= result.max), then *prevIt = rightmost max
+                        // else
+                        // (*first >= *prevIt) && (*prevIt < result.min), then *prevIt = leftmost min
+                        // (*first >= *prevIt) && (*first >= result.max), then *first = rightmost max
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *prevIt)))
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, result.min)))
+                            {
+                                result.min = *first;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.max)))
+                            {
+                                result.max = *prevIt;
+                            }
+                        }
+                        else
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, result.min)))
+                            {
+                                result.min = *prevIt;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, result.max)))
+                            {
+                                result.max = *first;
+                            }
+                        }
+                    }
+                }
+                return result;
+            }
+        };
+    }
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::minmax_fn minmax{};
+    }
+
+    namespace Internal
+    {
+        struct min_element_fn
+        {
+            template<class I, class S, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
+                -> enable_if_t<conjunction_v<
+                bool_constant<forward_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<I, Proj>>>
+                >, I>
+            {
+                I result{ first };
+                for (; first != last; ++first)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *result)))
+                    {
+                        result = first;
+                    }
+                }
+                return result;
+            }
+            template<class R, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(R&& r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<forward_range<R>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<iterator_t<R>, Proj>>>
+                >, borrowed_iterator_t<R>>
+            {
+                auto it = ranges::begin(r);
+                auto last = ranges::end(r);
+                borrowed_iterator_t<R> result{ it };
+                for (; it != last; ++it)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, *it), AZStd::invoke(proj, *result)))
+                    {
+                        result = it;
+                    }
+                }
+                return result;
+            }
+        };
+    }
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::min_element_fn min_element{};
+    }
+
+    namespace Internal
+    {
+        struct max_element_fn
+        {
+            template<class I, class S, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
+                -> enable_if_t<conjunction_v<
+                bool_constant<forward_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<I, Proj>>>
+                >, I>
+            {
+                I result{ first };
+                for (; first != last; ++first)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, *result), AZStd::invoke(proj, *first)))
+                    {
+                        result = first;
+                    }
+                }
+                return result;
+            }
+            template<class R, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(R&& r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<forward_range<R>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<iterator_t<R>, Proj>>>
+                >, borrowed_iterator_t<R>>
+            {
+                auto first = ranges::begin(r);
+                auto last = ranges::end(r);
+                borrowed_iterator_t<R> result{ first };
+                for (; first != last; ++first)
+                {
+                    if (AZStd::invoke(comp, AZStd::invoke(proj, *result), AZStd::invoke(proj, *first)))
+                    {
+                        result = first;
+                    }
+                }
+                return result;
+            }
+        };
+    }
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::max_element_fn max_element{};
+    }
+
+    namespace Internal
+    {
+        // C++ Standard footnote
+        // minmax_element returns the rightmost iterator with the largest value
+        // and is intentionally different from max_element which returns
+        // the leftmost iterator with the largest value
+        // https://eel.is/c++draft/algorithms#footnoteref-225
+        struct minmax_element_fn
+        {
+            template<
+                class I,
+                class S,
+                class Proj = identity,
+                class Comp = ranges::less>
+                constexpr auto operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<forward_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<I, Proj>>>
+                >, minmax_element_result<I>>
+            {
+                minmax_element_result<I> result{ first, first };
+                for (; first != last; ++first)
+                {
+                    // Algorithm requires at most (3/2 * ranges::distance(r)) comparisons
+                    if (auto prevIt = first++; first == last)
+                    {
+                        // Find the leftmost smallest element
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.min)))
+                        {
+                            result.min = prevIt;
+                        }
+                        // Find the rightmost largest element
+                        else if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.max)))
+                        {
+                            result.max = prevIt;
+                        }
+                        break;
+                    }
+                    else
+                    {
+                        // For every two elements performs a transitive comparisons to calculate either new
+                        // leftmost min or rightmost max using at most three comparisons
+                        // (*first < *prevIt) && (*first < result.min), then *first = leftmost min
+                        // (*first < *prevIt) && (*prevIt >= result.max), then *prevIt = rightmost max
+                        // else
+                        // (*first >= *prevIt) && (*prevIt < result.min), then *prevIt = leftmost min
+                        // (*first >= *prevIt) && (*first >= result.max), then *first = rightmost max
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *prevIt)))
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *result.min)))
+                            {
+                                result.min = first;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.max)))
+                            {
+                                result.max = prevIt;
+                            }
+                        }
+                        else
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.min)))
+                            {
+                                result.min = prevIt;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *result.max)))
+                            {
+                                result.max = first;
+                            }
+                        }
+                    }
+                }
+                return result;
+            }
+            template<class R, class Proj = identity, class Comp = ranges::less>
+            constexpr auto operator()(R&& r, Comp comp = {}, Proj proj = {}) const
+                ->enable_if_t<conjunction_v<
+                bool_constant<forward_range<R>>,
+                bool_constant<indirect_strict_weak_order<Comp, projected<iterator_t<R>, Proj>>>
+                >, minmax_element_result<borrowed_iterator_t<R>>>
+            {
+                auto first = ranges::begin(r);
+                minmax_element_result<borrowed_iterator_t<R>> result{ first, first };
+                auto last = ranges::end(r);
+                for (; first != last; ++first)
+                {
+                    // Algorithm requires at most (3/2 * ranges::distance(r)) comparisons
+                    if (auto prevIt = first++; first == last)
+                    {
+                        // Find the leftmost smallest element
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.min)))
+                        {
+                            result.min = prevIt;
+                        }
+                        // Find the rightmost largest element
+                        else if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.max)))
+                        {
+                            result.max = prevIt;
+                        }
+                        break;
+                    }
+                    else
+                    {
+                        // For every two elements performs a transitive comparisons to calculate either new
+                        // leftmost min or rightmost max using at most three comparisons
+                        // (*first < *prevIt) && (*first < result.min), then *first = leftmost min
+                        // (*first < *prevIt) && (*prevIt >= result.max), then *prevIt = rightmost max
+                        // else
+                        // (*first >= *prevIt) && (*prevIt < result.min), then *prevIt = leftmost min
+                        // (*first >= *prevIt) && (*first >= result.max), then *first = rightmost max
+                        if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *prevIt)))
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *result.min)))
+                            {
+                                result.min = first;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.max)))
+                            {
+                                result.max = prevIt;
+                            }
+                        }
+                        else
+                        {
+                            if (AZStd::invoke(comp, AZStd::invoke(proj, *prevIt), AZStd::invoke(proj, *result.min)))
+                            {
+                                result.min = prevIt;
+                            }
+                            if (!AZStd::invoke(comp, AZStd::invoke(proj, *first), AZStd::invoke(proj, *result.max)))
+                            {
+                                result.max = first;
+                            }
+                        }
+                    }
+                }
+                return result;
+            }
+        };
+    }
+
+    inline namespace customization_point_object
+    {
+        constexpr Internal::minmax_element_fn minmax_element{};
+    }
+
+    // find algorithms
+    namespace Internal
+    {
+        struct find_fn
+        {
+            template<class I, class S, class T, class Proj = identity, class = enable_if_t<conjunction_v<
+                bool_constant<input_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>>
+                >>>
+            constexpr I operator()(I first, S last, const T& value, Proj proj = {}) const
+            {
+                for (; first != last; ++first)
+                {
+                    if (AZStd::invoke(proj, *first) == value)
+                    {
+                        return first;
+                    }
+                }
+
+                return first;
+            }
+            template<class R, class T, class Proj = identity, class = enable_if_t<conjunction_v<
+                bool_constant<input_range<R>>,
+                bool_constant<indirect_binary_predicate<equal_to, projected<iterator_t<R>, Proj>, const T*>>
+                >>>
+            constexpr borrowed_iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const
+            {
+                return operator()(ranges::begin(r), ranges::end(r),
+                    value, AZStd::move(proj));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::find_fn find{};
+    }
+
+    namespace Internal
+    {
+        struct find_if_fn
+        {
+            template<class I, class S, class Proj = identity, class Pred, class = enable_if_t<conjunction_v<
+                bool_constant<input_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirect_unary_predicate<Pred, projected<I, Proj>>>
+                >>>
+            constexpr I operator()(I first, S last, Pred pred, Proj proj = {}) const
+            {
+                for (; first != last; ++first)
+                {
+                    if (AZStd::invoke(pred, AZStd::invoke(proj, *first)))
+                    {
+                        return first;
+                    }
+                }
+
+                return first;
+            }
+            template<class R,  class Proj = identity, class Pred, class = enable_if_t<conjunction_v<
+                bool_constant<input_range<R>>,
+                bool_constant<indirect_unary_predicate<Pred, projected<iterator_t<R>, Proj>>>
+                >>>
+            constexpr borrowed_iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const
+            {
+                return operator()(ranges::begin(r), ranges::end(r),
+                    AZStd::move(pred), AZStd::move(proj));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::find_if_fn find_if{};
+    }
+
+    namespace Internal
+    {
+        struct find_if_not_fn
+        {
+            template<class I, class S, class Proj = identity, class Pred, class = enable_if_t<conjunction_v<
+                bool_constant<input_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirect_unary_predicate<Pred, projected<I, Proj>>>
+                >>>
+            constexpr I operator()(I first, S last, Pred pred, Proj proj = {}) const
+            {
+                for (; first != last; ++first)
+                {
+                    if (!AZStd::invoke(pred, AZStd::invoke(proj, *first)))
+                    {
+                        return first;
+                    }
+                }
+
+                return first;
+            }
+            template<class R, class Proj = identity, class Pred, class = enable_if_t<conjunction_v<
+                bool_constant<input_range<R>>,
+                bool_constant<indirect_unary_predicate<Pred, projected<iterator_t<R>, Proj>>>
+                >>>
+            constexpr borrowed_iterator_t<R>
+                operator()(R&& r, Pred pred, Proj proj = {}) const
+            {
+                return operator()(ranges::begin(r), ranges::end(r),
+                    AZStd::move(pred), AZStd::move(proj));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::find_if_not_fn find_if_not{};
+    }
+
+    namespace Internal
+    {
+        struct find_first_of_fn
+        {
+            template<class I1, class S1, class I2, class S2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<input_iterator<I1>>,
+                bool_constant<sentinel_for<S1, I1>>,
+                bool_constant<forward_iterator<I2>>,
+                bool_constant<sentinel_for<S2, I2>>,
+                bool_constant<indirectly_comparable<I1, I2, Pred, Proj1, Proj2>>
+                >>>
+                constexpr I1 operator()(I1 first1, S1 last1, I2 first2, S2 last2,
+                    Pred pred = {},
+                    Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                for (; first1 != last1; ++first1)
+                {
+                    for (I2 elementIt = first2; elementIt != last2; ++elementIt)
+                    {
+                        if (AZStd::invoke(pred, AZStd::invoke(proj1, *first1), AZStd::invoke(proj2, *elementIt)))
+                        {
+                            return first1;
+                        }
+                    }
+                }
+
+                return first1;
+            }
+            template<class R1, class R2,class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<input_range<R1>>,
+                bool_constant<forward_range<R2>>,
+                bool_constant<indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>>
+            >>>
+            constexpr borrowed_iterator_t<R1> operator()(R1&& r1, R2&& r2,
+                    Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                return operator()(ranges::begin(r1), ranges::end(r1),
+                    ranges::begin(r2), ranges::end(r2),
+                        AZStd::move(pred), AZStd::move(proj1), AZStd::move(proj2));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::find_first_of_fn find_first_of{};
+    }
+
+    // ranges::mismatch
+    template<class I1, class I2>
+    using mismatch_result = in_in_result<I1, I2>;
+
+    namespace Internal
+    {
+        struct mismatch_fn
+        {
+            template<class I1, class S1, class I2, class S2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<input_iterator<I1>>,
+                bool_constant<sentinel_for<S1, I1>>,
+                bool_constant<input_iterator<I2>>,
+                bool_constant<sentinel_for<S2, I2>>,
+                bool_constant<indirectly_comparable<I1, I2, Pred, Proj1, Proj2>>
+                >>>
+            constexpr mismatch_result<I1, I2> operator()(I1 first1, S1 last1, I2 first2, S2 last2,
+                Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                for (; first1 != last1 && first2 != last2; ++first1, ++first2)
+                {
+                    if (!AZStd::invoke(pred, AZStd::invoke(proj1, *first1), AZStd::invoke(proj2, *first2)))
+                    {
+                        return { first1, first2 };
+                    }
+                }
+
+                return { first1, first2 };
+            }
+
+            template<class R1, class R2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<input_range<R1>>,
+                bool_constant<input_range<R2>>,
+                bool_constant<indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>>
+                >>>
+            constexpr mismatch_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>> operator()(R1&& r1, R2&& r2,
+                Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                return operator()(ranges::begin(r1), ranges::end(r1),
+                    ranges::begin(r2), ranges::end(r2),
+                    AZStd::move(pred), AZStd::move(proj1), AZStd::move(proj2));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::mismatch_fn mismatch{};
+    }
+
+    namespace Internal
+    {
+        struct equal_fn
+        {
+            template<class I1, class S1, class I2, class S2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<input_iterator<I1>>,
+                bool_constant<sentinel_for<S1, I1>>,
+                bool_constant<input_iterator<I2>>,
+                bool_constant<sentinel_for<S2, I2>>,
+                bool_constant<indirectly_comparable<I1, I2, Pred, Proj1, Proj2>>
+                >>>
+                constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
+                    Pred pred = {},
+                    Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                if constexpr (sized_sentinel_for<S1, I1> && sized_sentinel_for<S2, I2>)
+                {
+                    if (ranges::distance(first1, last1) != ranges::distance(first2, last2))
+                    {
+                        return false;
+                    }
+                }
+
+                for (; first1 != last1 && first2 != last2; ++first1, ++first2)
+                {
+                    if (!AZStd::invoke(pred, AZStd::invoke(proj1, *first1), AZStd::invoke(proj2, *first2)))
+                    {
+                        return false;
+                    }
+                }
+
+                return first1 == last1 && first2 == last2;
+            }
+
+            template<class R1, class R2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<input_range<R1>>,
+                bool_constant<input_range<R2>>,
+                bool_constant<indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>>
+                >>>
+                constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {},
+                    Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                return operator()(ranges::begin(r1), ranges::end(r1),
+                    ranges::begin(r2), ranges::end(r2),
+                    AZStd::move(pred), AZStd::move(proj1), AZStd::move(proj2));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::equal_fn equal{};
+    }
+
+    namespace Internal
+    {
+        struct search_fn
+        {
+            template<class I1, class S1, class I2, class S2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<forward_iterator<I1>>,
+                bool_constant<sentinel_for<S1, I1>>,
+                bool_constant<forward_iterator<I2>>,
+                bool_constant<sentinel_for<S2, I2>>,
+                bool_constant<indirectly_comparable<I1, I2, Pred, Proj1, Proj2>>
+                >>>
+            constexpr subrange<I1> operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
+                Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                do
+                {
+                    I1 it1 = first1;
+                    I2 it2 = first2;
+                    for (;; ++it1, ++it2)
+                    {
+                        if (it2 == last2)
+                        {
+                            // Reached the end of the second iteator sequence
+                            // Therefore the search has succeeded. return the matching range from the first sequence
+                            return { first1, it1 };
+                        }
+                        if (it1 == last1)
+                        {
+                            // The search has failed to find the second iterator sequence within the first
+                            return { last1, last1 };
+                        }
+                        if (!AZStd::invoke(pred, AZStd::invoke(proj1, *it1), AZStd::invoke(proj2, *it2)))
+                        {
+                            // Mismatch found break out of iteration of loop
+                            break;
+                        }
+                    }
+                    // Increment to the next element in the range of [first1, last1) and restart the search
+                    ++first1;
+                } while (true);
+            }
+
+            template<class R1, class R2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<forward_range<R1>>,
+                bool_constant<forward_range<R2>>,
+                bool_constant<indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>>
+                >>>
+            constexpr borrowed_subrange_t<R1>
+                operator()(R1&& r1, R2&& r2, Pred pred = {},
+                    Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                return operator()(ranges::begin(r1), ranges::end(r1),
+                    ranges::begin(r2), ranges::end(r2),
+                        AZStd::move(pred), AZStd::move(proj1), AZStd::move(proj2));
+            }
+
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::search_fn search{};
+    }
+
+    namespace Internal
+    {
+        struct search_n_fn
+        {
+            template<class I, class S, class T, class Pred = equal_to, class Proj = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<forward_iterator<I>>,
+                bool_constant<sentinel_for<S, I>>,
+                bool_constant<indirectly_comparable<I, const T*, Pred, Proj>>
+                >>>
+                constexpr subrange<I> operator()(I first, S last, iter_difference_t<I> count,
+                    const T& value, Pred pred = {}, Proj proj = {}) const
+            {
+                for (; first != last; ++first)
+                {
+                    iter_difference_t<I> foundCount{};
+                    I searchFirst = first;
+                    for (; foundCount != count && first != last; ++first, ++foundCount)
+                    {
+                        if (!AZStd::invoke(pred, AZStd::invoke(proj, *first), value))
+                        {
+                            break;
+                        }
+                    }
+                    if (foundCount == count)
+                    {
+                        // count consecutive elements matching value have been found
+                        return { searchFirst, first };
+                    }
+                    if (first == last)
+                    {
+                        // search has failed to find count matching elements over the range.
+                        break;
+                    }
+                }
+
+                return { last, last };
+            }
+            template<class R, class T, class Pred = equal_to, class Proj = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<forward_range<R>>,
+                bool_constant<indirectly_comparable<iterator_t<R>, const T*, Pred, Proj>>
+                >>>
+                constexpr borrowed_subrange_t<R> operator()(R&& r, range_difference_t<R> count,
+                    const T& value, Pred pred = {}, Proj proj = {}) const
+            {
+                return operator()(ranges::begin(r), ranges::end(r),
+                    AZStd::move(count), value, AZStd::move(pred), AZStd::move(proj));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::search_n_fn search_n{};
+    }
+
+    // ranges::find_end_fn
+    // use ranges::search
+    namespace Internal
+    {
+        struct find_end_fn
+        {
+            template<class I1, class S1, class I2, class S2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<forward_iterator<I1>>,
+                bool_constant<sentinel_for<S1, I1>>,
+                bool_constant<forward_iterator<I2>>,
+                bool_constant<sentinel_for<S2, I2>>,
+                bool_constant<indirectly_comparable<I1, I2, Pred, Proj1, Proj2>>
+                >>>
+                constexpr subrange<I1> operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
+                    Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                if (first2 == last2)
+                {
+                    return { last1, last1 };
+                }
+                auto foundSubrange = ranges::search(first1, last1, first2, last2, pred, proj1, proj2);
+                if (foundSubrange.empty())
+                {
+                    return foundSubrange;
+                }
+                do
+                {
+                    auto nextIt = ranges::next(foundSubrange.begin());
+                    auto nextSubrange = ranges::search(nextIt, last1, first2, last2, pred, proj1, proj2);
+                    if (nextSubrange.empty())
+                    {
+                        return foundSubrange;
+                    }
+
+                    foundSubrange = AZStd::move(nextSubrange);
+
+                } while (true);
+            }
+            template<class R1, class R2, class Pred = equal_to, class Proj1 = identity, class Proj2 = identity,
+                class = enable_if_t<conjunction_v<
+                bool_constant<forward_range<R1>>,
+                bool_constant<forward_range<R2>>,
+                bool_constant<indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>>
+                >>>
+                constexpr borrowed_subrange_t<R1> operator()(R1&& r1, R2&& r2, Pred pred = {},
+                    Proj1 proj1 = {}, Proj2 proj2 = {}) const
+            {
+                return operator()(ranges::begin(r1), ranges::end(r1),
+                    ranges::begin(r2), ranges::end(r2),
+                        AZStd::move(pred), AZStd::move(proj1), AZStd::move(proj2));
+            }
+        };
+    }
+    inline namespace customization_point_object
+    {
+        constexpr Internal::find_end_fn find_end{};
+    }
+} // namespace AZStd::ranges
+

+ 121 - 0
Code/Framework/AzCore/AzCore/std/ranges/ranges_functional.h

@@ -0,0 +1,121 @@
+/*
+ * 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/function/identity.h>
+#include <AzCore/std/ranges/ranges.h>
+
+namespace AZStd::ranges
+{
+    struct equal_to
+    {
+        template<class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const ->
+            enable_if_t<equality_comparable_with<T, U>, decltype(AZStd::forward<T>(t) == AZStd::forward<U>(u))>
+        {
+            return AZStd::forward<T>(t) == AZStd::forward<U>(u);
+        }
+        using is_transparent = void;
+    };
+
+    struct not_equal_to
+    {
+        template<class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const ->
+            enable_if_t<equality_comparable_with<T, U>, decltype(!ranges::equal_to{}(AZStd::forward<T>(t), AZStd::forward<U>(u)))>
+        {
+            return !ranges::equal_to{}(AZStd::forward<T>(t), AZStd::forward<U>(u));
+        }
+        using is_transparent = void;
+    };
+    
+    struct less
+    {
+        template<class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const ->
+            enable_if_t<totally_ordered_with<T, U>, decltype(AZStd::forward<T>(t) < AZStd::forward<U>(u))>
+        {
+            return AZStd::forward<T>(t) < AZStd::forward<U>(u);
+        }
+        using is_transparent = void;
+    };
+
+    struct greater
+    {
+        template<class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const ->
+            enable_if_t<totally_ordered_with<T, U>, decltype(ranges::less{}(AZStd::forward<T>(t) < AZStd::forward<U>(u)))>
+        {
+            return ranges::less{}(AZStd::forward<U>(u) < AZStd::forward<T>(t));
+        }
+        using is_transparent = void;
+    };
+    
+    struct greater_equal
+    {
+        template<class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const ->
+            enable_if_t<totally_ordered_with<T, U>, decltype(!ranges::less{}(AZStd::forward<T>(t), AZStd::forward<U>(u)))>
+        {
+            return !ranges::less{}(AZStd::forward<T>(t), AZStd::forward<U>(u));
+        }
+        using is_transparent = void;
+    };
+    
+    struct less_equal
+    {
+        template<class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const ->
+            enable_if_t<totally_ordered_with<T, U>, decltype(!ranges::less{}(AZStd::forward<U>(u), AZStd::forward<T>(t)))>
+        {
+            return !ranges::less{}(AZStd::forward<U>(u), AZStd::forward<T>(t));
+        }
+        using is_transparent = void;
+    };
+} // namespace AZStd::ranges
+
+
+// Iterator Common algorithm requirement concepts
+// https://eel.is/c++draft/alg.req
+namespace AZStd
+{
+    template<class I1, class I2, class R, class P1 = identity, class P2 = identity, class = void>
+    /*concept*/ constexpr bool indirectly_comparable = false;
+
+    template<class I1, class I2, class R, class P1, class P2>
+    /*concept*/ constexpr bool indirectly_comparable<I1, I2, R, P1, P2, enable_if_t<
+        indirect_binary_predicate<R, projected<I1, P1>, projected<I2, P2>>>> = true;
+
+    template<class I, class = void>
+    /*concept*/ constexpr bool permutable = false;
+
+    template<class I>
+    /*concept*/ constexpr bool permutable<I, enable_if_t<conjunction_v<
+        bool_constant<forward_iterator<I>>,
+        bool_constant<indirectly_movable_storable<I, I>>,
+        bool_constant<indirectly_swappable<I, I>> >>> = true;
+
+    template<class I1, class I2, class Out, class R = ranges::less, class P1 = identity, class P2 = identity, class = void>
+    /*concept*/ constexpr bool mergeable = false;
+
+    template<class I1, class I2, class Out, class R, class P1, class P2>
+    /*concept*/ constexpr bool mergeable<I1, I2, Out, R, P1, P2, enable_if_t<conjunction_v<
+        bool_constant<input_iterator<I1>>,
+        bool_constant<input_iterator<I2>>,
+        bool_constant<weakly_incrementable<Out>>,
+        bool_constant<indirectly_copyable<I1, Out>>,
+        bool_constant<indirectly_copyable<I2, Out>>,
+        bool_constant<indirect_strict_weak_order<R, projected<I1, P1>, projected<I2, P2>>> >>> = true;
+
+    template<class I, class R = ranges::less, class P = identity, class = void>
+    /*concept*/ constexpr bool sortable = false;
+    template<class I, class R, class P>
+    /*concept*/ constexpr bool sortable<I, R, P, enable_if_t<conjunction_v<
+        bool_constant<permutable<I>>,
+        bool_constant<indirect_strict_weak_order<R, projected<I, P>>> >>> = true;
+}

+ 77 - 0
Code/Framework/AzCore/AzCore/std/ranges/ref_view.h

@@ -0,0 +1,77 @@
+/*
+ * 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/ranges/ranges.h>
+#include <AzCore/std/optional.h>
+
+namespace AZStd::ranges
+{
+    template<class R, class = void>
+    class ref_view;
+
+    template<class R>
+    class ref_view<R, enable_if_t<ranges::range<R> && is_object_v<R>>>
+        : public ranges::view_interface<ref_view<R>>
+    {
+    private:
+        static void bindable_to_range(R&);
+        static void bindable_to_range(R&&) = delete;
+    public:
+        template<class T, class = enable_if_t<conjunction_v<
+            bool_constant<Internal::different_from<T, ref_view>>,
+            bool_constant<convertible_to<T, R&>>,
+            Internal::sfinae_trigger<decltype(bindable_to_range(declval<T>()))>
+            >>>
+        constexpr ref_view(T&& t)
+            : m_range{ addressof(static_cast<R&>(AZStd::forward<T>(t))) }
+        {}
+
+        constexpr R& base() const
+        {
+            return *m_range;
+        }
+
+        constexpr iterator_t<R> begin() const
+        {
+            return ranges::begin(*m_range);
+        }
+        constexpr sentinel_t<R> end() const
+        {
+            return ranges::end(*m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto empty() const -> enable_if_t<Internal::sfinae_trigger_v<decltype(ranges::empty(*declval<Rn*>()))>, bool>
+        {
+            return ranges::empty(*m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto size() const -> enable_if_t<sized_range<R>, decltype(ranges::size(*declval<Rn*>()))>
+        {
+            return ranges::size(*m_range);
+        }
+
+        template<class Rn = R>
+        constexpr auto data() const -> enable_if_t<contiguous_range<R>, decltype(ranges::data(*declval<Rn*>()))>
+        {
+            return ranges::data(*m_range);
+        }
+
+    private:
+        R* m_range{};
+    };
+
+    //! deduction guides
+    template<class R>
+    ref_view(R&) -> ref_view<R>;
+
+    template<class T>
+    inline constexpr bool enable_borrowed_range<ref_view<T>> = true;
+}

+ 89 - 0
Code/Framework/AzCore/AzCore/std/ranges/single_view.h

@@ -0,0 +1,89 @@
+/*
+ * 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/ranges/ranges_adaptor.h>
+
+namespace AZStd::ranges
+{
+    template<class T, class = void>
+    class single_view;
+
+    namespace views
+    {
+        namespace Internal
+        {
+            struct single_view_fn
+            {
+                template <class View>
+                constexpr decltype(auto) operator()(View&& view) const
+                {
+                    return single_view<decay_t<View>>(AZStd::forward<View>(view));
+                }
+            };
+        }
+        inline namespace customization_point_object
+        {
+            constexpr Internal::single_view_fn single{};
+        }
+    }
+
+    template<class T>
+    class single_view<T, enable_if_t<copy_constructible<T>&& is_object_v<T>>>
+        : public view_interface<single_view<T>>
+    {
+    public:
+
+        template<class T2 = T, class = enable_if_t<default_initializable<T2>>>
+        single_view() {}
+        constexpr explicit single_view(const T& t)
+            : m_value(in_place, t)
+        {}
+        constexpr explicit single_view(T&& t)
+            : m_value(in_place, AZStd::move(t))
+        {}
+        template<class... Args, enable_if_t<constructible_from<T, Args...>>* = nullptr>
+        constexpr explicit single_view(in_place_t, Args&&... args)
+            : m_value{ in_place, AZStd::forward<Args>(args)... }
+        {}
+
+        constexpr T* begin() noexcept
+        {
+            return data();
+        }
+        constexpr const T* begin() const noexcept
+        {
+            return data();
+        }
+        constexpr T* end() noexcept
+        {
+            return data() + 1;
+        }
+        constexpr const T* end() const noexcept
+        {
+            return data() + 1;
+        }
+        static constexpr size_t size() noexcept
+        {
+            return 1;
+        }
+        constexpr T* data() noexcept
+        {
+            return m_value.operator->();
+        }
+        constexpr const T* data() const noexcept
+        {
+            return m_value.operator->();
+        }
+    private:
+        Internal::copyable_box<T> m_value;
+    };
+
+    template<class T>
+    single_view(T) -> single_view<T>;
+}

+ 235 - 0
Code/Framework/AzCore/AzCore/std/ranges/split_view.h

@@ -0,0 +1,235 @@
+/*
+ * 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/ranges/all_view.h>
+#include <AzCore/std/ranges/ranges_adaptor.h>
+#include <AzCore/std/ranges/ranges_algorithm.h>
+#include <AzCore/std/ranges/ranges_functional.h>
+#include <AzCore/std/ranges/single_view.h>
+
+namespace AZStd::ranges
+{
+    template<class View, class Pattern, class = enable_if_t<conjunction_v<
+        bool_constant<forward_range<View>>,
+        bool_constant<forward_range<Pattern>>,
+        bool_constant<view<View>>,
+        bool_constant<view<Pattern>>,
+        bool_constant<indirectly_comparable<iterator_t<View>, iterator_t<Pattern>, ranges::equal_to>>
+        >>>
+        class split_view;
+
+    // views::split customization point
+    namespace views
+    {
+        namespace Internal
+        {
+            struct split_view_fn
+                : Internal::range_adaptor_closure<split_view_fn>
+            {
+                template <class View, class Pattern, class = enable_if_t<conjunction_v<
+                    bool_constant<viewable_range<View>>
+                    >>>
+                constexpr auto operator()(View&& view, Pattern&& pattern) const
+                {
+                    return split_view(AZStd::forward<View>(view), AZStd::forward<Pattern>(pattern));
+                }
+
+            };
+        }
+        inline namespace customization_point_object
+        {
+            constexpr Internal::split_view_fn split{};
+        }
+    }
+
+    template<class View, class Pattern, class>
+    class split_view
+        : public view_interface<split_view<View, Pattern>>
+    {
+        struct iterator;
+        struct sentinel;
+    public:
+        template <bool Enable = default_initializable<View> && default_initializable<Pattern>,
+            class = enable_if_t<Enable>>
+        split_view() {}
+
+        constexpr split_view(View base, Pattern pattern)
+            : m_base(AZStd::move(base))
+            , m_pattern(AZStd::move(pattern))
+        {}
+
+        template<class R, class = enable_if_t<conjunction_v<
+            bool_constant<forward_range<R>>,
+            bool_constant<constructible_from<View, views::all_t<R>>>,
+            bool_constant<constructible_from<Pattern, single_view<range_value_t<R>>>>
+            >>>
+        constexpr split_view(R&& r, range_value_t<R> e)
+            : m_base{ views::all(AZStd::forward<R>(r)) }
+            , m_pattern{ views::single(AZStd::move(e)) }
+        {
+        }
+
+        template <bool Enable = copy_constructible<View>, class = enable_if_t<Enable>>
+        constexpr View base() const&
+        {
+            return m_base;
+        }
+        constexpr View base()&&
+        {
+            return AZStd::move(m_base);
+        }
+
+        constexpr iterator begin()
+        {
+            return { *this, ranges::begin(m_base), find_next(ranges::begin(m_base)) };
+        }
+
+        constexpr auto end()
+        {
+            if constexpr (common_range<View>)
+            {
+                return iterator{ *this, ranges::end(m_base), {} };
+            }
+            else
+            {
+                return sentinel{ *this };
+            }
+        }
+
+        constexpr subrange<iterator_t<View>> find_next(iterator_t<View> it)
+        {
+            auto [first, last] = ranges::search(subrange(it, ranges::end(m_base)), m_pattern);
+            if (first != ranges::end(m_base) && ranges::empty(m_pattern))
+            {
+                ++first;
+                ++last;
+            }
+
+            return { first, last };
+        }
+    private:
+        View m_base;
+        Pattern m_pattern;
+    };
+
+    template<class R, class P>
+    split_view(R&&, P&&)->split_view<views::all_t<R>, views::all_t<P>>;
+
+    template<class R, class = enable_if_t<forward_range<R>>>
+    split_view(R&&, range_value_t<R>)
+        -> split_view<views::all_t<R>, single_view<range_value_t<R>>>;
+
+    template<class View, class Pattern, class Enable>
+    struct split_view<View, Pattern, Enable>::iterator
+    {
+        using iterator_concept = forward_iterator_tag;
+        using iterator_category = input_iterator_tag;
+        using value_type = subrange<iterator_t<View>>;
+        using difference_type = range_difference_t<View>;
+
+        iterator() = default;
+
+        constexpr iterator(split_view& parent, iterator_t<View> current, subrange<iterator_t<View>> patternSubrange)
+            : m_parent(&parent)
+            , m_current(AZStd::move(current))
+            , m_next(AZStd::move(patternSubrange))
+        {
+        }
+        constexpr iterator_t<View> base() const
+        {
+            return m_current;
+        }
+
+        constexpr value_type operator*() const
+        {
+            return { m_current, m_next.begin() };
+        }
+
+        constexpr iterator& operator++()
+        {
+            m_current = m_next.begin();
+            if (m_current != ranges::end(m_parent->m_base))
+            {
+                m_current = m_next.end();
+                if (m_current == ranges::end(m_parent->m_base))
+                {
+                    m_trailing_empty = true;
+                    m_next = { m_current, m_current };
+                }
+                else
+                {
+                    m_next = m_parent->find_next(m_current);
+                }
+            }
+            else
+            {
+                m_trailing_empty = false;
+            }
+
+            return *this;
+        }
+
+        constexpr iterator operator++(int)
+        {
+            auto tmp = *this;
+            ++(*this);
+            return tmp;
+        }
+
+        friend constexpr bool operator==(const iterator& x, const iterator& y)
+        {
+            return x.m_current == y.m_current && x.m_trailing_empty == y.m_trailing_empty;
+        }
+        friend constexpr bool operator!=(const iterator& y, const iterator& x)
+        {
+            return !operator==(x, y);
+        }
+    private:
+        //! reference to parent split_view
+        split_view<View, Pattern>* m_parent{};
+        //! iterator of the current split content of the view
+        iterator_t<View> m_current{};
+        //! The next subrange within the view that matches the pattern
+        subrange<iterator_t<View>> m_next{};
+        //! Set to true to indicate an iterator
+        //! pointing to the empty after the last pattern if the pattern is at the end of the view
+        //! For a View="a,b,c," and Pattern=",", the last iterator will point to the empty element
+        //! after the last comma. This iteator will not match the sentinel iterator to allow users
+        //! to know between the end of the View and an empty element after the last pattern
+        bool m_trailing_empty{};
+    };
+
+    template<class View, class Pattern, class Enable>
+    struct split_view<View, Pattern, Enable>::sentinel
+    {
+        sentinel() = default;
+        explicit constexpr sentinel(split_view& parent)
+            : m_end{ ranges::end(parent.m_base) }
+        {}
+
+        friend constexpr bool operator==(const iterator& x, const sentinel& y)
+        {
+            return x.m_current == y.m_end && !x.m_trailing_empty;
+        }
+        friend constexpr bool operator==(const sentinel& y, const iterator& x)
+        {
+            return operator==(x, y);
+        }
+        friend constexpr bool operator!=(const iterator& x, const sentinel& y)
+        {
+            return !operator==(x, y);
+        }
+        friend constexpr bool operator!=(const sentinel& y, const iterator& x)
+        {
+            return !operator==(x, y);
+        }
+    private:
+        sentinel_t<View> m_end;
+    };
+}

+ 290 - 0
Code/Framework/AzCore/AzCore/std/ranges/subrange.h

@@ -0,0 +1,290 @@
+/*
+ * 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/ranges/ranges_adaptor.h>
+#include <AzCore/std/tuple.h>
+
+// Specializing tuple in std:: namespace since tuple_size and tuple_element structs
+// are alias templates inside of the AZStd:: namespace
+namespace std
+{
+    AZ_PUSH_DISABLE_WARNING(, "-Wmismatched-tags")
+    template<class I, class S, AZStd::ranges::subrange_kind K>
+    struct tuple_size<AZStd::ranges::subrange<I, S, K>>
+        : integral_constant<size_t, 2> {};
+    template<class I, class S, AZStd::ranges::subrange_kind K>
+    struct tuple_element<0, AZStd::ranges::subrange<I, S, K>>
+    {
+        using type = I;
+    };
+    template<class I, class S, AZStd::ranges::subrange_kind K>
+    struct tuple_element<1, AZStd::ranges::subrange<I, S, K>>
+    {
+        using type = S;
+    };
+    template<class I, class S, AZStd::ranges::subrange_kind K>
+    struct tuple_element<0, const AZStd::ranges::subrange<I, S, K>>
+    {
+        using type = I;
+    };
+    template<class I, class S, AZStd::ranges::subrange_kind K>
+    struct tuple_element<1, const AZStd::ranges::subrange<I, S, K>>
+    {
+        using type = S;
+    };
+    AZ_POP_DISABLE_WARNING
+}
+
+namespace AZStd::ranges
+{
+    namespace Internal
+    {
+        template <typename From, typename To>
+        /*concept*/ constexpr bool uses_nonqualification_pointer_conversion =
+            is_pointer_v<From> && is_pointer_v<To> &&
+            !convertible_to<remove_pointer_t<From>(*)[], remove_pointer_t<To>(*)[]>;
+
+        template<class From, class To>
+        /*concept*/ constexpr bool convertible_to_non_slicing =
+            convertible_to<From, To> &&
+            !uses_nonqualification_pointer_conversion<decay_t<From>, decay_t<To>>;
+
+        template<class T, class = void>
+        /*concept*/ constexpr bool pair_like = false;
+
+        template<class T>
+        /*concept*/ constexpr bool pair_like<T, enable_if_t<conjunction_v<
+            bool_constant<!is_reference_v<T>>,
+            sfinae_trigger<typename tuple_size<T>::type>,
+            bool_constant<derived_from<tuple_size<T>, integral_constant<size_t, 2>>>,
+            sfinae_trigger<
+            tuple_element_t<0, remove_const_t<T>>,
+            tuple_element_t<1, remove_const_t<T>>>,
+            bool_constant<convertible_to<decltype(AZStd::get<0>(declval<T>())), const tuple_element_t<0, T>&>>,
+            bool_constant<convertible_to<decltype(AZStd::get<1>(declval<T>())), const tuple_element_t<1, T>&>>>
+            >> = true;
+
+        template<class T, class U, class V, class = void>
+        /*concept*/ constexpr bool pair_like_convertible_from = false;
+        template<class T, class U, class V>
+        /*concept*/ constexpr bool pair_like_convertible_from<T, U, V, enable_if_t<
+            !range<T> && pair_like<T> && constructible_from<T, U, V>>> =
+            convertible_to_non_slicing<U, tuple_element_t<0, T>> &&
+            convertible_to<V, tuple_element_t<1, T>>;
+    }
+
+    template<class I, class S, subrange_kind K>
+    class subrange<I, S, K, enable_if_t<conjunction_v<
+        bool_constant<input_or_output_iterator<I>>,
+        bool_constant<sentinel_for<S, I>>,
+        bool_constant<(K == subrange_kind::sized || !sized_sentinel_for<S, I>)>>
+        >>
+        : public view_interface<subrange<I, S, K>>
+    {
+        static constexpr bool StoreSize = K == subrange_kind::sized && !sized_sentinel_for<S, I>;
+
+    public:
+        template<class I2 = I, class = enable_if_t<default_initializable<I2>>>
+        constexpr subrange() {}
+
+        template<class I2, class = enable_if_t<Internal::convertible_to_non_slicing<I2, I> && !StoreSize>>
+        constexpr subrange(I2 i, S s)
+            : m_begin(AZStd::move(i))
+            , m_end(s)
+        {
+        }
+        template<class I2, class = enable_if_t<Internal::convertible_to_non_slicing<I2, I> && K == subrange_kind::sized>>
+        constexpr subrange(I2 i, S s, make_unsigned_t<iter_difference_t<I>> n)
+            : m_begin(AZStd::move(i))
+            , m_end(s)
+        {
+            if constexpr (StoreSize)
+            {
+                m_size = n;
+            }
+        }
+
+        template<class R, class = enable_if_t<conjunction_v<
+            bool_constant<Internal::different_from<R, subrange>>,
+            bool_constant<borrowed_range<R>>,
+            bool_constant<Internal::convertible_to_non_slicing<iterator_t<R>, I>>,
+            bool_constant<convertible_to<sentinel_t<R>, S>>,
+            bool_constant<(!StoreSize || sized_range<R>)>>
+            >>
+        constexpr subrange(R&& r)
+            : m_begin{ ranges::begin(AZStd::forward<R>(r)) }
+            , m_end{ ranges::end(AZStd::forward<R>(r)) }
+        {
+            if constexpr (StoreSize)
+            {
+                m_size = ranges::size(AZStd::forward<R>(r));
+            }
+        }
+
+        template<class R, class = enable_if_t<conjunction_v<
+            bool_constant<borrowed_range<R>>,
+            bool_constant<Internal::convertible_to_non_slicing<iterator_t<R>, I>>,
+            bool_constant<convertible_to<sentinel_t<R>, S>>,
+            bool_constant<(K == subrange_kind::sized)>>
+            >>
+        constexpr subrange(R&& r, make_unsigned_t<iter_difference_t<I>> n)
+            : subrange{ ranges::begin(r), ranges::end(r), n }
+        {
+        }
+
+        template<class PairLike, class = enable_if_t<conjunction_v<
+            bool_constant<Internal::different_from<PairLike, subrange>>,
+            bool_constant<Internal::pair_like_convertible_from<PairLike, const I&, const S&>>>
+            >>
+        constexpr operator PairLike() const
+        {
+            return PairLike{ m_begin, m_end };
+        }
+
+        template<bool Enable = copyable<I>, class = enable_if_t<Enable>>
+        constexpr I begin() const
+        {
+            return m_begin;
+        }
+        template<bool Enable = !copyable<I>, class = enable_if_t<Enable>>
+        [[nodiscard]] constexpr I begin()
+        {
+            return AZStd::move(m_begin);
+        }
+        constexpr S end() const
+        {
+            return m_end;
+        }
+
+        constexpr bool empty() const
+        {
+            return m_begin == m_end;
+        }
+        template<bool Enable = (K == subrange_kind::sized), class = enable_if_t<Enable>>
+        constexpr make_unsigned_t<iter_difference_t<I>> size() const
+        {
+            if constexpr (StoreSize)
+            {
+                return m_size;
+            }
+            else
+            {
+                using unsigned_difference_type = make_unsigned_t<iter_difference_t<I>>;
+                return static_cast<unsigned_difference_type>(m_end - m_begin);
+            }
+        }
+
+        template<bool Enable = forward_iterator<I>, class = enable_if_t<Enable>>
+        [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const&
+        {
+            auto tmp = *this;
+            tmp.advance(n);
+            return tmp;
+        }
+        [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1)&&
+        {
+            advance(n);
+            return AZStd::move(*this);
+        }
+        template<bool Enable = bidirectional_iterator<I>, class = enable_if_t<Enable>>
+        [[nodiscard]] constexpr subrange prev(iter_difference_t<I> n = 1) const
+        {
+            auto tmp = *this;
+            tmp.advance(-n);
+            return tmp;
+        }
+        constexpr subrange& advance(iter_difference_t<I> n)
+        {
+            using unsigned_difference_type = AZStd::make_unsigned_t<iter_difference_t<I>>;
+            if constexpr (bidirectional_iterator<I>)
+            {
+                if (n < 0)
+                {
+                    ranges::advance(m_begin, n);
+                    if constexpr (StoreSize)
+                    {
+                        m_size += static_cast<unsigned_difference_type>(-n);
+                    }
+                    return *this;
+                }
+            }
+
+            auto actualAdvanceDist = n - ranges::advance(m_begin, n, m_end);
+            if constexpr (StoreSize)
+            {
+                m_size -= static_cast<unsigned_difference_type>(actualAdvanceDist);
+            }
+
+            return *this;
+        }
+
+    private:
+        I m_begin{};
+        S m_end{};
+
+        // Size member will not count against the size of the class when using no_unique_address
+        struct SizeNotStored
+        {
+            constexpr SizeNotStored() noexcept = default;
+        };
+        using size_type = AZStd::conditional_t<StoreSize, make_unsigned_t<iter_difference_t<I>>, SizeNotStored>;
+        AZ_NO_UNIQUE_ADDRESS size_type m_size{};
+    };
+
+    template<class I, class S, class = enable_if_t<input_or_output_iterator<I> && sentinel_for<S, I>>>
+    subrange(I, S) -> subrange<I, S>;
+
+    template<class I, class S, class = enable_if_t<input_or_output_iterator<I>&& sentinel_for<S, I>>>
+    subrange(I, S, make_unsigned_t<iter_difference_t<I>>) -> subrange<I, S, subrange_kind::sized>;
+
+    template<class R, class = enable_if_t<borrowed_range<R>> >
+    subrange(R&&) -> subrange<iterator_t<R>, sentinel_t<R>,
+        (sized_range<R> || sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)
+        ? subrange_kind::sized : subrange_kind::unsized>;
+
+    template<class R, class = enable_if_t<borrowed_range<R>> >
+    subrange(R&&, make_unsigned_t<range_difference_t<R>>) ->
+        subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;
+
+    template<size_t N, class I, class S, subrange_kind K, class = enable_if_t<((N == 0 && copyable<I>) || N == 1)>>
+    constexpr auto get(const subrange<I, S, K>& r)
+    {
+        if constexpr (N == 0)
+        {
+            return r.begin();
+        }
+        else
+        {
+            return r.end();
+        }
+    }
+
+    template<size_t N, class I, class S, subrange_kind K, class = enable_if_t<(N < 2)>>
+    constexpr auto get(subrange<I, S, K>&& r)
+    {
+        if constexpr (N == 0)
+        {
+            return r.begin();
+        }
+        else
+        {
+            return r.end();
+        }
+    }
+
+
+    template<class I, class S, subrange_kind K>
+    inline constexpr bool enable_borrowed_range<subrange<I, S, K>> = true;
+
+}
+
+namespace AZStd
+{
+    using ranges::get;
+}

+ 116 - 0
Code/Framework/AzCore/AzCore/std/ranges/swap.h

@@ -0,0 +1,116 @@
+/*
+ * 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/base.h>
+
+#include <AzCore/std/concepts/concepts_assignable.h>
+#include <AzCore/std/concepts/concepts_constructible.h>
+#include <AzCore/std/typetraits/conjunction.h>
+#include <AzCore/std/typetraits/disjunction.h>
+#include <AzCore/std/typetraits/extent.h>
+#include <AzCore/std/typetraits/integral_constant.h>
+#include <AzCore/std/typetraits/is_assignable.h>
+#include <AzCore/std/typetraits/is_array.h>
+#include <AzCore/std/typetraits/is_class.h>
+#include <AzCore/std/typetraits/is_enum.h>
+#include <AzCore/std/typetraits/is_void.h>
+#include <AzCore/std/typetraits/remove_cvref.h>
+#include <AzCore/std/typetraits/void_t.h>
+#include <AzCore/std/utility/move.h>
+#include <AzCore/std/utility/declval.h>
+
+
+namespace AZStd
+{
+    // Bring std utility functions into AZStd namespace
+    using std::forward;
+}
+
+namespace AZStd::ranges::Internal
+{
+    template <class T, class U, class = void>
+    constexpr bool is_class_or_enum_with_swap_adl = false;
+    template <class T, class U>
+    constexpr bool is_class_or_enum_with_swap_adl<T, U, enable_if_t<conjunction_v<
+        disjunction<
+            disjunction<is_class<remove_cvref_t<T>>, is_enum<remove_cvref_t<T>>>,
+            disjunction<is_class<remove_cvref_t<U>>, is_enum<remove_cvref_t<U>>>>,
+        is_void<void_t<decltype(swap(declval<T&>(), declval<U&>()))>>
+        >>> = true;
+
+    template <class T>
+    void swap(T&, T&) = delete;
+
+    struct swap_fn
+    {
+        template <class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept(swap(AZStd::forward<T>(t), AZStd::forward<U>(u))))
+            ->enable_if_t<is_class_or_enum_with_swap_adl<T, U>>
+        {
+            swap(AZStd::forward<T>(t), AZStd::forward<U>(u));
+        }
+
+        // ranges::swap customization point https://eel.is/c++draft/concepts#concept.swappable-2.2
+        // Implemented in ranges.h as to prevent circular dependency.
+        // ranges::swap_ranges depends on the range concepts that can't be defined here
+        template <class T, class U>
+        constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept((*this)(*t, *u)))
+            ->enable_if_t<conjunction_v<
+            bool_constant<!is_class_or_enum_with_swap_adl<T, U>>,
+            is_array<T>,
+            is_array<U>,
+            bool_constant<extent_v<T> == extent_v<U>>
+            >>;
+
+        template <class T>
+        constexpr auto operator()(T& t1, T& t2) const noexcept(noexcept(is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>))
+            ->enable_if_t<conjunction_v<bool_constant<move_constructible<T>>, bool_constant<assignable_from<T&, T>> >>
+        {
+            auto temp(AZStd::move(t1));
+            t1 = AZStd::move(t2);
+            t2 = AZStd::move(temp);
+        }
+    };
+}
+
+namespace AZStd::ranges
+{
+    inline namespace customization_point_object
+    {
+        inline constexpr auto swap = Internal::swap_fn{};
+    }
+}
+
+namespace AZStd::Internal
+{
+    template <class T, class = void>
+    constexpr bool swappable_impl = false;
+    template <class T>
+    constexpr bool swappable_impl<T, void_t<decltype(AZStd::ranges::swap(declval<T&>(), declval<T&>()))>> = true;
+
+    template <class T, class U, class = void>
+    constexpr bool swappable_with_impl = false;
+    template <class T, class U>
+    constexpr bool swappable_with_impl<T, U, enable_if_t<conjunction_v<
+        bool_constant<common_reference_with<T, U>>,
+        is_void<void_t<
+        decltype(AZStd::ranges::swap(declval<T&>(), declval<T&>())),
+        decltype(AZStd::ranges::swap(declval<U&>(), declval<U&>())),
+        decltype(AZStd::ranges::swap(declval<T&>(), declval<U&>())),
+        decltype(AZStd::ranges::swap(declval<U&>(), declval<T&>()))>> >>> = true;
+}
+
+namespace AZStd
+{
+    template<class T>
+    /*concept*/ constexpr bool swappable = Internal::swappable_impl<T>;
+
+    template<class T, class U>
+    /*concept*/ constexpr bool swappable_with = Internal::swappable_with_impl<T, U>;
+}

+ 395 - 0
Code/Framework/AzCore/AzCore/std/ranges/zip_view.h

@@ -0,0 +1,395 @@
+/*
+ * 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/ranges/all_view.h>
+#include <AzCore/std/ranges/empty_view.h>
+#include <AzCore/std/ranges/ranges_algorithm.h>
+#include <AzCore/std/tuple.h>
+
+namespace AZStd::ranges
+{
+    template<class... Views>
+    class zip_view;
+
+    template<class... Views>
+    inline constexpr bool enable_borrowed_range<zip_view<Views...>> = (enable_borrowed_range<Views> && ...);
+
+    // views::zip customization point
+    namespace views
+    {
+        namespace Internal
+        {
+            struct zip_view_fn
+            {
+                template <class... Views>
+                constexpr auto operator()(Views&&... views) const
+                {
+                    if constexpr (sizeof...(Views) == 0)
+                    {
+                        return views::empty<tuple<>>;
+                    }
+                    else
+                    {
+                        return zip_view<views::all_t<decltype((declval<Views>()))>...>(AZStd::forward<Views>(views)...);
+                    }
+                }
+
+            };
+        }
+        inline namespace customization_point_object
+        {
+            constexpr Internal::zip_view_fn zip{};
+        }
+    }
+
+    namespace ZipViewInternal
+    {
+        template<class... Rs>
+        /*concept*/ constexpr bool zip_is_common = (sizeof...(Rs) == 1 && (common_range<Rs> && ...)) ||
+            (!(bidirectional_range<Rs> && ...) && (common_range<Rs> && ...)) ||
+            ((random_access_range<Rs> && ...) && (sized_range<Rs> && ...));
+
+        template<class... Ts>
+        using tuple_or_pair = tuple<Ts...>;
+
+        template<class F, class Tuple>
+        constexpr auto tuple_transform(F&& f, Tuple&& tuple)
+        {
+            auto TransformToResultTuple = [&](auto&&... elements)
+            {
+                return tuple_or_pair<invoke_result_t<F&, decltype(elements)>...>(
+                    AZStd::invoke(f, AZStd::forward<decltype(elements)>(elements))...);
+            };
+            return AZStd::apply(AZStd::move(TransformToResultTuple), AZStd::forward<Tuple>(tuple));
+        }
+
+        template<class F, class Tuple>
+        constexpr void tuple_for_each(F&& f, Tuple&& tuple)
+        {
+            auto InvokeTupleElement = [&](auto&&... elements)
+            {
+                (AZStd::invoke(f, AZStd::forward<decltype(elements)>(elements)), ...);
+            };
+            AZStd::apply(AZStd::move(InvokeTupleElement), AZStd::forward<Tuple>(tuple));
+        }
+
+        template<class F, class Tuple1, class Tuple2, size_t... Indices>
+        constexpr decltype(auto) tuple_zip(F&& f, AZStd::index_sequence<Indices...>,
+            Tuple1&& tuple1, Tuple2&& tuple2)
+        {
+            (AZStd::invoke(AZStd::forward<F>(f), AZStd::get<Indices>(tuple1), AZStd::get<Indices>(tuple2)), ...);
+        }
+    }
+
+    template<class... Views>
+    class zip_view
+        : public enable_if_t<conjunction_v<
+        bool_constant<(sizeof...(Views) > 0)>,
+        bool_constant<input_range<Views>>...,
+        bool_constant<view<Views>>...
+    >, view_interface<zip_view<Views...>>>
+    {
+        // [range.zip.iterator], class template zip_view::iterator
+        template<bool>
+        class iterator;
+
+        // [range.zip.sentinel], class template zip_view::sentinel
+        template<bool>
+        class sentinel; // exposition only
+
+    public:
+        zip_view() = default;
+        constexpr explicit zip_view(Views... views);
+
+        template<bool Enable = !conjunction_v<bool_constant<Internal::simple_view<Views>>...>, class = enable_if_t<Enable>>
+        constexpr auto begin();
+        template<bool Enable = conjunction_v<bool_constant<range<const Views>>...>, class = enable_if_t<Enable>>
+        constexpr auto begin() const;
+
+        template<bool Enable = !conjunction_v<bool_constant<Internal::simple_view<Views>>...>, class = enable_if_t<Enable>>
+        constexpr auto end();
+        template<bool Enable = conjunction_v<bool_constant<range<const Views>>...>, class = enable_if_t<Enable>>
+        constexpr auto end() const;
+
+        template<bool Enable = conjunction_v<bool_constant<sized_range<Views>>...>, class = enable_if_t<Enable>>
+        constexpr auto size();
+        template<bool Enable = conjunction_v<bool_constant<sized_range<const Views>>...>, class = enable_if_t<Enable>>
+        constexpr auto size() const;
+
+    private:
+        tuple<Views...> m_views;
+    };
+
+    template<class... Rs>
+    zip_view(Rs&&...)->zip_view<views::all_t<Rs>...>;
+
+    namespace ZipViewInternal
+    {
+        template<bool Const, class... Views>
+        /*concept*/ constexpr bool all_random_access = (random_access_range<::AZStd::ranges::Internal::maybe_const<Const, Views>>&&...);
+        template<bool Const, class... Views>
+        /*concept*/ constexpr bool all_bidirectional = (bidirectional_range<::AZStd::ranges::Internal::maybe_const<Const, Views>>&&...);
+        template<bool Const, class... Views>
+        /*concept*/ constexpr bool all_forward = (forward_range<::AZStd::ranges::Internal::maybe_const<Const, Views>>&&...);
+
+        struct requirements_fulfilled {};
+    }
+
+    template<class... Views>
+    template<bool Const>
+    class zip_view<Views...>::iterator
+        : public enable_if_t<(conjunction_v<
+            bool_constant<(sizeof...(Views) > 0)>,
+            bool_constant<input_range<Views>>...,
+            bool_constant<view<Views>>...>),
+        ZipViewInternal::requirements_fulfilled>
+    {
+        friend class zip_view<Views...>;
+        template<bool>
+        friend class zip_view<Views...>::sentinel;
+        constexpr explicit iterator(ZipViewInternal::tuple_or_pair<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...>);
+    public:
+        using iterator_category = input_iterator_tag; // not always present
+        using iterator_concept = conditional_t<ZipViewInternal::all_random_access<Const, Views...>, random_access_iterator_tag,
+            conditional_t<ZipViewInternal::all_bidirectional<Const, Views...>, bidirectional_iterator_tag,
+            conditional_t<ZipViewInternal::all_forward<Const, Views...>, forward_iterator_tag, input_iterator_tag>>>;
+        using value_type = ZipViewInternal::tuple_or_pair<range_value_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...>;
+        using difference_type = common_type_t<range_difference_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...>;
+
+    private:
+        constexpr auto view_iterator_to_value_tuple(difference_type n) const;
+        template<size_t... Indices>
+        static constexpr auto any_iterator_equal(const iterator& x, const iterator& y, AZStd::index_sequence<Indices...>);
+        template<size_t... Indices>
+        static constexpr auto min_distance_in_views(const iterator& x, const iterator& y, AZStd::index_sequence<Indices...>);
+    public:
+
+        iterator() = default;
+        template<bool Enable = Const && conjunction_v<
+            bool_constant<convertible_to<iterator_t<Views>, iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>>>...>,
+            class = enable_if_t<Enable>>
+        constexpr iterator(iterator<!Const> other);
+
+        constexpr auto operator*() const;
+        constexpr iterator& operator++();
+        constexpr decltype(auto) operator++(int);
+
+        template<bool Enable = ZipViewInternal::all_bidirectional<Const, Views...>, class = enable_if_t<Enable>>
+        constexpr auto operator--()->iterator&;
+        template<bool Enable = ZipViewInternal::all_bidirectional<Const, Views...>, class = enable_if_t<Enable>>
+        constexpr auto operator--(int)->iterator;
+
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        constexpr auto operator+=(difference_type x)->iterator&;
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        constexpr auto operator-=(difference_type x)->iterator&;
+
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        constexpr auto operator[](difference_type n) const;
+
+        // Out-of-line defintions with these friend functions are possible, but quite a mess signature wise
+        // that is why the defintions are inline, instead of
+        // template<bool Const, class... Views>
+        // constexpr auto operator==(const typename zip_views<Views...>::template iterator<Const>& x,
+        //     const typename zip_views<Views...>::template iterator<Const>& y){}
+        template<bool Enable = conjunction_v<bool_constant<equality_comparable<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>>>...>,
+            class = enable_if_t<Enable>>
+        friend constexpr auto operator==(const iterator& x, const iterator& y) -> bool
+        {
+            if constexpr (ZipViewInternal::all_bidirectional<Const, Views...>)
+            {
+                return x.m_current == y.m_current;
+            }
+            else
+            {
+                // Returns true if it at least one of the iterator views are equal
+                return any_iterator_equal(x, y, AZStd::index_sequence_for<Views...>{});
+            }
+        }
+
+        template<bool Enable = conjunction_v<bool_constant<equality_comparable<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>>>...>,
+            class = enable_if_t<Enable>>
+        friend constexpr auto operator!=(const iterator& x, const iterator& y) -> bool
+        {
+            return !(x == y);
+        }
+
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator<(const iterator& x, const iterator& y) -> bool
+        {
+            return x.m_current < y.m_current;
+        }
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator>(const iterator& x, const iterator& y) -> bool
+        {
+            return y.m_current < x.m_current;
+        }
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator<=(const iterator& x, const iterator& y) -> bool
+        {
+            return !(y.m_current < x.m_current);
+        }
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator>=(const iterator& x, const iterator& y) -> bool
+        {
+            return !(x.m_current < y.m_current);
+        }
+        /* Requires C++20 compiler support
+        friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires ZipViewInternal::all_random_access<Const, Views...> &&
+            (three_way_comparable<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>> && ...);
+        */
+
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator+(const iterator& i, difference_type n) -> iterator
+        {
+            auto r = i;
+            r += n;
+            return r;
+        }
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator+(difference_type n, const iterator& i) -> iterator
+        {
+            auto r = i;
+            r += n;
+            return r;
+        }
+        template<bool Enable = ZipViewInternal::all_random_access<Const, Views...>, class = enable_if_t<Enable>>
+        friend constexpr auto operator-(const iterator& i, difference_type n) -> iterator
+        {
+            auto r = i;
+            r -= n;
+            return r;
+        }
+        template<bool Enable = conjunction_v<
+            bool_constant<sized_sentinel_for<
+            iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>,
+            iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>>>...
+            >, class = enable_if_t<Enable>>
+            friend constexpr auto operator-(const iterator& x, const iterator& y) -> difference_type
+        {
+            return min_distance_in_views(x, y, AZStd::index_sequence_for<Views...>{});
+        }
+
+        // customization of iter_move and iter_swap
+        friend constexpr auto iter_move(
+            iterator& i) noexcept(
+            noexcept(ZipViewInternal::tuple_transform(ranges::iter_move, i.m_current)))
+        {
+            return ZipViewInternal::tuple_transform(ranges::iter_move, i.m_current);
+        }
+
+        friend constexpr auto iter_swap(
+            iterator& l,
+            iterator& r) noexcept
+        {
+            static_assert(!conjunction_v<
+                bool_constant<indirectly_swappable<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>>>...>);
+
+            ZipViewInternal::tuple_zip(ranges::iter_swap, l.m_current, r.m_current,
+                AZStd::index_sequence_for<Views...>{});
+        }
+
+    private:
+        ZipViewInternal::tuple_or_pair<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...> m_current;
+    };
+
+    // sentinel type for iterator
+    template<class... Views>
+    template<bool Const>
+    class zip_view<Views...>::sentinel
+        : public enable_if_t<conjunction_v<
+        bool_constant<(sizeof...(Views) > 0)>,
+        bool_constant<input_range<Views>>...,
+        bool_constant<view<Views>>...
+            >, ZipViewInternal::requirements_fulfilled>
+    {
+        friend class zip_view<Views...>;
+        constexpr explicit sentinel(ZipViewInternal::tuple_or_pair<sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...> end);
+
+        template<bool OtherConst, size_t... Indices>
+        static constexpr auto min_distance_between_view_iterators(const iterator<OtherConst>& x,
+            const sentinel& y, AZStd::index_sequence<Indices...>) ->
+            common_type_t<range_difference_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>...>;
+
+        // On MSVC The friend functions are can only access the sentinel struct members
+        // The iterator struct which is a friend of the sentinel struct is NOT a friend
+        // of the friend functions
+        // So a shim is added to provide access to the iterator m_current member
+        template<bool OtherConst>
+        static constexpr auto iterator_accessor(const iterator<OtherConst>& it);
+    public:
+        sentinel() = default;
+        template<bool Enable = Const && conjunction_v<
+            bool_constant<convertible_to<sentinel_t<Views>, sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>>>...>,
+            class = enable_if_t<Enable>>
+        constexpr sentinel(sentinel<!Const> i);
+
+        template<bool OtherConst, class = enable_if_t<conjunction_v<
+            bool_constant<sentinel_for<
+            sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>,
+            iterator_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>>>...>
+            >>
+        friend constexpr auto operator==(const iterator<OtherConst>&x, const sentinel & y) -> bool
+        {
+            // Tracks if any iterator of the Views is equal to a sentinel of the views
+            bool anyIteratorEqual = false;
+            auto CompareIterator = [&anyIteratorEqual](auto&& lhs, auto&& rhs)
+            {
+                anyIteratorEqual = anyIteratorEqual || AZStd::forward<decltype(lhs)>(lhs) == AZStd::forward<decltype(rhs)>(rhs);
+            };
+            ZipViewInternal::tuple_zip(AZStd::move(CompareIterator), AZStd::index_sequence_for<Views...>{},
+                iterator_accessor(x), y.m_end);
+
+            return anyIteratorEqual;
+        }
+
+        template<bool OtherConst>
+        friend constexpr auto operator==(const sentinel & y, const iterator<OtherConst>&x) -> bool
+        {
+            return x == y;
+        }
+        template<bool OtherConst>
+        friend constexpr auto operator!=(const iterator<OtherConst>&x, const sentinel & y) -> bool
+        {
+            return !(x == y);
+        }
+        template<bool OtherConst>
+        friend constexpr auto operator!=(const sentinel & y, const iterator<OtherConst>&x) -> bool
+        {
+            return !(x == y);
+        }
+
+        template<bool OtherConst, class = enable_if_t<conjunction_v<
+            bool_constant<sentinel_for<
+            sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>,
+            iterator_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>>>...>
+            >>
+        friend constexpr auto operator-(const iterator<OtherConst>&x, const sentinel & y) ->
+            common_type_t<range_difference_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>...>
+        {
+            return min_distance_between_view_iterators(x, y, AZStd::index_sequence_for<Views...>{});
+        }
+
+        template<bool OtherConst, class = enable_if_t<conjunction_v<
+            bool_constant<sentinel_for<
+            sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>,
+            iterator_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>>>...>
+            >>
+        friend constexpr auto operator-(const sentinel & y, const iterator<OtherConst>&x) ->
+            common_type_t<range_difference_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>...>
+        {
+            return -(x - y);
+        }
+
+    private:
+        ZipViewInternal::tuple_or_pair<sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...> m_end;
+    };
+} // namespace AZStd::ranges
+
+#include <AzCore/std/ranges/zip_view.inl>

+ 308 - 0
Code/Framework/AzCore/AzCore/std/ranges/zip_view.inl

@@ -0,0 +1,308 @@
+/*
+ * 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/ranges/all_view.h>
+#include <AzCore/std/ranges/ranges_algorithm.h>
+#include <AzCore/std/tuple.h>
+
+namespace AZStd::ranges
+{
+    // public zip_view functions
+    template<class... Views>
+    constexpr zip_view<Views...>::zip_view(Views... views)
+        : m_views{ AZStd::move(views)... }
+    {
+    }
+
+    template<class... Views>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::begin()
+    {
+        return iterator<false>(ZipViewInternal::tuple_transform(ranges::begin, m_views));
+    }
+    template<class... Views>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::begin() const
+    {
+        return iterator<true>(ZipViewInternal::tuple_transform(ranges::begin, m_views));
+    }
+
+    template<class... Views>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::end()
+    {
+        if constexpr (!ZipViewInternal::zip_is_common<Views...>)
+        {
+            return sentinel<false>(ZipViewInternal::tuple_transform(ranges::end, m_views));
+        }
+        else if constexpr ((random_access_range<Views> && ...))
+        {
+            return begin() + iter_difference_t<iterator<false>>(size());
+        }
+        else
+        {
+            return iterator<false>(ZipViewInternal::tuple_transform(ranges::end, m_views));
+        }
+    }
+    template<class... Views>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::end() const
+    {
+        if constexpr (!ZipViewInternal::zip_is_common<const Views...>)
+        {
+            return sentinel<true>(ZipViewInternal::tuple_transform(ranges::end, m_views));
+        }
+        else if constexpr ((random_access_range<const Views> && ...))
+        {
+            return begin() + iter_difference_t<iterator<true>>(size());
+        }
+        else
+        {
+            return iterator<true>(ZipViewInternal::tuple_transform(ranges::end, m_views));
+        }
+    }
+
+    template<class... Views>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::size()
+    {
+        auto GetSizeForViews = [](auto... sizes)
+        {
+            using CommonType = make_unsigned_t<common_type_t<decltype(sizes)...>>;
+            return ranges::min({ CommonType(sizes)... });
+        };
+        return AZStd::apply(AZStd::move(GetSizeForViews), ZipViewInternal::tuple_transform(ranges::size, m_views));
+    }
+    template<class... Views>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::size() const
+    {
+        auto GetSizeForViews = [](auto... sizes)
+        {
+            using CommonType = make_unsigned_t<common_type_t<decltype(sizes)...>>;
+            return ranges::min({ CommonType(sizes)... });
+        };
+        return AZStd::apply(AZStd::move(GetSizeForViews), ZipViewInternal::tuple_transform(ranges::size, m_views));
+    }
+
+
+    // public zip_view::iterator functions
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr zip_view<Views...>::iterator<Const>::iterator(iterator<!Const> other)
+        : m_current(AZStd::move(other.m_current))
+    {
+    }
+
+    template<class... Views>
+    template<bool Const>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator*() const
+    {
+        auto TransformToReference = [](auto& i) -> decltype(auto)
+        {
+            return *i;
+        };
+        return ZipViewInternal::tuple_transform(AZStd::move(TransformToReference), m_current);
+    }
+    template<class... Views>
+    template<bool Const>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator++() -> iterator&
+    {
+        auto PreIncrementIterator = [](auto& i)
+        {
+            ++i;
+        };
+        ZipViewInternal::tuple_for_each(AZStd::move(PreIncrementIterator), m_current);
+        return *this;
+    }
+
+    template<class... Views>
+    template<bool Const>
+    constexpr decltype(auto) zip_view<Views...>::iterator<Const>::operator++(int)
+    {
+        if constexpr (ZipViewInternal::all_forward<Const, Views...>)
+        {
+            auto tmp = *this;
+            ++(*this);
+            return tmp;
+        }
+        else
+        {
+            ++(*this);
+        }
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator--() -> iterator&
+    {
+        auto PreDecrementIterator = [](auto& i)
+        {
+            --i;
+        };
+        ZipViewInternal::tuple_for_each(AZStd::move(PreDecrementIterator), m_current);
+        return *this;
+    }
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator--(int) -> iterator
+    {
+        auto tmp = *this;
+        --* this;
+        return tmp;
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator+=(difference_type x) -> iterator&
+    {
+        auto AddIterator = [&](auto& i)
+        {
+            i += iter_difference_t<decltype(i)>(x);
+        };
+        ZipViewInternal::tuple_for_each(AZStd::move(AddIterator), m_current);
+        return *this;
+    }
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator-=(difference_type x) -> iterator&
+    {
+        auto AddIterator = [&](auto& i)
+        {
+            i -= iter_difference_t<decltype(i)>(x);
+        };
+        ZipViewInternal::tuple_for_each(AZStd::move(AddIterator), m_current);
+        return *this;
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr auto zip_view<Views...>::iterator<Const>::operator[](difference_type n) const
+    {
+        return view_iterator_to_value_tuple(n);
+    }
+
+    // private zip_view::iterator functions
+    template<class... Views>
+    template<bool Const>
+    constexpr zip_view<Views...>::iterator<Const>::iterator(
+        ZipViewInternal::tuple_or_pair<iterator_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...> current)
+        : m_current(AZStd::move(current))
+    {
+    }
+
+    template<class... Views>
+    template<bool Const>
+    constexpr auto zip_view<Views...>::iterator<Const>::view_iterator_to_value_tuple(difference_type n) const
+    {
+        auto TransformToValue = [&](auto& i) -> decltype(auto)
+        {
+            using I = decltype(i);
+            return i[iter_difference_t<I>(n)];
+        };
+        return ZipViewInternal::tuple_transform(AZStd::move(TransformToValue), m_current);
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<size_t... Indices>
+    constexpr auto zip_view<Views...>::iterator<Const>::any_iterator_equal(const iterator& x, const iterator& y,
+        AZStd::index_sequence<Indices...>)
+    {
+        return (... || (AZStd::get<Indices>(x.m_current) == AZStd::get<Indices>(y.m_current)));
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<size_t... Indices>
+    constexpr auto zip_view<Views...>::iterator<Const>::min_distance_in_views(const iterator& x, const iterator& y,
+        AZStd::index_sequence<Indices...>)
+    {
+        AZStd::array iterDistances{
+            ((AZStd::get<Indices>(x.m_current) - AZStd::get<Indices>(y.m_current)), ...) };
+        if (iterDistances.empty())
+        {
+            return difference_type{};
+        }
+
+        auto first = iterDistances.begin();
+        difference_type minDistance = *first++;
+        auto last = iterDistances.end();
+        for (; first != last; ++first)
+        {
+            difference_type absMinDistance = minDistance < 0 ? -minDistance : minDistance;
+            difference_type absDistance = *first < 0 ? -*first : *first;
+            minDistance = absDistance < absMinDistance ? *first : minDistance;
+        }
+
+        return minDistance;
+    }
+
+    // private zip_view::sentinel functions
+    template<class... Views>
+    template<bool Const>
+    constexpr zip_view<Views...>::sentinel<Const>::sentinel(
+        ZipViewInternal::tuple_or_pair<sentinel_t<::AZStd::ranges::Internal::maybe_const<Const, Views>>...> end)
+        : m_end(end)
+    {
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<bool, class>
+    constexpr zip_view<Views...>::sentinel<Const>::sentinel(sentinel<!Const> other)
+        : m_end(AZStd::move(other.m_end))
+    {
+    }
+
+    template<class... Views>
+    template<bool Const>
+    template<bool OtherConst, size_t... Indices>
+    constexpr auto zip_view<Views...>::sentinel<Const>::min_distance_between_view_iterators(
+        const typename zip_view<Views...>::template iterator<OtherConst>& x,
+        const typename zip_view<Views...>::template sentinel<Const>& y,
+        AZStd::index_sequence<Indices...>) ->
+        common_type_t<range_difference_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>...>
+    {
+        using difference_type = common_type_t<range_difference_t<::AZStd::ranges::Internal::maybe_const<OtherConst, Views>>...>;
+        // Tracks if any iterator of the Views is equal to a sentinel of the views
+        AZStd::array iterDistances{
+            ((AZStd::get<Indices>(x.m_current) - AZStd::get<Indices>(y.m_end)), ...) };
+        if (iterDistances.empty())
+        {
+            return difference_type{};
+        }
+
+        auto first = iterDistances.begin();
+        difference_type minDistance = *first++;
+        auto last = iterDistances.end();
+        for (; first != last; ++first)
+        {
+            difference_type absMinDistance = minDistance < 0 ? -minDistance : minDistance;
+            difference_type absDistance = *first < 0 ? -*first : *first;
+            minDistance = absDistance < absMinDistance ? *first : minDistance;
+        }
+
+        return minDistance;
+    }
+    
+    template<class... Views>
+    template<bool Const>
+    template<bool OtherConst>
+    constexpr auto zip_view<Views...>::sentinel<Const>::iterator_accessor(const iterator<OtherConst>& it)
+    {
+        return it.m_current;
+    }
+} // namespace AZStd::ranges

+ 41 - 0
Code/Framework/AzCore/AzCore/std/string/string_view.h

@@ -603,6 +603,23 @@ namespace AZStd
     template <class Element, class Traits = AZStd::char_traits<Element>>
     class basic_string_view
     {
+        template <class R, class = void>
+        static constexpr bool has_operator_basic_string_view = false;
+        template <class R>
+        static constexpr bool has_operator_basic_string_view<R, void_t<
+            decltype(declval<remove_cvref_t<R>>().operator basic_string_view<Element, Traits>())
+            >> = true;
+
+        // If the range has a traits_type element, it must match
+        template <class R, class = void>
+        static constexpr bool range_trait_type_matches = true;
+        template <class R>
+        static constexpr bool range_trait_type_matches<R,
+            enable_if_t<conjunction_v<
+            Internal::sfinae_trigger<typename remove_reference_t<R>::traits_type>,
+            bool_constant<!same_as<typename remove_reference_t<R>::traits_type, Traits>>
+            >>> = false;
+
     public:
         using traits_type = Traits;
         using value_type = Element;
@@ -646,6 +663,25 @@ namespace AZStd
             , m_size(AZStd::to_address(last) - AZStd::to_address(first))
         {}
 
+        // double SFINAE is used to defer evaluation of the contiguous range
+        // until after validating the input type isn't basic_string_view
+        template <typename R,
+            typename = enable_if_t<conjunction_v<
+            bool_constant<!same_as<remove_cvref_t<R>, basic_string_view>>,
+            bool_constant<!convertible_to<const_pointer, R>>
+            >>,
+            typename = enable_if_t<conjunction_v<
+            bool_constant<ranges::contiguous_range<R>>,
+            bool_constant<ranges::sized_range<R>>,
+            bool_constant<same_as<ranges::range_value_t<R>, value_type>>,
+            bool_constant<!has_operator_basic_string_view<R>>,
+            bool_constant<range_trait_type_matches<R>>
+            >>>
+        constexpr basic_string_view(R&& r)
+            : m_begin(ranges::data(r))
+            , m_size(ranges::size(r))
+        {}
+
         constexpr basic_string_view(const basic_string_view&) noexcept = default;
         constexpr basic_string_view(basic_string_view&& other)
         {
@@ -982,6 +1018,11 @@ namespace AZStd
         size_type m_size{};
     };
 
+    template<class It, class End>
+    basic_string_view(It, End)->basic_string_view<iter_value_t<It>>;
+    template<class R>
+    basic_string_view(R&&)->basic_string_view<ranges::range_value_t<R>>;
+
     using string_view = basic_string_view<char>;
     using wstring_view = basic_string_view<wchar_t>;
 

+ 6 - 14
Code/Framework/AzCore/AzCore/std/tuple.h

@@ -19,22 +19,14 @@
 
 namespace AZStd
 {
-    template<class... Types>
-    using tuple = std::tuple<Types...>;
-
-    template<class T>
-    using tuple_size = std::tuple_size<T>;
-
-    template<size_t I, class T>
-    using tuple_element = std::tuple_element<I, T>;
-
-    template<size_t I, class T>
-    using tuple_element_t = typename std::tuple_element<I, T>::type;
+    using std::tuple;
+    using std::tuple_size;
+    using std::tuple_size_v;
+    using std::tuple_element;
+    using std::tuple_element_t;
 
     // Placeholder structure that can be assigned any value with no effect.
-    // This is used by AZStd::tie as placeholder for unused arugments
-    using ignore_t = AZStd::decay_t<decltype(std::ignore)>;
-    decltype(std::ignore) ignore = std::ignore;
+    using std::ignore;
 
     using std::make_tuple;
     using std::tie;

+ 3 - 23
Code/Framework/AzCore/AzCore/std/typetraits/conjunction.h

@@ -7,30 +7,10 @@
  */
 #pragma once
 
-#include <AzCore/std/typetraits/typetraits.h>
-#include <AzCore/std/typetraits/conditional.h>
-#include <AzCore/std/typetraits/integral_constant.h> // for true_type
+#include <type_traits>
 
 namespace AZStd
 {
-    template<class... Bases>
-    struct conjunction
-        : true_type
-    {
-    };
-
-    template<class B1>
-    struct conjunction<B1>
-        : B1
-    {
-    };
-
-    template<class B1, class... Bases>
-    struct conjunction<B1, Bases...>
-        : conditional_t<!B1::value, B1, conjunction<Bases...>>
-    {
-    };
-
-    template<class... Bases>
-    constexpr bool conjunction_v = conjunction<Bases...>::value;
+    using std::conjunction;
+    using std::conjunction_v;
 } // namespace AZStd

+ 3 - 22
Code/Framework/AzCore/AzCore/std/typetraits/disjunction.h

@@ -7,29 +7,10 @@
  */
 #pragma once
 
-#include <AzCore/std/typetraits/integral_constant.h>
-#include <AzCore/std/typetraits/conditional.h>
+#include <type_traits>
 
 namespace AZStd
 {
-    template<class... Bases>
-    struct disjunction
-        : false_type
-    {
-    };
-
-    template<class B1>
-    struct disjunction<B1>
-        : B1
-    {
-    };
-
-    template<class B1, class... Bases>
-    struct disjunction<B1, Bases...>
-        : conditional_t<B1::value, B1, disjunction<Bases...>>
-    {
-    };
-
-    template<class... Bases>
-    constexpr bool disjunction_v = disjunction<Bases...>::value;
+    using std::disjunction;
+    using std::disjunction_v;
 }

+ 12 - 31
Code/Framework/AzCore/AzCore/std/typetraits/is_constructible.h

@@ -13,49 +13,30 @@
 namespace AZStd
 {
     using std::is_constructible;
+    using std::is_constructible_v;
     using std::is_trivially_constructible;
+    using std::is_trivially_constructible_v;
     using std::is_nothrow_constructible;
+    using std::is_nothrow_constructible_v;
 
     using std::is_default_constructible;
+    using std::is_default_constructible_v;
     using std::is_trivially_default_constructible;
+    using std::is_trivially_default_constructible_v;
     using std::is_nothrow_default_constructible;
+    using std::is_nothrow_default_constructible_v;
 
     using std::is_copy_constructible;
+    using std::is_copy_constructible_v;
     using std::is_trivially_copy_constructible;
+    using std::is_trivially_copy_constructible_v;
     using std::is_nothrow_copy_constructible;
+    using std::is_nothrow_copy_constructible_v;
 
     using std::is_move_constructible;
+    using std::is_move_constructible_v;
     using std::is_trivially_move_constructible;
+    using std::is_trivially_move_constructible_v;
     using std::is_nothrow_move_constructible;
-
-    template<class T, class... Args>
-    constexpr bool is_constructible_v = std::is_constructible<T, Args...>::value;
-
-    template<class T, class... Args>
-    constexpr bool is_trivially_constructible_v = std::is_trivially_constructible<T, Args...>::value;
-
-    template<class T, class... Args>
-    constexpr bool is_nothrow_constructible_v = std::is_nothrow_constructible<T, Args...>::value;
-
-    template<class T>
-    constexpr bool is_default_constructible_v = std::is_default_constructible<T>::value;
-    template<class T>
-    constexpr bool is_trivially_default_constructible_v = std::is_trivially_default_constructible<T>::value;
-    template<class T>
-    constexpr bool is_nothrow_default_constructible_v = std::is_nothrow_default_constructible<T>::value;
-
-    template<class T>
-    constexpr bool is_copy_constructible_v = std::is_copy_constructible<T>::value;
-    template<class T>
-    constexpr bool is_trivially_copy_constructible_v = std::is_trivially_copy_constructible<T>::value;
-    template<class T>
-    constexpr bool is_nothrow_copy_constructible_v = std::is_nothrow_copy_constructible<T>::value;
-
-    template<class T>
-    constexpr bool is_move_constructible_v = std::is_move_constructible<T>::value;
-    template<class T>
-    constexpr bool is_trivially_move_constructible_v = std::is_trivially_move_constructible<T>::value;
-    template<class T>
-    constexpr bool is_nothrow_move_constructible_v = std::is_nothrow_move_constructible<T>::value;
-
+    using std::is_nothrow_move_constructible_v;
 }

+ 3 - 9
Code/Framework/AzCore/AzCore/std/typetraits/negation.h

@@ -7,16 +7,10 @@
  */
 #pragma once
 
-#include <AzCore/std/typetraits/integral_constant.h>
+#include <type_traits>
 
 namespace AZStd
 {
-    template<class B>
-    struct negation
-        : integral_constant<bool, !B::value>
-    {
-    };
-
-    template<class B>
-    constexpr bool negation_v = negation<B>::value;
+    using std::negation;
+    using std::negation_v;
 }

+ 12 - 102
Code/Framework/AzCore/AzCore/std/utils.h

@@ -92,36 +92,13 @@ namespace AZStd
     //////////////////////////////////////////////////////////////////////////
 
     // The structure that encapsulates index lists
-    template <size_t... Is>
-    struct index_sequence
-    {
-        static constexpr size_t size = sizeof...(Is);
-    };
-
-    // Collects internal details for generating index ranges [MIN, MAX)
-    namespace Internal
-    {
-        // Declare primary template for index range builder
-        template <size_t MIN, size_t N, size_t... Is>
-        struct range_builder;
-
-        // Base step
-        template <size_t MIN, size_t... Is>
-        struct range_builder<MIN, MIN, Is...>
-        {
-            typedef index_sequence<Is...> type;
-        };
-
-        // Induction step
-        template <size_t MIN, size_t N, size_t... Is>
-        struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
-        {
-        };
-    }
+    using std::integer_sequence;
+    using std::index_sequence;
+    using std::index_sequence_for;
 
     // Create index range [0,N]
-    template<size_t N>
-    using make_index_sequence = typename Internal::range_builder<0, N>::type;
+    using std::make_index_sequence;
+    using std::make_integer_sequence;
 
     struct piecewise_construct_t {};
     static constexpr piecewise_construct_t piecewise_construct{};
@@ -279,31 +256,7 @@ namespace AZStd
     //////////////////////////////////////////////////////////////////////////
     // Address of
     //////////////////////////////////////////////////////////////////////////
-    namespace Internal
-    {
-        template<class T>
-        struct addr_impl_ref
-        {
-            T& m_v;
-            constexpr addr_impl_ref(T& v)
-                : m_v(v) {}
-            constexpr addr_impl_ref& operator=(const addr_impl_ref& v) { m_v = v; return *this; }
-            constexpr operator T& () const { return m_v; }
-        };
-
-        template<class T>
-        struct addressof_impl
-        {
-            static AZ_FORCE_INLINE T* f(T& v, long) { return reinterpret_cast<T*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(v))); }
-            static constexpr T* f(T* v, int)  { return v; }
-        };
-    }
-
-    template<class T>
-    T* addressof(T& v)
-    {
-        return Internal::addressof_impl<T>::f(Internal::addr_impl_ref<T>(v), 0);
-    }
+    using std::addressof;
     // End addressof
     //////////////////////////////////////////////////////////////////////////
 
@@ -446,57 +399,14 @@ namespace AZStd
     };
 #endif
 
-    template <template <class> class, typename...>
-    struct sequence_and;
+    using std::in_place_t;
+    using std::in_place;
 
-    template <template <class> class trait, typename T1, typename... Ts>
-    struct sequence_and<trait, T1, Ts...>
-    {
-        static const bool value = trait<T1>::value && sequence_and<trait, Ts...>::value;
-    };
-
-    template <template <class> class trait>
-    struct sequence_and<trait>
-    {
-        static const bool value = true;
-    };
-
-    template <template <class> class, typename...>
-    struct sequence_or;
+    using std::in_place_type_t;
+    using std::in_place_type;
 
-    template <template <class> class trait, typename T1, typename... Ts>
-    struct sequence_or<trait, T1, Ts...>
-    {
-        static const bool value = trait<T1>::value || sequence_or<trait, Ts...>::value;
-    };
-
-    template <template <class> class trait>
-    struct sequence_or<trait>
-    {
-        static const bool value = false;
-    };
-
-    struct in_place_t
-    {
-        explicit constexpr in_place_t() = default;
-    };
-    constexpr in_place_t in_place{};
-
-    template<typename T>
-    struct in_place_type_t
-    {
-        explicit constexpr in_place_type_t() = default;
-    };
-    template <typename T>
-    constexpr in_place_type_t<T> in_place_type{};
-
-    template<size_t I>
-    struct in_place_index_t
-    {
-        explicit constexpr in_place_index_t() = default;
-    };
-    template<size_t I>
-    constexpr in_place_index_t<I> in_place_index{}; 
+    using std::in_place_index_t;
+    using std::in_place_index;
 
     namespace Internal
     {

+ 119 - 0
Code/Framework/AzCore/Tests/AZStd/ConceptsTests.cpp

@@ -8,6 +8,7 @@
 
 #include <AzCore/UnitTest/TestTypes.h>
 #include <AzCore/std/concepts/concepts.h>
+#include <AzCore/std/ranges/ranges_functional.h>
 
 namespace UnitTest
 {
@@ -199,4 +200,122 @@ namespace UnitTest
         static_assert(!AZStd::strict_weak_order<RelationPredicate, int, Base>);
         static_assert(!AZStd::strict_weak_order<RelationPredicate, Base, int>);
     }
+
+    TEST_F(ConceptsTestFixture, IteratorInvocableConcepts)
+    {
+        // concept indirectly unary invocable
+        // i.e Is deferencing an iterator like type and invoking
+        // a unary callable a well formed expression
+        auto CharUnaryCallable = [](const char) -> int { return {}; };
+        auto IntUnaryCallable = [](int) -> int { return {}; };
+        auto IntRefUnaryCallable = [](int&) -> int { return {}; };
+        static_assert(AZStd::indirectly_unary_invocable<decltype(CharUnaryCallable), AZStd::string_view::iterator>);
+        static_assert(AZStd::indirectly_unary_invocable<decltype(IntUnaryCallable), AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirectly_unary_invocable<decltype(IntRefUnaryCallable), AZStd::string_view::iterator>);
+
+        // concept indirectly regular unary invocable
+        // i.e Is deferencing an iterator like type and invoking with a unary callable
+        // which will not modify the input arguments(hence the term "regular") a well formed expression
+        static_assert(AZStd::indirectly_regular_unary_invocable<decltype(CharUnaryCallable), AZStd::string_view::iterator>);
+        static_assert(AZStd::indirectly_regular_unary_invocable<decltype(IntUnaryCallable), AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirectly_regular_unary_invocable<decltype(IntRefUnaryCallable), AZStd::string_view::iterator>);
+
+        // concept indirect unary predicate
+        // i.e Is deferencing an iterator like type and invoking with a unary predicate
+        // i.e which is a callable that accepts one argument and returns value testable in a boolean context
+        auto CharUnaryPredicate = [](const char) -> bool { return {}; };
+        auto IntUnaryPredicate = [](int) -> int { return {}; };// Return value is an int which is convertible to bool
+        auto IntRefUnaryPredicate = [](int&) -> int { return {}; }; // string_view iterator value type(char) can't bind to an int&
+        auto CharUnaryNonPredicate = [](const char) -> AZStd::string_view { return {}; }; // string_view is not convertible to bool
+
+        static_assert(AZStd::indirect_unary_predicate<decltype(CharUnaryPredicate), AZStd::string_view::iterator>);
+        static_assert(AZStd::indirect_unary_predicate<decltype(IntUnaryPredicate), AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirect_unary_predicate<decltype(IntRefUnaryPredicate), AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirect_unary_predicate<decltype(CharUnaryNonPredicate), AZStd::string_view::iterator>);
+
+        // concept indirect binary predicate
+        // i.e Is deferencing two iterator like types and invoking a binary predicate with those values
+        // well formed and returns value testable in a boolean context.
+        auto CharIntBinaryPredicate = [](const char, int) -> bool { return{}; };
+        auto CharCharRefBinaryPredicate = [](const char, const char&) -> uint32_t { return{}; };
+        auto UIntRefCharBinaryPredicate = [](uint32_t&, char) -> bool { return{}; };
+        auto CharCharBinaryNonPredicate = [](const char, const char) -> AZStd::string_view { return {}; };
+
+        static_assert(AZStd::indirect_binary_predicate<decltype(CharIntBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(AZStd::indirect_binary_predicate<decltype(CharCharRefBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        // string_view iterator value type(char) cannot bind to int&
+        static_assert(!AZStd::indirect_binary_predicate<decltype(UIntRefCharBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        // string_view is not convertible to bool
+        static_assert(!AZStd::indirect_binary_predicate<decltype(CharCharBinaryNonPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        // Ok - iter_reference_t<uint32_t*> = uint32_t&
+        static_assert(AZStd::indirect_binary_predicate<decltype(UIntRefCharBinaryPredicate),
+            uint32_t*, AZStd::string_view::iterator>);
+
+        // concept indirect equivalence relation
+        // i.e Is deferencing two iterator like types and invoking a binary predicate with those values
+        // well formed and returns value testable in a boolean context.
+        // The dereferenced iterator types should be model an equivalence relationship
+        // (a == b) && (b == c) == (a ==c)
+        static_assert(AZStd::indirect_equivalence_relation<decltype(CharIntBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(AZStd::indirect_equivalence_relation<decltype(CharCharRefBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirect_equivalence_relation<decltype(UIntRefCharBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirect_equivalence_relation<decltype(CharCharBinaryNonPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        // The "relation" concept requires that both both arguments can be bind to
+        // either of the two binary parameters
+        static_assert(!AZStd::indirect_equivalence_relation<decltype(UIntRefCharBinaryPredicate),
+            uint32_t*, AZStd::string_view::iterator>);
+
+        // concept indirect strict weak order
+        // i.e Is deferencing two iterator like types and invoking a binary predicate with those values
+        // well formed and returns value testable in a boolean context.
+        // The dereferenced iterator types should be model a strict weak order relation
+        // (a < b) && (b < c) == (a < c)
+        static_assert(AZStd::indirect_strict_weak_order<decltype(CharIntBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(AZStd::indirect_strict_weak_order<decltype(CharCharRefBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirect_strict_weak_order<decltype(UIntRefCharBinaryPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        static_assert(!AZStd::indirect_strict_weak_order<decltype(CharCharBinaryNonPredicate),
+            AZStd::string_view::iterator, AZStd::string_view::iterator>);
+        // The "relation" concept requires that both both arguments can be bind to
+        // either of the two binary parameters
+        static_assert(!AZStd::indirect_strict_weak_order<decltype(UIntRefCharBinaryPredicate),
+            uint32_t*, AZStd::string_view::iterator>);
+
+        // indirect_result_t type alias
+        static_assert(AZStd::same_as<AZStd::indirect_result_t<decltype(CharCharRefBinaryPredicate),
+            AZStd::string_view::iterator, const char*>, uint32_t>);
+
+        // projected operator* returns indirect result of the projection function
+        static_assert(AZStd::same_as<AZStd::iter_reference_t<AZStd::projected<int*, AZStd::identity>>, int&>);
+    }
+
+    TEST_F(ConceptsTestFixture, IteratorAlgorithmConcepts)
+    {
+        static_assert(AZStd::indirectly_swappable<int*, int*>);
+        static_assert(!AZStd::indirectly_swappable<int*, const int*>);
+        auto CharIntIndirectlyComparable = [](const char lhs, int rhs) -> bool { return lhs == rhs; };
+        static_assert(AZStd::indirectly_comparable<const char*, int*, decltype(CharIntIndirectlyComparable)>);
+        static_assert(!AZStd::indirectly_comparable<AZStd::string_view, int*, decltype(CharIntIndirectlyComparable)>);
+
+        static_assert(AZStd::permutable<typename AZStd::vector<int>::iterator>);
+        // const iterator isn't indirectlly swappable or indirectly movable
+        static_assert(!AZStd::permutable<typename AZStd::vector<int>::const_iterator>);
+
+        static_assert(AZStd::mergeable<AZStd::vector<int>::iterator, AZStd::string_view::iterator, AZStd::vector<int>::iterator>);
+        static_assert(!AZStd::mergeable<AZStd::vector<int>::iterator, AZStd::string_view::iterator, AZStd::string_view::iterator>);
+
+        static_assert(AZStd::sortable<int*>);
+        // Not sortable becaue the iter_reference_t<const int*> = const int& which isn't swappable
+        static_assert(!AZStd::sortable<const int*>);
+    }
 }

+ 250 - 0
Code/Framework/AzCore/Tests/AZStd/RangesAlgorithmTests.cpp

@@ -0,0 +1,250 @@
+/*
+ * 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/UnitTest/TestTypes.h>
+#include <AzCore/std/string/string_view.h>
+#include <AzCore/std/ranges/ranges_algorithm.h>
+
+namespace UnitTest
+{
+    class RangesAlgorithmTestFixture
+        : public ScopedAllocatorSetupFixture
+    {};
+
+    // range algorithm min and max
+    TEST_F(RangesAlgorithmTestFixture, RangesMin_ReturnsSmallestElement)
+    {
+        // Simple Elements
+        EXPECT_EQ(-1, AZStd::ranges::min(5, -1));
+        EXPECT_EQ(78235, AZStd::ranges::min(78235, 124785));
+        EXPECT_EQ(7, AZStd::ranges::min(7, 7));
+
+        // Initializer list
+        AZStd::initializer_list<int> testIList{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        EXPECT_EQ(-8, AZStd::ranges::min(testIList));
+
+        // Range
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        EXPECT_EQ(-8, AZStd::ranges::min(testVector));
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesMax_ReturnsLargestElement)
+    {
+        // Simple Elements
+        EXPECT_EQ(5, AZStd::ranges::max(5, -1));
+        EXPECT_EQ(124785, AZStd::ranges::max(78235, 124785));
+        EXPECT_EQ(7, AZStd::ranges::max(7, 7));
+
+        // Initializer list
+        AZStd::initializer_list<int> testIList{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        EXPECT_EQ(1000, AZStd::ranges::max(testIList));
+
+        // Range
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        EXPECT_EQ(1000, AZStd::ranges::max(testVector));
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesMinMax_ReturnsSmallestAndLargestValue)
+    {
+        // Simple Elements
+        AZStd::ranges::minmax_result<int> expectedMinMax{ -1, 5 };
+        AZStd::ranges::minmax_result<int> testMinMax = AZStd::ranges::minmax(5, -1);
+        EXPECT_EQ(expectedMinMax.min, testMinMax.min);
+        EXPECT_EQ(expectedMinMax.max, testMinMax.max);
+
+        expectedMinMax = { 78235, 124785 };
+        testMinMax = AZStd::ranges::minmax(78235, 124785);
+        EXPECT_EQ(expectedMinMax.min, testMinMax.min);
+        EXPECT_EQ(expectedMinMax.max, testMinMax.max);
+
+        expectedMinMax = { 7, 7 };
+        testMinMax = AZStd::ranges::minmax(7, 7);
+        EXPECT_EQ(expectedMinMax.min, testMinMax.min);
+        EXPECT_EQ(expectedMinMax.max, testMinMax.max);
+
+        // Initializer list
+        AZStd::initializer_list<int> testIList{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        expectedMinMax = { -8, 1000 };
+        testMinMax = AZStd::ranges::minmax(testIList);
+        EXPECT_EQ(expectedMinMax.min, testMinMax.min);
+        EXPECT_EQ(expectedMinMax.max, testMinMax.max);
+
+        // Range
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        expectedMinMax = { -8, 1000 };
+        testMinMax = AZStd::ranges::minmax(testVector);
+        EXPECT_EQ(expectedMinMax.min, testMinMax.min);
+        EXPECT_EQ(expectedMinMax.max, testMinMax.max);
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesMinElement_ReturnsIteratorToLeftmostSmallestElement)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        // iterator
+        auto leftmostSmallestIt = AZStd::ranges::min_element(testVector.begin(), testVector.end());
+        ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
+        EXPECT_EQ(-8, *leftmostSmallestIt);
+
+        // Range
+        leftmostSmallestIt = AZStd::ranges::min_element(testVector);
+        ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
+        EXPECT_EQ(-8, *leftmostSmallestIt);
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesMaxElement_ReturnsIteratorToLeftmostLargestElement)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        // iterator
+        auto leftmostLargestIt = AZStd::ranges::max_element(testVector.begin(), testVector.end());
+        ASSERT_EQ(testVector.begin() + 6, leftmostLargestIt);
+        EXPECT_EQ(1000, *leftmostLargestIt);
+
+        // Range
+        leftmostLargestIt = AZStd::ranges::max_element(testVector);
+        ASSERT_EQ(testVector.begin() + 6, leftmostLargestIt);
+        EXPECT_EQ(1000, *leftmostLargestIt);
+    }
+    TEST_F(RangesAlgorithmTestFixture, RangesMinMaxElement_ReturnsIteratorToLeftmostSmallestElement_IteratorToRightmostLargestElement)
+    {
+        // The behavior of minmax_element is explicitly different from max_element
+        // as it relates to the max element being returned
+        // mixmax_element returns the rightmost largest element(assuming comparison function object is ranges::less)
+        // https://eel.is/c++draft/algorithms#footnoteref-225
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+        // iterator
+        {
+            auto [leftmostSmallestIt, rightmostLargestIt] = AZStd::ranges::minmax_element(testVector.begin(), testVector.end());
+            ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
+            ASSERT_EQ(testVector.begin() + 10, rightmostLargestIt);
+            EXPECT_EQ(-8, *leftmostSmallestIt);
+            EXPECT_EQ(1000, *rightmostLargestIt);
+        }
+
+        // Range
+        auto [leftmostSmallestIt, rightmostLargestIt] = AZStd::ranges::minmax_element(testVector);
+        ASSERT_EQ(testVector.begin() + 4, leftmostSmallestIt);
+        ASSERT_EQ(testVector.begin() + 10, rightmostLargestIt);
+        EXPECT_EQ(-8, *leftmostSmallestIt);
+        EXPECT_EQ(1000, *rightmostLargestIt);
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesFind_LocatesElementInContainer_Succeeds)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+
+        auto foundIt = AZStd::ranges::find(testVector, 22);
+        ASSERT_NE(testVector.end(), foundIt);
+        EXPECT_EQ(22, *foundIt);
+
+        foundIt = AZStd::ranges::find_if(testVector, [](int value) { return value < 0; });
+        ASSERT_NE(testVector.end(), foundIt);
+        EXPECT_EQ(-8, *foundIt);
+
+        foundIt = AZStd::ranges::find_if_not(testVector, [](int value) { return value < 1000; });
+        ASSERT_NE(testVector.end(), foundIt);
+        EXPECT_EQ(1000, *foundIt);
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesFindFirstOf_LocatesElementInContainer_Succeeds)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, 1000, 45 };
+
+        AZStd::array testArray{ -8, 47 };
+        auto foundIt = AZStd::ranges::find_first_of(testVector, testArray);
+        ASSERT_NE(testVector.end(), foundIt);
+        EXPECT_EQ(47, *foundIt);
+
+        AZStd::array<int, 0> emptyArray{};
+        foundIt = AZStd::ranges::find_first_of(testVector, emptyArray);
+        EXPECT_EQ(testVector.end(), foundIt);
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesSearch_LocatesElementInContainer_Succeeds)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45 };
+
+        AZStd::array testArray{ 1000 };
+        auto testSubrange = AZStd::ranges::search(testVector, testArray);
+        ASSERT_FALSE(testSubrange.empty());
+        EXPECT_EQ(1000, testSubrange.front());
+
+        AZStd::array testArray2{ 1000, 45 };
+        testSubrange = AZStd::ranges::search(testVector, testArray2);
+        ASSERT_EQ(2, testSubrange.size());
+        EXPECT_EQ(1000, testSubrange[0]);
+        EXPECT_EQ(45, testSubrange[1]);
+
+        testSubrange = AZStd::ranges::search_n(testVector, 1, 22);
+        ASSERT_FALSE(testSubrange.empty());
+        EXPECT_EQ(22, testSubrange.front());
+
+        // 2 Consecutive values of 22 does not exist in vector
+        testSubrange = AZStd::ranges::search_n(testVector, 2, 22);
+        EXPECT_TRUE(testSubrange.empty());
+
+        // 2 Consecutive values of -8 does exist in vector
+        testSubrange = AZStd::ranges::search_n(testVector, 2,- 8);
+        ASSERT_EQ(2, testSubrange.size());
+        EXPECT_EQ(-8, testSubrange[0]);
+        EXPECT_EQ(-8, testSubrange[1]);
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesFindEnd_LocatesElementLastElement_Succeeds)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45 };
+
+        AZStd::array testArray{ -8 };
+        auto testSubrange = AZStd::ranges::find_end(testVector, testArray);
+        ASSERT_FALSE(testSubrange.empty());
+        EXPECT_EQ(-8, testSubrange.front());
+        EXPECT_EQ(testVector.end() - 3, testSubrange.begin());
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesEqual_IsAbleToCompareTwoRanges_Succeeds)
+    {
+        AZStd::vector testVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45 };
+        AZStd::vector longerVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000, 45, 929 };
+        AZStd::vector shorterVector{ 5, 1, 22, 47, -8, -5, 1000, 687, 22, -8, -8, 1000 };
+        AZStd::vector unequalVector{ 5, 1, 22, 47, -8, -5, 1000, 14, 22, -8, -8, 1000, 25 };
+
+        EXPECT_TRUE(AZStd::ranges::equal(testVector, testVector));
+        EXPECT_FALSE(AZStd::ranges::equal(testVector, longerVector));
+        EXPECT_FALSE(AZStd::ranges::equal(longerVector, testVector));
+        EXPECT_FALSE(AZStd::ranges::equal(testVector, shorterVector));
+        EXPECT_FALSE(AZStd::ranges::equal(shorterVector, testVector));
+        EXPECT_FALSE(AZStd::ranges::equal(testVector, unequalVector));
+    }
+
+    TEST_F(RangesAlgorithmTestFixture, RangesMismatch_Returns_IteratorsToMismatchElements)
+    {
+        AZStd::vector testVector{ 1, 2, 3, 4, 5 ,6 };
+        AZStd::vector secondVector{ 1, 2, 3, 14, 5, 6 };
+        AZStd::vector<int> emptyVector;
+        AZStd::vector<int> longerVector{ 1, 2, 3, 4, 5, 6, 7 };
+
+        {
+            auto [mismatchIt1, mismatchIt2] = AZStd::ranges::mismatch(testVector, secondVector);
+            ASSERT_NE(testVector.end(), mismatchIt1);
+            EXPECT_EQ(4, *mismatchIt1);
+            ASSERT_NE(secondVector.end(), mismatchIt2);
+            EXPECT_EQ(14, *mismatchIt2);
+        }
+        {
+            auto [mismatchIt1, mismatchIt2] = AZStd::ranges::mismatch(testVector, emptyVector);
+            ASSERT_NE(testVector.end(), mismatchIt1);
+            EXPECT_EQ(1, *mismatchIt1);
+            EXPECT_EQ(emptyVector.end(), mismatchIt2);
+        }
+        {
+            auto [mismatchIt1, mismatchIt2] = AZStd::ranges::mismatch(testVector, longerVector);
+            EXPECT_EQ(testVector.end(), mismatchIt1);
+            ASSERT_NE(longerVector.end(), mismatchIt2);
+            EXPECT_EQ(7, *mismatchIt2);
+        }
+    }
+}

+ 483 - 0
Code/Framework/AzCore/Tests/AZStd/RangesViewTests.cpp

@@ -0,0 +1,483 @@
+/*
+ * 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/UnitTest/TestTypes.h>
+#include <AzCore/std/containers/list.h>
+#include <AzCore/std/containers/map.h>
+#include <AzCore/std/containers/vector.h>
+#include <AzCore/std/ranges/all_view.h>
+#include <AzCore/std/ranges/elements_view.h>
+#include <AzCore/std/ranges/empty_view.h>
+#include <AzCore/std/ranges/join_view.h>
+#include <AzCore/std/ranges/ranges_adaptor.h>
+#include <AzCore/std/ranges/single_view.h>
+#include <AzCore/std/ranges/split_view.h>
+#include <AzCore/std/ranges/subrange.h>
+#include <AzCore/std/ranges/zip_view.h>
+#include <AzCore/std/string/string_view.h>
+
+namespace UnitTest
+{
+    class RangesViewTestFixture
+        : public ScopedAllocatorSetupFixture
+    {};
+
+    TEST_F(RangesViewTestFixture, AllRangeAdaptor_Succeeds)
+    {
+        AZStd::string_view testString{ "Hello World" };
+        auto testAllView = AZStd::ranges::views::all(testString);
+        EXPECT_EQ(testString.size(), testAllView.size());
+        EXPECT_EQ(testString.data(), testAllView.data());
+        EXPECT_EQ(testString.begin(), testAllView.begin());
+        EXPECT_EQ(testString.end(), testAllView.end());
+        EXPECT_EQ(testString.empty(), testAllView.empty());
+        EXPECT_EQ(testString.front(), testAllView.front());
+        EXPECT_EQ(testString.back(), testAllView.back());
+        EXPECT_EQ(testString[5], testAllView[5]);
+
+        auto testAllViewChain = testString | AZStd::ranges::views::all;
+        EXPECT_EQ(testString.size(), testAllViewChain.size());
+        EXPECT_EQ(testString.data(), testAllViewChain.data());
+        EXPECT_EQ(testString.begin(), testAllViewChain.begin());
+        EXPECT_EQ(testString.end(), testAllViewChain.end());
+        EXPECT_EQ(testString.empty(), testAllViewChain.empty());
+        EXPECT_EQ(testString.front(), testAllViewChain.front());
+        EXPECT_EQ(testString.back(), testAllViewChain.back());
+        EXPECT_EQ(testString[5], testAllViewChain[5]);
+    }
+
+    TEST_F(RangesViewTestFixture, Subrange_DeductionGuides_Compile)
+    {
+        AZStd::string_view testString{ "Hello World" };
+        AZStd::ranges::subrange rangeDeduction(testString);
+        AZStd::ranges::subrange rangeDeductionWithSize(testString, testString.size());
+        AZStd::ranges::subrange iteratorDeduction(testString.begin(), testString.end());
+        AZStd::ranges::subrange iteratorDeductionWithSize(testString.begin(), testString.end(),
+            testString.size());
+        EXPECT_TRUE(rangeDeduction);
+        EXPECT_TRUE(rangeDeductionWithSize);
+        EXPECT_TRUE(iteratorDeduction);
+        EXPECT_TRUE(iteratorDeductionWithSize);
+    }
+
+    TEST_F(RangesViewTestFixture, Subrange_CanTakeSubsetOfContainer_Succeeds)
+    {
+        AZStd::vector<int> testVector{ 1, 3, 5, 6, 7, 6, 89, -178 };
+        AZStd::ranges::subrange subVector(testVector);
+        EXPECT_TRUE(subVector);
+        ASSERT_FALSE(subVector.empty());
+        EXPECT_EQ(testVector.data(), subVector.data());
+        EXPECT_EQ(testVector.begin(), subVector.begin());
+        EXPECT_EQ(testVector.end(), subVector.end());
+        EXPECT_EQ(testVector.size(), subVector.size());
+        EXPECT_EQ(testVector[0], subVector[0]);
+        EXPECT_EQ(testVector.front(), subVector.front());
+        EXPECT_EQ(testVector.back(), subVector.back());
+
+        // Now validate the iterator operations
+        subVector.advance(2);
+        subVector = subVector.prev();
+        subVector.advance(2);
+        subVector = subVector.next();
+        subVector.advance(-4);
+        EXPECT_EQ(testVector.begin(), subVector.begin());
+
+        // Obtain a copy of the subrange with the first and last elements removed
+        AZStd::ranges::subrange subVectorSplice(subVector.begin() + 1, subVector.end() - 1);
+        EXPECT_TRUE(subVectorSplice);
+        ASSERT_FALSE(subVector.empty());
+        EXPECT_LT(testVector.data(), subVectorSplice.data());
+        EXPECT_EQ(testVector.begin() + 1, subVectorSplice.begin());
+        EXPECT_EQ(testVector.end() - 1, subVectorSplice.end());
+        ASSERT_EQ(testVector.size() - 2, subVectorSplice.size());
+        EXPECT_EQ(testVector[1], subVectorSplice.front());
+        EXPECT_EQ(testVector[testVector.size() - 2], subVectorSplice.back());
+        EXPECT_NE(testVector.front(), subVectorSplice.front());
+        EXPECT_NE(testVector.back(), subVectorSplice.back());
+
+
+    }
+
+    TEST_F(RangesViewTestFixture, EmptyView_ReturnsEmptyViewRange_Succeeds)
+    {
+        AZStd::ranges::empty_view<int> emptyView;
+
+        EXPECT_EQ(nullptr, emptyView.data());
+        EXPECT_EQ(0, emptyView.size());
+        EXPECT_TRUE(emptyView.empty());
+        EXPECT_EQ(emptyView.end(), emptyView.begin());
+
+        EXPECT_EQ(nullptr, AZStd::ranges::views::empty<AZStd::string_view>.data());
+        EXPECT_EQ(0, AZStd::ranges::views::empty<AZStd::string_view>.size());
+        EXPECT_TRUE(AZStd::ranges::views::empty<AZStd::string_view>.empty());
+        EXPECT_EQ(AZStd::ranges::views::empty<AZStd::string_view>.end(), AZStd::ranges::views::empty<AZStd::string_view>.begin());
+    }
+
+    TEST_F(RangesViewTestFixture, SingleView_ReturnsViewOverSingleElement_Succeeds)
+    {
+        AZStd::string_view testString{ "Hello World" };
+        AZStd::ranges::single_view singleView{ AZStd::move(testString) };
+        EXPECT_NE(nullptr, singleView.data());
+        EXPECT_EQ(1, singleView.size());
+        EXPECT_FALSE(singleView.empty());
+        ASSERT_NE(singleView.end(), singleView.begin());
+
+        auto singleViewStringIt = singleView.begin();
+        EXPECT_EQ("Hello World", *singleViewStringIt);
+    }
+
+    TEST_F(RangesViewTestFixture, RefView_CanWrapStringView_Succeeds)
+    {
+        AZStd::string_view testString{ "Hello World" };
+        AZStd::ranges::ref_view refView(testString);
+        EXPECT_EQ(testString.size(), refView.size());
+        EXPECT_EQ(testString.data(), refView.data());
+        EXPECT_EQ(testString.begin(), refView.begin());
+        EXPECT_EQ(testString.end(), refView.end());
+        EXPECT_EQ(testString.empty(), refView.empty());
+        EXPECT_EQ(testString.front(), refView.front());
+        EXPECT_EQ(testString.back(), refView.back());
+        EXPECT_EQ(testString[5], refView[5]);
+    }
+
+    TEST_F(RangesViewTestFixture, OwningView_CanWrapStringView_Succeeds)
+    {
+        AZStd::string_view sourceView{ "Hello World" };
+        AZStd::string_view testString{ sourceView };
+        AZStd::ranges::owning_view owningView(AZStd::move(testString));
+        EXPECT_TRUE(testString.empty());
+        EXPECT_FALSE(owningView.empty());
+        EXPECT_EQ(sourceView.size(), owningView.size());
+        EXPECT_EQ(sourceView.data(), owningView.data());
+        EXPECT_EQ(sourceView.begin(), owningView.begin());
+        EXPECT_EQ(sourceView.end(), owningView.end());
+        EXPECT_EQ(sourceView.empty(), owningView.empty());
+        EXPECT_EQ(sourceView.front(), owningView.front());
+        EXPECT_EQ(sourceView.back(), owningView.back());
+        EXPECT_EQ(sourceView[5], owningView[5]);
+    }
+
+    MATCHER_P(ZipViewAtSentinel, sentinel, "") {
+        *result_listener << "zip view has iterated to sentinel";
+        return !(arg == sentinel);
+    }
+    TEST_F(RangesViewTestFixture, ZipView_CompilesWithRange_Succeeds)
+    {
+        AZStd::string_view sourceView{ "Hello World" };
+        AZStd::ranges::zip_view zipView(AZStd::move(sourceView));
+        auto zipItTuple = zipView.begin();
+        auto zipSentinelTuple = zipView.end();
+        ASSERT_THAT(zipItTuple, ZipViewAtSentinel(zipSentinelTuple));
+        EXPECT_EQ('H', AZStd::get<0>(*zipItTuple));
+        ptrdiff_t zipDistance = zipSentinelTuple - zipItTuple;
+        EXPECT_EQ(11, zipDistance);
+
+        AZStd::list<int> sourceList{ 1, 2, 3, 4, 5 };
+        AZStd::ranges::zip_view zipView2(AZStd::move(sourceList));
+        auto zipListTupleIt = zipView2.begin();
+        auto zipListTupleEnd = zipView2.end();
+        ASSERT_THAT(zipListTupleIt, ZipViewAtSentinel(zipListTupleEnd));
+    }
+
+    TEST_F(RangesViewTestFixture, ZipView_CanIteratOverMultipleContainers_Succeeds)
+    {
+        AZStd::string_view sourceView{ "abcdef" };
+        AZStd::vector intVector{ 1, 2, 3, 4, 5 };
+        AZStd::list<uint32_t> uintList{ 2, 4, 6, 8, 10 };
+        constexpr int expectedIterations = 5;
+
+        int iterationCount{};
+        for (auto [charX, intY, uintZ] : (AZStd::ranges::views::zip(sourceView, AZStd::move(intVector), AZStd::move(uintList))))
+        {
+            ++iterationCount;
+            switch (charX)
+            {
+            case 'a':
+                EXPECT_EQ(1, intY);
+                EXPECT_EQ(2, uintZ);
+                break;
+            case 'b':
+                EXPECT_EQ(2, intY);
+                EXPECT_EQ(4, uintZ);
+                break;
+            case 'c':
+                EXPECT_EQ(3, intY);
+                EXPECT_EQ(6, uintZ);
+                break;
+            case 'd':
+                EXPECT_EQ(4, intY);
+                EXPECT_EQ(8, uintZ);
+                break;
+            case 'e':
+                EXPECT_EQ(5, intY);
+                EXPECT_EQ(10, uintZ);
+                break;
+            default:
+                ADD_FAILURE() << "Unexpected character value " << charX << " found when iterating zip view";
+            }
+        }
+
+        EXPECT_EQ(expectedIterations, iterationCount);
+    }
+
+    TEST_F(RangesViewTestFixture, SplitView_CanSplitPatterns_Succeeds)
+    {
+        AZStd::string_view emptyView{ "" };
+        auto splitView = AZStd::ranges::views::split(emptyView, " ");
+        auto splitIt = splitView.begin();
+        EXPECT_EQ(splitView.end(), splitIt);
+
+        AZStd::string_view testView1{ "Hello" };
+        auto splitViewCharPattern = AZStd::ranges::views::split(testView1, ' ');
+        auto splitCharIt = splitViewCharPattern.begin();
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
+
+        AZStd::string_view testView2{ "Hello World" };
+        splitViewCharPattern = AZStd::ranges::views::split(testView2, ' ');
+        splitCharIt = splitViewCharPattern.begin();
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
+
+        AZStd::string_view testView3{ "Hello World Moon" };
+        splitViewCharPattern = AZStd::ranges::views::split(testView3, ' ');
+        splitCharIt = splitViewCharPattern.begin();
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
+
+
+        AZStd::string_view testView4{ "Hello World Moon " };
+        splitViewCharPattern = AZStd::ranges::views::split(testView4, ' ');
+        splitCharIt = splitViewCharPattern.begin();
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
+
+        AZStd::string_view testView5{ "Hello World Moon  " };
+        splitViewCharPattern = AZStd::ranges::views::split(testView5, ' ');
+        splitCharIt = splitViewCharPattern.begin();
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
+
+        AZStd::string_view testView6{ "Hello  World Moon" };
+        splitViewCharPattern = AZStd::ranges::views::split(testView6, ' ');
+        splitCharIt = splitViewCharPattern.begin();
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Hello", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("World", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        ASSERT_NE(splitViewCharPattern.end(), splitCharIt);
+        EXPECT_EQ("Moon", AZStd::string_view(*splitCharIt));
+        ++splitCharIt;
+        EXPECT_EQ(splitViewCharPattern.end(), splitCharIt);
+    }
+
+    TEST_F(RangesViewTestFixture, SplitView_SplitsFromNonString_Succeeds)
+    {
+        const AZStd::vector<int> testVector{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+        // Split the vector on 3
+        auto splitView = AZStd::ranges::views::split(testVector, 3);
+        auto splitIt = splitView.begin();
+        ASSERT_NE(splitView.end(), splitIt);
+        auto splitSubrange = *splitIt;
+        {
+            AZStd::array expectedValue{ 1, 2 };
+            EXPECT_TRUE(AZStd::ranges::equal(expectedValue, splitSubrange));
+        }
+
+        ++splitIt;
+        ASSERT_NE(splitView.end(), splitIt);
+        splitSubrange = *splitIt;
+        {
+            AZStd::array expectedValue{ 4, 5, 6, 7, 8, 9, 10 };
+            EXPECT_TRUE(AZStd::ranges::equal(expectedValue, splitSubrange));
+        }
+    }
+
+    TEST_F(RangesViewTestFixture, JoinView_IteratesOverInnerViews_Succeeds)
+    {
+        constexpr AZStd::string_view expectedString = "HelloWorldMoonSun";
+        using Rope = AZStd::fixed_vector<AZStd::string_view, 32>;
+        Rope rope{ "Hello", "World", "Moon", "Sun" };
+        AZStd::fixed_string<128> accumString;
+        for (auto&& charElement : AZStd::ranges::join_view(rope))
+        {
+            accumString.push_back(charElement);
+        }
+
+        EXPECT_EQ(expectedString, accumString);
+    }
+
+    TEST_F(RangesViewTestFixture, JoinView_IteratesCanIterateOverSplitView_Succeeds)
+    {
+        constexpr AZStd::string_view expectedString = "HelloWorldMoonSun";
+        constexpr AZStd::string_view splitExpression = "Hello,World,Moon,Sun";
+        AZStd::fixed_string<128> accumString;
+
+        for (auto&& charElement : AZStd::ranges::views::join(AZStd::ranges::views::split(splitExpression, ',')))
+        {
+            accumString.push_back(charElement);
+        }
+
+        EXPECT_EQ(expectedString, accumString);
+    }
+
+    TEST_F(RangesViewTestFixture, JoinView_IterSwapCustomization_Succeeds)
+    {
+        AZStd::fixed_vector<AZStd::string, 8> testVector1{ "World", "Hello" };
+        AZStd::fixed_vector<AZStd::string, 8> testVector2{ "Value", "First" };
+        auto joinView1 = AZStd::ranges::views::join(testVector1);
+        auto joinView2 = AZStd::ranges::views::join(testVector2);
+        auto joinViewIter1 = joinView1.begin();
+        auto joinViewIter2 = joinView2.begin();
+        // swaps the 'W' and 'V'
+        AZStd::ranges::iter_swap(joinViewIter1, joinViewIter2);
+        AZStd::ranges::advance(joinViewIter1, 5, joinView1.end());
+        AZStd::ranges::advance(joinViewIter2, 5, joinView2.end());
+        // swaps the 'H' and 'F' of the second string of each vector
+        AZStd::ranges::iter_swap(joinViewIter1, joinViewIter2);
+        EXPECT_EQ("Vorld", testVector1[0]);
+        EXPECT_EQ("Fello", testVector1[1]);
+        EXPECT_EQ("Walue", testVector2[0]);
+        EXPECT_EQ("Hirst", testVector2[1]);
+    }
+
+    TEST_F(RangesViewTestFixture, JoinView_IterMoveCustomization_Succeeds)
+    {
+        using StringWrapper = AZStd::ranges::single_view<AZStd::string>;
+
+        AZStd::fixed_vector<StringWrapper, 8> testVector1{ StringWrapper{"5"}, StringWrapper{"10"} };
+        AZStd::fixed_vector<StringWrapper, 8> testVector2{ StringWrapper{"15"}, StringWrapper{"20"} };
+        auto joinView1 = AZStd::ranges::views::join(testVector1);
+        auto joinView2 = AZStd::ranges::views::join(testVector2);
+        auto joinViewIter1 = joinView1.begin();
+        auto joinViewIter2 = joinView2.begin();
+        AZStd::string value = AZStd::ranges::iter_move(joinViewIter1);
+
+        EXPECT_EQ("5", value);
+        EXPECT_TRUE((*joinViewIter1).empty());
+        ++joinViewIter2;
+        value = AZStd::ranges::iter_move(joinViewIter2);
+        EXPECT_EQ("20", value);
+        EXPECT_TRUE((*joinViewIter2).empty());
+    }
+
+    TEST_F(RangesViewTestFixture, ElementsView_CanIterateVectorOfTuple_Succeeds)
+    {
+        using TestTuple = AZStd::tuple<int, AZStd::string, bool>;
+        AZStd::vector testVector{ TestTuple{1, "hello", false}, TestTuple{2, "world", true},
+            TestTuple{3, "Moon", false} };
+
+        auto firstElementView = AZStd::ranges::views::elements<0>(testVector);
+        auto firstElementBegin = AZStd::ranges::begin(firstElementView);
+        auto firstElementEnd = AZStd::ranges::end(firstElementView);
+        EXPECT_NE(firstElementEnd, firstElementBegin);
+        ASSERT_EQ(3, firstElementView.size());
+        EXPECT_EQ(1, firstElementView[0]);
+        EXPECT_EQ(2, firstElementView[1]);
+        EXPECT_EQ(3, firstElementView[2]);
+
+        auto secondElementView = AZStd::ranges::views::elements<1>(testVector);
+        ASSERT_EQ(3, secondElementView.size());
+        EXPECT_EQ("hello", secondElementView[0]);
+        EXPECT_EQ("world", secondElementView[1]);
+        EXPECT_EQ("Moon", secondElementView[2]);
+
+        auto thirdElementView = AZStd::ranges::views::elements<2>(testVector);
+        ASSERT_EQ(3, thirdElementView.size());
+        EXPECT_FALSE(thirdElementView[0]);
+        EXPECT_TRUE(thirdElementView[1]);
+        EXPECT_FALSE(thirdElementView[2]);
+
+        using TestPair = AZStd::pair<AZStd::string, int>;
+        AZStd::vector testPairVector{ TestPair{"hello", 5}, TestPair{"world", 10}, TestPair{"Sun", 15} };
+        using ElementsViewBase = AZStd::ranges::views::all_t<decltype((testPairVector))>;
+        using ElementsViewType = AZStd::ranges::elements_view<ElementsViewBase, 0>;
+
+        constexpr AZStd::string_view expectedString = "helloworldSun";
+        AZStd::string accumString;
+        for (auto&& stringValue : ElementsViewType(testPairVector))
+        {
+            accumString += stringValue;
+        }
+
+        EXPECT_EQ(expectedString, accumString);
+    }
+
+    TEST_F(RangesViewTestFixture, ElementsView_KeysAlias_CanIterateAssociativeContainerKeyType)
+    {
+        using PairType = AZStd::pair<int, const char*>;
+        AZStd::map testMap{ PairType{1, "Hello"}, PairType{2, "World"}, PairType{3, "Sun"}, PairType{45, "RandomText"} };
+
+        int accumResult{};
+        for (int key : AZStd::ranges::views::keys(testMap))
+        {
+            accumResult += key;
+        }
+
+        EXPECT_EQ(51, accumResult);
+    }
+
+    TEST_F(RangesViewTestFixture, ElementsView_ValuesAlias_CanIterateAssociativeContainerMappedType)
+    {
+        using PairType = AZStd::pair<int, const char*>;
+        AZStd::map testMap{ PairType{1, "Hello"}, PairType{2, "World"}, PairType{3, "Sun"}, PairType{45, "RandomText"} };
+
+        AZStd::string accumResult{};
+        for (const char* value : AZStd::ranges::views::values(testMap))
+        {
+            accumResult += value;
+        }
+
+        EXPECT_EQ("HelloWorldSunRandomText", accumResult);
+    }
+}

+ 1 - 0
Code/Framework/AzCore/Tests/Main.cpp

@@ -8,6 +8,7 @@
 
 #include <AzCore/UnitTest/UnitTest.h>
 #include <AzTest/AzTest.h>
+#include <AzCore/Memory/SystemAllocator.h>
 
 
 #if defined(HAVE_BENCHMARK)

+ 2 - 0
Code/Framework/AzCore/Tests/azcoretests_files.cmake

@@ -206,7 +206,9 @@ set(FILES
     AZStd/Optional.cpp
     AZStd/Pair.cpp
     AZStd/Parallel.cpp
+    AZStd/RangesAlgorithmTests.cpp
     AZStd/RangesTests.cpp
+    AZStd/RangesViewTests.cpp
     AZStd/ScopedLockTests.cpp
     AZStd/SetsIntrusive.cpp
     AZStd/SmartPtr.cpp

+ 1 - 2
Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h

@@ -8,11 +8,10 @@
 
 #pragma once
 
+#include <AzCore/std/chrono/chrono.h>
 #include <AzCore/std/functional.h>
 #include <AzCore/std/optional.h>
 
-#include <chrono>
-
 namespace AzFramework
 {
     //! Default value to use for detecting if the mouse has moved far enough after a mouse down to no longer

+ 1 - 1
Code/Tools/LuaIDE/Source/LUA/BreakpointPanel.cpp

@@ -185,5 +185,5 @@ void DHBreakpointsWidget::RemoveRow(int which)
     QByteArray fileName = file->data(Qt::DisplayRole).toString().toUtf8().data();
     int lineNumber = line->data(Qt::DisplayRole).toInt();
 
-    EBUS_EVENT(LUAEditor::LUABreakpointRequestMessages::Bus, RequestDeleteBreakpoint, AZStd::string(fileName), lineNumber);
+    EBUS_EVENT(LUAEditor::LUABreakpointRequestMessages::Bus, RequestDeleteBreakpoint, AZStd::string(fileName.constData()), lineNumber);
 }

+ 5 - 1
Code/Tools/SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.h

@@ -25,7 +25,9 @@ namespace AZ
             public:
                 ProxyPointer(const Type& value);
                 Type& operator*();
+                const Type& operator*() const;
                 Type* operator->();
+                const Type* operator->() const;
 
             private:
                 Type m_value;
@@ -36,8 +38,10 @@ namespace AZ
             {
             public:
                 ProxyPointer(Type& value);
-                Type& operator*();
                 Type* operator->();
+                const Type& operator*() const;
+                Type& operator*();
+                const Type* operator->() const;
 
             private:
                 Type& m_value;

+ 20 - 0
Code/Tools/SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.inl

@@ -23,12 +23,22 @@ namespace AZ
             {
                 return m_value;
             }
+            template<typename Type>
+            const Type& ProxyPointer<Type>::operator*() const
+            {
+                return m_value;
+            }
 
             template<typename Type>
             Type* ProxyPointer<Type>::operator->()
             {
                 return &m_value;
             }
+            template<typename Type>
+            const Type* ProxyPointer<Type>::operator->() const
+            {
+                return &m_value;
+            }
 
             template<typename Type>
             ProxyPointer<Type&>::ProxyPointer(Type& value)
@@ -41,12 +51,22 @@ namespace AZ
             {
                 return m_value;
             }
+            template<typename Type>
+            const Type& ProxyPointer<Type&>::operator*() const
+            {
+                return m_value;
+            }
 
             template<typename Type>
             Type* ProxyPointer<Type&>::operator->()
             {
                 return &m_value;
             }
+            template<typename Type>
+            const Type* ProxyPointer<Type&>::operator->() const
+            {
+                return &m_value;
+            }
         } // Containers
     } // SceneAPI
 } // AZ

+ 1 - 0
Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactCommandLineOptions.h

@@ -11,6 +11,7 @@
 #include <TestImpactFramework/TestImpactTestSequence.h>
 #include <TestImpactFramework/TestImpactRepoPath.h>
 
+#include <AzCore/std/chrono/chrono.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/optional.h>
 #include <AzCore/std/containers/vector.h>

+ 2 - 1
Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h

@@ -9,6 +9,7 @@
 
 #include <AzCore/base.h>
 #include <AzCore/Preprocessor/Enum.h>
+#include <AzCore/RTTI/TypeInfo.h>
 
 namespace AZ
 {
@@ -47,5 +48,5 @@ namespace AZ
     } // namespace Render
 
     AZ_TYPE_INFO_SPECIALIZE(Render::ShadowmapSize, "{3EC1CE83-483D-41FD-9909-D22B03E56F4E}");
-    
+
 } // namespace AZ

+ 2 - 1
Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h

@@ -9,6 +9,7 @@
 
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/containers/unordered_map.h>
+#include <AzCore/Memory/SystemAllocator.h>
 
 namespace AZ
 {
@@ -44,6 +45,6 @@ namespace AZ
             AZStd::vector<VariantInfo> m_shaderVariants;
 
         };
-        
+
     } // namespace RPI
 } // namespace AZ

+ 1 - 0
Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowserInteractions.h

@@ -8,6 +8,7 @@
 
 #pragma once
 
+#include <AzCore/Memory/SystemAllocator.h>
 #include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
 #include <AzToolsFramework/SourceControl/SourceControlAPI.h>
 

+ 1 - 0
Gems/PythonAssetBuilder/Code/Source/PythonBuilderMessageSink.h

@@ -7,6 +7,7 @@
  */
 #pragma once
 
+#include <AzCore/Memory/SystemAllocator.h>
 #include <AzToolsFramework/API/EditorPythonConsoleBus.h>
 
 namespace PythonAssetBuilder