Merge branch 'development' into optimization/unused_files
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Code/Editor/IEditorImpl.cpp # Code/Editor/IEditorImpl.h # Gems/LmbrCentral/Code/Tests/lmbrcentral_editor_tests_files.cmake
This commit is contained in:
@@ -104,13 +104,11 @@ ly_add_target(
|
||||
3rdParty::Qt::Concurrent
|
||||
3rdParty::TIFF
|
||||
3rdParty::squish-ccr
|
||||
3rdParty::AWSNativeSDK::STS
|
||||
Legacy::CryCommon
|
||||
Legacy::EditorCommon
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
Gem::LmbrCentral.Static
|
||||
AZ::AWSNativeSDKInit
|
||||
AZ::AtomCore
|
||||
Gem::Atom_RPI.Edit
|
||||
Gem::Atom_RPI.Public
|
||||
@@ -119,7 +117,6 @@ ly_add_target(
|
||||
Gem::AtomViewportDisplayInfo
|
||||
${additional_dependencies}
|
||||
PUBLIC
|
||||
3rdParty::AWSNativeSDK::Core
|
||||
3rdParty::Qt::Network
|
||||
Legacy::EditorCore
|
||||
RUNTIME_DEPENDENCIES
|
||||
|
||||
+13
-12
@@ -36,14 +36,6 @@ AZ_POP_DISABLE_WARNING
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
// Aws Native SDK
|
||||
#include <aws/sts/STSClient.h>
|
||||
#include <aws/core/auth/AWSCredentialsProvider.h>
|
||||
#include <aws/sts/model/GetFederationTokenRequest.h>
|
||||
#include <aws/core/http/HttpClient.h>
|
||||
#include <aws/core/http/HttpResponse.h>
|
||||
#include <aws/core/utils/json/JsonSerializer.h>
|
||||
|
||||
// AzCore
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Component/ComponentApplicationLifecycle.h>
|
||||
@@ -144,9 +136,7 @@ AZ_POP_DISABLE_WARNING
|
||||
|
||||
#include "Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h"
|
||||
|
||||
// AWSNativeSDK
|
||||
#include <AzToolsFramework/Undo/UndoSystem.h>
|
||||
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
|
||||
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
@@ -2125,8 +2115,6 @@ bool CCryEditApp::FixDanglingSharedMemory(const QString& sharedMemName) const
|
||||
|
||||
int CCryEditApp::ExitInstance(int exitCode)
|
||||
{
|
||||
AZ_TracePrintf("Exit", "Called ExitInstance() with exit code: 0x%x", exitCode);
|
||||
|
||||
if (m_pEditor)
|
||||
{
|
||||
m_pEditor->OnBeginShutdownSequence();
|
||||
@@ -3363,6 +3351,10 @@ CCryEditDoc* CCryEditApp::OpenDocumentFile(const char* filename, bool addToMostR
|
||||
return GetIEditor()->GetDocument();
|
||||
}
|
||||
|
||||
bool usePrefabSystemForLevels = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
|
||||
|
||||
// If we are loading and we're in simulate mode, then switch it off before we do anything else
|
||||
if (GetIEditor()->GetGameEngine() && GetIEditor()->GetGameEngine()->GetSimulationMode())
|
||||
{
|
||||
@@ -3370,6 +3362,15 @@ CCryEditDoc* CCryEditApp::OpenDocumentFile(const char* filename, bool addToMostR
|
||||
bool bIsDocModified = GetIEditor()->GetDocument()->IsModified();
|
||||
OnSwitchPhysics();
|
||||
GetIEditor()->GetDocument()->SetModifiedFlag(bIsDocModified);
|
||||
|
||||
if (usePrefabSystemForLevels)
|
||||
{
|
||||
auto* rootSpawnableInterface = AzFramework::RootSpawnableInterface::Get();
|
||||
if (rootSpawnableInterface)
|
||||
{
|
||||
rootSpawnableInterface->ProcessSpawnableQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We're about to start loading a level, so start recording errors to display at the end.
|
||||
|
||||
@@ -101,7 +101,7 @@ void CEditorPreferencesPage_AWS::SaveSettingsRegistryFile()
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved{};
|
||||
[[maybe_unused]] bool saved{};
|
||||
constexpr auto configurationMode =
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// AzCore
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/IO/IStreamer.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
// Qt
|
||||
#include <QByteArray>
|
||||
|
||||
// AWS Native SDK
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option")
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/platform/FileSystem.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
// AzCore
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/JSON/document.h>
|
||||
@@ -76,9 +70,6 @@ AZ_POP_DISABLE_WARNING
|
||||
#include "Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.h"
|
||||
#include "Editor/AssetEditor/AssetEditorRequestsHandler.h"
|
||||
|
||||
// AWSNativeSDK
|
||||
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
|
||||
|
||||
#include "Core/QtEditorApplication.h" // for Editor::EditorQtApplication
|
||||
|
||||
static CCryEditDoc * theDocument;
|
||||
@@ -130,7 +121,6 @@ CEditorImpl::CEditorImpl()
|
||||
, m_pSettingsManager(nullptr)
|
||||
, m_pLevelIndependentFileMan(nullptr)
|
||||
, m_pExportManager(nullptr)
|
||||
, m_awsResourceManager(nullptr)
|
||||
, m_bMatEditMode(false)
|
||||
, m_bShowStatusText(true)
|
||||
, m_bInitialized(false)
|
||||
|
||||
@@ -361,7 +361,6 @@ protected:
|
||||
QString m_selectFileBuffer;
|
||||
QString m_levelNameBuffer;
|
||||
|
||||
IAWSResourceManager* m_awsResourceManager;
|
||||
|
||||
//! True if the editor is in material edit mode. Fast preview of materials.
|
||||
//! In this mode only very limited functionality is available.
|
||||
|
||||
@@ -47,12 +47,12 @@ namespace UnitTest
|
||||
|
||||
void ViewportMouseCursorRequestImpl::BeginCursorCapture()
|
||||
{
|
||||
m_inputChannelMapper->SetCursorCaptureEnabled(true);
|
||||
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeCaptured);
|
||||
}
|
||||
|
||||
void ViewportMouseCursorRequestImpl::EndCursorCapture()
|
||||
{
|
||||
m_inputChannelMapper->SetCursorCaptureEnabled(false);
|
||||
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone);
|
||||
}
|
||||
|
||||
bool ViewportMouseCursorRequestImpl::IsMouseOver() const
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// AWs Native SDK
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option")
|
||||
#include <aws/core/auth/AWSCredentialsProvider.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
// Qt
|
||||
#include <QMenuBar>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -63,11 +63,11 @@ namespace AzToolsFramework
|
||||
//! @name Reverse URLs.
|
||||
//! Used to identify common actions and override them when necessary.
|
||||
//@{
|
||||
constexpr inline AZ::Crc32 EditModeMove = AZ_CRC_CE("com.o3de.action.editor.editmode.move");
|
||||
constexpr inline AZ::Crc32 EditModeRotate = AZ_CRC_CE("com.o3de.action.editor.editmode.rotate");
|
||||
constexpr inline AZ::Crc32 EditModeScale = AZ_CRC_CE("com.o3de.action.editor.editmode.scale");
|
||||
constexpr inline AZ::Crc32 SnapToGrid = AZ_CRC_CE("com.o3de.action.editor.snaptogrid");
|
||||
constexpr inline AZ::Crc32 SnapAngle = AZ_CRC_CE("com.o3de.action.editor.snapangle");
|
||||
constexpr inline AZ::Crc32 EditModeMove = AZ_CRC_CE("org.o3de.action.editor.editmode.move");
|
||||
constexpr inline AZ::Crc32 EditModeRotate = AZ_CRC_CE("org.o3de.action.editor.editmode.rotate");
|
||||
constexpr inline AZ::Crc32 EditModeScale = AZ_CRC_CE("org.o3de.action.editor.editmode.scale");
|
||||
constexpr inline AZ::Crc32 SnapToGrid = AZ_CRC_CE("org.o3de.action.editor.snaptogrid");
|
||||
constexpr inline AZ::Crc32 SnapAngle = AZ_CRC_CE("org.o3de.action.editor.snapangle");
|
||||
//@}
|
||||
}
|
||||
|
||||
|
||||
@@ -1128,7 +1128,7 @@ void SEditorSettings::SaveSettingsRegistryFile()
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved{};
|
||||
[[maybe_unused]] bool saved{};
|
||||
constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE
|
||||
| AZ::IO::SystemFile::SF_OPEN_CREATE_PATH
|
||||
| AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
|
||||
@@ -45,7 +45,8 @@ bool ModalWindowDismisser::eventFilter(QObject* object, QEvent* event)
|
||||
{
|
||||
if (dialog->isModal())
|
||||
{
|
||||
if (event->type() == QEvent::Show)
|
||||
QEvent::Type test = event->type();
|
||||
if (test == QEvent::Show || test == QEvent::WindowActivate)
|
||||
{
|
||||
auto it = AZStd::find(m_windows.begin(), m_windows.end(), dialog);
|
||||
if (it == m_windows.end())
|
||||
|
||||
+18
-21
@@ -87,29 +87,15 @@ public:
|
||||
}
|
||||
|
||||
// Handle labels with submenus
|
||||
if (auto toolLabel = qobject_cast<QLabel*>(toolWidget))
|
||||
if (auto toolLabel = qobject_cast<QToolButton*>(toolWidget))
|
||||
{
|
||||
if (!toolLabel->isVisible())
|
||||
{
|
||||
// Manually turn the custom context menus into submenus
|
||||
if (toolLabel->objectName() == "m_fovStaticCtrl")
|
||||
if (toolLabel->menu())
|
||||
{
|
||||
QAction* newAction = menu->addMenu(m_viewportDlg->GetFovMenu());
|
||||
newAction->setText(QString("FOV: %1").arg(toolLabel->text()));
|
||||
}
|
||||
else if (toolLabel->objectName() == "m_ratioStaticCtrl")
|
||||
{
|
||||
QAction* newAction = menu->addMenu(m_viewportDlg->GetAspectMenu());
|
||||
newAction->setText(QString("Ratio: %1").arg(toolLabel->text()));
|
||||
}
|
||||
else if (toolLabel->objectName() == "m_sizeStaticCtrl")
|
||||
{
|
||||
QAction* newAction = menu->addMenu(m_viewportDlg->GetResolutionMenu());
|
||||
newAction->setText(QString("%1").arg(toolLabel->text()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't add actions for other Labels
|
||||
QAction* action = menu->addMenu(toolLabel->menu());
|
||||
action->setText(toolLabel->text());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -179,14 +165,25 @@ CLayoutViewPane::CLayoutViewPane(QWidget* parent)
|
||||
toolbar->installEventFilter(&m_viewportTitleDlg);
|
||||
toolbar->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(toolbar, &QWidget::customContextMenuRequested, &m_viewportTitleDlg, &QWidget::customContextMenuRequested);
|
||||
|
||||
setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
|
||||
if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(toolbar))
|
||||
{
|
||||
expansion->installEventFilter(m_expanderWatcher);
|
||||
}
|
||||
|
||||
AzQtComponents::BreadCrumbs* prefabsBreadcrumbs =
|
||||
qobject_cast<AzQtComponents::BreadCrumbs*>(toolbar->findChild<QWidget*>("m_prefabFocusPath"));
|
||||
QToolButton* backButton = qobject_cast<QToolButton*>(toolbar->findChild<QWidget*>("m_prefabFocusBackButton"));
|
||||
|
||||
AZ_Assert(prefabsBreadcrumbs, "Could not find Prefabs Breadcrumbs widget on CLayoutViewPane initialization!");
|
||||
AZ_Assert(backButton, "Could not find Prefabs Breadcrumbs back button on CLayoutViewPane initialization!");
|
||||
|
||||
if (prefabsBreadcrumbs && backButton)
|
||||
{
|
||||
m_viewportTitleDlg.InitializePrefabViewportFocusPathHandler(prefabsBreadcrumbs, backButton);
|
||||
}
|
||||
|
||||
m_id = -1;
|
||||
}
|
||||
|
||||
@@ -745,7 +742,7 @@ namespace
|
||||
|
||||
void PySetActiveViewport(unsigned int viewportIndex)
|
||||
{
|
||||
bool success = false;
|
||||
[[maybe_unused]] bool success = false;
|
||||
CLayoutWnd* layout = GetIEditor()->GetViewManager()->GetLayout();
|
||||
if (layout)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportInteractionHelpers.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -33,53 +34,6 @@ namespace SandboxEditor
|
||||
|
||||
ViewportManipulatorControllerInstance::~ViewportManipulatorControllerInstance() = default;
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::MouseButton;
|
||||
using InputButton = AzFramework::InputDeviceMouse::Button;
|
||||
const auto& id = inputChannel.GetInputChannelId();
|
||||
if (id == InputButton::Left)
|
||||
{
|
||||
return MouseButton::Left;
|
||||
}
|
||||
if (id == InputButton::Middle)
|
||||
{
|
||||
return MouseButton::Middle;
|
||||
}
|
||||
if (id == InputButton::Right)
|
||||
{
|
||||
return MouseButton::Right;
|
||||
}
|
||||
return MouseButton::None;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::IsMouseMove(const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition;
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifier ViewportManipulatorControllerInstance::GetKeyboardModifier(
|
||||
const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::KeyboardModifier;
|
||||
using Key = AzFramework::InputDeviceKeyboard::Key;
|
||||
const auto& id = inputChannel.GetInputChannelId();
|
||||
if (id == Key::ModifierAltL || id == Key::ModifierAltR)
|
||||
{
|
||||
return KeyboardModifier::Alt;
|
||||
}
|
||||
if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR)
|
||||
{
|
||||
return KeyboardModifier::Ctrl;
|
||||
}
|
||||
if (id == Key::ModifierShiftL || id == Key::ModifierShiftR)
|
||||
{
|
||||
return KeyboardModifier::Shift;
|
||||
}
|
||||
return KeyboardModifier::None;
|
||||
}
|
||||
|
||||
bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
// We only care about manipulator and viewport interaction events
|
||||
@@ -97,6 +51,7 @@ namespace SandboxEditor
|
||||
using AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
|
||||
using AzToolsFramework::ViewportInteraction::ProjectedViewportRay;
|
||||
using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus;
|
||||
using AzToolsFramework::ViewportInteraction::Helpers;
|
||||
|
||||
bool interactionHandled = false;
|
||||
float wheelDelta = 0.0f;
|
||||
@@ -109,7 +64,7 @@ namespace SandboxEditor
|
||||
const bool finishedProcessingEvents = event.m_priority == InteractionPriority;
|
||||
|
||||
const auto state = event.m_inputChannel.GetState();
|
||||
if (IsMouseMove(event.m_inputChannel))
|
||||
if (Helpers::IsMouseMove(event.m_inputChannel))
|
||||
{
|
||||
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
|
||||
if (event.m_priority == ManipulatorPriority)
|
||||
@@ -136,7 +91,7 @@ namespace SandboxEditor
|
||||
|
||||
eventType = MouseEvent::Move;
|
||||
}
|
||||
else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
|
||||
else if (auto mouseButton = Helpers::GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
|
||||
{
|
||||
const AZ::u32 mouseButtonValue = static_cast<AZ::u32>(mouseButton);
|
||||
overrideButton = mouseButton;
|
||||
@@ -178,7 +133,7 @@ namespace SandboxEditor
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto keyboardModifier = GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None)
|
||||
else if (auto keyboardModifier = Helpers::GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None)
|
||||
{
|
||||
if (state == InputChannel::State::Began || state == InputChannel::State::Updated)
|
||||
{
|
||||
|
||||
@@ -35,10 +35,6 @@ namespace SandboxEditor
|
||||
private:
|
||||
bool IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton) const;
|
||||
|
||||
static AzToolsFramework::ViewportInteraction::MouseButton GetMouseButton(const AzFramework::InputChannel& inputChannel);
|
||||
static bool IsMouseMove(const AzFramework::InputChannel& inputChannel);
|
||||
static AzToolsFramework::ViewportInteraction::KeyboardModifier GetKeyboardModifier(const AzFramework::InputChannel& inputChannel);
|
||||
|
||||
//! Represents the time and location of a click.
|
||||
struct ClickEvent
|
||||
{
|
||||
|
||||
@@ -383,12 +383,7 @@ void CViewportTitleDlg::OnInitDialog()
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
|
||||
if (isPrefabSystemEnabled)
|
||||
{
|
||||
m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler();
|
||||
m_prefabViewportFocusPathHandler->Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton);
|
||||
}
|
||||
else
|
||||
if (!isPrefabSystemEnabled)
|
||||
{
|
||||
m_ui->m_prefabFocusPath->setEnabled(false);
|
||||
m_ui->m_prefabFocusBackButton->setEnabled(false);
|
||||
@@ -397,6 +392,23 @@ void CViewportTitleDlg::OnInitDialog()
|
||||
}
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton)
|
||||
{
|
||||
if (m_prefabViewportFocusPathHandler != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
|
||||
if (isPrefabSystemEnabled)
|
||||
{
|
||||
m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler();
|
||||
m_prefabViewportFocusPathHandler->Initialize(breadcrumbsWidget, backButton);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CViewportTitleDlg::SetTitle(const QString& title)
|
||||
{
|
||||
|
||||
@@ -70,6 +70,8 @@ public:
|
||||
QMenu* const GetAspectMenu();
|
||||
QMenu* const GetResolutionMenu();
|
||||
|
||||
void InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton);
|
||||
|
||||
Q_SIGNALS:
|
||||
void ActionTriggered(int command);
|
||||
|
||||
|
||||
@@ -80,6 +80,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Camera settings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Camera settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/camera.svg</normaloff>:/Menu/camera.svg</iconset>
|
||||
@@ -91,6 +94,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Debug information</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug information</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/debug.svg</normaloff>:/Menu/debug.svg</iconset>
|
||||
@@ -105,6 +111,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Toggle viewport helpers</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Toggle viewport helpers</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/helpers.svg</normaloff>:/Menu/helpers.svg</iconset>
|
||||
@@ -119,6 +128,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Viewport resolution</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Viewport resolution</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/resolution.svg</normaloff>:/Menu/resolution.svg</iconset>
|
||||
@@ -130,6 +142,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Other settings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Other settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/menu.svg</normaloff>:/Menu/menu.svg</iconset>
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/std/parallel/shared_mutex.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
class any;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Data
|
||||
|
||||
@@ -64,7 +64,7 @@ public class LumberyardActivity extends NativeActivity
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// called from the native to get the application package name
|
||||
// e.g. com.lumberyard.samples for SamplesProject
|
||||
// e.g. org.o3de.samples for SamplesProject
|
||||
public String GetPackageName()
|
||||
{
|
||||
return getApplicationContext().getPackageName();
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzCore/std/typetraits/is_base_of.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/IO/IStreamerTypes.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
|
||||
@@ -7,11 +7,62 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Asset/AssetDataStream.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/IO/IStreamer.h>
|
||||
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
|
||||
namespace AZ::Data
|
||||
{
|
||||
namespace DataStreamInternal
|
||||
{
|
||||
struct AssetDataStreamPrivate
|
||||
{
|
||||
//! Optional data buffer that's been directly passed in through Open(), instead of reading data from a file.
|
||||
AZStd::vector<AZ::u8> m_preloadedData;
|
||||
//! The current active streamer read request - tracked in case we need to cancel it prematurely
|
||||
AZ::IO::FileRequestPtr m_curReadRequest{ nullptr };
|
||||
|
||||
//! Synchronization for the read request, so that it's possible to block until completion.
|
||||
AZStd::mutex m_readRequestMutex;
|
||||
AZStd::condition_variable m_readRequestActive;
|
||||
|
||||
void SetReadRequest(AZ::IO::FileRequestPtr&& req)
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
|
||||
// The read request finished, so stop tracking it.
|
||||
m_curReadRequest = AZStd::move(req);
|
||||
}
|
||||
void BlockUntilReadComplete()
|
||||
{
|
||||
AZStd::unique_lock lock(m_readRequestMutex);
|
||||
m_readRequestActive.wait(
|
||||
lock,
|
||||
[this]
|
||||
{
|
||||
return m_curReadRequest == nullptr;
|
||||
});
|
||||
lock.unlock();
|
||||
}
|
||||
void CancelRequest()
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
|
||||
if (m_curReadRequest)
|
||||
{
|
||||
auto streamer = Interface<IO::IStreamer>::Get();
|
||||
m_curReadRequest = streamer->Cancel(m_curReadRequest);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace Internal
|
||||
|
||||
AssetDataStream::AssetDataStream(AZ::IO::IStreamerTypes::RequestMemoryAllocator* bufferAllocator)
|
||||
: m_bufferAllocator(bufferAllocator ? bufferAllocator : &m_defaultAllocator)
|
||||
: m_privateData(AZStd::make_unique<DataStreamInternal::AssetDataStreamPrivate>())
|
||||
, m_bufferAllocator(bufferAllocator ? bufferAllocator : &m_defaultAllocator)
|
||||
{
|
||||
ClearInternalStateData();
|
||||
}
|
||||
@@ -53,9 +104,9 @@ namespace AZ::Data
|
||||
OpenInternal(data.size(), "(mem buffer)");
|
||||
|
||||
// Directly take ownership of the provided buffer
|
||||
m_preloadedData = AZStd::move(data);
|
||||
m_buffer = m_preloadedData.data();
|
||||
m_loadedSize = m_preloadedData.size();
|
||||
m_privateData->m_preloadedData = AZStd::move(data);
|
||||
m_buffer = m_privateData->m_preloadedData.data();
|
||||
m_loadedSize = m_privateData->m_preloadedData.size();
|
||||
}
|
||||
|
||||
void AssetDataStream::Open(const AZStd::string& filePath, size_t fileOffset, size_t assetSize,
|
||||
@@ -65,7 +116,7 @@ namespace AZ::Data
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
|
||||
AZ_Assert(!m_isOpen, "Attempting to open the stream when it is already open.");
|
||||
AZ_Assert(!m_curReadRequest, "Queueing an asset stream load while one is still in progress.");
|
||||
AZ_Assert(!m_privateData->m_curReadRequest, "Queueing an asset stream load while one is still in progress.");
|
||||
AZ_Assert(!filePath.empty(), "AssetDataStream::Open called without a valid file name.");
|
||||
|
||||
// Initialize the state variables and start tracking the overall load timings
|
||||
@@ -97,11 +148,8 @@ namespace AZ::Data
|
||||
"Buffer for %s was expected to be %zu bytes, but is %zu bytes.",
|
||||
m_filePath.c_str(), m_requestedAssetSize, m_loadedSize);
|
||||
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
|
||||
// The read request finished, so stop tracking it.
|
||||
m_curReadRequest = nullptr;
|
||||
}
|
||||
// The read request finished, so stop tracking it.
|
||||
m_privateData->SetReadRequest(nullptr);
|
||||
|
||||
// Call the load callback to start processing the loaded data.
|
||||
if (loadCallback)
|
||||
@@ -115,21 +163,22 @@ namespace AZ::Data
|
||||
}
|
||||
|
||||
// Notify that the load is complete, in case anyone is using BlockUntilLoadComplete to block.
|
||||
m_readRequestActive.notify_one();
|
||||
m_privateData->m_readRequestActive.notify_one();
|
||||
};
|
||||
|
||||
// Queue the raw file load with the file streamer.
|
||||
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
|
||||
m_curReadRequest = streamer->Read(
|
||||
m_privateData->m_curReadRequest =
|
||||
streamer->Read(
|
||||
m_filePath,
|
||||
*m_bufferAllocator,
|
||||
m_requestedAssetSize,
|
||||
deadline, priority, m_fileOffset);
|
||||
m_curDeadline = deadline;
|
||||
m_curPriority = priority;
|
||||
streamer->SetRequestCompleteCallback(m_curReadRequest, streamerCallback);
|
||||
streamer->SetRequestCompleteCallback(m_privateData->m_curReadRequest, streamerCallback);
|
||||
|
||||
streamer->QueueRequest(m_curReadRequest);
|
||||
streamer->QueueRequest(m_privateData->m_curReadRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -139,19 +188,19 @@ namespace AZ::Data
|
||||
loadCallback(AZ::IO::IStreamerTypes::RequestStatus::Completed);
|
||||
}
|
||||
|
||||
m_readRequestActive.notify_one();
|
||||
m_privateData->m_readRequestActive.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDataStream::Reschedule(AZStd::chrono::milliseconds newDeadline, AZ::IO::IStreamerTypes::Priority newPriority)
|
||||
{
|
||||
if (m_curReadRequest && (newDeadline < m_curDeadline || newPriority > m_curPriority))
|
||||
if (m_privateData->m_curReadRequest && (newDeadline < m_curDeadline || newPriority > m_curPriority))
|
||||
{
|
||||
auto deadline = AZStd::GetMin(m_curDeadline, newDeadline);
|
||||
auto priority = AZStd::GetMax(m_curPriority, newPriority);
|
||||
|
||||
auto streamer = Interface<IO::IStreamer>::Get();
|
||||
m_curReadRequest = streamer->RescheduleRequest(m_curReadRequest, deadline, priority);
|
||||
m_privateData->m_curReadRequest = streamer->RescheduleRequest(m_privateData->m_curReadRequest, deadline, priority);
|
||||
m_curDeadline = deadline;
|
||||
m_curPriority = priority;
|
||||
}
|
||||
@@ -159,15 +208,13 @@ namespace AZ::Data
|
||||
|
||||
void AssetDataStream::BlockUntilLoadComplete()
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> lock(m_readRequestMutex);
|
||||
m_readRequestActive.wait(lock, [this] { return m_curReadRequest == nullptr; });
|
||||
lock.unlock();
|
||||
m_privateData->BlockUntilReadComplete();
|
||||
}
|
||||
|
||||
void AssetDataStream::ClearInternalStateData()
|
||||
{
|
||||
// Clear all our internal state data.
|
||||
m_preloadedData.resize(0);
|
||||
m_privateData->m_preloadedData.resize(0);
|
||||
m_buffer = nullptr;
|
||||
m_loadedSize = 0;
|
||||
m_requestedAssetSize = 0;
|
||||
@@ -204,10 +251,10 @@ namespace AZ::Data
|
||||
void AssetDataStream::Close()
|
||||
{
|
||||
AZ_Assert(m_isOpen, "Attempting to close a stream that hasn't been opened.");
|
||||
AZ_Assert(m_curReadRequest == nullptr, "Attempting to close a stream with a read request in flight.");
|
||||
AZ_Assert(m_privateData->m_curReadRequest == nullptr, "Attempting to close a stream with a read request in flight.");
|
||||
|
||||
// Destroy the asset buffer and unlock the allocator, so the allocator itself knows that it is no longer needed.
|
||||
if (m_buffer != m_preloadedData.data())
|
||||
if (m_buffer != m_privateData->m_preloadedData.data())
|
||||
{
|
||||
m_bufferAllocator->Release(m_buffer);
|
||||
}
|
||||
@@ -221,12 +268,7 @@ namespace AZ::Data
|
||||
|
||||
void AssetDataStream::RequestCancel()
|
||||
{
|
||||
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
|
||||
if (m_curReadRequest)
|
||||
{
|
||||
auto streamer = Interface<IO::IStreamer>::Get();
|
||||
m_curReadRequest = streamer->Cancel(m_curReadRequest);
|
||||
}
|
||||
m_privateData->CancelRequest();
|
||||
}
|
||||
|
||||
void AssetDataStream::Seek(AZ::IO::OffsetType bytes, AZ::IO::GenericStream::SeekMode mode)
|
||||
|
||||
@@ -9,17 +9,26 @@
|
||||
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/IO/IStreamerTypes.h>
|
||||
#include <AzCore/IO/IStreamer.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class T, class Allocator>
|
||||
class vector;
|
||||
}
|
||||
|
||||
namespace AZ::Data
|
||||
{
|
||||
namespace DataStreamInternal
|
||||
{
|
||||
struct AssetDataStreamPrivate;
|
||||
}
|
||||
|
||||
class AssetDataStream : public AZ::IO::GenericStream
|
||||
{
|
||||
public:
|
||||
using VectorDataSource = AZStd::vector<AZ::u8, AZStd::allocator>;
|
||||
// The default Generic Stream APIs in this class will only allow for a single sequential pass
|
||||
// through the data, no seeking. Reads will block when pages aren't available yet, and
|
||||
// pages will be marked for recycling once reading has progressed beyond them.
|
||||
@@ -29,10 +38,10 @@ namespace AZ::Data
|
||||
~AssetDataStream() override;
|
||||
|
||||
// Open the AssetDataStream and make a copy of the provided memory buffer.
|
||||
void Open(const AZStd::vector<AZ::u8>& data);
|
||||
void Open(const VectorDataSource& data);
|
||||
|
||||
// Open the AssetDataStream and directly take ownership of a pre-populated memory buffer.
|
||||
void Open(AZStd::vector<AZ::u8>&& data);
|
||||
void Open(VectorDataSource&& data);
|
||||
|
||||
// Open the AssetDataStream and load it via file streaming
|
||||
using OnCompleteCallback = AZStd::function<void(AZ::IO::IStreamerTypes::RequestStatus)>;
|
||||
@@ -91,6 +100,8 @@ namespace AZ::Data
|
||||
|
||||
void ClearInternalStateData();
|
||||
|
||||
AZStd::unique_ptr<DataStreamInternal::AssetDataStreamPrivate> m_privateData;
|
||||
|
||||
//! The allocator to use for allocating / deallocating asset buffers
|
||||
AZ::IO::IStreamerTypes::RequestMemoryAllocator* m_bufferAllocator{ nullptr };
|
||||
|
||||
@@ -106,9 +117,6 @@ namespace AZ::Data
|
||||
//! The amount of data that's expected to be loaded.
|
||||
size_t m_requestedAssetSize{ 0 };
|
||||
|
||||
//! Optional data buffer that's been directly passed in through Open(), instead of reading data from a file.
|
||||
AZStd::vector<AZ::u8> m_preloadedData;
|
||||
|
||||
//! The buffer that will hold the raw data after it's loaded from the file.
|
||||
void* m_buffer{ nullptr };
|
||||
|
||||
@@ -119,19 +127,12 @@ namespace AZ::Data
|
||||
//! The current offset representing how far we've read into the buffer.
|
||||
size_t m_curOffset{ 0 };
|
||||
|
||||
//! The current active streamer read request - tracked in case we need to cancel it prematurely
|
||||
AZ::IO::FileRequestPtr m_curReadRequest{ nullptr };
|
||||
|
||||
//! The current request deadline. Used to avoid requesting a reschedule to the same (current) deadline.
|
||||
AZStd::chrono::milliseconds m_curDeadline{ AZ::IO::IStreamerTypes::s_noDeadline };
|
||||
|
||||
//! The current request priority. Used to avoid requesting a reschedule to the same (current) priority.
|
||||
AZ::IO::IStreamerTypes::Priority m_curPriority{ AZ::IO::IStreamerTypes::s_priorityMedium };
|
||||
|
||||
//! Synchronization for the read request, so that it's possible to block until completion.
|
||||
AZStd::mutex m_readRequestMutex;
|
||||
AZStd::condition_variable m_readRequestActive;
|
||||
|
||||
//! Track whether or not the stream is currently open
|
||||
bool m_isOpen{ false };
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/Asset/AssetManager_private.h>
|
||||
#include <AzCore/Asset/AssetDataStream.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/IO/IStreamer.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <AzCore/Asset/AssetContainer.h>
|
||||
#include <AzCore/Asset/AssetDataStream.h>
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h> // used as allocator for most components
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace AZ
|
||||
return m_entity->GetId();
|
||||
}
|
||||
|
||||
AZ_Warning("System", false, "Can't get component %p entity ID as it is not attached to an entity yet!", this);
|
||||
AZ_Warning("System", false, "Can't get component (type: %s, addr: %p) entity ID as it is not attached to an entity yet!", RTTI_GetTypeName(), this);
|
||||
return EntityId();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace AZ
|
||||
return NamedEntityId(m_entity->GetId(), m_entity->GetName());
|
||||
}
|
||||
|
||||
AZ_Warning("System", false, "Can't get component %p entity ID as it is not attached to an entity yet!", this);
|
||||
AZ_Warning("System", false, "Can't get component (type: %s, addr: %p) entity ID as it is not attached to an entity yet!", RTTI_GetTypeName(), this);
|
||||
return NamedEntityId();
|
||||
}
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace AZ
|
||||
EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id);
|
||||
EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id);
|
||||
|
||||
AZ_Assert(m_state == State::Active, "Component should be in Active state to br Deactivated!");
|
||||
AZ_Assert(m_state == State::Active, "Component should be in Active state to be Deactivated!");
|
||||
SetState(State::Deactivating);
|
||||
|
||||
for (ComponentArrayType::reverse_iterator it = m_components.rbegin(); it != m_components.rend(); ++it)
|
||||
|
||||
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* 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/Casting/numeric_cast.h>
|
||||
#include <AzCore/DOM/DomPath.h>
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
#include <AzCore/Console/ConsoleTypeHelpers.h>
|
||||
|
||||
namespace AZ::Dom
|
||||
{
|
||||
PathEntry::PathEntry(size_t value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
PathEntry::PathEntry(AZ::Name value)
|
||||
: m_value(AZStd::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
PathEntry::PathEntry(AZStd::string_view value)
|
||||
: m_value(AZ::Name(value))
|
||||
{
|
||||
}
|
||||
|
||||
PathEntry& PathEntry::operator=(size_t value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PathEntry& PathEntry::operator=(AZ::Name value)
|
||||
{
|
||||
m_value = AZStd::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PathEntry& PathEntry::operator=(AZStd::string_view value)
|
||||
{
|
||||
m_value = AZ::Name(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool PathEntry::operator==(const PathEntry& other) const
|
||||
{
|
||||
return m_value == other.m_value;
|
||||
}
|
||||
|
||||
bool PathEntry::operator==(size_t value) const
|
||||
{
|
||||
return IsIndex() && GetIndex() == value;
|
||||
}
|
||||
|
||||
bool PathEntry::operator==(const AZ::Name& key) const
|
||||
{
|
||||
return IsKey() && GetKey() == key;
|
||||
}
|
||||
|
||||
bool PathEntry::operator==(AZStd::string_view key) const
|
||||
{
|
||||
return IsKey() && GetKey() == AZ::Name(key);
|
||||
}
|
||||
|
||||
bool PathEntry::operator!=(const PathEntry& other) const
|
||||
{
|
||||
return m_value != other.m_value;
|
||||
}
|
||||
|
||||
bool PathEntry::operator!=(size_t value) const
|
||||
{
|
||||
return !IsIndex() || GetIndex() != value;
|
||||
}
|
||||
|
||||
bool PathEntry::operator!=(const AZ::Name& key) const
|
||||
{
|
||||
return !IsKey() || GetKey() != key;
|
||||
}
|
||||
|
||||
bool PathEntry::operator!=(AZStd::string_view key) const
|
||||
{
|
||||
return !IsKey() || GetKey() != AZ::Name(key);
|
||||
}
|
||||
|
||||
void PathEntry::SetEndOfArray()
|
||||
{
|
||||
m_value = EndOfArrayIndex;
|
||||
}
|
||||
|
||||
bool PathEntry::IsEndOfArray() const
|
||||
{
|
||||
const size_t* result = AZStd::get_if<size_t>(&m_value);
|
||||
return result == nullptr ? false : ((*result) == EndOfArrayIndex);
|
||||
}
|
||||
|
||||
bool PathEntry::IsIndex() const
|
||||
{
|
||||
const size_t* result = AZStd::get_if<size_t>(&m_value);
|
||||
return result == nullptr ? false : ((*result) != EndOfArrayIndex);
|
||||
}
|
||||
|
||||
bool PathEntry::IsKey() const
|
||||
{
|
||||
return AZStd::holds_alternative<AZ::Name>(m_value);
|
||||
}
|
||||
|
||||
size_t PathEntry::GetIndex() const
|
||||
{
|
||||
AZ_Assert(IsIndex(), "GetIndex called on PathEntry that is not an index");
|
||||
return AZStd::get<size_t>(m_value);
|
||||
}
|
||||
|
||||
const AZ::Name& PathEntry::GetKey() const
|
||||
{
|
||||
AZ_Assert(IsKey(), "Key called on PathEntry that is not a key");
|
||||
return AZStd::get<AZ::Name>(m_value);
|
||||
}
|
||||
|
||||
Path::Path(AZStd::initializer_list<PathEntry> init)
|
||||
: m_entries(init)
|
||||
{
|
||||
}
|
||||
|
||||
Path::Path(AZStd::string_view pathString)
|
||||
{
|
||||
FromString(pathString);
|
||||
}
|
||||
|
||||
Path Path::operator/(const PathEntry& entry) const
|
||||
{
|
||||
Path newPath(*this);
|
||||
newPath /= entry;
|
||||
return newPath;
|
||||
}
|
||||
|
||||
Path Path::operator/(size_t index) const
|
||||
{
|
||||
return *this / PathEntry(index);
|
||||
}
|
||||
|
||||
Path Path::operator/(AZ::Name key) const
|
||||
{
|
||||
return *this / PathEntry(key);
|
||||
}
|
||||
|
||||
Path Path::operator/(AZStd::string_view key) const
|
||||
{
|
||||
return *this / PathEntry(key);
|
||||
}
|
||||
|
||||
Path Path::operator/(const Path& other) const
|
||||
{
|
||||
Path newPath(*this);
|
||||
newPath /= other;
|
||||
return newPath;
|
||||
}
|
||||
|
||||
Path& Path::operator/=(const PathEntry& entry)
|
||||
{
|
||||
Push(entry);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Path& Path::operator/=(size_t index)
|
||||
{
|
||||
return *this /= PathEntry(index);
|
||||
}
|
||||
|
||||
Path& Path::operator/=(AZ::Name key)
|
||||
{
|
||||
return *this /= PathEntry(key);
|
||||
}
|
||||
|
||||
Path& Path::operator/=(AZStd::string_view key)
|
||||
{
|
||||
return *this /= PathEntry(key);
|
||||
}
|
||||
|
||||
Path& Path::operator/=(const Path& other)
|
||||
{
|
||||
for (const PathEntry& entry : other)
|
||||
{
|
||||
Push(entry);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Path::operator==(const Path& other) const
|
||||
{
|
||||
return m_entries == other.m_entries;
|
||||
}
|
||||
|
||||
const Path::ContainerType& Path::GetEntries() const
|
||||
{
|
||||
return m_entries;
|
||||
}
|
||||
|
||||
void Path::Push(PathEntry entry)
|
||||
{
|
||||
m_entries.push_back(AZStd::move(entry));
|
||||
}
|
||||
|
||||
void Path::Push(size_t entry)
|
||||
{
|
||||
Push(PathEntry(entry));
|
||||
}
|
||||
|
||||
void Path::Push(AZ::Name entry)
|
||||
{
|
||||
Push(PathEntry(AZStd::move(entry)));
|
||||
}
|
||||
|
||||
void Path::Push(AZStd::string_view entry)
|
||||
{
|
||||
Push(AZ::Name(entry));
|
||||
}
|
||||
|
||||
void Path::Pop()
|
||||
{
|
||||
m_entries.pop_back();
|
||||
}
|
||||
|
||||
void Path::Clear()
|
||||
{
|
||||
m_entries.clear();
|
||||
}
|
||||
|
||||
PathEntry Path::At(size_t index) const
|
||||
{
|
||||
if (index < m_entries.size())
|
||||
{
|
||||
return m_entries[index];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t Path::Size() const
|
||||
{
|
||||
return m_entries.size();
|
||||
}
|
||||
|
||||
PathEntry& Path::operator[](size_t index)
|
||||
{
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
const PathEntry& Path::operator[](size_t index) const
|
||||
{
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
Path::ContainerType::iterator Path::begin()
|
||||
{
|
||||
return m_entries.begin();
|
||||
}
|
||||
|
||||
Path::ContainerType::iterator Path::end()
|
||||
{
|
||||
return m_entries.end();
|
||||
}
|
||||
|
||||
Path::ContainerType::const_iterator Path::begin() const
|
||||
{
|
||||
return m_entries.cbegin();
|
||||
}
|
||||
|
||||
Path::ContainerType::const_iterator Path::end() const
|
||||
{
|
||||
return m_entries.cend();
|
||||
}
|
||||
|
||||
Path::ContainerType::const_iterator Path::cbegin() const
|
||||
{
|
||||
return m_entries.cbegin();
|
||||
}
|
||||
|
||||
Path::ContainerType::const_iterator Path::cend() const
|
||||
{
|
||||
return m_entries.cend();
|
||||
}
|
||||
|
||||
size_t Path::size() const
|
||||
{
|
||||
return m_entries.size();
|
||||
}
|
||||
|
||||
size_t Path::GetStringLength() const
|
||||
{
|
||||
size_t size = 0;
|
||||
for (const PathEntry& entry : m_entries)
|
||||
{
|
||||
++size;
|
||||
if (entry.IsEndOfArray())
|
||||
{
|
||||
size += 1;
|
||||
}
|
||||
else if (entry.IsIndex())
|
||||
{
|
||||
const size_t index = entry.GetIndex();
|
||||
const double digitCount = index > 0 ? log10(aznumeric_cast<double>(index + 1)) : 1.0;
|
||||
size += aznumeric_cast<size_t>(ceil(digitCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* nameBuffer = entry.GetKey().GetCStr();
|
||||
for (size_t i = 0; nameBuffer[i]; ++i)
|
||||
{
|
||||
if (nameBuffer[i] == EscapeCharacter || nameBuffer[i] == PathSeparator)
|
||||
{
|
||||
++size;
|
||||
}
|
||||
++size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void Path::FormatString(char* stringBuffer, size_t bufferSize) const
|
||||
{
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
auto putChar = [&](char c)
|
||||
{
|
||||
if (bufferIndex == bufferSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
stringBuffer[bufferIndex++] = c;
|
||||
};
|
||||
|
||||
auto writeToBuffer = [&](const char* key)
|
||||
{
|
||||
for (size_t keyIndex = 0; key[keyIndex]; ++keyIndex)
|
||||
{
|
||||
const char c = key[keyIndex];
|
||||
if (c == EscapeCharacter)
|
||||
{
|
||||
putChar(EscapeCharacter);
|
||||
putChar(TildeSequence);
|
||||
}
|
||||
else if (c == PathSeparator)
|
||||
{
|
||||
putChar(EscapeCharacter);
|
||||
putChar(ForwardSlashSequence);
|
||||
}
|
||||
else
|
||||
{
|
||||
putChar(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const PathEntry& entry : m_entries)
|
||||
{
|
||||
putChar(PathSeparator);
|
||||
if (entry.IsEndOfArray())
|
||||
{
|
||||
putChar(EndOfArrayCharacter);
|
||||
}
|
||||
else if (entry.IsIndex())
|
||||
{
|
||||
bufferIndex += azsnprintf(&stringBuffer[bufferIndex], bufferSize - bufferIndex, "%zu", entry.GetIndex());
|
||||
}
|
||||
else
|
||||
{
|
||||
writeToBuffer(entry.GetKey().GetCStr());
|
||||
}
|
||||
}
|
||||
|
||||
putChar('\0');
|
||||
}
|
||||
|
||||
AZStd::string Path::ToString() const
|
||||
{
|
||||
AZStd::string formattedString;
|
||||
const size_t size = GetStringLength();
|
||||
formattedString.resize_no_construct(size);
|
||||
FormatString(formattedString.data(), size + 1);
|
||||
return formattedString;
|
||||
}
|
||||
|
||||
void Path::AppendToString(AZStd::string& output) const
|
||||
{
|
||||
const size_t startIndex = output.length();
|
||||
const size_t stringLength = GetStringLength();
|
||||
output.resize_no_construct(startIndex + stringLength);
|
||||
FormatString(output.data() + startIndex, stringLength + 1);
|
||||
}
|
||||
|
||||
void Path::FromString(AZStd::string_view pathString)
|
||||
{
|
||||
m_entries.clear();
|
||||
if (pathString.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t pathEntryCount = 0;
|
||||
for (size_t i = 1; i <= pathString.size(); ++i)
|
||||
{
|
||||
if (pathString[i] == PathSeparator)
|
||||
{
|
||||
++pathEntryCount;
|
||||
}
|
||||
}
|
||||
m_entries.reserve(pathEntryCount);
|
||||
|
||||
// Ignore a preceeding path separator and start processing after it
|
||||
size_t pathIndex = pathString[0] == PathSeparator ? 1 : 0;
|
||||
bool isNumber = true;
|
||||
AZStd::string convertedSection;
|
||||
for (size_t i = pathIndex; i <= pathString.size(); ++i)
|
||||
{
|
||||
if (i == pathString.size() || pathString[i] == PathSeparator)
|
||||
{
|
||||
AZStd::string_view section = pathString.substr(pathIndex, i - pathIndex);
|
||||
if (section.size() == 1 && section[0] == EndOfArrayCharacter)
|
||||
{
|
||||
PathEntry entry;
|
||||
entry.SetEndOfArray();
|
||||
m_entries.push_back(AZStd::move(entry));
|
||||
}
|
||||
else if (isNumber && !section.empty())
|
||||
{
|
||||
size_t index = 0;
|
||||
ConsoleTypeHelpers::StringToValue(index, section);
|
||||
m_entries.push_back(PathEntry{ index });
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedSection.clear();
|
||||
size_t lastPos = 0;
|
||||
size_t posToEscape = section.find(EscapeCharacter);
|
||||
while (posToEscape != AZStd::string_view::npos)
|
||||
{
|
||||
if (convertedSection.empty())
|
||||
{
|
||||
convertedSection.reserve(section.size() - 1);
|
||||
}
|
||||
convertedSection += section.substr(lastPos, posToEscape - lastPos);
|
||||
if (section[posToEscape + 1] == ForwardSlashSequence)
|
||||
{
|
||||
convertedSection += '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedSection += '~';
|
||||
}
|
||||
|
||||
lastPos = posToEscape + 2;
|
||||
posToEscape = section.find(EscapeCharacter, posToEscape + 2);
|
||||
}
|
||||
|
||||
if (!convertedSection.empty())
|
||||
{
|
||||
convertedSection += section.substr(lastPos);
|
||||
m_entries.emplace_back(convertedSection);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entries.emplace_back(section);
|
||||
}
|
||||
}
|
||||
pathIndex = i + 1;
|
||||
isNumber = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char c = pathString[i];
|
||||
isNumber = isNumber && c >= '0' && c <= '9';
|
||||
}
|
||||
}
|
||||
} // namespace AZ::Dom
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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/Name/Name.h>
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AZ::Dom
|
||||
{
|
||||
//! Represents the path to a direct descendant of a Value.
|
||||
//! PathEntry may be one of the following:
|
||||
//! - Index, a numerical index for indexing within Arrays and Nodes
|
||||
//! - Key, a name for indexing within Objects and Nodes
|
||||
//! - EndOfArray, a special-case indicator for representing the end of an array
|
||||
//! used by the patching system to represent push / pop back operations.
|
||||
class PathEntry final
|
||||
{
|
||||
public:
|
||||
static constexpr size_t EndOfArrayIndex = size_t(-1);
|
||||
|
||||
PathEntry() = default;
|
||||
PathEntry(const PathEntry&) = default;
|
||||
PathEntry(PathEntry&&) = default;
|
||||
explicit PathEntry(size_t value);
|
||||
explicit PathEntry(AZ::Name value);
|
||||
explicit PathEntry(AZStd::string_view value);
|
||||
|
||||
PathEntry& operator=(const PathEntry&) = default;
|
||||
PathEntry& operator=(PathEntry&&) = default;
|
||||
PathEntry& operator=(size_t value);
|
||||
PathEntry& operator=(AZ::Name value);
|
||||
PathEntry& operator=(AZStd::string_view value);
|
||||
|
||||
bool operator==(const PathEntry& other) const;
|
||||
bool operator==(size_t index) const;
|
||||
bool operator==(const AZ::Name& key) const;
|
||||
bool operator==(AZStd::string_view key) const;
|
||||
bool operator!=(const PathEntry& other) const;
|
||||
bool operator!=(size_t index) const;
|
||||
bool operator!=(const AZ::Name& key) const;
|
||||
bool operator!=(AZStd::string_view key) const;
|
||||
|
||||
void SetEndOfArray();
|
||||
|
||||
bool IsEndOfArray() const;
|
||||
bool IsIndex() const;
|
||||
bool IsKey() const;
|
||||
|
||||
size_t GetIndex() const;
|
||||
const AZ::Name& GetKey() const;
|
||||
|
||||
private:
|
||||
AZStd::variant<size_t, AZ::Name> m_value;
|
||||
};
|
||||
|
||||
//! Represents a path, represented as a series of PathEntry values, to a position in a Value.
|
||||
class Path final
|
||||
{
|
||||
public:
|
||||
using ContainerType = AZStd::vector<PathEntry>;
|
||||
static constexpr char PathSeparator = '/';
|
||||
static constexpr char EscapeCharacter = '~';
|
||||
static constexpr char TildeSequence = '0';
|
||||
static constexpr char ForwardSlashSequence = '1';
|
||||
static constexpr char EndOfArrayCharacter = '-';
|
||||
|
||||
Path() = default;
|
||||
Path(const Path&) = default;
|
||||
Path(Path&&) = default;
|
||||
explicit Path(AZStd::initializer_list<PathEntry> init);
|
||||
//! Creates a Path from a path string, a path string is formatted per the JSON pointer specification
|
||||
//! and looks like "/path/to/value/0"
|
||||
explicit Path(AZStd::string_view pathString);
|
||||
|
||||
template<class InputIterator>
|
||||
explicit Path(InputIterator first, InputIterator last)
|
||||
: m_entries(first, last)
|
||||
{
|
||||
}
|
||||
|
||||
Path& operator=(const Path&) = default;
|
||||
Path& operator=(Path&&) = default;
|
||||
|
||||
Path operator/(const PathEntry&) const;
|
||||
Path operator/(size_t) const;
|
||||
Path operator/(AZ::Name) const;
|
||||
Path operator/(AZStd::string_view) const;
|
||||
Path operator/(const Path&) const;
|
||||
|
||||
Path& operator/=(const PathEntry&);
|
||||
Path& operator/=(size_t);
|
||||
Path& operator/=(AZ::Name);
|
||||
Path& operator/=(AZStd::string_view);
|
||||
Path& operator/=(const Path&);
|
||||
|
||||
bool operator==(const Path&) const;
|
||||
|
||||
const ContainerType& GetEntries() const;
|
||||
void Push(PathEntry entry);
|
||||
void Push(size_t entry);
|
||||
void Push(AZ::Name entry);
|
||||
void Push(AZStd::string_view key);
|
||||
void Pop();
|
||||
void Clear();
|
||||
PathEntry At(size_t index) const;
|
||||
size_t Size() const;
|
||||
|
||||
PathEntry& operator[](size_t index);
|
||||
const PathEntry& operator[](size_t index) const;
|
||||
|
||||
ContainerType::iterator begin();
|
||||
ContainerType::iterator end();
|
||||
ContainerType::const_iterator begin() const;
|
||||
ContainerType::const_iterator end() const;
|
||||
ContainerType::const_iterator cbegin() const;
|
||||
ContainerType::const_iterator cend() const;
|
||||
size_t size() const;
|
||||
|
||||
//! Gets the length this path would require, if string-formatted.
|
||||
//! The length includes the contents of the string but not a null terminator.
|
||||
size_t GetStringLength() const;
|
||||
//! Formats a JSON-pointer style path string into the target buffer.
|
||||
//! This operation will fail if bufferSize < GetStringLength() + 1
|
||||
void FormatString(char* stringBuffer, size_t bufferSize) const;
|
||||
//! Returns a JSON-pointer style path string for this path.
|
||||
AZStd::string ToString() const;
|
||||
void AppendToString(AZStd::string& output) const;
|
||||
//! Reads a JSON-pointer style path from pathString and replaces this path's contents.
|
||||
//! Paths are accepted in the following forms:
|
||||
//! "/path/to/foo/0"
|
||||
//! "path/to/foo/0"
|
||||
void FromString(AZStd::string_view pathString);
|
||||
|
||||
private:
|
||||
ContainerType m_entries;
|
||||
};
|
||||
} // namespace AZ::Dom
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/DOM/DomPath.h>
|
||||
#include <AzCore/DOM/DomValue.h>
|
||||
#include <AzCore/DOM/DomValueWriter.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
@@ -1177,4 +1178,124 @@ namespace AZ::Dom
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
Value& Value::operator[](const PathEntry& entry)
|
||||
{
|
||||
if (entry.IsEndOfArray())
|
||||
{
|
||||
Array::ContainerType& array = GetArrayInternal();
|
||||
array.push_back();
|
||||
return array[array.size() - 1];
|
||||
}
|
||||
return entry.IsIndex() ? operator[](entry.GetIndex()) : operator[](entry.GetKey());
|
||||
}
|
||||
|
||||
const Value& Value::operator[](const PathEntry& entry) const
|
||||
{
|
||||
return entry.IsIndex() ? operator[](entry.GetIndex()) : operator[](entry.GetKey());
|
||||
}
|
||||
|
||||
Value& Value::operator[](const Path& path)
|
||||
{
|
||||
Value* value = this;
|
||||
for (const PathEntry& entry : path)
|
||||
{
|
||||
value = &value->operator[](entry);
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
const Value& Value::operator[](const Path& path) const
|
||||
{
|
||||
const Value* value = this;
|
||||
for (const PathEntry& entry : path)
|
||||
{
|
||||
value = &value->operator[](entry);
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
const Value* Value::FindChild(const PathEntry& entry) const
|
||||
{
|
||||
if (entry.IsEndOfArray())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else if (entry.IsIndex())
|
||||
{
|
||||
const Array::ContainerType& array = GetArrayInternal();
|
||||
const size_t index = entry.GetIndex();
|
||||
if (index < array.size())
|
||||
{
|
||||
return &array[index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const Object::ContainerType& obj = GetObjectInternal();
|
||||
auto memberIt = FindMember(entry.GetKey());
|
||||
if (memberIt != obj.end())
|
||||
{
|
||||
return &memberIt->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value* Value::FindMutableChild(const PathEntry& entry)
|
||||
{
|
||||
if (entry.IsEndOfArray())
|
||||
{
|
||||
Array::ContainerType& array = GetArrayInternal();
|
||||
array.push_back();
|
||||
return &array[array.size() - 1];
|
||||
}
|
||||
else if (entry.IsIndex())
|
||||
{
|
||||
Array::ContainerType& array = GetArrayInternal();
|
||||
const size_t index = entry.GetIndex();
|
||||
if (index < array.size())
|
||||
{
|
||||
return &array[index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Object::ContainerType& obj = GetObjectInternal();
|
||||
auto memberIt = FindMutableMember(entry.GetKey());
|
||||
if (memberIt != obj.end())
|
||||
{
|
||||
return &memberIt->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Value* Value::FindChild(const Path& path) const
|
||||
{
|
||||
const Value* value = this;
|
||||
for (const PathEntry& entry : path)
|
||||
{
|
||||
value = value->FindChild(entry);
|
||||
if (value == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Value* Value::FindMutableChild(const Path& path)
|
||||
{
|
||||
Value* value = this;
|
||||
for (const PathEntry& entry : path)
|
||||
{
|
||||
value = value->FindMutableChild(entry);
|
||||
if (value == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
} // namespace AZ::Dom
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
namespace AZ::Dom
|
||||
{
|
||||
class PathEntry;
|
||||
class Path;
|
||||
using KeyType = AZ::Name;
|
||||
|
||||
//! The type of underlying value stored in a value. \see Value
|
||||
@@ -380,6 +382,17 @@ namespace AZ::Dom
|
||||
Visitor::Result Accept(Visitor& visitor, bool copyStrings) const;
|
||||
AZStd::unique_ptr<Visitor> GetWriteHandler();
|
||||
|
||||
// Path API...
|
||||
Value& operator[](const PathEntry& entry);
|
||||
const Value& operator[](const PathEntry& entry) const;
|
||||
Value& operator[](const Path& path);
|
||||
const Value& operator[](const Path& path) const;
|
||||
|
||||
const Value* FindChild(const PathEntry& entry) const;
|
||||
Value* FindMutableChild(const PathEntry& entry);
|
||||
const Value* FindChild(const Path& path) const;
|
||||
Value* FindMutableChild(const Path& path);
|
||||
|
||||
//! Gets the internal value of this Value. Note that this value's types may not correspond one-to-one with the Type enumeration,
|
||||
//! as internally the same type might have different storage mechanisms. Where possible, prefer using the typed API.
|
||||
const ValueType& GetInternalValue() const;
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Statistics/StatisticalProfilerProxy.h>
|
||||
|
||||
#ifdef USE_PIX
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <WinPixEventRuntime/pix3.h>
|
||||
#endif
|
||||
|
||||
#if defined(AZ_PROFILER_MACRO_DISABLE) // by default we never disable the profiler registers as their overhead should be minimal, you can
|
||||
// still do that for your code though.
|
||||
#define AZ_PROFILE_SCOPE(...)
|
||||
|
||||
@@ -10,44 +10,48 @@
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
template<typename... T>
|
||||
void BeginProfileRegion(Budget* budget, const char* eventName, T const&... args);
|
||||
void BeginProfileRegion(Budget* budget, const char* eventName);
|
||||
void EndProfileRegion(Budget* budget);
|
||||
} // namespace Platform
|
||||
|
||||
template<typename... T>
|
||||
void ProfileScope::BeginRegion(
|
||||
[[maybe_unused]] Budget* budget, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args)
|
||||
{
|
||||
if (!budget)
|
||||
#if !defined(_RELEASE)
|
||||
if (budget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !defined(_RELEASE)
|
||||
// TODO: Verification that the supplied system name corresponds to a known budget
|
||||
#if defined(USE_PIX)
|
||||
PIXBeginEvent(PIX_COLOR_INDEX(budget->Crc() & 0xff), eventName, args...);
|
||||
#endif
|
||||
budget->BeginProfileRegion();
|
||||
Platform::BeginProfileRegion(budget, eventName, args...);
|
||||
|
||||
if (auto profiler = AZ::Interface<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->BeginRegion(budget, eventName);
|
||||
budget->BeginProfileRegion();
|
||||
|
||||
if (auto profiler = AZ::Interface<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->BeginRegion(budget, eventName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // #if !defined(_RELEASE)
|
||||
}
|
||||
|
||||
inline void ProfileScope::EndRegion([[maybe_unused]] Budget* budget)
|
||||
{
|
||||
if (!budget)
|
||||
#if !defined(_RELEASE)
|
||||
if (budget)
|
||||
{
|
||||
return;
|
||||
budget->EndProfileRegion();
|
||||
|
||||
if (auto profiler = AZ::Interface<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->EndRegion(budget);
|
||||
}
|
||||
|
||||
Platform::EndProfileRegion(budget);
|
||||
}
|
||||
#if !defined(_RELEASE)
|
||||
budget->EndProfileRegion();
|
||||
#if defined(USE_PIX)
|
||||
PIXEndEvent();
|
||||
#endif
|
||||
if (auto profiler = AZ::Interface<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->EndRegion(budget);
|
||||
}
|
||||
#endif
|
||||
#endif // !defined(_RELEASE)
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
@@ -63,3 +67,5 @@ namespace AZ::Debug
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
|
||||
#include <AzCore/Debug/Profiler_Platform.inl>
|
||||
|
||||
@@ -15,14 +15,18 @@
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzCore/std/any.h>
|
||||
|
||||
// These Streamer includes need to be moved to Streamer internals/implementation,
|
||||
// and pull out only what we need for visibility at IStreamer.h interface declaration.
|
||||
#include <AzCore/IO/Streamer/Statistics.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
class ExternalFileRequest;
|
||||
class FileRequestHandle;
|
||||
|
||||
using FileRequestPtr = AZStd::intrusive_ptr<ExternalFileRequest>;
|
||||
/**
|
||||
* Data Streamer Interface
|
||||
*/
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace AZ::IO
|
||||
// Class template instantations
|
||||
template class BasicPath<AZStd::string>;
|
||||
template class BasicPath<FixedMaxPathString>;
|
||||
template class PathIterator<PathView>;
|
||||
template class PathIterator<Path>;
|
||||
template class PathIterator<FixedMaxPath>;
|
||||
template class PathIterator<const PathView>;
|
||||
template class PathIterator<const Path>;
|
||||
template class PathIterator<const FixedMaxPath>;
|
||||
|
||||
// Swap function instantiations
|
||||
template void swap<AZStd::string>(Path& lhs, Path& rhs) noexcept;
|
||||
@@ -38,16 +38,16 @@ namespace AZ::IO
|
||||
const typename BasicPath<FixedMaxPathString>::value_type* rhs);
|
||||
|
||||
// Iterator compare instantiations
|
||||
template bool operator==<PathView>(const PathIterator<PathView>& lhs,
|
||||
const PathIterator<PathView>& rhs);
|
||||
template bool operator==<Path>(const PathIterator<Path>& lhs,
|
||||
const PathIterator<Path>& rhs);
|
||||
template bool operator==<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
|
||||
const PathIterator<FixedMaxPath>& rhs);
|
||||
template bool operator!=<PathView>(const PathIterator<PathView>& lhs,
|
||||
const PathIterator<PathView>& rhs);
|
||||
template bool operator!=<Path>(const PathIterator<Path>& lhs,
|
||||
const PathIterator<Path>& rhs);
|
||||
template bool operator!=<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
|
||||
const PathIterator<FixedMaxPath>& rhs);
|
||||
template bool operator==<const PathView>(const PathIterator<const PathView>& lhs,
|
||||
const PathIterator<const PathView>& rhs);
|
||||
template bool operator==<const Path>(const PathIterator<const Path>& lhs,
|
||||
const PathIterator<const Path>& rhs);
|
||||
template bool operator==<const FixedMaxPath>(const PathIterator<const FixedMaxPath>& lhs,
|
||||
const PathIterator<const FixedMaxPath>& rhs);
|
||||
template bool operator!=<const PathView>(const PathIterator<const PathView>& lhs,
|
||||
const PathIterator<const PathView>& rhs);
|
||||
template bool operator!=<const Path>(const PathIterator<const Path>& lhs,
|
||||
const PathIterator<const Path>& rhs);
|
||||
template bool operator!=<const FixedMaxPath>(const PathIterator<const FixedMaxPath>& lhs,
|
||||
const PathIterator<const FixedMaxPath>& rhs);
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace AZ::IO
|
||||
public:
|
||||
using string_view_type = AZStd::string_view;
|
||||
using value_type = char;
|
||||
using const_iterator = const PathIterator<PathView>;
|
||||
using const_iterator = PathIterator<const PathView>;
|
||||
using iterator = const_iterator;
|
||||
friend PathIterator<PathView>;
|
||||
friend const_iterator;
|
||||
|
||||
// constructors and destructor
|
||||
constexpr PathView() = default;
|
||||
@@ -319,9 +319,9 @@ namespace AZ::IO
|
||||
using value_type = typename StringType::value_type;
|
||||
using traits_type = typename StringType::traits_type;
|
||||
using string_view_type = AZStd::string_view;
|
||||
using const_iterator = const PathIterator<BasicPath>;
|
||||
using const_iterator = PathIterator<const BasicPath>;
|
||||
using iterator = const_iterator;
|
||||
friend PathIterator<BasicPath>;
|
||||
friend const_iterator;
|
||||
|
||||
// constructors and destructor
|
||||
constexpr BasicPath() = default;
|
||||
@@ -692,7 +692,7 @@ namespace AZ::IO
|
||||
friend PathType;
|
||||
|
||||
using iterator_category = AZStd::bidirectional_iterator_tag;
|
||||
using value_type = PathType;
|
||||
using value_type = AZStd::remove_cv_t<PathType>;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
@@ -703,8 +703,9 @@ namespace AZ::IO
|
||||
|
||||
constexpr PathIterator() = default;
|
||||
constexpr PathIterator(const PathIterator&) = default;
|
||||
|
||||
constexpr PathIterator(PathIterator&&) noexcept = default;
|
||||
constexpr PathIterator& operator=(const PathIterator&) = default;
|
||||
constexpr PathIterator& operator=(PathIterator&&) noexcept = default;
|
||||
|
||||
constexpr reference operator*() const;
|
||||
|
||||
@@ -733,10 +734,10 @@ namespace AZ::IO
|
||||
ParserState m_state{ Singular };
|
||||
};
|
||||
|
||||
template <typename PathType1>
|
||||
constexpr bool operator==(const PathIterator<PathType1>& lhs, const PathIterator<PathType1>& rhs);
|
||||
template <typename PathType1>
|
||||
constexpr bool operator!=(const PathIterator<PathType1>& lhs, const PathIterator<PathType1>& rhs);
|
||||
template <typename PathType>
|
||||
constexpr bool operator==(const PathIterator<PathType>& lhs, const PathIterator<PathType>& rhs);
|
||||
template <typename PathType>
|
||||
constexpr bool operator!=(const PathIterator<PathType>& lhs, const PathIterator<PathType>& rhs);
|
||||
}
|
||||
|
||||
#include <AzCore/IO/Path/Path.inl>
|
||||
|
||||
@@ -399,7 +399,7 @@ namespace AZ::IO
|
||||
constexpr auto PathView::begin() const -> const_iterator
|
||||
{
|
||||
auto pathParser = parser::PathParser::CreateBegin(m_path, m_preferred_separator);
|
||||
PathIterator<PathView> it;
|
||||
const_iterator it;
|
||||
it.m_path_ref = this;
|
||||
it.m_state = static_cast<typename const_iterator::ParserState>(pathParser.m_parser_state);
|
||||
it.m_path_entry_view = pathParser.m_path_raw_entry;
|
||||
@@ -409,7 +409,7 @@ namespace AZ::IO
|
||||
|
||||
constexpr auto PathView::end() const -> const_iterator
|
||||
{
|
||||
PathIterator<PathView> it;
|
||||
const_iterator it;
|
||||
it.m_state = const_iterator::AtEnd;
|
||||
it.m_path_ref = this;
|
||||
return it;
|
||||
@@ -1262,7 +1262,7 @@ namespace AZ::IO
|
||||
constexpr auto BasicPath<StringType>::begin() const -> const_iterator
|
||||
{
|
||||
auto pathParser = parser::PathParser::CreateBegin(m_path, m_preferred_separator);
|
||||
PathIterator<BasicPath> it;
|
||||
const_iterator it;
|
||||
it.m_path_ref = this;
|
||||
it.m_state = static_cast<typename const_iterator::ParserState>(pathParser.m_parser_state);
|
||||
it.m_path_entry_view = pathParser.m_path_raw_entry;
|
||||
@@ -1273,7 +1273,7 @@ namespace AZ::IO
|
||||
template <typename StringType>
|
||||
constexpr auto BasicPath<StringType>::end() const -> const_iterator
|
||||
{
|
||||
PathIterator<BasicPath> it;
|
||||
const_iterator it;
|
||||
it.m_state = const_iterator::AtEnd;
|
||||
it.m_path_ref = this;
|
||||
return it;
|
||||
@@ -1529,16 +1529,16 @@ namespace AZ::IO
|
||||
const typename BasicPath<FixedMaxPathString>::value_type* rhs);
|
||||
|
||||
// Iterator compare explicit declarations
|
||||
extern template bool operator==<PathView>(const PathIterator<PathView>& lhs,
|
||||
const PathIterator<PathView>& rhs);
|
||||
extern template bool operator==<Path>(const PathIterator<Path>& lhs,
|
||||
const PathIterator<Path>& rhs);
|
||||
extern template bool operator==<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
|
||||
const PathIterator<FixedMaxPath>& rhs);
|
||||
extern template bool operator!=<PathView>(const PathIterator<PathView>& lhs,
|
||||
const PathIterator<PathView>& rhs);
|
||||
extern template bool operator!=<Path>(const PathIterator<Path>& lhs,
|
||||
const PathIterator<Path>& rhs);
|
||||
extern template bool operator!=<FixedMaxPath>(const PathIterator<FixedMaxPath>& lhs,
|
||||
const PathIterator<FixedMaxPath>& rhs);
|
||||
extern template bool operator==<const PathView>(const PathIterator<const PathView>& lhs,
|
||||
const PathIterator<const PathView>& rhs);
|
||||
extern template bool operator==<const Path>(const PathIterator<const Path>& lhs,
|
||||
const PathIterator<const Path>& rhs);
|
||||
extern template bool operator==<const FixedMaxPath>(const PathIterator<const FixedMaxPath>& lhs,
|
||||
const PathIterator<const FixedMaxPath>& rhs);
|
||||
extern template bool operator!=<const PathView>(const PathIterator<const PathView>& lhs,
|
||||
const PathIterator<const PathView>& rhs);
|
||||
extern template bool operator!=<const Path>(const PathIterator<const Path>& lhs,
|
||||
const PathIterator<const Path>& rhs);
|
||||
extern template bool operator!=<const FixedMaxPath>(const PathIterator<const FixedMaxPath>& lhs,
|
||||
const PathIterator<const FixedMaxPath>& rhs);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/AzCore_Traits_Platform.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/std/concepts/concepts.h>
|
||||
|
||||
namespace AZ::IO::Internal
|
||||
{
|
||||
@@ -17,7 +18,7 @@ namespace AZ::IO::Internal
|
||||
{
|
||||
return elem == '/' || elem == '\\';
|
||||
}
|
||||
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::Internal::is_input_iterator_v<InputIt>>>
|
||||
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::input_iterator<InputIt>>>
|
||||
static constexpr bool HasDrivePrefix(InputIt first, EndIt last)
|
||||
{
|
||||
size_t prefixSize = AZStd::distance(first, last);
|
||||
@@ -46,7 +47,7 @@ namespace AZ::IO::Internal
|
||||
//! Windows root names can have include drive letter within them
|
||||
template <typename InputIt>
|
||||
constexpr auto ConsumeRootName(InputIt entryBeginIter, InputIt entryEndIter, const char preferredSeparator)
|
||||
-> AZStd::enable_if_t<AZStd::Internal::is_forward_iterator_v<InputIt>, InputIt>
|
||||
-> AZStd::enable_if_t<AZStd::forward_iterator<InputIt>, InputIt>
|
||||
{
|
||||
if (preferredSeparator == PosixPathSeparator)
|
||||
{
|
||||
@@ -147,7 +148,7 @@ namespace AZ::IO::Internal
|
||||
//! If the preferred separator is '/' just checks if the path starts with a '/
|
||||
//! Otherwise a check for a Windows absolute path occurs
|
||||
//! Windows absolute paths can include a RootName
|
||||
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::Internal::is_input_iterator_v<InputIt>>>
|
||||
template <typename InputIt, typename EndIt, typename = AZStd::enable_if_t<AZStd::input_iterator<InputIt>>>
|
||||
static constexpr bool IsAbsolute(InputIt first, EndIt last, const char preferredSeparator)
|
||||
{
|
||||
size_t pathSize = AZStd::distance(first, last);
|
||||
@@ -208,11 +209,11 @@ namespace AZ::IO::parser
|
||||
enum ParserState : uint8_t
|
||||
{
|
||||
// Zero is a special sentinel value used by default constructed iterators.
|
||||
PS_BeforeBegin = PathIterator<PathView>::BeforeBegin,
|
||||
PS_InRootName = PathIterator<PathView>::InRootName,
|
||||
PS_InRootDir = PathIterator<PathView>::InRootDir,
|
||||
PS_InFilenames = PathIterator<PathView>::InFilenames,
|
||||
PS_AtEnd = PathIterator<PathView>::AtEnd
|
||||
PS_BeforeBegin = PathView::const_iterator::BeforeBegin,
|
||||
PS_InRootName = PathView::const_iterator::InRootName,
|
||||
PS_InRootDir = PathView::const_iterator::InRootDir,
|
||||
PS_InFilenames = PathView::const_iterator::InFilenames,
|
||||
PS_AtEnd = PathView::const_iterator::AtEnd
|
||||
};
|
||||
|
||||
struct PathParser
|
||||
|
||||
@@ -137,18 +137,18 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
ReadFile(request, args);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
|
||||
{
|
||||
FlushCache(args.m_path);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
|
||||
{
|
||||
FlushEntireCache();
|
||||
}
|
||||
@@ -166,7 +166,7 @@ namespace AZ::IO
|
||||
{
|
||||
Section& delayed = m_delayedSections.front();
|
||||
AZ_Assert(delayed.m_parent, "Delayed section doesn't have a reference to the original request.");
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&delayed.m_parent->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&delayed.m_parent->GetCommand());
|
||||
AZ_Assert(data, "A request in the delayed queue of the BlockCache didn't have a parent with read data.");
|
||||
// This call can add the same section to the back of the queue if there's not
|
||||
// enough space. Because of this the entry needs to be removed from the delayed
|
||||
@@ -233,7 +233,7 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
void BlockCache::ReadFile(FileRequest* request, FileRequest::ReadData& data)
|
||||
void BlockCache::ReadFile(FileRequest* request, Requests::ReadData& data)
|
||||
{
|
||||
if (!m_next)
|
||||
{
|
||||
@@ -250,7 +250,7 @@ namespace AZ::IO
|
||||
m_numMetaDataRetrievalInProgress--;
|
||||
if (fileSizeRequest.GetStatus() == IStreamerTypes::RequestStatus::Completed)
|
||||
{
|
||||
auto& requestInfo = AZStd::get<FileRequest::FileMetaDataRetrievalData>(fileSizeRequest.GetCommand());
|
||||
auto& requestInfo = AZStd::get<Requests::FileMetaDataRetrievalData>(fileSizeRequest.GetCommand());
|
||||
if (requestInfo.m_found)
|
||||
{
|
||||
ContinueReadFile(request, requestInfo.m_fileSize);
|
||||
@@ -272,7 +272,7 @@ namespace AZ::IO
|
||||
Section main;
|
||||
Section epilog;
|
||||
|
||||
auto& data = AZStd::get<FileRequest::ReadData>(request->GetCommand());
|
||||
auto& data = AZStd::get<Requests::ReadData>(request->GetCommand());
|
||||
|
||||
if (!SplitRequest(prolog, main, epilog, data.m_path, fileLength, data.m_offset, data.m_size,
|
||||
reinterpret_cast<u8*>(data.m_output)))
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
class RequestPath;
|
||||
namespace Requests
|
||||
{
|
||||
struct ReadData;
|
||||
}
|
||||
|
||||
struct BlockCacheConfig final :
|
||||
public IStreamerStackConfig
|
||||
{
|
||||
@@ -109,7 +115,7 @@ namespace AZ::IO
|
||||
|
||||
using TimePoint = AZStd::chrono::system_clock::time_point;
|
||||
|
||||
void ReadFile(FileRequest* request, FileRequest::ReadData& data);
|
||||
void ReadFile(FileRequest* request, Requests::ReadData& data);
|
||||
void ContinueReadFile(FileRequest* request, u64 fileLength);
|
||||
CacheResult ReadFromCache(FileRequest* request, Section& section, const RequestPath& filePath);
|
||||
CacheResult ReadFromCache(FileRequest* request, Section& section, u32 cacheBlock);
|
||||
|
||||
@@ -101,12 +101,12 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData>)
|
||||
{
|
||||
args.m_range = FileRange::CreateRangeForEntireFile();
|
||||
m_context->PushPreparedRequest(request);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
|
||||
{
|
||||
args.m_range = FileRange::CreateRangeForEntireFile();
|
||||
m_context->PushPreparedRequest(request);
|
||||
@@ -125,28 +125,28 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
ReadFile(request, args);
|
||||
return;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData>)
|
||||
{
|
||||
CreateDedicatedCache(request, args);
|
||||
return;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
|
||||
{
|
||||
DestroyDedicatedCache(request, args);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
|
||||
{
|
||||
FlushCache(args.m_path);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
|
||||
{
|
||||
FlushEntireCache();
|
||||
}
|
||||
@@ -200,7 +200,7 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
void DedicatedCache::ReadFile(FileRequest* request, FileRequest::ReadData& data)
|
||||
void DedicatedCache::ReadFile(FileRequest* request, Requests::ReadData& data)
|
||||
{
|
||||
size_t index = FindCache(data.m_path, data.m_offset);
|
||||
if (index == s_fileNotFound)
|
||||
@@ -255,7 +255,7 @@ namespace AZ::IO
|
||||
StreamStackEntry::CollectStatistics(statistics);
|
||||
}
|
||||
|
||||
void DedicatedCache::CreateDedicatedCache(FileRequest* request, FileRequest::CreateDedicatedCacheData& data)
|
||||
void DedicatedCache::CreateDedicatedCache(FileRequest* request, Requests::CreateDedicatedCacheData& data)
|
||||
{
|
||||
size_t index = FindCache(data.m_path, data.m_range);
|
||||
if (index == s_fileNotFound)
|
||||
@@ -276,7 +276,7 @@ namespace AZ::IO
|
||||
m_context->MarkRequestAsCompleted(request);
|
||||
}
|
||||
|
||||
void DedicatedCache::DestroyDedicatedCache(FileRequest* request, FileRequest::DestroyDedicatedCacheData& data)
|
||||
void DedicatedCache::DestroyDedicatedCache(FileRequest* request, Requests::DestroyDedicatedCacheData& data)
|
||||
{
|
||||
size_t index = FindCache(data.m_path, data.m_range);
|
||||
if (index != s_fileNotFound)
|
||||
|
||||
@@ -11,15 +11,21 @@
|
||||
#include <AzCore/IO/Streamer/BlockCache.h>
|
||||
#include <AzCore/IO/Streamer/FileRange.h>
|
||||
#include <AzCore/IO/Streamer/Statistics.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
#include <AzCore/IO/Streamer/StreamStackEntry.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/limits.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/limits.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
namespace Requests
|
||||
{
|
||||
struct CreateDedicatedCacheData;
|
||||
struct DestroyDedicatedCacheData;
|
||||
} // namespace Requests
|
||||
|
||||
struct DedicatedCacheConfig final :
|
||||
public IStreamerStackConfig
|
||||
{
|
||||
@@ -56,16 +62,19 @@ namespace AZ::IO
|
||||
|
||||
void UpdateStatus(Status& status) const override;
|
||||
|
||||
void UpdateCompletionEstimates(AZStd::chrono::system_clock::time_point now, AZStd::vector<FileRequest*>& internalPending,
|
||||
StreamerContext::PreparedQueue::iterator pendingBegin, StreamerContext::PreparedQueue::iterator pendingEnd) override;
|
||||
void UpdateCompletionEstimates(
|
||||
AZStd::chrono::system_clock::time_point now,
|
||||
AZStd::vector<FileRequest*>& internalPending,
|
||||
StreamerContext::PreparedQueue::iterator pendingBegin,
|
||||
StreamerContext::PreparedQueue::iterator pendingEnd) override;
|
||||
|
||||
void CollectStatistics(AZStd::vector<Statistic>& statistics) const override;
|
||||
|
||||
private:
|
||||
void CreateDedicatedCache(FileRequest* request, FileRequest::CreateDedicatedCacheData& data);
|
||||
void DestroyDedicatedCache(FileRequest* request, FileRequest::DestroyDedicatedCacheData& data);
|
||||
void CreateDedicatedCache(FileRequest* request, Requests::CreateDedicatedCacheData& data);
|
||||
void DestroyDedicatedCache(FileRequest* request, Requests::DestroyDedicatedCacheData& data);
|
||||
|
||||
void ReadFile(FileRequest* request, FileRequest::ReadData& data);
|
||||
void ReadFile(FileRequest* request, Requests::ReadData& data);
|
||||
size_t FindCache(const RequestPath& filename, FileRange range);
|
||||
size_t FindCache(const RequestPath& filename, u64 offset);
|
||||
|
||||
|
||||
@@ -12,22 +12,30 @@
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/IO/Streamer/StreamerContext.h>
|
||||
|
||||
namespace AZ::IO
|
||||
//
|
||||
// Command structures.
|
||||
//
|
||||
|
||||
namespace AZ::IO::Requests
|
||||
{
|
||||
//
|
||||
// Command structures.
|
||||
//
|
||||
ReadData::ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead)
|
||||
: m_path(path)
|
||||
, m_output(output)
|
||||
, m_outputSize(outputSize)
|
||||
, m_offset(offset)
|
||||
, m_size(size)
|
||||
, m_sharedRead(sharedRead)
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::ExternalRequestData::ExternalRequestData(FileRequestPtr&& request)
|
||||
: m_request(AZStd::move(request))
|
||||
{}
|
||||
|
||||
FileRequest::RequestPathStoreData::RequestPathStoreData(RequestPath path)
|
||||
: m_path(AZStd::move(path))
|
||||
{}
|
||||
|
||||
FileRequest::ReadRequestData::ReadRequestData(RequestPath path, void* output, u64 outputSize, u64 offset, u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority)
|
||||
ReadRequestData::ReadRequestData(
|
||||
RequestPath path,
|
||||
void* output,
|
||||
u64 outputSize,
|
||||
u64 offset,
|
||||
u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline,
|
||||
IStreamerTypes::Priority priority)
|
||||
: m_path(AZStd::move(path))
|
||||
, m_allocator(nullptr)
|
||||
, m_deadline(deadline)
|
||||
@@ -37,10 +45,16 @@ namespace AZ::IO
|
||||
, m_size(size)
|
||||
, m_priority(priority)
|
||||
, m_memoryType(IStreamerTypes::MemoryType::ReadWrite) // Only generic memory can be assigned externally.
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::ReadRequestData::ReadRequestData(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator,
|
||||
u64 offset, u64 size, AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority)
|
||||
ReadRequestData::ReadRequestData(
|
||||
RequestPath path,
|
||||
IStreamerTypes::RequestMemoryAllocator* allocator,
|
||||
u64 offset,
|
||||
u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline,
|
||||
IStreamerTypes::Priority priority)
|
||||
: m_path(AZStd::move(path))
|
||||
, m_allocator(allocator)
|
||||
, m_deadline(deadline)
|
||||
@@ -50,9 +64,10 @@ namespace AZ::IO
|
||||
, m_size(size)
|
||||
, m_priority(priority)
|
||||
, m_memoryType(IStreamerTypes::MemoryType::ReadWrite) // Only generic memory can be assigned externally.
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::ReadRequestData::~ReadRequestData()
|
||||
ReadRequestData::~ReadRequestData()
|
||||
{
|
||||
if (m_allocator != nullptr)
|
||||
{
|
||||
@@ -64,65 +79,80 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
FileRequest::ReadData::ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead)
|
||||
: m_output(output)
|
||||
, m_outputSize(outputSize)
|
||||
, m_path(path)
|
||||
, m_offset(offset)
|
||||
, m_size(size)
|
||||
, m_sharedRead(sharedRead)
|
||||
{}
|
||||
CreateDedicatedCacheData::CreateDedicatedCacheData(RequestPath path, const FileRange& range)
|
||||
: m_path(AZStd::move(path))
|
||||
, m_range(range)
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::CompressedReadData::CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize)
|
||||
DestroyDedicatedCacheData::DestroyDedicatedCacheData(RequestPath path, const FileRange& range)
|
||||
: m_path(AZStd::move(path))
|
||||
, m_range(range)
|
||||
{
|
||||
}
|
||||
|
||||
ExternalRequestData::ExternalRequestData(FileRequestPtr&& request)
|
||||
: m_request(AZStd::move(request))
|
||||
{
|
||||
}
|
||||
|
||||
RequestPathStoreData::RequestPathStoreData(RequestPath path)
|
||||
: m_path(AZStd::move(path))
|
||||
{
|
||||
}
|
||||
|
||||
CompressedReadData::CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize)
|
||||
: m_compressionInfo(AZStd::move(compressionInfo))
|
||||
, m_output(output)
|
||||
, m_readOffset(readOffset)
|
||||
, m_readSize(readSize)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::FileExistsCheckData::FileExistsCheckData(const RequestPath& path)
|
||||
FileExistsCheckData::FileExistsCheckData(const RequestPath& path)
|
||||
: m_path(path)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::FileMetaDataRetrievalData::FileMetaDataRetrievalData(const RequestPath& path)
|
||||
FileMetaDataRetrievalData::FileMetaDataRetrievalData(const RequestPath& path)
|
||||
: m_path(path)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::CancelData::CancelData(FileRequestPtr target)
|
||||
CancelData::CancelData(FileRequestPtr target)
|
||||
: m_target(AZStd::move(target))
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::FlushData::FlushData(RequestPath path)
|
||||
FlushData::FlushData(RequestPath path)
|
||||
: m_path(AZStd::move(path))
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::RescheduleData::RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline,
|
||||
RescheduleData::RescheduleData(
|
||||
FileRequestPtr target,
|
||||
AZStd::chrono::system_clock::time_point newDeadline,
|
||||
IStreamerTypes::Priority newPriority)
|
||||
: m_target(AZStd::move(target))
|
||||
, m_newDeadline(newDeadline)
|
||||
, m_newPriority(newPriority)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::CreateDedicatedCacheData::CreateDedicatedCacheData(RequestPath path, const FileRange& range)
|
||||
: m_path(AZStd::move(path))
|
||||
, m_range(range)
|
||||
{}
|
||||
|
||||
FileRequest::DestroyDedicatedCacheData::DestroyDedicatedCacheData(RequestPath path, const FileRange& range)
|
||||
: m_path(AZStd::move(path))
|
||||
, m_range(range)
|
||||
{}
|
||||
|
||||
FileRequest::ReportData::ReportData(ReportType reportType)
|
||||
ReportData::ReportData(ReportType reportType)
|
||||
: m_reportType(reportType)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
FileRequest::CustomData::CustomData(AZStd::any data, bool failWhenUnhandled)
|
||||
CustomData::CustomData(AZStd::any data, bool failWhenUnhandled)
|
||||
: m_data(AZStd::move(data))
|
||||
, m_failWhenUnhandled(failWhenUnhandled)
|
||||
{}
|
||||
|
||||
{
|
||||
}
|
||||
} // namespace AZ::IO::Requests
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
//
|
||||
// FileRequest
|
||||
//
|
||||
@@ -145,14 +175,14 @@ namespace AZ::IO
|
||||
m_parent = request->m_request.m_parent;
|
||||
request->m_request.m_parent = this;
|
||||
m_dependencies++;
|
||||
m_command.emplace<ExternalRequestData>(AZStd::move(request));
|
||||
m_command.emplace<Requests::ExternalRequestData>(AZStd::move(request));
|
||||
}
|
||||
|
||||
void FileRequest::CreateRequestPathStore(FileRequest* parent, RequestPath path)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'CreateRequestPathStore', but another task was already assigned.");
|
||||
m_command.emplace<RequestPathStoreData>(AZStd::move(path));
|
||||
m_command.emplace<Requests::RequestPathStoreData>(AZStd::move(path));
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
@@ -161,7 +191,7 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'ReadRequest', but another task was already assigned.");
|
||||
m_command.emplace<ReadRequestData>(AZStd::move(path), output, outputSize, offset, size, deadline, priority);
|
||||
m_command.emplace<Requests::ReadRequestData>(AZStd::move(path), output, outputSize, offset, size, deadline, priority);
|
||||
}
|
||||
|
||||
void FileRequest::CreateReadRequest(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator, u64 offset, u64 size,
|
||||
@@ -169,7 +199,7 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'ReadRequest', but another task was already assigned.");
|
||||
m_command.emplace<ReadRequestData>(AZStd::move(path), allocator, offset, size, deadline, priority);
|
||||
m_command.emplace<Requests::ReadRequestData>(AZStd::move(path), allocator, offset, size, deadline, priority);
|
||||
}
|
||||
|
||||
void FileRequest::CreateRead(FileRequest* parent, void* output, u64 outputSize, const RequestPath& path,
|
||||
@@ -177,7 +207,7 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Read', but another task was already assigned.");
|
||||
m_command.emplace<ReadData>(output, outputSize, AZStd::move(path), offset, size, sharedRead);
|
||||
m_command.emplace<Requests::ReadData>(output, outputSize, AZStd::move(path), offset, size, sharedRead);
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
@@ -192,7 +222,7 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'CompressedRead', but another task was already assigned.");
|
||||
m_command.emplace<CompressedReadData>(AZStd::move(compressionInfo), output, readOffset, readSize);
|
||||
m_command.emplace<Requests::CompressedReadData>(AZStd::move(compressionInfo), output, readOffset, readSize);
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
@@ -200,7 +230,7 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Wait', but another task was already assigned.");
|
||||
m_command.emplace<WaitData>();
|
||||
m_command.emplace<Requests::WaitData>();
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
@@ -208,21 +238,21 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'FileExistsCheck', but another task was already assigned.");
|
||||
m_command.emplace<FileExistsCheckData>(path);
|
||||
m_command.emplace<Requests::FileExistsCheckData>(path);
|
||||
}
|
||||
|
||||
void FileRequest::CreateFileMetaDataRetrieval(const RequestPath& path)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'FileMetaDataRetrieval', but another task was already assigned.");
|
||||
m_command.emplace<FileMetaDataRetrievalData>(path);
|
||||
m_command.emplace<Requests::FileMetaDataRetrievalData>(path);
|
||||
}
|
||||
|
||||
void FileRequest::CreateCancel(FileRequestPtr target)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Cancel', but another task was already assigned.");
|
||||
m_command.emplace<CancelData>(AZStd::move(target));
|
||||
m_command.emplace<Requests::CancelData>(AZStd::move(target));
|
||||
}
|
||||
|
||||
void FileRequest::CreateReschedule(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline,
|
||||
@@ -230,28 +260,28 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Reschedule', but another task was already assigned.");
|
||||
m_command.emplace<RescheduleData>(AZStd::move(target), newDeadline, newPriority);
|
||||
m_command.emplace<Requests::RescheduleData>(AZStd::move(target), newDeadline, newPriority);
|
||||
}
|
||||
|
||||
void FileRequest::CreateFlush(RequestPath path)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Flush', but another task was already assigned.");
|
||||
m_command.emplace<FlushData>(AZStd::move(path));
|
||||
m_command.emplace<Requests::FlushData>(AZStd::move(path));
|
||||
}
|
||||
|
||||
void FileRequest::CreateFlushAll()
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'FlushAll', but another task was already assigned.");
|
||||
m_command.emplace<FlushAllData>();
|
||||
m_command.emplace<Requests::FlushAllData>();
|
||||
}
|
||||
|
||||
void FileRequest::CreateDedicatedCacheCreation(RequestPath path, const FileRange& range, FileRequest* parent)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'CreateDedicateCache', but another task was already assigned.");
|
||||
m_command.emplace<CreateDedicatedCacheData>(AZStd::move(path), range);
|
||||
m_command.emplace<Requests::CreateDedicatedCacheData>(AZStd::move(path), range);
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
@@ -259,22 +289,22 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'DestroyDedicateCache', but another task was already assigned.");
|
||||
m_command.emplace<DestroyDedicatedCacheData>(AZStd::move(path), range);
|
||||
m_command.emplace<Requests::DestroyDedicatedCacheData>(AZStd::move(path), range);
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
void FileRequest::CreateReport(ReportData::ReportType reportType)
|
||||
void FileRequest::CreateReport(Requests::ReportType reportType)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Report', but another task was already assigned.");
|
||||
m_command.emplace<ReportData>(reportType);
|
||||
m_command.emplace<Requests::ReportData>(reportType);
|
||||
}
|
||||
|
||||
void FileRequest::CreateCustom(AZStd::any data, bool failWhenUnhandled, FileRequest* parent)
|
||||
{
|
||||
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
|
||||
"Attempting to set FileRequest to 'Custom', but another task was already assigned.");
|
||||
m_command.emplace<CustomData>(AZStd::move(data), failWhenUnhandled);
|
||||
m_command.emplace<Requests::CustomData>(AZStd::move(data), failWhenUnhandled);
|
||||
SetOptionalParent(parent);
|
||||
}
|
||||
|
||||
@@ -361,7 +391,7 @@ namespace AZ::IO
|
||||
"Request does not contain a valid command. It may have been reset already or was never assigned a command.");
|
||||
return true;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CustomData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CustomData>)
|
||||
{
|
||||
return args.m_failWhenUnhandled;
|
||||
}
|
||||
@@ -398,7 +428,7 @@ namespace AZ::IO
|
||||
const FileRequest* current = this;
|
||||
while (current)
|
||||
{
|
||||
auto* link = AZStd::get_if<ExternalRequestData>(¤t->m_command);
|
||||
auto* link = AZStd::get_if<Requests::ExternalRequestData>(¤t->m_command);
|
||||
if (!link)
|
||||
{
|
||||
current = current->m_parent;
|
||||
|
||||
@@ -27,7 +27,252 @@ namespace AZ::IO
|
||||
class ExternalFileRequest;
|
||||
|
||||
using FileRequestPtr = AZStd::intrusive_ptr<ExternalFileRequest>;
|
||||
} // namespace AZ::IO
|
||||
|
||||
namespace AZ::IO::Requests
|
||||
{
|
||||
//! Request to read data. This is a translated request and holds an absolute path and has been
|
||||
//! resolved to the archive file if needed.
|
||||
struct ReadData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead);
|
||||
|
||||
const RequestPath& m_path; //!< The path to the file that contains the requested data.
|
||||
void* m_output; //!< Target output to write the read data to.
|
||||
u64 m_outputSize; //!< Size of memory m_output points to. This needs to be at least as big as m_size, but can be bigger.
|
||||
u64 m_offset; //!< The offset in bytes into the file.
|
||||
u64 m_size; //!< The number of bytes to read from the file.
|
||||
bool m_sharedRead; //!< True if other code will be reading from the file or the stack entry can exclusively lock.
|
||||
};
|
||||
|
||||
//! Request to read data. This is an untranslated request and holds a relative path. The Scheduler
|
||||
//! will translate this to the appropriate ReadData or CompressedReadData.
|
||||
struct ReadRequestData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
ReadRequestData(
|
||||
RequestPath path,
|
||||
void* output,
|
||||
u64 outputSize,
|
||||
u64 offset,
|
||||
u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline,
|
||||
IStreamerTypes::Priority priority);
|
||||
ReadRequestData(
|
||||
RequestPath path,
|
||||
IStreamerTypes::RequestMemoryAllocator* allocator,
|
||||
u64 offset,
|
||||
u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline,
|
||||
IStreamerTypes::Priority priority);
|
||||
~ReadRequestData();
|
||||
|
||||
RequestPath m_path; //!< Relative path to the target file.
|
||||
IStreamerTypes::RequestMemoryAllocator* m_allocator; //!< Allocator used to manage the memory for this request.
|
||||
AZStd::chrono::system_clock::time_point m_deadline; //!< Time by which this request should have been completed.
|
||||
void* m_output; //!< The memory address assigned (during processing) to store the read data to.
|
||||
u64 m_outputSize; //!< The memory size of the addressed used to store the read data.
|
||||
u64 m_offset; //!< The offset in bytes into the file.
|
||||
u64 m_size; //!< The number of bytes to read from the file.
|
||||
IStreamerTypes::Priority m_priority; //!< Priority used for ordering requests. This is used when requests have the same deadline.
|
||||
IStreamerTypes::MemoryType m_memoryType; //!< The type of memory provided by the allocator if used.
|
||||
};
|
||||
|
||||
//! Creates a cache dedicated to a single file. This is best used for files where blocks are read from
|
||||
//! periodically such as audio banks of video files.
|
||||
struct CreateDedicatedCacheData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
CreateDedicatedCacheData(RequestPath path, const FileRange& range);
|
||||
|
||||
RequestPath m_path;
|
||||
FileRange m_range;
|
||||
};
|
||||
|
||||
//! Destroys a cache dedicated to a single file that was previously created by CreateDedicatedCache
|
||||
struct DestroyDedicatedCacheData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
DestroyDedicatedCacheData(RequestPath path, const FileRange& range);
|
||||
|
||||
RequestPath m_path;
|
||||
FileRange m_range;
|
||||
};
|
||||
|
||||
enum class ReportType : int8_t
|
||||
{
|
||||
FileLocks
|
||||
};
|
||||
|
||||
struct ReportData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityLow;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit ReportData(ReportType reportType);
|
||||
|
||||
ReportType m_reportType;
|
||||
};
|
||||
|
||||
//! Stores a reference to the external request so it stays alive while the request is being processed.
|
||||
//! This is needed because Streamer supports fire-and-forget requests since completion can be handled by
|
||||
//! registering a callback.
|
||||
struct ExternalRequestData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
explicit ExternalRequestData(FileRequestPtr&& request);
|
||||
|
||||
FileRequestPtr m_request; //!< The request that was send to Streamer.
|
||||
};
|
||||
|
||||
//! Stores an instance of a RequestPath. To reduce copying instances of a RequestPath functions that
|
||||
//! need a path take them by reference to the original request. In some cases a path originates from
|
||||
//! within in the stack and temporary storage is needed. This struct allows for that temporary storage
|
||||
//! so it can be safely referenced later.
|
||||
struct RequestPathStoreData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
explicit RequestPathStoreData(RequestPath path);
|
||||
|
||||
RequestPath m_path;
|
||||
};
|
||||
|
||||
//! Request to read and decompress data.
|
||||
struct CompressedReadData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize);
|
||||
|
||||
CompressionInfo m_compressionInfo;
|
||||
void* m_output; //!< Target output to write the read data to.
|
||||
u64 m_readOffset; //!< The offset into the decompressed to start copying from.
|
||||
u64 m_readSize; //!< Number of bytes to read from the decompressed file.
|
||||
};
|
||||
|
||||
//! Holds the progress of an operation chain until this request is explicitly completed.
|
||||
struct WaitData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
};
|
||||
|
||||
//! Checks to see if any node in the stack can find a file at the provided path.
|
||||
struct FileExistsCheckData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit FileExistsCheckData(const RequestPath& path);
|
||||
|
||||
const RequestPath& m_path;
|
||||
bool m_found{ false };
|
||||
};
|
||||
|
||||
//! Searches for a file in the stack and retrieves the meta data. This may be slower than a file exists
|
||||
//! check.
|
||||
struct FileMetaDataRetrievalData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit FileMetaDataRetrievalData(const RequestPath& path);
|
||||
|
||||
const RequestPath& m_path;
|
||||
u64 m_fileSize{ 0 };
|
||||
bool m_found{ false };
|
||||
};
|
||||
|
||||
//! Cancels a request in the stream stack, if possible.
|
||||
struct CancelData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHighest;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit CancelData(FileRequestPtr target);
|
||||
|
||||
FileRequestPtr m_target; //!< The request that will be canceled.
|
||||
};
|
||||
|
||||
//! Updates the priority and deadline of a request that has not been queued yet.
|
||||
struct RescheduleData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority);
|
||||
|
||||
FileRequestPtr m_target; //!< The request that will be rescheduled.
|
||||
AZStd::chrono::system_clock::time_point m_newDeadline; //!< The new deadline for the request.
|
||||
IStreamerTypes::Priority m_newPriority; //!< The new priority for the request.
|
||||
};
|
||||
|
||||
//! Flushes all references to the provided file in the streaming stack.
|
||||
struct FlushData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit FlushData(RequestPath path);
|
||||
|
||||
RequestPath m_path;
|
||||
};
|
||||
|
||||
//! Flushes all caches in the streaming stack.
|
||||
struct FlushAllData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
};
|
||||
|
||||
//! Data for a custom command. This can be used by nodes added extensions that need data that can't be stored
|
||||
//! in the already provided data.
|
||||
struct CustomData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
|
||||
CustomData(AZStd::any data, bool failWhenUnhandled);
|
||||
|
||||
AZStd::any m_data; //!< The data for the custom request.
|
||||
bool m_failWhenUnhandled; //!< Whether or not the request is marked as failed or success when no node process it.
|
||||
};
|
||||
using CommandVariant = AZStd::variant<
|
||||
AZStd::monostate,
|
||||
ExternalRequestData,
|
||||
RequestPathStoreData,
|
||||
ReadRequestData,
|
||||
ReadData,
|
||||
CompressedReadData,
|
||||
WaitData,
|
||||
FileExistsCheckData,
|
||||
FileMetaDataRetrievalData,
|
||||
CancelData,
|
||||
RescheduleData,
|
||||
FlushData,
|
||||
FlushAllData,
|
||||
CreateDedicatedCacheData,
|
||||
DestroyDedicatedCacheData,
|
||||
ReportData,
|
||||
CustomData>;
|
||||
|
||||
} // namespace AZ::IO::Requests
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
class FileRequest final
|
||||
{
|
||||
public:
|
||||
@@ -36,218 +281,7 @@ namespace AZ::IO
|
||||
friend class StreamerContext;
|
||||
friend class ExternalFileRequest;
|
||||
|
||||
//! Stores a reference to the external request so it stays alive while the request is being processed.
|
||||
//! This is needed because Streamer supports fire-and-forget requests since completion can be handled by
|
||||
//! registering a callback.
|
||||
struct ExternalRequestData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
explicit ExternalRequestData(FileRequestPtr&& request);
|
||||
|
||||
FileRequestPtr m_request; //!< The request that was send to Streamer.
|
||||
};
|
||||
|
||||
//! Stores an instance of a RequestPath. To reduce copying instances of a RequestPath functions that
|
||||
//! need a path take them by reference to the original request. In some cases a path originates from
|
||||
//! within in the stack and temporary storage is needed. This struct allows for that temporary storage
|
||||
//! so it can be safely referenced later.
|
||||
struct RequestPathStoreData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
explicit RequestPathStoreData(RequestPath path);
|
||||
|
||||
RequestPath m_path;
|
||||
};
|
||||
|
||||
//! Request to read data. This is an untranslated request and holds a relative path. The Scheduler
|
||||
//! will translate this to the appropriate ReadData or CompressedReadData.
|
||||
struct ReadRequestData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
ReadRequestData(RequestPath path, void* output, u64 outputSize, u64 offset, u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority);
|
||||
ReadRequestData(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator, u64 offset, u64 size,
|
||||
AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority);
|
||||
~ReadRequestData();
|
||||
|
||||
RequestPath m_path; //!< Relative path to the target file.
|
||||
IStreamerTypes::RequestMemoryAllocator* m_allocator; //!< Allocator used to manage the memory for this request.
|
||||
AZStd::chrono::system_clock::time_point m_deadline; //!< Time by which this request should have been completed.
|
||||
void* m_output; //!< The memory address assigned (during processing) to store the read data to.
|
||||
u64 m_outputSize; //!< The memory size of the addressed used to store the read data.
|
||||
u64 m_offset; //!< The offset in bytes into the file.
|
||||
u64 m_size; //!< The number of bytes to read from the file.
|
||||
IStreamerTypes::Priority m_priority; //!< Priority used for ordering requests. This is used when requests have the same deadline.
|
||||
IStreamerTypes::MemoryType m_memoryType; //!< The type of memory provided by the allocator if used.
|
||||
};
|
||||
|
||||
//! Request to read data. This is a translated request and holds an absolute path and has been
|
||||
//! resolved to the archive file if needed.
|
||||
struct ReadData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead);
|
||||
|
||||
const RequestPath& m_path; //!< The path to the file that contains the requested data.
|
||||
void* m_output; //!< Target output to write the read data to.
|
||||
u64 m_outputSize; //!< Size of memory m_output points to. This needs to be at least as big as m_size, but can be bigger.
|
||||
u64 m_offset; //!< The offset in bytes into the file.
|
||||
u64 m_size; //!< The number of bytes to read from the file.
|
||||
bool m_sharedRead; //!< True if other code will be reading from the file or the stack entry can exclusively lock.
|
||||
};
|
||||
|
||||
//! Request to read and decompress data.
|
||||
struct CompressedReadData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
|
||||
CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize);
|
||||
|
||||
CompressionInfo m_compressionInfo;
|
||||
void* m_output; //!< Target output to write the read data to.
|
||||
u64 m_readOffset; //!< The offset into the decompressed to start copying from.
|
||||
u64 m_readSize; //!< Number of bytes to read from the decompressed file.
|
||||
};
|
||||
|
||||
//! Holds the progress of an operation chain until this request is explicitly completed.
|
||||
struct WaitData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
inline constexpr static bool s_failWhenUnhandled = true;
|
||||
};
|
||||
|
||||
//! Checks to see if any node in the stack can find a file at the provided path.
|
||||
struct FileExistsCheckData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit FileExistsCheckData(const RequestPath& path);
|
||||
|
||||
const RequestPath& m_path;
|
||||
bool m_found{ false };
|
||||
};
|
||||
|
||||
//! Searches for a file in the stack and retrieves the meta data. This may be slower than a file exists
|
||||
//! check.
|
||||
struct FileMetaDataRetrievalData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit FileMetaDataRetrievalData(const RequestPath& path);
|
||||
|
||||
const RequestPath& m_path;
|
||||
u64 m_fileSize{ 0 };
|
||||
bool m_found{ false };
|
||||
};
|
||||
|
||||
//! Cancels a request in the stream stack, if possible.
|
||||
struct CancelData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHighest;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit CancelData(FileRequestPtr target);
|
||||
|
||||
FileRequestPtr m_target; //!< The request that will be canceled.
|
||||
};
|
||||
|
||||
//! Updates the priority and deadline of a request that has not been queued yet.
|
||||
struct RescheduleData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority);
|
||||
|
||||
FileRequestPtr m_target; //!< The request that will be rescheduled.
|
||||
AZStd::chrono::system_clock::time_point m_newDeadline; //!< The new deadline for the request.
|
||||
IStreamerTypes::Priority m_newPriority; //!< The new priority for the request.
|
||||
};
|
||||
|
||||
//! Flushes all references to the provided file in the streaming stack.
|
||||
struct FlushData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
explicit FlushData(RequestPath path);
|
||||
|
||||
RequestPath m_path;
|
||||
};
|
||||
|
||||
//! Flushes all caches in the streaming stack.
|
||||
struct FlushAllData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
};
|
||||
|
||||
//! Creates a cache dedicated to a single file. This is best used for files where blocks are read from
|
||||
//! periodically such as audio banks of video files.
|
||||
struct CreateDedicatedCacheData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
CreateDedicatedCacheData(RequestPath path, const FileRange& range);
|
||||
|
||||
RequestPath m_path;
|
||||
FileRange m_range;
|
||||
};
|
||||
|
||||
//! Destroys a cache dedicated to a single file that was previously created by CreateDedicatedCache
|
||||
struct DestroyDedicatedCacheData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
DestroyDedicatedCacheData(RequestPath path, const FileRange& range);
|
||||
|
||||
RequestPath m_path;
|
||||
FileRange m_range;
|
||||
};
|
||||
|
||||
struct ReportData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityLow;
|
||||
inline constexpr static bool s_failWhenUnhandled = false;
|
||||
|
||||
enum class ReportType
|
||||
{
|
||||
FileLocks
|
||||
};
|
||||
|
||||
explicit ReportData(ReportType reportType);
|
||||
|
||||
ReportType m_reportType;
|
||||
};
|
||||
|
||||
//! Data for a custom command. This can be used by nodes added extensions that need data that can't be stored
|
||||
//! in the already provided data.
|
||||
struct CustomData
|
||||
{
|
||||
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
|
||||
|
||||
CustomData(AZStd::any data, bool failWhenUnhandled);
|
||||
|
||||
AZStd::any m_data; //!< The data for the custom request.
|
||||
bool m_failWhenUnhandled; //!< Whether or not the request is marked as failed or success when no node process it.
|
||||
};
|
||||
|
||||
using CommandVariant = AZStd::variant<AZStd::monostate, ExternalRequestData, RequestPathStoreData, ReadRequestData, ReadData,
|
||||
CompressedReadData, WaitData, FileExistsCheckData, FileMetaDataRetrievalData, CancelData, RescheduleData, FlushData,
|
||||
FlushAllData, CreateDedicatedCacheData, DestroyDedicatedCacheData, ReportData, CustomData>;
|
||||
using CommandVariant = Requests::CommandVariant;
|
||||
using OnCompletionCallback = AZStd::function<void(FileRequest& request)>;
|
||||
|
||||
AZ_CLASS_ALLOCATOR(FileRequest, SystemAllocator, 0);
|
||||
@@ -278,7 +312,7 @@ namespace AZ::IO
|
||||
void CreateFlushAll();
|
||||
void CreateDedicatedCacheCreation(RequestPath path, const FileRange& range = {}, FileRequest* parent = nullptr);
|
||||
void CreateDedicatedCacheDestruction(RequestPath path, const FileRange& range = {}, FileRequest* parent = nullptr);
|
||||
void CreateReport(ReportData::ReportType reportType);
|
||||
void CreateReport(Requests::ReportType reportType);
|
||||
void CreateCustom(AZStd::any data, bool failWhenUnhandled = true, FileRequest* parent = nullptr);
|
||||
|
||||
void SetCompletionCallback(OnCompletionCallback callback);
|
||||
@@ -325,8 +359,17 @@ namespace AZ::IO
|
||||
//! Command and parameters for the request.
|
||||
CommandVariant m_command;
|
||||
|
||||
//! Status of the request.
|
||||
AZStd::atomic<IStreamerTypes::RequestStatus> m_status{ IStreamerTypes::RequestStatus::Pending };
|
||||
//! Estimated time this request will complete. This is an estimation and depends on many
|
||||
//! factors which can cause it to change drastically from moment to moment.
|
||||
AZStd::chrono::system_clock::time_point m_estimatedCompletion;
|
||||
|
||||
//! The file request that has a dependency on this one. This can be null if there are no
|
||||
//! other request depending on this one to complete.
|
||||
FileRequest* m_parent{ nullptr };
|
||||
|
||||
|
||||
//! Id assigned when the request is added to the pending queue.
|
||||
size_t m_pendingId{ 0 };
|
||||
|
||||
//! Called once the request has completed. This will always be called from the Streamer thread
|
||||
//! and thread safety is the responsibility of called function. When assigning a lambda avoid
|
||||
@@ -336,16 +379,8 @@ namespace AZ::IO
|
||||
//! a longer running task is needed consider using a job to do the work.
|
||||
OnCompletionCallback m_onCompletion;
|
||||
|
||||
//! Estimated time this request will complete. This is an estimation and depends on many
|
||||
//! factors which can cause it to change drastically from moment to moment.
|
||||
AZStd::chrono::system_clock::time_point m_estimatedCompletion;
|
||||
|
||||
//! The file request that has a dependency on this one. This can be null if there are no
|
||||
//! other request depending on this one to complete.
|
||||
FileRequest* m_parent{ nullptr };
|
||||
|
||||
//! Id assigned when the request is added to the pending queue.
|
||||
size_t m_pendingId{ 0 };
|
||||
//! Status of the request.
|
||||
AZStd::atomic<IStreamerTypes::RequestStatus> m_status{ IStreamerTypes::RequestStatus::Pending };
|
||||
|
||||
//! The number of dependent file request that need to complete before this one is done.
|
||||
u16 m_dependencies{ 0 };
|
||||
|
||||
@@ -91,12 +91,12 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadRequestData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadRequestData>)
|
||||
{
|
||||
PrepareReadRequest(request, args);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData> ||
|
||||
AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData> ||
|
||||
AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
|
||||
{
|
||||
PrepareDedicatedCache(request, args.m_path);
|
||||
}
|
||||
@@ -114,11 +114,11 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
m_pendingReads.push_back(request);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
|
||||
{
|
||||
m_pendingFileExistChecks.push_back(request);
|
||||
}
|
||||
@@ -203,7 +203,7 @@ namespace AZ::IO
|
||||
{
|
||||
FileRequest* compressedRequest = m_processingJobs[i].m_waitRequest->GetParent();
|
||||
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
AZ_Assert(data, "Compressed request in the decompression queue in FullFileDecompressor didn't contain compression read data.");
|
||||
|
||||
size_t bytesToDecompress = data->m_compressionInfo.m_compressedSize;
|
||||
@@ -255,7 +255,7 @@ namespace AZ::IO
|
||||
|
||||
// Calculate the amount of time it will take to decompress the data.
|
||||
FileRequest* compressedRequest = m_readRequests[i]->GetParent();
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
|
||||
size_t bytesToDecompress = data->m_compressionInfo.m_compressedSize;
|
||||
auto decompressionDuration = AZStd::chrono::microseconds(
|
||||
@@ -290,7 +290,7 @@ namespace AZ::IO
|
||||
void FullFileDecompressor::EstimateCompressedReadRequest(FileRequest* request, AZStd::chrono::microseconds& cumulativeDelay,
|
||||
AZStd::chrono::microseconds decompressionDelay, double totalDecompressionDurationUs, double totalBytesDecompressed) const
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&request->GetCommand());
|
||||
if (data)
|
||||
{
|
||||
AZStd::chrono::microseconds processingTime = decompressionDelay;
|
||||
@@ -343,7 +343,7 @@ namespace AZ::IO
|
||||
m_numRunningJobs == 0;
|
||||
}
|
||||
|
||||
void FullFileDecompressor::PrepareReadRequest(FileRequest* request, FileRequest::ReadRequestData& data)
|
||||
void FullFileDecompressor::PrepareReadRequest(FileRequest* request, Requests::ReadRequestData& data)
|
||||
{
|
||||
CompressionInfo info;
|
||||
if (CompressionUtils::FindCompressionInfo(info, data.m_path.GetRelativePath()))
|
||||
@@ -359,7 +359,7 @@ namespace AZ::IO
|
||||
{
|
||||
FileRequest* pathStorageRequest = m_context->GetNewInternalRequest();
|
||||
pathStorageRequest->CreateRequestPathStore(request, AZStd::move(info.m_archiveFilename));
|
||||
auto& pathStorage = AZStd::get<FileRequest::RequestPathStoreData>(pathStorageRequest->GetCommand());
|
||||
auto& pathStorage = AZStd::get<Requests::RequestPathStoreData>(pathStorageRequest->GetCommand());
|
||||
|
||||
nextRequest->CreateRead(pathStorageRequest, data.m_output, data.m_outputSize, pathStorage.m_path,
|
||||
info.m_offset + data.m_offset, data.m_size, info.m_isSharedPak);
|
||||
@@ -370,13 +370,13 @@ namespace AZ::IO
|
||||
auto callback = [this, nextRequest](const FileRequest& checkRequest)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
auto check = AZStd::get_if<FileRequest::FileExistsCheckData>(&checkRequest.GetCommand());
|
||||
auto check = AZStd::get_if<Requests::FileExistsCheckData>(&checkRequest.GetCommand());
|
||||
AZ_Assert(check,
|
||||
"Callback in FullFileDecompressor::PrepareReadRequest expected FileExistsCheck but got another command.");
|
||||
if (check->m_found)
|
||||
{
|
||||
FileRequest* originalRequest = m_context->RejectRequest(nextRequest);
|
||||
if (AZStd::holds_alternative<FileRequest::RequestPathStoreData>(originalRequest->GetCommand()))
|
||||
if (AZStd::holds_alternative<Requests::RequestPathStoreData>(originalRequest->GetCommand()))
|
||||
{
|
||||
originalRequest = m_context->RejectRequest(originalRequest);
|
||||
}
|
||||
@@ -412,12 +412,12 @@ namespace AZ::IO
|
||||
AZStd::visit([request, &info, nextRequest](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData>)
|
||||
{
|
||||
nextRequest->CreateDedicatedCacheCreation(AZStd::move(info.m_archiveFilename),
|
||||
FileRange::CreateRange(info.m_offset, info.m_compressedSize), request);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
|
||||
{
|
||||
nextRequest->CreateDedicatedCacheDestruction(AZStd::move(info.m_archiveFilename),
|
||||
FileRange::CreateRange(info.m_offset, info.m_compressedSize), request);
|
||||
@@ -429,7 +429,7 @@ namespace AZ::IO
|
||||
auto callback = [this, nextRequest](const FileRequest& checkRequest)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
auto check = AZStd::get_if<FileRequest::FileExistsCheckData>(&checkRequest.GetCommand());
|
||||
auto check = AZStd::get_if<Requests::FileExistsCheckData>(&checkRequest.GetCommand());
|
||||
AZ_Assert(check,
|
||||
"Callback in FullFileDecompressor::PrepareDedicatedCache expected FileExistsCheck but got another command.");
|
||||
if (check->m_found)
|
||||
@@ -461,7 +461,7 @@ namespace AZ::IO
|
||||
|
||||
void FullFileDecompressor::FileExistsCheck(FileRequest* checkRequest)
|
||||
{
|
||||
auto& fileCheckRequest = AZStd::get<FileRequest::FileExistsCheckData>(checkRequest->GetCommand());
|
||||
auto& fileCheckRequest = AZStd::get<Requests::FileExistsCheckData>(checkRequest->GetCommand());
|
||||
CompressionInfo info;
|
||||
if (CompressionUtils::FindCompressionInfo(info, fileCheckRequest.m_path.GetRelativePath()))
|
||||
{
|
||||
@@ -487,7 +487,7 @@ namespace AZ::IO
|
||||
{
|
||||
if (m_readBufferStatus[i] == ReadBufferStatus::Unused)
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedReadRequest->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedReadRequest->GetCommand());
|
||||
AZ_Assert(data, "Compressed request that's starting a read in FullFileDecompressor didn't contain compression read data.");
|
||||
AZ_Assert(data->m_compressionInfo.m_decompressor,
|
||||
"FileRequest for FullFileDecompressor is missing a decompression callback.");
|
||||
@@ -549,7 +549,7 @@ namespace AZ::IO
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
AZ_Assert(data, "Compressed request in FullFileDecompressor that finished unsuccessfully didn't contain compression read data.");
|
||||
CompressionInfo& info = data->m_compressionInfo;
|
||||
size_t offsetAdjustment = info.m_offset - AZ_SIZE_ALIGN_DOWN(info.m_offset, aznumeric_cast<size_t>(m_alignment));
|
||||
@@ -591,7 +591,7 @@ namespace AZ::IO
|
||||
}
|
||||
|
||||
FileRequest* waitRequest = m_readRequests[readSlot];
|
||||
AZ_Assert(AZStd::holds_alternative<FileRequest::WaitData>(waitRequest->GetCommand()),
|
||||
AZ_Assert(AZStd::holds_alternative<Requests::WaitData>(waitRequest->GetCommand()),
|
||||
"File request waiting for decompression wasn't marked as being a wait operation.");
|
||||
FileRequest* compressedRequest = waitRequest->GetParent();
|
||||
AZ_Assert(compressedRequest, "Read requests started by FullFileDecompressor is missing a parent request.");
|
||||
@@ -610,7 +610,7 @@ namespace AZ::IO
|
||||
m_readBuffers[readSlot] = nullptr;
|
||||
|
||||
AZ::Job* decompressionJob;
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
AZ_Assert(data, "Compressed request in FullFileDecompressor that's starting decompression didn't contain compression read data.");
|
||||
AZ_Assert(data->m_compressionInfo.m_decompressor, "FullFileDecompressor is queuing a decompression job but couldn't find a decompressor.");
|
||||
|
||||
@@ -664,7 +664,7 @@ namespace AZ::IO
|
||||
|
||||
FileRequest* compressedRequest = jobInfo.m_waitRequest->GetParent();
|
||||
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
|
||||
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
AZ_Assert(data, "Compressed request in FullFileDecompressor that completed decompression didn't contain compression read data.");
|
||||
CompressionInfo& info = data->m_compressionInfo;
|
||||
size_t offsetAdjustment = info.m_offset - AZ_SIZE_ALIGN_DOWN(info.m_offset, aznumeric_cast<size_t>(m_alignment));
|
||||
@@ -694,7 +694,7 @@ namespace AZ::IO
|
||||
|
||||
FileRequest* compressedRequest = info.m_waitRequest->GetParent();
|
||||
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
|
||||
auto request = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto request = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
AZ_Assert(request, "Compressed request in FullFileDecompressor that's running full decompression didn't contain compression read data.");
|
||||
CompressionInfo& compressionInfo = request->m_compressionInfo;
|
||||
AZ_Assert(compressionInfo.m_decompressor, "Full decompressor job started, but there's no decompressor callback assigned.");
|
||||
@@ -719,7 +719,7 @@ namespace AZ::IO
|
||||
|
||||
FileRequest* compressedRequest = info.m_waitRequest->GetParent();
|
||||
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
|
||||
auto request = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
auto request = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
|
||||
AZ_Assert(request, "Compressed request in FullFileDecompressor that's running partial decompression didn't contain compression read data.");
|
||||
CompressionInfo& compressionInfo = request->m_compressionInfo;
|
||||
AZ_Assert(compressionInfo.m_decompressor, "Partial decompressor job started, but there's no decompressor callback assigned.");
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
namespace Requests
|
||||
{
|
||||
struct ReadRequestData;
|
||||
}
|
||||
|
||||
struct FullFileDecompressorConfig final :
|
||||
public IStreamerStackConfig
|
||||
{
|
||||
@@ -87,7 +92,7 @@ namespace AZ::IO
|
||||
|
||||
bool IsIdle() const;
|
||||
|
||||
void PrepareReadRequest(FileRequest* request, FileRequest::ReadRequestData& data);
|
||||
void PrepareReadRequest(FileRequest* request, Requests::ReadRequestData& data);
|
||||
void PrepareDedicatedCache(FileRequest* request, const RequestPath& path);
|
||||
void FileExistsCheck(FileRequest* checkRequest);
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace AZ::IO
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
|
||||
if (data == nullptr)
|
||||
{
|
||||
StreamStackEntry::QueueRequest(request);
|
||||
@@ -156,7 +156,7 @@ namespace AZ::IO
|
||||
|
||||
void ReadSplitter::QueueAlignedRead(FileRequest* request)
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
|
||||
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
|
||||
|
||||
if (data->m_size <= m_maxReadSize)
|
||||
@@ -187,7 +187,7 @@ namespace AZ::IO
|
||||
|
||||
bool ReadSplitter::QueueAlignedRead(PendingRead& pending)
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&pending.m_request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&pending.m_request->GetCommand());
|
||||
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
|
||||
|
||||
while (pending.m_readSize > 0)
|
||||
@@ -237,7 +237,7 @@ namespace AZ::IO
|
||||
|
||||
void ReadSplitter::QueueBufferedRead(FileRequest* request)
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
|
||||
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
|
||||
|
||||
PendingRead pendingRead;
|
||||
@@ -262,7 +262,7 @@ namespace AZ::IO
|
||||
|
||||
bool ReadSplitter::QueueBufferedRead(PendingRead& pending)
|
||||
{
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&pending.m_request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&pending.m_request->GetCommand());
|
||||
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
|
||||
|
||||
while (pending.m_readSize > 0)
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/Streamer/Scheduler.h>
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/IO/Streamer/Scheduler.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
|
||||
@@ -35,6 +37,8 @@ namespace AZ::IO
|
||||
m_threadData.m_streamStack = AZStd::move(streamStack);
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler() = default;
|
||||
|
||||
void Scheduler::Start(const AZStd::thread_desc& threadDesc)
|
||||
{
|
||||
if (!m_isRunning)
|
||||
@@ -222,10 +226,10 @@ namespace AZ::IO
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (
|
||||
AZStd::is_same_v<Command, FileRequest::ReadData> ||
|
||||
AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
AZStd::is_same_v<Command, Requests::ReadData> ||
|
||||
AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
auto parentReadRequest = next->GetCommandFromChain<FileRequest::ReadRequestData>();
|
||||
auto parentReadRequest = next->GetCommandFromChain<Requests::ReadRequestData>();
|
||||
AZ_Assert(parentReadRequest != nullptr, "The issued read request can't be found for the (compressed) read command.");
|
||||
|
||||
size_t size = parentReadRequest->m_size;
|
||||
@@ -234,7 +238,7 @@ namespace AZ::IO
|
||||
AZ_Assert(parentReadRequest->m_allocator,
|
||||
"The read request was issued without a memory allocator or valid output address.");
|
||||
u64 recommendedSize = size;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
recommendedSize = m_recommendations.CalculateRecommendedMemorySize(size, parentReadRequest->m_offset);
|
||||
}
|
||||
@@ -249,12 +253,12 @@ namespace AZ::IO
|
||||
parentReadRequest->m_output = allocation.m_address;
|
||||
parentReadRequest->m_outputSize = allocation.m_size;
|
||||
parentReadRequest->m_memoryType = allocation.m_type;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
args.m_output = parentReadRequest->m_output;
|
||||
args.m_outputSize = allocation.m_size;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
args.m_output = parentReadRequest->m_output;
|
||||
}
|
||||
@@ -267,7 +271,7 @@ namespace AZ::IO
|
||||
}
|
||||
#endif
|
||||
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
m_threadData.m_lastFilePath = args.m_path;
|
||||
m_threadData.m_lastFileOffset = args.m_offset + args.m_size;
|
||||
@@ -275,7 +279,7 @@ namespace AZ::IO
|
||||
m_processingSize += args.m_size;
|
||||
#endif
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
const CompressionInfo& info = args.m_compressionInfo;
|
||||
m_threadData.m_lastFilePath = info.m_archiveFilename;
|
||||
@@ -288,15 +292,15 @@ namespace AZ::IO
|
||||
"Streamer queued %zu: %s", next->GetCommand().index(), parentReadRequest->m_path.GetRelativePath());
|
||||
m_threadData.m_streamStack->QueueRequest(next);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CancelData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CancelData>)
|
||||
{
|
||||
return Thread_ProcessCancelRequest(next, args);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::RescheduleData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::RescheduleData>)
|
||||
{
|
||||
return Thread_ProcessRescheduleRequest(next, args);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData> || AZStd::is_same_v<Command, FileRequest::FlushAllData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FlushData> || AZStd::is_same_v<Command, Requests::FlushAllData>)
|
||||
{
|
||||
AZ_PROFILE_INTERVAL_START_COLORED(AzCore, next, ProfilerColor,
|
||||
"Streamer queued %zu", next->GetCommand().index());
|
||||
@@ -345,7 +349,7 @@ namespace AZ::IO
|
||||
#endif
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadRequestData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadRequestData>)
|
||||
{
|
||||
if (args.m_output == nullptr && args.m_allocator != nullptr)
|
||||
{
|
||||
@@ -393,7 +397,7 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::Thread_ProcessCancelRequest(FileRequest* request, FileRequest::CancelData& data)
|
||||
void Scheduler::Thread_ProcessCancelRequest(FileRequest* request, Requests::CancelData& data)
|
||||
{
|
||||
AZ_PROFILE_INTERVAL_START_COLORED(AzCore, request, ProfilerColor, "Streamer queued cancel");
|
||||
auto& pending = m_context.GetPreparedRequests();
|
||||
@@ -415,7 +419,7 @@ namespace AZ::IO
|
||||
m_threadData.m_streamStack->QueueRequest(request);
|
||||
}
|
||||
|
||||
void Scheduler::Thread_ProcessRescheduleRequest(FileRequest* request, FileRequest::RescheduleData& data)
|
||||
void Scheduler::Thread_ProcessRescheduleRequest(FileRequest* request, Requests::RescheduleData& data)
|
||||
{
|
||||
AZ_PROFILE_INTERVAL_START_COLORED(AzCore, request, ProfilerColor, "Streamer queued reschedule");
|
||||
auto& pendingRequests = m_context.GetPreparedRequests();
|
||||
@@ -424,7 +428,7 @@ namespace AZ::IO
|
||||
if (pending->WorksOn(data.m_target))
|
||||
{
|
||||
// Read requests are the only requests that use deadlines and dynamic priorities.
|
||||
auto readRequest = pending->GetCommandFromChain<FileRequest::ReadRequestData>();
|
||||
auto readRequest = pending->GetCommandFromChain<Requests::ReadRequestData>();
|
||||
if (readRequest)
|
||||
{
|
||||
readRequest->m_deadline = data.m_newDeadline;
|
||||
@@ -463,8 +467,8 @@ namespace AZ::IO
|
||||
|
||||
// Order is the same for both requests, so prioritize the request that are at risk of missing
|
||||
// it's deadline.
|
||||
const FileRequest::ReadRequestData* firstRead = first->GetCommandFromChain<FileRequest::ReadRequestData>();
|
||||
const FileRequest::ReadRequestData* secondRead = second->GetCommandFromChain<FileRequest::ReadRequestData>();
|
||||
const Requests::ReadRequestData* firstRead = first->GetCommandFromChain<Requests::ReadRequestData>();
|
||||
const Requests::ReadRequestData* secondRead = second->GetCommandFromChain<Requests::ReadRequestData>();
|
||||
|
||||
if (firstRead == nullptr || secondRead == nullptr)
|
||||
{
|
||||
@@ -496,11 +500,11 @@ namespace AZ::IO
|
||||
auto sameFile = [this](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
return m_threadData.m_lastFilePath == args.m_path;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
return m_threadData.m_lastFilePath == args.m_compressionInfo.m_archiveFilename;
|
||||
}
|
||||
@@ -517,11 +521,11 @@ namespace AZ::IO
|
||||
auto offset = [](auto&& args) -> s64
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
return aznumeric_caster(args.m_offset);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
return aznumeric_caster(args.m_compressionInfo.m_offset);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Streamer/RequestPath.h>
|
||||
#include <AzCore/IO/IStreamerTypes.h>
|
||||
#include <AzCore/IO/Streamer/Statistics.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
@@ -24,11 +25,19 @@ namespace AZ::IO
|
||||
{
|
||||
class FileRequest;
|
||||
|
||||
namespace Requests
|
||||
{
|
||||
struct CancelData;
|
||||
struct RescheduleData;
|
||||
} // namespace Requests
|
||||
|
||||
class Scheduler final
|
||||
{
|
||||
public:
|
||||
explicit Scheduler(AZStd::shared_ptr<StreamStackEntry> streamStack, u64 memoryAlignment = AZCORE_GLOBAL_NEW_ALIGNMENT,
|
||||
u64 sizeAlignment = 1, u64 granularity = 1_mib);
|
||||
~Scheduler();
|
||||
|
||||
void Start(const AZStd::thread_desc& threadDesc);
|
||||
void Stop();
|
||||
|
||||
@@ -61,14 +70,14 @@ namespace AZ::IO
|
||||
bool Thread_ExecuteRequests();
|
||||
bool Thread_PrepareRequests(AZStd::vector<FileRequestPtr>& outstandingRequests);
|
||||
void Thread_ProcessTillIdle();
|
||||
void Thread_ProcessCancelRequest(FileRequest* request, FileRequest::CancelData& data);
|
||||
void Thread_ProcessRescheduleRequest(FileRequest* request, FileRequest::RescheduleData& data);
|
||||
void Thread_ProcessCancelRequest(FileRequest* request, Requests::CancelData& data);
|
||||
void Thread_ProcessRescheduleRequest(FileRequest* request, Requests::RescheduleData& data);
|
||||
|
||||
enum class Order
|
||||
{
|
||||
FirstRequest, //< The first request is the most important to process next.
|
||||
SecondRequest, //< The second request is the most important to process next.
|
||||
Equal //< Both requests are equally important.
|
||||
FirstRequest, //!< The first request is the most important to process next.
|
||||
SecondRequest, //!< The second request is the most important to process next.
|
||||
Equal //!< Both requests are equally important.
|
||||
};
|
||||
//! Determine which of the two provided requests is more important to process next.
|
||||
Order Thread_PrioritizeRequests(const FileRequest* first, const FileRequest* second) const;
|
||||
|
||||
@@ -60,13 +60,13 @@ namespace AZ::IO
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
AZ_Assert(request, "PrepareRequest was provided a null request.");
|
||||
|
||||
if (AZStd::holds_alternative<FileRequest::ReadRequestData>(request->GetCommand()))
|
||||
if (AZStd::holds_alternative<Requests::ReadRequestData>(request->GetCommand()))
|
||||
{
|
||||
auto& readRequest = AZStd::get<FileRequest::ReadRequestData>(request->GetCommand());
|
||||
auto& readRequest = AZStd::get<Requests::ReadRequestData>(request->GetCommand());
|
||||
|
||||
FileRequest* read = m_context->GetNewInternalRequest();
|
||||
read->CreateRead(request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path,
|
||||
readRequest.m_offset, readRequest.m_size);
|
||||
read->CreateRead(
|
||||
request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path, readRequest.m_offset, readRequest.m_size);
|
||||
m_context->PushPreparedRequest(read);
|
||||
return;
|
||||
}
|
||||
@@ -79,29 +79,29 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData> ||
|
||||
AZStd::is_same_v<Command, FileRequest::FileExistsCheckData> ||
|
||||
AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData> ||
|
||||
AZStd::is_same_v<Command, Requests::FileExistsCheckData> ||
|
||||
AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
|
||||
{
|
||||
m_pendingRequests.push_back(request);
|
||||
return;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CancelData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CancelData>)
|
||||
{
|
||||
CancelRequest(request, args.m_target);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
|
||||
{
|
||||
FlushCache(args.m_path);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
|
||||
{
|
||||
FlushEntireCache();
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::ReportData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::ReportData>)
|
||||
{
|
||||
Report(args);
|
||||
}
|
||||
@@ -118,15 +118,15 @@ namespace AZ::IO
|
||||
AZStd::visit([this, request](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
ReadFile(request);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
|
||||
{
|
||||
FileExistsRequest(request);
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
|
||||
{
|
||||
FileMetaDataRetrievalRequest(request);
|
||||
}
|
||||
@@ -199,25 +199,25 @@ namespace AZ::IO
|
||||
AZStd::visit([&](auto&& args)
|
||||
{
|
||||
using Command = AZStd::decay_t<decltype(args)>;
|
||||
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
|
||||
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
|
||||
{
|
||||
targetFile = &args.m_path;
|
||||
readSize = args.m_size;
|
||||
offset = args.m_offset;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
|
||||
{
|
||||
targetFile = &args.m_compressionInfo.m_archiveFilename;
|
||||
readSize = args.m_compressionInfo.m_compressedSize;
|
||||
offset = args.m_compressionInfo.m_offset;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
|
||||
{
|
||||
readSize = 0;
|
||||
AZStd::chrono::microseconds averageTime = m_getFileExistsTimeAverage.CalculateAverage();
|
||||
startTime += averageTime;
|
||||
}
|
||||
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
|
||||
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
|
||||
{
|
||||
readSize = 0;
|
||||
AZStd::chrono::microseconds averageTime = m_getFileMetaDataTimeAverage.CalculateAverage();
|
||||
@@ -254,7 +254,7 @@ namespace AZ::IO
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
|
||||
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
|
||||
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
|
||||
AZ_Assert(data, "FileRequest queued on StorageDrive to be read didn't contain read data.");
|
||||
|
||||
SystemFile* file = nullptr;
|
||||
@@ -342,7 +342,7 @@ namespace AZ::IO
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
TIMED_AVERAGE_WINDOW_SCOPE(m_getFileExistsTimeAverage);
|
||||
|
||||
auto& fileExists = AZStd::get<FileRequest::FileExistsCheckData>(request->GetCommand());
|
||||
auto& fileExists = AZStd::get<Requests::FileExistsCheckData>(request->GetCommand());
|
||||
size_t cacheIndex = FindFileInCache(fileExists.m_path);
|
||||
if (cacheIndex != s_fileNotFound)
|
||||
{
|
||||
@@ -360,7 +360,7 @@ namespace AZ::IO
|
||||
AZ_PROFILE_FUNCTION(AzCore);
|
||||
TIMED_AVERAGE_WINDOW_SCOPE(m_getFileMetaDataTimeAverage);
|
||||
|
||||
auto& command = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request->GetCommand());
|
||||
auto& command = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
|
||||
// If the file is already open, use the file handle which usually is cheaper than asking for the file by name.
|
||||
size_t cacheIndex = FindFileInCache(command.m_path);
|
||||
if (cacheIndex != s_fileNotFound)
|
||||
@@ -446,11 +446,11 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
void StorageDrive::Report(const FileRequest::ReportData& data) const
|
||||
void StorageDrive::Report(const Requests::ReportData& data) const
|
||||
{
|
||||
switch (data.m_reportType)
|
||||
{
|
||||
case FileRequest::ReportData::ReportType::FileLocks:
|
||||
case Requests::ReportType::FileLocks:
|
||||
for (u32 i = 0; i < m_fileHandles.size(); ++i)
|
||||
{
|
||||
if (m_fileHandles[i] != nullptr)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Streamer/RequestPath.h>
|
||||
#include <AzCore/IO/Streamer/Statistics.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
#include <AzCore/IO/Streamer/StreamStackEntry.h>
|
||||
@@ -16,6 +17,11 @@
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/chrono/clocks.h>
|
||||
|
||||
namespace AZ::IO::Requests
|
||||
{
|
||||
struct ReportData;
|
||||
}
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
struct StorageDriveConfig final :
|
||||
@@ -72,7 +78,7 @@ namespace AZ::IO
|
||||
void EstimateCompletionTimeForRequest(FileRequest* request, AZStd::chrono::system_clock::time_point& startTime,
|
||||
const RequestPath*& activeFile, u64& activeOffset) const;
|
||||
|
||||
void Report(const FileRequest::ReportData& data) const;
|
||||
void Report(const Requests::ReportData& data) const;
|
||||
|
||||
TimedAverageWindow<s_statisticsWindowSize> m_fileOpenCloseTimeAverage;
|
||||
TimedAverageWindow<s_statisticsWindowSize> m_getFileExistsTimeAverage;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/IO/CompressionBus.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/IO/Streamer/Streamer.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
#include <AzCore/IO/Streamer/StreamStackEntry.h>
|
||||
@@ -210,7 +211,7 @@ namespace AZ::IO
|
||||
IStreamerTypes::ClaimMemory claimMemory) const
|
||||
{
|
||||
AZ_Assert(request.m_request, "The request handle provided to Streamer::GetReadRequestResult is invalid.");
|
||||
auto readRequest = AZStd::get_if<FileRequest::ReadRequestData>(&request.m_request->GetCommand());
|
||||
auto readRequest = AZStd::get_if<Requests::ReadRequestData>(&request.m_request->GetCommand());
|
||||
if (readRequest != nullptr)
|
||||
{
|
||||
buffer = readRequest->m_output;
|
||||
@@ -281,14 +282,14 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
FileRequestPtr Streamer::Report(FileRequest::ReportData::ReportType reportType)
|
||||
FileRequestPtr Streamer::Report(Requests::ReportType reportType)
|
||||
{
|
||||
FileRequestPtr result = CreateRequest();
|
||||
Report(result, reportType);
|
||||
return result;
|
||||
}
|
||||
|
||||
FileRequestPtr& Streamer::Report(FileRequestPtr& request, FileRequest::ReportData::ReportType reportType)
|
||||
FileRequestPtr& Streamer::Report(FileRequestPtr& request, Requests::ReportType reportType)
|
||||
{
|
||||
request->m_request.CreateReport(reportType);
|
||||
return request;
|
||||
|
||||
@@ -20,6 +20,10 @@ namespace AZStd
|
||||
struct thread_desc;
|
||||
}
|
||||
|
||||
namespace AZ::IO::Requests
|
||||
{
|
||||
enum class ReportType : int8_t;
|
||||
}
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
@@ -185,9 +189,9 @@ namespace AZ::IO
|
||||
void RecordStatistics();
|
||||
|
||||
//! Tells AZ::IO::Streamer the report the information for the report to the output.
|
||||
FileRequestPtr Report(FileRequest::ReportData::ReportType reportType);
|
||||
FileRequestPtr Report(Requests::ReportType reportType);
|
||||
//! Tells AZ::IO::Streamer the report the information for the report to the output.
|
||||
FileRequestPtr& Report(FileRequestPtr& request, FileRequest::ReportData::ReportType reportType);
|
||||
FileRequestPtr& Report(FileRequestPtr& request, Requests::ReportType reportType);
|
||||
|
||||
|
||||
Streamer(const AZStd::thread_desc& threadDesc, AZStd::unique_ptr<Scheduler> streamStack);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/IO/Streamer/BlockCache.h>
|
||||
#include <AzCore/IO/Streamer/DedicatedCache.h>
|
||||
#include <AzCore/IO/Streamer/FullFileDecompressor.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/IO/Streamer/Scheduler.h>
|
||||
#include <AzCore/IO/Streamer/StreamerComponent.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
@@ -207,7 +208,7 @@ namespace AZ
|
||||
{
|
||||
if (m_streamer)
|
||||
{
|
||||
m_streamer->QueueRequest(m_streamer->Report(AZ::IO::FileRequest::ReportData::ReportType::FileLocks));
|
||||
m_streamer->QueueRequest(m_streamer->Report(AZ::IO::Requests::ReportType::FileLocks));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace AZ
|
||||
static constexpr char LatePredictionName[] = "Early completions";
|
||||
static constexpr char MissedDeadlinesName[] = "Missed deadlines";
|
||||
#endif // AZ_STREAMER_ADD_EXTRA_PROFILING_INFO
|
||||
|
||||
StreamerContext::StreamerContext() = default;
|
||||
|
||||
StreamerContext::~StreamerContext()
|
||||
{
|
||||
for (FileRequest* entry : m_internalRecycleBin)
|
||||
@@ -204,7 +207,7 @@ namespace AZ
|
||||
m_latePredictionsPercentageStat.GetMostRecentSample());
|
||||
}
|
||||
}
|
||||
auto readRequest = AZStd::get_if<FileRequest::ReadRequestData>(&top->GetCommand());
|
||||
auto readRequest = AZStd::get_if<Requests::ReadRequestData>(&top->GetCommand());
|
||||
if (readRequest != nullptr)
|
||||
{
|
||||
m_missedDeadlinePercentageStat.PushSample(now < readRequest->m_deadline ? 0.0 : 1.0);
|
||||
@@ -224,7 +227,7 @@ namespace AZ
|
||||
top->m_onCompletion(*top);
|
||||
AZ_PROFILE_INTERVAL_END(AzCore, top);
|
||||
}
|
||||
|
||||
|
||||
if (parent)
|
||||
{
|
||||
AZ_Assert(parent->m_dependencies > 0,
|
||||
|
||||
@@ -8,22 +8,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/IO/Streamer/FileRequest.h>
|
||||
#include <AzCore/IO/Streamer/Statistics.h>
|
||||
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
|
||||
#include <AzCore/IO/Streamer/StreamerContext_Platform.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/Statistics/RunningStatistic.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
class FileRequest;
|
||||
class ExternalFileRequest;
|
||||
|
||||
using FileRequestPtr = AZStd::intrusive_ptr<ExternalFileRequest>;
|
||||
|
||||
class StreamerContext
|
||||
{
|
||||
public:
|
||||
using PreparedQueue = AZStd::deque<FileRequest*>;
|
||||
|
||||
StreamerContext();
|
||||
~StreamerContext();
|
||||
|
||||
//! Gets a new file request, either by creating a new instance or
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace AZ
|
||||
|
||||
void Matrix3x4SetRowGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
bool rowIsSet = false;
|
||||
[[maybe_unused]] bool rowIsSet = false;
|
||||
if (dc.GetNumArguments() >= 5)
|
||||
{
|
||||
if (dc.IsNumber(0))
|
||||
@@ -88,7 +88,7 @@ namespace AZ
|
||||
|
||||
void Matrix3x4SetColumnGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
bool columnIsSet = false;
|
||||
[[maybe_unused]] bool columnIsSet = false;
|
||||
if (dc.GetNumArguments() >= 4)
|
||||
{
|
||||
if (dc.IsNumber(0))
|
||||
@@ -133,7 +133,7 @@ namespace AZ
|
||||
|
||||
void Matrix3x4SetTranslationGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
bool translationIsSet = false;
|
||||
[[maybe_unused]] bool translationIsSet = false;
|
||||
|
||||
if (dc.GetNumArguments() == 3 &&
|
||||
dc.IsNumber(0) &&
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace AZ
|
||||
|
||||
// check open brace
|
||||
char c = *current++;
|
||||
bool has_open_brace = false;
|
||||
[[maybe_unused]] bool has_open_brace = false;
|
||||
if (c == '{')
|
||||
{
|
||||
c = *current++;
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace AZ
|
||||
|
||||
NameDictionary::~NameDictionary()
|
||||
{
|
||||
bool leaksDetected = false;
|
||||
[[maybe_unused]] bool leaksDetected = false;
|
||||
|
||||
for (const auto& keyValue : m_dictionary)
|
||||
{
|
||||
|
||||
@@ -248,14 +248,14 @@
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__builtin_is_constant_evaluated)
|
||||
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
|
||||
#define az_has_builtin_is_constant_evaluated() true
|
||||
#define az_has_builtin_is_constant_evaluated true
|
||||
#endif
|
||||
#elif AZ_COMPILER_MSVC >= 1928
|
||||
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
|
||||
#define az_has_builtin_is_constant_evaluated() true
|
||||
#define az_has_builtin_is_constant_evaluated true
|
||||
#elif AZ_COMPILER_GCC
|
||||
#define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated()
|
||||
#define az_has_builtin_is_constant_evaluated() true
|
||||
#define az_has_builtin_is_constant_evaluated true
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
}
|
||||
}
|
||||
#define az_builtin_is_constant_evaluated() AZ::Internal::builtin_is_constant_evaluated()
|
||||
#define az_has_builtin_is_constant_evaluated() false
|
||||
#define az_has_builtin_is_constant_evaluated false
|
||||
#endif
|
||||
|
||||
// define builtin functions used by char_traits class for efficient compile time and runtime
|
||||
|
||||
@@ -1668,9 +1668,23 @@ namespace AZ
|
||||
SerializeContext::ENUM_ACCESS_FOR_READ,
|
||||
&m_errorLogger
|
||||
);
|
||||
if (objectStreamWriteOverrideCB.Invoke<void>(callContext, objectPtr, *classData, classElement))
|
||||
if (ObjectStreamWriteOverrideResponse writeResponse;
|
||||
objectStreamWriteOverrideCB.Read<ObjectStreamWriteOverrideResponse>(writeResponse, callContext, objectPtr, *classData, classElement))
|
||||
{
|
||||
return false;
|
||||
switch (writeResponse)
|
||||
{
|
||||
case ObjectStreamWriteOverrideResponse::FallbackToDefaultWrite:
|
||||
break;
|
||||
case ObjectStreamWriteOverrideResponse::AbortWrite:
|
||||
m_errorLogger.ReportError(AZStd::string::format("ObjectStream Write Element Override callback has aborted the write for class data %s",
|
||||
classData->m_name).c_str());
|
||||
[[fallthrough]];
|
||||
case ObjectStreamWriteOverrideResponse::CompletedWrite:
|
||||
return false;
|
||||
default:
|
||||
AZ_Error("Serialize", false, "Invalid Response %d returned from the ObjectStream Write Element Override callback", static_cast<int>(writeResponse));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -49,14 +49,24 @@ namespace AZ
|
||||
static const AZ::Crc32 ObjectStreamWriteElementOverride = AZ_CRC("ObjectStreamWriteElementOverride", 0x35eb659f);
|
||||
}
|
||||
|
||||
enum class ObjectStreamWriteOverrideResponse
|
||||
{
|
||||
CompletedWrite,
|
||||
FallbackToDefaultWrite,
|
||||
AbortWrite
|
||||
};
|
||||
AZ_TYPE_INFO_SPECIALIZE(ObjectStreamWriteOverrideResponse, "{BDF960A8-0F18-4E9D-96DA-F800A122C42D}");
|
||||
|
||||
///< Callback that the object stream invokes to override saving an instance of the registered class
|
||||
///< @param callContext EnumerateInstanceCallContext which contains the WriteElement BeingElemCB and the CloseElement EndElemCB
|
||||
///< the callContext parameter can be passed to the SerializeContext::EnumerateInstance to continue object stream writing
|
||||
///< @param classPtr class type which is of pointer to the type represented by the m_typeId value
|
||||
///< @param classData reference to this instance Class Data that will be supplied to the callback
|
||||
///< @param classElement class element pointer which contains information about the element being serialized.
|
||||
///< root elements do not not have a valid class element pointer
|
||||
using ObjectStreamWriteOverrideCB = AZStd::function<void(SerializeContext::EnumerateInstanceCallContext& callContext,
|
||||
///< root elements have a nullptr classElement
|
||||
///< @return enum to indicate that the override has saved the registered class and that the default writing should be skipped.
|
||||
///< Returning false will have the WriteElement code fallback to using the default logic
|
||||
using ObjectStreamWriteOverrideCB = AZStd::function<ObjectStreamWriteOverrideResponse(SerializeContext::EnumerateInstanceCallContext& callContext,
|
||||
const void* classPtr, const SerializeContext::ClassData& classData, const SerializeContext::ClassElement* classElement)>;
|
||||
|
||||
AZ_TYPE_INFO_SPECIALIZE(ObjectStreamWriteOverrideCB, "{87B1A36B-8C8A-42B6-A0B5-E770D9FDBAD4}");
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
enum class ObjectStreamWriteOverrideResponse;
|
||||
|
||||
namespace VariantSerializationInternal
|
||||
{
|
||||
template <class ValueType>
|
||||
@@ -480,7 +482,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
private:
|
||||
static void ObjectStreamWriter(SerializeContext::EnumerateInstanceCallContext& callContext, const void* variantPtr,
|
||||
static ObjectStreamWriteOverrideResponse ObjectStreamWriter(SerializeContext::EnumerateInstanceCallContext& callContext, const void* variantPtr,
|
||||
[[maybe_unused]] const SerializeContext::ClassData& variantClassData, const SerializeContext::ClassElement* variantClassElement)
|
||||
{
|
||||
auto alternativeVisitor = [&callContext, variantClassElement](auto&& elementAlt)
|
||||
@@ -503,6 +505,9 @@ namespace AZ
|
||||
};
|
||||
|
||||
AZStd::visit(AZStd::move(alternativeVisitor), *reinterpret_cast<const VariantType*>(variantPtr));
|
||||
// To avoid including ObjectStream.h into this file, we static cast the value of 0
|
||||
// to an AZ::ObjectStreamWriteElemntResponse which corresponds to the CompletedWrite enum value
|
||||
return static_cast<AZ::ObjectStreamWriteOverrideResponse>(0);
|
||||
}
|
||||
|
||||
VariantSerializationInternal::AZStdVariantContainer<Types...> m_variantContainer;
|
||||
|
||||
@@ -116,6 +116,8 @@ set(FILES
|
||||
Debug/TraceReflection.h
|
||||
DOM/DomBackend.cpp
|
||||
DOM/DomBackend.h
|
||||
DOM/DomPath.cpp
|
||||
DOM/DomPath.h
|
||||
DOM/DomUtils.cpp
|
||||
DOM/DomUtils.h
|
||||
DOM/DomValue.cpp
|
||||
|
||||
@@ -19,6 +19,7 @@ set(FILES
|
||||
any.h
|
||||
base.h
|
||||
config.h
|
||||
concepts/concepts.h
|
||||
createdestroy.h
|
||||
docs.h
|
||||
exceptions.h
|
||||
@@ -27,11 +28,14 @@ set(FILES
|
||||
hash.cpp
|
||||
hash.h
|
||||
hash_table.h
|
||||
iterator/iterator_primitives.h
|
||||
iterator.h
|
||||
limits.h
|
||||
numeric.h
|
||||
math.h
|
||||
optional.h
|
||||
ranges/iter_move.h
|
||||
ranges/ranges.h
|
||||
ratio.h
|
||||
reference_wrapper.h
|
||||
sort.h
|
||||
@@ -151,6 +155,7 @@ set(FILES
|
||||
typetraits/alignment_of.h
|
||||
typetraits/config.h
|
||||
typetraits/common_type.h
|
||||
typetraits/common_reference.h
|
||||
typetraits/conjunction.h
|
||||
typetraits/disjunction.h
|
||||
typetraits/extent.h
|
||||
@@ -217,4 +222,6 @@ set(FILES
|
||||
typetraits/void_t.h
|
||||
typetraits/internal/type_sequence_traits.h
|
||||
typetraits/internal/is_template_copy_constructible.h
|
||||
utility/declval.h
|
||||
utility/move.h
|
||||
)
|
||||
|
||||
@@ -30,4 +30,6 @@ namespace AZStd
|
||||
using std::nullptr_t;
|
||||
|
||||
using sys_time_t = AZ::s64;
|
||||
|
||||
using std::byte;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,840 @@
|
||||
/*
|
||||
* 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/invoke.h>
|
||||
#include <AzCore/std/iterator/iterator_primitives.h>
|
||||
#include <AzCore/std/ranges/iter_move.h>
|
||||
|
||||
#include <AzCore/std/typetraits/add_pointer.h>
|
||||
#include <AzCore/std/typetraits/common_reference.h>
|
||||
#include <AzCore/std/typetraits/extent.h>
|
||||
#include <AzCore/std/typetraits/is_array.h>
|
||||
#include <AzCore/std/typetraits/is_assignable.h>
|
||||
#include <AzCore/std/typetraits/is_class.h>
|
||||
#include <AzCore/std/typetraits/is_constructible.h>
|
||||
#include <AzCore/std/typetraits/is_destructible.h>
|
||||
#include <AzCore/std/typetraits/is_enum.h>
|
||||
#include <AzCore/std/typetraits/is_floating_point.h>
|
||||
#include <AzCore/std/typetraits/is_function.h>
|
||||
#include <AzCore/std/typetraits/is_integral.h>
|
||||
#include <AzCore/std/typetraits/is_object.h>
|
||||
#include <AzCore/std/typetraits/is_same.h>
|
||||
#include <AzCore/std/typetraits/is_signed.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>
|
||||
#include <AzCore/std/utility/move.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// alias std::pointer_traits into the AZStd::namespace
|
||||
using std::pointer_traits;
|
||||
|
||||
// Alias re-declarations from iterator.h
|
||||
/// Identifying tag for input iterators.
|
||||
using input_iterator_tag = std::input_iterator_tag;
|
||||
/// Identifying tag for output iterators.
|
||||
using output_iterator_tag = std::output_iterator_tag;
|
||||
/// Identifying tag for forward iterators.
|
||||
using forward_iterator_tag = std::forward_iterator_tag;
|
||||
/// Identifying tag for bidirectional iterators.
|
||||
using bidirectional_iterator_tag = std::bidirectional_iterator_tag;
|
||||
/// Identifying tag for random-access iterators.
|
||||
using random_access_iterator_tag = std::random_access_iterator_tag;
|
||||
/// Identifying tag for contagious iterators
|
||||
struct contiguous_iterator_tag;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <typename T, typename = void>
|
||||
constexpr bool pointer_traits_has_to_address_v = false;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool pointer_traits_has_to_address_v<T, enable_if_t<
|
||||
is_void_v<void_t<decltype(pointer_traits<T>::to_address(declval<const T&>()))>>> > = true;
|
||||
|
||||
|
||||
// pointer_traits isn't SFINAE friendly https://cplusplus.github.io/LWG/lwg-active.html#3545
|
||||
// So working around that by checking if type T has an element_type alias
|
||||
template <typename T, typename = void>
|
||||
constexpr bool pointer_traits_valid_and_has_to_address_v = false;
|
||||
template <typename T>
|
||||
constexpr bool pointer_traits_valid_and_has_to_address_v<T, enable_if_t<has_element_type_v<T>> >
|
||||
= pointer_traits_has_to_address_v<T>;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
//! Implements the C++20 to_address function
|
||||
//! This obtains the address represented by ptr without forming a reference
|
||||
//! to the pointee type
|
||||
template <typename T>
|
||||
constexpr T* to_address(T* ptr) noexcept
|
||||
{
|
||||
static_assert(!AZStd::is_function_v<T>, "Invoking to address on a function pointer is not allowed");
|
||||
return ptr;
|
||||
}
|
||||
//! Fancy pointer overload which delegates to using a specialization of pointer_traits<T>::to_address
|
||||
//! if that is a well-formed expression, otherwise it returns ptr->operator->()
|
||||
//! For example invoking `to_address(AZStd::reverse_iterator<const char*>(char_ptr))`
|
||||
//! Returns an element of type const char*
|
||||
template <typename T>
|
||||
constexpr auto to_address(const T& ptr) noexcept
|
||||
{
|
||||
if constexpr (AZStd::Internal::pointer_traits_valid_and_has_to_address_v<T>)
|
||||
{
|
||||
return pointer_traits<T>::to_address(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return to_address(ptr.operator->());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// Variadic template which maps types to true For SFINAE
|
||||
template <class... Args>
|
||||
constexpr bool sfinae_trigger_v = true;
|
||||
|
||||
template <class It, class = void>
|
||||
constexpr bool is_class_or_enum = false;
|
||||
template <class It>
|
||||
constexpr bool is_class_or_enum<It, enable_if_t<
|
||||
(is_class_v<remove_cvref_t<It>> || is_enum_v<remove_cvref_t<It>>)>> = true;
|
||||
|
||||
template<class LHS, class RHS, class = void>
|
||||
constexpr bool assignable_from_impl = false;
|
||||
template<class LHS, class RHS>
|
||||
constexpr bool assignable_from_impl<LHS, RHS, enable_if_t<is_lvalue_reference_v<LHS>
|
||||
&& common_reference_with<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&>
|
||||
&& same_as<decltype(declval<LHS>() = declval<RHS>()), LHS> >> = true;
|
||||
|
||||
|
||||
template<class T, class U, class = void>
|
||||
constexpr bool common_with_impl = false;
|
||||
template<class T, class U>
|
||||
constexpr bool common_with_impl<T, U, enable_if_t<
|
||||
same_as<common_type_t<T, U>, common_type_t<U, T>>
|
||||
&& sfinae_trigger_v<decltype(static_cast<common_type_t<T, U>>(declval<T>()))>
|
||||
&& sfinae_trigger_v<decltype(static_cast<common_type_t<T, U>>(declval<U>()))>
|
||||
&& common_reference_with<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>
|
||||
&& common_reference_with<add_lvalue_reference_t<common_type_t<T, U>>, common_reference_t<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class T, class U>
|
||||
/*concept*/ constexpr bool common_with = Internal::common_with_impl<T, U>;
|
||||
|
||||
template<class LHS, class RHS>
|
||||
/*concept*/ constexpr bool assignable_from = Internal::assignable_from_impl<LHS, RHS>;
|
||||
|
||||
template<class T, class... Args>
|
||||
/*concept*/ constexpr bool constructible_from = destructible<T> && is_constructible_v<T, Args...>;
|
||||
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool move_constructible = constructible_from<T, T> && convertible_to<T, T>;
|
||||
|
||||
template<class Derived, class Base>
|
||||
/*concept*/ constexpr bool derived_from = is_base_of_v<Base, Derived> && is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
}
|
||||
|
||||
namespace AZStd::ranges::Internal
|
||||
{
|
||||
template <class T, class U, class = void>
|
||||
constexpr bool is_class_or_enum_with_swap_adl = false;
|
||||
template <class T, class U>
|
||||
constexpr bool is_class_or_enum_with_swap_adl<T, U, enable_if_t<
|
||||
(is_class_v<remove_cvref_t<T>> || is_enum_v<remove_cvref_t<T>>
|
||||
|| is_class_v<remove_cvref_t<U>> || is_enum_v<remove_cvref_t<T>>)
|
||||
&& is_void_v<void_t<decltype(swap(declval<T&>(), declval<U&>()))>>
|
||||
>> = true;
|
||||
|
||||
template <class T>
|
||||
void swap(T&, T&) = delete;
|
||||
|
||||
struct swap_fn
|
||||
{
|
||||
template <class T, class U>
|
||||
constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept(swap(AZStd::forward<T>(t), AZStd::forward<U>(u))))
|
||||
->enable_if_t<is_class_or_enum_with_swap_adl<T, U>>
|
||||
{
|
||||
swap(AZStd::forward<T>(t), AZStd::forward<U>(u));
|
||||
}
|
||||
|
||||
// ranges::swap customization point https://eel.is/c++draft/concepts#concept.swappable-2.2
|
||||
// Implemented in ranges.h as to prevent circular dependency.
|
||||
// ranges::swap_ranges depends on the range concepts that can't be defined here
|
||||
template <class T, class U>
|
||||
constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept((*this)(*t, *u)))
|
||||
->enable_if_t<!is_class_or_enum_with_swap_adl<T, U>
|
||||
&& is_array_v<T> && is_array_v<U> && (extent_v<T> == extent_v<U>)
|
||||
>;
|
||||
|
||||
template <class T>
|
||||
constexpr auto operator()(T& t1, T& t2) const noexcept(noexcept(is_nothrow_move_constructible_v<T>&& is_nothrow_move_assignable_v<T>))
|
||||
->enable_if_t<move_constructible<T>&& assignable_from<T&, T>>
|
||||
{
|
||||
auto temp(AZStd::move(t1));
|
||||
t1 = AZStd::move(t2);
|
||||
t2 = AZStd::move(temp);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZStd::ranges
|
||||
{
|
||||
inline namespace customization_point_object
|
||||
{
|
||||
inline constexpr auto swap = Internal::swap_fn{};
|
||||
}
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <class T, class = void>
|
||||
constexpr bool swappable_impl = false;
|
||||
template <class T>
|
||||
constexpr bool swappable_impl<T, void_t<decltype(AZStd::ranges::swap(declval<T&>(), declval<T&>()))>> = true;
|
||||
|
||||
template <class T, class U, class = void>
|
||||
constexpr bool swappable_with_impl = false;
|
||||
template <class T, class U>
|
||||
constexpr bool swappable_with_impl<T, U, enable_if_t<common_reference_with<T, U>
|
||||
&& sfinae_trigger_v<
|
||||
decltype(AZStd::ranges::swap(declval<T&>(), declval<T&>())),
|
||||
decltype(AZStd::ranges::swap(declval<U&>(), declval<U&>())),
|
||||
decltype(AZStd::ranges::swap(declval<T&>(), declval<U&>())),
|
||||
decltype(AZStd::ranges::swap(declval<U&>(), declval<T&>()))>>> = true;
|
||||
}
|
||||
namespace AZStd
|
||||
{
|
||||
template <class T>
|
||||
/*concept*/ constexpr bool signed_integral = integral<T> && is_signed_v<T>;
|
||||
template <class T>
|
||||
/*concept*/ constexpr bool unsigned_integral = integral<T> && !signed_integral<T>;
|
||||
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool swappable = Internal::swappable_impl<T>;
|
||||
|
||||
template<class T, class U>
|
||||
/*concept*/ constexpr bool swappable_with = Internal::swappable_with_impl<T, U>;
|
||||
}
|
||||
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// boolean-testable concept (exposition only in the C++standard)
|
||||
template<class T>
|
||||
constexpr bool boolean_testable_impl = convertible_to<T, bool>;
|
||||
|
||||
template<class T, class = void>
|
||||
constexpr bool boolean_testable = false;
|
||||
template<class T>
|
||||
constexpr bool boolean_testable<T, enable_if_t<boolean_testable_impl<T> && boolean_testable_impl<decltype(!declval<T>())>>> = true;
|
||||
|
||||
// weakly comparable ==, !=
|
||||
template<class T, class U, class = void>
|
||||
constexpr bool weakly_equality_comparable_with = false;
|
||||
template<class T, class U>
|
||||
constexpr bool weakly_equality_comparable_with<T, U, enable_if_t<
|
||||
boolean_testable<decltype(declval<AZStd::remove_reference_t<T>&>() == declval<AZStd::remove_reference_t<U>&>())>
|
||||
&& boolean_testable<decltype(declval<AZStd::remove_reference_t<T>&>() != declval<AZStd::remove_reference_t<U>&>())>
|
||||
&& boolean_testable<decltype(declval<AZStd::remove_reference_t<U>&>() == declval<AZStd::remove_reference_t<T>&>())>
|
||||
&& boolean_testable<decltype(declval<AZStd::remove_reference_t<U>&>() != declval<AZStd::remove_reference_t<T>&>())>
|
||||
>> = true;
|
||||
|
||||
// partially ordered <, >, <=, >=
|
||||
template<class, class U, class = void>
|
||||
constexpr bool partially_ordered_with_impl = false;
|
||||
template<class T, class U>
|
||||
constexpr bool partially_ordered_with_impl<T, U, enable_if_t<
|
||||
boolean_testable<decltype(declval<const remove_reference_t<T>&>() < declval<const remove_reference_t<U>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<T>&>() > declval<const remove_reference_t<U>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<T>&>() <= declval<const remove_reference_t<U>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<T>&>() >= declval<const remove_reference_t<U>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<U>&>() < declval<const remove_reference_t<T>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<U>&>() > declval<const remove_reference_t<T>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<U>&>() <= declval<const remove_reference_t<T>&>())>
|
||||
&& boolean_testable<decltype(declval<const remove_reference_t<U>&>() >= declval<const remove_reference_t<T>&>())>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool equality_comparable = Internal::weakly_equality_comparable_with<T, T>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// equally_comparable + partially ordered
|
||||
template<class, class U, class = void>
|
||||
constexpr bool equally_comparable_with_impl = false;
|
||||
template<class T, class U>
|
||||
constexpr bool equally_comparable_with_impl<T, U, enable_if_t<equality_comparable<T>
|
||||
&& equality_comparable<U>
|
||||
&& common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&>
|
||||
&& equality_comparable<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>
|
||||
&& Internal::weakly_equality_comparable_with<T, U>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class T, class U>
|
||||
/*concept*/ constexpr bool equality_comparable_with = Internal::equally_comparable_with_impl<T, U>;
|
||||
|
||||
template<class T, class U>
|
||||
/*concept*/ constexpr bool partially_ordered_with = Internal::partially_ordered_with_impl<T, U>;
|
||||
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool totally_ordered = equality_comparable<T> && partially_ordered_with<T, T>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// equally_comparable + partially ordered
|
||||
template<class, class U, class = void>
|
||||
constexpr bool totally_ordered_with_impl = false;
|
||||
template<class T, class U>
|
||||
constexpr bool totally_ordered_with_impl<T, U, enable_if_t<totally_ordered<T>&& totally_ordered<U>
|
||||
&& equality_comparable_with<T, U>
|
||||
&& totally_ordered<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>
|
||||
&& partially_ordered_with<T, U>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class T, class U>
|
||||
/*concept*/ constexpr bool totally_ordered_with = Internal::totally_ordered_with_impl<T, U>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class T, class = void>
|
||||
inline constexpr bool is_default_initializable = false;
|
||||
template<class T>
|
||||
inline constexpr bool is_default_initializable<T, void_t<decltype(::new T)>> = true;
|
||||
|
||||
template<class T, class = void>
|
||||
constexpr bool default_initializable_impl = false;
|
||||
template<class T>
|
||||
constexpr bool default_initializable_impl < T, enable_if_t < constructible_from<T>
|
||||
&& sfinae_trigger_v<decltype(T{}) > && Internal::is_default_initializable<T> >> = true;
|
||||
|
||||
template <class T, class = void>
|
||||
constexpr bool movable_impl = false;
|
||||
template <class T>
|
||||
constexpr bool movable_impl<T, enable_if_t<is_object_v<T> && move_constructible<T> &&
|
||||
assignable_from<T&, T> && swappable<T>> > = true;
|
||||
|
||||
template <class T, class = void>
|
||||
constexpr bool copy_constructible_impl = false;
|
||||
template <class T>
|
||||
constexpr bool copy_constructible_impl<T, enable_if_t<move_constructible<T> &&
|
||||
constructible_from<T, T&> && convertible_to<T&, T> &&
|
||||
constructible_from<T, const T&> && convertible_to<const T&, T> &&
|
||||
constructible_from<T, const T> && convertible_to<const T, T>> > = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// movable
|
||||
template <class T>
|
||||
/*concept*/ constexpr bool movable = Internal::movable_impl<T>;
|
||||
|
||||
// default_initializable
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool default_initializable = Internal::default_initializable_impl<T>;
|
||||
|
||||
// copy constructible
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool copy_constructible = Internal::copy_constructible_impl<T>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <class T, class = void>
|
||||
constexpr bool copyable_impl = false;
|
||||
template <class T>
|
||||
constexpr bool copyable_impl<T, enable_if_t<copy_constructible<T> && movable<T> && assignable_from<T&, T&> &&
|
||||
assignable_from<T&, const T&> && assignable_from<T&, const T>> > = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// copyable
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool copyable = Internal::copyable_impl<T>;
|
||||
|
||||
// semiregular
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool semiregular = copyable<T> && default_initializable<T>;
|
||||
|
||||
// regular
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool regular = semiregular<T> && equality_comparable<T>;
|
||||
}
|
||||
|
||||
// Iterator Concepts
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <class T>
|
||||
constexpr bool is_integer_like = integral<T> && !same_as<T, bool>;
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_signed_integer_like = signed_integral<T>;
|
||||
|
||||
template <class T, class = void>
|
||||
constexpr bool weakly_incrementable_impl = false;
|
||||
template <class T>
|
||||
constexpr bool weakly_incrementable_impl<T, enable_if_t<movable<T>
|
||||
&& is_signed_integer_like<iter_difference_t<T>>
|
||||
&& same_as<decltype(++declval<T&>()), T&>
|
||||
&& sfinae_trigger_v<decltype(declval<T&>()++)> >> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// models weakly_incrementable concept
|
||||
template <class T>
|
||||
/*concept*/ constexpr bool weakly_incrementable = Internal::weakly_incrementable_impl<T>;
|
||||
|
||||
// models input_or_output_iterator concept
|
||||
template <class T>
|
||||
/*concept*/ constexpr bool input_or_output_iterator = !is_void_v<T>
|
||||
&& weakly_incrementable<T>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <class T, class = void>
|
||||
constexpr bool incrementable_impl = false;
|
||||
template <class T>
|
||||
constexpr bool incrementable_impl<T, enable_if_t<regular<T>
|
||||
&& weakly_incrementable<T>
|
||||
&& same_as<decltype(declval<T&>()++), T> >> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template <class T>
|
||||
/*concept*/ constexpr bool incrementable = Internal::incrementable_impl<T>;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class S, class I>
|
||||
/*concept*/ constexpr bool sentinel_for = semiregular<S> &&
|
||||
input_or_output_iterator<I> &&
|
||||
Internal::weakly_equality_comparable_with<S, I>;
|
||||
template<class S, class I>
|
||||
inline constexpr bool disable_sized_sentinel_for = false;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class S, class I, class = void>
|
||||
/*concept*/ constexpr bool sized_sentinel_for_impl = false;
|
||||
template<class S, class I>
|
||||
/*concept*/ constexpr bool sized_sentinel_for_impl<S, I, enable_if_t<
|
||||
sentinel_for<S, I>
|
||||
&& !disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>>
|
||||
&& same_as<decltype(declval<S>() - declval<I>()), iter_difference_t<I>>
|
||||
&& same_as<decltype(declval<I>() - declval<S>()), iter_difference_t<I>> >> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class S, class I>
|
||||
/*concept*/ constexpr bool sized_sentinel_for = Internal::sized_sentinel_for_impl<S, I>;
|
||||
|
||||
template<class I>
|
||||
struct iterator_traits;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// ITER_CONCEPT(I) general concept
|
||||
template<class I, class = void>
|
||||
constexpr bool use_traits_iterator_concept_for_concept = false;
|
||||
template<class I>
|
||||
constexpr bool use_traits_iterator_concept_for_concept<I, void_t<typename iterator_traits<I>::iterator_concept>> = true;
|
||||
|
||||
template<class I, class = void>
|
||||
constexpr bool use_traits_iterator_category_for_concept = false;
|
||||
template<class I>
|
||||
constexpr bool use_traits_iterator_category_for_concept<I,
|
||||
void_t<typename iterator_traits<I>::iterator_category>> = !use_traits_iterator_concept_for_concept<I>;
|
||||
|
||||
template<class I, class = void>
|
||||
constexpr bool use_random_access_iterator_tag_for_concept = false;
|
||||
template<class I>
|
||||
constexpr bool use_random_access_iterator_tag_for_concept<I,
|
||||
void_t<iterator_traits<I>>> = !use_traits_iterator_concept_for_concept<I>
|
||||
&& !use_traits_iterator_category_for_concept<I>;
|
||||
|
||||
template<class I, class = void>
|
||||
struct iter_concept;
|
||||
|
||||
template<class I>
|
||||
struct iter_concept<I, enable_if_t<use_traits_iterator_concept_for_concept<I>>>
|
||||
{
|
||||
using type = typename iterator_traits<I>::iterator_concept;
|
||||
};
|
||||
template<class I>
|
||||
struct iter_concept<I, enable_if_t<use_traits_iterator_category_for_concept<I>>>
|
||||
{
|
||||
using type = typename iterator_traits<I>::iterator_category;
|
||||
};
|
||||
|
||||
template<class I>
|
||||
struct iter_concept<I, enable_if_t<use_random_access_iterator_tag_for_concept<I>>>
|
||||
{
|
||||
using type = random_access_iterator_tag;
|
||||
};
|
||||
template<class I>
|
||||
using iter_concept_t = typename iter_concept<I>::type;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// indirectly readable
|
||||
template <class In>
|
||||
/*concept*/ constexpr bool indirectly_readable = Internal::indirectly_readable_impl<remove_cvref_t<In>>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// model the indirectly writable concept
|
||||
template <class Out, class T, class = void>
|
||||
constexpr bool indirectly_writable_impl = false;
|
||||
|
||||
template <class Out, class T>
|
||||
constexpr bool indirectly_writable_impl<Out, T, void_t<
|
||||
decltype(*declval<Out&>() = declval<T>()),
|
||||
decltype(*declval<Out>() = declval<T>()),
|
||||
decltype(const_cast<const iter_reference_t<Out>&&>(*declval<Out&>()) = declval<T>()),
|
||||
decltype(const_cast<const iter_reference_t<Out>&&>(*declval<Out>()) = declval<T>())>
|
||||
> = true;
|
||||
}
|
||||
namespace AZStd
|
||||
{
|
||||
// indirectly writable
|
||||
template <class Out, class T>
|
||||
/*concept*/ constexpr bool indirectly_writable = Internal::indirectly_writable_impl<Out, T>;
|
||||
|
||||
// indirectly movable
|
||||
template<class In, class Out>
|
||||
/*concept*/ constexpr bool indirectly_movable = indirectly_readable<In> && indirectly_writable<Out, iter_rvalue_reference_t<In>>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class In, class Out, class = void>
|
||||
constexpr bool indirectly_movable_storage_impl = false;
|
||||
|
||||
template<class In, class Out>
|
||||
constexpr bool indirectly_movable_storage_impl<In, Out, enable_if_t<
|
||||
indirectly_movable<In, Out> &&
|
||||
indirectly_writable<Out, iter_value_t<In>> &&
|
||||
movable<iter_value_t<In>> &&
|
||||
constructible_from<iter_value_t<In>, iter_rvalue_reference_t<In>> &&
|
||||
assignable_from<iter_value_t<In>&, iter_rvalue_reference_t<In>>> > = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class In, class Out>
|
||||
/*concept*/ constexpr bool indirectly_movable_storable = Internal::indirectly_movable_storage_impl<In, Out>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class In, class Out, class = void>
|
||||
constexpr bool indirectly_copyable_impl = false;
|
||||
|
||||
template<class In, class Out>
|
||||
constexpr bool indirectly_copyable_impl<In, Out, enable_if_t<
|
||||
indirectly_readable<In> &&
|
||||
indirectly_writable<Out, iter_reference_t<In>>> > = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// indirectly copyable
|
||||
template<class In, class Out>
|
||||
/*concept*/ constexpr bool indirectly_copyable = Internal::indirectly_copyable_impl<In, Out>;
|
||||
}
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class In, class Out, class = void>
|
||||
constexpr bool indirectly_copyable_storable_impl = false;
|
||||
|
||||
template<class In, class Out>
|
||||
constexpr bool indirectly_copyable_storable_impl<In, Out, enable_if_t<
|
||||
indirectly_copyable<In, Out> &&
|
||||
indirectly_writable<Out, iter_value_t<In>&> &&
|
||||
indirectly_writable<Out, const iter_value_t<In>&> &&
|
||||
indirectly_writable<Out, iter_value_t<In>&&> &&
|
||||
indirectly_writable<Out, const iter_value_t<In>&&> &&
|
||||
copyable<iter_value_t<In>> &&
|
||||
constructible_from<iter_value_t<In>, iter_reference_t<In>> &&
|
||||
assignable_from<iter_value_t<In>&, iter_reference_t<In>>> > = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class In, class Out>
|
||||
/*concept*/ constexpr bool indirectly_copyable_storable = Internal::indirectly_copyable_storable_impl<In, Out>;
|
||||
}
|
||||
|
||||
namespace AZStd::ranges::Internal
|
||||
{
|
||||
template<class I1, class I2>
|
||||
void iter_swap(I1, I2) = delete;
|
||||
|
||||
template <class I1, class I2, class = void>
|
||||
constexpr bool iter_swap_adl = false;
|
||||
|
||||
template <class I1, class I2>
|
||||
constexpr bool iter_swap_adl<I1, I2, void_t<decltype(iter_swap(declval<I1>(), declval<I2>()))>> = true;
|
||||
|
||||
template <class I1, class I2, class = void>
|
||||
constexpr bool is_class_or_enum_with_iter_swap_adl = false;
|
||||
|
||||
template <class I1, class I2>
|
||||
constexpr bool is_class_or_enum_with_iter_swap_adl<I1, I2, enable_if_t<iter_swap_adl<I1, I2>
|
||||
&& (is_class_v<remove_cvref_t<I1>> || is_enum_v<remove_cvref_t<I1>>)
|
||||
&& (is_class_v<remove_cvref_t<I2>> || is_enum_v<remove_cvref_t<I2>>)>> = true;
|
||||
|
||||
struct iter_swap_fn
|
||||
{
|
||||
template <class I1, class I2>
|
||||
constexpr auto operator()(I1&& i1, I2&& i2) const
|
||||
->enable_if_t<is_class_or_enum_with_iter_swap_adl<I1, I2>
|
||||
>
|
||||
{
|
||||
iter_swap(AZStd::forward<I1>(i1), AZStd::forward<I1>(i2));
|
||||
}
|
||||
template <class I1, class I2>
|
||||
constexpr auto operator()(I1&& i1, I2&& i2) const
|
||||
->enable_if_t<!is_class_or_enum_with_iter_swap_adl<I1, I2>
|
||||
&& indirectly_readable<I1>
|
||||
&& indirectly_readable<I2>
|
||||
&& swappable_with<iter_reference_t<I1>, iter_reference_t<I2>>
|
||||
>
|
||||
{
|
||||
ranges::swap(*i1, *i2);
|
||||
}
|
||||
|
||||
template <class I1, class I2>
|
||||
constexpr auto operator()(I1&& i1, I2&& i2) const
|
||||
->enable_if_t<!is_class_or_enum_with_iter_swap_adl<I1, I2>
|
||||
&& indirectly_movable_storable<I1, I2>
|
||||
&& indirectly_movable_storable<I2, I1>
|
||||
>
|
||||
{
|
||||
*AZStd::forward<I1>(i1) = iter_exchange_move(AZStd::forward<I2>(i2), AZStd::forward<I1>(i1));
|
||||
}
|
||||
|
||||
private:
|
||||
template<class X, class Y>
|
||||
static constexpr iter_value_t<X> iter_exchange_move(X&& x, Y&& y)
|
||||
noexcept(noexcept(iter_value_t<X>(iter_move(x))) && noexcept(*x = iter_move(y)))
|
||||
{
|
||||
iter_value_t<X> old_value(iter_move(x));
|
||||
*x = iter_move(y);
|
||||
return old_value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZStd::ranges
|
||||
{
|
||||
inline namespace customization_point_object
|
||||
{
|
||||
inline constexpr Internal::iter_swap_fn iter_swap{};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <class I1, class I2, class = void>
|
||||
constexpr bool indirectly_swappable_impl = false;
|
||||
template <class I1, class I2>
|
||||
constexpr bool indirectly_swappable_impl<I1, I2, enable_if_t<
|
||||
indirectly_readable<I1>&& indirectly_readable<I2>
|
||||
&& sfinae_trigger_v<
|
||||
decltype(AZStd::ranges::iter_swap(declval<I1>(), declval<I1>())),
|
||||
decltype(AZStd::ranges::iter_swap(declval<I2>(), declval<I2>())),
|
||||
decltype(AZStd::ranges::iter_swap(declval<I1>(), declval<I2>())),
|
||||
decltype(AZStd::ranges::iter_swap(declval<I2>(), declval<I1>()))>>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class I1, class I2 = I1>
|
||||
/*concept*/ constexpr bool indirectly_swappable = Internal::indirectly_swappable_impl<I1, I2>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class I, class = void>
|
||||
constexpr bool input_iterator_impl = false;
|
||||
template<class I>
|
||||
constexpr bool input_iterator_impl<I, enable_if_t<input_or_output_iterator<I>
|
||||
&& derived_from<iter_concept_t<I>, input_iterator_tag>
|
||||
&& indirectly_readable<I>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// input iterator
|
||||
template<class I>
|
||||
/*concept*/ constexpr bool input_iterator = Internal::input_iterator_impl<I>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class I, class T, class = void>
|
||||
constexpr bool output_iterator_impl = false;
|
||||
template<class I, class T>
|
||||
constexpr bool output_iterator_impl<I, T, enable_if_t<input_or_output_iterator<I>
|
||||
&& indirectly_writable<I, T>
|
||||
&& sfinae_trigger_v<decltype(*declval<I&>()++ = AZStd::declval<T>())>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// output iterator
|
||||
template<class I, class T>
|
||||
/*concept*/ constexpr bool output_iterator = Internal::output_iterator_impl<I, T>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class I, class = void>
|
||||
constexpr bool forward_iterator_impl = false;
|
||||
template<class I>
|
||||
constexpr bool forward_iterator_impl<I, enable_if_t<input_iterator<I>
|
||||
&& derived_from<Internal::iter_concept_t<I>, forward_iterator_tag>
|
||||
&& incrementable<I>
|
||||
&& sentinel_for<I, I>> > = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// forward_iterator
|
||||
template<class I>
|
||||
/*concept*/ constexpr bool forward_iterator = Internal::forward_iterator_impl<I>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class I, class = void>
|
||||
constexpr bool bidirectional_iterator_impl = false;
|
||||
template<class I>
|
||||
constexpr bool bidirectional_iterator_impl<I, enable_if_t<forward_iterator<I>
|
||||
&& derived_from<iter_concept_t<I>, bidirectional_iterator_tag>
|
||||
&& same_as<decltype(--declval<I&>()), I&>
|
||||
&& same_as<decltype(declval<I&>()--), I> >> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// bidirectional iterator
|
||||
template<class I>
|
||||
/*concept*/ constexpr bool bidirectional_iterator = Internal::bidirectional_iterator_impl<I>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class I, class = void>
|
||||
constexpr bool random_access_iterator_impl = false;
|
||||
template<class I>
|
||||
constexpr bool random_access_iterator_impl<I, enable_if_t<bidirectional_iterator<I>
|
||||
&& derived_from<iter_concept_t<I>, random_access_iterator_tag>
|
||||
&& totally_ordered<I>
|
||||
&& sized_sentinel_for<I, I>
|
||||
&& same_as<decltype(declval<I&>() += declval<const iter_difference_t<I>>()), I&>
|
||||
&& same_as<decltype(declval<const I>() + declval<const iter_difference_t<I>>()), I>
|
||||
&& same_as<decltype(declval<iter_difference_t<I>>() + declval<const I>()), I>
|
||||
&& same_as<decltype(declval<I&>() -= declval<const iter_difference_t<I>>()), I&>
|
||||
&& same_as<decltype(declval<const I>() - declval<const iter_difference_t<I>>()), I>
|
||||
&& same_as<decltype(declval<const I&>()[declval<iter_difference_t<I>>()]), iter_reference_t<I>>>>
|
||||
= true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template<class I>
|
||||
/*concept*/ constexpr bool random_access_iterator = Internal::random_access_iterator_impl<I>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template<class I, class = void>
|
||||
constexpr bool contiguous_iterator_impl = false;
|
||||
template<class I>
|
||||
constexpr bool contiguous_iterator_impl<I, enable_if_t<random_access_iterator<I>
|
||||
&& derived_from<iter_concept_t<I>, contiguous_iterator_tag>
|
||||
&& is_lvalue_reference_v<iter_reference_t<I>>
|
||||
&& indirectly_readable<I>
|
||||
&& same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>>
|
||||
> >
|
||||
= same_as<decltype(to_address(declval<const I&>())), add_pointer_t<iter_reference_t<I>>>;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// contiguous iterator
|
||||
template<class I>
|
||||
/*concept*/ constexpr bool contiguous_iterator = Internal::contiguous_iterator_impl<I>;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// models the predicate concept
|
||||
template <bool, class F, class... Args>
|
||||
constexpr bool predicate_impl = false;
|
||||
template <class F, class... Args>
|
||||
constexpr bool predicate_impl<true, F, Args...> = Internal::boolean_testable<invoke_result_t<F, Args...>>;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// models the predicate concept
|
||||
template <class F, class... Args>
|
||||
/*concept*/ constexpr bool predicate = Internal::predicate_impl<regular_invocable<F, Args...>, F, Args...>;
|
||||
|
||||
// models the relation concept
|
||||
template <class R, class T, class U>
|
||||
/*concept*/ constexpr bool relation = predicate<R, T, T> && predicate<R, U, U>
|
||||
&& predicate<R, T, U> && predicate<R, U, T>;
|
||||
|
||||
// models the equivalence_relation concept
|
||||
template <class R, class T, class U>
|
||||
/*concept*/ constexpr bool equivalence_relation = relation<R, T, U>;
|
||||
|
||||
// models the strict_weak_order concept
|
||||
// Note: semantically this is different than equivalence_relation
|
||||
template <class R, class T, class U>
|
||||
/*concept*/ constexpr bool strict_weak_order = relation<R, T, U>;
|
||||
}
|
||||
@@ -135,9 +135,10 @@ namespace AZStd
|
||||
AZ_FORCE_INLINE this_type& operator--() { --m_offset; return *this; }
|
||||
AZ_FORCE_INLINE this_type operator--(int) { this_type tmp = *this; --m_offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type& operator+=(difference_type offset) { m_offset += offset; return *this; }
|
||||
AZ_FORCE_INLINE this_type operator+(difference_type offset) { this_type tmp = *this; tmp += offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type operator+(difference_type offset) const { this_type tmp = *this; tmp += offset; return tmp; }
|
||||
friend AZ_FORCE_INLINE this_type operator+(difference_type offset, const this_type& rhs) { this_type tmp = rhs; tmp += offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type& operator-=(difference_type offset) { m_offset -= offset; return *this; }
|
||||
AZ_FORCE_INLINE this_type operator-(difference_type offset) { this_type tmp = *this; tmp -= offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type operator-(difference_type offset) const { this_type tmp = *this; tmp -= offset; return tmp; }
|
||||
/// ???
|
||||
AZ_FORCE_INLINE difference_type operator-(const this_type& rhs) const
|
||||
{
|
||||
@@ -197,9 +198,10 @@ namespace AZStd
|
||||
AZ_FORCE_INLINE this_type& operator--() { --base_type::m_offset; return *this; }
|
||||
AZ_FORCE_INLINE this_type operator--(int) { this_type tmp = *this; --base_type::m_offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type& operator+=(difference_type offset) { base_type::m_offset += offset; return *this; }
|
||||
AZ_FORCE_INLINE this_type operator+(difference_type offset) { this_type tmp = *this; tmp += offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type operator+(difference_type offset) const { this_type tmp = *this; tmp += offset; return tmp; }
|
||||
friend AZ_FORCE_INLINE this_type operator+(difference_type offset, const this_type& rhs) { this_type tmp = rhs; tmp += offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type& operator-=(difference_type offset) { base_type::m_offset -= offset; return *this; }
|
||||
AZ_FORCE_INLINE this_type operator-(difference_type offset) { this_type tmp = *this; tmp -= offset; return tmp; }
|
||||
AZ_FORCE_INLINE this_type operator-(difference_type offset) const { this_type tmp = *this; tmp -= offset; return tmp; }
|
||||
AZ_FORCE_INLINE difference_type operator-(const this_type& rhs) const
|
||||
{
|
||||
return rhs.m_offset <= base_type::m_offset ? base_type::m_offset - rhs.m_offset : -(difference_type)(rhs.m_offset - base_type::m_offset);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/concepts/concepts.h>
|
||||
#include <AzCore/std/createdestroy.h>
|
||||
#include <AzCore/std/typetraits/typetraits.h>
|
||||
|
||||
@@ -101,7 +102,7 @@ namespace AZStd::Internal
|
||||
//! Invokes destructor on all elements in range
|
||||
//! No-op on empty container
|
||||
//! Nothing to destroy since the storage is empty.
|
||||
template <typename InputIt, typename = enable_if_t<Internal::is_input_iterator_v<InputIt>>>
|
||||
template <typename InputIt, typename = enable_if_t<input_iterator<InputIt>>>
|
||||
static constexpr void unsafe_destroy(InputIt, InputIt) noexcept
|
||||
{
|
||||
}
|
||||
@@ -214,7 +215,7 @@ namespace AZStd::Internal
|
||||
//! Destructs elements in the range [begin, end).
|
||||
//! This does not modify the size of the storage
|
||||
//! This is a no-op for trivial types
|
||||
template <typename InputIt, typename = enable_if_t<Internal::is_input_iterator_v<InputIt>>>
|
||||
template <typename InputIt, typename = enable_if_t<input_iterator<InputIt>>>
|
||||
void unsafe_destroy(InputIt, InputIt) noexcept
|
||||
{
|
||||
}
|
||||
@@ -334,7 +335,7 @@ namespace AZStd::Internal
|
||||
//! Destructs elements in the range [begin, end).
|
||||
//! This does not modify the size of the storage
|
||||
//! Invokes the destuctor via the AZStd::destroy method
|
||||
template <typename InputIt, typename = enable_if_t<Internal::is_input_iterator_v<InputIt>>>
|
||||
template <typename InputIt, typename = enable_if_t<input_iterator<InputIt>>>
|
||||
void unsafe_destroy(InputIt first, InputIt last) noexcept(is_nothrow_destructible_v<value_type>)
|
||||
{
|
||||
AZSTD_CONTAINER_ASSERT(first >= data() && first <= data() + size(), "begin iterator is not in range of storage");
|
||||
@@ -410,7 +411,7 @@ namespace AZStd
|
||||
AZStd::uninitialized_fill_n(data(), numElements, value);
|
||||
}
|
||||
|
||||
template <class InputIt, typename = AZStd::enable_if_t<Internal::is_input_iterator_v<InputIt>>>
|
||||
template <class InputIt, typename = AZStd::enable_if_t<input_iterator<InputIt>>>
|
||||
fixed_vector(InputIt first, InputIt last)
|
||||
{
|
||||
resize_no_construct(AZStd::distance(first, last));
|
||||
@@ -615,7 +616,7 @@ namespace AZStd
|
||||
insert(end(), numElements, value);
|
||||
}
|
||||
|
||||
template <class InputIt, typename = AZStd::enable_if_t<Internal::is_input_iterator_v<InputIt>>>
|
||||
template <class InputIt, typename = AZStd::enable_if_t<input_iterator<InputIt>>>
|
||||
void assign(InputIt first, InputIt last)
|
||||
{
|
||||
clear();
|
||||
@@ -641,8 +642,18 @@ namespace AZStd
|
||||
return &newElement;
|
||||
}
|
||||
|
||||
AZStd::uninitialized_move(insertPosPtr, dataEnd, insertPosPtr + 1);
|
||||
// We need to move data with care, it is overlapping.
|
||||
|
||||
// first move the last element into the uninitialized position as that will not overlap.
|
||||
pointer nonOverlap = dataEnd - 1;
|
||||
AZStd::uninitialized_move(nonOverlap, dataEnd, dataEnd);
|
||||
|
||||
// copy the memory backwards while performing AZStd::move on the existing elements the area with overlapping memory
|
||||
// to move the elments to the right by 1
|
||||
AZStd::move_backward(insertPosPtr, nonOverlap, dataEnd);
|
||||
// add new elements
|
||||
AZStd::construct_at(insertPosPtr, AZStd::forward<Args>(args)...);
|
||||
resize_no_construct(size() + 1);
|
||||
return iterator(insertPosPtr);
|
||||
}
|
||||
iterator insert(const_iterator insertPos, const_reference value)
|
||||
@@ -707,7 +718,7 @@ namespace AZStd
|
||||
}
|
||||
}
|
||||
|
||||
template<class InputIt, typename = AZStd::enable_if_t<Internal::is_input_iterator_v<InputIt>>>
|
||||
template<class InputIt, typename = AZStd::enable_if_t<input_iterator<InputIt>>>
|
||||
void insert(const_iterator insertPos, InputIt first, InputIt last)
|
||||
{
|
||||
// specialize for iterator categories.
|
||||
|
||||
@@ -7,9 +7,37 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/std/limits.h>
|
||||
#include <AzCore/std/ranges/ranges.h>
|
||||
#include <AzCore/std/typetraits/type_identity.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
inline constexpr size_t dynamic_extent = numeric_limits<size_t>::max();
|
||||
|
||||
template <class T, size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <class T>
|
||||
inline constexpr bool is_std_array = false;
|
||||
|
||||
template <class U, size_t N>
|
||||
inline constexpr bool is_std_array<::AZStd::array<U, N>> = true;
|
||||
|
||||
template <class T>
|
||||
inline constexpr bool is_std_span = false;
|
||||
|
||||
template <class U, size_t Extent>
|
||||
inline constexpr bool is_std_span<::AZStd::span<U, Extent>> = true;
|
||||
|
||||
template <class T, class U>
|
||||
inline constexpr bool is_array_convertible = is_convertible_v<T(*)[], U(*)[]>;
|
||||
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
@@ -33,97 +61,149 @@ namespace AZStd
|
||||
*
|
||||
* Since the span does not copy and store any data, it is only valid as long as the data used to create it is valid.
|
||||
*/
|
||||
template <class T>
|
||||
class span final
|
||||
template <class T, size_t Extent>
|
||||
class span
|
||||
{
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = AZStd::remove_cv_t<T>;
|
||||
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
using size_type = AZStd::size_t;
|
||||
using difference_type = AZStd::ptrdiff_t;
|
||||
|
||||
using iterator = T*;
|
||||
using const_iterator = const T*;
|
||||
using pointer = element_type*;
|
||||
using const_pointer = const element_type*;
|
||||
|
||||
using reference = element_type&;
|
||||
using const_reference = const element_type&;
|
||||
|
||||
|
||||
using iterator = element_type*;
|
||||
using const_iterator = const element_type*;
|
||||
using reverse_iterator = AZStd::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = AZStd::reverse_iterator<const_iterator>;
|
||||
|
||||
constexpr span();
|
||||
inline static constexpr size_t extent = Extent;
|
||||
|
||||
constexpr span() noexcept = default;;
|
||||
|
||||
~span() = default;
|
||||
|
||||
constexpr span(pointer s, size_type length);
|
||||
template <class It, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
Extent == dynamic_extent>* = nullptr>
|
||||
constexpr span(It first, size_type length);
|
||||
|
||||
constexpr span(pointer first, pointer last);
|
||||
template <class It, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
Extent != dynamic_extent, int> = 0>
|
||||
constexpr explicit span(It first, size_type length);
|
||||
|
||||
// We explicitly delete this constructor because it's too easy to accidentally
|
||||
// create a span to just the first element instead of an entire array.
|
||||
constexpr span(const_pointer s) = delete;
|
||||
template <class It, class End, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
sized_sentinel_for<End, It> &&
|
||||
Extent == dynamic_extent>* = nullptr>
|
||||
constexpr span(It first, End last);
|
||||
|
||||
template<typename Container>
|
||||
constexpr span(Container& data);
|
||||
template <class It, class End, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
sized_sentinel_for<End, It> &&
|
||||
Extent != dynamic_extent, int> = 0>
|
||||
constexpr explicit span(It first, End last);
|
||||
|
||||
template<typename Container>
|
||||
constexpr span(const Container& data);
|
||||
template<size_t N, class = enable_if_t<N == dynamic_extent || N == Extent>>
|
||||
constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;
|
||||
|
||||
constexpr span(const span&) = default;
|
||||
template <class U, size_t N, class = enable_if_t<N == dynamic_extent || N == Extent>>
|
||||
constexpr span(array<U, N>& data) noexcept;
|
||||
template <class U, size_t N, class = enable_if_t<N == dynamic_extent || N == Extent>>
|
||||
constexpr span(const array<U, N>& data) noexcept;
|
||||
|
||||
constexpr span(span&& other);
|
||||
template <class R, class = enable_if_t<ranges::contiguous_range<R> &&
|
||||
ranges::sized_range<R> &&
|
||||
(ranges::borrowed_range<R> || is_const_v<element_type>) &&
|
||||
!Internal::is_std_span<remove_cvref_t<R>> &&
|
||||
!Internal::is_std_array<remove_cvref_t<R>> &&
|
||||
!is_array_v<remove_cvref_t<R>> &&
|
||||
Internal::is_array_convertible<remove_reference_t<ranges::range_reference_t<R>>, element_type> >>
|
||||
constexpr span(R&& r);
|
||||
|
||||
template <class U, size_t OtherExtent, class = enable_if_t<
|
||||
(extent == dynamic_extent || OtherExtent == dynamic_extent || extent == OtherExtent)
|
||||
&& Internal::is_array_convertible<U, element_type> >>
|
||||
constexpr span(const span<U, OtherExtent>& other);
|
||||
|
||||
constexpr span(const span&) noexcept = default;
|
||||
|
||||
constexpr span& operator=(const span& other) = default;
|
||||
|
||||
constexpr span& operator=(span&& other);
|
||||
// subviews -> https://eel.is/c++draft/views#span.sub
|
||||
template <size_t Count>
|
||||
constexpr span<element_type, Count> first() const;
|
||||
template <size_t Count>
|
||||
constexpr span<element_type, Count> last() const;
|
||||
template <size_t Offset, size_t Count = dynamic_extent>
|
||||
constexpr auto subspan() const;
|
||||
|
||||
constexpr size_type size() const;
|
||||
constexpr span<element_type, dynamic_extent> first(size_type count) const;
|
||||
constexpr span<element_type, dynamic_extent> last(size_type count) const;
|
||||
constexpr span<element_type, dynamic_extent> subspan(size_type offset, size_type count = dynamic_extent) const;
|
||||
|
||||
constexpr bool empty() const;
|
||||
// observers - https://eel.is/c++draft/views#span.obs
|
||||
constexpr size_type size() const noexcept;
|
||||
constexpr size_type size_bytes() const noexcept;
|
||||
|
||||
constexpr pointer data();
|
||||
constexpr const_pointer data() const;
|
||||
[[nodiscard]] constexpr bool empty() const noexcept;
|
||||
|
||||
constexpr const_reference operator[](size_type index) const;
|
||||
constexpr reference operator[](size_type index);
|
||||
// element access - https://eel.is/c++draft/views#span.elem
|
||||
constexpr reference operator[](size_type index) const;
|
||||
constexpr reference front() const;
|
||||
constexpr reference back() const;
|
||||
constexpr pointer data() const noexcept;
|
||||
|
||||
constexpr void erase();
|
||||
// iterator support - https://eel.is/c++draft/views#span.iterators
|
||||
constexpr iterator begin() const noexcept;
|
||||
constexpr iterator end() const noexcept;
|
||||
|
||||
constexpr iterator begin();
|
||||
constexpr iterator end();
|
||||
constexpr const_iterator begin() const;
|
||||
constexpr const_iterator end() const;
|
||||
|
||||
constexpr const_iterator cbegin() const;
|
||||
constexpr const_iterator cend() const;
|
||||
|
||||
constexpr reverse_iterator rbegin();
|
||||
constexpr reverse_iterator rend();
|
||||
constexpr const_reverse_iterator rbegin() const;
|
||||
constexpr const_reverse_iterator rend() const;
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const;
|
||||
constexpr const_reverse_iterator crend() const;
|
||||
|
||||
friend bool operator==(span lhs, span rhs)
|
||||
{
|
||||
return lhs.m_begin == rhs.m_begin && lhs.m_end == rhs.m_end;
|
||||
}
|
||||
|
||||
friend bool operator!=(span lhs, span rhs) { return !(lhs == rhs); }
|
||||
friend bool operator< (span lhs, span rhs) { return lhs.m_begin < rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end < rhs.m_end; }
|
||||
friend bool operator> (span lhs, span rhs) { return lhs.m_begin > rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end > rhs.m_end; }
|
||||
friend bool operator<=(span lhs, span rhs) { return lhs == rhs || lhs < rhs; }
|
||||
friend bool operator>=(span lhs, span rhs) { return lhs == rhs || lhs > rhs; }
|
||||
constexpr reverse_iterator rbegin() const noexcept;
|
||||
constexpr reverse_iterator rend() const noexcept;
|
||||
|
||||
private:
|
||||
pointer m_begin;
|
||||
pointer m_end;
|
||||
pointer m_data{};
|
||||
size_type m_size{};
|
||||
};
|
||||
|
||||
// deduction guides https://eel.is/c++draft/views#span.deduct
|
||||
template <class It, class EndOrSize, class = enable_if_t<contiguous_iterator<It>>>
|
||||
span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>>;
|
||||
|
||||
// array deductions
|
||||
template <class T, size_t N>
|
||||
span(T(&)[N]) -> span<T, N>;
|
||||
template <class T, size_t N>
|
||||
span(array<T, N>&) -> span<T, N>;
|
||||
template <class T, size_t N>
|
||||
span(const array<T, N>&) -> span<const T, N>;
|
||||
|
||||
template <class R, class = enable_if_t<ranges::contiguous_range<R>>>
|
||||
span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
|
||||
|
||||
// [span.objectrep], views of object representation
|
||||
template <class ElementType, size_t Extent>
|
||||
auto as_bytes(span<ElementType, Extent> s) noexcept
|
||||
-> span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>;
|
||||
|
||||
template <class ElementType, size_t Extent>
|
||||
auto as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
-> enable_if_t<!is_const_v<ElementType>, span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>>;
|
||||
|
||||
} // namespace AZStd
|
||||
|
||||
namespace AZStd::ranges
|
||||
{
|
||||
template<class ElementType, size_t Extent>
|
||||
inline constexpr bool enable_view<span<ElementType, Extent>> = true;
|
||||
template<class ElementType, size_t Extent>
|
||||
inline constexpr bool enable_borrowed_range<span<ElementType, Extent>> = true;
|
||||
}
|
||||
|
||||
#include <AzCore/std/containers/span.inl>
|
||||
|
||||
@@ -9,116 +9,206 @@
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template <class Element>
|
||||
inline constexpr span<Element>::span()
|
||||
: m_begin(nullptr)
|
||||
, m_end(nullptr)
|
||||
{ }
|
||||
template <class T, size_t Extent>
|
||||
template <class It, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
Extent == dynamic_extent>*>
|
||||
inline constexpr span<T, Extent>::span(It first, size_type length)
|
||||
: m_data{ to_address(first) }
|
||||
, m_size{ length }
|
||||
{}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr span<Element>::span(pointer s, size_type length)
|
||||
: m_begin(s)
|
||||
, m_end(m_begin + length)
|
||||
template <class T, size_t Extent>
|
||||
template <class It, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
Extent != dynamic_extent, int>>
|
||||
inline constexpr span<T, Extent>::span(It first, size_type length)
|
||||
: m_data{ to_address(first) }
|
||||
, m_size{ length }
|
||||
{}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <class It, class End, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
sized_sentinel_for<End, It> &&
|
||||
Extent == dynamic_extent>*>
|
||||
inline constexpr span<T, Extent>::span(It first, End last)
|
||||
: m_data{to_address(first)}
|
||||
, m_size(last - first)
|
||||
{}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <class It, class End, enable_if_t<contiguous_iterator<It> &&
|
||||
Internal::is_array_convertible<remove_reference_t<iter_reference_t<It>>, T> &&
|
||||
sized_sentinel_for<End, It> &&
|
||||
Extent != dynamic_extent, int>>
|
||||
inline constexpr span<T, Extent>::span(It first, End last)
|
||||
: m_data{to_address(first)}
|
||||
, m_size(last - first)
|
||||
{}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <size_t N, class>
|
||||
inline constexpr span<T, Extent>::span(type_identity_t<element_type>(&arr)[N]) noexcept
|
||||
: m_data{ arr }
|
||||
, m_size{ N }
|
||||
{}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <class U, size_t N, class>
|
||||
inline constexpr span<T, Extent>::span(array<U, N>& arr) noexcept
|
||||
: m_data{ arr.data() }
|
||||
, m_size{ arr.size() }
|
||||
{}
|
||||
template <class T, size_t Extent>
|
||||
template <class U, size_t N, class>
|
||||
inline constexpr span<T, Extent>::span(const array<U, N>& arr) noexcept
|
||||
: m_data{ arr.data() }
|
||||
, m_size{ arr.size() }
|
||||
{}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <class R, class>
|
||||
inline constexpr span<T, Extent>::span(R&& r)
|
||||
: m_data{ ranges::data(r) }
|
||||
, m_size{ ranges::size(r) }
|
||||
{
|
||||
if (length == 0) erase();
|
||||
AZ_Assert(Extent == dynamic_extent || Extent == m_size, "The extent of the span is non dynamic,"
|
||||
" therefore the range size must match the extent. Extent=%zu, Range size=%zu",
|
||||
Extent, ranges::size(r));
|
||||
}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr span<Element>::span(pointer first, pointer last)
|
||||
: m_begin(first)
|
||||
, m_end(last)
|
||||
{ }
|
||||
|
||||
template<class Element>
|
||||
template<typename Container>
|
||||
inline constexpr span<Element>::span(Container& data)
|
||||
: m_begin(data.data())
|
||||
, m_end(m_begin + data.size())
|
||||
{ }
|
||||
|
||||
template<class Element>
|
||||
template<typename Container>
|
||||
inline constexpr span<Element>::span(const Container& data)
|
||||
: m_begin(data.data())
|
||||
, m_end(m_begin + data.size())
|
||||
{ }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr span<Element>::span(span&& other)
|
||||
: span(other.m_begin, other.m_end)
|
||||
template <class T, size_t Extent>
|
||||
template <class U, size_t OtherExtent, class>
|
||||
inline constexpr span<T, Extent>::span(const span<U, OtherExtent>& other)
|
||||
: m_data{ other.data() }
|
||||
, m_size{ other.size() }
|
||||
{
|
||||
#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging
|
||||
other.m_begin = nullptr;
|
||||
other.m_end = nullptr;
|
||||
#endif
|
||||
AZ_Assert(Extent == dynamic_extent || Extent == m_size, "The extent of the span is non dynamic,"
|
||||
" therefore the current size of the other span must match the extent. Extent=%zu, Other span size=%zu",
|
||||
Extent, other.size());
|
||||
}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr AZStd::size_t span<Element>::size() const { return m_end - m_begin; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr bool span<Element>::empty() const { return m_end == m_begin; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr Element* span<Element>::data() { return m_begin; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr const Element* span<Element>::data() const { return m_begin; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr span<Element>& span<Element>::operator=(span<Element>&& other)
|
||||
// subviews
|
||||
template <class T, size_t Extent>
|
||||
template <size_t Count>
|
||||
inline constexpr auto span<T, Extent>::first() const -> span<element_type, Count>
|
||||
{
|
||||
m_begin = other.m_begin;
|
||||
m_end = other.m_end;
|
||||
#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging
|
||||
other.m_begin = nullptr;
|
||||
other.m_end = nullptr;
|
||||
#endif
|
||||
return *this;
|
||||
static_assert(Count <= Extent, "Count is larger than the Extent of the span, a subview of the first"
|
||||
" Count elemnts of the span cannot be returned");
|
||||
AZ_Assert(Count <= size(), "Count %zu is larger than span size %zu", Count, size());
|
||||
return span<element_type, Count>{data(), Count};
|
||||
}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr const Element& span<Element>::operator[](AZStd::size_t index) const
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::first(size_type count) const -> span<element_type, dynamic_extent>
|
||||
{
|
||||
AZ_Assert(count <= size(), "Count %zu is larger than current size of span size %zu", count, size());
|
||||
return { data(), count };
|
||||
}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <size_t Count>
|
||||
inline constexpr auto span<T, Extent>::last() const -> span<element_type, Count>
|
||||
{
|
||||
static_assert(Count <= Extent, "Count is larger than the Extent of the span, a subview of the last"
|
||||
" Count elements of the span cannot be returned");
|
||||
AZ_Assert(Count <= size(), "Count %zu is larger than span size %zu", Count, size());
|
||||
return span<element_type, Count>{data() + (size() - Count), Count};
|
||||
}
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::last(size_type count) const -> span<element_type, dynamic_extent>
|
||||
{
|
||||
AZ_Assert(count <= size(), "Count %zu is larger than span size %zu", count, size());
|
||||
return { data() + (size() - count), count };
|
||||
}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
template <size_t Offset, size_t Count>
|
||||
inline constexpr auto span<T, Extent>::subspan() const
|
||||
{
|
||||
static_assert(Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset),
|
||||
"Subspan Offset must <= span Extent and the Count must be either dynamic_extent"
|
||||
" or <= (span Extent - Offset)");
|
||||
AZ_Assert(Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset),
|
||||
"Either the Subspan Offset %zu is larger than the span size %zu or the Count != dynamic_extent and"
|
||||
" its value %zu is greater than \"span size - Offset\" %zu",
|
||||
Offset, size(), Count, size() - Offset);
|
||||
using return_type = span<element_type, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)>;
|
||||
return return_type{ data() + Offset, Count != dynamic_extent ? Count : size() - Offset };
|
||||
}
|
||||
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::subspan(size_type offset, size_type count) const -> span<element_type, dynamic_extent>
|
||||
{
|
||||
AZ_Assert(offset <= size() && (count == dynamic_extent || count <= size() - offset),
|
||||
"Either the Subspan offset %zu is larger than the span size %zu or the count != dynamic_extent and"
|
||||
" its value %zu is greater than \"span size - offset\" %zu",
|
||||
offset, size(), count, size() - offset);
|
||||
return { data() + offset, count != dynamic_extent ? count : size() - offset };
|
||||
}
|
||||
|
||||
|
||||
// observers
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::size() const noexcept -> size_type { return m_size; }
|
||||
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::size_bytes() const noexcept -> size_type { return m_size * sizeof(element_type); }
|
||||
|
||||
template <class T, size_t Extent>
|
||||
[[nodiscard]] inline constexpr bool span<T, Extent>::empty() const noexcept{ return size() == 0; }
|
||||
|
||||
// element access
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::operator[](size_type index) const -> reference
|
||||
{
|
||||
AZ_Assert(index < size(), "index value is out of range");
|
||||
return m_begin[index];
|
||||
return data()[index];
|
||||
}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr Element& span<Element>::operator[](AZStd::size_t index)
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::front() const -> reference
|
||||
{
|
||||
AZ_Assert(index < size(), "index value is out of range");
|
||||
return m_begin[index];
|
||||
AZ_Assert(!empty(), "span cannot be empty when invoking front");
|
||||
return *data();
|
||||
}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr void span<Element>::erase() { m_begin = m_end = nullptr; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr Element* span<Element>::begin() { return m_begin; }
|
||||
template <class Element>
|
||||
inline constexpr Element* span<Element>::end() { return m_end; }
|
||||
template <class Element>
|
||||
inline constexpr const Element* span<Element>::begin() const { return m_begin; }
|
||||
template <class Element>
|
||||
inline constexpr const Element* span<Element>::end() const { return m_end; }
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::back() const -> reference
|
||||
{
|
||||
AZ_Assert(!empty(), "span cannot be empty when invoking back");
|
||||
return *(data() + (size() - 1));
|
||||
}
|
||||
|
||||
template <class Element>
|
||||
inline constexpr const Element* span<Element>::cbegin() const { return m_begin; }
|
||||
template <class Element>
|
||||
inline constexpr const Element* span<Element>::cend() const { return m_end; }
|
||||
// iterator support
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::data() const noexcept -> pointer { return m_data; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr AZStd::reverse_iterator<Element*> span<Element>::rbegin() { return AZStd::reverse_iterator<Element*>(m_end); }
|
||||
template <class Element>
|
||||
inline constexpr AZStd::reverse_iterator<Element*> span<Element>::rend() { return AZStd::reverse_iterator<Element*>(m_begin); }
|
||||
template <class Element>
|
||||
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::rbegin() const { return AZStd::reverse_iterator<const Element*>(m_end); }
|
||||
template <class Element>
|
||||
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::rend() const { return AZStd::reverse_iterator<const Element*>(m_begin); }
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::begin() const noexcept -> iterator{ return m_data; }
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::end() const noexcept -> iterator { return m_data + m_size; }
|
||||
|
||||
template <class Element>
|
||||
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::crbegin() const { return AZStd::reverse_iterator<const Element*>(cend()); }
|
||||
template <class Element>
|
||||
inline constexpr AZStd::reverse_iterator<const Element*> span<Element>::crend() const { return AZStd::reverse_iterator<const Element*>(cbegin()); }
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::rbegin() const noexcept -> reverse_iterator { return AZStd::make_reverse_iterator(end()); }
|
||||
template <class T, size_t Extent>
|
||||
inline constexpr auto span<T, Extent>::rend() const noexcept -> reverse_iterator { return AZStd::make_reverse_iterator(begin()); }
|
||||
|
||||
|
||||
template <class ElementType, size_t Extent>
|
||||
inline auto as_bytes(span<ElementType, Extent> s) noexcept
|
||||
-> span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
|
||||
{
|
||||
return span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>(
|
||||
reinterpret_cast<const byte*>(s.data()), s.size_bytes());
|
||||
}
|
||||
|
||||
|
||||
template <class ElementType, size_t Extent>
|
||||
inline auto as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
-> enable_if_t<!is_const_v<ElementType>, span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>>
|
||||
{
|
||||
return span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>(
|
||||
reinterpret_cast<byte*>(s.data()), s.size_bytes());
|
||||
}
|
||||
} // namespace AZStd
|
||||
|
||||
@@ -7,22 +7,19 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/concepts/concepts.h>
|
||||
#include <AzCore/std/iterator.h>
|
||||
#include <AzCore/std/typetraits/integral_constant.h>
|
||||
#include <AzCore/std/typetraits/is_array.h>
|
||||
#include <AzCore/std/typetraits/is_assignable.h>
|
||||
#include <AzCore/std/typetraits/is_constructible.h>
|
||||
#include <AzCore/std/typetraits/is_destructible.h>
|
||||
#include <AzCore/std/typetraits/is_function.h>
|
||||
#include <AzCore/std/typetraits/is_trivially_copyable.h>
|
||||
#include <AzCore/std/typetraits/is_void.h>
|
||||
#include <AzCore/std/utils.h> // AZStd::addressof
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// alias std::pointer_traits into the AZStd::namespace
|
||||
using std::pointer_traits;
|
||||
|
||||
//! Bring the names of uninitialized_default_construct and
|
||||
//! uninitialized_default_construct_n into the AZStd namespace
|
||||
using std::uninitialized_default_construct;
|
||||
@@ -34,42 +31,6 @@ namespace AZStd
|
||||
using std::uninitialized_value_construct_n;
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
template <typename T, typename = void>
|
||||
constexpr bool pointer_traits_has_to_address_v = false;
|
||||
template <typename T>
|
||||
constexpr bool pointer_traits_has_to_address_v<T, AZStd::void_t<decltype(AZStd::pointer_traits<T>::to_address(declval<const T&>()))>> = true;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
//! Implements the C++20 to_address function
|
||||
//! This obtains the address represented by ptr without forming a reference
|
||||
//! to the pointee type
|
||||
template <typename T>
|
||||
constexpr T* to_address(T* ptr) noexcept
|
||||
{
|
||||
static_assert(!AZStd::is_function_v<T>, "Invoking to address on a function pointer is not allowed");
|
||||
return ptr;
|
||||
}
|
||||
//! Fancy pointer overload which delegates to using a specialization of pointer_traits<T>::to_address
|
||||
//! if that is a well-formed expression, otherwise it returns ptr->operator->()
|
||||
//! For example invoking `to_address(AZStd::reverse_iterator<const char*>(char_ptr))`
|
||||
//! Returns an element of type const char*
|
||||
template <typename T>
|
||||
constexpr auto to_address(const T& ptr) noexcept
|
||||
{
|
||||
if constexpr (AZStd::Internal::pointer_traits_has_to_address_v<T>)
|
||||
{
|
||||
return pointer_traits<T>::to_address(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZStd::to_address(ptr.operator->());
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
/**
|
||||
@@ -81,7 +42,7 @@ namespace AZStd::Internal
|
||||
/**
|
||||
* Type has trivial destructor. We don't call it.
|
||||
*/
|
||||
template <class InputIterator, class ValueType = typename iterator_traits<InputIterator>::value_type, bool = is_trivially_destructible_v<ValueType>>
|
||||
template <class InputIterator, class ValueType = iter_value_t<InputIterator>, bool = is_trivially_destructible_v<ValueType>>
|
||||
struct destroy
|
||||
{
|
||||
static constexpr void range(InputIterator first, InputIterator last) { (void)first; (void)last; }
|
||||
@@ -163,7 +124,7 @@ namespace AZStd::Internal
|
||||
* Default object construction.
|
||||
*/
|
||||
// placement new isn't a core constant expression therefore it cannot be used in a constexpr function
|
||||
template<class InputIterator, class ValueType = typename iterator_traits<InputIterator>::value_type,
|
||||
template<class InputIterator, class ValueType = iter_value_t<InputIterator>,
|
||||
bool = is_trivially_constructible_v<ValueType>>
|
||||
struct construct
|
||||
{
|
||||
@@ -242,93 +203,125 @@ namespace AZStd::Internal
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Sequence copy. If we use optimized version we use memcpy.
|
||||
/**
|
||||
* Helper class to determine if we have apply fast copy. There are 2 conditions
|
||||
* Class to determine if we have apply fast copy. There are 2 conditions
|
||||
* - trivial copy ctor.
|
||||
* - all iterators satisfy the C++20 are contiguous iterator concept: pointers or iterator classes with
|
||||
* the iterator_concept typedef set to contiguous_iterator_tag
|
||||
* - all iterators satisfy the C++20 are contiguous iterator concept
|
||||
*/
|
||||
template<class Out, class = void>
|
||||
constexpr bool indirectly_trivially_copyable = false;
|
||||
template<class Out>
|
||||
constexpr bool indirectly_trivially_copyable<Out,
|
||||
enable_if_t<indirectly_readable<Out>>> = is_trivially_copyable_v<iter_value_t<Out>>;
|
||||
|
||||
template<class InputIterator, class ResultIterator>
|
||||
struct is_fast_copy_helper
|
||||
{
|
||||
using value_type = typename iterator_traits<ResultIterator>::value_type;
|
||||
static constexpr bool value = AZStd::is_trivially_copyable_v<value_type>
|
||||
&& Internal::satisfies_contiguous_iterator_concept_v<InputIterator>
|
||||
&& Internal::satisfies_contiguous_iterator_concept_v<ResultIterator>;
|
||||
};
|
||||
using is_fast_copy = bool_constant<indirectly_trivially_copyable<ResultIterator>
|
||||
&& contiguous_iterator<InputIterator>
|
||||
&& contiguous_iterator<ResultIterator>
|
||||
>;
|
||||
|
||||
// Use this trait to to determine copy mode, based on the iterator category and object copy properties,
|
||||
// Use it when when you call uninitialized_copy, Internal::copy, Internal::move, etc.
|
||||
template< typename InputIterator, typename ResultIterator >
|
||||
struct is_fast_copy
|
||||
: public ::AZStd::integral_constant<bool, ::AZStd::Internal::is_fast_copy_helper<InputIterator, ResultIterator>::value> {};
|
||||
template<class InputIterator, class ResultIterator>
|
||||
constexpr bool is_fast_copy_v = is_fast_copy<InputIterator, ResultIterator>::value;
|
||||
|
||||
|
||||
// is_fast_copy argument is no longer used.
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
constexpr ForwardIterator copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
constexpr ForwardIterator copy(InputIterator first, InputIterator last, ForwardIterator result, bool)
|
||||
{
|
||||
InputIterator iter(first);
|
||||
for (; iter != last; ++result, ++iter)
|
||||
if constexpr (is_fast_copy_v<InputIterator, ForwardIterator>)
|
||||
{
|
||||
*result = *iter;
|
||||
}
|
||||
// Specialized copy for contiguous iterators which are trivially copyable
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
#if az_has_builtin_memcpy
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Size of value types must match for a trivial copy");
|
||||
__builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
#else
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
*result = *first;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Size of value types must match for a trivial copy");
|
||||
AZ_Assert((static_cast<const void*>(&*result) < static_cast<const void*>(&*first))
|
||||
|| (static_cast<const void*>(&*result) >= static_cast<const void*>(&*first + numElements)),
|
||||
"AZStd::copy memory overlaps use AZStd::copy_backward!");
|
||||
::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
*result = *first;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized copy for contiguous iterators (pointers) and trivial copy type.
|
||||
// This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
inline ForwardIterator copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
{
|
||||
// \todo Make sure memory ranges don't overlap, otherwise people should use move and move_backward.
|
||||
static_assert(sizeof(typename iterator_traits<InputIterator>::value_type) == sizeof(typename iterator_traits<ForwardIterator>::value_type), "Size of value types must match for a trivial copy");
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
AZ_Assert((static_cast<const void*>(&*result) < static_cast<const void*>(&*first)) || (static_cast<const void*>(&*result) >= static_cast<const void*>(&*first + numElements)), "AZStd::copy memory overlaps use AZStd::copy_backward!");
|
||||
AZ_Assert((static_cast<const void*>(&*result + numElements) <= static_cast<const void*>(&*first)) || (static_cast<const void*>(&*result + numElements) > static_cast<const void*>(&*first + numElements)), "AZStd::copy memory overlaps use AZStd::copy_backward!");
|
||||
/*AZSTD_STL::*/ memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits<InputIterator>::value_type));
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
|
||||
// Copy backward.
|
||||
template <class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
constexpr BidirectionalIterator2 copy_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const false_type& /* is_fast_copy<BidirectionalIterator1,BidirectionalIterator2>() */)
|
||||
constexpr BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result, bool)
|
||||
{
|
||||
BidirectionalIterator1 iter(last);
|
||||
while (first != iter)
|
||||
if constexpr (is_fast_copy_v<BidirectionalIterator1, BidirectionalIterator2>)
|
||||
{
|
||||
*--result = *--iter;
|
||||
// Specialized copy for contiguous iterators which are trivially copyable
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
#if az_has_builtin_memmove
|
||||
static_assert(sizeof(iter_value_t<BidirectionalIterator1>) == sizeof(iter_value_t<BidirectionalIterator2>), "Size of value types must match for a trivial copy");
|
||||
result -= numElements;
|
||||
__builtin_memmove(to_address(result), to_address(first), numElements * sizeof(iter_value_t<BidirectionalIterator1>));
|
||||
#else
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
*--result = *--last;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(iter_value_t<BidirectionalIterator1>) == sizeof(iter_value_t<BidirectionalIterator2>), "Size of value types must match for a trivial copy");
|
||||
result -= numElements;
|
||||
AZ_Assert(((&*result + numElements) <= &*first) || ((&*result + numElements) > (&*first + numElements)), "AZStd::copy_backward memory overlaps use AZStd::copy!");
|
||||
::memmove(&*result, &*first, numElements * sizeof(iter_value_t<BidirectionalIterator1>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Specialized copy for contiguous iterators (pointers) and trivial copy type.
|
||||
// This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers
|
||||
template <class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
inline BidirectionalIterator2 copy_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const true_type& /* is_fast_copy<BidirectionalIterator1,BidirectionalIterator2>() */)
|
||||
{
|
||||
// \todo Make sure memory ranges don't overlap, otherwise people should use move and move_backward.
|
||||
static_assert(sizeof(typename iterator_traits<BidirectionalIterator1>::value_type) == sizeof(typename iterator_traits<BidirectionalIterator2>::value_type), "Size of value types must match for a trivial copy");
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
else
|
||||
{
|
||||
result -= numElements;
|
||||
AZ_Assert((&*result < &*first) || (&*result >= (&*first + numElements)), "AZStd::copy_backward memory overlaps use AZStd::copy!");
|
||||
AZ_Assert(((&*result + numElements) <= &*first) || ((&*result + numElements) > (&*first + numElements)), "AZStd::copy_backward memory overlaps use AZStd::copy!");
|
||||
/*AZSTD_STL::*/ memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits<BidirectionalIterator1>::value_type));
|
||||
while (first != last)
|
||||
{
|
||||
*--result = *--last;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class BidirectionalIterator1, class ForwardIterator>
|
||||
constexpr ForwardIterator reverse_copy(const BidirectionalIterator1& first, const BidirectionalIterator1& last, ForwardIterator dest)
|
||||
constexpr ForwardIterator reverse_copy(BidirectionalIterator1 first, BidirectionalIterator1 last, ForwardIterator dest)
|
||||
{
|
||||
BidirectionalIterator1 iter(last);
|
||||
while (iter != first)
|
||||
while (last != first)
|
||||
{
|
||||
*(dest++) = *(--iter);
|
||||
*(dest++) = *(--last);
|
||||
}
|
||||
|
||||
return dest;
|
||||
@@ -342,143 +335,209 @@ namespace AZStd
|
||||
* Specialized algorithms 20.4.4. We extend that by adding faster specialized versions when we have trivial assign type.
|
||||
*/
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
constexpr ForwardIterator uninitialized_copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
constexpr ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, bool)
|
||||
{
|
||||
InputIterator iter(first);
|
||||
for (; iter != last; ++result, ++iter)
|
||||
// Specialized copy for contiguous iterators which are trivially copyable
|
||||
if constexpr (Internal::is_fast_copy_v<InputIterator, ForwardIterator>)
|
||||
{
|
||||
::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*iter);
|
||||
}
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
#if az_has_builtin_memcpy
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Value type sizes must match for a trivial copy");
|
||||
__builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
#else
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(result)), *first);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Value type sizes must match for a trivial copy");
|
||||
::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(result)), *first);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized copy for contiguous iterators and trivial copy type.
|
||||
// This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
inline ForwardIterator uninitialized_copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
{
|
||||
static_assert(sizeof(typename iterator_traits<InputIterator>::value_type) == sizeof(typename iterator_traits<ForwardIterator>::value_type), "Value type sizes must match for a trivial copy");
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits<InputIterator>::value_type));
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
constexpr ForwardIterator uninitialized_copy(const InputIterator& first, const InputIterator& last, ForwardIterator result)
|
||||
constexpr ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result)
|
||||
{
|
||||
return uninitialized_copy(first, last, result, Internal::is_fast_copy<InputIterator, ForwardIterator>());
|
||||
return uninitialized_copy(first, last, result, {});
|
||||
}
|
||||
|
||||
// 25.3.1 Copy
|
||||
template<class InputIterator, class OutputIterator>
|
||||
constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
|
||||
{
|
||||
return AZStd::Internal::copy(first, last, result, AZStd::Internal::is_fast_copy<InputIterator, OutputIterator>());
|
||||
return Internal::copy(first, last, result, {});
|
||||
}
|
||||
|
||||
template <class BidirectionalIterator, class OutputIterator>
|
||||
constexpr OutputIterator reverse_copy(BidirectionalIterator first, BidirectionalIterator last, OutputIterator dest)
|
||||
{
|
||||
return AZStd::Internal::reverse_copy(first, last, dest);
|
||||
return Internal::reverse_copy(first, last, dest);
|
||||
}
|
||||
|
||||
template<class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result)
|
||||
{
|
||||
return AZStd::Internal::copy_backward(first, last, result, AZStd::Internal::is_fast_copy<BidirectionalIterator1, BidirectionalIterator2>());
|
||||
return Internal::copy_backward(first, last, result, {});
|
||||
}
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Sequence move. If we use optimized version we use memmove.
|
||||
// Sequence move
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
constexpr ForwardIterator move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
constexpr ForwardIterator move(InputIterator first, InputIterator last, ForwardIterator result, bool)
|
||||
{
|
||||
InputIterator iter(first);
|
||||
for (; iter != last; ++result, ++iter)
|
||||
// Specialized copy for contiguous iterators which are trivially copyable
|
||||
if constexpr (is_fast_copy_v<InputIterator, ForwardIterator>)
|
||||
{
|
||||
*result = AZStd::move(*iter);
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
#if az_has_builtin_memcpy
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Size of value types must match for a trivial copy");
|
||||
__builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
#else
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
*result = ::AZStd::move(*first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Size of value types must match for a trivial copy");
|
||||
AZ_Assert((static_cast<const void*>(&*result) < static_cast<const void*>(&*first))
|
||||
|| (static_cast<const void*>(&*result) >= static_cast<const void*>(&*first + numElements)),
|
||||
"AZStd::move memory overlaps use AZStd::move_backward!");
|
||||
::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
*result = ::AZStd::move(*first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Specialized copy for contiguous iterators (pointers) and trivial copy type.
|
||||
// This overload cannot be constexpr until builtin_memmove is added to MSVC compilers
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
inline ForwardIterator move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
{
|
||||
static_assert(sizeof(typename iterator_traits<InputIterator>::value_type) == sizeof(typename iterator_traits<ForwardIterator>::value_type), "Size of value types must match for a trivial copy");
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memmove(&*result, &*first, numElements * sizeof(typename iterator_traits<InputIterator>::value_type));
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
|
||||
// For generic iterators, move is the same as copy.
|
||||
template <class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
constexpr BidirectionalIterator2 move_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const false_type& /* is_fast_copy<BidirectionalIterator1,BidirectionalIterator2>() */)
|
||||
constexpr BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result, bool)
|
||||
{
|
||||
BidirectionalIterator1 iter(last);
|
||||
while (first != iter)
|
||||
// Specialized copy for contiguous iterators which are trivially copyable
|
||||
if constexpr (is_fast_copy_v<BidirectionalIterator1, BidirectionalIterator1>)
|
||||
{
|
||||
*--result = AZStd::move(*--iter);
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
#if az_has_builtin_memmove
|
||||
static_assert(sizeof(iter_value_t<BidirectionalIterator1>) == sizeof(iter_value_t<BidirectionalIterator2>), "Size of value types must match for a trivial copy");
|
||||
result -= numElements;
|
||||
__builtin_memmove(to_address(result), to_address(first), numElements * sizeof(iter_value_t<BidirectionalIterator1>));
|
||||
#else
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
*--result = ::AZStd::move(*--last);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(iter_value_t<BidirectionalIterator1>) == sizeof(iter_value_t<BidirectionalIterator2>), "Size of value types must match for a trivial copy");
|
||||
result -= numElements;
|
||||
AZ_Assert((static_cast<const void*>(&*result + numElements) <= static_cast<const void*>(&*first))
|
||||
|| (static_cast<const void*>(&*result + numElements) > static_cast<const void*>(&*first + numElements)),
|
||||
"AZStd::move_backward memory overlaps use AZStd::move!");
|
||||
::memmove(to_address(result), to_address(first), numElements * sizeof(iter_value_t<BidirectionalIterator1>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Specialized copy for contiguous iterators (pointers) and trivial copy type.
|
||||
// This overload cannot be constexpr until builtin_memmove is added to MSVC compilers
|
||||
template <class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
inline BidirectionalIterator2 move_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const true_type& /* is_fast_copy<BidirectionalIterator1,BidirectionalIterator2>() */)
|
||||
{
|
||||
// \todo Make sure memory ranges don't overlap, otherwise people should use move and move_backward.
|
||||
static_assert(sizeof(typename iterator_traits<BidirectionalIterator1>::value_type) == sizeof(typename iterator_traits<BidirectionalIterator2>::value_type), "Size of value types must match for a trivial copy");
|
||||
AZStd::size_t numElements = last - first;
|
||||
result -= numElements;
|
||||
if (numElements > 0)
|
||||
else
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memmove(&*result, &*first, numElements * sizeof(typename iterator_traits<BidirectionalIterator1>::value_type));
|
||||
while (first != last)
|
||||
{
|
||||
*--result = ::AZStd::move(*--last);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
constexpr ForwardIterator uninitialized_move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
constexpr ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result, bool)
|
||||
{
|
||||
InputIterator iter(first);
|
||||
|
||||
for (; iter != last; ++result, ++iter)
|
||||
// Specialized copy for contiguous iterators which are trivially copyable
|
||||
if constexpr (is_fast_copy_v<InputIterator, ForwardIterator>)
|
||||
{
|
||||
::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(AZStd::move(*iter));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Specialized copy for contiguous iterators and trivial move type. (since the object is POD we will just perform a copy)
|
||||
// This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers
|
||||
template <class InputIterator, class ForwardIterator>
|
||||
inline ForwardIterator uninitialized_move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy<InputIterator,ForwardIterator>() */)
|
||||
{
|
||||
static_assert(sizeof(typename iterator_traits<InputIterator>::value_type) == sizeof(typename iterator_traits<ForwardIterator>::value_type), "Value type sizes must match for a trivial copy");
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits<InputIterator>::value_type));
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
#if az_has_builtin_memcpy
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Value type sizes must match for a trivial copy");
|
||||
__builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
#else
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(result)), ::AZStd::move(*first));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(iter_value_t<InputIterator>) == sizeof(iter_value_t<ForwardIterator>), "Value type sizes must match for a trivial copy");
|
||||
::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t<InputIterator>));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result + numElements;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; first != last; ++result, ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(result)), ::AZStd::move(*first));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// end of sequence move.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -492,19 +551,19 @@ namespace AZStd
|
||||
template <typename InputIt, typename ForwardIt>
|
||||
ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt result)
|
||||
{
|
||||
return AZStd::Internal::uninitialized_move(first, last, result, AZStd::Internal::is_fast_copy<InputIt, InputIt>{});
|
||||
return AZStd::Internal::uninitialized_move(first, last, result, {});
|
||||
}
|
||||
// 25.3.2 Move
|
||||
template<class InputIterator, class OutputIterator>
|
||||
OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
|
||||
{
|
||||
return AZStd::Internal::move(first, last, result, AZStd::Internal::is_fast_copy<InputIterator, OutputIterator>());
|
||||
return AZStd::Internal::move(first, last, result, {});
|
||||
}
|
||||
|
||||
template<class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result)
|
||||
{
|
||||
return AZStd::Internal::move_backward(first, last, result, AZStd::Internal::is_fast_copy<BidirectionalIterator1, BidirectionalIterator2>());
|
||||
return AZStd::Internal::move_backward(first, last, result, {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,63 +575,77 @@ namespace AZStd::Internal
|
||||
* Helper class to determine if we have apply fast fill. There are 3 conditions
|
||||
* - trivial assign
|
||||
* - size of type == 1 (chars) to use memset
|
||||
* - contiguous iterators (pointers)
|
||||
* - contiguous iterators
|
||||
*/
|
||||
template<class Out, class = void>
|
||||
constexpr bool indirectly_copy_assignable = false;
|
||||
template<class Out>
|
||||
constexpr bool indirectly_copy_assignable<Out, enable_if_t<indirectly_readable<Out>>> =
|
||||
is_trivially_copy_assignable_v<iter_value_t<Out>> && sizeof(iter_value_t<Out>) == 1;
|
||||
|
||||
template<class Iterator>
|
||||
struct is_fast_fill_helper
|
||||
{
|
||||
using value_type = typename iterator_traits<Iterator>::value_type;
|
||||
constexpr static bool value = is_trivially_copy_assignable_v<value_type> && sizeof(value_type) == 1
|
||||
&& Internal::satisfies_contiguous_iterator_concept_v<Iterator>;
|
||||
};
|
||||
|
||||
// Use this trait to to determine fill mode, based on the iterator, value size, etc.
|
||||
// Use it when you call uninitialized_fill, uninitialized_fill_n, fill and fill_n.
|
||||
template< typename Iterator >
|
||||
struct is_fast_fill
|
||||
: public ::AZStd::integral_constant<bool, ::AZStd::Internal::is_fast_fill_helper<Iterator>::value>
|
||||
{};
|
||||
using is_fast_fill = bool_constant<indirectly_copy_assignable<Iterator> && contiguous_iterator<Iterator>>;
|
||||
template<class Iterator>
|
||||
constexpr bool is_fast_fill_v = is_fast_fill<Iterator>::value;
|
||||
|
||||
// The fast fill trait is no longer used
|
||||
// It is detected using C++20 concepts now
|
||||
template <class ForwardIterator, class T>
|
||||
constexpr void fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const false_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value, bool)
|
||||
{
|
||||
ForwardIterator iter(first);
|
||||
for (; iter != last; ++iter)
|
||||
if constexpr (is_fast_fill_v<ForwardIterator>)
|
||||
{
|
||||
*iter = value;
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
*first = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
::memset(to_address(first), reinterpret_cast<const unsigned char&>(value), numElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Specialized version for character types where memset can be used
|
||||
// This overload cannot be constexpr until builtin_memset is added to MSVC compilers
|
||||
template <class ForwardIterator, class T>
|
||||
inline void fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const true_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
{
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
else
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memset((void*)&*first, *reinterpret_cast<const unsigned char*>(&value), numElements);
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
*first = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
constexpr void fill_n(ForwardIterator first, Size numElements, const T& value, const false_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
constexpr void fill_n(ForwardIterator first, Size numElements, const T& value, bool)
|
||||
{
|
||||
for (; numElements--; ++first)
|
||||
if constexpr (is_fast_fill_v<ForwardIterator>)
|
||||
{
|
||||
*first = value;
|
||||
if (numElements)
|
||||
{
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; numElements--; ++first)
|
||||
{
|
||||
*first = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
::memset(to_address(first), reinterpret_cast<const unsigned char&>(value), numElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized version for character types where memset can be used to perform the fill
|
||||
// This overload cannot be constexpr until builtin_memset is added to MSVC compilers
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
inline void fill_n(ForwardIterator first, Size numElements, const T& value, const true_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
{
|
||||
if (numElements > 0)
|
||||
else
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memset(&*first, *reinterpret_cast<const unsigned char*>(&value), numElements);
|
||||
for (; numElements--; ++first)
|
||||
{
|
||||
*first = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,78 +653,85 @@ namespace AZStd::Internal
|
||||
namespace AZStd
|
||||
{
|
||||
template <class ForwardIterator, class T>
|
||||
constexpr void fill(const ForwardIterator& first, const ForwardIterator& last, const T& value)
|
||||
constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value)
|
||||
{
|
||||
Internal::fill(first, last, value, Internal::is_fast_fill<ForwardIterator>());
|
||||
Internal::fill(first, last, value, {});
|
||||
}
|
||||
|
||||
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
constexpr void fill_n(ForwardIterator first, Size numElements, const T& value)
|
||||
{
|
||||
Internal::fill_n(first, numElements, value, Internal::is_fast_fill<ForwardIterator>());
|
||||
Internal::fill_n(first, numElements, value, {});
|
||||
}
|
||||
|
||||
template <class ForwardIterator, class T>
|
||||
constexpr void uninitialized_fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const false_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
constexpr void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value, bool)
|
||||
{
|
||||
ForwardIterator iter(first);
|
||||
for (; iter != last; ++iter)
|
||||
if constexpr (Internal::is_fast_fill_v<ForwardIterator>)
|
||||
{
|
||||
::new (static_cast<void*>(&*iter)) typename iterator_traits<ForwardIterator>::value_type(value);
|
||||
size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
{
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(first)), value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
::memset(to_address(first), reinterpret_cast<const unsigned char&>(value), numElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized overload for types which meet the following criteria.
|
||||
// 1. Has it's iterator_traits<T>::iterator_concept type set to to contiguous_iterator_tag
|
||||
// 2. Is trivially assignable
|
||||
// 3. Has a sizeof(T) == 1
|
||||
// In such a case memset can be used to fill in the data
|
||||
// This overload cannot be constexpr until builtin_memset is added to MSVC compilers
|
||||
template <class ForwardIterator, class T>
|
||||
inline void uninitialized_fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const true_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
{
|
||||
AZStd::size_t numElements = last - first;
|
||||
if (numElements > 0)
|
||||
else
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memset(&*first, *reinterpret_cast<const unsigned char*>(&value), numElements);
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(first)), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
constexpr void uninitialized_fill(ForwardIterator first, Size numElements, const T& value)
|
||||
{
|
||||
return uninitialized_fill(first, numElements, value, Internal::is_fast_fill<ForwardIterator>());
|
||||
return uninitialized_fill(first, numElements, value, {});
|
||||
}
|
||||
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
constexpr void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value, const false_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
constexpr void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value, bool)
|
||||
{
|
||||
for (; numElements--; ++first)
|
||||
if constexpr (Internal::is_fast_fill_v<ForwardIterator>)
|
||||
{
|
||||
::new (static_cast<void*>(&*first)) typename iterator_traits<ForwardIterator>::value_type(value);
|
||||
if (numElements > 0)
|
||||
{
|
||||
if (az_builtin_is_constant_evaluated())
|
||||
{
|
||||
for (; numElements--; ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(first)), value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
::memset(to_address(first), reinterpret_cast<const unsigned char&>(value), numElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized overload for types which meet the following criteria.
|
||||
// 1. Has it's iterator_traits<T>::iterator_concept type set to to contiguous_iterator_tag
|
||||
// 2. Is trivially assignable
|
||||
// 3. Has a sizeof(T) == 1
|
||||
// In such a case memset can be used to fill in the data
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
inline void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value, const true_type& /* is_fast_fill<ForwardIterator>() */)
|
||||
{
|
||||
if (numElements)
|
||||
else
|
||||
{
|
||||
/*AZSTD_STL::*/
|
||||
memset(&*first, *reinterpret_cast<const unsigned char*>(&value), numElements);
|
||||
for (; numElements--; ++first)
|
||||
{
|
||||
construct_at(static_cast<iter_value_t<ForwardIterator>*>(to_address(first)), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ForwardIterator, class Size, class T>
|
||||
constexpr void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value)
|
||||
{
|
||||
return uninitialized_fill_n(first, numElements, value, Internal::is_fast_fill<ForwardIterator>());
|
||||
return uninitialized_fill_n(first, numElements, value, {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +38,12 @@ namespace AZStd
|
||||
{
|
||||
return Internal::INVOKE(Internal::InvokeTraits::forward<F>(f), Internal::InvokeTraits::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// models the invocable concept
|
||||
template <class F, class... Args>
|
||||
/*concept*/ constexpr bool invocable = is_invocable_v<F, Args...>;
|
||||
|
||||
// models the regular_invocable concept
|
||||
template <class F, class... Args>
|
||||
/*concept*/ constexpr bool regular_invocable = invocable<F, Args...>;
|
||||
}
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/base.h>
|
||||
#include <AzCore/std/typetraits/integral_constant.h>
|
||||
#include <AzCore/std/typetraits/void_t.h>
|
||||
#include <AzCore/std/typetraits/is_convertible.h>
|
||||
|
||||
#include <AzCore/std/typetraits/is_base_of.h> // use by ConstIteratorCast
|
||||
#include <AzCore/std/iterator/iterator_primitives.h>
|
||||
#include <AzCore/std/typetraits/is_base_of.h>
|
||||
#include <AzCore/std/typetraits/is_convertible.h>
|
||||
#include <AzCore/std/typetraits/remove_cv.h>
|
||||
#include <AzCore/std/typetraits/is_reference.h>
|
||||
#include <AzCore/std/typetraits/void_t.h>
|
||||
#include <AzCore/std/utils.h>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// Everything unless specified is based on C++ standard 24 (lib.iterators).
|
||||
// Everything unless specified is based on C++ standard 20 (lib.iterators).
|
||||
|
||||
/// Identifying tag for input iterators.
|
||||
using input_iterator_tag = std::input_iterator_tag;
|
||||
@@ -51,16 +51,6 @@ namespace AZStd::Internal
|
||||
typename Iterator::reference>
|
||||
> = true;
|
||||
|
||||
|
||||
template <typename Iterator, typename = void>
|
||||
inline constexpr bool has_iterator_category_v = false;
|
||||
template <typename Iterator>
|
||||
inline constexpr bool has_iterator_category_v<Iterator, AZStd::void_t<typename Iterator::iterator_category>> = true;
|
||||
template <typename Iterator, typename = void>
|
||||
inline constexpr bool has_iterator_concept_v = false;
|
||||
template <typename Iterator>
|
||||
inline constexpr bool has_iterator_concept_v<Iterator, AZStd::void_t<typename Iterator::iterator_concept>> = true;
|
||||
|
||||
// Iterator iterator_category alias must be one of the iterator category tags
|
||||
template <typename Iterator, bool>
|
||||
struct iterator_traits_category_tags
|
||||
@@ -98,6 +88,8 @@ namespace AZStd
|
||||
struct iterator_traits
|
||||
: Internal::iterator_traits_type_aliases<Iterator, Internal::has_iterator_type_aliases_v<Iterator>>
|
||||
{
|
||||
// Internal type alias meant to indicate that this is the primary template
|
||||
using _is_primary_template = iterator_traits;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -114,45 +106,6 @@ namespace AZStd
|
||||
using iterator_category = random_access_iterator_tag;
|
||||
using iterator_concept = contiguous_iterator_tag;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// iterator_category tag testers
|
||||
template <typename Iterator, typename Category, bool = has_iterator_category_v<iterator_traits<Iterator>>>
|
||||
inline constexpr bool has_iterator_category_convertible_to_v = false;
|
||||
template <typename Iterator, typename Category>
|
||||
inline constexpr bool has_iterator_category_convertible_to_v<Iterator, Category, true> = is_convertible_v<typename iterator_traits<Iterator>::iterator_category, Category>;
|
||||
|
||||
template <typename Iterator>
|
||||
inline constexpr bool is_input_iterator_v = has_iterator_category_convertible_to_v<Iterator, input_iterator_tag>;
|
||||
|
||||
template <typename Iterator>
|
||||
inline constexpr bool is_forward_iterator_v = has_iterator_category_convertible_to_v<Iterator, forward_iterator_tag>;
|
||||
|
||||
template <typename Iterator>
|
||||
inline constexpr bool is_bidirectional_iterator_v = has_iterator_category_convertible_to_v<Iterator, bidirectional_iterator_tag>;
|
||||
|
||||
template <typename Iterator>
|
||||
inline constexpr bool is_random_access_iterator_v = has_iterator_category_convertible_to_v<Iterator, random_access_iterator_tag>;
|
||||
|
||||
template <typename Iterator>
|
||||
inline constexpr bool is_contiguous_iterator_v = has_iterator_category_convertible_to_v<Iterator, contiguous_iterator_tag>;
|
||||
|
||||
template <typename Iterator>
|
||||
inline constexpr bool is_exactly_input_iterator_v = has_iterator_category_convertible_to_v<Iterator, input_iterator_tag> && !has_iterator_category_convertible_to_v<Iterator, forward_iterator_tag>;
|
||||
|
||||
// iterator concept testers
|
||||
template <typename Derived, typename Base>
|
||||
inline constexpr bool derived_from = is_base_of_v<Base, Derived> && is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
|
||||
template <typename Iterator, typename Concept, bool = has_iterator_concept_v<iterator_traits<Iterator>>>
|
||||
inline constexpr bool satisfies_iterator_concept = false;
|
||||
template <typename Iterator, typename Concept>
|
||||
inline constexpr bool satisfies_iterator_concept<Iterator, Concept, true> = derived_from<typename iterator_traits<Iterator>::iterator_concept, Concept>;
|
||||
template <typename Iterator>
|
||||
inline constexpr bool satisfies_contiguous_iterator_concept_v = satisfies_iterator_concept<Iterator, contiguous_iterator_tag>;
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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/ranges/iter_move.h>
|
||||
#include <AzCore/std/typetraits/common_reference.h>
|
||||
#include <AzCore/std/typetraits/conditional.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_integral.h>
|
||||
#include <AzCore/std/typetraits/is_object.h>
|
||||
#include <AzCore/std/typetraits/is_lvalue_reference.h>
|
||||
#include <AzCore/std/typetraits/is_rvalue_reference.h>
|
||||
#include <AzCore/std/typetraits/is_signed.h>
|
||||
#include <AzCore/std/typetraits/is_void.h>
|
||||
#include <AzCore/std/typetraits/remove_extent.h>
|
||||
#include <AzCore/std/typetraits/void_t.h>
|
||||
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// Bring in std utility functions into AZStd namespace
|
||||
using std::forward;
|
||||
|
||||
// forward declare iterator_traits to avoid iterator.h include
|
||||
template <class I>
|
||||
struct iterator_traits;
|
||||
}
|
||||
|
||||
// C++20 range traits for iteratable types
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// Models the can-reference concept which isn't available until C++20
|
||||
// template <class T, class = void>
|
||||
template <class T>
|
||||
constexpr bool can_reference = true;
|
||||
template <>
|
||||
inline constexpr bool can_reference<void> = false;
|
||||
|
||||
// Models the dereferencable concept which isn't available until C++20
|
||||
template <class T, class = void>
|
||||
/*concept*/ constexpr bool dereferenceable = false;
|
||||
template <class T>
|
||||
constexpr bool dereferenceable<T, enable_if_t<can_reference<decltype(*declval<T>())>>> = true;
|
||||
|
||||
template <class T, class = void>
|
||||
constexpr bool is_primary_template_v = false;
|
||||
template <class T>
|
||||
constexpr bool is_primary_template_v<T, enable_if_t<is_same_v<T, typename T::_is_primary_template>>> = true;
|
||||
|
||||
// indirectly readable traits
|
||||
template <typename T, typename = void>
|
||||
constexpr bool has_value_type_v = false;
|
||||
template <typename T>
|
||||
constexpr bool has_value_type_v<T, void_t<typename T::value_type>> = true;
|
||||
template <typename T, typename = void>
|
||||
constexpr bool has_element_type_v = false;
|
||||
template <typename T>
|
||||
constexpr bool has_element_type_v<T, void_t<typename T::element_type>> = true;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct object_type_value_requires {};
|
||||
template <typename T>
|
||||
struct object_type_value_requires<T, enable_if_t<is_object_v<T>>>
|
||||
{
|
||||
using value_type = remove_cv_t<T>;
|
||||
};
|
||||
template <typename T, typename = void>
|
||||
struct indirectly_readable_requires {};
|
||||
template <typename T>
|
||||
struct indirectly_readable_requires<T, enable_if_t<!is_primary_template_v<iterator_traits<T>>
|
||||
&& is_void_v<void_t<typename iterator_traits<T>::value_type>> >>
|
||||
{
|
||||
// iterator_traits has been been specialized
|
||||
using value_type = typename iterator_traits<T>::value_type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct indirectly_readable_requires<T, enable_if_t<is_primary_template_v<iterator_traits<T>>
|
||||
&& is_array_v<T>>>
|
||||
{
|
||||
using value_type = remove_cv_t<remove_extent_t<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct indirectly_readable_requires<T, enable_if_t<is_primary_template_v<iterator_traits<T>>
|
||||
&& has_value_type_v<T> && !has_element_type_v<T>>>
|
||||
: object_type_value_requires<typename T::value_type> {};
|
||||
|
||||
template <typename T>
|
||||
struct indirectly_readable_requires<T, enable_if_t<is_primary_template_v<iterator_traits<T>>
|
||||
&& has_element_type_v<T> && !has_value_type_v<T>>>
|
||||
: object_type_value_requires<typename T::element_type> {};
|
||||
|
||||
template <typename T>
|
||||
struct indirectly_readable_requires<T, enable_if_t<is_primary_template_v<iterator_traits<T>>
|
||||
&& has_value_type_v<T>&& has_element_type_v<T>
|
||||
&& same_as<remove_cv_t<typename T::element_type>, remove_cv_t<typename T::value_type>> >>
|
||||
: object_type_value_requires<typename T::value_type> {};
|
||||
|
||||
// incrementable traits
|
||||
template <typename T, typename = void>
|
||||
constexpr bool has_difference_type_v = false;
|
||||
template <typename T>
|
||||
constexpr bool has_difference_type_v<T, void_t<typename T::difference_type>> = true;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct object_type_difference_requires {};
|
||||
template <typename T>
|
||||
struct object_type_difference_requires<T, enable_if_t<is_object_v<T>>>
|
||||
{
|
||||
using difference_type = ptrdiff_t;
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
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>> >>
|
||||
{
|
||||
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>>>
|
||||
{
|
||||
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>())> >>
|
||||
{
|
||||
using difference_type = make_signed_t<decltype(declval<T>() - declval<T>())>;
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// indirectly_readable_traits for iter_value_t
|
||||
template <typename T>
|
||||
struct indirectly_readable_traits
|
||||
: Internal::indirectly_readable_requires<T> {};
|
||||
template <typename T>
|
||||
struct indirectly_readable_traits<T*>
|
||||
: Internal::object_type_value_requires<T> {};
|
||||
template <typename T>
|
||||
struct indirectly_readable_traits<const T>
|
||||
: indirectly_readable_traits<T> {};
|
||||
|
||||
template <typename T>
|
||||
using iter_value_t = typename indirectly_readable_traits<remove_cvref_t<T>>::value_type;
|
||||
|
||||
template <typename T>
|
||||
using iter_reference_t = enable_if_t<Internal::dereferenceable<T>, decltype(*declval<T&>())>;
|
||||
|
||||
// incrementable_traits for iter_difference_t
|
||||
template <typename T>
|
||||
struct incrementable_traits
|
||||
: Internal::incrementable_requires<T> {};
|
||||
template <typename T>
|
||||
struct incrementable_traits<T*>
|
||||
: Internal::object_type_difference_requires<T> {};
|
||||
template <typename T>
|
||||
struct incrementable_traits<const T>
|
||||
: incrementable_traits<T> {};
|
||||
|
||||
template <typename T>
|
||||
using iter_difference_t = typename incrementable_traits<remove_cvref_t<T>>::difference_type;
|
||||
|
||||
template <typename T>
|
||||
using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<T&>()));
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
// model the indirectly readable concept
|
||||
template <class In, class = void>
|
||||
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;
|
||||
}
|
||||
|
||||
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>&>>;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/base.h>
|
||||
|
||||
#include <AzCore/std/typetraits/conditional.h>
|
||||
|
||||
#include <AzCore/std/typetraits/is_class.h>
|
||||
#include <AzCore/std/typetraits/is_enum.h>
|
||||
#include <AzCore/std/typetraits/is_lvalue_reference.h>
|
||||
#include <AzCore/std/typetraits/is_rvalue_reference.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 in std utility functions into AZStd namespace
|
||||
using std::forward;
|
||||
}
|
||||
|
||||
// C++20 range traits for iteratable types
|
||||
namespace AZStd::ranges::Internal
|
||||
{
|
||||
void iter_move();
|
||||
|
||||
template <typename It, typename = void>
|
||||
constexpr bool iter_move_adl = false;
|
||||
|
||||
template <typename It>
|
||||
constexpr bool iter_move_adl<It, void_t<decltype(iter_move(declval<It>()))>> = true;
|
||||
|
||||
template <typename It, typename = void>
|
||||
constexpr bool is_class_or_enum_with_iter_move_adl = false;
|
||||
|
||||
template <typename It>
|
||||
constexpr bool is_class_or_enum_with_iter_move_adl<It, enable_if_t<iter_move_adl<It>
|
||||
&& (is_class_v<remove_cvref_t<It>> || is_enum_v<remove_cvref_t<It>>)>>
|
||||
= true;
|
||||
|
||||
struct iter_move_fn
|
||||
{
|
||||
template <typename It>
|
||||
constexpr auto operator()(It&& it) const
|
||||
->enable_if_t<is_class_or_enum_with_iter_move_adl<It>,
|
||||
decltype(iter_move(AZStd::forward<It>(it)))>
|
||||
{
|
||||
return iter_move(AZStd::forward<It>(it));
|
||||
}
|
||||
template <typename It>
|
||||
constexpr auto operator()(It&& it) const
|
||||
->enable_if_t<!is_class_or_enum_with_iter_move_adl<It>&& is_lvalue_reference_v<decltype(*AZStd::forward<It>(it))>,
|
||||
decltype(AZStd::move(*AZStd::forward<It>(it)))>
|
||||
{
|
||||
return AZStd::move(*AZStd::forward<It>(it));
|
||||
}
|
||||
template <typename It>
|
||||
constexpr auto operator()(It&& it) const
|
||||
->enable_if_t<!is_class_or_enum_with_iter_move_adl<It> && !is_lvalue_reference_v<decltype(*AZStd::forward<It>(it))>,
|
||||
decltype(*AZStd::forward<It>(it))>
|
||||
{
|
||||
return *AZStd::forward<It>(it);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZStd::ranges
|
||||
{
|
||||
inline namespace customization_point_object
|
||||
{
|
||||
inline constexpr auto iter_move = Internal::iter_move_fn{};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -74,7 +74,7 @@ namespace AZStd
|
||||
constexpr basic_fixed_string(const_pointer ptr);
|
||||
|
||||
// #6
|
||||
template<class InputIt, typename = enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_t>>>
|
||||
template<class InputIt, typename = enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_t>>>
|
||||
constexpr basic_fixed_string(InputIt first, InputIt last);
|
||||
|
||||
// #7
|
||||
@@ -146,7 +146,7 @@ namespace AZStd
|
||||
constexpr auto append(size_type count, Element ch) -> basic_fixed_string&;
|
||||
template<class InputIt>
|
||||
constexpr auto append(InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
|
||||
constexpr auto append(AZStd::initializer_list<Element> ilist) -> basic_fixed_string&;
|
||||
|
||||
constexpr auto assign(const basic_fixed_string& rhs) -> basic_fixed_string&;
|
||||
@@ -161,7 +161,7 @@ namespace AZStd
|
||||
constexpr auto assign(size_type count, Element ch) -> basic_fixed_string&;
|
||||
template<class InputIt>
|
||||
constexpr auto assign(InputIt first, InputIt last)
|
||||
->enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
|
||||
->enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
|
||||
|
||||
constexpr auto assign(AZStd::initializer_list<Element> ilist) -> basic_fixed_string&;
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace AZStd
|
||||
constexpr auto insert(const_iterator insertPos, size_type count, Element ch) -> iterator;
|
||||
template<class InputIt>
|
||||
constexpr auto insert(const_iterator insertPos, InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>;
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>;
|
||||
|
||||
constexpr auto insert(const_iterator insertPos, AZStd::initializer_list<Element> ilist) -> iterator;
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace AZStd
|
||||
constexpr auto replace(const_iterator first, const_iterator last, size_type count, Element ch) -> basic_fixed_string&;
|
||||
template<class InputIt>
|
||||
constexpr auto replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>;
|
||||
constexpr auto replace(const_iterator first, const_iterator last, AZStd::initializer_list<Element> ilist) -> basic_fixed_string&;
|
||||
|
||||
constexpr auto at(size_type offset) -> reference;
|
||||
|
||||
@@ -325,14 +325,14 @@ namespace AZStd
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
template<class InputIt>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::append(InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
|
||||
{
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
return append(AZStd::to_address(first), AZStd::distance(first, last));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be appended one by one into the buffer
|
||||
@@ -461,14 +461,14 @@ namespace AZStd
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
template<class InputIt>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::assign(InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
|
||||
{
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
return assign(AZStd::to_address(first), AZStd::distance(first, last));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be assigned one by one into the buffer
|
||||
@@ -627,15 +627,15 @@ namespace AZStd
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
template<class InputIt>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::insert(const_iterator insertPos,
|
||||
InputIt first, InputIt last)-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
|
||||
InputIt first, InputIt last)-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
|
||||
{ // insert [_First, _Last) at _Where
|
||||
size_type insertOffset = AZStd::distance(cbegin(), insertPos);
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
insert(insertOffset, AZStd::to_address(first), AZStd::distance(first, last));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be inserted one by one into the buffer
|
||||
@@ -927,14 +927,14 @@ namespace AZStd
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
template<class InputIt>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::replace(const_iterator first, const_iterator last,
|
||||
InputIt replaceFirst, InputIt replaceLast) -> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
|
||||
InputIt replaceFirst, InputIt replaceLast) -> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, basic_fixed_string&>
|
||||
{ // replace [first, last) with [replaceFirst,replaceLast)
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
return replace(first, last, AZStd::to_address(replaceFirst), AZStd::distance(replaceFirst, replaceLast));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be appended one by one into the buffer
|
||||
|
||||
@@ -114,28 +114,23 @@ namespace AZStd
|
||||
assign(count, ch);
|
||||
}
|
||||
|
||||
template<class InputIt, typename = enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_t>>>
|
||||
template<class InputIt, typename = enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_t>>>
|
||||
inline basic_string(InputIt first, InputIt last, const Allocator& alloc = Allocator())
|
||||
: m_storage{ skip_element_tag{}, alloc }
|
||||
{ // construct from [first, last)
|
||||
assign(first, last);
|
||||
}
|
||||
|
||||
inline basic_string(const_pointer first, const_pointer last)
|
||||
{ // construct from [first, last), const pointers
|
||||
assign(first, last - first);
|
||||
}
|
||||
|
||||
inline basic_string(const this_type& rhs)
|
||||
: m_storage{ skip_element_tag{}, rhs.m_storage.second() }
|
||||
{
|
||||
assign(rhs, 0, npos);
|
||||
assign(rhs);
|
||||
}
|
||||
|
||||
inline basic_string(this_type&& rhs)
|
||||
: m_storage{ skip_element_tag{}, AZStd::move(rhs.m_storage.second()) }
|
||||
: m_storage{ skip_element_tag{}, rhs.m_storage.second() }
|
||||
{
|
||||
assign(AZStd::forward<this_type>(rhs));
|
||||
assign(AZStd::move(rhs));
|
||||
}
|
||||
|
||||
inline basic_string(const this_type& rhs, size_type rhsOffset, size_type count = npos)
|
||||
@@ -251,14 +246,14 @@ namespace AZStd
|
||||
|
||||
template<class InputIt>
|
||||
inline auto append(InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, this_type&>
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, this_type&>
|
||||
{ // append [first, last)
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
return append(AZStd::to_address(first), AZStd::distance(first, last));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be appended one by one into the buffer
|
||||
@@ -299,7 +294,7 @@ namespace AZStd
|
||||
|
||||
inline this_type& assign(const this_type& rhs)
|
||||
{
|
||||
return assign(rhs, 0, npos);
|
||||
return this != &rhs ? assign(rhs, 0, npos) : *this;
|
||||
}
|
||||
|
||||
inline this_type& assign(basic_string_view<Element, Traits> view)
|
||||
@@ -319,7 +314,8 @@ namespace AZStd
|
||||
pointer rhsData = rhs.data();
|
||||
// Memmove the right hand side string data if it is using the short string optimization
|
||||
// Otherwise set the pointer to the right hand side
|
||||
if (rhs.m_storage.first().ShortStringOptimizationActive())
|
||||
if (rhs.m_storage.first().ShortStringOptimizationActive() ||
|
||||
(get_allocator() != rhs.get_allocator() && !allocator_traits<allocator_type>::propagate_on_container_move_assignment::value))
|
||||
{
|
||||
Traits::move(data, rhsData, rhs.size() + 1); // string + null-terminator
|
||||
}
|
||||
@@ -395,14 +391,14 @@ namespace AZStd
|
||||
|
||||
template<class InputIt>
|
||||
auto assign(InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, this_type&>
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, this_type&>
|
||||
{
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
return assign(AZStd::to_address(first), AZStd::distance(first, last));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// forward iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be assigned one by one into the buffer
|
||||
@@ -431,7 +427,7 @@ namespace AZStd
|
||||
inputCopy.push_back(static_cast<Element>(*first));
|
||||
}
|
||||
|
||||
return assign(inputCopy.c_str(), inputCopy.size());
|
||||
return assign(AZStd::move(inputCopy));
|
||||
}
|
||||
}
|
||||
inline this_type& insert(size_type offset, const this_type& rhs) { return insert(offset, rhs, 0, npos); }
|
||||
@@ -539,15 +535,15 @@ namespace AZStd
|
||||
|
||||
template<class InputIt>
|
||||
auto insert(const_iterator insertPos, InputIt first, InputIt last)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, iterator>
|
||||
{ // insert [_First, _Last) at _Where
|
||||
size_type insertOffset = AZStd::distance(cbegin(), insertPos);
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
insert(insertOffset, AZStd::to_address(first), AZStd::distance(first, last));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be inserted one by one into the buffer
|
||||
@@ -834,14 +830,14 @@ namespace AZStd
|
||||
|
||||
template<class InputIt>
|
||||
inline auto replace(const_iterator first, const_iterator last, InputIt replaceFirst, InputIt replaceLast)
|
||||
-> enable_if_t<Internal::is_input_iterator_v<InputIt> && !is_convertible_v<InputIt, size_type>, this_type&>
|
||||
-> enable_if_t<input_iterator<InputIt> && !is_convertible_v<InputIt, size_type>, this_type&>
|
||||
{
|
||||
if constexpr (Internal::satisfies_contiguous_iterator_concept_v<InputIt>
|
||||
if constexpr (contiguous_iterator<InputIt>
|
||||
&& is_same_v<typename AZStd::iterator_traits<InputIt>::value_type, value_type>)
|
||||
{
|
||||
return replace(first, last, AZStd::to_address(replaceFirst), AZStd::distance(replaceFirst, replaceLast));
|
||||
}
|
||||
else if constexpr (Internal::is_forward_iterator_v<InputIt>)
|
||||
else if constexpr (forward_iterator<InputIt>)
|
||||
{
|
||||
// Input Iterator pointer type doesn't match the const_pointer type
|
||||
// So the elements need to be appended one by one into the buffer
|
||||
@@ -1031,12 +1027,19 @@ namespace AZStd
|
||||
// same allocator, swap storage
|
||||
m_storage.first().swap(rhs.m_storage.first());
|
||||
}
|
||||
else if (allocator_traits<allocator_type>::propagate_on_container_swap::value)
|
||||
{
|
||||
// The allocator propagates on swap, so the allocators can be swapped
|
||||
m_storage.first().swap(rhs.m_storage.first());
|
||||
using AZStd::swap;
|
||||
swap(m_storage.second(), rhs.m_storage.second());
|
||||
}
|
||||
else
|
||||
{
|
||||
// different allocator, do multiple assigns
|
||||
this_type tmp = *this;
|
||||
*this = rhs;
|
||||
rhs = tmp;
|
||||
this_type tmp = AZStd::move(*this);
|
||||
*this = AZStd::move(rhs);
|
||||
rhs = AZStd::move(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/ranges/ranges.h>
|
||||
#include <AzCore/std/createdestroy.h>
|
||||
#include <AzCore/std/iterator.h>
|
||||
#include <AzCore/std/limits.h>
|
||||
@@ -613,8 +614,9 @@ namespace AZStd
|
||||
{}
|
||||
|
||||
template <typename It, typename End, typename = AZStd::enable_if_t<
|
||||
Internal::satisfies_contiguous_iterator_concept_v<It>
|
||||
&& is_same_v<typename AZStd::iterator_traits<It>::value_type, value_type>
|
||||
contiguous_iterator<It>
|
||||
&& sized_sentinel_for<End, It>
|
||||
&& is_same_v<iter_value_t<It>, value_type>
|
||||
&& !is_convertible_v<End, size_type>>
|
||||
>
|
||||
constexpr basic_string_view(It first, End last)
|
||||
@@ -961,23 +963,6 @@ namespace AZStd
|
||||
using string_view = basic_string_view<char>;
|
||||
using wstring_view = basic_string_view<wchar_t>;
|
||||
|
||||
template<class Element, class Traits = AZStd::char_traits<Element>>
|
||||
using basic_const_string = basic_string_view<Element, Traits>;
|
||||
using const_string = string_view;
|
||||
using const_wstring = wstring_view;
|
||||
|
||||
template <class Element, class Traits = AZStd::char_traits<Element>>
|
||||
constexpr typename basic_string_view<Element, Traits>::const_iterator begin(basic_string_view<Element, Traits> sv)
|
||||
{
|
||||
return sv.begin();
|
||||
}
|
||||
|
||||
template <class Element, class Traits = AZStd::char_traits<Element>>
|
||||
constexpr typename basic_string_view<Element, Traits>::const_iterator end(basic_string_view<Element, Traits> sv)
|
||||
{
|
||||
return sv.end();
|
||||
}
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
inline namespace string_view_literals
|
||||
@@ -1024,6 +1009,15 @@ namespace AZStd
|
||||
|
||||
} // namespace AZStd
|
||||
|
||||
namespace AZStd::ranges
|
||||
{
|
||||
template <class Element, class Traits>
|
||||
inline constexpr bool enable_borrowed_range<basic_string_view<Element, Traits>> = true;
|
||||
|
||||
template <class Element, class Traits>
|
||||
inline constexpr bool enable_view<basic_string_view<Element, Traits>> = true;
|
||||
}
|
||||
|
||||
//! Use this macro to simplify safe printing of a string_view which may not be null-terminated.
|
||||
//! Example: AZStd::string::format("Safely formatted: %.*s", AZ_STRING_ARG(myString));
|
||||
#define AZ_STRING_ARG(str) aznumeric_cast<int>(str.size()), str.data()
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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/config.h>
|
||||
#include <AzCore/std/typetraits/common_type.h>
|
||||
#include <AzCore/std/typetraits/conditional.h>
|
||||
#include <AzCore/std/typetraits/is_const.h>
|
||||
#include <AzCore/std/typetraits/is_convertible.h>
|
||||
#include <AzCore/std/typetraits/is_lvalue_reference.h>
|
||||
#include <AzCore/std/typetraits/is_rvalue_reference.h>
|
||||
#include <AzCore/std/typetraits/is_same.h>
|
||||
#include <AzCore/std/typetraits/is_volatile.h>
|
||||
#include <AzCore/std/typetraits/remove_reference.h>
|
||||
#include <AzCore/std/typetraits/remove_cvref.h>
|
||||
#include <AzCore/std/typetraits/void_t.h>
|
||||
#include <AzCore/std/utility/declval.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
template <class T, class U, template<class> class TQual, template<class> class UQual>
|
||||
struct basic_common_reference
|
||||
{};
|
||||
}
|
||||
|
||||
namespace AZStd::Internal
|
||||
{
|
||||
// const volatile and reference qualifier copy templates
|
||||
template <class T, class QualType>
|
||||
struct copy_cv_qual
|
||||
{
|
||||
using type = conditional_t<is_const_v<T>, conditional_t<is_volatile_v<T>, const volatile QualType, const QualType>,
|
||||
conditional_t<is_volatile_v<T>, volatile QualType, QualType>>;
|
||||
};
|
||||
|
||||
template <class T,class QualType>
|
||||
using copy_cv_qual_t = typename copy_cv_qual<T, QualType>::type;
|
||||
|
||||
static_assert(is_same_v<copy_cv_qual_t<int, float>, float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const int, float>, const float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<volatile int, float>, volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const volatile int, float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<int, const float>, const float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const int, const float>, const float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<volatile int, const float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const volatile int, const float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<int, volatile float>, volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const int, volatile float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<volatile int, volatile float>, volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const volatile int, volatile float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<int, const volatile float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const int, const volatile float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<volatile int, const volatile float>, const volatile float>);
|
||||
static_assert(is_same_v<copy_cv_qual_t<const volatile int, const volatile float>, const volatile float>);
|
||||
|
||||
template <class T, class QualType>
|
||||
struct copy_reference_qual
|
||||
{
|
||||
using type = conditional_t<is_lvalue_reference_v<T>, QualType&,
|
||||
conditional_t<is_rvalue_reference_v<T>, QualType&&, QualType>>;
|
||||
};
|
||||
|
||||
template <class T, class QualType>
|
||||
using copy_reference_qual_t = typename copy_reference_qual<T, QualType>::type;
|
||||
|
||||
static_assert(is_same_v<copy_reference_qual_t<int, float>, float>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int&, float>, float&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int&&, float>, float&&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int, float&>, float&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int&, float&>, float&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int&&, float&>, float&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int, float&&>, float&&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int&, float&&>, float&>);
|
||||
static_assert(is_same_v<copy_reference_qual_t<int&&, float&&>, float&&>);
|
||||
|
||||
template <class T, class QualType>
|
||||
using copy_cvref_qual_t = copy_cv_qual_t<copy_reference_qual_t<T, QualType>, QualType>;
|
||||
|
||||
template <class T>
|
||||
struct copy_qualifiers_from_t
|
||||
{
|
||||
template <class X>
|
||||
using templ = copy_cvref_qual_t<T, X>;
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
using cond_res = decltype(false ? declval<copy_cv_qual_t<remove_reference_t<T>, remove_reference_t<U>>&>()
|
||||
: declval<copy_cv_qual_t<remove_reference_t<U>, remove_reference_t<T>>&>());
|
||||
|
||||
// common reference helper templates begin
|
||||
template <class T, class U, typename = void>
|
||||
struct common_reference_base_reference_test;
|
||||
|
||||
// COMMON_REF is defined within the C++ standard at https://eel.is/c++draft/meta.trans.other#3.5
|
||||
template <class T, class U>
|
||||
struct common_reference_base_reference_test<T, U,
|
||||
enable_if_t<is_lvalue_reference_v<T>&& is_lvalue_reference_v<U>,
|
||||
void_t<cond_res<T,U>> >>
|
||||
{
|
||||
// Uses the ternary operator for determining the common type
|
||||
using type = cond_res<T, U>;
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct common_reference_base_reference_test<T, U, enable_if_t<is_rvalue_reference_v<T>&& is_rvalue_reference_v<U>>>
|
||||
{
|
||||
using C = remove_reference_t<typename common_reference_base_reference_test<remove_reference_t<T>&, remove_reference_t<U>&>::type>;
|
||||
using type = AZStd::enable_if_t<is_convertible_v<T, C>&& is_convertible_v<U, C>, C>;
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct common_reference_base_reference_test<T, U, enable_if_t<is_rvalue_reference_v<T>&& is_lvalue_reference_v<U>>>
|
||||
{
|
||||
// Turn rvalue references to const lvalue references
|
||||
using D = typename common_reference_base_reference_test<const remove_reference_t<T>&, remove_reference_t<U>&>::type;
|
||||
using type = AZStd::enable_if_t<is_convertible_v<T, D>, D>;
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct common_reference_base_reference_test<T, U, enable_if_t<is_lvalue_reference_v<T>&& is_rvalue_reference_v<U>>>
|
||||
{
|
||||
// Swap the parameters to call the 3rd specialization for common_reference_base_reference_test
|
||||
using type = typename common_reference_base_reference_test<U, T>::type;
|
||||
};
|
||||
|
||||
template <class T, class U, typename = void>
|
||||
constexpr bool has_reference_test = false;
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool has_reference_test<T, U, void_t<typename common_reference_base_reference_test<T, U>::type>> = true;
|
||||
|
||||
template <class T, class U, typename = void>
|
||||
struct basic_common_reference_test;
|
||||
|
||||
template <class T, class U>
|
||||
struct basic_common_reference_test<T, U, void_t<typename basic_common_reference<remove_cvref_t<T>, remove_cvref_t<U>,
|
||||
copy_qualifiers_from_t<T>::template templ, copy_qualifiers_from_t<U>::template templ>::type>>
|
||||
{
|
||||
using type = typename basic_common_reference<remove_cvref_t<T>, remove_cvref_t<U>,
|
||||
copy_qualifiers_from_t<T>::template templ, copy_qualifiers_from_t<U>::template templ>::type;
|
||||
};
|
||||
|
||||
template <class T, class U, typename = void>
|
||||
constexpr bool has_basic_common_reference_test = false;
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool has_basic_common_reference_test<T, U,
|
||||
void_t<typename basic_common_reference_test<T, U>::type>> = true;
|
||||
|
||||
template <class T, class U, typename = void>
|
||||
constexpr bool has_condition_result_test = false;
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool has_condition_result_test<T, U, void_t<decltype(false ? declval<T>() : declval<U>())>> = true;
|
||||
|
||||
template <class T, class U, typename = void>
|
||||
struct common_reference_base_test
|
||||
{};
|
||||
|
||||
template <class T, class U>
|
||||
struct common_reference_base_test<T, U, enable_if_t<has_reference_test<T, U>>>
|
||||
: common_reference_base_reference_test<T, U>
|
||||
{};
|
||||
template <class T, class U>
|
||||
struct common_reference_base_test<T, U, enable_if_t<!has_reference_test<T, U>
|
||||
&& has_basic_common_reference_test<T, U>>>
|
||||
: basic_common_reference_test<T, U>
|
||||
{};
|
||||
template <class T, class U>
|
||||
struct common_reference_base_test<T, U, enable_if_t<!has_reference_test<T, U>
|
||||
&& !has_basic_common_reference_test<T, U> && has_condition_result_test<T,U>>>
|
||||
{
|
||||
using type = decltype(false ? declval<T>() : declval<U>());
|
||||
};
|
||||
template <class T, class U>
|
||||
struct common_reference_base_test<T, U, enable_if_t<!has_reference_test<T, U>
|
||||
&& !has_basic_common_reference_test<T, U> && !has_condition_result_test<T, U>>>
|
||||
: common_type<T, U>
|
||||
{};
|
||||
|
||||
template <class... T>
|
||||
struct common_reference_base
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct common_reference_base<T>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
template <class T, class U>
|
||||
struct common_reference_base<T, U>
|
||||
: common_reference_base_test<T, U>
|
||||
{};
|
||||
|
||||
template <class T, class U, class V, class... Rs>
|
||||
struct common_reference_base<T, U, V, Rs...>
|
||||
: common_reference_base<typename common_reference_base<T, U>::type, V, Rs...>
|
||||
{};
|
||||
}
|
||||
namespace AZStd
|
||||
{
|
||||
template <class... T>
|
||||
struct common_reference
|
||||
: Internal::common_reference_base<T...>
|
||||
{};
|
||||
|
||||
template <class... T>
|
||||
using common_reference_t = typename common_reference<T...>::type;
|
||||
|
||||
// models the common reference concept
|
||||
namespace Internal
|
||||
{
|
||||
template<class T, class U, typename = void>
|
||||
constexpr bool common_reference_with_impl = false;
|
||||
template<class T, class U>
|
||||
constexpr bool common_reference_with_impl<T, U, enable_if_t<
|
||||
same_as<common_reference_t<T, U>, common_reference_t<U, T>>
|
||||
&& convertible_to<T, common_reference_t<T, U>>
|
||||
&& convertible_to<U, common_reference_t<T, U>>
|
||||
>> = true;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
/*concept*/ constexpr bool common_reference_with = Internal::common_reference_with_impl<T, U>;
|
||||
}
|
||||
@@ -8,12 +8,26 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/typetraits/conditional.h>
|
||||
#include <AzCore/std/typetraits/intrinsics.h>
|
||||
#include <AzCore/std/typetraits/void_t.h>
|
||||
#include <AzCore/std/utility/declval.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
using std::is_convertible;
|
||||
using std::is_convertible_v;
|
||||
|
||||
// models the C++20 convertible_to concept
|
||||
namespace Internal
|
||||
{
|
||||
template<typename From, typename To, typename = void>
|
||||
constexpr bool convertible_to_impl = false;
|
||||
template<typename From, typename To>
|
||||
constexpr bool convertible_to_impl<From, To, enable_if_t<
|
||||
is_convertible_v<From, To>, void_t<decltype(static_cast<To>(declval<From>()))>>> = true;
|
||||
}
|
||||
template<typename From, typename To>
|
||||
constexpr bool is_convertible_v = std::is_convertible_v<From, To>;
|
||||
/*concept*/ constexpr bool convertible_to = Internal::convertible_to_impl<From, To>;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,4 +21,7 @@ namespace AZStd
|
||||
constexpr bool is_trivially_destructible_v = std::is_trivially_destructible<T>::value;
|
||||
template<class T>
|
||||
constexpr bool is_nothrow_destructible_v = std::is_nothrow_destructible<T>::value;
|
||||
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool destructible = is_nothrow_destructible_v<T>;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,7 @@ namespace AZStd
|
||||
{
|
||||
using std::is_floating_point;
|
||||
using std::is_floating_point_v;
|
||||
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool floating_point = is_floating_point_v<T>;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,7 @@ namespace AZStd
|
||||
{
|
||||
using std::is_integral;
|
||||
using std::is_integral_v;
|
||||
|
||||
template<class T>
|
||||
/*concept*/ constexpr bool integral = is_integral_v<T>;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,8 @@ namespace AZStd
|
||||
{
|
||||
using std::is_same;
|
||||
using std::is_same_v;
|
||||
|
||||
// models the same_as concept
|
||||
template <class T, class U>
|
||||
/*concept*/ constexpr bool same_as = is_same_v<T, U>;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <AzCore/std/typetraits/add_volatile.h>
|
||||
#include <AzCore/std/typetraits/alignment_of.h>
|
||||
#include <AzCore/std/typetraits/aligned_storage.h>
|
||||
#include <AzCore/std/typetraits/common_reference.h>
|
||||
#include <AzCore/std/typetraits/common_type.h>
|
||||
#include <AzCore/std/typetraits/conditional.h>
|
||||
#include <AzCore/std/typetraits/conjunction.h>
|
||||
#include <AzCore/std/typetraits/decay.h>
|
||||
|
||||
+6
-1
@@ -7,4 +7,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.h>
|
||||
#include <utility>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
using std::declval;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
// rvalue
|
||||
// rvalue move
|
||||
template<class T>
|
||||
constexpr AZStd::remove_reference_t<T>&& move(T&& t)
|
||||
{
|
||||
return static_cast<AZStd::remove_reference_t<T>&&>(t);
|
||||
}
|
||||
}
|
||||
@@ -22,22 +22,15 @@
|
||||
#include <AzCore/std/typetraits/is_convertible.h>
|
||||
#include <AzCore/std/typetraits/is_lvalue_reference.h>
|
||||
#include <AzCore/std/typetraits/void_t.h>
|
||||
#include <AzCore/std/utility/declval.h>
|
||||
#include <AzCore/std/utility/move.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// rvalue
|
||||
// rvalue move
|
||||
template<class T>
|
||||
constexpr AZStd::remove_reference_t<T>&& move(T && t)
|
||||
{
|
||||
return static_cast<AZStd::remove_reference_t<T>&&>(t);
|
||||
}
|
||||
|
||||
using std::forward;
|
||||
using std::declval;
|
||||
using std::exchange;
|
||||
|
||||
template <class T>
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ namespace AZ
|
||||
const char* GetObbStoragePath() const { return m_obbStoragePath.c_str(); }
|
||||
|
||||
//! Get the dot separated package name for the current application.
|
||||
//! e.g. com.lumberyard.samples for SamplesProject
|
||||
//! e.g. org.o3de.samples for SamplesProject
|
||||
const char* GetPackageName() const { return m_packageName.c_str(); }
|
||||
|
||||
//! Get the app version code (android:versionCode in the manifest).
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user