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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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++();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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>;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+8
-8
@@ -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);
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
+11
-4
@@ -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;
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
|
||||
+38
-28
@@ -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;
|
||||
|
||||
+10
@@ -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
|
||||
|
||||
+10
-13
@@ -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;
|
||||
|
||||
|
||||
+9
@@ -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)
|
||||
|
||||
+2
@@ -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;
|
||||
|
||||
+18
-3
@@ -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);
|
||||
|
||||
+3
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
+13
@@ -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
|
||||
|
||||
+1
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -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
|
||||
|
||||
+16
-13
@@ -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
Reference in New Issue
Block a user