Merge branch 'development' into math_string_converters
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__":
|
||||
|
||||
@@ -61,6 +61,7 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import Graph_HappyPath_ZoomInZoomOut as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails on nightly build builds, it needs to be fixed.")
|
||||
def test_NodePalette_HappyPath_CanSelectNode(self, request, workspace, editor, launcher_platform):
|
||||
from . import NodePalette_HappyPath_CanSelectNode as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
@@ -113,6 +114,7 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import Debugger_HappyPath_TargetMultipleGraphs as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails on nightly build builds, it needs to be fixed.")
|
||||
@pytest.mark.parametrize("level", ["tmp_level"])
|
||||
def test_Debugger_HappyPath_TargetMultipleEntities(self, request, workspace, editor, launcher_platform, project, level):
|
||||
def teardown():
|
||||
@@ -174,6 +176,7 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import ScriptEvents_ReturnSetType_Successfully as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails on nightly build builds, it needs to be fixed.")
|
||||
def test_NodeCategory_ExpandOnClick(self, request, workspace, editor, launcher_platform):
|
||||
from . import NodeCategory_ExpandOnClick as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
@@ -187,6 +190,7 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import VariableManager_UnpinVariableType_Works as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails on nightly build builds, it needs to be fixed.")
|
||||
def test_Node_HappyPath_DuplicateNode(self, request, workspace, editor, launcher_platform):
|
||||
from . import Node_HappyPath_DuplicateNode as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
@@ -263,6 +267,7 @@ class TestScriptCanvasTests(object):
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails on nightly build builds, it needs to be fixed.")
|
||||
def test_VariableManager_Default_CreateDeleteVars(self, request, editor, launcher_platform):
|
||||
var_types = ["Boolean", "Color", "EntityID", "Number", "String", "Transform", "Vector2", "Vector3", "Vector4"]
|
||||
expected_lines = [f"Success: {var_type} variable is created" for var_type in var_types]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AzCore/Memory/OSAllocator.h> // required by certain platforms
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
#include <AzCore/std/containers/intrusive_list.h>
|
||||
#include <AzCore/std/containers/intrusive_set.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -56,212 +57,6 @@ namespace AZ {
|
||||
// Enabled mutex per bucket
|
||||
#define USE_MUTEX_PER_BUCKET
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: Replace with AZStd::intrusive_list
|
||||
class intrusive_list_base
|
||||
{
|
||||
public:
|
||||
class node_base
|
||||
{
|
||||
node_base* mPrev;
|
||||
node_base* mNext;
|
||||
public:
|
||||
node_base* next() const {return mNext; }
|
||||
node_base* prev() const {return mPrev; }
|
||||
void reset()
|
||||
{
|
||||
mPrev = this;
|
||||
mNext = this;
|
||||
}
|
||||
void unlink()
|
||||
{
|
||||
mNext->mPrev = mPrev;
|
||||
mPrev->mNext = mNext;
|
||||
}
|
||||
void link(node_base* node)
|
||||
{
|
||||
mPrev = node->mPrev;
|
||||
mNext = node;
|
||||
node->mPrev = this;
|
||||
mPrev->mNext = this;
|
||||
}
|
||||
};
|
||||
intrusive_list_base()
|
||||
{
|
||||
mHead.reset();
|
||||
}
|
||||
intrusive_list_base(const intrusive_list_base&)
|
||||
{
|
||||
mHead.reset();
|
||||
}
|
||||
bool empty() const {return mHead.next() == &mHead; }
|
||||
void swap(intrusive_list_base& other)
|
||||
{
|
||||
node_base* node = &other.mHead;
|
||||
if (!empty())
|
||||
{
|
||||
node = mHead.next();
|
||||
mHead.unlink();
|
||||
mHead.reset();
|
||||
}
|
||||
node_base* other_node = &mHead;
|
||||
if (!other.empty())
|
||||
{
|
||||
other_node = other.mHead.next();
|
||||
other.mHead.unlink();
|
||||
other.mHead.reset();
|
||||
}
|
||||
mHead.link(other_node);
|
||||
other.mHead.link(node);
|
||||
}
|
||||
protected:
|
||||
node_base mHead;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: Replace with AZStd::intrusive_list
|
||||
template<class T>
|
||||
class intrusive_list
|
||||
: public intrusive_list_base
|
||||
{
|
||||
intrusive_list(const intrusive_list& rhs);
|
||||
intrusive_list& operator=(const intrusive_list& rhs);
|
||||
public:
|
||||
class node
|
||||
: public node_base
|
||||
{
|
||||
public:
|
||||
T* next() const {return static_cast<T*>(node_base::next()); }
|
||||
T* prev() const {return static_cast<T*>(node_base::prev()); }
|
||||
const T& data() const {return *static_cast<const T*>(this); }
|
||||
T& data() {return *static_cast<T*>(this); }
|
||||
};
|
||||
|
||||
class const_iterator;
|
||||
class iterator
|
||||
{
|
||||
using reference = T&;
|
||||
using pointer = T*;
|
||||
friend class const_iterator;
|
||||
T* mPtr;
|
||||
public:
|
||||
iterator()
|
||||
: mPtr(0) {}
|
||||
explicit iterator(T* ptr)
|
||||
: mPtr(ptr) {}
|
||||
reference operator*() const {return mPtr->data(); }
|
||||
pointer operator->() const {return &mPtr->data(); }
|
||||
operator pointer() const {
|
||||
return &mPtr->data();
|
||||
}
|
||||
iterator& operator++()
|
||||
{
|
||||
mPtr = mPtr->next();
|
||||
return *this;
|
||||
}
|
||||
iterator& operator--()
|
||||
{
|
||||
mPtr = mPtr->prev();
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const iterator& rhs) const {return mPtr == rhs.mPtr; }
|
||||
bool operator!=(const iterator& rhs) const {return mPtr != rhs.mPtr; }
|
||||
T* ptr() const {return mPtr; }
|
||||
};
|
||||
|
||||
class const_iterator
|
||||
{
|
||||
using reference = const T &;
|
||||
using pointer = const T *;
|
||||
const T* mPtr;
|
||||
public:
|
||||
const_iterator()
|
||||
: mPtr(0) {}
|
||||
explicit const_iterator(const T* ptr)
|
||||
: mPtr(ptr) {}
|
||||
const_iterator(const iterator& it)
|
||||
: mPtr(it.mPtr) {}
|
||||
reference operator*() const {return mPtr->data(); }
|
||||
pointer operator->() const {return &mPtr->data(); }
|
||||
operator pointer() const {
|
||||
return &mPtr->data();
|
||||
}
|
||||
const_iterator& operator++()
|
||||
{
|
||||
mPtr = mPtr->next();
|
||||
return *this;
|
||||
}
|
||||
const_iterator& operator--()
|
||||
{
|
||||
mPtr = mPtr->prev();
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const const_iterator& rhs) const {return mPtr == rhs.mPtr; }
|
||||
bool operator!=(const const_iterator& rhs) const {return mPtr != rhs.mPtr; }
|
||||
const T* ptr() const {return mPtr; }
|
||||
};
|
||||
|
||||
intrusive_list()
|
||||
: intrusive_list_base() {}
|
||||
~intrusive_list() {clear(); }
|
||||
|
||||
const_iterator begin() const {return const_iterator((const T*)mHead.next()); }
|
||||
iterator begin() {return iterator((T*)mHead.next()); }
|
||||
const_iterator end() const {return const_iterator((const T*)&mHead); }
|
||||
iterator end() {return iterator((T*)&mHead); }
|
||||
|
||||
const T& front() const
|
||||
{
|
||||
HPPA_ASSERT(!empty());
|
||||
return *begin();
|
||||
}
|
||||
T& front()
|
||||
{
|
||||
HPPA_ASSERT(!empty());
|
||||
return *begin();
|
||||
}
|
||||
const T& back() const
|
||||
{
|
||||
HPPA_ASSERT(!empty());
|
||||
return *(--end());
|
||||
}
|
||||
T& back()
|
||||
{
|
||||
HPPA_ASSERT(!empty());
|
||||
return *(--end());
|
||||
}
|
||||
|
||||
void push_front(T* v) {insert(this->begin(), v); }
|
||||
void pop_front() {erase(this->begin()); }
|
||||
void push_back(T* v) {insert(this->end(), v); }
|
||||
void pop_back() {erase(--(this->end())); }
|
||||
|
||||
iterator insert(iterator where, T* node)
|
||||
{
|
||||
T* newLink = node;
|
||||
newLink->link(where.ptr());
|
||||
return iterator(newLink);
|
||||
}
|
||||
iterator erase(iterator where)
|
||||
{
|
||||
T* node = where.ptr();
|
||||
++where;
|
||||
node->unlink();
|
||||
return where;
|
||||
}
|
||||
void erase(T* node)
|
||||
{
|
||||
node->unlink();
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
while (!this->empty())
|
||||
{
|
||||
this->pop_back();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class HpAllocator
|
||||
{
|
||||
@@ -376,7 +171,7 @@ namespace AZ {
|
||||
};
|
||||
struct page
|
||||
: public block_header_proxy /* must be first */
|
||||
, public intrusive_list<page>::node
|
||||
, public AZStd::list_base_hook<page>::node_type
|
||||
{
|
||||
page(size_t elemSize, size_t pageSize, size_t marker)
|
||||
: mBucketIndex((unsigned short)bucket_spacing_function_aligned(elemSize))
|
||||
@@ -415,7 +210,7 @@ namespace AZ {
|
||||
void dec_ref() { HPPA_ASSERT(mUseCount > 0); mUseCount--; }
|
||||
bool check_marker(size_t marker) const { return mMarker == (marker ^ ((size_t)this)); }
|
||||
};
|
||||
using page_list = intrusive_list<page>;
|
||||
using page_list = AZStd::intrusive_list<page, AZStd::list_base_hook<page>>;
|
||||
class bucket
|
||||
{
|
||||
page_list mPageList;
|
||||
@@ -442,16 +237,17 @@ namespace AZ {
|
||||
#endif
|
||||
#endif
|
||||
size_t marker() const {return mMarker; }
|
||||
const page* page_list_begin() const {return mPageList.begin(); }
|
||||
page* page_list_begin() {return mPageList.begin(); }
|
||||
const page* page_list_end() const {return mPageList.end(); }
|
||||
page* page_list_end() {return mPageList.end(); }
|
||||
auto page_list_begin() const {return mPageList.begin(); }
|
||||
auto page_list_begin() {return mPageList.begin(); }
|
||||
auto page_list_end() const {return mPageList.end(); }
|
||||
auto page_list_end() {return mPageList.end(); }
|
||||
bool page_list_empty() const {return mPageList.empty(); }
|
||||
void add_free_page(page* p) {mPageList.push_front(p); }
|
||||
void add_free_page(page* p) {mPageList.push_front(*p); }
|
||||
page* get_free_page();
|
||||
const page* get_free_page() const;
|
||||
void* alloc(page* p);
|
||||
void free(page* p, void* ptr);
|
||||
void unlink(page* p);
|
||||
};
|
||||
void* bucket_system_alloc();
|
||||
void bucket_system_free(void* ptr);
|
||||
@@ -1278,8 +1074,8 @@ namespace AZ {
|
||||
if (!next)
|
||||
{
|
||||
// if full, auto sort to back
|
||||
p->unlink();
|
||||
mPageList.push_back(p);
|
||||
mPageList.erase(*p);
|
||||
mPageList.push_back(*p);
|
||||
}
|
||||
return (void*)free;
|
||||
}
|
||||
@@ -1295,11 +1091,16 @@ namespace AZ {
|
||||
if (!free)
|
||||
{
|
||||
// if the page was previously full, auto sort to front
|
||||
p->unlink();
|
||||
mPageList.push_front(p);
|
||||
mPageList.erase(*p);
|
||||
mPageList.push_front(*p);
|
||||
}
|
||||
}
|
||||
|
||||
void HpAllocator::bucket::unlink(page* p)
|
||||
{
|
||||
mPageList.erase(*p);
|
||||
}
|
||||
|
||||
void* HpAllocator::bucket_system_alloc()
|
||||
{
|
||||
void* ptr;
|
||||
@@ -1522,8 +1323,8 @@ namespace AZ {
|
||||
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
|
||||
#endif
|
||||
#endif
|
||||
const page* pageEnd = mBuckets[i].page_list_end();
|
||||
for (const page* p = mBuckets[i].page_list_begin(); p != pageEnd; )
|
||||
auto pageEnd = mBuckets[i].page_list_end();
|
||||
for (auto p = mBuckets[i].page_list_begin(); p != pageEnd; )
|
||||
{
|
||||
// early out if we reach fully occupied page (the remaining should all be full)
|
||||
if (p->mFreeList == nullptr)
|
||||
@@ -1537,7 +1338,7 @@ namespace AZ {
|
||||
{
|
||||
AZ_TracePrintf("System", "Unused Bucket %d page %p elementSize: %d available: %d elements\n", i, p, elementSize, availableMemory / elementSize);
|
||||
}
|
||||
p = p->next();
|
||||
p = p->m_next;
|
||||
}
|
||||
}
|
||||
return unusedMemory;
|
||||
@@ -1554,21 +1355,21 @@ namespace AZ {
|
||||
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
|
||||
#endif
|
||||
#endif
|
||||
page* pageEnd = mBuckets[i].page_list_end();
|
||||
for (page* p = mBuckets[i].page_list_begin(); p != pageEnd; )
|
||||
auto pageEnd = mBuckets[i].page_list_end();
|
||||
for (auto p = mBuckets[i].page_list_begin(); p != pageEnd; )
|
||||
{
|
||||
// early out if we reach fully occupied page (the remaining should all be full)
|
||||
if (p->mFreeList == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
page* next = p->next();
|
||||
page* next = p->m_next;
|
||||
if (p->empty())
|
||||
{
|
||||
HPPA_ASSERT(p->mFreeList);
|
||||
p->unlink();
|
||||
mBuckets[i].unlink(AZStd::to_address(p));
|
||||
p->setInvalid();
|
||||
bucket_system_free(p);
|
||||
bucket_system_free(AZStd::to_address(p));
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
@@ -2239,11 +2040,17 @@ namespace AZ {
|
||||
|
||||
size_t HpAllocator::tree_get_max_allocation() const
|
||||
{
|
||||
#ifdef MULTITHREADED
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(mTreeMutex);
|
||||
#endif
|
||||
return mFreeTree.maximum()->get_block()->size();
|
||||
}
|
||||
|
||||
size_t HpAllocator::tree_get_unused_memory(bool isPrint) const
|
||||
{
|
||||
#ifdef MULTITHREADED
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(mTreeMutex);
|
||||
#endif
|
||||
size_t unusedMemory = 0;
|
||||
for (free_node_tree::const_iterator it = mFreeTree.begin(); it != mFreeTree.end(); ++it)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -159,6 +159,36 @@ namespace UnitTest
|
||||
TeardownAllocator();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* RAII wrapper around a BenchmarkEnvironmentBase to encapsulate
|
||||
* the creation and destuction of the SystemAllocator
|
||||
* SetUpBenchmark and TearDownBenchmark can still be used for custom
|
||||
* benchmark environment setup
|
||||
*/
|
||||
class ScopedAllocatorBenchmarkEnvironment
|
||||
: public AZ::Test::BenchmarkEnvironmentBase
|
||||
{
|
||||
public:
|
||||
ScopedAllocatorBenchmarkEnvironment()
|
||||
{
|
||||
// Only create the allocator if it doesn't exist
|
||||
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
|
||||
m_ownsAllocator = true;
|
||||
}
|
||||
}
|
||||
~ScopedAllocatorBenchmarkEnvironment() override
|
||||
{
|
||||
if (m_ownsAllocator)
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool m_ownsAllocator{};
|
||||
};
|
||||
#endif
|
||||
|
||||
class DLLTestVirtualClass
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -42,20 +42,13 @@ namespace AZStd
|
||||
template<class U, class Hook, class Compare>
|
||||
friend class intrusive_multiset;
|
||||
|
||||
#ifdef AZ_DEBUG_BUILD
|
||||
intrusive_multiset_node()
|
||||
{
|
||||
m_children[0] = nullptr;
|
||||
m_children[1] = nullptr;
|
||||
m_neighbours[0] = nullptr;
|
||||
m_neighbours[1] = nullptr;
|
||||
m_parentColorSide = nullptr;
|
||||
}
|
||||
intrusive_multiset_node() = default;
|
||||
~intrusive_multiset_node()
|
||||
{
|
||||
#if defined(AZ_DEBUG_BUILD)
|
||||
AZSTD_CONTAINER_ASSERT(m_children[0] == nullptr && m_children[1] == nullptr && m_parentColorSide == nullptr, "AZStd::intrusive_multiset_node - intrusive list node is being destroyed while still in a container!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// We use the lower 2 bits of the parent pointer to store
|
||||
enum Bits
|
||||
{
|
||||
@@ -95,9 +88,9 @@ namespace AZStd
|
||||
AZ_FORCE_INLINE T* next() const { return m_neighbours[AZSTD_RBTREE_RIGHT]; }
|
||||
|
||||
protected:
|
||||
T* m_children[2];
|
||||
T* m_neighbours[2];
|
||||
T* m_parentColorSide;
|
||||
T* m_children[2]{};
|
||||
T* m_neighbours[2]{};
|
||||
T* m_parentColorSide{};
|
||||
} AZ_MAY_ALIAS; // we access the object in such way that we potentially can break strict aliasing rules
|
||||
|
||||
/**
|
||||
@@ -659,12 +652,10 @@ namespace AZStd
|
||||
|
||||
--m_numElements;
|
||||
|
||||
#ifdef AZ_DEBUG_BUILD
|
||||
nodeHook->m_children[0] = nodeHook->m_children[1] = nullptr;
|
||||
nodeHook->m_parentColorSide = nullptr;
|
||||
#ifdef DEBUG_INTRUSIVE_MULTISET
|
||||
#if defined(AZ_DEBUG_BUILD) && defined(DEBUG_INTRUSIVE_MULTISET)
|
||||
validate();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -955,8 +946,11 @@ namespace AZStd
|
||||
hookNode->setParentSide(side);
|
||||
}
|
||||
|
||||
//! pre-condition
|
||||
//! @param node must be non-nullptr
|
||||
inline static node_ptr_type MinOrMax(const_node_ptr_type node, SideType side)
|
||||
{
|
||||
AZSTD_CONTAINER_ASSERT(node != nullptr, "MinOrMax can only be called with a non-nullptr node")
|
||||
const_node_ptr_type cur = node;
|
||||
const_node_ptr_type minMax = cur;
|
||||
while (!iterator_impl::isNil(cur))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -7,28 +7,13 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/UnitTest/UnitTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
|
||||
#if defined(HAVE_BENCHMARK)
|
||||
|
||||
namespace AzCore
|
||||
{
|
||||
class AzCoreBenchmarkEnvironment
|
||||
: public AZ::Test::BenchmarkEnvironmentBase
|
||||
{
|
||||
void SetUpBenchmark() override
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
|
||||
}
|
||||
void TearDownBenchmark() override
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV, AzCore::AzCoreBenchmarkEnvironment)
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV, UnitTest::ScopedAllocatorBenchmarkEnvironment)
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace Benchmark
|
||||
for (auto _ : state)
|
||||
{
|
||||
state.PauseTiming();
|
||||
|
||||
|
||||
AZStd::vector<void*>& perThreadAllocations = base::GetPerThreadAllocations(state.thread_index);
|
||||
const size_t numberOfAllocations = perThreadAllocations.size();
|
||||
size_t totalAllocationSize = 0;
|
||||
@@ -300,7 +300,7 @@ namespace Benchmark
|
||||
const AllocationSizeArray& allocationArray = s_allocationSizes[TAllocationSize];
|
||||
const size_t allocationSize = allocationArray[allocationIndex % allocationArray.size()];
|
||||
totalAllocationSize += allocationSize;
|
||||
|
||||
|
||||
state.ResumeTiming();
|
||||
perThreadAllocations[allocationIndex] = TestAllocatorType::Allocate(allocationSize, 0);
|
||||
state.PauseTiming();
|
||||
@@ -319,6 +319,8 @@ namespace Benchmark
|
||||
TestAllocatorType::GarbageCollect();
|
||||
|
||||
state.SetItemsProcessed(numberOfAllocations);
|
||||
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -364,6 +366,8 @@ namespace Benchmark
|
||||
state.SetItemsProcessed(numberOfAllocations);
|
||||
|
||||
TestAllocatorType::GarbageCollect();
|
||||
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -519,6 +523,8 @@ namespace Benchmark
|
||||
state.SetItemsProcessed(itemsProcessed);
|
||||
|
||||
TestAllocatorType::GarbageCollect();
|
||||
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -207,7 +207,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
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace AzFramework::SurfaceData
|
||||
{
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AZStd::fixed_vector<SurfaceTagWeight, Constants::MaxSurfaceWeights>>();
|
||||
serializeContext->Class<SurfacePoint>()
|
||||
->Field("m_position", &SurfacePoint::m_position)
|
||||
->Field("m_normal", &SurfacePoint::m_normal)
|
||||
@@ -46,6 +47,7 @@ namespace AzFramework::SurfaceData
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AZStd::fixed_vector<SurfaceTagWeight, Constants::MaxSurfaceWeights>>();
|
||||
behaviorContext->Class<SurfacePoint>("AzFramework::SurfaceData::SurfacePoint")
|
||||
->Attribute(AZ::Script::Attributes::Category, "SurfaceData")
|
||||
->Constructor()
|
||||
|
||||
@@ -10,13 +10,19 @@
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
|
||||
namespace AzFramework::SurfaceData
|
||||
{
|
||||
namespace Constants
|
||||
{
|
||||
static constexpr const char* s_unassignedTagName = "(unassigned)";
|
||||
|
||||
//! The maximum number of surface weights that we can store.
|
||||
//! For performance reasons, we want to limit this so that we can preallocate the max size in advance.
|
||||
//! The current number is chosen to be higher than expected needs, but small enough to avoid being excessively wasteful.
|
||||
//! (Dynamic structures would end up taking more memory than what we're preallocating)
|
||||
static constexpr size_t MaxSurfaceWeights = 16;
|
||||
}
|
||||
|
||||
struct SurfaceTagWeight
|
||||
@@ -70,7 +76,7 @@ namespace AzFramework::SurfaceData
|
||||
}
|
||||
};
|
||||
|
||||
using SurfaceTagWeightList = AZStd::vector<SurfaceTagWeight>;
|
||||
using SurfaceTagWeightList = AZStd::fixed_vector<SurfaceTagWeight, Constants::MaxSurfaceWeights>;
|
||||
|
||||
struct SurfacePoint final
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,16 @@ namespace AZ
|
||||
m_envs.push_back(std::move(env));
|
||||
}
|
||||
|
||||
// Remove a registered benchmark from the registry
|
||||
void RemoveBenchmarkEnvironment(BenchmarkEnvironmentBase* env)
|
||||
{
|
||||
auto RemoveBenchmarkFunc = [env](const std::unique_ptr<BenchmarkEnvironmentBase>& envElement)
|
||||
{
|
||||
return envElement.get() == env;
|
||||
};
|
||||
m_envs.erase(std::remove_if(m_envs.begin(), m_envs.end(), std::move(RemoveBenchmarkFunc)));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<BenchmarkEnvironmentBase>>& GetBenchmarkEnvironments()
|
||||
{
|
||||
return m_envs;
|
||||
@@ -194,21 +204,26 @@ namespace AZ
|
||||
return *benchmarkEnv;
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
std::array<BenchmarkEnvironmentBase*, sizeof...(Ts)> RegisterBenchmarkEnvironments()
|
||||
/*
|
||||
* An RAII wrapper about registering a BenchmarkEnvironment with the BenchmarkRegistry
|
||||
* It will unregister the BenchmarkEnvironment with the BenchmarkRegistry on destruction
|
||||
*/
|
||||
struct ScopedRegisterBenchmarkEnvironment
|
||||
{
|
||||
constexpr size_t EnvironmentCount{ sizeof...(Ts) };
|
||||
if constexpr (EnvironmentCount)
|
||||
template<typename T>
|
||||
ScopedRegisterBenchmarkEnvironment(T& benchmarkEnv)
|
||||
: m_benchmarkEnv(benchmarkEnv)
|
||||
{}
|
||||
~ScopedRegisterBenchmarkEnvironment()
|
||||
{
|
||||
std::array<BenchmarkEnvironmentBase*, EnvironmentCount> benchmarkEnvs{ { &RegisterBenchmarkEnvironment<Ts>()... } };
|
||||
return benchmarkEnvs;
|
||||
if (auto benchmarkRegistry = AZ::Environment::FindVariable<BenchmarkEnvironmentRegistry>(s_benchmarkEnvironmentName);
|
||||
benchmarkRegistry != nullptr)
|
||||
{
|
||||
benchmarkRegistry->RemoveBenchmarkEnvironment(&m_benchmarkEnv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::array<BenchmarkEnvironmentBase*, EnvironmentCount> benchmarkEnvs{};
|
||||
return benchmarkEnvs;
|
||||
}
|
||||
}
|
||||
BenchmarkEnvironmentBase& m_benchmarkEnv;
|
||||
};
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! listener class to capture and print test output for embedded platforms
|
||||
@@ -276,7 +291,7 @@ namespace AZ
|
||||
#define AZ_BENCHMARK_HOOK_ENV(TEST_ENV) \
|
||||
AZTEST_EXPORT int AzRunBenchmarks(int argc, char** argv) \
|
||||
{ \
|
||||
AZ::Test::RegisterBenchmarkEnvironments<TEST_ENV>(); \
|
||||
AZ::Test::ScopedRegisterBenchmarkEnvironment scopedBenchmarkEnv(AZ::Test::RegisterBenchmarkEnvironment<TEST_ENV>()); \
|
||||
auto benchmarkEnvRegistry = AZ::Environment::FindVariable<AZ::Test::BenchmarkEnvironmentRegistry>(AZ::Test::s_benchmarkEnvironmentName); \
|
||||
std::vector<std::unique_ptr<AZ::Test::BenchmarkEnvironmentBase>>* benchmarkEnvs = benchmarkEnvRegistry ? &(benchmarkEnvRegistry->GetBenchmarkEnvironments()) : nullptr; \
|
||||
if (benchmarkEnvs != nullptr) \
|
||||
@@ -307,7 +322,6 @@ AZTEST_EXPORT int AzRunBenchmarks(int argc, char** argv) \
|
||||
#define AZ_BENCHMARK_HOOK() \
|
||||
AZTEST_EXPORT int AzRunBenchmarks(int argc, char** argv) \
|
||||
{ \
|
||||
AZ::Test::RegisterBenchmarkEnvironments<>(); \
|
||||
auto benchmarkEnvRegistry = AZ::Environment::FindVariable<AZ::Test::BenchmarkEnvironmentRegistry>(AZ::Test::s_benchmarkEnvironmentName); \
|
||||
std::vector<std::unique_ptr<AZ::Test::BenchmarkEnvironmentBase>>* benchmarkEnvs = benchmarkEnvRegistry ? &(benchmarkEnvRegistry->GetBenchmarkEnvironments()) : nullptr; \
|
||||
if (benchmarkEnvs != nullptr) \
|
||||
|
||||
+3
-4
@@ -21,7 +21,6 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetEntryChangeset.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/FolderThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
|
||||
@@ -71,9 +70,9 @@ namespace AzToolsFramework
|
||||
AssetBrowserInteractionNotificationBus::Handler::BusConnect();
|
||||
|
||||
using namespace Thumbnailer;
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(FolderThumbnailCache), ThumbnailContext::DefaultContext);
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SourceThumbnailCache), ThumbnailContext::DefaultContext);
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(ProductThumbnailCache), ThumbnailContext::DefaultContext);
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(FolderThumbnailCache));
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SourceThumbnailCache));
|
||||
ThumbnailerRequestBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(ProductThumbnailCache));
|
||||
|
||||
AzFramework::SocketConnection* socketConn = AzFramework::SocketConnection::GetInstance();
|
||||
AZ_Assert(socketConn, "AzToolsFramework::AssetBrowser::AssetBrowserComponent requires a valid socket conection!");
|
||||
|
||||
+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();
|
||||
|
||||
|
||||
+3
-1
@@ -75,7 +75,9 @@ namespace AzToolsFramework
|
||||
bool foundIt = false;
|
||||
AZStd::string watchFolder;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, iconPath.toUtf8().constData(), assetInfo, watchFolder);
|
||||
AssetSystemRequestBus::BroadcastResult(
|
||||
foundIt, &AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, iconPath.toUtf8().constData(), assetInfo,
|
||||
watchFolder);
|
||||
|
||||
if (foundIt)
|
||||
{
|
||||
|
||||
+2
-1
@@ -67,7 +67,8 @@ namespace AzToolsFramework
|
||||
bool foundIt = false;
|
||||
AZStd::string watchFolder;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AssetSystemRequestBus::BroadcastResult(foundIt, &AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, sourceKey->GetSourceUuid(), assetInfo, watchFolder);
|
||||
AssetSystemRequestBus::BroadcastResult(
|
||||
foundIt, &AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, sourceKey->GetSourceUuid(), assetInfo, watchFolder);
|
||||
|
||||
QString iconPathToUse;
|
||||
if (foundIt)
|
||||
|
||||
-5
@@ -203,11 +203,6 @@ namespace AzToolsFramework
|
||||
return selectionModel()->selectedIndexes();
|
||||
}
|
||||
|
||||
void AssetBrowserTreeView::SetThumbnailContext(const char* thumbnailContext) const
|
||||
{
|
||||
m_delegate->SetThumbnailContext(thumbnailContext);
|
||||
}
|
||||
|
||||
void AssetBrowserTreeView::SetShowSourceControlIcons(bool showSourceControlsIcons)
|
||||
{
|
||||
m_delegate->SetShowSourceControlIcons(showSourceControlsIcons);
|
||||
|
||||
-1
@@ -73,7 +73,6 @@ namespace AzToolsFramework
|
||||
void OnAssetBrowserComponentReady() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SetThumbnailContext(const char* context) const;
|
||||
void SetShowSourceControlIcons(bool showSourceControlsIcons);
|
||||
void UpdateAfterFilter(bool hasFilter, bool selectFirstValidEntry);
|
||||
|
||||
|
||||
+2
-7
@@ -112,11 +112,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EntryDelegate::SetThumbnailContext(const char* thumbnailContext)
|
||||
{
|
||||
m_thumbnailContext = thumbnailContext;
|
||||
}
|
||||
|
||||
void EntryDelegate::SetShowSourceControlIcons(bool showSourceControl)
|
||||
{
|
||||
m_showSourceControl = showSourceControl;
|
||||
@@ -125,8 +120,8 @@ namespace AzToolsFramework
|
||||
int EntryDelegate::DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
ThumbnailerRequestsBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, thumbnailKey, m_thumbnailContext.c_str());
|
||||
AZ_Assert(thumbnail, "The shared numbernail was not available from the ThumbnailerRequestsBus.");
|
||||
ThumbnailerRequestBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, thumbnailKey);
|
||||
AZ_Assert(thumbnail, "The shared numbernail was not available from the ThumbnailerRequestBus.");
|
||||
AZ_Assert(painter, "A null QPainter was passed in to DrawThumbnail.");
|
||||
if (!painter || !thumbnail || thumbnail->GetState() == Thumbnail::State::Failed)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
|
||||
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
|
||||
#include <QStyledItemDelegate>
|
||||
@@ -50,14 +49,11 @@ namespace AzToolsFramework
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
//! Set location where thumbnails are located for this instance of asset browser
|
||||
void SetThumbnailContext(const char* thumbnailContext);
|
||||
//! Set whether to show source control icons, this is still temporary mainly to support existing functionality of material browser
|
||||
void SetShowSourceControlIcons(bool showSourceControl);
|
||||
|
||||
protected:
|
||||
int m_iconSize;
|
||||
AZStd::string m_thumbnailContext = ThumbnailContext::DefaultContext;
|
||||
bool m_showSourceControl = false;
|
||||
//! Draw a thumbnail and return its width
|
||||
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const;
|
||||
|
||||
+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;
|
||||
|
||||
@@ -23,7 +23,15 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ThumbnailKey
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool ThumbnailKey::IsReady() const { return m_ready; }
|
||||
void ThumbnailKey::SetReady(bool ready)
|
||||
{
|
||||
m_ready = ready;
|
||||
}
|
||||
|
||||
bool ThumbnailKey::IsReady() const
|
||||
{
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
bool ThumbnailKey::UpdateThumbnail()
|
||||
{
|
||||
@@ -75,10 +83,8 @@ namespace AzToolsFramework
|
||||
if (m_state == State::Unloaded)
|
||||
{
|
||||
m_state = State::Loading;
|
||||
QThreadPool* threadPool;
|
||||
ThumbnailContextRequestBus::BroadcastResult(
|
||||
threadPool,
|
||||
&ThumbnailContextRequestBus::Handler::GetThreadPool);
|
||||
QThreadPool* threadPool = {};
|
||||
ThumbnailerRequestBus::BroadcastResult(threadPool, &ThumbnailerRequestBus::Handler::GetThreadPool);
|
||||
QFuture<void> future = QtConcurrent::run(threadPool, [this](){ LoadThread(); });
|
||||
m_watcher.setFuture(future);
|
||||
}
|
||||
|
||||
@@ -26,13 +26,11 @@ namespace AzToolsFramework
|
||||
//! ThumbnailKey is used to locate thumbnails in thumbnail cache
|
||||
/*
|
||||
ThumbnailKey contains any kind of identifiable information to retrieve thumbnails (e.g. assetId, assetType, filename, etc.)
|
||||
To use thumbnail system, keep reference to your thumbnail key, and retrieve Thumbnail via ThumbnailerRequestsBus
|
||||
To use thumbnail system, keep reference to your thumbnail key, and retrieve Thumbnail via ThumbnailerRequestBus
|
||||
*/
|
||||
class ThumbnailKey
|
||||
: public QObject
|
||||
{
|
||||
friend class ThumbnailContext;
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_RTTI(ThumbnailKey, "{43F20F6B-333D-4226-8E4F-331A62315255}");
|
||||
@@ -40,6 +38,8 @@ namespace AzToolsFramework
|
||||
ThumbnailKey() = default;
|
||||
virtual ~ThumbnailKey() = default;
|
||||
|
||||
void SetReady(bool ready);
|
||||
|
||||
bool IsReady() const;
|
||||
|
||||
virtual bool UpdateThumbnail();
|
||||
@@ -47,13 +47,13 @@ namespace AzToolsFramework
|
||||
virtual size_t GetHash() const;
|
||||
|
||||
virtual bool Equals(const ThumbnailKey* other) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
//! Updated signal is dispatched whenever thumbnail data was changed. Anyone using this thumbnail should listen to this.
|
||||
void ThumbnailUpdatedSignal() const;
|
||||
//! Force update mapped thumbnails
|
||||
void UpdateThumbnailSignal() const;
|
||||
|
||||
|
||||
private:
|
||||
bool m_ready = false;
|
||||
};
|
||||
@@ -114,11 +114,14 @@ namespace AzToolsFramework
|
||||
ThumbnailProvider() = default;
|
||||
virtual ~ThumbnailProvider() = default;
|
||||
virtual bool GetThumbnail(SharedThumbnailKey key, SharedThumbnail& thumbnail) = 0;
|
||||
//! Priority identifies ThumbnailProvider order in ThumbnailContext
|
||||
//! Higher priority means this ThumbnailProvider will take precedence in generating a thumbnail when
|
||||
//! a supplied ThumbnailKey is supported by multiple providers.
|
||||
virtual int GetPriority() const { return 0; }
|
||||
//! A unique ThumbnailProvider name identifying it in a ThumbnailContext
|
||||
//! Priority identifies ThumbnailProvider order
|
||||
//! Higher priority means this ThumbnailProvider will take precedence in generating a thumbnail when a supplied ThumbnailKey is
|
||||
//! supported by multiple providers.
|
||||
virtual int GetPriority() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//! A unique ThumbnailProvider name identifyier
|
||||
virtual const char* GetProviderName() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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 <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/MissingThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/LoadingThumbnail.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option") // 4251: 'QImageIOHandler::d_ptr': class 'QScopedPointer<QImageIOHandlerPrivate,QScopedPointerDeleter<T>>' needs to have dll-interface to be used by clients of class 'QImageIOHandler'
|
||||
#include <AzQtComponents/Components/StyledBusyLabel.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
ThumbnailContext::ThumbnailContext()
|
||||
: m_missingThumbnail(new MissingThumbnail())
|
||||
, m_loadingThumbnail(new LoadingThumbnail())
|
||||
, m_threadPool(this)
|
||||
{
|
||||
ThumbnailContextRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
ThumbnailContext::~ThumbnailContext()
|
||||
{
|
||||
ThumbnailContextRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool ThumbnailContext::IsLoading(SharedThumbnailKey key)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
return thumbnail->GetState() == Thumbnail::State::Unloaded ||
|
||||
thumbnail->GetState() == Thumbnail::State::Loading;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThumbnailContext::RedrawThumbnail()
|
||||
{
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(&AzToolsFramework::AssetBrowser::AssetBrowserViewRequests::Update);
|
||||
}
|
||||
|
||||
QThreadPool* ThumbnailContext::GetThreadPool()
|
||||
{
|
||||
return &m_threadPool;
|
||||
}
|
||||
|
||||
SharedThumbnail ThumbnailContext::GetThumbnail(SharedThumbnailKey key)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
// find provider who can handle supplied key
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
// if thumbnail is ready return it
|
||||
if (thumbnail->GetState() == Thumbnail::State::Ready)
|
||||
{
|
||||
return thumbnail;
|
||||
}
|
||||
// if thumbnail is not loaded, start loading it, meanwhile return loading thumbnail
|
||||
if (thumbnail->GetState() == Thumbnail::State::Unloaded)
|
||||
{
|
||||
// listen to the loading signal, so the anyone using it will update loading animation
|
||||
connect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
AzQtComponents::StyledBusyLabel* busyLabel;
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserComponentRequestBus::BroadcastResult(busyLabel, &AzToolsFramework::AssetBrowser::AssetBrowserComponentRequests::GetStyledBusyLabel);
|
||||
connect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailContext::RedrawThumbnail);
|
||||
// once the thumbnail is loaded, disconnect it from loading thumbnail
|
||||
connect(thumbnail.data(), &Thumbnail::Updated, this , [this, key, thumbnail, busyLabel]()
|
||||
{
|
||||
disconnect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
disconnect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailContext::RedrawThumbnail);
|
||||
thumbnail->disconnect();
|
||||
connect(thumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
connect(key.data(), &ThumbnailKey::UpdateThumbnailSignal, thumbnail.data(), &Thumbnail::Update);
|
||||
key->m_ready = true;
|
||||
Q_EMIT key->ThumbnailUpdatedSignal();
|
||||
});
|
||||
thumbnail->Load();
|
||||
}
|
||||
if (thumbnail->GetState() == Thumbnail::State::Failed)
|
||||
{
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
return m_loadingThumbnail;
|
||||
}
|
||||
}
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
|
||||
void ThumbnailContext::RegisterThumbnailProvider(SharedThumbnailProvider providerToAdd)
|
||||
{
|
||||
auto it = AZStd::find_if(m_providers.begin(), m_providers.end(), [providerToAdd](const SharedThumbnailProvider& provider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), providerToAdd->GetProviderName());
|
||||
});
|
||||
|
||||
if (it != m_providers.end())
|
||||
{
|
||||
AZ_Error("ThumbnailContext", false, "Provider with name %s is already registered with context.", providerToAdd->GetProviderName());
|
||||
return;
|
||||
}
|
||||
|
||||
m_providers.insert(providerToAdd);
|
||||
}
|
||||
|
||||
void ThumbnailContext::UnregisterThumbnailProvider(const char* providerName)
|
||||
{
|
||||
auto it = AZStd::remove_if(m_providers.begin(), m_providers.end(), [providerName](const SharedThumbnailProvider& provider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), providerName);
|
||||
});
|
||||
m_providers.erase(it, m_providers.end());
|
||||
}
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#include "Thumbnails/moc_ThumbnailContext.cpp"
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QThreadPool>
|
||||
#endif
|
||||
|
||||
class QString;
|
||||
class QPixmap;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
class ThumbnailProvider;
|
||||
|
||||
//! ThumbnailContext provides distinct thumbnail location for specific context
|
||||
/*
|
||||
There can be any number of contexts for every unique feature that may need different types of thumbnails.
|
||||
For example 'AssetBrowser' context provides thumbnails specific to Asset Browser
|
||||
'PreviewContext' may provide thumbnails for Preview Widget
|
||||
'MaterialBrowser' may provide thumbnails for Material Browser
|
||||
etc.
|
||||
*/
|
||||
class ThumbnailContext
|
||||
: public QObject
|
||||
, public ThumbnailContextRequestBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ThumbnailContext, AZ::SystemAllocator, 0);
|
||||
|
||||
ThumbnailContext();
|
||||
~ThumbnailContext() override;
|
||||
|
||||
//! Is the thumbnail currently loading or is about to load.
|
||||
bool IsLoading(SharedThumbnailKey key);
|
||||
//! Retrieve thumbnail by key, generate one if needed
|
||||
SharedThumbnail GetThumbnail(SharedThumbnailKey key);
|
||||
//! Add new thumbnail cache
|
||||
void RegisterThumbnailProvider(SharedThumbnailProvider providerToAdd);
|
||||
//! Remove thumbnail cache by name if found
|
||||
void UnregisterThumbnailProvider(const char* providerName);
|
||||
|
||||
void RedrawThumbnail();
|
||||
|
||||
//! Default context used for most thumbnails
|
||||
static constexpr const char* DefaultContext = "Default";
|
||||
|
||||
// ThumbnailContextRequestBus::Handler interface overrides...
|
||||
QThreadPool* GetThreadPool() override;
|
||||
|
||||
private:
|
||||
struct ProviderCompare {
|
||||
bool operator() (const SharedThumbnailProvider& lhs, const SharedThumbnailProvider& rhs) const
|
||||
{
|
||||
// sorting in reverse, higher priority means the provider should be considered first
|
||||
return lhs->GetPriority() > rhs->GetPriority();
|
||||
}
|
||||
};
|
||||
|
||||
//! Collection of thumbnail caches provided by this context
|
||||
AZStd::multiset<SharedThumbnailProvider, ProviderCompare> m_providers;
|
||||
//! Default missing thumbnail used when no thumbnail for given key can be found within this context
|
||||
SharedThumbnail m_missingThumbnail;
|
||||
//! Default loading thumbnail used when thumbnail is found by is not yet generated
|
||||
SharedThumbnail m_loadingThumbnail;
|
||||
//! There is only a limited number of threads on global threadPool, because there can be many thumbnails rendering at once
|
||||
//! an individual threadPool is needed to avoid deadlocks
|
||||
QThreadPool m_threadPool;
|
||||
};
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
@@ -30,14 +30,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailWidget::SetThumbnailKey(SharedThumbnailKey key, const char* contextName)
|
||||
void ThumbnailWidget::SetThumbnailKey(SharedThumbnailKey key)
|
||||
{
|
||||
if (m_key)
|
||||
{
|
||||
disconnect(m_key.data(), &ThumbnailKey::ThumbnailUpdatedSignal, this, &ThumbnailWidget::KeyUpdatedSlot);
|
||||
}
|
||||
m_key = key;
|
||||
m_contextName = contextName;
|
||||
connect(m_key.data(), &ThumbnailKey::ThumbnailUpdatedSignal, this, &ThumbnailWidget::KeyUpdatedSlot);
|
||||
repaint();
|
||||
}
|
||||
@@ -65,7 +64,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
// thumbnail instance is not stored locally, but retrieved each paintEvent since thumbnail mapped to a specific key may change
|
||||
SharedThumbnail thumbnail;
|
||||
ThumbnailerRequestsBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, m_key, m_contextName.c_str());
|
||||
ThumbnailerRequestBus::BroadcastResult(thumbnail, &ThumbnailerRequests::GetThumbnail, m_key);
|
||||
QPainter painter(this);
|
||||
|
||||
// Scaling and centering pixmap within bounds to preserve aspect ratio
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace AzToolsFramework
|
||||
~ThumbnailWidget() override = default;
|
||||
|
||||
//! Call this to set what thumbnail widget will display
|
||||
void SetThumbnailKey(SharedThumbnailKey key, const char* contextName = "Default");
|
||||
void SetThumbnailKey(SharedThumbnailKey key);
|
||||
//! Remove current thumbnail
|
||||
void ClearThumbnail();
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
SharedThumbnailKey m_key;
|
||||
AZStd::string m_contextName;
|
||||
|
||||
private Q_SLOTS:
|
||||
void KeyUpdatedSlot();
|
||||
|
||||
@@ -19,48 +19,30 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
//! Interaction with thumbnail context
|
||||
class ThumbnailContextRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Get thread pool for drawing thumbnails
|
||||
virtual QThreadPool* GetThreadPool() = 0;
|
||||
};
|
||||
|
||||
using ThumbnailContextRequestBus = AZ::EBus<ThumbnailContextRequests>;
|
||||
|
||||
//! Interaction with thumbnailer
|
||||
class ThumbnailerRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Add thumbnail context
|
||||
virtual void RegisterContext(const char* contextName) = 0;
|
||||
//! Add new thumbnail provider
|
||||
virtual void RegisterThumbnailProvider(SharedThumbnailProvider provider) = 0;
|
||||
|
||||
//! Remove thumbnail context and all associated ThumbnailProviders
|
||||
virtual void UnregisterContext(const char* contextName) = 0;
|
||||
|
||||
//! Return whether a given ThumbnailContext has been registered
|
||||
virtual bool HasContext(const char* contextName) const = 0;
|
||||
|
||||
//! Add new thumbnail provider to ThumbnailContext
|
||||
virtual void RegisterThumbnailProvider(SharedThumbnailProvider provider, const char* contextName) = 0;
|
||||
|
||||
//! Remove thumbnail provider from ThumbnailContext
|
||||
virtual void UnregisterThumbnailProvider(const char* providerName, const char* contextName) = 0;
|
||||
//! Remove thumbnail provider
|
||||
virtual void UnregisterThumbnailProvider(const char* providerName) = 0;
|
||||
|
||||
//! Retrieve thumbnail by key,
|
||||
//! if no thumbnail matching found, one of ThumbnailProviders will attempt to create
|
||||
//! If no compatible providers found, MissingThumbnail will be returned
|
||||
virtual SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey, const char* contextName) = 0;
|
||||
virtual SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey) = 0;
|
||||
|
||||
//! Return whether the thumbnail is loading.
|
||||
virtual bool IsLoading(SharedThumbnailKey thumbnailKey, const char* contextName) = 0;
|
||||
virtual bool IsLoading(SharedThumbnailKey thumbnailKey) = 0;
|
||||
|
||||
//! Get thread pool for drawing thumbnails
|
||||
virtual QThreadPool* GetThreadPool() = 0;
|
||||
};
|
||||
|
||||
using ThumbnailerRequestBus = AZ::EBus<ThumbnailerRequests>;
|
||||
using ThumbnailerRequestsBus = AZ::EBus<ThumbnailerRequests>; //deprecated
|
||||
|
||||
//! Request product thumbnail to be rendered
|
||||
class ThumbnailerRendererRequests
|
||||
|
||||
+97
-38
@@ -6,11 +6,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzQtComponents/Components/StyledBusyLabel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/LoadingThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/MissingThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
@@ -19,8 +22,10 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
|
||||
ThumbnailerComponent::ThumbnailerComponent()
|
||||
: m_missingThumbnail(new MissingThumbnail())
|
||||
, m_loadingThumbnail(new LoadingThumbnail())
|
||||
, m_threadPool(this)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,14 +33,13 @@ namespace AzToolsFramework
|
||||
|
||||
void ThumbnailerComponent::Activate()
|
||||
{
|
||||
RegisterContext(ThumbnailContext::DefaultContext);
|
||||
BusConnect();
|
||||
ThumbnailerRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::Deactivate()
|
||||
{
|
||||
BusDisconnect();
|
||||
m_thumbnails.clear();
|
||||
ThumbnailerRequestBus::Handler::BusDisconnect();
|
||||
m_providers.clear();
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::Reflect(AZ::ReflectContext* context)
|
||||
@@ -49,59 +53,114 @@ namespace AzToolsFramework
|
||||
|
||||
void ThumbnailerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
incompatible.push_back(AZ_CRC_CE("ThumbnailerService"));
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
provided.push_back(AZ_CRC_CE("ThumbnailerService"));
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::RegisterContext(const char* contextName)
|
||||
void ThumbnailerComponent::RegisterThumbnailProvider(SharedThumbnailProvider provider)
|
||||
{
|
||||
AZ_Assert(m_thumbnails.find(contextName) == m_thumbnails.end(), "Context %s already registered", contextName);
|
||||
m_thumbnails[contextName] = AZStd::make_shared<ThumbnailContext>();
|
||||
auto it = AZStd::find_if(m_providers.begin(), m_providers.end(), [provider](const SharedThumbnailProvider& existingProvider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), existingProvider->GetProviderName());
|
||||
});
|
||||
|
||||
if (it != m_providers.end())
|
||||
{
|
||||
AZ_Error("ThumbnailerComponent", false, "Provider with name %s is already registered with context.", provider->GetProviderName());
|
||||
return;
|
||||
}
|
||||
|
||||
m_providers.insert(provider);
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::UnregisterContext(const char* contextName)
|
||||
void ThumbnailerComponent::UnregisterThumbnailProvider(const char* providerName)
|
||||
{
|
||||
AZ_Assert(m_thumbnails.find(contextName) != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
m_thumbnails.erase(contextName);
|
||||
AZStd::erase_if(
|
||||
m_providers,
|
||||
[providerName](const SharedThumbnailProvider& provider)
|
||||
{
|
||||
return AZ::StringFunc::Equal(provider->GetProviderName(), providerName);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
bool ThumbnailerComponent::HasContext(const char* contextName) const
|
||||
SharedThumbnail ThumbnailerComponent::GetThumbnail(SharedThumbnailKey key)
|
||||
{
|
||||
return m_thumbnails.find(contextName) != m_thumbnails.end();
|
||||
// find provider who can handle supplied key
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
// if thumbnail is ready return it
|
||||
if (thumbnail->GetState() == Thumbnail::State::Ready)
|
||||
{
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
// if thumbnail is not loaded, start loading it, meanwhile return loading thumbnail
|
||||
if (thumbnail->GetState() == Thumbnail::State::Unloaded)
|
||||
{
|
||||
// listen to the loading signal, so the anyone using it will update loading animation
|
||||
AzQtComponents::StyledBusyLabel* busyLabel;
|
||||
AssetBrowser::AssetBrowserComponentRequestBus::BroadcastResult(busyLabel, &AssetBrowser::AssetBrowserComponentRequests::GetStyledBusyLabel);
|
||||
QObject::connect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
QObject::connect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailerComponent::RedrawThumbnail);
|
||||
|
||||
// once the thumbnail is loaded, disconnect it from loading thumbnail
|
||||
QObject::connect(thumbnail.data(), &Thumbnail::Updated, this , [this, key, thumbnail, busyLabel]()
|
||||
{
|
||||
QObject::disconnect(m_loadingThumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
QObject::disconnect(busyLabel, &AzQtComponents::StyledBusyLabel::repaintNeeded, this, &ThumbnailerComponent::RedrawThumbnail);
|
||||
|
||||
thumbnail->disconnect();
|
||||
QObject::connect(thumbnail.data(), &Thumbnail::Updated, key.data(), &ThumbnailKey::ThumbnailUpdatedSignal);
|
||||
QObject::connect(key.data(), &ThumbnailKey::UpdateThumbnailSignal, thumbnail.data(), &Thumbnail::Update);
|
||||
|
||||
key->SetReady(true);
|
||||
Q_EMIT key->ThumbnailUpdatedSignal();
|
||||
});
|
||||
|
||||
thumbnail->Load();
|
||||
}
|
||||
|
||||
if (thumbnail->GetState() == Thumbnail::State::Failed)
|
||||
{
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
|
||||
return m_loadingThumbnail;
|
||||
}
|
||||
}
|
||||
return m_missingThumbnail;
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::RegisterThumbnailProvider(SharedThumbnailProvider provider, const char* contextName)
|
||||
bool ThumbnailerComponent::IsLoading(SharedThumbnailKey key)
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
it->second->RegisterThumbnailProvider(provider);
|
||||
for (auto& provider : m_providers)
|
||||
{
|
||||
SharedThumbnail thumbnail;
|
||||
if (provider->GetThumbnail(key, thumbnail))
|
||||
{
|
||||
return thumbnail->GetState() == Thumbnail::State::Unloaded || thumbnail->GetState() == Thumbnail::State::Loading;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThumbnailerComponent::UnregisterThumbnailProvider(const char* providerName, const char* contextName)
|
||||
QThreadPool* ThumbnailerComponent::GetThreadPool()
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
it->second->UnregisterThumbnailProvider(providerName);
|
||||
return &m_threadPool;
|
||||
}
|
||||
|
||||
SharedThumbnail ThumbnailerComponent::GetThumbnail(SharedThumbnailKey key, const char* contextName)
|
||||
void ThumbnailerComponent::RedrawThumbnail()
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
return it->second->GetThumbnail(key);
|
||||
AssetBrowser::AssetBrowserViewRequestBus::Broadcast(&AssetBrowser::AssetBrowserViewRequests::Update);
|
||||
}
|
||||
|
||||
bool ThumbnailerComponent::IsLoading(SharedThumbnailKey key, const char* contextName)
|
||||
{
|
||||
auto it = m_thumbnails.find(contextName);
|
||||
AZ_Assert(it != m_thumbnails.end(), "Context %s not registered", contextName);
|
||||
return it->second->IsLoading(key);
|
||||
}
|
||||
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
+41
-18
@@ -7,19 +7,29 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QThreadPool>
|
||||
#endif
|
||||
|
||||
class QString;
|
||||
class QPixmap;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
class ThumbnailContext;
|
||||
|
||||
class ThumbnailerComponent
|
||||
: public AZ::Component
|
||||
, public ThumbnailerRequestsBus::Handler
|
||||
, public ThumbnailerRequestBus::Handler
|
||||
, public QObject
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ThumbnailerComponent, "{80090CA5-6A3A-4554-B5FE-A6D74ECB2D84}")
|
||||
@@ -27,28 +37,41 @@ namespace AzToolsFramework
|
||||
ThumbnailerComponent();
|
||||
virtual ~ThumbnailerComponent();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ThumbnailerRequests
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void RegisterContext(const char* contextName) override;
|
||||
void UnregisterContext(const char* contextName) override;
|
||||
bool HasContext(const char* contextName) const override;
|
||||
void RegisterThumbnailProvider(SharedThumbnailProvider provider, const char* contextName) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName, const char* contextName) override;
|
||||
SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
bool IsLoading(SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
// ThumbnailerRequestBus::Handler interface overrides...
|
||||
void RegisterThumbnailProvider(SharedThumbnailProvider provider) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName) override;
|
||||
SharedThumbnail GetThumbnail(SharedThumbnailKey thumbnailKey) override;
|
||||
bool IsLoading(SharedThumbnailKey thumbnailKey) override;
|
||||
QThreadPool* GetThreadPool() override;
|
||||
|
||||
void RedrawThumbnail();
|
||||
|
||||
private:
|
||||
AZStd::unordered_map<AZStd::string, AZStd::shared_ptr<ThumbnailContext>> m_thumbnails;
|
||||
struct ProviderCompare
|
||||
{
|
||||
bool operator()(const SharedThumbnailProvider& lhs, const SharedThumbnailProvider& rhs) const
|
||||
{
|
||||
// sorting in reverse, higher priority means the provider should be considered first
|
||||
return lhs->GetPriority() > rhs->GetPriority();
|
||||
}
|
||||
};
|
||||
|
||||
//! Collection of thumbnail caches provided by this context
|
||||
AZStd::multiset<SharedThumbnailProvider, ProviderCompare> m_providers;
|
||||
//! Default missing thumbnail used when no thumbnail for given key can be found within this context
|
||||
SharedThumbnail m_missingThumbnail;
|
||||
//! Default loading thumbnail used when thumbnail is found by is not yet generated
|
||||
SharedThumbnail m_loadingThumbnail;
|
||||
//! There is only a limited number of threads on global threadPool, because there can be many thumbnails rendering at once
|
||||
//! an individual threadPool is needed to avoid deadlocks
|
||||
QThreadPool m_threadPool;
|
||||
};
|
||||
} // Thumbnailer
|
||||
} // namespace AssetBrowser
|
||||
|
||||
+9
-18
@@ -9,7 +9,6 @@
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerNullComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/MissingThumbnail.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -47,35 +46,27 @@ namespace AzToolsFramework
|
||||
services.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::RegisterContext(const char* /*contextName*/)
|
||||
void ThumbnailerNullComponent::RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider /*provider*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::UnregisterContext(const char* /*contextName*/)
|
||||
void ThumbnailerNullComponent::UnregisterThumbnailProvider(const char* /*providerName*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool ThumbnailerNullComponent::HasContext(const char* /*contextName*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider /*provider*/, const char* /*contextName*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailerNullComponent::UnregisterThumbnailProvider(const char* /*providerName*/, const char* /*contextName*/)
|
||||
{
|
||||
}
|
||||
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail ThumbnailerNullComponent::GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*key*/, const char* /*contextName*/)
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail ThumbnailerNullComponent::GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*key*/)
|
||||
{
|
||||
return m_nullThumbnail;
|
||||
}
|
||||
|
||||
bool ThumbnailerNullComponent::IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*thumbnailKey*/, const char* /*contextName*/)
|
||||
bool ThumbnailerNullComponent::IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey /*thumbnailKey*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QThreadPool* ThumbnailerNullComponent::GetThreadPool()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace Thumbnailer
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+7
-10
@@ -19,11 +19,9 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Thumbnailer
|
||||
{
|
||||
class ThumbnailContext;
|
||||
|
||||
class ThumbnailerNullComponent
|
||||
: public AZ::Component
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRequestsBus::Handler
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ThumbnailerNullComponent, "{8009D651-3FAA-9815-B99E-AF174A3B29D4}")
|
||||
@@ -42,13 +40,12 @@ namespace AzToolsFramework
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ThumbnailerRequests
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void RegisterContext(const char* contextName) override;
|
||||
void UnregisterContext(const char* contextName) override;
|
||||
bool HasContext(const char* contextName) const override;
|
||||
void RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider provider, const char* contextName) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName, const char* contextName) override;
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
bool IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, const char* contextName) override;
|
||||
void RegisterThumbnailProvider(AzToolsFramework::Thumbnailer::SharedThumbnailProvider provider) override;
|
||||
void UnregisterThumbnailProvider(const char* providerName) override;
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail GetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey) override;
|
||||
bool IsLoading(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey) override;
|
||||
QThreadPool* GetThreadPool() override;
|
||||
|
||||
private:
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnail m_nullThumbnail;
|
||||
};
|
||||
|
||||
+9
-1
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
@@ -117,9 +118,16 @@ namespace AzToolsFramework
|
||||
{
|
||||
}
|
||||
|
||||
bool EditorEntityUiHandlerBase::OnEntityDoubleClick([[maybe_unused]] AZ::EntityId entityId) const
|
||||
bool EditorEntityUiHandlerBase::OnOutlinerItemDoubleClick([[maybe_unused]] const QModelIndex& index) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::EntityId EditorEntityUiHandlerBase::GetEntityIdFromIndex(const QModelIndex& index)
|
||||
{
|
||||
QModelIndex firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
|
||||
|
||||
return AZ::EntityId(firstColumnIndex.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+12
-8
@@ -21,7 +21,6 @@ class QTreeView;
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! Defines a handler that can customize entity UI appearance and behavior in the Entity Outliner.
|
||||
//! This class is meant to be abstract, entities do not have a handler by default.
|
||||
class EditorEntityUiHandlerBase
|
||||
{
|
||||
protected:
|
||||
@@ -33,7 +32,7 @@ namespace AzToolsFramework
|
||||
public:
|
||||
EditorEntityUiHandlerId GetHandlerId();
|
||||
|
||||
// # Entity Outliner
|
||||
// # Entity Outliner Item
|
||||
|
||||
//! Returns the item info string that is appended to the item name in the Outliner.
|
||||
virtual QString GenerateItemInfoString(AZ::EntityId entityId) const;
|
||||
@@ -41,10 +40,12 @@ namespace AzToolsFramework
|
||||
virtual QString GenerateItemTooltip(AZ::EntityId entityId) const;
|
||||
//! Returns the item icon pixmap to display in the Outliner.
|
||||
virtual QIcon GenerateItemIcon(AZ::EntityId entityId) const;
|
||||
//! Returns whether the element's lock and visibility state should be accessible in the Outliner
|
||||
virtual bool CanToggleLockVisibility(AZ::EntityId entityId) const;
|
||||
//! Returns whether the element's name should be editable
|
||||
virtual bool CanRename(AZ::EntityId entityId) const;
|
||||
//! Returns whether the element's lock and visibility state should be accessible in the Outliner
|
||||
virtual bool CanToggleLockVisibility(AZ::EntityId entityId) const;
|
||||
|
||||
// Qt-specific painting functions
|
||||
|
||||
//! Paints the background of the item in the Outliner.
|
||||
virtual void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
@@ -54,24 +55,27 @@ namespace AzToolsFramework
|
||||
//! Paints the background of the descendant branches of the item in the Outliner.
|
||||
virtual void PaintDescendantBranchBackground(QPainter* painter, const QTreeView* view, const QRect& rect,
|
||||
const QModelIndex& index, const QModelIndex& descendantIndex) const;
|
||||
|
||||
//! Paints visual elements on the foreground of the item in the Outliner.
|
||||
virtual void PaintItemForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
//! Paints visual elements on the foreground of the descendants of the item in the Outliner.
|
||||
virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const;
|
||||
|
||||
// Outliner-specific interactions
|
||||
|
||||
//! Triggered when the entity is clicked in the Outliner.
|
||||
//! @return True if the click has been handled and should not be propagated, false otherwise.
|
||||
virtual bool OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
//! Triggered when the entity is double-clicked in the Outliner.
|
||||
//! @return True if the double-click has been handled and should not be propagated, false otherwise.
|
||||
virtual bool OnOutlinerItemDoubleClick(const QModelIndex& index) const;
|
||||
//! Triggered when an entity's children are expanded in the Outliner.
|
||||
virtual void OnOutlinerItemExpand(const QModelIndex& index) const;
|
||||
//! Triggered when an entity's children are collapsed in the Outliner.
|
||||
virtual void OnOutlinerItemCollapse(const QModelIndex& index) const;
|
||||
|
||||
//! Triggered when the entity is double clicked in the Outliner or in the Viewport.
|
||||
//! @return True if the double click has been handled and should not be propagated, false otherwise.
|
||||
virtual bool OnEntityDoubleClick(AZ::EntityId entityId) const;
|
||||
protected:
|
||||
static AZ::EntityId GetEntityIdFromIndex(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
EditorEntityUiHandlerId m_handlerId = 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user