Merge branch 'development' of https://github.com/o3de/o3de into jckand/ImageGradientTests

Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com>
This commit is contained in:
jckand-amzn
2022-02-14 10:19:00 -06:00
241 changed files with 11624 additions and 3590 deletions
@@ -162,11 +162,11 @@ def select_model_config(configname):
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SelectModelPresetByName", configname)
def destroy_main_window():
def exit():
"""
Closes the Material Editor window
Closes the Material Editor
"""
azlmbr.atomtools.AtomToolsMainWindowFactoryRequestBus(azlmbr.bus.Broadcast, "DestroyMainWindow")
azlmbr.atomtools.general.exit()
def wait_for_condition(function, timeout_in_seconds=1.0):
@@ -214,7 +214,7 @@ def run():
(not material_editor.is_open(document1_id)) and
(not material_editor.is_open(document2_id)) and
(not material_editor.is_open(document3_id)), 2.0)
material_editor.destroy_main_window()
material_editor.exit()
if __name__ == "__main__":
@@ -38,7 +38,10 @@
},
"Component_[7874177159288365422]": {
"$type": "EditorEntitySortComponent",
"Id": 7874177159288365422
"Id": 7874177159288365422,
"Child Entity Order": [
"Entity_[471076350497]"
]
},
"Component_[8018146290632383969]": {
"$type": "EditorEntityIconComponent",
@@ -110,34 +113,14 @@
"Component_[16871442125196328877]": {
"$type": "EditorEntitySortComponent",
"Id": 16871442125196328877,
"ChildEntityOrderEntryArray": [
{
"EntityId": "Entity_[604220336673]"
},
{
"EntityId": "Entity_[599925369377]",
"SortIndex": 1
},
{
"EntityId": "Entity_[475371317793]",
"SortIndex": 2
},
{
"EntityId": "Entity_[509731056161]",
"SortIndex": 3
},
{
"EntityId": "Entity_[505436088865]",
"SortIndex": 4
},
{
"EntityId": "Entity_[539795827233]",
"SortIndex": 5
},
{
"EntityId": "Entity_[569860598305]",
"SortIndex": 6
}
"Child Entity Order": [
"Entity_[604220336673]",
"Entity_[599925369377]",
"Entity_[475371317793]",
"Entity_[509731056161]",
"Entity_[505436088865]",
"Entity_[539795827233]",
"Entity_[569860598305]"
]
},
"Component_[18389136819207633744]": {
@@ -263,10 +246,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -370,10 +353,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -477,10 +460,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -584,10 +567,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -691,10 +674,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -798,10 +781,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -905,10 +888,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -944,30 +927,13 @@
"Component_[11056805018150955063]": {
"$type": "EditorEntitySortComponent",
"Id": 11056805018150955063,
"ChildEntityOrderEntryArray": [
{
"EntityId": "Entity_[488256219681]"
},
{
"EntityId": "Entity_[483961252385]",
"SortIndex": 1
},
{
"EntityId": "Entity_[479666285089]",
"SortIndex": 2
},
{
"EntityId": "Entity_[492551186977]",
"SortIndex": 3
},
{
"EntityId": "Entity_[496846154273]",
"SortIndex": 4
},
{
"EntityId": "Entity_[501141121569]",
"SortIndex": 5
}
"Child Entity Order": [
"Entity_[488256219681]",
"Entity_[483961252385]",
"Entity_[479666285089]",
"Entity_[492551186977]",
"Entity_[496846154273]",
"Entity_[501141121569]"
]
},
"Component_[11466054095979053511]": {
@@ -1028,30 +994,13 @@
"Component_[11056805018150955063]": {
"$type": "EditorEntitySortComponent",
"Id": 11056805018150955063,
"ChildEntityOrderEntryArray": [
{
"EntityId": "Entity_[522615958049]"
},
{
"EntityId": "Entity_[518320990753]",
"SortIndex": 1
},
{
"EntityId": "Entity_[514026023457]",
"SortIndex": 2
},
{
"EntityId": "Entity_[526910925345]",
"SortIndex": 3
},
{
"EntityId": "Entity_[531205892641]",
"SortIndex": 4
},
{
"EntityId": "Entity_[535500859937]",
"SortIndex": 5
}
"Child Entity Order": [
"Entity_[522615958049]",
"Entity_[518320990753]",
"Entity_[514026023457]",
"Entity_[526910925345]",
"Entity_[531205892641]",
"Entity_[535500859937]"
]
},
"Component_[11466054095979053511]": {
@@ -1180,10 +1129,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -1287,10 +1236,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -1394,10 +1343,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -1501,10 +1450,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -1608,10 +1557,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -1715,10 +1664,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -1754,30 +1703,13 @@
"Component_[11056805018150955063]": {
"$type": "EditorEntitySortComponent",
"Id": 11056805018150955063,
"ChildEntityOrderEntryArray": [
{
"EntityId": "Entity_[552680729121]"
},
{
"EntityId": "Entity_[548385761825]",
"SortIndex": 1
},
{
"EntityId": "Entity_[544090794529]",
"SortIndex": 2
},
{
"EntityId": "Entity_[556975696417]",
"SortIndex": 3
},
{
"EntityId": "Entity_[561270663713]",
"SortIndex": 4
},
{
"EntityId": "Entity_[565565631009]",
"SortIndex": 5
}
"Child Entity Order": [
"Entity_[552680729121]",
"Entity_[548385761825]",
"Entity_[544090794529]",
"Entity_[556975696417]",
"Entity_[561270663713]",
"Entity_[565565631009]"
]
},
"Component_[11466054095979053511]": {
@@ -1906,10 +1838,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2013,10 +1945,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2120,10 +2052,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2227,10 +2159,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2334,10 +2266,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2441,10 +2373,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2480,30 +2412,13 @@
"Component_[11056805018150955063]": {
"$type": "EditorEntitySortComponent",
"Id": 11056805018150955063,
"ChildEntityOrderEntryArray": [
{
"EntityId": "Entity_[582745500193]"
},
{
"EntityId": "Entity_[578450532897]",
"SortIndex": 1
},
{
"EntityId": "Entity_[574155565601]",
"SortIndex": 2
},
{
"EntityId": "Entity_[587040467489]",
"SortIndex": 3
},
{
"EntityId": "Entity_[591335434785]",
"SortIndex": 4
},
{
"EntityId": "Entity_[595630402081]",
"SortIndex": 5
}
"Child Entity Order": [
"Entity_[582745500193]",
"Entity_[578450532897]",
"Entity_[574155565601]",
"Entity_[587040467489]",
"Entity_[591335434785]",
"Entity_[595630402081]"
]
},
"Component_[11466054095979053511]": {
@@ -2632,10 +2547,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2739,10 +2654,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2846,10 +2761,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -2953,10 +2868,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -3060,10 +2975,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
@@ -3167,10 +3082,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{D0F73AAF-52B7-507C-B045-DBE2FE2D4403}",
"subId": 268677693
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball_simple/shaberball_simple_1m.azmodel"
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
},
"LodOverride": 255
}
+4 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
@@ -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
View File
@@ -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
@@ -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
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/parallel/scoped_lock.h>
namespace AZ
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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>;
}
@@ -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>>>;
}
@@ -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>;
}
@@ -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>;
}
@@ -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>;
}
@@ -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
>;
}
}
@@ -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>;
}
@@ -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
@@ -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>;
#endif // AZSTD_UNORDERED_SET_H
#pragma once
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>;
}
@@ -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);
}
@@ -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>
@@ -197,9 +197,5 @@ namespace AZStd
return *reinterpret_cast<Iterator*>(&iter);
}
}
using std::size;
using std::empty;
using std::data;
} // namespace AZStd
@@ -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>;
}
File diff suppressed because it is too large Load Diff
@@ -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;
}
@@ -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{};
};
}
@@ -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;
}
@@ -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;
}
@@ -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>;
}
@@ -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{};
};
}
@@ -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
View File
@@ -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;
}
@@ -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
@@ -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
@@ -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;
}
@@ -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;
}
@@ -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>;
}
@@ -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;
};
}
@@ -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;
}
@@ -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>;
}
@@ -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>
@@ -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
@@ -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
View File
@@ -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;
@@ -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
@@ -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;
}
@@ -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;
}
@@ -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
View File
@@ -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;
};
using std::in_place_type_t;
using std::in_place_type;
template <template <class> class trait>
struct sequence_and<trait>
{
static const bool value = true;
};
template <template <class> class, typename...>
struct sequence_or;
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
{
@@ -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*>);
}
}
@@ -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);
}
}
}
@@ -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
View File
@@ -8,6 +8,7 @@
#include <AzCore/UnitTest/UnitTest.h>
#include <AzTest/AzTest.h>
#include <AzCore/Memory/SystemAllocator.h>
#if defined(HAVE_BENCHMARK)
@@ -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
@@ -8,10 +8,12 @@
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Jobs/JobContext.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/std/containers/span.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzFramework/Render/GeometryIntersectionStructures.h>
#include <AzFramework/SurfaceData/SurfaceData.h>
@@ -193,6 +195,147 @@ namespace AzFramework
//! Given a ray, return the closest intersection with terrain.
virtual RenderGeometry::RayResult GetClosestIntersection(const RenderGeometry::RayRequest& ray) const = 0;
//! A JobContext used to run jobs spawned by calls to the various Process*Async functions.
class TerrainJobContext : public AZ::JobContext
{
public:
TerrainJobContext(AZ::JobManager& jobManager,
int numJobsToComplete)
: JobContext(jobManager)
, m_numJobsToComplete(numJobsToComplete)
{
}
// When a terrain job context is cancelled, all associated
// jobs are still guaranteed to at least begin processing,
// and if any ProcessAsyncParams::m_completionCallback was
// set it's guaranteed to be called even in the event of a
// cancellation. If a job only begins processing after its
// associated job context has been cancelled, no processing
// will occur and the callback will be invoked immediately,
// otherwise the job may either run to completion or cease
// processing early; the callback is invoked in all cases,
// provided one was specified with the original request.
void Cancel() { m_isCancelled = true; }
// Was this TerrainJobContext cancelled?
bool IsCancelled() const { return m_isCancelled; }
// Called by the TerrainSystem when a job associated with
// this TerrainJobContext completes. Returns true if this
// was the final job to be completed, or false otherwise.
bool OnJobCompleted() { return (--m_numJobsToComplete == 0); }
private:
AZStd::atomic_int m_numJobsToComplete = 0;
AZStd::atomic_bool m_isCancelled = false;
};
//! Alias for an optional callback function to invoke when the various Process*Async functions complete.
//! The TerrainJobContext, returned from the original Process*Async function call, is passed as a param
//! to the callback function so it can be queried to see if the job was cancelled or completed normally.
typedef AZStd::function<void(AZStd::shared_ptr<TerrainJobContext>)> ProcessAsyncCompleteCallback;
//! A parameter group struct that can optionally be passed to the various Process*Async API functions.
struct ProcessAsyncParams
{
//! The default minimum number ofpositions per async terrain request job.
static constexpr int32_t MinPositionsPerJobDefault = 8;
//! The default number of jobs which async terrain requests will be split into.
static constexpr int32_t NumJobsDefault = 1;
//! The maximum number of jobs which async terrain requests will be split into.
//! This is not the value itself, rather a constant that can be used to request
//! the work be split into the maximum number of job manager threads available.
static constexpr int32_t NumJobsMax = -1;
//! The desired number of jobs to split async terrain requests into.
//! The actual value used will be clamped to the number of available job manager threads.
//!
//! Note: Currently, splitting the work over multiple threads causes contention when
//! locking various mutexes, resulting in slower overall wall time for async
//! requests split over multiple threads vs one where all the work is done on
//! a single thread. The latter is still preferable over a regular synchronous
//! call because it is just as quick and prevents the main thread from blocking.
//! This note should be removed once the mutex contention issues have been addressed.
int32_t m_desiredNumberOfJobs = NumJobsDefault;
//! The minimum number of positions per async terrain request job.
int32_t m_minPositionsPerJob = MinPositionsPerJobDefault;
//! The callback function that will be invoked when a call to a Process*Async function completes.
//! If the job is cancelled, the completion callback will not be invoked.
ProcessAsyncCompleteCallback m_completionCallback = nullptr;
};
//! Asynchronous versions of the various 'Process*' API functions declared above.
//! It's the responsibility of the caller to ensure all callbacks are threadsafe.
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
const AZStd::span<AZ::Vector3>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
const AZStd::span<AZ::Vector2>& inPositions,
SurfacePointListFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromRegionAsync(
const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromRegionAsync(
const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromRegionAsync(
const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromRegionAsync(
const AZ::Aabb& inRegion,
const AZ::Vector2& stepSize,
SurfacePointRegionFillCallback perPositionCallback,
Sampler sampleFilter = Sampler::DEFAULT,
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
private:
// Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of
// using an "out" parameter. The "out" parameter is useful for reusing memory allocated in SurfacePoint when
@@ -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
@@ -106,5 +106,30 @@ namespace UnitTest
GetTerrainRaycastEntityContextId, AzFramework::EntityContextId());
MOCK_CONST_METHOD1(
GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&));
MOCK_CONST_METHOD4(
ProcessHeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessNormalsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessSurfaceWeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessSurfacePointsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessHeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessNormalsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessSurfaceWeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD4(
ProcessSurfacePointsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5(
ProcessHeightsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5(
ProcessNormalsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5(
ProcessSurfaceWeightsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
MOCK_CONST_METHOD5(
ProcessSurfacePointsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
};
} // namespace UnitTest
@@ -46,9 +46,9 @@ namespace AzManipulatorTestFramework
//! Send a double click event.
DerivedDispatcherT* MouseLButtonDoubleClick();
//! Set the keyboard modifier button down.
DerivedDispatcherT* KeyboardModifierDown(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
DerivedDispatcherT* KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier);
//! Set the keyboard modifier button up.
DerivedDispatcherT* KeyboardModifierUp(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
DerivedDispatcherT* KeyboardModifierUp(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier);
//! Set the mouse position to the specified screen space position.
DerivedDispatcherT* MousePosition(const AzFramework::ScreenPoint& position);
//! Expect the selected manipulator to be interacting.
@@ -81,8 +81,8 @@ namespace AzManipulatorTestFramework
virtual void MouseMButtonUpImpl() = 0;
virtual void MouseLButtonDoubleClickImpl() = 0;
virtual void MousePositionImpl(const AzFramework::ScreenPoint& position) = 0;
virtual void KeyboardModifierDownImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
virtual void KeyboardModifierUpImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
virtual void KeyboardModifierDownImpl(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier) = 0;
virtual void KeyboardModifierUpImpl(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier) = 0;
virtual void ExpectManipulatorBeingInteractedImpl() = 0;
virtual void ExpectManipulatorNotBeingInteractedImpl() = 0;
virtual void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) = 0;
@@ -94,7 +94,7 @@ namespace AzManipulatorTestFramework
bool m_logging = false;
private:
const char* KeyboardModifierString(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
const char* KeyboardModifierString(AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier);
static void DebugPrint(const char* format, ...);
};
@@ -215,7 +215,7 @@ namespace AzManipulatorTestFramework
template<typename DerivedDispatcherT>
const char* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierString(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
const AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier)
{
using namespace AzToolsFramework::ViewportInteraction;
switch (keyModifier)
@@ -235,7 +235,7 @@ namespace AzManipulatorTestFramework
template<typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierDown(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
const AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier)
{
Log("Keyboard modifier down: %s", KeyboardModifierString(keyModifier));
KeyboardModifierDownImpl(keyModifier);
@@ -244,7 +244,7 @@ namespace AzManipulatorTestFramework
template<typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierUp(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
const AzToolsFramework::ViewportInteraction::KeyboardModifier keyModifier)
{
Log("Keyboard modifier up: %s", KeyboardModifierString(keyModifier));
KeyboardModifierUpImpl(keyModifier);
@@ -66,8 +66,8 @@ namespace AzManipulatorTestFramework
void MouseMButtonUpImpl() override;
void MouseLButtonDoubleClickImpl() override;
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
void KeyboardModifierDownImpl(const KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override;
void KeyboardModifierDownImpl(KeyboardModifier keyModifier) override;
void KeyboardModifierUpImpl(KeyboardModifier keyModifier) override;
void ExpectManipulatorBeingInteractedImpl() override;
void ExpectManipulatorNotBeingInteractedImpl() override;
void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override;
@@ -126,12 +126,12 @@ namespace AzManipulatorTestFramework
m_manipulatorViewportInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
}
void ImmediateModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier& keyModifier)
void ImmediateModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier keyModifier)
{
ToggleOn(GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers.m_keyModifiers, keyModifier);
}
void ImmediateModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier& keyModifier)
void ImmediateModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier keyModifier)
{
ToggleOff(GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers.m_keyModifiers, keyModifier);
}
@@ -82,7 +82,7 @@ namespace AzToolsFramework
});
connect(m_ui->m_assetBrowserTreeViewWidget, &QAbstractItemView::doubleClicked, this, &AssetPickerDialog::DoubleClickedSlot);
connect(m_ui->m_assetBrowserTreeViewWidget, &AssetBrowserTreeView::selectionChangedSignal, this,
[this](const QItemSelection&, const QItemSelection&){ AssetPickerDialog::SelectionChangedSlot(); });
[this](const QItemSelection&, const QItemSelection&){ SelectionChangedSlot(); });
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
@@ -153,7 +153,7 @@ namespace AzToolsFramework
m_ui->m_assetBrowserTableViewWidget, &AssetBrowserTableView::selectionChangedSignal, this,
[this](const QItemSelection&, const QItemSelection&)
{
AssetPickerDialog::SelectionChangedSlot();
SelectionChangedSlot();
});
connect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AssetPickerDialog::DoubleClickedSlot);
@@ -174,8 +174,15 @@ namespace AzToolsFramework
m_tableModel->UpdateTableModelMaps();
}
QTimer::singleShot(0, this, &AssetPickerDialog::RestoreState);
SelectionChangedSlot();
QTimer::singleShot(0, this, [this]() {
RestoreState();
// The selection doesn't propagate immediately, so we need to delay
// it as well so that the OK button can be updated appropriately.
// Otherwise, it will always be disabled when you first launch
// the asset picker dialog.
SelectionChangedSlot();
});
}
AssetPickerDialog::~AssetPickerDialog() = default;
@@ -58,16 +58,16 @@ namespace AzToolsFramework
void keyPressEvent(QKeyEvent* e) override;
void resizeEvent(QResizeEvent* resizeEvent) override;
private Q_SLOTS:
protected Q_SLOTS:
void DoubleClickedSlot(const QModelIndex& index);
void SelectionChangedSlot();
void RestoreState();
void OnFilterUpdated();
private:
protected:
//! Evaluate whether current selection is valid.
//! Valid selection requires exactly one item to be selected, must be source or product type, and must match the wildcard filter
bool EvaluateSelection() const;
virtual bool EvaluateSelection() const;
void UpdatePreview() const;
void SaveState();
@@ -14,6 +14,8 @@
#include <AzToolsFramework/Manipulators/ManipulatorSnapping.h>
#include <AzFramework/Viewport/ViewportColors.h>
#include <AzFramework/Viewport/ViewportConstants.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
namespace AzToolsFramework
{
@@ -37,20 +39,20 @@ namespace AzToolsFramework
void BoxViewportEdit::UpdateManipulators()
{
AZ::Transform boxWorldFromLocal = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult(
boxWorldFromLocal, m_entityComponentIdPair, &BoxManipulatorRequests::GetCurrentTransform);
AZ::TransformBus::EventResult(
boxWorldFromLocal, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
AZ::Vector3 boxScale = AZ::Vector3::CreateOne();
BoxManipulatorRequestBus::EventResult(
boxScale, m_entityComponentIdPair, &BoxManipulatorRequests::GetBoxScale);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(
nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequestBus::Events::GetScale);
AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero();
BoxManipulatorRequestBus::EventResult(
boxDimensions, m_entityComponentIdPair, &BoxManipulatorRequests::GetDimensions);
boxDimensions, m_entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetDimensions);
// ensure we apply the entity scale to the box dimensions so
// the manipulators appear in the correct location
boxDimensions *= boxScale;
AZ::Transform boxLocalTransform = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult(
boxLocalTransform, m_entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetCurrentLocalTransform);
for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex)
{
@@ -58,7 +60,8 @@ namespace AzToolsFramework
{
linearManipulator->SetSpace(boxWorldFromLocal);
linearManipulator->SetLocalTransform(
AZ::Transform::CreateTranslation(s_boxAxes[manipulatorIndex] * 0.5f * boxDimensions));
boxLocalTransform * AZ::Transform::CreateTranslation(s_boxAxes[manipulatorIndex] * 0.5f * boxDimensions));
linearManipulator->SetNonUniformScale(nonUniformScale);
linearManipulator->SetBoundsDirty();
}
}
@@ -69,8 +72,8 @@ namespace AzToolsFramework
m_entityComponentIdPair = entityComponentIdPair;
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult(
worldFromLocal, entityComponentIdPair, &BoxManipulatorRequests::GetCurrentTransform);
AZ::TransformBus::EventResult(
worldFromLocal, entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex)
{
@@ -85,36 +88,35 @@ namespace AzToolsFramework
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewQuadBillboard(
AzFramework::ViewportColors::DefaultManipulatorHandleColor, AzFramework::ViewportConstants::DefaultManipulatorHandleSize));
AzFramework::ViewportColors::DefaultManipulatorHandleColor,
AzFramework::ViewportConstants::DefaultManipulatorHandleSize));
linearManipulator->SetViews(AZStd::move(views));
linearManipulator->InstallMouseMoveCallback(
[this, entityComponentIdPair](
const LinearManipulator::Action& action)
[this, entityComponentIdPair,
transformScale{ linearManipulator->GetSpace().GetUniformScale() }](const LinearManipulator::Action& action)
{
AZ::Transform boxLocalTransform = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult(
boxLocalTransform, entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetCurrentLocalTransform);
const AZ::Vector3 manipulatorPosition = GetPositionInManipulatorFrame(transformScale, boxLocalTransform, action);
// calculate the amount of displacement along an axis this manipulator has moved
// clamp movement so it cannot go negative based on axis direction
const AZ::Vector3 axisDisplacement =
action.LocalPosition().GetAbs() * 2.0f
* AZ::GetMax<float>(0.0f, action.LocalPosition().GetNormalized().Dot(action.m_fixed.m_axis));
AZ::Vector3 boxScale = AZ::Vector3::CreateOne();
BoxManipulatorRequestBus::EventResult(
boxScale, entityComponentIdPair, &BoxManipulatorRequests::GetBoxScale);
manipulatorPosition.GetAbs() * 2.0f
* AZ::GetMax(0.0f, manipulatorPosition.GetNormalized().Dot(action.m_fixed.m_axis));
AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero();
BoxManipulatorRequestBus::EventResult(
boxDimensions, entityComponentIdPair, &BoxManipulatorRequests::GetDimensions);
// ensure we take into account the entity scale using the axis displacement
const AZ::Vector3 scaledAxisDisplacement =
axisDisplacement / boxScale;
boxDimensions, entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetDimensions);
// update dimensions - preserve dimensions not effected by this
// axis, and update current axis displacement
BoxManipulatorRequestBus::Event(
entityComponentIdPair, &BoxManipulatorRequests::SetDimensions,
(NotAxis(action.m_fixed.m_axis) * boxDimensions).GetMax(scaledAxisDisplacement));
entityComponentIdPair, &BoxManipulatorRequestBus::Events::SetDimensions,
(NotAxis(action.m_fixed.m_axis) * boxDimensions).GetMax(axisDisplacement));
UpdateManipulators();
});
@@ -137,4 +139,12 @@ namespace AzToolsFramework
}
}
}
AZ::Vector3 GetPositionInManipulatorFrame(float worldUniformScale, const AZ::Transform& manipulatorLocalTransform,
const LinearManipulator::Action& action)
{
return manipulatorLocalTransform.GetInverse().TransformPoint(
action.m_start.m_localPosition +
action.m_current.m_localPositionOffset / AZ::GetClamp(worldUniformScale, AZ::MinTransformScale, AZ::MaxTransformScale));
}
} // namespace AzToolsFramework
@@ -31,4 +31,10 @@ namespace AzToolsFramework
using BoxManipulators = AZStd::array<AZStd::shared_ptr<LinearManipulator>, 6>;
BoxManipulators m_linearManipulators; ///< Manipulators for editing box size.
};
/// Calculates the position of the manipulator in its own reference frame.
/// Removes the effects of the manipulator local transform, and accounts for world transform scale in
/// the action local offset.
AZ::Vector3 GetPositionInManipulatorFrame(float worldUniformScale, const AZ::Transform& manipulatorLocalTransform,
const LinearManipulator::Action& action);
} // namespace AzToolsFramework
@@ -54,7 +54,8 @@ namespace AzToolsFramework
virtual ~BaseManipulator();
using EntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
using UniqueEntityIds = AZStd::unordered_set<AZ::EntityId>;
using UniqueEntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
//! Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed.
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
@@ -137,7 +138,7 @@ namespace AzToolsFramework
}
//! Returns all EntityComponentIdPairs associated with this manipulator.
const EntityComponentIds& EntityComponentIdPairs() const
const UniqueEntityComponentIds& EntityComponentIdPairs() const
{
return m_entityComponentIdPairs;
}
@@ -147,10 +148,10 @@ namespace AzToolsFramework
//! Remove an entity from being affected by this manipulator.
//! @note All components on this entity registered with the manipulator will be removed.
EntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
UniqueEntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
//! Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator.
EntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
UniqueEntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
//! Is this entity currently being tracked by this manipulator.
bool HasEntityId(AZ::EntityId entityId) const;
@@ -26,11 +26,21 @@ namespace AzToolsFramework
virtual AZ::Vector3 GetDimensions() = 0;
//! Set the X/Y/Z dimensions of the box shape/collider.
virtual void SetDimensions(const AZ::Vector3& dimensions) = 0;
// O3DE_DEPRECATION_NOTICE(GHI-7572)
//! @deprecated Because non-uniform scale effects can be complex, it is recommended to separately use
//! AZ::TransformBus::Events::GetWorldTM, AZ::NonUniformScaleRequests::GetScale and GetCurrentLocalTransform
//! and combine their effects.
//! Get the transform of the box shape/collider.
//! This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus
//! because a collider may have an additional translation/orientation offset from
//! the Entity transform.
virtual AZ::Transform GetCurrentTransform() = 0;
//! Get the transform of the box relative to the entity.
virtual AZ::Transform GetCurrentLocalTransform() = 0;
// O3DE_DEPRECATION_NOTICE(GHI-7572)
//! @deprecated Because non-uniform scale effects can be complex, it is recommended to separately use
//! AZ::TransformBus::Events::GetWorldTM, AZ::NonUniformScaleRequests::GetScale and GetCurrentLocalTransform
//! and combine their effects.
//! Get the scale currently applied to the box.
//! With the Box Shape, the largest x/y/z component is taken
//! so scale is always uniform, with colliders the scale may
@@ -80,23 +80,18 @@ namespace AzToolsFramework
m_onMouseMoveCallback = onMouseMoveCallback;
}
void SurfaceManipulator::InstallEntityIdsToIgnoreFn(EntityIdsToIgnoreFn entityIdsToIgnoreCallback)
{
m_entityIdsToIgnoreFn = AZStd::move(entityIdsToIgnoreCallback);
}
void SurfaceManipulator::OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction, [[maybe_unused]] float rayIntersectionDistance)
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const AzFramework::ViewportId viewportId = interaction.m_interactionId.m_viewportId;
const auto& entityComponentIdPairs = EntityComponentIdPairs();
m_rayRequest.m_entityFilter.m_ignoreEntities.clear();
m_rayRequest.m_entityFilter.m_ignoreEntities.reserve(entityComponentIdPairs.size());
AZStd::transform(
entityComponentIdPairs.begin(), entityComponentIdPairs.end(),
AZStd::inserter(m_rayRequest.m_entityFilter.m_ignoreEntities, m_rayRequest.m_entityFilter.m_ignoreEntities.begin()),
[](const AZ::EntityComponentIdPair& entityComponentIdPair)
{
return entityComponentIdPair.GetEntityId();
});
m_rayRequest.m_entityFilter.m_ignoreEntities = m_entityIdsToIgnoreFn(interaction);
// calculate the start and end of the ray
RefreshRayRequest(
@@ -139,6 +134,8 @@ namespace AzToolsFramework
{
const AzFramework::ViewportId viewportId = interaction.m_interactionId.m_viewportId;
m_rayRequest.m_entityFilter.m_ignoreEntities = m_entityIdsToIgnoreFn(interaction);
// update the start and end of the ray
RefreshRayRequest(
m_rayRequest, ViewportInteraction::ViewportScreenToWorldRay(viewportId, interaction.m_mousePick.m_screenCoordinates),
@@ -162,12 +159,12 @@ namespace AzToolsFramework
const ManipulatorManagerState& managerState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
const ViewportInteraction::MouseInteraction& interaction)
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState, GetManipulatorId(),
ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
cameraState, interaction);
}
void SurfaceManipulator::InvalidateImpl()
@@ -40,6 +40,9 @@ namespace AzToolsFramework
//! A Manipulator must only be created and managed through a shared_ptr.
static AZStd::shared_ptr<SurfaceManipulator> MakeShared(const AZ::Transform& worldFromLocal);
//! Callback function to determine which EntityIds to ignore when performing the ray intersection.
using EntityIdsToIgnoreFn = AZStd::function<UniqueEntityIds(const ViewportInteraction::MouseInteraction&)>;
//! The state of the manipulator at the start of an interaction.
struct Start
{
@@ -77,11 +80,13 @@ namespace AzToolsFramework
void InstallLeftMouseUpCallback(const MouseActionCallback& onMouseUpCallback);
void InstallMouseMoveCallback(const MouseActionCallback& onMouseMoveCallback);
void InstallEntityIdsToIgnoreFn(EntityIdsToIgnoreFn entityIdsToIgnoreFn);
void Draw(
const ManipulatorManagerState& managerState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
const ViewportInteraction::MouseInteraction& interaction) override;
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
@@ -109,6 +114,9 @@ namespace AzToolsFramework
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
MouseActionCallback m_onMouseMoveCallback = nullptr;
//! Customization point to determine which (if any) EntityIds to ignore while performing the ray intersection.
EntityIdsToIgnoreFn m_entityIdsToIgnoreFn = nullptr;
//! Cached ray request initialized at mouse down and updated during mouse move.
AzFramework::RenderGeometry::RayRequest m_rayRequest;
@@ -145,6 +145,15 @@ namespace AzToolsFramework
}
}
void TranslationManipulators::InstallSurfaceManipulatorEntityIdsToIgnoreFn(
SurfaceManipulator::EntityIdsToIgnoreFn entityIdsToIgnoreFn)
{
if (m_surfaceManipulator)
{
m_surfaceManipulator->InstallEntityIdsToIgnoreFn(AZStd::move(entityIdsToIgnoreFn));
}
}
void TranslationManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
{
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
@@ -61,6 +61,8 @@ namespace AzToolsFramework
void InstallSurfaceManipulatorMouseMoveCallback(const SurfaceManipulator::MouseActionCallback& onMouseMoveCallback);
void InstallSurfaceManipulatorMouseUpCallback(const SurfaceManipulator::MouseActionCallback& onMouseUpCallback);
void InstallSurfaceManipulatorEntityIdsToIgnoreFn(SurfaceManipulator::EntityIdsToIgnoreFn entityIdsToIgnoreFn);
void SetSpaceImpl(const AZ::Transform& worldFromLocal) override;
void SetLocalTransformImpl(const AZ::Transform& localTransform) override;
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
@@ -813,7 +813,7 @@ namespace AzToolsFramework
selection.SetDisplayFilter(FilterConstType(compFilter));
}
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget());
PickAssetSelectionFromDialog(selection, parentWidget());
if (selection.IsValid())
{
const auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
@@ -831,6 +831,11 @@ namespace AzToolsFramework
}
}
void PropertyAssetCtrl::PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent)
{
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parent);
}
void PropertyAssetCtrl::OnClearButtonClicked()
{
ClearAssetInternal();
@@ -1524,7 +1529,7 @@ namespace AzToolsFramework
ConsumeAttributeInternal(GUI, attrib, attrValue, debugName);
}
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
void AssetPropertyHandlerDefault::WriteGUIValuesIntoPropertyInternal(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
{
(void)index;
(void)node;
@@ -1539,7 +1544,12 @@ namespace AzToolsFramework
}
}
bool AssetPropertyHandlerDefault::ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
{
WriteGUIValuesIntoPropertyInternal(index, GUI, instance, node);
}
bool AssetPropertyHandlerDefault::ReadValuesIntoGUIInternal(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
{
(void)index;
(void)node;
@@ -1559,6 +1569,11 @@ namespace AzToolsFramework
return false;
}
bool AssetPropertyHandlerDefault::ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node)
{
return ReadValuesIntoGUIInternal(index, GUI, instance, node);
}
QWidget* SimpleAssetPropertyHandlerDefault::CreateGUI(QWidget* pParent)
{
PropertyAssetCtrl* newCtrl = aznew PropertyAssetCtrl(pParent);
@@ -244,6 +244,7 @@ namespace AzToolsFramework
void SetCurrentAssetHint(const AZStd::string& hint);
void SetDefaultAssetID(const AZ::Data::AssetId& defaultID);
virtual void PopupAssetPicker();
virtual void PickAssetSelectionFromDialog(AssetSelectionModel& selection, QWidget* parent);
void OnClearButtonClicked();
void UpdateAssetDisplay();
void OnLineEditFocus(bool focus);
@@ -280,7 +281,9 @@ namespace AzToolsFramework
virtual QWidget* CreateGUI(QWidget* pParent) override;
static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName);
void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
static void WriteGUIValuesIntoPropertyInternal(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node);
virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override;
static bool ReadValuesIntoGUIInternal(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node);
virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override;
};
@@ -1360,6 +1360,19 @@ namespace AzToolsFramework
EndRecordManipulatorCommand();
});
translationManipulators->InstallSurfaceManipulatorEntityIdsToIgnoreFn(
[this](const ViewportInteraction::MouseInteraction& interaction)
{
if (interaction.m_keyboardModifiers.Ctrl())
{
return AZStd::unordered_set<AZ::EntityId>();
}
else
{
return m_selectedEntityIds;
}
});
// transfer ownership
m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators);
}
@@ -3277,4 +3277,45 @@ namespace UnitTest
const AZ::Transform finalEntityTransform = AzToolsFramework::GetWorldTransform(m_entityIdBox);
EXPECT_THAT(finalEntityTransform.GetTranslation(), IsCloseTolerance(expectedWorldPosition, 0.01f));
}
TEST_F(
EditorTransformComponentSelectionRenderGeometryIntersectionManipulatorFixture, SurfaceManipulatorSelfIntersectsMeshWhenCtrlIsHeld)
{
// camera (go to position format) - 47.00, -52.00, 20.00, 0.00, -60.00
m_cameraState.m_viewportSize = AZ::Vector2(1280.0f, 720.0f);
// position camera
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(-60.0f)), AZ::Vector3(47.0f, -52.0f, 20.0f)));
// position box
AzToolsFramework::SetWorldTransform(m_entityIdBox, AZ::Transform::CreateTranslation(AZ::Vector3(50.0f, -50.0f, 20.0f)));
// the initial starting position of the entity
const auto initialTransformWorld = AzToolsFramework::GetWorldTransform(m_entityIdBox);
// where the surface manipulator should end up (surface of the box)
const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(49.5f, -49.6337357f, 19.5793953f));
// calculate the position in screen space of the initial position of the entity
const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState);
// calculate the position in screen space of the final position of the entity
const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState);
// select the entity (this will cause the manipulators to appear in EditorTransformComponentSelection)
AzToolsFramework::SelectEntity(m_entityIdBox);
// press and drag the mouse (starting where the surface manipulator is)
m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(initialPositionScreen)
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
->MouseLButtonDown()
->MousePosition(finalPositionScreen)
->MouseLButtonUp();
// read back the position of the entity now
const AZ::Transform finalManipulatorTransform = GetManipulatorTransform().value_or(AZ::Transform::CreateIdentity());
// ensure final world positions match
EXPECT_THAT(finalManipulatorTransform, IsCloseTolerance(finalTransformWorld, 0.01f));
}
} // namespace UnitTest
@@ -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);
}
@@ -482,10 +482,10 @@ QTabBar::tab:focus {
#labelButtonOverlay {
background-color: rgba(50,50,50,200);
min-width:210px;
max-width:210px;;
min-height:278px;
max-height:278px;
min-width:208px;
max-width:208px;;
min-height:270px;
max-height:270px;
}
QProgressBar {
@@ -81,7 +81,7 @@ namespace O3DE::ProjectManager
m_rightPanelStack = new QStackedWidget(this);
m_rightPanelStack->setFixedWidth(sidePanelWidth);
m_gemInspector = new GemInspector(m_gemModel, this);
m_gemInspector = new GemInspector(m_gemModel, m_rightPanelStack);
connect(m_gemInspector, &GemInspector::TagClicked, [=](const Tag& tag) { SelectGem(tag.id); });
connect(m_gemInspector, &GemInspector::UpdateGem, this, &GemCatalogScreen::UpdateGem);
@@ -233,7 +233,12 @@ namespace O3DE::ProjectManager
const QVector<GemInfo>& gemInfos = allGemInfosResult.GetValue();
for (const GemInfo& gemInfo : gemInfos)
{
gemInfoHash.insert(gemInfo.m_name, gemInfo);
// ${Name} is a special name used for templates and should be ignored
// eventually we should handle this in Python instead of here
if (gemInfo.m_name != "${Name}")
{
gemInfoHash.insert(gemInfo.m_name, gemInfo);
}
}
}
@@ -503,7 +508,10 @@ namespace O3DE::ProjectManager
const QVector<GemInfo>& allGemInfos = allGemInfosResult.GetValue();
for (const GemInfo& gemInfo : allGemInfos)
{
m_gemModel->AddGem(gemInfo);
if (gemInfo.m_name != "${Name}")
{
m_gemModel->AddGem(gemInfo);
}
}
const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allRepoGemInfosResult = PythonBindingsInterface::Get()->GetGemInfosForAllRepos();
@@ -30,6 +30,10 @@ namespace O3DE::ProjectManager
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_mainWidget = new QWidget();
if (parent)
{
m_mainWidget->setFixedWidth(parent->width());
}
setWidget(m_mainWidget);
m_mainLayout = new QVBoxLayout();
@@ -207,6 +207,7 @@ namespace O3DE::ProjectManager
{
m_templateDisplayName = new QLabel(this);
m_templateDisplayName->setObjectName("displayName");
m_templateDisplayName->setWordWrap(true);
templateDetailsLayout->addWidget(m_templateDisplayName);
m_templateSummary = new QLabel(this);
@@ -330,6 +330,11 @@ namespace O3DE::ProjectManager
void ProjectButton::ShowWarning(bool show, const QString& warning)
{
if (show)
{
// hide any overlay text, we cannot show the warning and an overlay at the same time
m_projectImageLabel->GetOverlayLabel()->setVisible(false);
}
m_projectImageLabel->GetWarningLabel()->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
m_projectImageLabel->GetWarningLabel()->setText(warning);
m_projectImageLabel->GetWarningLabel()->setVisible(show);
@@ -362,6 +367,9 @@ namespace O3DE::ProjectManager
m_projectImageLabel->SetOverlayText(tr("Building...\n\n"));
m_projectMenuButton->setVisible(false);
// hide the warning label about this project needing to be built while building
ShowWarning(false, "");
QProgressBar* progressBar = m_projectImageLabel->GetProgressBar();
progressBar->setVisible(true);
progressBar->setValue(0);
@@ -1356,11 +1356,18 @@ namespace O3DE::ProjectManager
IPythonBindings::ErrorPair PythonBindings::GetErrorPair()
{
AZStd::string detailedString = m_pythonErrorStrings.size() == 1
? ""
: AZStd::accumulate(m_pythonErrorStrings.begin(), m_pythonErrorStrings.end(), AZStd::string(""));
if (const size_t errorSize = m_pythonErrorStrings.size())
{
AZStd::string detailedString =
errorSize == 1 ? "" : AZStd::accumulate(m_pythonErrorStrings.begin(), m_pythonErrorStrings.end(), AZStd::string(""));
return IPythonBindings::ErrorPair(m_pythonErrorStrings.front(), detailedString);
return IPythonBindings::ErrorPair(m_pythonErrorStrings.front(), detailedString);
}
// If no error was found
else
{
return IPythonBindings::ErrorPair(AZStd::string("Unknown Python Bindings Error"), AZStd::string(""));
}
}
void PythonBindings::AddErrorString(AZStd::string errorString)
@@ -38,6 +38,7 @@ namespace O3DE::ProjectManager
QLabel* label = new QLabel(labelText, this);
label->setObjectName("templateLabel");
label->setWordWrap(true);
vLayout->addWidget(label);
connect(this, &QAbstractButton::toggled, this, &TemplateButton::onToggled);
@@ -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;
@@ -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
@@ -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>
@@ -82,7 +82,7 @@ namespace AZ
// Register Shader Asset Builder
AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor;
shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder";
shaderAssetBuilderDescriptor.m_version = 110; // Add "Definitions" field to shader asset to support convenient addition of preprocessor definitions
shaderAssetBuilderDescriptor.m_version = 111; // Enable shader PDB generation globally if Atom/GraphicsDevMode settings registry key is set
shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderAssetBuilder>();
shaderAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderAssetBuilder::CreateJobs, &m_shaderAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
@@ -318,10 +318,8 @@ namespace AZ
RPI::RenderPipelineDescriptor renderPipelineDescriptor = *RPI::GetDataFromAnyAsset<RPI::RenderPipelineDescriptor>(pipelineAsset);
renderPipelineDescriptor.m_name = AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId());
// Make sure non-msaa super variant is used for non-msaa pipeline
bool isNonMsaaPipeline = (renderPipelineDescriptor.m_renderSettings.m_multisampleState.m_samples == 1);
const char* supervariantName = isNonMsaaPipeline ? AZ::RPI::NoMsaaSupervariantName : "";
AZ::RPI::ShaderSystemInterface::Get()->SetSupervariantName(AZ::Name(supervariantName));
// The default pipeline determines the initial MSAA state for the application
AZ::RPI::RPISystemInterface::Get()->SetApplicationMultisampleState(renderPipelineDescriptor.m_renderSettings.m_multisampleState);
if (!scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name)))
{
@@ -34,11 +34,11 @@
"Attachment": "Output"
}
},
"MultisampleSource": {
"Pass": "Pipeline"
},
"ImageDescriptor": {
"Format": "D32_FLOAT_S8X24_UINT",
"MultisampleState": {
"samples": 4
},
"SharedQueueMask": "Graphics"
}
}
@@ -29,6 +29,24 @@
"RootShaderVariantAssetFileName": "diffuseprobegridrender_null_0.azshadervariant"
}
]
},
{
"Name": "NoMSAA",
"RootShaderVariantAssets":
[
{
"APIName": "dx12",
"RootShaderVariantAssetFileName": "diffuseprobegridrender-nomsaa_dx12_0.azshadervariant"
},
{
"APIName": "vulkan",
"RootShaderVariantAssetFileName": "diffuseprobegridrender-nomsaa_vulkan_0.azshadervariant"
},
{
"APIName": "null",
"RootShaderVariantAssetFileName": "diffuseprobegridrender-nomsaa_null_0.azshadervariant"
}
]
}
]
}
@@ -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
@@ -92,21 +92,24 @@ namespace AZ
AZ_Error("DiffuseProbeGridFeatureProcessor", m_probeGridRenderData.m_srgLayout != nullptr, "Failed to find ObjectSrg layout");
}
// initialize the buffer pools for the DiffuseProbeGrid visualization
m_visualizationBufferPools = RHI::RayTracingBufferPools::CreateRHIRayTracingBufferPools();
m_visualizationBufferPools->Init(device);
// load probe visualization model, the BLAS will be created in OnAssetReady()
m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
"Models/DiffuseProbeSphere.azmodel",
AZ::RPI::AssetUtils::TraceLevel::Assert);
if (!m_visualizationModelAsset.IsReady())
if (device->GetFeatures().m_rayTracing)
{
m_visualizationModelAsset.QueueLoad();
}
// initialize the buffer pools for the DiffuseProbeGrid visualization
m_visualizationBufferPools = RHI::RayTracingBufferPools::CreateRHIRayTracingBufferPools();
m_visualizationBufferPools->Init(device);
Data::AssetBus::MultiHandler::BusConnect(m_visualizationModelAsset.GetId());
// load probe visualization model, the BLAS will be created in OnAssetReady()
m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
"Models/DiffuseProbeSphere.azmodel",
AZ::RPI::AssetUtils::TraceLevel::Assert);
if (!m_visualizationModelAsset.IsReady())
{
m_visualizationModelAsset.QueueLoad();
}
Data::AssetBus::MultiHandler::BusConnect(m_visualizationModelAsset.GetId());
}
EnableSceneNotification();
}

Some files were not shown because too many files have changed in this diff Show More