diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfb98d4..ffb7147 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -115,12 +115,13 @@ jobs: fail-fast: false matrix: os: ${{ fromJson(needs.setup-matrix.outputs.matrix) }} - build-type: [Release] + build-type: [Development] steps: - name: Checkout code uses: actions/checkout@v5 with: + submodules: recursive fetch-depth: 0 - name: Set up MSVC Dev Cmd @@ -154,7 +155,16 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DFETCHCONTENT_BASE_DIR="$HOME/.cache/cmake_deps" + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DFETCHCONTENT_BASE_DIR="$HOME/.cache/cmake_deps" \ + -DGPBT_RUNNING_IN_CI=TRUE \ + -DGPBT_TESTS_ENABLED=FALSE \ + -DGPBT_LOG_PREFIX_ENABLED=FALSE \ + -DGPBT_LOG_VERBOSE_ENABLED=TRUE \ + -DGPBT_DUMP_TARGETS_PROPERTIES=TRUE \ + -DGPBT_THIRDPARTY_MODE=AUTO \ + -DGPBT_IS_MONOLITHIC=FALSE \ + -DGPBT_EXPORT_DEPENDENCY_GRAPH=FALSE - name: Build run: cmake --build build --config ${{ matrix.build-type }} --parallel --verbose @@ -182,7 +192,11 @@ jobs: os: ${{ fromJson(needs.setup-matrix.outputs.matrix) }} build-type: [Release] steps: - - uses: actions/checkout@v5 + - name: Checkout code + uses: actions/checkout@v5 + with: + submodules: recursive + - name: Download Build Tree uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e8da6bc..f4bc9a2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v5 + with: + submodules: recursive - name: Download All Artifacts uses: actions/download-artifact@v5 diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml index 8bbdac0..0f0de13 100644 --- a/.github/workflows/sync-docs.yml +++ b/.github/workflows/sync-docs.yml @@ -29,7 +29,7 @@ jobs: run: | mkdir -p gp-docs/docs/gp-engine cd gp-engine - find . -type f -path "*/docs/*" -print0 | while IFS= read -r -d '' file; do + find . -type f -path "*/docs/*" -not -path "./thirdparty/*" -print0 | while IFS= read -r -d '' file; do rel_path="${file#./}" dest_path=$(echo "$rel_path" | sed -e 's|^docs/||' -e 's|/docs/|/|g') target_file="../gp-docs/docs/gp-engine/$dest_path" diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5f62950 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "thirdparty/gp-build-tool"] + path = thirdparty/gp-build-tool + url = https://github.com/GraphicalPlayground/gp-build-tool.git diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..eef0d50 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,13 @@ +cff-version: 1.2.0 +message: "If you use this software or educational material, please cite it as below." +title: "Graphical Playground" +abstract: "An open-source platform and hybrid ecosystem dedicated to learning modern graphics engineering through hands-on experimentation and deconstructionist pedagogy." +authors: + - name: "The Graphical Playground Team" + address: "Lyon, France" + email: "support@graphical-playground.com" + affiliation: "Graphical Playground" +type: "software" +repository-code: "https://github.com/GraphicalPlayground/gp-engine" +url: "https://graphical-playground.com" +license: "Apache-2.0" diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dc90a6..b49a8d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # For more information, see https://graphical-playground/legal # mailto:support AT graphical-playground DOT com -cmake_minimum_required(VERSION 3.21.0) +cmake_minimum_required(VERSION 3.28.0) # Project Definition project(GraphicalPlayground @@ -11,82 +11,14 @@ project(GraphicalPlayground DESCRIPTION "Graphical Playground Engine, learning and prototyping platform for graphics programming." ) -# Enforce C++23 globally -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) # Forces standard C++ (no GCC extensions) +# Add the source directory to the module path and include the GPBT build tool module +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/gp-build-tool/source") +include(gp-build-tool) -# If not specified, build type is Release -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "[GP] Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") -endif() +# Apply the default policies and configurations for Graphical Playground targets. +gpApplyGraphicalPlaygroundDefaultPolicy() -# If not specified, export compile commands for IDEs -if(NOT CMAKE_EXPORT_COMPILE_COMMANDS) - message(STATUS "[GP] Enabling export of compile commands for IDEs.") - set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "Export compile commands." FORCE) -endif() - -# Build Shared Libraries (DLLs) by default? -# Set to OFF for Monolithic builds (Static Linking) -option(GP_BUILD_SHARED "Build Engine as DLLs" ON) -if(GP_BUILD_SHARED) - set(BUILD_SHARED_LIBS ON) - add_compile_definitions(GP_BUILD_DLL) # Global define for DLL logic -endif() - -# Output Directories (Clean bin/ folder structure) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/binaries/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/binaries/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/binaries/bin) - -# Enable Position Independent Code (PIC) for static libraries to allow linking into shared libraries on all platforms -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -# Put Debug/Release in subfolders (Bin/Debug, Bin/Release) -foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_SOURCE_DIR}/binaries/bin/${OUTPUTCONFIG}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_SOURCE_DIR}/binaries/lib/${OUTPUTCONFIG}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_SOURCE_DIR}/binaries/lib/${OUTPUTCONFIG}) -endforeach() - -# Include the module creation function -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") - -# Option to run tests on the Build Tool -option(GP_TEST_BUILD_TOOL "Run tests for the Build Tool" OFF) - -# Option for engine features -option(GP_ENABLE_PROFILING "Enable Tracy Profiler integration" ON) - -# Target options -option(GP_BUILD_TESTS "Build test targets" ON) -option(GP_BUILD_BENCHMARKS "Build benchmark targets" ON) -option(GP_BUILD_EXAMPLES "Build example targets" ON) -option(GP_BUILD_EDITOR "Build engine tools and offline compilers" ON) - -# Graphics API Options -option(GP_USE_VULKAN "Enable Vulkan support" ON) -option(GP_USE_OPENGL "Enable OpenGL support" ON) -option(GP_USE_METAL "Enable Metal support" ON) -option(GP_USE_D3D12 "Enable D3D12 support" ON) -option(GP_USE_D3D11 "Enable D3D11 support" ON) - -if (GP_TEST_BUILD_TOOL) - include(gp-build-tool/tests/gp-all.tests) - return() -endif() - -# Enable testing if tests are enabled for any target -if(GP_BUILD_TESTS) - enable_testing() -endif() - -# Add Subdirectories -add_subdirectory(thirdparty) -add_subdirectory(source) -add_subdirectory(examples) +# Start the GPBT build tool and auto-scan the source directory for targets to build. +gpStartBuildTool() + gpBuildToolAutoScan(source) +gpEndBuildTool() diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 0000000..3e6166f --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,127 @@ +# Graphical Playground Governance + +This document establishes the governance model for the **Graphical Playground** ecosystem, covering `gp-engine`, `gp-docs`, and associated tooling. The goal is an open, transparent community that welcomes contributions while maintaining technical and quality standards. + +The Project accepts contributions from independent developers, students, and researchers. A **Steering Committee (SC)** oversees development to ensure the engine remains useful to the broader community and stays true to one principle it will not trade away: code should be readable and teachable, not merely optimized. The SC determines where work belongs within the ecosystem, whether in the core engine, a community add-on, or a contributor's own project. + +This document refers to the project collectively as "the Project." + +> Graphical Playground intends to maintain high technical and quality standards. It is ultimately up to each user to verify that the software meets any requirements specific to their context. + +## Applicability + +This document applies to all repositories under the Graphical Playground organization, including `gp-engine`, `gp-docs`, and official tooling. It also applies to community repositories directly managed by the Project. Third-party forks and add-ons are governed by their creators. + +## Roles + +The community is organized into roles with distinct responsibilities and privileges. + +| Role | Available to | Description | +|-------------------|--------------------------------|----------------------------------------------------------------------------------------------------------| +| User | Anyone | Anyone who downloads, deploys, or learns from the engine. | +| Contributor | Anyone | Anyone who provides input to the Project: code, issues, documentation, tutorials, etc. | +| SC Member | Active, sustained contributors | Member of the Steering Committee (SC), responsible for guiding Project development. | +| Maintainer | Active SC members | Holds binding review and merge authority for specific repositories. Selected by the SC. | +| Community Manager | Active SC members | Responsible for executing SC decisions. Also a member of the SC. | + +Each role carries a set of privileges: + +| Role | Read/Clone | Propose pull request | Comment in tickets/discussions | Review | Binding review | Merge | Project decisions | Release | +|-------------------|------------|----------------------|--------------------------------|--------|----------------|-------|-------------------|---------| +| User | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| Contributor | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | +| SC Member | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | +| Maintainer | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | +| Community Manager | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +### User + +Anyone who downloads or uses Graphical Playground is a User. Users may read and clone any Project repository. A User who opens an issue or posts to the community becomes a Contributor. + +### Contributor + +Contributors are anyone who provides input to the Project. This includes code, issues, documentation, tutorials, and design work. The easiest way to get started is to join the Discussions or submit an Issue. + +Contributors must follow the [Code of Conduct](CODE_OF_CONDUCT.md) and the [Contributing Guide](CONTRIBUTING.md). + +### SC Member + +Steering Committee members guide the direction of the Project. As a group, they decide how proposed ideas fit within the ecosystem and whether contributions belong in the core engine, a community add-on, or a contributor's own project. SC members gather feedback through Discussions and Issues, and open Calls for Comments when wider input is needed before a decision is finalized. + +SC membership is open to active, sustained contributors and is determined by the existing SC. + +### Maintainer + +Maintainers hold binding review authority for specific repositories and are authorized to merge and release changes within their scope. They work alongside Community Managers to carry out SC decisions for their assigned repository. Maintainers are selected by the SC. + +### Community Manager + +Community Managers carry out SC decisions. This includes communicating outcomes, merging pull requests, and running Calls for Comments. Community Managers are also SC members and participate in all Project decisions. + +Pull requests are merged by Community Managers after receiving a binding review from at least one SC Member. + +## The decision-making process + +The Project must serve a broad community of learners and practitioners while staying true to its educational mission. The SC guides these decisions. + +Ideas are submitted as Issues and placed in "SC Review" on submission. Contributors should avoid developing substantial changes without SC approval, as unapproved work may be reworked or rejected. + +The SC evaluates each idea to answer: how does this fit within the Graphical Playground ecosystem? For small changes like bug reports, this is usually a fast decision. For larger or more disruptive proposals, the SC may produce one of the following outcomes: + +1. A Call for Comments +2. A recommendation for modifications +3. Acceptance into the core engine +4. Acceptance as a community add-on +5. A recommendation to develop the work within the contributor's own project + +Contributors can check the status of an item on the SC Resolution Board. + +### Call for Comments + +When the SC lacks sufficient context, a proposal is incomplete, or a change could affect a large portion of the community, the SC will open a Call for Comments in the Project's Discussions. Community input is gathered before the SC re-evaluates the proposal. + +### A recommendation for modifications + +The SC may respond with suggested changes to help an idea fit better within the engine's scope and standards. Receiving these recommendations usually means the contribution is wanted and the SC is helping it meet the bar for inclusion. + +### Acceptance into the core engine + +The SC has determined that the contribution belongs in the core Graphical Playground engine and development may begin. When evaluating acceptance, the SC applies the Project's foundational principle: the preferred implementation is the one that is easier to explain and teach, not simply the most compact or optimized. + +### Acceptance as a community add-on + +When an idea has merit but limited applicability to the broader community, the SC may recommend development as a community add-on. These add-ons are available to all users and released independently from the core engine. Should a community add-on demonstrate sufficient merit and code quality, it may be adopted into the official organization. + +### A recommendation to develop within a contributor's project + +Some ideas fit better within a contributor's own codebase. These may be changes with narrow community impact, broad breaking changes, or contributions that require looser standards than the Project allows. In these cases, the SC routes the idea back to the contributor. + +## Bypassing the process + +Since Graphical Playground is open source, nothing prevents a Contributor from submitting a pull request without SC approval. Community Managers will make a reasonable effort to evaluate these contributions and seek SC review. This effort is not guaranteed, and unsolicited contributions may be closed without feedback. The process above is always the recommended path. + +## Conflict resolution + +Technical disagreements are expected and healthy in graphics engineering. The Project resolves them by: + +1. Focusing on the code, not the contributor. +2. Applying the pedagogical principle: when two technically valid approaches exist, the one that is easier to explain and teach takes precedence. +3. Escalating to the SC: if Maintainers cannot reach consensus, the SC reviews the arguments and makes a final, binding decision. + +All participants must follow the [Code of Conduct](CODE_OF_CONDUCT.md). Harassment, gatekeeping, and elitism have no place here. + +## Communication channels + +GitHub is the primary communication medium for the Project. Issues and Discussions are the main venues for community conversation. The "Reviews" feature communicates feedback on specific contributions. The SC comments on Issues and pull requests to document decisions. Community Managers use the "Reviews" feature to provide the required binding pre-merge reviews. + +Announcements communicate Project-wide news to the entire community. Calls for Comments gather input on specific SC proposals. + +To report security concerns, follow the [Security Policy](SECURITY.md). + +## Changing this document + +This governance model is a living document. Any community member may propose a change via a pull request. Changes to this document require approval by a majority of the SC. + +## Acknowledgements + +The structure of this document was modeled after the [NASA F Prime Project Governance](https://github.com/nasa/fprime/blob/devel/GOVERNANCE.md). diff --git a/assets/engine/meshes/cube.obj b/assets/engine/meshes/cube.obj deleted file mode 100644 index 3bac126..0000000 --- a/assets/engine/meshes/cube.obj +++ /dev/null @@ -1,20 +0,0 @@ -# Simple Cube -o cube - -# Vertices -v -1.0 -1.0 1.0 -v 1.0 -1.0 1.0 -v -1.0 1.0 1.0 -v 1.0 1.0 1.0 -v -1.0 -1.0 -1.0 -v 1.0 -1.0 -1.0 -v -1.0 1.0 -1.0 -v 1.0 1.0 -1.0 - -# Faces (Quads) -f 1 2 4 3 -f 6 5 7 8 -f 3 4 8 7 -f 5 6 2 1 -f 2 6 8 4 -f 5 1 3 7 diff --git a/assets/engine/textures/checkerboard.png b/assets/engine/textures/checkerboard.png deleted file mode 100644 index 8fd020e..0000000 Binary files a/assets/engine/textures/checkerboard.png and /dev/null differ diff --git a/cmake/gp-build-tool.cmake b/cmake/gp-build-tool.cmake deleted file mode 100644 index 9a8c268..0000000 --- a/cmake/gp-build-tool.cmake +++ /dev/null @@ -1,280 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -# Options for the GP Build Tool -option(GP_BUILD_TOOL_VERBOSE "Enable verbose output for the GP Build Tool" OFF) - -# Version control -set(GP_BUILD_TOOL_VERSION_MAJOR 0) -set(GP_BUILD_TOOL_VERSION_MINOR 3) -set(GP_BUILD_TOOL_VERSION_PATCH 0) -set(GP_BUILD_TOOL_VERSION "${GP_BUILD_TOOL_VERSION_MAJOR}.${GP_BUILD_TOOL_VERSION_MINOR}.${GP_BUILD_TOOL_VERSION_PATCH}") - -# Include all the dependencies -include(gp-build-tool/internals/gp-logger.internal) -include(gp-build-tool/internals/gp-scope.internal) -include(gp-build-tool/internals/gp-stringify.internal) -include(gp-build-tool/internals/gp-targets.internal) -include(gp-build-tool/internals/gp-utils.internal) -include(gp-build-tool/internals/gp-api.internal) -include(gp-build-tool/internals/gp-scan.internal) -include(gp-build-tool/gp-thirdparty) - -# Startup banner, only printed once per CMake invocation -gpExecuteOnce("GPBT_STARTUP_BANNER" _shouldPrintBanner) -if(_shouldPrintBanner) - gpLog("${GP_MAGENTA}=======================================${GP_RESET}") - gpLog("${GP_MAGENTA} Graphical Playground Build Tool ${GP_RESET}") - gpLog("${GP_MAGENTA} v${GP_BUILD_TOOL_VERSION}${GP_RESET}") - gpLog("${GP_MAGENTA}=======================================${GP_RESET}") - gpLog("Initializing build environment...") -endif() - -# TODO: Add comments for every function of the gpbt API - -# @brief Starts the definition of a new build target. -# This macro initializes the target's scope and sets up necessary properties for the target. -# It also performs validation to ensure that the target name is unique and that we are not -# already in another target definition. -# @param[in] targetName The name of the target to create (e.g., "my_module") -# @param[in] targetType The type of the target (e.g., "module" or "executable") -macro(gpStartTarget targetName targetType) - _implGpStartTarget("${targetName}" "${targetType}") -endmacro() - -macro(gpStartModule targetName) - gpStartTarget("${targetName}" "module") -endmacro() - -macro(gpStartExecutable targetName) - gpStartTarget("${targetName}" "executable") -endmacro() - -macro(gpStartPlugin targetName) - gpStartTarget("${targetName}" "plugin") -endmacro() - -macro(gpEndTarget) - _implGpEndTarget() -endmacro() - -macro(gpEndModule) - _implGpEndTarget() -endmacro() - -macro(gpEndExecutable) - _implGpEndTarget() -endmacro() - -macro(gpEndPlugin) - _implGpEndTarget() -endmacro() - -macro(gpAddPrivateDefinitions definitions) - _implGpAddDefinitions("private" "${definitions}") -endmacro() - -macro(gpAddPublicDefinitions definitions) - _implGpAddDefinitions("public" "${definitions}") -endmacro() - -macro(gpAddInternalDefinitions definitions) - _implGpAddDefinitions("internal" "${definitions}") -endmacro() - -macro(gpAddPrivateDependency dependency) - _implGpAddDependency("private" "${dependency}") -endmacro() - -macro(gpAddPublicDependency dependency) - _implGpAddDependency("public" "${dependency}") -endmacro() - -macro(gpAddInternalDependency dependency) - _implGpAddDependency("internal" "${dependency}") -endmacro() - -macro(gpAddDynamicDependency dependency) - _implGpAddDependency("dynamic" "${dependency}") -endmacro() - -macro(gpAddPrivateCompileFlag flag) - _implGpAddCompileFlag("private" "${flag}") -endmacro() - -macro(gpAddPublicCompileFlag flag) - _implGpAddCompileFlag("public" "${flag}") -endmacro() - -macro(gpTargetReplaceCompileFlag newFlag conflicRegex visibility) - _implGpTargetReplaceCompileFlag("${newFlag}" "${conflicRegex}" "${visibility}") -endmacro() - -macro(gpAddPrivateIncludesPath includePath) - _implGpAddIncludesPath("private" "${includePath}") -endmacro() - -macro(gpAddPublicIncludesPath includePath) - _implGpAddIncludesPath("public" "${includePath}") -endmacro() - -macro(gpAddInternalIncludesPath includePath) - _implGpAddIncludesPath("internal" "${includePath}") -endmacro() - -macro(gpTargetSetTestsEnabled value) - if(GP_BUILD_TESTS) - _implGpSetBooleanTargetValue("gpTargetSetTestsEnabled" __targetEnableTests "${value}") - endif() -endmacro() - -macro(gpTargetSetBenchmarksEnabled value) - if(GP_BUILD_BENCHMARKS) - _implGpSetBooleanTargetValue("gpTargetSetBenchmarksEnabled" __targetEnableBenchmarks "${value}") - endif() -endmacro() - -macro(gpTargetSetExamplesEnabled value) - if(GP_BUILD_EXAMPLES) - _implGpSetBooleanTargetValue("gpTargetSetExamplesEnabled" __targetEnableExamples "${value}") - endif() -endmacro() - -macro(gpTargetSetISPCEnabled value) - _implGpSetBooleanTargetValue("gpTargetSetISPCEnabled" __targetEnableISPC "${value}") -endmacro() - -macro(gpTargetSetStrictWarningEnabled value) - _implGpSetBooleanTargetValue("gpTargetSetStrictWarningEnabled" __targetEnableStrictWarnings "${value}") -endmacro() - -macro(gpTargetSetIsHeaderOnly value) - _implGpSetBooleanTargetValue("gpTargetSetIsHeaderOnly" __targetIsHeaderOnly "${value}") -endmacro() - -macro(gpTargetAddSources) - gpFatalIfNotInNamedScope("target" "gpTargetAddSources can only be called within a target scope.") - list(APPEND __targetSources ${ARGN}) - gpVerbose("Added sources '${ARGN}' to target '${__targetName}'") -endmacro() - -macro(gpTargetExcludeSourcesRegex regexPattern) - gpFatalIfNotInNamedScope("target" "gpTargetExcludeSourcesRegex can only be called within a target scope.") - list(FILTER __targetSources EXCLUDE REGEX "${regexPattern}") - gpVerbose("Excluded sources matching regex '${regexPattern}' from target '${__targetName}'") -endmacro() - -macro(gpTargetExcludeDirectory directoryName) - gpTargetExcludeSourcesRegex("/${directoryName}/") -endmacro() - -macro(gpTargetExcludeFile fileName) - gpTargetExcludeSourcesRegex("/${fileName}$") -endmacro() - -macro(gpTargetAddPCHHeaders headerPath) - gpFatalIfNotInNamedScope("target" "gpTargetAddPCHHeaders can only be called within a target scope.") - list(APPEND __targetPCHs "${headerPath}") - gpVerbose("Added PCH header '${headerPath}' to target '${__targetName}'") -endmacro() - -macro(gpTargetAddSourcesFromDirectory directoryPath) - gpFatalIfNotInNamedScope("target" "gpTargetAddSourcesFromDirectory can only be called within a target scope.") - file(GLOB_RECURSE sourcesFromDir "${directoryPath}/*.cpp" "${directoryPath}/*.c" "${directoryPath}/*.cc") - list(APPEND __targetSources ${sourcesFromDir}) - gpVerbose("Added sources from directory '${directoryPath}' to target '${__targetName}'") - unset(sourcesFromDir) -endmacro() - -macro(gpSetTargetOutputName outputName) - gpFatalIfNotInNamedScope("target" "gpSetTargetOutputName can only be called within a target scope.") - set(__targetOutputName "${outputName}") - gpVerbose("Set output name for target '${__targetName}' to '${outputName}'") -endmacro() - -macro(gpExecutableAddResource resourcePath) - gpFatalIfNotInNamedScope("target" "gpExecutableAddResource can only be called within a target scope.") - list(APPEND __targetExecutableResourceFiles "${resourcePath}") - gpVerbose("Added resource file '${resourcePath}' to target '${__targetName}'") -endmacro() - -macro(gpExecutableSetEntryPoint entryPoint) - gpFatalIfNotInNamedScope("target" "gpExecutableSetEntryPoint can only be called within a target scope.") - set(__targetExecutableEntryPoint "${entryPoint}") - gpVerbose("Set entry point for executable target '${__targetName}' to '${entryPoint}'") -endmacro() - -macro(gpExecutableSetIsGUI isGui) - if (NOT "${__targetType}" STREQUAL "executable") - gpFatal("gpExecutableSetIsGUI can only be used within an executable target. Current target '${__targetName}' is of type '${__targetType}'.") - endif() - _implGpSetBooleanTargetValue("gpExecutableSetIsGUI" __targetExecutableIsGUI "${isGui}") -endmacro() - -macro(gpScanForTargets) - _implGpScanForTargets() -endmacro() - -# Platform-conditional dependencies — add a dependency only when building for the -# specified platform. Platform tokens: WINDOWS, LINUX, MAC, UNIX, ALL. -macro(gpAddPrivateDependencyOnPlatform dependency platform) - _implGpAddDependencyOnPlatform("private" "${dependency}" "${platform}") -endmacro() - -macro(gpAddPublicDependencyOnPlatform dependency platform) - _implGpAddDependencyOnPlatform("public" "${dependency}" "${platform}") -endmacro() - -macro(gpAddInternalDependencyOnPlatform dependency platform) - _implGpAddDependencyOnPlatform("internal" "${dependency}" "${platform}") -endmacro() - -macro(gpAddDynamicDependencyOnPlatform dependency platform) - _implGpAddDependencyOnPlatform("dynamic" "${dependency}" "${platform}") -endmacro() - -# Unity build — batch source files for faster cold compilation. -macro(gpTargetSetUnityBuildEnabled value) - _implGpSetBooleanTargetValue("gpTargetSetUnityBuildEnabled" __targetUnityBuild "${value}") -endmacro() - -# Custom IDE folder — overrides the default folder derived from the target type. -macro(gpTargetSetFolder folderPath) - gpFatalIfNotInNamedScope("target" "gpTargetSetFolder can only be called within a target scope.") - set(__targetCustomFolder "${folderPath}") - gpVerbose("Set custom IDE folder '${folderPath}' for target '${__targetName}'") -endmacro() - -# @brief Generates the CMake package config and install export for the entire engine. -# Call this once from the root CMakeLists.txt AFTER all add_subdirectory() calls. -# This enables downstream CMake projects to consume GP Engine via find_package(). -function(gpGenerateInstallExport) - include(CMakePackageConfigHelpers) - - install(EXPORT GPEngineTargets - FILE GPEngineTargets.cmake - NAMESPACE gp:: - DESTINATION lib/cmake/GPEngine - ) - - write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/GPEngineConfigVersion.cmake" - VERSION "${PROJECT_VERSION}" - COMPATIBILITY SameMajorVersion - ) - - configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GPEngineConfig.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/GPEngineConfig.cmake" - INSTALL_DESTINATION lib/cmake/GPEngine - ) - - install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/GPEngineConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/GPEngineConfigVersion.cmake" - DESTINATION lib/cmake/GPEngine - ) - - gpSuccess("Install export 'GPEngineTargets' configured. Run cmake --install to deploy.") -endfunction() diff --git a/cmake/gp-build-tool/gp-tests.cmake b/cmake/gp-build-tool/gp-tests.cmake deleted file mode 100644 index ad015b7..0000000 --- a/cmake/gp-build-tool/gp-tests.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-logger.internal) - -# @brief A simple testing framework for CMake to validate conditions during the build process. -# It provides macros to define test sections, run individual tests, and summarize results. -# @param[in] sectionName The name of the test section being defined. -macro(_gpStartTestsSection sectionName) - gpSetLogPrefixEnabled(FALSE) - gpNewLine() - gpLog(" === Running ${sectionName} Tests ===") - - # Initialize counters and state using a safer __GP prefix - set(__GP_TESTS_TOTAL 0) - set(__GP_TESTS_PASSED 0) - set(__GP_TESTS_FAILED 0) - set(__GP_TEST_FAILURE_MESSAGES "") -endmacro() - -# @brief Runs a test and updates the test counters based on the result. -# @param[in] testName A descriptive name for the test being run. -# @param[in] ARGN The condition to evaluate for the test. If it evaluates to true, the test is considered passed; otherwise, it is failed. -macro(_gpRunTest testName) - # Increment total tests - math(EXPR __GP_TESTS_TOTAL "${__GP_TESTS_TOTAL} + 1") - - # CRITICAL FIX: Evaluate the expression directly so STREQUAL, MATCHES, etc., work. - if(${ARGN}) - math(EXPR __GP_TESTS_PASSED "${__GP_TESTS_PASSED} + 1") - gpSuccess("Test passed: ${testName}") - else() - math(EXPR __GP_TESTS_FAILED "${__GP_TESTS_FAILED} + 1") - # Record the failure along with the evaluated arguments for easier debugging - set(__GP_TEST_FAILURE_MESSAGES "${__GP_TEST_FAILURE_MESSAGES} ${testName} (Failed condition: ${ARGN})\n") - gpWarning("Test failed: ${testName}") - endif() -endmacro() - -# @brief Summarizes the test results and reports any failures. If there are failed tests, it will stop the build process with an error. -macro(_gpEndTestsSection) - gpLog(" === Test Summary ===") - gpLog(" Total: ${__GP_TESTS_TOTAL}") - gpLog(" Passed: ${GP_GREEN}${__GP_TESTS_PASSED}${GP_RESET}") - gpLog(" Failed: ${GP_RED}${__GP_TESTS_FAILED}${GP_RESET}") - - if(__GP_TESTS_FAILED GREATER 0) - gpFatal(" === Some tests failed ===\n${__GP_TEST_FAILURE_MESSAGES}") - else() - gpLog(" === All tests passed successfully! ===") - endif() - - gpNewLine() - - # Cleanup internal state - unset(__GP_TESTS_TOTAL) - unset(__GP_TESTS_PASSED) - unset(__GP_TESTS_FAILED) - unset(__GP_TEST_FAILURE_MESSAGES) - gpRestorePreviousLogPrefixState() -endmacro() diff --git a/cmake/gp-build-tool/gp-thirdparty.cmake b/cmake/gp-build-tool/gp-thirdparty.cmake deleted file mode 100644 index 7991c38..0000000 --- a/cmake/gp-build-tool/gp-thirdparty.cmake +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-logger.internal) -include(FetchContent) - -# @brief A helper function to fetch and manage third-party dependencies. It first attempts to find the package locally, and if it is not found, it -# will fetch it from a specified Git repository and tag. This function also allows for custom build options to be injected into the CMake cache before configuration. -# @param[in] NAME The name of the dependency. This is used for logging and as the identifier for the FetchContent module. -# @param[in] GIT_REPOSITORY The URL of the Git repository to fetch the dependency from if it is not found locally. -# @param[in] GIT_TAG The specific Git tag or commit to fetch from the repository. -# @param[in] PACKAGE_NAME (Optional) The name of the package to find with find_package. If not specified, it defaults to the value of NAME. -# @param[in] REQUIRED_VERSION (Optional) The version requirement to pass to find_package when checking for a local installation of the package. -# @param[in] COMPONENTS (Optional) A list of components to pass to find_package when checking for a local installation of the package. -# @param[in] OPTIONS (Optional) A list of custom build options to set in the CMake cache before fetching the dependency. Each option should be in the format "KEY=VALUE". -function(gpFetchContent) - # Parse function arguments - cmake_parse_arguments( - ARG - "QUIET" - "NAME;GIT_REPOSITORY;GIT_TAG;PACKAGE_NAME;REQUIRED_VERSION" - "COMPONENTS;OPTIONS" - ${ARGN} - ) - - # Validate required arguments - if(NOT ARG_NAME) - gpFatal("gpFetchContent: 'NAME' argument is required.") - endif() - - if(NOT ARG_GIT_REPOSITORY) - gpFatal("gpFetchContent: 'GIT_REPOSITORY' argument is required for '${ARG_NAME}'.") - endif() - - if(NOT ARG_GIT_TAG) - gpFatal("gpFetchContent: 'GIT_TAG' argument is required for '${ARG_NAME}'.") - endif() - - # Default PACKAGE_NAME to NAME if not specified - if(NOT ARG_PACKAGE_NAME) - set(ARG_PACKAGE_NAME ${ARG_NAME}) - endif() - - gpLog("Resolving third-party dependency: '${ARG_NAME}'") - - # Construct find_package arguments - set(FIND_PACKAGE_ARGS ${ARG_PACKAGE_NAME}) - - if(ARG_REQUIRED_VERSION) - list(APPEND FIND_PACKAGE_ARGS ${ARG_REQUIRED_VERSION}) - endif() - - # Always use QUIET for the internal check to keep the console output clean - list(APPEND FIND_PACKAGE_ARGS QUIET) - - if(ARG_COMPONENTS) - list(APPEND FIND_PACKAGE_ARGS COMPONENTS ${ARG_COMPONENTS}) - endif() - - # Attempt to find the package locally - gpVerbose("Checking for local system installation of '${ARG_PACKAGE_NAME}'...") - find_package(${FIND_PACKAGE_ARGS}) - - # Check if package was found - if(${ARG_PACKAGE_NAME}_FOUND) - # Local installation found - log details - gpLog("Found local system installation of '${ARG_PACKAGE_NAME}'") - - if(${ARG_PACKAGE_NAME}_VERSION) - gpVerbose("Version: ${${ARG_PACKAGE_NAME}_VERSION}") - endif() - - if(${ARG_PACKAGE_NAME}_DIR) - gpVerbose("Location: ${${ARG_PACKAGE_NAME}_DIR}") - endif() - - else() - # Local installation not found - fetch from Git - gpVerbose("Local installation not found. Fetching from remote repository...") - gpVerbose("Repository: ${ARG_GIT_REPOSITORY} | Tag: ${ARG_GIT_TAG}") - - # Declare the external dependency - FetchContent_Declare( - ${ARG_NAME} - GIT_REPOSITORY ${ARG_GIT_REPOSITORY} - GIT_TAG ${ARG_GIT_TAG} - GIT_SHALLOW TRUE # Clone only the specified tag (faster) - GIT_PROGRESS ${GP_BUILD_TOOL_VERBOSE} # Show clone/fetch progress - SYSTEM TRUE # Treat as system dependency (suppress warnings) - ) - - # Inject custom build options into the CMake cache before configuration - if(ARG_OPTIONS) - gpVerbose("Applying custom build options for '${ARG_NAME}':") - foreach(_OPTION IN LISTS ARG_OPTIONS) - # Use regex to split "KEY=VALUE" into CMAKE_MATCH_1 (Key) and CMAKE_MATCH_2 (Value) - if(_OPTION MATCHES "^([^=]+)=(.*)$") - set(${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE STRING "GPBT Forced Dependency Option" FORCE) - gpVerbose(" -> ${CMAKE_MATCH_1} = ${CMAKE_MATCH_2}") - else() - gpFatal("Invalid option format '${_OPTION}' passed to gpFetchContent. Expected format is 'KEY=VALUE'.") - endif() - endforeach() - endif() - - # Log fetch operation start - gpLog("Downloading and configuring '${ARG_NAME}'...") - - # Fetch and make the dependency available - FetchContent_MakeAvailable(${ARG_NAME}) - - # Log successful fetch - gpLog("Successfully fetched and configured '${ARG_NAME}'") - - # Get the source and binary directories for additional context (visible in verbose mode) - FetchContent_GetProperties(${ARG_NAME} SOURCE_DIR SOURCE_DIR BINARY_DIR BINARY_DIR) - - if(SOURCE_DIR) - gpVerbose("Source directory: ${SOURCE_DIR}") - endif() - - if(BINARY_DIR) - gpVerbose("Build directory: ${BINARY_DIR}") - endif() - - endif() -endfunction() - -# @brief A helper function to set the FOLDER property of a target, which organizes the target into a folder in IDEs that support it (like Visual Studio or Xcode). -# This is purely for improving the organization and readability of the project structure within the IDE and does not affect the build process. -# @param[in] TARGET_NAME The name of the target to organize into a folder. -# @param[in] FOLDER_NAME The name of the folder to place the target in within the IDE. -function(gpSetTargetFolder TARGET_NAME FOLDER_NAME) - if(TARGET ${TARGET_NAME}) - get_target_property(_IS_ALIAS ${TARGET_NAME} ALIASED_TARGET) - - # If _IS_ALIAS is true, it contains the name of the aliased target. - # If it is false (NOTFOUND), it's a real target and safe to proceed. - if(NOT _IS_ALIAS) - get_target_property(_TARGET_TYPE ${TARGET_NAME} TYPE) - - # We cannot set the FOLDER property on Interface or Alias libraries - if(NOT _TARGET_TYPE STREQUAL "INTERFACE_LIBRARY" AND NOT _TARGET_TYPE STREQUAL "ALIAS_LIBRARY") - set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "${FOLDER_NAME}") - gpVerbose("Organized target '${TARGET_NAME}' into IDE folder '${FOLDER_NAME}'") - endif() - endif() - endif() -endfunction() - -# TODO: ADd gpThirdPartyFetchBinaries to handle binary fetching instead of whole source code diff --git a/cmake/gp-build-tool/internals/gp-api.internal.cmake b/cmake/gp-build-tool/internals/gp-api.internal.cmake deleted file mode 100644 index 7b69c81..0000000 --- a/cmake/gp-build-tool/internals/gp-api.internal.cmake +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-logger.internal) -include(gp-build-tool/internals/gp-scope.internal) -include(gp-build-tool/internals/gp-stringify.internal) - -# @brief Internal macro to add a compile definition to the target with the specified visibility. This is used to implement gpAddPublicDefinitions, gpAddPrivateDefinitions, and gpAddInternalDefinitions. -# @param[in] visibility The visibility level for the definition (public, private, or internal). -# @param[in] definitions The compile definition(s) to add to the target. Can be a single definition or a list of definitions. -# Each definition can be in the form 'KEY' or 'KEY=VALUE'. If only 'KEY' is provided, it will be treated as 'KEY=1'. -macro(_implGpAddDefinitions visibility definitions) - # Check that we're in a target scope - gpFatalIfNotInNamedScope("target" "gpAddDefinitions can only be called within a target scope.") - - # Set the available visibility levels for definitions - set(GPBT_AVAILABLE_VISIBILITY "public;private;internal") - - # Verify that the provided visibility is valid - if(NOT "${visibility}" IN_LIST GPBT_AVAILABLE_VISIBILITY) - gpFatal("Invalid visibility '${visibility}' for gpAddDefinitions. Valid options are: ${GPBT_AVAILABLE_VISIBILITY}") - endif() - - # Validate the format of each definition. Valid formats are: - # - KEY - # - KEY=VALUE - if("${definitions}" MATCHES "^[A-Za-z_][A-Za-z0-9_]*(=.+)?$") - # If the definition does not contain an '=', append '=1' to it - if(NOT "${definitions}" MATCHES "=") - set(definitions "${definitions}=1") - endif() - else() - gpFatal("Invalid format for definition '${definitions}'. Definitions must be in the form 'KEY' or 'KEY=VALUE', where KEY is a valid C preprocessor identifier.") - endif() - - # Append the definitions to the appropriate list based on visibility - if("${visibility}" STREQUAL "public") - list(APPEND __targetPublicCompileDefinitions ${definitions}) - elseif("${visibility}" STREQUAL "private") - list(APPEND __targetPrivateCompileDefinitions ${definitions}) - else() # internal - list(APPEND __targetInternalCompileDefinitions ${definitions}) - endif() - - # Log the added definition for debugging purposes - gpVerbose("Added compile definition '${definitions}' with visibility '${visibility}' to target '${__targetName}'") -endmacro() - -# @brief Internal macro to add a dependency to the target with the specified visibility. This is used to implement gpAddPublicDependency, gpAddPrivateDependency, gpAddInternalDependency, and gpAddDynamicDependency. -# @param[in] visibility The visibility level for the dependency (public, private, internal, or dynamic). -# @param[in] dependency The name of the dependency to add to the target. -macro(_implGpAddDependency visibility dependency) - # Check that we're in a target scope - gpFatalIfNotInNamedScope("target" "gpAddDependency can only be called within a target scope.") - - # Set the available visibility levels for dependencies - set(GPBT_AVAILABLE_VISIBILITY "public;private;internal;dynamic") - - # Verify that the provided visibility is valid - if(NOT "${visibility}" IN_LIST GPBT_AVAILABLE_VISIBILITY) - gpFatal("Invalid visibility '${visibility}' for gpAddDependency. Valid options are: ${GPBT_AVAILABLE_VISIBILITY}") - endif() - - # Check if the dependency is already listed in any of the dependency lists to prevent duplicates - if("${dependency}" IN_LIST __targetPublicDependencies) - gpFatal("Dependency '${dependency}' is already in the public dependencies list.") - elseif("${dependency}" IN_LIST __targetInternalDependencies) - gpFatal("Dependency '${dependency}' is already in the internal dependencies list.") - elseif("${dependency}" IN_LIST __targetPrivateDependencies) - gpFatal("Dependency '${dependency}' is already in the private dependencies list.") - elseif("${dependency}" IN_LIST __targetDynamicDependencies) - gpFatal("Dependency '${dependency}' is already in the dynamic dependencies list.") - endif() - - # Append the dependency to the appropriate list based on visibility - if("${visibility}" STREQUAL "public") - list(APPEND __targetPublicDependencies ${dependency}) - elseif("${visibility}" STREQUAL "private") - list(APPEND __targetPrivateDependencies ${dependency}) - elseif("${visibility}" STREQUAL "internal") - list(APPEND __targetInternalDependencies ${dependency}) - else() # dynamic - list(APPEND __targetDynamicDependencies ${dependency}) - endif() - - # Log the added dependency for debugging purposes - gpVerbose("Added dependency '${dependency}' with visibility '${visibility}' to target '${__targetName}'") -endmacro() - -# @brief internal macro to validate the format of a compile flag. -# @param[in] flag The compile flag to validate. -macro(_implGpValidateCompileFlagFormat flag) - # Validate the format of the compile flag. It should be a non-empty string without spaces. - if("${flag}" NOT MATCHES "^[^\\s]+$") - gpFatal("Invalid format for compile flag '${flag}'. Compile flags must be non-empty strings without spaces.") - endif() - - # Validate that MSVC specific compile flags that start with '/' are not used in non-MSVC environments. - if(NOT MSVC AND "${flag}" MATCHES "^/[A-Za-z]") - gpFatal("Compile flag '${flag}' appears to be an MSVC-specific flag (starts with '/'), but the current compiler is not MSVC. Please use appropriate flags for your compiler.") - endif() -endmacro() - -# @brief Internal macro to add a compile flag to the target with the specified visibility. This is used to implement gpAddPublicCompileFlag and gpAddPrivateCompileFlag. -# @param[in] visibility The visibility level for the compile flag (public or private). -# @param[in] flag The compile flag to add to the target. -macro(_implGpAddCompileFlag visibility flag) - # Check that we're in a target scope - gpFatalIfNotInNamedScope("target" "gpAddCompileFlag can only be called within a target scope.") - - # Set the available visibility levels for compile flags - set(GPBT_AVAILABLE_VISIBILITY "public;private") - - # Verify that the provided visibility is valid - if(NOT "${visibility}" IN_LIST GPBT_AVAILABLE_VISIBILITY) - gpFatal("Invalid visibility '${visibility}' for gpAddCompileFlag. Valid options are: ${GPBT_AVAILABLE_VISIBILITY}") - endif() - - # Validate the format of the compile flag before adding it to the target's properties - _implGpValidateCompileFlagFormat("${flag}") - - # Check if the compile flag is already listed in the appropriate list to prevent duplicates - if("${visibility}" STREQUAL "public") - if("${flag}" IN_LIST __targetPublicCompileOptions) - gpFatal("Compile flag '${flag}' is already in the public compile flags list.") - endif() - list(APPEND __targetPublicCompileOptions "${flag}") - else() # private - if("${flag}" IN_LIST __targetPrivateCompileOptions) - gpFatal("Compile flag '${flag}' is already in the private compile flags list.") - endif() - list(APPEND __targetPrivateCompileOptions "${flag}") - endif() - - # Log the added compile flag for debugging purposes - gpVerbose("Added compile flag '${flag}' with visibility '${visibility}' to target '${__targetName}'") -endmacro() - -# @brief Internal macro to replace existing compile flags that match a given regex with a new flag, based on visibility. This is used to implement gpTargetReplaceCompileFlag. -# @param[in] newFlag The new compile flag to add. -# @param[in] conflictRegex A regex pattern to identify which existing flags should be replaced by the new flag. -# @param[in] visibility The visibility level for the new compile flag (public or private). -macro(_implGpTargetReplaceCompileFlag newFlag conflicRegex visibility) - # Check that we're in a target scope - gpFatalIfNotInNamedScope("target" "gpTargetReplaceCompileFlag can only be called within a target scope.") - - # Validate the format of the compile flag before adding it to the target's properties - _implGpValidateCompileFlagFormat("${newFlag}") - - # Normalize visibility to lowercase for consistent comparison - string(TOLOWER "${visibility}" _visibility) - - # Set the available visibility levels for compile flags - set(GPBT_AVAILABLE_VISIBILITY "public;private") - - # Verify that the provided visibility is valid - if(NOT "${visibility}" IN_LIST GPBT_AVAILABLE_VISIBILITY) - gpFatal("Invalid visibility '${visibility}' for gpTargetReplaceCompileFlag. Valid options are: ${GPBT_AVAILABLE_VISIBILITY}") - endif() - - # Set the available visibility levels for compile flags - if ("${_visibility}" STREQUAL "private") - # Strip any existing flags that match the conflict regex - list(FILTER __targetPrivateCompileOptions EXCLUDE REGEX "${conflicRegex}") - # Safely add the new flag - gpAddPrivateCompileFlag("${newFlag}") - elseif ("${_visibility}" STREQUAL "public") - list(FILTER __targetPublicCompileOptions EXCLUDE REGEX "${conflicRegex}") - gpAddPublicCompileFlag("${newFlag}") - endif() - - # Log the replacement action for debugging purposes - gpVerbose("Replaced compile flags matching regex '${conflicRegex}' with '${newFlag}' for visibility '${visibility}' in target '${__targetName}'") -endmacro() - -# @brief Internal macro to add an include path to the target with the specified visibility. This is used to implement gpAddPublicIncludesPath, gpAddPrivateIncludesPath, and gpAddInternalIncludesPath. -# @param[in] visibility The visibility level for the include path (public, private, or internal). -# @param[in] includePath The include path to add to the target. -macro(_implGpAddIncludesPath visibility includePath) - # Check that we're in a target scope - gpFatalIfNotInNamedScope("target" "gpAddIncludesPath can only be called within a target scope.") - - # Set the available visibility levels for dependencies - set(GPBT_AVAILABLE_VISIBILITY "public;private;internal") - - # Verify that the provided visibility is valid - if(NOT "${visibility}" IN_LIST GPBT_AVAILABLE_VISIBILITY) - gpFatal("Invalid visibility '${visibility}' for gpAddIncludesPath. Valid options are: ${GPBT_AVAILABLE_VISIBILITY}") - endif() - - # Check if the include path is already listed in any of the include path lists to prevent duplicates - if("${includePath}" IN_LIST __targetPublicIncludes) - gpFatal("Include path '${includePath}' is already in the public include paths list.") - elseif("${includePath}" IN_LIST __targetInternalIncludes) - gpFatal("Include path '${includePath}' is already in the internal include paths list.") - elseif("${includePath}" IN_LIST __targetPrivateIncludes) - gpFatal("Include path '${includePath}' is already in the private include paths list.") - endif() - - # Append the include path to the appropriate list based on visibility - if("${visibility}" STREQUAL "public") - list(APPEND __targetPublicIncludes "${includePath}") - elseif("${visibility}" STREQUAL "private") - list(APPEND __targetPrivateIncludes "${includePath}") - elseif("${visibility}" STREQUAL "internal") - list(APPEND __targetInternalIncludes "${includePath}") - endif() - - # Log the added include path for debugging purposes - gpVerbose("Added include path '${includePath}' with visibility '${visibility}' to target '${__targetName}'") -endmacro() - -# @brief Internal macro to create a boolean target property based on a command. -# This is used to implement commands like gpTargetSetTestsEnabled, gpTargetSetBenchmarksEnabled, etc. -# @param[in] commandName The name of the command being implemented (for error messages and logging). -# @param[in] targetVariable The variable name where the boolean value will be stored for the target. -# @param[in] value The value to set (expected to be ON or OFF). -macro(_implGpSetBooleanTargetValue commandName targetVariable value) - # Check that we're in a target scope - gpFatalIfNotInNamedScope("target" "${commandName} can only be called within a target scope.") - - # Validate that the value is either ON or OFF (TRUE or FALSE) - set(GPBT_AVAILABLE_OPTIONS "ON;OFF;TRUE;FALSE") - if(NOT "${value}" IN_LIST GPBT_AVAILABLE_OPTIONS) - gpFatal("Invalid value '${value}' for ${commandName}. Valid options are: ON, OFF") - endif() - - # Set the target property based on the command - set(${targetVariable} "${value}") - - # Verbose logging for debugging purposes - gpVerbose("Set '${commandName}' to '${value}' for target '${__targetName}'") -endmacro() - -# @brief Internal macro to conditionally add a dependency only when the target platform matches. -# Supported platform tokens: WINDOWS, LINUX, MAC, UNIX, ALL. -# @param[in] visibility The visibility level for the dependency (public, private, internal, or dynamic). -# @param[in] dependency The name of the dependency to add. -# @param[in] platform The platform token controlling when the dependency is active. -macro(_implGpAddDependencyOnPlatform visibility dependency platform) - gpFatalIfNotInNamedScope("target" "gpAdd*DependencyOnPlatform can only be called within a target scope.") - - set(GPBT_VALID_PLATFORMS "WINDOWS;LINUX;MAC;UNIX;ALL") - string(TOUPPER "${platform}" _gpPlatformUpper) - - if(NOT "${_gpPlatformUpper}" IN_LIST GPBT_VALID_PLATFORMS) - gpFatal("Invalid platform '${platform}'. Valid options are: WINDOWS, LINUX, MAC, UNIX, ALL") - endif() - - set(_gpShouldAdd FALSE) - if("${_gpPlatformUpper}" STREQUAL "ALL") - set(_gpShouldAdd TRUE) - elseif("${_gpPlatformUpper}" STREQUAL "WINDOWS" AND WIN32) - set(_gpShouldAdd TRUE) - elseif("${_gpPlatformUpper}" STREQUAL "LINUX" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(_gpShouldAdd TRUE) - elseif("${_gpPlatformUpper}" STREQUAL "MAC" AND APPLE) - set(_gpShouldAdd TRUE) - elseif("${_gpPlatformUpper}" STREQUAL "UNIX" AND UNIX) - set(_gpShouldAdd TRUE) - endif() - - if(_gpShouldAdd) - _implGpAddDependency("${visibility}" "${dependency}") - else() - gpVerbose("Skipped dependency '${dependency}' (platform '${platform}' not active) for target '${__targetName}'") - endif() - - unset(_gpPlatformUpper) - unset(_gpShouldAdd) -endmacro() diff --git a/cmake/gp-build-tool/internals/gp-logger.internal.cmake b/cmake/gp-build-tool/internals/gp-logger.internal.cmake deleted file mode 100644 index 30deacf..0000000 --- a/cmake/gp-build-tool/internals/gp-logger.internal.cmake +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -# Generate the ASCII escape character -string(ASCII 27 gp_ESC) - -# Text Formatting -set(GP_RESET "${gp_ESC}[0m") -set(GP_BOLD "${gp_ESC}[1m") - -# Foreground Colors -set(GP_RED "${gp_ESC}[31m") -set(GP_GREEN "${gp_ESC}[32m") -set(GP_YELLOW "${gp_ESC}[33m") -set(GP_BLUE "${gp_ESC}[34m") -set(GP_MAGENTA "${gp_ESC}[35m") -set(GP_CYAN "${gp_ESC}[36m") -set(GP_WHITE "${gp_ESC}[37m") - -# Bold Foreground Colors -set(GP_BOLD_RED "${gp_ESC}[1;31m") -set(GP_BOLD_GREEN "${gp_ESC}[1;32m") -set(GP_BOLD_YELLOW "${gp_ESC}[1;33m") - -# Default state for the prefix -set(__GP_LOG_PREFIX_ENABLED TRUE CACHE INTERNAL "Enable or disable the [GPBT] log prefix") -set(__GP_PREVIOUS_LOG_PREFIX_ENABLED TRUE CACHE INTERNAL "Store the previous state of the log prefix for scope management") - -# @brief Enables or disables the [GPBT] prefix on all gpLog/gpWarning/gpFatal calls. -# @param[in] value TRUE to enable the prefix, FALSE to disable it. -function(gpSetLogPrefixEnabled value) - set(__GP_PREVIOUS_LOG_PREFIX_ENABLED ${__GP_LOG_PREFIX_ENABLED} CACHE INTERNAL "Store the previous state of the log prefix for scope management") - set(__GP_LOG_PREFIX_ENABLED ${value} CACHE INTERNAL "Enable or disable the [GPBT] log prefix") -endfunction() - -# @brief Restores the previous state of the log prefix enabled setting. Useful for ensuring that changes to the log prefix state are properly scoped. -function(gpRestorePreviousLogPrefixState) - set(__GP_LOG_PREFIX_ENABLED ${__GP_PREVIOUS_LOG_PREFIX_ENABLED} CACHE INTERNAL "Restore the previous state of the log prefix enabled setting") -endfunction() - -# @brief Internal function to format log messages with optional severity and prefix. -# @param[out] outVar The variable to store the formatted message in. -# @param[in] severityColor The color code for the severity level (e.g. ${GP_RED} for errors). -# @param[in] severityName The name of the severity level (e.g. "ERROR", "WARNING"). Can be empty for no severity. -macro(_gpFormatLogMessage outVar severityColor severityName) - set(_prefix "") - if(__GP_LOG_PREFIX_ENABLED) - set(_prefix "[GPBT] ") - endif() - - # Concatenate all passed arguments into a single string - # (so users can do gpLog("Value is: " ${MY_VAR})) - set(_msg_list ${ARGN}) - string(REPLACE ";" "" _msg "${_msg_list}") - - if("${severityName}" STREQUAL "") - set(${outVar} "${_prefix}${_msg}") - else() - set(${outVar} "${severityColor}${_prefix}${severityName}: ${_msg}${GP_RESET}") - endif() -endmacro() - -# @brief Prints a standard log message. -function(gpLog) - _gpFormatLogMessage(_formatted_msg "" "" ${ARGN}) - message(STATUS "${_formatted_msg}") -endfunction() - -# @brief Prints a success in green. -function(gpSuccess) - _gpFormatLogMessage(_formatted_msg "${GP_BOLD_GREEN}" "SUCCESS" ${ARGN}) - message(STATUS "${_formatted_msg}") -endfunction() - -# @brief Prints a warning in yellow WITHOUT a CMake stack trace. -function(gpWarning) - _gpFormatLogMessage(_formatted_msg "${GP_BOLD_YELLOW}" "WARNING" ${ARGN}) - # Using STATUS instead of WARNING prevents CMake from dumping the stack trace! - message(STATUS "${_formatted_msg}") -endfunction() - -# @brief Prints a fatal error in red WITHOUT a stack trace on the actual message, then halts. -function(gpFatal) - _gpFormatLogMessage(_formatted_msg "${GP_BOLD_RED}" "FATAL ERROR" ${ARGN}) - # Print the colored error nicely without a stack trace - message(STATUS "${_formatted_msg}") - - # We still MUST call FATAL_ERROR to stop CMake execution, but we pass a generic - # short message so the user focuses on your beautiful custom colored log above it. - message(FATAL_ERROR "Build halted. See the error above.") -endfunction() - -# @brief Prints a verbose message only if GP_BUILD_TOOL_VERBOSE is enabled. -function(gpVerbose) - if(GP_BUILD_TOOL_VERBOSE) - _gpFormatLogMessage(_formatted_msg "${GP_CYAN}" "VERBOSE" ${ARGN}) - message(STATUS "${_formatted_msg}") - endif() -endfunction() - -# @brief Prints a blank line for better readability in logs. -function(gpNewLine) - message(STATUS "") -endfunction(gpNewLine) diff --git a/cmake/gp-build-tool/internals/gp-scan.internal.cmake b/cmake/gp-build-tool/internals/gp-scan.internal.cmake deleted file mode 100644 index edb8170..0000000 --- a/cmake/gp-build-tool/internals/gp-scan.internal.cmake +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-utils.internal) -include(gp-build-tool/internals/gp-logger.internal) -include(gp-build-tool/internals/gp-scope.internal) - -# @brief Internal function to perform a topological sort of the registered targets based on their dependencies. This is used to determine the correct build order of the targets. -# It uses a depth-first search approach to sort the targets. If it detects a circular dependency, it will report an error and stop the configuration process. -# @param[out] outSortedList The output variable where the sorted list of targets will be stored. -function(_implGpSortTargets outSortedList) - # Retrieve the master list of all registered targets - get_property(registeredTargets GLOBAL PROPERTY GPBT_REGISTERED_TARGETS) - - # Verbose logging of the registered targets for debugging purposes - gpVerbose("Registered targets before sorting: ${registeredTargets}") - - # unsorted starts with all targets. sorted starts empty. - set(unsorted ${registeredTargets}) - set(sorted "") - - # Loop as long as we have unsorted targets AND we are making progress - set(progressMade TRUE) - while(unsorted AND progressMade) - set(progressMade FALSE) - set(nextUnsorted "") - - foreach(target IN LISTS unsorted) - # To upper snake case the target name for consistent property access - gpToUpperSnakeCase("${target}" targetUpper) - - # Fetch the combined dependencies for the current target - get_property(allDependencies GLOBAL PROPERTY GPBT_TARGET_${targetUpper}_ALL_DEPS) - - # Check if all of this target's dependencies are already in the sorted list - set(allDependenciesMet TRUE) - foreach(dependency IN LISTS allDependencies) - # We ONLY care about resolving dependencies that are registered GP targets. - # (This prevents the script from freezing if a target depends on an external OS library). - if(dependency IN_LIST registeredTargets) - if(NOT dependency IN_LIST sorted) - set(allDependenciesMet FALSE) - break() # Stop checking, we already know we can't sort this target yet - endif() - endif() - endforeach() - - if(allDependenciesMet) - # Success! All internal dependencies are met. Add to the sorted list. - list(APPEND sorted ${target}) - set(progressMade TRUE) # We successfully processed at least one target - else() - # Not ready yet. Push it to the next pass. - list(APPEND nextUnsorted ${target}) - endif() - endforeach() - - # Update the unsorted list for the next iteration of the while loop - set(unsorted ${nextUnsorted}) - endwhile() - - # Dependency validation: distinguish unresolved deps from true circular deps. - # An unresolved dep is one that was never registered at all (typo, missing module). - # A circular dep means every remaining target has at least one dep still in unsorted. - if(unsorted) - foreach(target IN LISTS unsorted) - gpToUpperSnakeCase("${target}" targetUpper) - get_property(allDependencies GLOBAL PROPERTY GPBT_TARGET_${targetUpper}_ALL_DEPS) - foreach(dependency IN LISTS allDependencies) - if(NOT dependency IN_LIST registeredTargets AND NOT dependency IN_LIST sorted) - gpWarning("Target '${target}' depends on '${dependency}' which is not a registered GP target. Check for typos or a missing add_subdirectory().") - endif() - endforeach() - endforeach() - gpFatal("Circular dependency detected! The following targets form an infinite dependency loop and cannot be ordered: ${unsorted}") - endif() - - # Return the sorted list to the caller's scope - set(${outSortedList} "${sorted}" PARENT_SCOPE) -endfunction() - -# @brief Internal recursive function to scan the source tree for modules. This function is called by _implGpScanForTargets and should not be called directly. -# It traverses the directory structure starting from the given directory, looking for CMakeLists.txt files that indicate the presence of a module. -# When it finds one, it registers the module and stops recursing that branch. If it doesn't find one, it continues to dive deeper into the subdirectories. -# @param[in] currentDirectory The directory to scan for modules. This should initially be called with the root source directory of the project. -function(_implGpScanRecursive currentDirectory) - file(GLOB entries RELATIVE ${currentDirectory} ${currentDirectory}/*) - - foreach(entry ${entries}) - set(fullPath "${currentDirectory}/${entry}") - - if(IS_DIRECTORY "${fullPath}") - if(EXISTS "${fullPath}/CMakeLists.txt") - # Found a module! Register it and STOP recursing this branch - # add_subdirectory uses paths relative to CMAKE_CURRENT_SOURCE_DIR - file(RELATIVE_PATH relativePath ${CMAKE_CURRENT_SOURCE_DIR} ${fullPath}) - add_subdirectory(${relativePath}) - else() - # No CMakeLists here, dive deeper into this subfolder - _implGpScanRecursive("${fullPath}") - endif() - endif() - endforeach() -endfunction() - -# @brief Main function to scan the source tree for modules, register them, sort them based on dependencies, and include their CMakeLists.txt files in the correct order. -# This function orchestrates the entire scanning and configuration process for the build tool. -function(_implGpScanForTargets) - # Set the current phase to REGISTRATION to allow modules to register themselves as we scan through the directories. - _gpSetCurrentPhase("REGISTRATION") - - # Scan the entire source tree for modules. - # Each module will register itself during this process, and we will build up a master list of all targets and their dependencies. - _implGpScanRecursive("${CMAKE_CURRENT_SOURCE_DIR}") - - # Now that we've registered all targets, we need to sort them based on their dependencies to determine the correct build order. - _implGpSortTargets(orderedTargetList) - - # Verbose logging of the final sorted target list for debugging purposes - gpVerbose("Final sorted target list: ${orderedTargetList}") - - # Finally, we transition to the CONFIGURATION phase, which allows modules to perform any necessary configuration steps now that - # we have a complete picture of all targets and their dependencies. - _gpSetCurrentPhase("CONFIGURATION") - - # Include each module's CMakeLists.txt in the correct order. This will allow them to configure their targets, - # knowing that all dependencies have been registered and sorted. - foreach(module ${orderedTargetList}) - string(REPLACE "/" "_" moduleClean "${module}") - gpToUpperSnakeCase("${moduleClean}" moduleUpper) - get_property(moduleLocation GLOBAL PROPERTY GPBT_TARGET_${moduleUpper}_LOCATION) - if (NOT moduleLocation) - gpFatal("Could not find location for module '${module}'. Make sure it is registered correctly.") - endif() - gpVerbose("Configuring module '${module}' located at '${moduleLocation}'") - include(${moduleLocation}/CMakeLists.txt) - endforeach(module) -endfunction() diff --git a/cmake/gp-build-tool/internals/gp-scope.internal.cmake b/cmake/gp-build-tool/internals/gp-scope.internal.cmake deleted file mode 100644 index 346a155..0000000 --- a/cmake/gp-build-tool/internals/gp-scope.internal.cmake +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-logger.internal) - -# Verify that scope depth variable is initialized -if(NOT DEFINED __GP_SCOPE_DEPTH) - set(__GP_SCOPE_DEPTH 0) -endif() - -# Track active named scopes to prevent duplicates -if(NOT DEFINED __GP_ACTIVE_NAMED_SCOPES) - set(__GP_ACTIVE_NAMED_SCOPES "") -endif() - -# @brief Pushes a new scope onto the stack. Variables set after this call will be tracked and can -# be reverted by a corresponding call to gpPopScope(). -macro(gpPushScope) - math(EXPR __GP_SCOPE_DEPTH "${__GP_SCOPE_DEPTH} + 1") - set(__gp_scope_vars_${__GP_SCOPE_DEPTH} "") -endmacro() - -# @brief Pops the current scope from the stack, reverting any variables that were set since the -# last call to gpPushScope(). -macro(gpPopScope) - if(__GP_SCOPE_DEPTH EQUAL 0) - gpFatal("gpPopScope called without a matching gpPushScope().") - endif() - - foreach(_var IN LISTS __gp_scope_vars_${__GP_SCOPE_DEPTH}) - if(__gp_scope_had_${__GP_SCOPE_DEPTH}_${_var}) - set(${_var} "${__gp_scope_backup_${__GP_SCOPE_DEPTH}_${_var}}") - unset(__gp_scope_backup_${__GP_SCOPE_DEPTH}_${_var}) - else() - unset(${_var}) - endif() - - unset(__gp_scope_had_${__GP_SCOPE_DEPTH}_${_var}) - endforeach() - - unset(__gp_scope_vars_${__GP_SCOPE_DEPTH}) - math(EXPR __GP_SCOPE_DEPTH "${__GP_SCOPE_DEPTH} - 1") -endmacro() - -# @brief Pushes a new named scope. Wraps gpPushScope and tracks the name. -# Prevents opening a duplicate named scope if it is already active. -# @param[in] scopeName The unique name of the scope to open. -macro(gpPushNamedScope scopeName) - # Check if the scope is already active (using list(FIND) avoids CMP0057 IN_LIST requirements) - list(FIND __GP_ACTIVE_NAMED_SCOPES "${scopeName}" _gp_name_idx) - if(NOT _gp_name_idx EQUAL -1) - gpFatal("Cannot open named scope '${scopeName}': a scope with this name is already active.") - endif() - - # Call your existing base scope logic - gpPushScope() - - # Track the new named scope globally and link it to the current depth - list(APPEND __GP_ACTIVE_NAMED_SCOPES "${scopeName}") - set(__gp_scope_name_${__GP_SCOPE_DEPTH} "${scopeName}") -endmacro() - -# @brief Optional but recommended: A strict pop that enforces matching names. -# @param[in] scopeName The name of the scope you expect to be popping. -macro(gpPopNamedScope scopeName) - if(NOT DEFINED __gp_scope_name_${__GP_SCOPE_DEPTH} OR NOT "${__gp_scope_name_${__GP_SCOPE_DEPTH}}" STREQUAL "${scopeName}") - gpFatal("gpPopNamedScope called for '${scopeName}', but the current top scope is '${__gp_scope_name_${__GP_SCOPE_DEPTH}}'.") - endif() - - # Delegate to gpPopScope, which will handle the actual cleanup - gpPopScope() - - # Remove the scope name from the active list - list(REMOVE_ITEM __GP_ACTIVE_NAMED_SCOPES "${scopeName}") -endmacro() - -# @brief Sets a variable in the current scope, tracking it so that it can be reverted by gpPopScope(). -# Must be called after gpPushScope() to ensure the variable is tracked properly. -# @param[in] varName The name of the variable to set. -# @param[in] ARGN The value(s) to set the variable to. Supports lists and multiple values. -macro(gpSetScoped varName) - # Ensure we are inside a scope - if(__GP_SCOPE_DEPTH EQUAL 0) - gpFatal("gpSetScoped called outside of any scope. Call gpPushScope() first.") - endif() - - # If this is the first time we are modifying this variable in the current scope, back it up - if(NOT "${varName}" IN_LIST __gp_scope_vars_${__GP_SCOPE_DEPTH}) - list(APPEND __gp_scope_vars_${__GP_SCOPE_DEPTH} "${varName}") - - if(DEFINED ${varName}) - # Variable already exists, back it up - set(__gp_scope_backup_${__GP_SCOPE_DEPTH}_${varName} "${${varName}}") - set(__gp_scope_had_${__GP_SCOPE_DEPTH}_${varName} TRUE) - else() - # Variable didn't exist, remember that so we completely delete it later - set(__gp_scope_had_${__GP_SCOPE_DEPTH}_${varName} FALSE) - endif() - endif() - - # Actually set the variable (using ARGN to support lists/multiple values) - set(${varName} ${ARGN}) -endmacro() - -# @brief Bulk sets multiple variables in the current scope using Key-Value pairs. -# Must be called after gpPushScope(). -# @param[in] ARGN Key-Value pairs. e.g., gpSetScopedMultiple(KEY1 "Val1" KEY2 "Val2") -macro(gpSetScopedMultiple) - # Capture all arguments as a list - set(_gp_bulk_args "${ARGN}") - list(LENGTH _gp_bulk_args _gp_bulk_count) - math(EXPR _gp_bulk_remainder "${_gp_bulk_count} % 2") - - # Ensure we have perfect pairs - if(NOT _gp_bulk_remainder EQUAL 0) - message(FATAL_ERROR "[GPBT] gpSetScopedMultiple requires an even number of arguments (Key-Value pairs).") - endif() - - # Process pairs - math(EXPR _gp_bulk_max "${_gp_bulk_count} - 1") - if(_gp_bulk_count GREATER 0) - foreach(_idx RANGE 0 ${_gp_bulk_max} 2) - math(EXPR _val_idx "${_idx} + 1") - - # Extract key and value - list(GET _gp_bulk_args ${_idx} _gp_key) - list(GET _gp_bulk_args ${_val_idx} _gp_value) - - # Delegate to your existing single-setter macro - gpSetScoped("${_gp_key}" "${_gp_value}") - endforeach() - endif() - - # Clean up temporary macro variables so we don't pollute the caller's scope - unset(_gp_bulk_args) - unset(_gp_bulk_count) - unset(_gp_bulk_remainder) - unset(_gp_bulk_max) - unset(_idx) - unset(_val_idx) - unset(_gp_key) - unset(_gp_value) -endmacro() - -# @brief Registers existing variables into the current scope tracker so they are -# reverted/deleted on gpPopScope(), without modifying their current values. -# @param[in] ARGN A list of variable names. e.g., gpTrackScopedMultiple(varA varB varC) -macro(gpTrackScopedMultiple) - if(__GP_SCOPE_DEPTH EQUAL 0) - message(FATAL_ERROR "[GPBT] gpTrackScopedMultiple called outside of any scope.") - endif() - - foreach(_varName IN ITEMS ${ARGN}) - if(NOT "${_varName}" IN_LIST __gp_scope_vars_${__GP_SCOPE_DEPTH}) - list(APPEND __gp_scope_vars_${__GP_SCOPE_DEPTH} "${_varName}") - - if(DEFINED ${_varName}) - set(__gp_scope_backup_${__GP_SCOPE_DEPTH}_${_varName} "${${_varName}}") - set(__gp_scope_had_${__GP_SCOPE_DEPTH}_${_varName} TRUE) - else() - set(__gp_scope_had_${__GP_SCOPE_DEPTH}_${_varName} FALSE) - endif() - endif() - endforeach() -endmacro() - -# @brief Guard to ensure a block of code executes only once per CMake configuration run. -# @param[in] identifier A unique name for the code block (e.g., "STARTUP_BANNER"). -# @param[out] outVar Evaluates to TRUE on the first call, and FALSE on all subsequent calls. -macro(gpExecuteOnce identifier outVar) - get_property(_has_run GLOBAL PROPERTY "__GP_ONCE_${identifier}") - - if(NOT _has_run) - # Mark it as run so future checks return false - set_property(GLOBAL PROPERTY "__GP_ONCE_${identifier}" TRUE) - set(${outVar} TRUE) - else() - set(${outVar} FALSE) - endif() -endmacro() - -# @brief Checks whether a specific named scope is currently active anywhere in the stack. -# @param[in] scopeName The name of the scope to check. -# @param[out] outVar Evaluates to TRUE if inside the scope, FALSE otherwise. -macro(gpIsInNamedScope scopeName outVar) - list(FIND __GP_ACTIVE_NAMED_SCOPES "${scopeName}" _gp_name_idx) - if(NOT _gp_name_idx EQUAL -1) - set(${outVar} TRUE) - else() - set(${outVar} FALSE) - endif() -endmacro() - -# @brief Guard to ensure a block of code is only executed within a specific named scope. -# @param[in] scopeName The name of the required scope. -# @param[in] errorMessage The error message to display if not in the required scope. -macro(gpFatalIfNotInNamedScope scopeName errorMessage) - gpIsInNamedScope("${scopeName}" _is_in_scope) - if(NOT _is_in_scope) - gpFatal("${errorMessage}") - endif() -endmacro() diff --git a/cmake/gp-build-tool/internals/gp-stringify.internal.cmake b/cmake/gp-build-tool/internals/gp-stringify.internal.cmake deleted file mode 100644 index 6600dd4..0000000 --- a/cmake/gp-build-tool/internals/gp-stringify.internal.cmake +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -# @brief Checks if a string is in lower_snake_case. -# @param[in] input The string to check. -# @param[out] outVar The variable to store the result. -function(gpIsLowerSnakeCase input outVar) - string(REGEX MATCH "^[a-z0-9]+(_[a-z0-9]+)*$" match "${input}") - if(match AND NOT input STREQUAL "") - set(${outVar} TRUE PARENT_SCOPE) - else() - set(${outVar} FALSE PARENT_SCOPE) - endif() -endfunction() - -# @brief Checks if a string is in UPPER_SNAKE_CASE. -# @param[in] input The string to check. -# @param[out] outVar The variable to store the result. -function(gpIsUpperSnakeCase input outVar) - string(REGEX MATCH "^[A-Z0-9]+(_[A-Z0-9]+)*$" match "${input}") - if(match AND NOT input STREQUAL "") - set(${outVar} TRUE PARENT_SCOPE) - else() - set(${outVar} FALSE PARENT_SCOPE) - endif() -endfunction() - -# @brief Checks if a string is in camelCase. -# @param[in] input The string to check. -# @param[out] outVar The variable to store the result. -function(gpIsCamelCase input outVar) - string(REGEX MATCH "^[a-z][a-z0-9]*([A-Z][a-z0-9]*)*$" match "${input}") - if(match AND NOT input STREQUAL "") - set(${outVar} TRUE PARENT_SCOPE) - else() - set(${outVar} FALSE PARENT_SCOPE) - endif() -endfunction() - -# @brief Checks if a string is in PascalCase. -# @param[in] input The string to check. -# @param[out] outVar The variable to store the result. -function(gpIsPascalCase input outVar) - string(REGEX MATCH "^([A-Z][a-z0-9]*)+$" match "${input}") - if(match AND NOT input STREQUAL "") - set(${outVar} TRUE PARENT_SCOPE) - else() - set(${outVar} FALSE PARENT_SCOPE) - endif() -endfunction() - -# @brief Internal function to tokenize a string into words based on case transitions and separators. -# @param[in] input The string to tokenize. -# @param[out] outVar The variable to store the list of words. -function(_gpTokenizeToWords input outVar) - # (e.g., "myCustomVar2" -> "my;Custom;Var2", "myHTTPResponse" -> "my;HTTPResponse") - string(REGEX REPLACE "([a-z0-9])([A-Z])" "\\1;\\2" tokenized "${input}") - - # (e.g., "XMLParser" -> "XML;Parser", "my;HTTPResponse" -> "my;HTTP;Response") - string(REGEX REPLACE "([A-Z]+)([A-Z][a-z])" "\\1;\\2" tokenized "${tokenized}") - - # (Using + naturally collapses multiple separators like "__" or "--") - string(REGEX REPLACE "[-_]+" ";" tokenized "${tokenized}") - - string(TOLOWER "${tokenized}" tokenized) - list(REMOVE_ITEM tokenized "") - set(${outVar} "${tokenized}" PARENT_SCOPE) -endfunction() - -# @brief Converts a string to lower_snake_case. -# @param[in] input The string to convert. -# @param[out] outVar The variable to store the result. -function(gpToLowerSnakeCase input outVar) - _gpTokenizeToWords("${input}" words) - string(REPLACE ";" "_" result "${words}") - set(${outVar} "${result}" PARENT_SCOPE) -endfunction() - -# @brief Converts a string to UPPER_SNAKE_CASE. -# @param[in] input The string to convert. -# @param[out] outVar The variable to store the result. -function(gpToUpperSnakeCase input outVar) - _gpTokenizeToWords("${input}" words) - string(REPLACE ";" "_" result "${words}") - string(TOUPPER "${result}" result) - set(${outVar} "${result}" PARENT_SCOPE) -endfunction() - -# @brief Converts a string to PascalCase. -# @param[in] input The string to convert. -# @param[out] outVar The variable to store the result. -function(gpToPascalCase input outVar) - _gpTokenizeToWords("${input}" words) - set(result "") - foreach(word IN LISTS words) - string(SUBSTRING "${word}" 0 1 first_char) - string(TOUPPER "${first_char}" first_char) - string(SUBSTRING "${word}" 1 -1 rest) - string(APPEND result "${first_char}${rest}") - endforeach() - set(${outVar} "${result}" PARENT_SCOPE) -endfunction() - -# @brief Converts a string to camelCase. -# @param[in] input The string to convert. -# @param[out] outVar The variable to store the result. -function(gpToCamelCase input outVar) - _gpTokenizeToWords("${input}" words) - set(result "") - list(LENGTH words len) - if(len GREATER 0) - list(GET words 0 first_word) - set(result "${first_word}") - list(REMOVE_AT words 0) - - foreach(word IN LISTS words) - string(SUBSTRING "${word}" 0 1 first_char) - string(TOUPPER "${first_char}" first_char) - string(SUBSTRING "${word}" 1 -1 rest) - string(APPEND result "${first_char}${rest}") - endforeach() - endif() - set(${outVar} "${result}" PARENT_SCOPE) -endfunction() diff --git a/cmake/gp-build-tool/internals/gp-targets.internal.cmake b/cmake/gp-build-tool/internals/gp-targets.internal.cmake deleted file mode 100644 index d4a9c0c..0000000 --- a/cmake/gp-build-tool/internals/gp-targets.internal.cmake +++ /dev/null @@ -1,613 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-scope.internal) -include(gp-build-tool/internals/gp-logger.internal) -include(gp-build-tool/internals/gp-stringify.internal) -include(gp-build-tool/internals/gp-utils.internal) - -# List of valid target types for the build system. -set(GPBT_TARGET_TYPES "module;executable;plugin" CACHE INTERNAL "List of valid target types for the build system") - -# @brief Internal macro to initialize a new target with the given name and type. -# @param[in] targetName The name of the target being defined. -# @param[in] targetType The type of the target (e.g., "module", "executable"). This must be one of the valid types defined in GPBT_TARGET_TYPES. -macro(_implGpStartTarget targetName targetType) - # Push a named scope for the target, which will track all variables - # set within it and prevent duplicate target definitions - gpPushNamedScope("target") - - # Prepare all the necessary variables for the target based on the provided name and type - gpSetScopedMultiple( - # Metadata about the target - __targetName "${targetName}" - __targetCleanName "" - __targetNameUpper "" - __targetType "" - __targetOutputName "" - __targetExportName "" - __targetAliasName "" - __targetLocation "" - - # Source files for the target - __targetSources "" - __targetPCHs "" - - # Include directories categorized by visibility - __targetPublicIncludes "" - __targetInternalIncludes "" - __targetPrivateIncludes "" - - # Dependencies categorized by visibility - __targetPublicDependencies "" - __targetInternalDependencies "" - __targetPrivateDependencies "" - __targetDynamicDependencies "" - - # Compile definitions categorized by visibility - __targetPublicCompileDefinitions "" - __targetInternalCompileDefinitions "" - __targetPrivateCompileDefinitions "" - - # Compile options categorized by visibility - __targetPublicCompileOptions "" - __targetPrivateCompileOptions "" - - # Boolean flags for the target - __targetIsHeaderOnly FALSE - __targetEnableTests FALSE - __targetEnableBenchmarks FALSE - __targetEnableExamples FALSE - __targetEnableISPC FALSE - __targetEnableStrictWarnings FALSE - __targetUnityBuild FALSE - - # Executable-specific properties - __targetExecutableEntryPoint "" - __targetExecutableResourceFiles "" - __targetExecutableIsGUI FALSE - - # Optional overrides - __targetCustomFolder "" - ) - - # Populate the target metadata variables based on the provided name and type - string(TOLOWER "${targetType}" __targetType) - string(REPLACE "/" "_" __targetCleanName "${targetName}") - gpToUpperSnakeCase("${__targetCleanName}" __targetNameUpper) - gpToLowerSnakeCase("${__targetCleanName}" __targetOutputName) - gpToLowerSnakeCase("${__targetCleanName}" __targetExportName) - set(__targetExportName "gp_${__targetExportName}") - set(__targetOutputName "gp_${__targetOutputName}") - set(__targetAliasName "gp::${__targetCleanName}") - - # Verbose naming of the target for better visibility in the build output - gpVerbose("Initializing target '${__targetName}' of type '${__targetType}' with export name '${__targetExportName}' and alias '${__targetAliasName}'") - - # Log the start of the target definition for better visibility in the build output - gpLog("Defining target '${targetName}' of type '${targetType}'") - - # Get the list of currently registered targets to check for duplicates during the registration phase - get_property(currentTargets GLOBAL PROPERTY GPBT_REGISTERED_TARGETS) - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # Setup the target for the registration phase. - # This includes validating the target name and type, storing the target location, - # and registering the target in the global list of targets. - if(GPBT_CURRENT_PHASE STREQUAL "REGISTRATION") - # Store location of the target for potential use in custom build steps or tools that need to know where the source files are - set_property(GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") - - # Verify that the target name is unique during the registration phase - if("${__targetName}" IN_LIST currentTargets) - gpFatal("Target name '${__targetName}' is already registered. Target names must be unique.") - else() - set_property(GLOBAL APPEND PROPERTY GPBT_REGISTERED_TARGETS "${__targetName}") - endif() - endif() - - # Retrieve the target location for use in later phases. - # This ensures that the variable is always populated regardless of the current phase. - get_property(__targetLocation GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_LOCATION) - - # Verify that the target type is valid - if(NOT __targetType IN_LIST GPBT_TARGET_TYPES) - gpFatal("Invalid target type '${targetType}' for target '${targetName}'. Valid types are: ${GPBT_TARGET_TYPES}") - endif() - - # Append initial properties to the target's properties - list(APPEND __targetPublicIncludes "${__targetLocation}/public") - list(APPEND __targetInternalIncludes "${__targetLocation}/internal") - list(APPEND __targetPrivateIncludes "${__targetLocation}/private") - foreach(directory "${__targetLocation}/private" "${__targetLocation}/internal") - if(EXISTS "${directory}") - file(GLOB_RECURSE sourcesFromDir "${directory}/*.cpp" "${directory}/*.cc" "${directory}/*.cxx") - list(APPEND __targetSources ${sourcesFromDir}) - endif() - endforeach() - set(__targetEnableStrictWarnings TRUE) -endmacro() - -# @brief Internal macro to finalize the definition of a target. -macro(_implGpEndTarget) - # Check being in a target scope before trying to end it. - gpFatalIfNotInNamedScope("target" "gpEndTarget() called without a matching gpStartTarget(). Each target definition must begin with gpStartTarget() and end with gpEndTarget().") - - # Get the curent phase - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # During the registration phase, we need to store the collected properties for this target in global properties so that - # they can be accessed during the configuration phase when we actually create the CMake targets. - if(GPBT_CURRENT_PHASE STREQUAL "REGISTRATION") - # Combine all dependencies into a single property for easier access during the generation phase. - gpSetScoped(allDependencies ${__targetPublicDependencies} ${__targetInternalDependencies} ${__targetPrivateDependencies} ${__targetDynamicDependencies}) - # Store specific and combined dependencies using dynamic property names. - set_property(GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_PUBLIC_DEPS "${__targetPublicDependencies}") - set_property(GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_INTERNAL_DEPS "${__targetInternalDependencies}") - set_property(GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_PRIVATE_DEPS "${__targetPrivateDependencies}") - set_property(GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_DYNAMIC_DEPS "${__targetDynamicDependencies}") - set_property(GLOBAL PROPERTY GPBT_TARGET_${__targetNameUpper}_ALL_DEPS "${allDependencies}") - elseif(GPBT_CURRENT_PHASE STREQUAL "CONFIGURATION") - # During the configuration phase, we can perform the actual CMake target creation and configuration - # based on the properties collected during registration. - _implGpDefineCMakeTarget() - endif() - - # Log the completion of the target definition for better visibility in the build output - gpLog("Finished defining target '${__targetName}'") - - # Pop the target scope, which will revert any variables set - # within it and clean up the named scope tracking - gpPopNamedScope("target") -endmacro() - -# @brief Cleans the name of a dependency by removing any leading or trailing whitespace, adding proper prefix/suffix if needed. -# @param[in] inName The variable containing the dependency name to clean. -# @param[out] outName The variable containing the cleaned dependency name. -function(_implGpCleanDependencyName inName outName) - # TODO: Implement more robust cleaning logic if needed - # (e.g., handling version suffixes, platform-specific variants, etc.) - get_property(allRegisteredTargets GLOBAL PROPERTY GPBT_REGISTERED_TARGETS) - if("${inName}" IN_LIST allRegisteredTargets AND NOT "${inName}" MATCHES "^gp::") - string(REPLACE "/" "_" cleanedName "${inName}") - # Dereference outName and export it to the caller - set(${outName} "gp::${cleanedName}" PARENT_SCOPE) - else() - # Dereference outName and export it to the caller - set(${outName} "${inName}" PARENT_SCOPE) - endif() -endfunction() - -# @brief Internal function to clean a list of dependency names by applying the cleaning logic to each item in the list. -# @param[in] inList The variable containing the list of dependency names to clean. -# @param[out] outList The variable containing the list of cleaned dependency names. -function(_implGpGetCleanedDependencyList inList outList) - set(_tempList "") - - foreach(item IN LISTS ${inList}) - _implGpCleanDependencyName("${item}" cleanedItem) - list(APPEND _tempList "${cleanedItem}") - endforeach() - - # Push the final compiled list back to the caller's scope - set(${outList} "${_tempList}" PARENT_SCOPE) -endfunction() - -# @brief Internal helper to stamp the standard GP compile definitions onto any target. -# Centralises all build-config, feature, and graphics-API definitions so they are -# applied identically to the main target, tests, benchmarks, and any future sub-targets. -# @param[in] targetName The CMake target name to receive the definitions. -macro(_implGpApplyCommonDefinitions targetName) - target_compile_definitions(${targetName} PRIVATE - $<$:GP_BUILD_DEBUG=1> - $<$:GP_BUILD_RELEASE=1> - $<$:GP_BUILD_RELWITHDEBINFO=1> - $<$:GP_BUILD_MINSIZEREL=1> - $<$:GP_ENABLE_PROFILING=1> - $<$:GP_BUILD_EDITOR=1> - $<$:GP_USE_VULKAN=1> - $<$:GP_USE_D3D12=1> - $<$:GP_USE_D3D11=1> - $<$:GP_USE_METAL=1> - $<$:GP_USE_OPENGL=1> - ) -endmacro() - -# @brief Internal macro to define the actual CMake target based on the properties collected during the registration phase. -# This is called during the configuration phase after all targets have been registered. -macro(_implGpDefineCMakeTarget) - # Check being in a target scope before trying to end it. - gpFatalIfNotInNamedScope("target" "Internal error: _implGpDefineCMakeTarget() called without a matching gpStartTarget(). This indicates a logic error in the build tool implementation.") - - # Get current phase - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # Check the current phase to ensure this function is only called during the configuration phase - if(NOT GPBT_CURRENT_PHASE STREQUAL "CONFIGURATION") - gpFatal("Internal error: _implGpDefineCMakeTarget() called during phase '${GPBT_CURRENT_PHASE}'. This function should only be called during the CONFIGURATION phase.") - endif() - - # Prepare the CMake target name and type based on the collected properties - gpVerbose("Defining CMake target '${__targetExportName}' of type '${__targetType}' with alias '${__targetAliasName}'") - - # If no sources were added, and the target is not header-only, we need to add a dummy source file to ensure CMake creates the target correctly. - list(LENGTH __targetSources numSources) - if(numSources EQUAL 0 AND NOT __targetIsHeaderOnly) - gpSetScoped(dummySource "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp") - if(NOT EXISTS "${dummySource}") - file(WRITE "${dummySource}" "// Auto-generated keep file for link language detection\n") - endif() - list(APPEND __targetSources "${dummySource}") - gpLog("No sources specified for target '${__targetName}'. Added dummy source to ensure target creation.") - endif() - - # Gather the header files for IDE integration and better project organization. - # This is optional but improves the developer experience. - gpSetScoped(headerFiles "") - foreach(directory IN LISTS __targetPublicIncludes __targetInternalIncludes __targetPrivateIncludes) - if(EXISTS "${directory}") - file(GLOB_RECURSE headers "${directory}/*.h" "${directory}/*.hpp" "${directory}/*.hh" "${directory}/*.hxx") - list(APPEND headerFiles ${headers}) - endif() - endforeach() - - # Determine the IDE folder for this target. Prefer the user-supplied override, then - # fall back to a canonical name derived from the target type. - gpSetScoped(_ideFolder "modules") - if("${__targetType}" STREQUAL "executable") - set(_ideFolder "executables") - elseif("${__targetType}" STREQUAL "plugin") - set(_ideFolder "plugins") - endif() - if(NOT "${__targetCustomFolder}" STREQUAL "") - set(_ideFolder "${__targetCustomFolder}") - endif() - - # Create the CMake target based on the collected properties and the target type. - if(__targetType STREQUAL "module") - add_library(${__targetExportName} ${__targetSources} ${headerFiles}) - add_library(${__targetAliasName} ALIAS ${__targetExportName}) - elseif(__targetType STREQUAL "plugin") - # Plugins are always SHARED: they are runtime-loaded and must produce a .so/.dll. - add_library(${__targetExportName} SHARED ${__targetSources} ${headerFiles}) - add_library(${__targetAliasName} ALIAS ${__targetExportName}) - elseif(__targetType STREQUAL "executable") - add_executable(${__targetExportName} ${__targetSources} ${headerFiles} ${__targetExecutableResourceFiles} ${__targetExecutableEntryPoint}) - add_executable(${__targetAliasName} ALIAS ${__targetExportName}) - - if(WIN32) - set_target_properties(${__targetExportName} PROPERTIES - WIN32_EXECUTABLE ${__targetExecutableIsGUI} - ) - endif() - - target_compile_definitions(${__targetExportName} PRIVATE "GP_EXECUTABLE_IS_GUI=$") - else() - gpFatal("Internal error: Unsupported target type '${__targetType}' for target '${__targetName}'.") - endif() - - # Apply the standard GP compile definitions (build config, features, graphics APIs). - _implGpApplyCommonDefinitions(${__targetExportName}) - - # Determine whether Windows DLL export-all-symbols is needed. - # Modules: follow BUILD_SHARED_LIBS. Plugins: always shared, so always export. - gpSetScoped(_isShared FALSE) - if(__targetType STREQUAL "plugin") - set(_isShared TRUE) - elseif(BUILD_SHARED_LIBS) - set(_isShared TRUE) - endif() - - # Set target properties for symbol export, visibility, and other relevant settings. - set_target_properties(${__targetExportName} PROPERTIES - OUTPUT_NAME "${__targetOutputName}" - DEFINE_SYMBOL "GP_${__targetNameUpper}_API_EXPORTS" - CXX_VISIBILITY_PRESET default - VISIBILITY_INLINES_HIDDEN OFF - POSITION_INDEPENDENT_CODE ON - FOLDER "${_ideFolder}" - ) - - if(WIN32 AND _isShared) - set_target_properties(${__targetExportName} PROPERTIES - WINDOWS_EXPORT_ALL_SYMBOLS ON - ) - endif() - - # Unity build: batch source files together for faster cold-build throughput. - if(__targetUnityBuild) - set_target_properties(${__targetExportName} PROPERTIES - UNITY_BUILD ON - UNITY_BUILD_BATCH_SIZE 16 - ) - gpVerbose("Unity build enabled for target '${__targetName}' (batch size 16)") - endif() - - # Set include directories with proper visibility (PUBLIC, PRIVATE, INTERFACE) - target_include_directories(${__targetExportName} - PUBLIC - # Map all source-tree public paths to the Build Interface - $ - # Define where headers will live after installation - $ - PRIVATE - # Private and Internal remain local to this target - ${__targetPrivateIncludes} - ${__targetInternalIncludes} - ) - - # Apply user-defined compile definitions with the correct CMake visibility. - # "internal" definitions are scoped to this target's own translation units (PRIVATE). - list(LENGTH __targetPublicCompileDefinitions _numPublicDefs) - if(_numPublicDefs GREATER 0) - target_compile_definitions(${__targetExportName} PUBLIC ${__targetPublicCompileDefinitions}) - endif() - list(LENGTH __targetPrivateCompileDefinitions _numPrivateDefs) - if(_numPrivateDefs GREATER 0) - target_compile_definitions(${__targetExportName} PRIVATE ${__targetPrivateCompileDefinitions}) - endif() - list(LENGTH __targetInternalCompileDefinitions _numInternalDefs) - if(_numInternalDefs GREATER 0) - target_compile_definitions(${__targetExportName} PRIVATE ${__targetInternalCompileDefinitions}) - endif() - - # Add precompile headers if specified - list(LENGTH __targetPCHs numPCHs) - if(numPCHs GREATER 0) - gpVerbose("Adding precompiled headers to target '${__targetName}': ${__targetPCHs}") - target_precompile_headers(${__targetExportName} PRIVATE ${__targetPCHs}) - endif() - - # Apply public compilation flags to the target - list(LENGTH __targetPublicCompileOptions numPublicCompileOptions) - if(numPublicCompileOptions GREATER 0) - gpVerbose("Applying public compile options to target '${__targetName}': ${__targetPublicCompileOptions}") - target_compile_options(${__targetExportName} PUBLIC ${__targetPublicCompileOptions}) - endif() - - # Apply private compilation flags to the target - list(LENGTH __targetPrivateCompileOptions numPrivateCompileOptions) - if(numPrivateCompileOptions GREATER 0) - gpVerbose("Applying private compile options to target '${__targetName}': ${__targetPrivateCompileOptions}") - target_compile_options(${__targetExportName} PRIVATE ${__targetPrivateCompileOptions}) - endif() - - # Set the public dependencies for the target. - _implGpGetCleanedDependencyList(__targetPublicDependencies publicDeps) - list(LENGTH publicDeps numPublicDeps) - if(numPublicDeps GREATER 0) - gpVerbose("Linking public dependencies for target '${__targetName}': ${publicDeps}") - target_link_libraries(${__targetExportName} PUBLIC ${publicDeps}) - endif() - - # Set the private dependencies for the target. - _implGpGetCleanedDependencyList(__targetPrivateDependencies privateDeps) - list(LENGTH privateDeps numPrivateDeps) - if(numPrivateDeps GREATER 0) - gpVerbose("Linking private dependencies for target '${__targetName}': ${privateDeps}") - target_link_libraries(${__targetExportName} PRIVATE ${privateDeps}) - endif() - - # Set the internal dependencies for the target. - # "Internal" means used only in this target's own implementation — PRIVATE, not INTERFACE. - _implGpGetCleanedDependencyList(__targetInternalDependencies internalDeps) - list(LENGTH internalDeps numInternalDeps) - if(numInternalDeps GREATER 0) - gpVerbose("Linking internal dependencies for target '${__targetName}': ${internalDeps}") - target_link_libraries(${__targetExportName} PRIVATE ${internalDeps}) - endif() - - # Wire dynamic dependencies as build-order edges only (no linker coupling). - # These are runtime-loaded modules (plugins, RHI backends) that must exist in the - # output directory before this target runs, but must NOT be linked at compile time. - _implGpGetCleanedDependencyList(__targetDynamicDependencies dynamicDeps) - list(LENGTH dynamicDeps numDynamicDeps) - if(numDynamicDeps GREATER 0) - gpVerbose("Adding build-order edges for dynamic dependencies of '${__targetName}': ${dynamicDeps}") - add_dependencies(${__targetExportName} ${dynamicDeps}) - endif() - - # Ensure C++23 standard is used for all targets - target_compile_features(${__targetExportName} PUBLIC cxx_std_23) - if (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - target_compile_options(${__targetExportName} PRIVATE /Zc:__cplusplus) - endif() - - # Setup installation rules for the target (optional, but common for libraries) - install(TARGETS ${__targetExportName} - EXPORT GPEngineTargets - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - INCLUDES DESTINATION include - ) - - # Install public headers to the appropriate location under include/ for this target. - foreach(_dir IN LISTS __targetPublicIncludes) - install(DIRECTORY ${_dir}/ - DESTINATION include/${__targetName} - FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.hh" PATTERN "*.hxx" - ) - endforeach() - - # Compiler-aware strict warnings. Warnings-as-errors keeps the codebase clean. - if(__targetEnableStrictWarnings) - if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - target_compile_options(${__targetExportName} PRIVATE - /W4 # Warning level 4 - /WX # Warnings as errors - /permissive- # Standards-conformance mode - ) - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - target_compile_options(${__targetExportName} PRIVATE - -Wall -Wextra -Werror - -Wno-unused-parameter - -Wno-missing-field-initializers - ) - else() # GCC - target_compile_options(${__targetExportName} PRIVATE - -Wall -Wextra -Werror - -Wno-unused-parameter - -Wno-missing-field-initializers - ) - endif() - endif() - - # Create the target for IPSC, if enabled - if(__targetEnableISPC) - _implGpDefineIPSCTarget() - endif() - - # Create the target for tests, if enabled - if(__targetEnableTests) - _implGpDefineTestsTarget() - endif() - - # Create the target for benchmarks, if enabled - if(__targetEnableBenchmarks) - _implGpDefineBenchmarksTarget() - endif() - - # Create the target for examples, if enabled - if(__targetEnableExamples) - _implGpDefineExamplesTarget() - endif() -endmacro() - -# @brief Internal macro to define a tests target for the current target. -macro(_implGpDefineTestsTarget) - # Check being in a target scope before trying to end it. - gpFatalIfNotInNamedScope("target" "Internal error: _implGpDefineTestsTarget() called without a matching gpStartTarget(). This indicates a logic error in the build tool implementation.") - - # Get current phase - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # Check the current phase to ensure this function is only called during the configuration phase - if(NOT GPBT_CURRENT_PHASE STREQUAL "CONFIGURATION") - gpFatal("Internal error: _implGpDefineTestsTarget() called during phase '${GPBT_CURRENT_PHASE}'. This function should only be called during the CONFIGURATION phase.") - endif() - - # Check that the Catch2 testing framework is available before trying to create the tests target. - if(NOT TARGET Catch2WithMain) - gpFatal("Catch2 target 'Catch2WithMain' not found. Ensure Catch2 is properly added as a dependency for tests.") - endif() - - # Log the creation of the tests target for better visibility in the build output - gpLog("Defining tests target '${__targetExportName}_tests' for target '${__targetName}'") - - # Create the tests target as an executable that depends on the main target and Catch2. - gpSetScoped(__targetTestsDir "${__targetLocation}/tests") - if(NOT EXISTS "${__targetTestsDir}") - gpWarning("No test sources found in '${__targetTestsDir}' for target '${__targetName}'. No tests will be generated.") - else() - file(GLOB_RECURSE __targetTestsSources "${__targetTestsDir}/*.cpp" "${__targetTestsDir}/*.cc") - - if (NOT __targetTestsSources) - gpWarning("No test sources found in '${__targetTestsDir}' for target '${__targetName}'. No tests will be generated.") - else() - add_executable(${__targetExportName}_tests ${__targetTestsSources}) - target_link_libraries(${__targetExportName}_tests PRIVATE Catch2WithMain ${__targetExportName}) - set_target_properties(${__targetExportName}_tests PROPERTIES - OUTPUT_NAME "${__targetOutputName}_tests" - FOLDER "tests" - ) - - target_compile_features(${__targetExportName}_tests PUBLIC cxx_std_23) - if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - target_compile_options(${__targetExportName}_tests PRIVATE /Zc:__cplusplus) - endif() - - _implGpApplyCommonDefinitions(${__targetExportName}_tests) - - add_test(NAME ${__targetName}_tests COMMAND ${__targetExportName}_tests) - set_tests_properties(${__targetName}_tests PROPERTIES - LABELS "gp;${__targetName};tests" - ) - endif() - endif() -endmacro() - -# @brief Internal macro to define an ISPC target for the current target. -macro(_implGpDefineIPSCTarget) - # Check being in a target scope before trying to end it. - gpFatalIfNotInNamedScope("target" "Internal error: _implGpDefineIPSCTarget() called without a matching gpStartTarget(). This indicates a logic error in the build tool implementation.") - - # Get current phase - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # Check the current phase to ensure this function is only called during the configuration phase - if(NOT GPBT_CURRENT_PHASE STREQUAL "CONFIGURATION") - gpFatal("Internal error: _implGpDefineIPSCTarget() called during phase '${GPBT_CURRENT_PHASE}'. This function should only be called during the CONFIGURATION phase.") - endif() - - gpWarning("ISPC target generation is not yet implemented for target '${__targetName}'.") -endmacro() - -# @brief Internal macro to define a benchmarks target for the current target. -macro(_implGpDefineBenchmarksTarget) - # Check being in a target scope before trying to end it. - gpFatalIfNotInNamedScope("target" "Internal error: _implGpDefineBenchmarksTarget() called without a matching gpStartTarget(). This indicates a logic error in the build tool implementation.") - - # Get current phase - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # Check the current phase to ensure this function is only called during the configuration phase - if(NOT GPBT_CURRENT_PHASE STREQUAL "CONFIGURATION") - gpFatal("Internal error: _implGpDefineBenchmarksTarget() called during phase '${GPBT_CURRENT_PHASE}'. This function should only be called during the CONFIGURATION phase.") - endif() - - if(NOT TARGET Catch2WithMain) - gpFatal("Catch2 target 'Catch2WithMain' not found. Ensure Catch2 is properly added as a dependency for benchmarks.") - endif() - - gpLog("Defining benchmarks target '${__targetExportName}_benchmarks' for target '${__targetName}'") - - gpSetScoped(__targetBenchmarksDir "${__targetLocation}/benchmarks") - if(NOT EXISTS "${__targetBenchmarksDir}") - gpWarning("No benchmark sources found in '${__targetBenchmarksDir}' for target '${__targetName}'. No benchmarks will be generated.") - else() - file(GLOB_RECURSE __targetBenchmarksSources "${__targetBenchmarksDir}/*.cpp" "${__targetBenchmarksDir}/*.cc") - - if(NOT __targetBenchmarksSources) - gpWarning("No benchmark sources found in '${__targetBenchmarksDir}' for target '${__targetName}'. No benchmarks will be generated.") - else() - add_executable(${__targetExportName}_benchmarks ${__targetBenchmarksSources}) - target_link_libraries(${__targetExportName}_benchmarks PRIVATE Catch2WithMain ${__targetExportName}) - set_target_properties(${__targetExportName}_benchmarks PROPERTIES - OUTPUT_NAME "${__targetOutputName}_benchmarks" - FOLDER "benchmarks" - ) - - target_compile_features(${__targetExportName}_benchmarks PUBLIC cxx_std_23) - if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - target_compile_options(${__targetExportName}_benchmarks PRIVATE /Zc:__cplusplus) - endif() - - # Activate Catch2's built-in benchmark support. - target_compile_definitions(${__targetExportName}_benchmarks PRIVATE CATCH_CONFIG_ENABLE_BENCHMARKING=1) - _implGpApplyCommonDefinitions(${__targetExportName}_benchmarks) - - add_test(NAME ${__targetName}_benchmarks COMMAND ${__targetExportName}_benchmarks "[benchmark]") - set_tests_properties(${__targetName}_benchmarks PROPERTIES - LABELS "gp;${__targetName};benchmarks" - ) - endif() - endif() -endmacro() - -# @brief Internal macro to define an examples target for the current target. -macro(_implGpDefineExamplesTarget) - # Check being in a target scope before trying to end it. - gpFatalIfNotInNamedScope("target" "Internal error: _implGpDefineExamplesTarget() called without a matching gpStartTarget(). This indicates a logic error in the build tool implementation.") - - # Get current phase - _gpGetCurrentPhase(GPBT_CURRENT_PHASE) - - # Check the current phase to ensure this function is only called during the configuration phase - if(NOT GPBT_CURRENT_PHASE STREQUAL "CONFIGURATION") - gpFatal("Internal error: _implGpDefineExamplesTarget() called during phase '${GPBT_CURRENT_PHASE}'. This function should only be called during the CONFIGURATION phase.") - endif() - - gpWarning("Examples target generation is not yet implemented for target '${__targetName}'.") -endmacro() diff --git a/cmake/gp-build-tool/internals/gp-utils.internal.cmake b/cmake/gp-build-tool/internals/gp-utils.internal.cmake deleted file mode 100644 index 724e155..0000000 --- a/cmake/gp-build-tool/internals/gp-utils.internal.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool/internals/gp-logger.internal) - -# @brief Internal function to set the current build phase. This is used to control the flow of the -# build process and ensure that certain operations only happen during the appropriate phase. -# @param[in] newPhase The new build phase to transition to. Must be one of the allowed phases defined in GPBT_ALLOWED_PHASES. -function(_gpSetCurrentPhase newPhase) - set(GPBT_ALLOWED_PHASES "REGISTRATION" "CONFIGURATION" "GENERATION") - if (NOT "${newPhase}" IN_LIST GPBT_ALLOWED_PHASES) - gpFatal("Invalid build phase '${newPhase}'. Allowed phases are ${GPBT_ALLOWED_PHASES}") - endif() - get_property(currentPhase GLOBAL PROPERTY GPBT_CURRENT_PHASE) - if ("${currentPhase}" STREQUAL "${newPhase}") - gpFatal("Attempting to set build phase to '${newPhase}', but it is already the current phase. This likely indicates a logic error in the GP Build Tool's internal phase management.") - endif() - set_property(GLOBAL PROPERTY GPBT_CURRENT_PHASE "${newPhase}") - gpLog("Build phase set to '${newPhase}'") -endfunction() - -# @brief Internal function to retrieve the current build phase. -# @param[out] outVar The variable to store the current build phase in. -function(_gpGetCurrentPhase outVar) - get_property(currentPhase GLOBAL PROPERTY GPBT_CURRENT_PHASE) - if (NOT currentPhase) - _gpSetCurrentPhase("REGISTRATION") - set(currentPhase "REGISTRATION") - endif() - set(${outVar} "${currentPhase}" PARENT_SCOPE) -endfunction() diff --git a/cmake/gp-build-tool/tests/gp-all.tests.cmake b/cmake/gp-build-tool/tests/gp-all.tests.cmake deleted file mode 100644 index 4282b71..0000000 --- a/cmake/gp-build-tool/tests/gp-all.tests.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -message(STATUS "=== Including Build Tool Tests ===") - -include(gp-build-tool/tests/gp-stringify.tests) -include(gp-build-tool/tests/gp-scope.internal.tests) - -message(STATUS "=== All Build Tool Tests Included ===") diff --git a/cmake/gp-build-tool/tests/gp-scope.internal.tests.cmake b/cmake/gp-build-tool/tests/gp-scope.internal.tests.cmake deleted file mode 100644 index 43a9b6c..0000000 --- a/cmake/gp-build-tool/tests/gp-scope.internal.tests.cmake +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include (gp-build-tool/internals/gp-scope.internal) -include (gp-build-tool/gp-tests) - -_gpStartTestsSection("gp-utils - Scope System") - # Ensure we start from a clean slate for testing - set(__GP_SCOPE_DEPTH 0) - - # Test 1: Basic Scoping (Creation and Deletion) - gpPushScope() - gpSetScoped(TEST_SCOPE_VAR_1 "HelloWorld") - _gpRunTest("Scoped variable creation" DEFINED TEST_SCOPE_VAR_1 AND "${TEST_SCOPE_VAR_1}" STREQUAL "HelloWorld") - gpPopScope() - _gpRunTest("Scoped variable deletion after pop" NOT DEFINED TEST_SCOPE_VAR_1) - - # Test 2: Variable Masking (Backup and Restore) - set(TEST_SCOPE_VAR_2 "OriginalValue") - gpPushScope() - gpSetScoped(TEST_SCOPE_VAR_2 "ScopedValue") - _gpRunTest("Scoped variable successfully masks original" "${TEST_SCOPE_VAR_2}" STREQUAL "ScopedValue") - gpPopScope() - _gpRunTest("Original variable correctly restored after pop" "${TEST_SCOPE_VAR_2}" STREQUAL "OriginalValue") - unset(TEST_SCOPE_VAR_2) - - # Test 3: Nested Scopes - set(TEST_SCOPE_VAR_3 "Level0") - - gpPushScope() - gpSetScoped(TEST_SCOPE_VAR_3 "Level1") - - gpPushScope() - gpSetScoped(TEST_SCOPE_VAR_3 "Level2") - _gpRunTest("Nested scope reads Level 2 value" "${TEST_SCOPE_VAR_3}" STREQUAL "Level2") - gpPopScope() - - _gpRunTest("Nested scope correctly falls back to Level 1" "${TEST_SCOPE_VAR_3}" STREQUAL "Level1") - gpPopScope() - - _gpRunTest("Global scope correctly falls back to Level 0" "${TEST_SCOPE_VAR_3}" STREQUAL "Level0") - unset(TEST_SCOPE_VAR_3) - - # Test 4: Mutation Tracking (Using standard CMake commands) - set(TEST_SCOPE_LIST "OriginalList") - gpPushScope() - gpSetScoped(TEST_SCOPE_LIST "A") - - # Mutate heavily using standard CMake commands - list(APPEND TEST_SCOPE_LIST "B" "C") - string(REPLACE ";" "_" TEST_SCOPE_LIST_STR "${TEST_SCOPE_LIST}") - - _gpRunTest("Scoped list mutation successful" "${TEST_SCOPE_LIST_STR}" STREQUAL "A_B_C") - gpPopScope() - - _gpRunTest("Mutated scoped list restored to original after pop" "${TEST_SCOPE_LIST}" STREQUAL "OriginalList") - unset(TEST_SCOPE_LIST) - - # Test 5: Multiple Arguments Initialization - gpPushScope() - gpSetScoped(TEST_SCOPE_MULTI "One" "Two" "Three") - set(LIST_MATCHES FALSE) - if("${TEST_SCOPE_MULTI}" STREQUAL "One;Two;Three") - set(LIST_MATCHES TRUE) - endif() - _gpRunTest("Scoped initialization handles multiple arguments (lists)" ${LIST_MATCHES}) - gpPopScope() - _gpRunTest("Multiple arguments cleaned up after pop" NOT DEFINED TEST_SCOPE_MULTI) - - # Ensure the scope stack is perfectly balanced after all tests - _gpRunTest("Scope depth returned to 0" __GP_SCOPE_DEPTH EQUAL 0) -_gpEndTestsSection() diff --git a/cmake/gp-build-tool/tests/gp-stringify.tests.cmake b/cmake/gp-build-tool/tests/gp-stringify.tests.cmake deleted file mode 100644 index 41bb51f..0000000 --- a/cmake/gp-build-tool/tests/gp-stringify.tests.cmake +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include (gp-build-tool/internals/gp-stringify.internal) -include (gp-build-tool/gp-tests) - -_gpStartTestsSection("gp-stringify - UPPER_SNAKE_CASE Validation") - set(TEST_STRING "MY_VARIABLE_NAME") - gpIsUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("Valid UPPER_SNAKE_CASE Test" ${result}) - - set(TEST_STRING "My_Variable_Name") - gpIsUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("Invalid UPPER_SNAKE_CASE Test" NOT ${result}) - - set(TEST_STRING "") - gpIsUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("Empty String UPPER_SNAKE_CASE Test" NOT ${result}) -_gpEndTestsSection() - -_gpStartTestsSection("gp-stringify - camelCase Validation") - set(TEST_STRING "myVariableName") - gpIsCamelCase("${TEST_STRING}" result) - _gpRunTest("Valid camelCase Test" ${result}) - - set(TEST_STRING "MyVariableName") - gpIsCamelCase("${TEST_STRING}" result) - _gpRunTest("Invalid camelCase Test (Starts with Capital)" NOT ${result}) - - set(TEST_STRING "my_variableName") - gpIsCamelCase("${TEST_STRING}" result) - _gpRunTest("Invalid camelCase Test (Contains Underscore)" NOT ${result}) -_gpEndTestsSection() - -_gpStartTestsSection("gp-stringify - PascalCase Validation") - set(TEST_STRING "MyVariableName") - gpIsPascalCase("${TEST_STRING}" result) - _gpRunTest("Valid PascalCase Test" ${result}) - - set(TEST_STRING "myVariableName") - gpIsPascalCase("${TEST_STRING}" result) - _gpRunTest("Invalid PascalCase Test (Starts with Lowercase)" NOT ${result}) -_gpEndTestsSection() - -_gpStartTestsSection("gp-stringify - to UPPER_SNAKE_CASE") - set(TEST_STRING "myCustomVariable") - gpToUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("camelCase to UPPER_SNAKE_CASE" "${result}" STREQUAL "MY_CUSTOM_VARIABLE") - - set(TEST_STRING "MyCustomVariable") - gpToUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("PascalCase to UPPER_SNAKE_CASE" "${result}" STREQUAL "MY_CUSTOM_VARIABLE") - - set(TEST_STRING "my_custom_variable") - gpToUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("lower_snake_case to UPPER_SNAKE_CASE" "${result}" STREQUAL "MY_CUSTOM_VARIABLE") -_gpEndTestsSection() - -_gpStartTestsSection("gp-stringify - to camelCase") - set(TEST_STRING "my_custom_variable") - gpToCamelCase("${TEST_STRING}" result) - _gpRunTest("lower_snake_case to camelCase" "${result}" STREQUAL "myCustomVariable") - - set(TEST_STRING "MY_CUSTOM_VARIABLE") - gpToCamelCase("${TEST_STRING}" result) - _gpRunTest("UPPER_SNAKE_CASE to camelCase" "${result}" STREQUAL "myCustomVariable") - - set(TEST_STRING "MyCustomVariable") - gpToCamelCase("${TEST_STRING}" result) - _gpRunTest("PascalCase to camelCase" "${result}" STREQUAL "myCustomVariable") -_gpEndTestsSection() - -_gpStartTestsSection("gp-stringify - to PascalCase") - set(TEST_STRING "my_custom_variable") - gpToPascalCase("${TEST_STRING}" result) - _gpRunTest("lower_snake_case to PascalCase" "${result}" STREQUAL "MyCustomVariable") - - set(TEST_STRING "myCustomVariable") - gpToPascalCase("${TEST_STRING}" result) - _gpRunTest("camelCase to PascalCase" "${result}" STREQUAL "MyCustomVariable") - - set(TEST_STRING "MY_CUSTOM_VARIABLE") - gpToPascalCase("${TEST_STRING}" result) - _gpRunTest("UPPER_SNAKE_CASE to PascalCase" "${result}" STREQUAL "MyCustomVariable") -_gpEndTestsSection() - -_gpStartTestsSection("gp-stringify - Edge Cases") - # Testing consecutive uppercase letters (Acronyms) - set(TEST_STRING "XMLParser") - gpToLowerSnakeCase("${TEST_STRING}" result) - _gpRunTest("Acronym splitting (XMLParser -> xml_parser)" "${result}" STREQUAL "xml_parser") - - set(TEST_STRING "myHTTPResponse") - gpToUpperSnakeCase("${TEST_STRING}" result) - _gpRunTest("Embedded Acronym (myHTTPResponse -> MY_HTTP_RESPONSE)" "${result}" STREQUAL "MY_HTTP_RESPONSE") - - # Testing messy separators - set(TEST_STRING "my__messy---variable_name") - gpToCamelCase("${TEST_STRING}" result) - _gpRunTest("Multiple mixed separators to camelCase" "${result}" STREQUAL "myMessyVariableName") - - set(TEST_STRING "__leading_and_trailing__") - gpToPascalCase("${TEST_STRING}" result) - _gpRunTest("Leading and trailing separators to PascalCase" "${result}" STREQUAL "LeadingAndTrailing") -_gpEndTestsSection() diff --git a/docs/CI.md b/docs/CI.md deleted file mode 100644 index fd59b1b..0000000 --- a/docs/CI.md +++ /dev/null @@ -1,323 +0,0 @@ ---- -sidebar_position: 3 -title: Continuous Integration -description: Information about the CI pipeline for Graphical Playground. -tags: - - ci - - continuous integration - - github actions ---- - -# Continuous Integration - -

Information about the CI pipeline for Graphical Playground.

- -At Graphical Playground, we use [GitHub Actions](https://docs.github.com/en/actions) to automate -our build, validation, formatting, and release pipelines. All workflow files live under -`.github/workflows/` in the repository root. - -Adhering to the practices described in this document is mandatory. A pull request that breaks CI -must not be merged until the failure is resolved. - -## Workflow Overview - -The table below lists every workflow file, its trigger, and its responsibility. - -| File | Trigger | Purpose | -|---|---|---| -| `build.yml` | Push to `main`, Pull Request, `workflow_call` | Compile the engine across all target platforms | -| `formatting.yml` | Pull Request | Enforce `clang-format` on all C++ source files | -| `release.yml` | Push of a version tag (`v*.*.*`) | Build, package, and draft a GitHub release | -| `shader-ci.yml` | Pull Request (shader file changes) | Validate GLSL/HLSL shaders | -| `sync-docs.yml` | Push to `main` (documentation changes) | Mirror docs to the central `gp-docs` portal | -| `labeler.yml` | Pull Request | Automatically apply labels based on changed paths | -| `welcome.yml` | Pull Request opened | Post a welcome comment for first-time contributors | - ---- - -## CI Build - -The core of our pipeline is `build.yml`. It compiles the engine in `Release` mode across every -supported operating system. The job is designed to be both efficient and flexible through a -two-stage matrix approach. - -### Triggers - -The build workflow activates on three distinct events: - -- **Push to `main`**: Runs automatically whenever code lands on the default branch. Supports - commit-message tags to fine-tune which platforms are built (see [Selective Builds](#selective-builds)). -- **Pull Request targeting `main`**: Always builds on all platforms, with no tag-based filtering. - This ensures complete coverage before code is merged. -- **`workflow_call`**: Allows other workflows (such as `release.yml`) to invoke the build job - as a reusable step, with optional parameters for platform filtering and artifact packaging. - -### Path Filtering - -The build job does not run on every push to `main`. It is scoped to changes within the following -paths: - -- `source/**` -- `thirdparty/**` -- `toolchain/**` -- `cmake/**` -- `CMakeLists.txt` - -Changes that touch only documentation, CI workflow files, or other non-source assets will not -trigger a build. This keeps runner usage lean. - -### Build Matrix - -The `setup-matrix` job runs first. It dynamically computes which operating systems to build against -and passes the result to the `build` job via an output variable. - -The three supported runners are: - -- `ubuntu-latest` -- `windows-latest` -- `macos-latest` - -The `build` job uses `fail-fast: false`. This means a failure on one platform will not cancel the -builds on the remaining platforms. We always want to see the full picture of breakage across all targets. - -### Selective Builds - -On a push to `main`, you may control the build matrix by embedding a tag in the commit message. -This is useful when a change is platform-specific and building everywhere would waste runner time. - -- **`[skip ci]`**: Cancels all builds for that commit. - - Note: GitHub natively honors `[skip ci]`, but we handle it explicitly as well. -- **`[run linux,windows]`**: Builds only on the listed platforms. -- **`[skip macos]`**: Builds everywhere except the listed platforms. - -Valid platform keys for these tags are: `linux`, `ubuntu`, `windows`, `macos`. - -:::tip -Selective build tags apply **only to pushes to `main`**. Pull requests always build on all -platforms: do not expect these tags to have any effect on PR-triggered runs. -::: - -```yaml -# Example commit messages - -# Build only on Linux and Windows -fix: resolve vertex buffer alignment [run linux,windows] - -# Skip the macOS runner for this push -chore: update third-party headers [skip macos] - -# Skip CI entirely -docs: fix typo in README [skip ci] -``` - -### Caching - -We use two caching strategies to minimize build times: - -- **`ccache`**: Compiler output is cached via `hendrikmuhs/ccache-action`. The cache key is - scoped to the OS and build type (e.g., `ubuntu-latest-Release`). -- **CMake `FetchContent`**: Dependencies fetched by CMake are cached under `~/.cache/cmake_deps`. - The cache key is derived from a hash of all `CMakeLists.txt` and `.cmake` files. - -Do not disable or remove these caching steps without a documented justification. Cold builds are -significantly slower and consume unnecessary CI minutes. - -### Configure and Build Steps - -After caching, the workflow runs two CMake commands: - -```yaml -# Configure -cmake -S . -B build \ - -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DFETCHCONTENT_BASE_DIR="$HOME/.cache/cmake_deps" - -# Build -cmake --build build --config Release --parallel --verbose -``` - -- We always build with **Ninja** for consistent cross-platform performance. -- We always pass `--parallel` to utilize all available cores on the runner. -- We always pass `--verbose` to ensure full compiler output is visible in the CI log for - diagnosis purposes. - -### Artifact Packaging - -Artifact packaging is **disabled by default**. It is only enabled when the workflow is called -with `package-artifacts: true`, which the `release.yml` workflow does automatically. - -When enabled, the following additional steps run: - -1. **Install**: CMake installs the build output into `install_staging/` using - `cmake --install`. -2. **Version resolution**: The version string is resolved from the Git tag (if the workflow was - triggered by one) or from the first line of the `VERSION` file. -3. **Packaging**: Archives are created per platform: - - Linux / macOS: `.tar.gz` via `tar` - - Windows: `.zip` via PowerShell's `Compress-Archive` -4. **Upload**: Artifacts are uploaded under the name `release-{os}` with a 14-day retention - period. The step fails if no archive file is found (`if-no-files-found: error`). - ---- - -## Code Formatting - -The `formatting.yml` workflow enforces code style on every pull request. It uses -`jidicula/clang-format-action` at version `22` and checks all files under the `source/` directory. - -A pull request that fails the formatting check must not be merged. Fix the formatting locally -before pushing. - -:::tip -Run `clang-format` on your changes before opening a pull request. Most editors and IDEs support -format-on-save when pointed at the project's `.clang-format` configuration file. Use this to -avoid formatting failures entirely. -::: - -The following additional checks are planned for future integration: - -- `clang-tidy`: static analysis -- `cmake-format` / `cmake-lint`: CMake file consistency -- `markdownlint`: documentation formatting - ---- - -## Release Pipeline - -The `release.yml` workflow is triggered automatically when a tag matching the pattern `v*.*.*` is -pushed to the repository. It is responsible for producing a complete, packaged draft release on -GitHub. - -### Steps - -1. **Compile artifacts**: Invokes `build.yml` via `workflow_call` with `package-artifacts: true`. - This compiles and archives the engine on all three platforms. -2. **Download artifacts**: Downloads all uploaded archives from the build job into a local - `artifacts/` directory. -3. **Create draft release**: Uses `softprops/action-gh-release` to create a **draft** release - with auto-generated release notes and all platform archives attached. - -The release is always created as a **draft**. A maintainer must manually review and publish it. -Do not publish a release without verifying the attached artifacts. - -### Versioning - -The resolved version string follows this priority: - -- If triggered by a Git tag (e.g., `v1.2.0`), the tag name is used directly. -- Otherwise, the first line of the `VERSION` file in the repository root is used. - -Always ensure the `VERSION` file is updated and committed before pushing a release tag. - -:::tip -The canonical way to cut a release is to push a version tag: -``` -git tag v1.2.0 -git push origin v1.2.0 -``` -The pipeline handles everything from that point forward. -::: - ---- - -## Shader Validation - -The `shader-ci.yml` workflow runs on pull requests that modify files in `source/shaders/`. It -targets the following file extensions: - -- `.hlsl` -- `.glsl` -- `.vert` -- `.frag` -- `.geom` - -:::tip -This workflow is currently a **stub**. The Vulkan SDK installation and the -`glslangValidator` invocation steps are planned but not yet implemented. Shader validation is -not yet enforced at the CI level. -::: - ---- - -## Documentation Sync - -The `sync-docs.yml` workflow runs on pushes to `main` when any file matching `**/docs/**` is -modified. It automatically mirrors documentation into the central -[`gp-docs`](https://github.com/GraphicalPlayground/gp-docs) portal repository. - -### How It Works - -1. Both `gp-engine` and `gp-docs` are checked out in parallel. -2. All files matching `*/docs/*` within `gp-engine` are discovered via `find`. -3. Each file is copied to the corresponding path under `gp-docs/docs/gp-engine/`, preserving the - directory structure but stripping the `docs/` path segment. -4. If any changes are detected in `gp-docs`, they are committed and pushed by the - `github-actions[bot]` user. - -The sync requires a Personal Access Token with write access to `gp-docs`, stored as the -`DOCS_SYNC_PAT` repository secret. Do not rotate or delete this secret without updating the -workflow. - -:::tip -Do not manually edit files under `gp-docs/docs/gp-engine/`. That directory is fully managed by -this sync workflow and any manual changes will be overwritten on the next push to `gp-engine`. -::: - ---- - -## Automated Labeling and Contributor Onboarding - -### Pull Request Labeler - -The `labeler.yml` workflow uses `actions/labeler@v6` to automatically apply labels to pull -requests based on the files changed. Label rules are defined in `.github/labeler.yml`. - -Keep the labeler configuration up to date whenever new top-level directories or source modules -are introduced. - -### Welcome Message - -The `welcome.yml` workflow posts an automated comment on a contributor's very first pull request. -It fires on `pull_request_target` when the PR is opened and is suppressed for bot accounts. - -The welcome message directs contributors to: - -- The formatting guidelines. -- The `CONTRIBUTING.md` file. - -Do not remove or disable this workflow. First impressions matter, and the message provides -immediate, actionable guidance to new contributors. - ---- - -## Concurrency Control - -The CI build workflow uses a concurrency group keyed on the workflow name and the Git ref: - -```yaml -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -``` - -When a new push arrives on the same branch while a build is already running, the in-progress run -is cancelled automatically. This prevents queuing multiple redundant builds during rapid iteration. - ---- - -## Permissions - -We follow the principle of least privilege for all workflow permissions. - -| Workflow | Permission | Reason | -|---|---|---| -| `build.yml` | `contents: read` | Source checkout only | -| `release.yml` | `contents: write` | Required to create and upload the GitHub release | -| `labeler.yml` | `contents: read`, `pull-requests: write` | Read files, apply labels | -| `welcome.yml` | `pull-requests: write` | Post the welcome comment | - -Do not elevate workflow permissions beyond what is listed here without a code review and a -documented justification in the workflow file itself. \ No newline at end of file diff --git a/docs/Introduction.md b/docs/Introduction.md deleted file mode 100644 index a4ad7cd..0000000 --- a/docs/Introduction.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Introduction - -_the following section will just demonstrate docs capacity to render markdown content, and will be -removed in the future_ - -## Tabs - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - - - This is an apple 🍎 - - - This is an orange 🍊 - - - This is a banana 🍌 - - - -## Code blocks - -_Normal code blocks_ - -```cpp -#include - -int main() -{ - std::cout << "Hello World!" << std::endl; - return 0; -} -``` - -_Code blocks with line numbers_ - -```cpp showLineNumbers -#include - -int main() -{ - std::cout << "Hello World!" << std::endl; - return 0; -} -``` - -_Code blocks with line numbers and highlights_ - -```cpp showLineNumbers {2-4,6} -#include - -int main() -{ - std::cout << "Hello World!" << std::endl; - return 0; -} -``` - -_Code blocks with filename_ - -```cpp title="source/Main.cpp" -#include - -int main() -{ - std::cout << "Hello World!" << std::endl; - return 0; -} -``` - -## Admonitions - -:::note -Some **content** with _Markdown_ `syntax`. Check [this api](#). -::: - -:::tip -Some **content** with _Markdown_ `syntax`. Check [this api](#). -::: - -:::info -Some **content** with _Markdown_ `syntax`. Check [this api](#). -::: - -:::warning -Some **content** with _Markdown_ `syntax`. Check [this api](#). -::: - -:::danger -Some **content** with _Markdown_ `syntax`. Check [this api](#). -::: - -## Collapsibles - -
- Click to expand -

This is the hidden content that will be revealed when the user clicks on the summary.

-
- -## Math - -Inline math: $E=mc^2$ - -Block math: -$$ -\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi} -$$ - -## Mermaid - -```mermaid -graph TD; - A-->B; - A-->C; - B-->D; - C-->D; -``` - -_This section will be removed in the future_ diff --git a/docs/Programming With C++/Coding Standard.md b/docs/Programming With C++/Coding Standard.md deleted file mode 100644 index e4a1e00..0000000 --- a/docs/Programming With C++/Coding Standard.md +++ /dev/null @@ -1,987 +0,0 @@ ---- -sidebar_position: 1 -title: Coding Standard -description: Write maintainable code by adhering to established standards and best practices. -tags: - - coding standard - - c++ ---- -# Coding Standard - -

Write maintainable code by adhering to established standards and -best practices.

- -At Graphical Playground, we have a few simple coding standards and conventions. -This document reflects the state of Graphical Playground' current coding standards. -Following the coding standards is mandatory. - -Code conventions are important to programmers for several reasons: - -- 80% of the lifetime cost of a piece of software goes to maintenance. -- Hardly any software is maintained for its whole life by the original author. -- Code conventions improve the readability of software, allowing engineers to understand new code - quickly and thoroughly. -- If we decide to expose source code to mod community developers, we want it to be easily - understood. -- Many of these conventions are required for cross-compiler compatibility. - -The coding standards below are C++-centric; however, the standard is expected to be followed no -matter which language is used. -A section may provide equivalent rules or exceptions for specific languages where it's applicable. - -## Class Organization - -**Classes** should be organized with the reader in mind rather than the writer. -Since most readers will use the public interface of the class, the public implementation should be -declared first, followed by the class's private implementation. - -```cpp showLineNumbers -class EXAMPLEPROJECT_API ExampleClass : public BaseClass -{ -public: - // Public interface goes here - ExampleClass(); - -protected: - // Private implementation goes here - virtual void protectedMethod(); -}; -``` - -## Copyright Notice - -Any source file (`.hpp`, `.cpp`, `.xaml`) provided by Graphical Playground for public distribution -must contain a copyright notice as the first line in the file. -The format of the notice must exactly match that shown below: - -``` -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com -``` - -## Naming Conventions - -When using Naming Conventions, all code and comments should use U.S. English spelling and grammar. - -- We use a combination of PascalCase for types and enumerations, and camelCase for variables, - constants and methods to ensure a clear distinction between definitions and instances. - - All type names, and enumerations must start with a capital letter. - There are no underscores between words. - To further distinguish types from instances, we use specific prefixes. - - Variables, constants and methods use lowerCamelCase, where the first letter is lowercase and - subsequent words are capitalized. - - Local Variables: Standard camelCase (e.g., `health`, `lastMouseCoordinates`). - - Private/Protected Fields: Use the `m_` prefix followed by camelCase to denote member variables - (e.g., `m_health`, `m_deltaCoordinates`). - - Global Variables: Use the `g_` prefix followed by camelCase to denote global variables (e.g., - `g_gameState`, `g_windowWidth`). - - Constants: Use the `k` prefix followed by PascalCase to denote constants (e.g., `kMaxHealth`, - `kDefaultWindowSize`). - - Methods: Use camelCase without any prefix (e.g., `calculateDamage()`, - `updatePlayerPosition()`). -- Type template parameters and nested type aliases based on those template parameters are not - subject to the above prefix rules, as the type category is unknown. -- Prefer a Type suffix after a descriptive term. -- Disambiguate template parameters from aliases by using an In prefix: -```cpp showLineNumbers -template -class Container -{ -public: - using ElementType = InElementType; -}; -``` -- Type and variable names are nouns. -- Method names are verbs that either describe the method's effect, or the return value of a method - without an effect. -- Macro names should be fully capitalized with words separated by underscores, and prefixed with - `GP_`. -```cpp -#define GP_AUDIT_SPRITER_IMPORT -``` - -Variable, method, and class names should be: - -- Clear -- Unambiguous -- Descriptive - -The greater the scope of the name, the greater the importance of a good, descriptive name. -Avoid over-abbreviation. - -All variables should be declared on their own line so that you can provide comment on the meaning of -each variable. - -You can use multi-line or single-line comments before a variable Blank lines are optional for -grouping variables. - -All functions that return a bool should ask a true/false question, such as `isVisible()` or -`shouldClearBuffer()`. - -A procedure (a function with no return value) should use a strong verb followed by an Object. -An exception is, if the Object of the method is the Object it is in. -In this case, the Object is understood from context. -Names to avoid include those beginning with "Handle" and "Process" because the verbs are ambiguous. - -We encourage you to prefix function parameter names with "Out" if: -- The function parameters are passed by reference. -- The function is expected to write to that value. - -This makes it obvious that the value passed in this argument is replaced by the function. - -Functions that return a value should describe the return value. -The name should make clear what value the function returns. -This is particularly important for boolean functions. -Consider the following two example methods: - -```cpp showLineNumbers -// what does true mean? -bool checkTea(Tea Tea); - -// name makes it clear true means tea is fresh -bool isTeaFresh(Tea Tea); - -float teaWeight; -int32 teaCount; -bool doesTeaStink; -FName teaName; -FString teaFriendlyName; -UClass* teaClass; -USoundCue* teaSound; -UTexture* teaTexture; -``` - -## Inclusive Word Choice - -When you work in the Graphical Playground codebase, we encourage you to strive to use respectful, -inclusive, and professional language. - -Word choice applies when you: -- name classes. -- functions. -- data structures. -- types. -- variables. -- files and folders. -- plugins. - -It applies when you write snippets of user-facing text for the UI, error messages, and -notifications. It also applies when writing about code, such as in comments and changelist -descriptions. - -The following sections provide guidance and suggestions to help you choose words and names that are -respectful and appropriate for all situations and audiences, and be a more effective communicator. - -### Racial, ethnic, and religious inclusiveness - -- Do not use metaphors or similes that reinforce stereotypes. - Examples include contrast black and white or *blacklist* and *whitelist*. -- Do not use words that refer to historical trauma or lived experience of discrimination. - Examples include *slave*, *master*, and *nuke*. - -### Gender inclusiveness - -- Refer to hypothetical people as *they*, *them*, and *their*, even in the singular. -- Refer to anything that is not a person as *it* and *its*. For example, a module, plugin, function, - client, server, or any other software or hardware component. -- Do not assign a gender to anything that doesn't have one. -- Do not use collective nouns like guys that assume gender. -- Avoid colloquial phrases that contain arbitrary genders, like "a poor man's X". - -### Slang - -- Remember that your words are being read by a global audience that may not share the same idioms - and attitudes, and who might not understand the same cultural references. -- Avoid slang and colloquialisms, even if you think they are funny or harmless. - These may be hard to understand for people whose first language is not English, and might not - translate well. -- Do not use profanity. - -### Overloaded Words - -- Many terms that we use for their technical meanings also have other meanings outside of - technology. Examples include *abort*, *execute*, or *native*. When you use words like these, always - be precise and examine the context in which they appear. - -## Portable C++ code - -The `int` and `unsigned int` types vary in size across platforms. -They are guaranteed to be at least 32 bits in width and are acceptable in code when the integer -width is unimportant. -Explicitly-sized types are used in serialized or replicated formats. - -Below is a list of common types: - -- `bool` for boolean values (NEVER assume the size of bool). - `BOOL` will not compile. -- `UInt8` for unsigned bytes (1 byte). -- `Int8` for signed bytes (1 byte). -- `UInt16` for unsigned shorts (2 bytes). -- `Int16` for signed shorts (2 bytes). -- `UInt32` for unsigned ints (4 bytes). -- `Int32` for signed ints (4 bytes). -- `UInt64` for unsigned quad words (8 bytes). -- `Int64` for signed quad words (8 bytes). -- `float`/`Float32` for single precision floating point (4 bytes). -- `double`/`Float64` for double precision floating point (8 bytes). - -## Comments - -Comments are communication and communication is vital. -The following sections detail some important things to keep in mind about comments (from Kernighan & -Pike The Practice of Programming). - -### Guidelines - -- Write self-documenting code. - For example: -```cpp showLineNumbers -// Bad: -t = s + l - b; - -// Good: -totalLeaves = smallLeaves + largeLeaves - smallAndLargeLeaves; -``` -- Write useful comments. - For example: -```cpp showLineNumbers -// Bad: -// increment Leaves -++Leaves; - -// Good: -// we know there is another tea leaf -++Leaves; -``` -- Do not over comment bad code, rewrite it instead. - For example: -```cpp showLineNumbers -// Bad: -// total number of leaves is sum of -// small and large leaves less the -// number of leaves that are both -t = s + l - b; - -// Good: -TotalLeaves = SmallLeaves + LargeLeaves - SmallAndLargeLeaves; -``` -- Do not contradict the code. - For example: -```cpp showLineNumbers -// Bad: -// never increment Leaves! -++Leaves; - -// Good: -// we know there is another tea leaf -++Leaves; -``` - -### Const Correctness - -Const is documentation as much as it is a compiler directive. -All code should strive to be const-correct. -This includes the following guidelines: -- Pass function arguments by const pointer or reference if those arguments are not intended to be - modified by the function. -- Flag methods as const if they do not modify the object. -- Use const iteration over containers if the loop isn't intended to modify the container. - -Const Example: -```cpp showLineNumbers -void someMutatingOperation(Thing& outResult, const gp::Array& inArray) -{ - // inArray will not be modified here, but outResult probably will be -} - -void Thing::someNonMutatingOperation() const -{ - // This code will not modify the Thing it is invoked on -} - -gp::Array stringArray; -for (const gp::String& : stringArray) -{ - // The body of this loop will not modify stringArray -} -``` - -Const is also preferred for by-value function parameters and locals. -This tells the reader that the variable will not be modified in the body of the function, which -makes it easier to understand. -If you do this, make sure that the declaration and the definition match, as this can affect the -JavaDoc process. - -```cpp showLineNumbers -void addSomeThings(const Int32 count); - -void addSomeThings(const Int32 count) -{ - const Int32 countPlusOne = count + 1; - // Neither count nor countPlusOne can be changed during the body of the function -} -``` - -One exception to this is pass-by-value parameters, which are moved into a container. -For more information, see the "Move semantics" section on this page. - -Example: -```cpp showLineNumbers -void Blah::setMemberArray(gp::Array inNewArray) -{ - MemberArray = moveTemp(inNewArray); -} -``` - -Never use const on a return type. -This inhibits move semantics for complex types, and will give compile warnings for built-in types. -This rule only applies to the return type itself, not the target type of a pointer or reference -being returned. - -Example: - -```cpp showLineNumbers -// Bad - returning a const array -const gp::Array getSomeArray(); - -// Fine - returning a reference to a const array -const gp::Array& getSomeArray(); - -// Fine - returning a pointer to a const array -const gp::Array* getSomeArray(); - -// Bad - returning a const pointer to a const array -const gp::Array* const getSomeArray(); -``` - -## Modern C++ Language Syntax - -Graphical Playground is built to be massively portable to many C++ compilers, so we are careful to -use features that are compatible with the compilers we might be supporting. -Sometimes, features are so useful that we will wrap them in macros and use them pervasively. -However, we usually wait until all the compilers we support are up to the latest standard. - -Graphical Playground compiles with a language version of C++23 by default and requires a minimum -version of C++20 to build. -We use many modern language features that are well-supported across modern compilers. -In some cases, we wrap usage of these features in preprocessor conditionals. -However, sometimes we decide to avoid certain language features entirely, for portability or other -reasons. - -Unless specified below, as a modern C++ compiler feature we are supporting, you should not use -compiler-specific language features unless they are wrapped in preprocessor macros or conditionals -and used sparingly. - -### Static Assert - -The `static_assert` keyword is valid for use where you need a compile-time assertion. - -### Override and Final - -The `override` and `final` keywords are valid for use, and their use is strongly encouraged. -There might be many places where these have been omitted, but they will be fixed over time. - -### Nullptr - -You should use `nullptr` instead of the C-style `NULL` macro in all cases. - -One exception to this is the use of `nullptr` in C++/CX builds (such as for Xbox One). -In this case, the use of `nullptr` is actually the managed null reference type. -It is mostly compatible with `nullptr` from native C++ except in its type and some template -instantiation contexts, and so you should use the `TYPE_OF_NULLPTR` macro instead of the more usual -`decltype(nullptr)` for compatibility. - -### Auto - -You shouldn't use `auto` in C++ code, except for the few exceptions listed below. -Always be explicit about the type you're initializing. -This means that the type must be plainly visible to the reader. - -C++20's structured binding feature should also not be used, as it is effectively a variadic `auto`. - -Acceptable use of `auto`: -- When you need to bind a lambda to a variable, as lambda types are not expressible in code. -- For iterator variables, but only where the iterator's type is verbose and would impair - readability. -- In template code, where the type of an expression cannot easily be discerned. - This is an advanced case. - -It's very important that types are clearly visible to someone who is reading the code. -Even though some IDEs are able to infer the type, doing so relies on the code being in a compilable -state. It also won't assist users of merge/diff tools, or when viewing individual source files in -isolation, such as on GitHub. - -If you're sure you are using `auto` in an acceptable way, always remember to correctly use `const`, -`&`, or `*` just like you would with the type name. -With `auto`, this will coerce the inferred type to be what you want. - -### Captures and Return Types - -Explicit captures should be used rather than automatic capture (`[&]` and `[=]`). This is important -for readability, maintainability, safety, and performance reasons, particularly when used with large -lambdas and deferred execution. - -Explicit captures declare the author's intent; therefore, mistakes are caught during code review. -Incorrect captures can cause serious bugs and crashes, which are more likely to become problematic -as the code is maintained over time. -Here are some additional things to keep in mind about lambda captures: -- By-reference capture and by-value capture of pointers (including the `this` pointer) can cause - data corruption and crashes if the execution of the lambda is deferred. - Local and member variables should never be captured by reference for deferred lambdas. -- By-value capture can be a performance concern if it makes unnecessary copies for a non-deferred - lambda. -- Accidentally captured pointers are invisible to the garbage collector. - Automatic capture catches `this` implicitly if any member variables are referenced, even though - `[=]` gives the impression of the lambda having its own copies of everything. -- Any deferred lambda use that does not follow these guidelines must have a comment explaining why - the lambda capture is safe. - -Explicit return types should be used for large lambdas or when you are returning the result of -another function call. -These should be considered in the same way as the `auto` keyword. - -### Strongly-Typed Enums - -Enumerated (Enum) classes are a replacement for old-style namespaced enums. -For example: - -```cpp showLineNumbers -// Old enum -namespace Thing -{ - enum Type - { - Thing1, - Thing2 - }; -} - -// New enum -enum class Thing : UInt8 -{ - Thing1, - Thing2 -} -``` - -Enum classes used as flags can take advantage of the `GP_ENABLE_ENUM_BITWISE_OPERATIONS(EnumType)` -macro to automatically define all of the bitwise operators: - -```cpp showLineNumbers -enum class Flags -{ - None = 0x00, - Flag1 = 0x01, - Flag2 = 0x02, - Flag3 = 0x04 -}; - -GP_ENABLE_ENUM_BITWISE_OPERATIONS(Flags) -``` - -The one exception to this is the use of flags in a truth context - this is a limitation of the -language. Instead, all enum flags should have an enumerator called `None` which is set to 0 for -comparisons: - -```cpp showLineNumbers -// Old -if (flags & Flags::Flag1) - -// New -if ((flags & Flags::Flag1) != Flags::None) -``` - -### Move Semantics - -All of the main container types, `gp::Array`, `gp::Map`, `gp::Set`, `gp::String` have move -constructors and move assignment operators. -These are often used automatically when passing or returning these types by value. - -Returning containers or strings by value can be beneficial for expressivity, without the usual cost -of temporary copies. -Rules around pass-by-value and use of `std::move` are still being established, but can already be -found in some optimized areas of the codebase. - -### Default Member Initializers - -Default member initializers can be used to define the defaults of a class inside the class itself: - -```cpp showLineNumbers -class Thing -{ -public: - Int32 maximumNumberOfWidgets = 10; - float widgetSize = 11.5f; - String widgetName = "DefaultWidget"; - WidgetType widgetType = WidgetType::Standard; -}; -``` - -Code written like this has the following benefits: -- It doesn't need to duplicate initializers across multiple constructors. -- It isn't possible to mix the initialization order and declaration order. -- The member type, property flags, and default values are all in one place. - This helps readability and maintainability. - -However, there are also some downsides: -- Any change to the defaults requires a rebuild of all dependent files. -- Headers can't change in patch releases of the engine, so this style can limit the kinds of fixes - that are possible. -- Some things can't be initialized in this way, such as base classes, pointers to forward-declared - types, values deduced from constructor arguments, and members initialized over multiple steps. -- Putting some initializers in the header and the rest in constructors in the .cpp file, can reduce - readability and maintainability. - -:::tip - -Use your best judgment when deciding whether to use default member initializers. -As a rule of thumb, default member initializers make more sense with in-game code than engine code. -Consider using config files for default values. - -::: - -## Code Formatting - -### Braces - -Brace wars are foul. -Graphical Playground has a long standing usage pattern of putting braces on a new line. -Please adhere to this usage, regardless of the size of the function or block. -For example: - -```cpp showLineNumbers -// Bad -Int32 getSize() const { return Size; } - -// Good -Int32 getSize() const -{ - return Size; -} -``` - -Always include braces in single-statement blocks. -For example: - -```cpp showLineNumbers -if (thing) -{ - return; -} -``` - -### If - Else - -Each block of execution in an if-else statement should be in braces. -This helps prevent editing mistakes. -When braces are not used, someone could unwittingly add another line to an if block. -The extra line wouldn't be controlled by the if expression, which would be bad. -It's also bad when conditionally compiled items cause if/else statements to break. -So always use braces. - -```cpp showLineNumbers -if (thingToCheck) -{ - doSomethingHere(); -} -else -{ - doOtherThingHere(); -} -``` - -A multi-way if statement should be indented with each `else if` indented the same amount as the -first `if`; this makes the structure clear to a reader: - -```cpp showLineNumbers -if (thingToCheck) -{ - doSomethingHere(); -} -else if (otherThingToCheck) -{ - doOtherThingHere(); -} -else -{ - doDefaultThingHere(); -} -``` - -### Tabs and Indenting - -Below are some standards for indenting your code. - -- Indent code by execution block. -- Use spaces for whitespace at the beginning of a line, not tabs. - -### Switch Statements - -Except for empty cases (multiple cases having identical code), switch case statements should -explicitly label that a case falls through to the next case. -Either include a break, or include a "falls through" comment in each case. -Other code control-transfer commands (return, continue, and so on) are fine as well. - -Always have a default case. -Include a break just in case someone adds a new case after the default. - -```cpp showLineNumbers -switch (condition) -{ - case 1: - ... - // falls through - - case 2: - ... - break; - - case 3: - ... - return; - - case 4: - case 5: - ... - break; - - default: - break; -} -``` - -## Namespaces - -You can use namespaces to organize your classes, functions and variables where appropriate. -If you do use them, follow the rules below. - -- `Using` declarations: - - Do not put `using` declarations in the global scope, even in a `.cpp` file (it will cause - problems with our "unity" build system.) -- It's okay to put `using` declarations within another namespace, or within a function body. -- If you put `using` declarations within a namespace, this will carry over to other occurrences of - that namespace in the same translation unit. - As long as you are consistent, it will be fine. -- You can only use `using` declarations in header files safely if you follow the above rules. -- Forward-declared types need to be declared within their respective namespace. - - If you don't do this, you will get link errors. -- If you declare a lot of classes or types within a namespace, it can be difficult to use those - types in other global-scoped classes (for example, function signatures will need to use explicit - namespace when appearing in class declarations). -- You can use using declarations to only alias specific variables within a namespace into your - scope. - - For example, using `Foo::Bar`. However, we don't usually do that in GP code. -- Macros cannot live in a namespace. - - They should be prefixed with `GP_` instead of living in a namespace, for example `GP_LOG`. - -## Physical Dependencies - -- File names should not be prefixed where possible. - - For example, `Mat2.cpp` instead of `TMat2.cpp`. This makes it easy to use tools like Workspace - Whiz or Visual Assist's Open File in Solution, by reducing the number of letters needed to - identify the file you want. -- All headers should protect against multiple includes with the `#pragma once` directive. - - Note that all compilers we use support `#pragma once`. -```cpp showLineNumbers -#pragma once -// -``` -- Try to minimize physical coupling. - - In particular, avoid including standard library headers from other headers. -- Forward declarations are preferred to including headers. -- When including a header, be as fine grained as possible. - - For example, do not include `Core.hpp`. Instead, you should include the specific headers in Core - that you need definitions from. -- Try to include every header you need directly to make fine-grained inclusion easier. -- Don't rely on a header that is included indirectly by another header you include. -- Don't rely on anything being included through another header. - Include everything you need. -- Modules have Private, Internal and Public source directories. - - Any definitions that are needed by other modules must be in headers in the Public directory. - Everything else should be in the Private directory. - The Internal directory is for definitions that are needed by other modules, but aren't intended - to be used by external users of the engine. - This is a soft distinction, but it can be useful for organization and maintainability. -- Split large functions into logical sub-functions. - - One area of compilers' optimizations is the elimination of common subexpressions. - The larger your functions are, the more work the compiler has to do to identify them. - This leads to greatly inflated build times. -- Don't use a large number of inline functions. - - Inline functions force rebuilds even in files which don't use them. - Inline functions should only be used for trivial accessors and when profiling shows there is a - benefit to doing so. -- Be conservative in your use of `GP_FORCEINLINE`. - - All code and local variables will be expanded out into the calling function. - This will cause the same build time problems as those caused by large functions. - -## Encapsulation - -Enforce encapsulation with the protection keywords. -Class members should almost always be declared private unless they are part of the public/protected -interface to the class. -Use your best judgment, but always be aware that a lack of accessors makes it hard to refactor later -without breaking plugins and existing projects. - -If particular fields are only intended to be usable by derived classes, make them private and -provide protected accessors. - -Use final if your class is not designed to be derived from. - -## General Style Issues - -- Minimize dependency distance. - - When code depends on a variable having a certain value, try to set that variable's value right - before using it. Initializing a variable at the top of an execution block, and not using it for a - hundred lines of code, gives lots of space for someone to accidentally change the value without - realizing the dependency. - Having it on the next line makes it clear why the variable is initialized the way it is and - where it is used. -- Split methods into sub-methods where possible. - - It is easier for someone to look at a big picture, and then drill down to the interesting - details, than it is to start with the details and reconstruct the big picture from them. - In the same way, it is easier to understand a simple method, that calls a sequence of several - well-named sub-methods, than it is to understand an equivalent method that simply contains all - the code in those sub-methods. -- In function declarations or function call sites, do not add a space between the function's name - and the parentheses that precede the argument list. -- Address compiler warnings. - - Compiler warning messages mean something is wrong. - Fix what the compiler is warning you about. - If you absolutely can't address it, use `#pragma` to suppress the warning, but this should only - be done as a last resort. -- Leave a blank line at the end of the file. - - All `.cpp` and `.hpp` files should include a blank line, to coordinate with gcc. -- Debug code should either be useful and polished, or not checked in. - - Debug code that is intermixed with other code makes the other code harder to read. -- Avoid repeating the same operation redundantly in loops. - - Move common subexpressions out of loops to avoid redundant calculations. - Make use of statics in some cases, to avoid globally-redundant operations across function calls, - such as constructing an `gp::Name` from a string literal. -- Be mindful of hot reload. - - Minimize dependencies to cut down on iteration time. - Don't use inlining or templates for functions which are likely to change over a reload. - Only use statics for things which are expected to remain constant over a reload. -- Use intermediate variables to simplify complicated expressions. - - If you have a complicated expression, it can be easier to understand if you split it into - sub-expressions, that are assigned to intermediate variables, with names describing the meaning - of the sub-expression within the parent expression. - For example: -```cpp showLineNumbers -if ((Blah->BlahP->WindowExists->etc && stuff) && - !(playerExists && gameStarted && playerStillHasPawn && - IsTuesday()))) -{ - doSomething(); -} -``` -Should be replaced with: - -```cpp showLineNumbers -const bool isLegalWindow = Blah->BlahP->WindowExists->etc && stuff; -const bool isPlayerDead = playerExists && gameStarted && playerStillHasPawn && isTuesday(); -if (isLegalWindow && !isPlayerDead) -{ - doSomething(); -} -``` -- Pointers and references should only have one space to the right of the pointer or reference. - - This makes it easy to quickly use Find in Files for all pointers or references to a certain - type. For example: -```cpp showLineNumbers -// Use this -ShaderType* ptr - -// Do not use these: -ShaderType *ptr -ShaderType * ptr -``` -- Shadowed variables are not allowed. - - C++ allows variables to be shadowed from an outer scope, but this makes usage ambiguous to a - reader. For example, there are three usable `count` variables in this member function: -```cpp showLineNumbers -class SomeClass -{ -public: - void func(const Int32 count) - { - for (Int32 count = 0; count != 10; ++count) - { - // Use Count - } - } - -private: - Int32 count; -} -``` -- Avoid using anonymous literals in function calls. - - Prefer named constants which describe their meaning. - This makes intent more obvious to a casual reader as it avoids the need to look up the function - declaration to understand it. -```cpp showLineNumbers -// Old style -trigger("Soldier", 5, true); - -// New style -const gp::Name objectName = "Soldier"; -const float cooldownInSeconds = 5; -const bool vulnerableDuringCooldown = true; -trigger(objectName, cooldownInSeconds, vulnerableDuringCooldown); -``` -- Avoid defining non-trivial static variables in headers. - - Non-trivial static variables cause an instance to be compiled into in every translation unit - that includes that header: -```cpp showLineNumbers -// SomeModule.h -static const gp::String usefulNamedString = "String"; - -// *Replace the above with:* - -// SomeModule.h -extern SOMEMODULE_API const gp::String usefulNamedString; - -// SomeModule.cpp -const gp::String usefulNamedString = "String"; -``` -- Avoid making extensive changes which do not change the code's behavior (for example: changing - whitespace or mass renaming of private variables) as these cause unnecessary noise in source - history and are disruptive when merging. - - If such a change is important, for example fixing broken indentation caused by an automated - merge tool, it should be submitted on its own and not mixed with behavioral changes. - - Prefer to fix whitespace or other minor coding standard violations only when other edits are - being made to the same lines or nearby code. - -## API Design Guidelines - -- Boolean function parameters should be avoided. - - In particular, boolean parameters should be avoided for flags passed to functions. - These have the same anonymous literal problem as mentioned previously, but they also tend to - multiply over time as APIs get extended with more behavior. - Instead, prefer an enum (see the advice on use of enums as flags in the - [Strongly-Typed Enums](#strongly-typed-enums) section): -```cpp showLineNumbers -// Old style -Cup* makeCupOfTea(Tea* tea, bool addSugar = false, bool addMilk = false, bool addHoney = false, bool addLemon = false); -Cup* cup = makeCupOfTea(tea, false, true, true); - -// New style -enum class TeaFlags -{ - None, - Milk = 0x01, - Sugar = 0x02, - Honey = 0x04, - Lemon = 0x08 -}; -GP_ENABLE_ENUM_BITWISE_OPERATIONS(TeaFlags) - -Cup* makeCupOfTea(FTea* tea, TeaFlags flags = TeaFlags::None); -Cup* cup = makeCupOfTea(tea, TeaFlags::Milk | TeaFlags::Honey); -``` -- This form prevents the accidental transposing of flags, avoids accidental conversion from pointer - and integer arguments, removes the need to repeat redundant defaults, and is more efficient. -- It is acceptable to use `bools` as arguments when they are the complete state to be passed to a - function like a setter, such as void `Widget::setEnabled(bool enabled)`. Though consider - refactoring if this changes. -- Avoid overly-long function parameter lists. - - If a function takes many parameters then consider passing a dedicated struct instead: -```cpp showLineNumbers -// Old style -gp::UniquePtr makeTeaForParty(const TeaFlags* teaPreferences, UInt32 numCupsToMake, Kettle* kettle, TeaType teaType = TeaType::EnglishBreakfast, float brewingTimeInSeconds = 120.0f); - -// New style -struct TeaPartyParams -{ - const TeaFlags* teaPreferences = nullptr; - UInt32 numCupsToMake = 0; - Kettle* kettle = nullptr; - TeaType teaType = TeaType::EnglishBreakfast; - float brewingTimeInSeconds = 120.0f; -}; -gp::UniquePtr makeTeaForParty(const TeaPartyParams& params); -``` -- Interface classes should always be abstract. - - Interface classes are prefixed with "I" and must not have member variables. - Interfaces are allowed to contain methods that are not pure-virtual, and can contain methods - that are non-virtual or static, as long as they are implemented inline. -- Use the `virtual` and `override` keywords when declaring an overriding method. - -When declaring a virtual function in a derived class that overrides a virtual function in the parent -class, you must use both the `virtual` and the `override` keywords. -For example: - -```cpp showLineNumbers -class A -{ -public: - virtual void func() {} -}; - -class B : public A -{ -public: - virtual void func() override; -} -``` - -## Platform-Specific Code - -Platform-specific code should always be abstracted and implemented in platform-specific source files -in appropriately named subdirectories, for example: - -``` -/source/runtime/hal/private/[PLATFORM]/PlatformMemory.cpp -``` - -In general, you should avoid adding any uses of `PLATFORM_[PLATFORM]`. For example, avoid adding -`PLATFORM_XBOXONE` to code outside of a directory named `[PLATFORM]`. Instead, extend the hardware -abstraction layer to add a static function, for example in FPlatformMisc: - -```cpp showLineNumbers -GP_FORCEINLINE static Int32 getMaxPathLength() -{ - return 128; -} -``` - -Platforms can then override this function, returning either a platform-specific constant value or -even using platform APIs to determine the result. -If you force-inline the function it has the same performance characteristics as using a define. - -In cases where a define is absolutely necessary, create new `#define` directives that describe -particular properties that can apply to a platform, for example `PLATFORM_USE_PTHREADS`. Set the -default value in `Platform.hpp` and override for any platforms which require it in the -platform-specific `Platform.hpp` file. - -For example, in `Platform.hpp` we have: -```cpp showLineNumbers -#ifndef PLATFORM_USE_PTHREADS - #define PLATFORM_USE_PTHREADS 1 -#endif -``` - -`WindowsPlatform.hpp` has: -```cpp showLineNumbers -#define PLATFORM_USE_PTHREADS 0 -``` - -Cross-platform code can then use the define directly without needing to know the platform. - -```cpp showLineNumbers -#if PLATFORM_USE_PTHREADS - #include "hal/PThreadRunnableThread.h" -#endif -``` - -We centralize the platform-specific details of the engine which allows details to be contained -entirely within platform-specific source files. -Doing so makes it easier to maintain the engine across multiple platforms, additionally you are able -to port code to new platforms without the need to scour the codebase for platform-specific defines. - -Keeping platform code in platform-specific folders is also a requirement for NDA platforms such as -PlayStation, Xbox and Nintendo Switch. - -It is important to ensure the code compiles and runs regardless of whether the `[PLATFORM]` -subdirectory is present. -In other words, cross-platform code should never be dependent on platform-specific code. diff --git a/docs/Programming With C++/Engine Architecture/Include What You Use.md b/docs/Programming With C++/Engine Architecture/Include What You Use.md deleted file mode 100644 index 2ee64f4..0000000 --- a/docs/Programming With C++/Engine Architecture/Include What You Use.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -sidebar_position: 2 -title: Include What You Use (IWYU) -description: Include What You Use (IWYU) is a tool that helps ensure you only include the headers you actually need in your C++ files. -tags: - - c++ - - coding standard - - iwyu - - includes - - architecture ---- - -# Include-What-You-Use (IWYU) - -At Graphical Playground, our C++ codebase strictly adheres to the "Include-What-You-Use" (IWYU) -philosophy. Managing physical dependencies effectively is crucial for preventing bloated translation -units, reducing compilation times, and making code easier to refactor. - -The following guidelines outline our standards for managing header inclusions and forward -declarations. - -## Explicit and Direct Inclusions - -You must explicitly include the headers for the types and functions you use in your code. - -- **Never rely on indirect inclusions**: Do not rely on a header that is included indirectly by - another header you include. If your .cpp or .hpp file uses a type, it must include the header - that defines that type directly. -- **Include everything you need**: Try to include every header you need directly to make - fine-grained inclusion easier. - -:::danger Hidden Dependencies -Relying on indirect (transitive) includes creates fragile code. If a third-party or engine header -is updated and removes an `#include` internally, your code will suddenly fail to compile even if you -didn't change it. Always include what you use directly! -::: - -## Fine-Grained Headers - -We avoid monolithic headers that drag in massive amounts of unrelated code. - -- **Be as fine-grained as possible**: When including a header, be as fine grained as possible. -- **Avoid module-level headers**: For example, do not include `Core.hpp`. Instead, you should - include the specific headers in Core that you need definitions from. - -```cpp -// Bad: Pulls in the entire Core module, drastically increasing compile times -#include "core/Core.hpp" - -// Good: Only includes exactly what is needed for this translation unit -#include "core/memory/UniquePtr.hpp" -#include "core/math/Vec3.hpp" -``` - -## Forward Declarations - -Forward declarations are a powerful tool for minimizing physical coupling between files. - -- **Prefer forward declarations**: Forward declarations are preferred to including headers. -- **Namespace rules**: Forward-declared types need to be declared within their respective namespace. - If you don't do this, you will get link errors. - -If your header file only utilizes a type by pointer (`*`) or reference (`&`), you should forward -declare it rather than including its full header definition. - -```cpp showLineNumbers -#pragma once - -// Good: Forward declaring the type inside its namespace avoids an #include -namespace gp -{ - class RenderDevice; -} - -class MyClass -{ -public: - // Only uses a pointer, so the full definition of RenderDevice isn't needed here - void initialize(gp::RenderDevice* device); -}; -``` - -## Header Protection - -To prevent compiler errors caused by circular dependencies or multiple inclusions during the -preprocessor phase, all header files must be protected. - -- **Use pragma once**: All headers should protect against multiple includes with the `#pragma once` - directive. All compilers we use support this directive. - -```cpp -#pragma once - -// -``` diff --git a/docs/Programming With C++/Engine Architecture/Modules.md b/docs/Programming With C++/Engine Architecture/Modules.md deleted file mode 100644 index e6245a7..0000000 --- a/docs/Programming With C++/Engine Architecture/Modules.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -sidebar_position: 1 -title: Modules -description: Modules are the building blocks of GP Engine's software architecture. You can organize your code into modules to create more efficient and maintainable projects. -tags: - - c++ - - architecture ---- -import FileTree from '@site/src/components/FileTree'; - -# Graphical Playground Engine Modules - -

Modules are the building blocks of GP Engine's software -architecture. You can organize your code into modules to create more efficient and maintainable -projects.

- -**Modules** are the basic building block of Graphical Playground Engine's (GPE) software -architecture. These encapsulate specific editor tools, runtime features, libraries, or other -functionality in standalone units of code. - -All projects and plugins have their own **primary module** by default, however, you can define other -modules outside of these to organize your code. - -This page provides an overview of how modules are structured and how they can benefit your GP Engine -projects. - -:::note -GP Engine modules are not related to C++ 20 modules. -::: - -## Benefits of Using Modules - -Organizing your project with modules provides the following benefits: -- Modules enforce good code separation, providing a means to encapsulate functionality and hide - internal parts of the code. -- Modules are compiled as separate compilation units. - This means only modules that have changed will need to compile, and build times for larger - projects will be significantly faster. -- Modules are linked together in a dependency graph and limit header includes to code that is - actually used, per the [Include What You Use (IWYU)](./Include%20What%20You%20Use.md) standard. - This means modules that are not used in your project will be safely excluded from compilation. -- You can control when specific modules are loaded and unloaded at runtime. - This provides a way to optimize the performance of your project by managing which systems are - available and active. -- Modules can be included or excluded from your project based on certain conditions, such as which - platform the project is being compiled for. - -In summary, if you observe best practices with modules, your project's code will be better -organized, will compile more efficiently, and will be more reusable than if you put all of your -project's code into a single module. - -## Setting Up a Module - -The following is an overview of how to build and implement a module from scratch. -If you follow these steps, you will create a gameplay module separate from the primary module that -your project includes by default. - -1. Create a directory for your module at the top level of your project's Source folder. - This directory should have the same name as your module. - -:::tip You can place modules in any subdirectory within your Source folder, at any number of levels -deep. This makes it possible to use subdirectories to group modules. -::: - -2. Create a `CMakeLists.txt` file inside your module's root directory and use it to define - dependencies with other modules. - This makes it possible for the CMake build system to discover your module. -3. Create Private and Public subfolders inside your module's root directory. -4. Create a `[ModuleName]Module.cpp` file in the Private subfolder for your module. - Use this to provide methods for starting up and shutting down your module, as well as other - common functions that GP Engine uses to manage modules. -5. List your module as a dependency in the `CMakeList.txt` file for any module that will need to use - it. - -:::warning TODO: Describe how to set up a module to be loaded at runtime instead of startup, and how -to set up a module to be included or excluded based on certain conditions. -::: - -## Understanding the Structure of a Module - -All modules should be placed in the Source directory for either a plugin or project. -The module's root folder should have the same name as the corresponding module. - -There should also be a `CMakeLists.txt` file for each module in its root folder, and its C++ code -should be contained in **Private** and **Public** folders. - -The following is an example of the recommended folder structure for a module: - - - -### Configuring Dependencies in the CMakeLists.txt File - -:::warning -TODO: Add example of how to set up a module to be loaded at runtime instead of startup, -and how to set up a module to be included or excluded based on certain conditions. -::: - -### Private and Public Dependencies - -You should use the `PublicDependencyModuleNames` list if you use the classes from a module publicly, -such as in a public `.hpp` file. -This will make it possible for other modules that depend on your module to include your header files -without issues. - -You should put a module's name in the `PrivateDependencyModuleNames` list if they are only used -privately, such as in `.cpp` files. -Private dependencies are preferred wherever possible, as they can reduce your project's compile -times. - -:::tip -You can make many dependencies private instead of public by using forward declarations in -your header files. -::: - -### Using the Private and Public Folders - -If your module is a regular C++ module, its C++ files should be placed in the Private and Public -subfolders inside your module's root directory. - -These do not have any relation to the `Private`, `Public`, or `Protected` access specifiers in your -C++ code. Instead, they control the availability of the module's code to other modules. -If you use these folders, all `.cpp` files should be placed in the Private folder. -Header (`.hpp`) files should be placed in the Private and Public folders per the guidelines below. - -If you place a header file in the Private folder, its contents will not be exposed to any modules -outside its owning module. -Classes, structs, and enums in this folder will be accessible to other classes inside the same -module, but they will not be available to classes in other modules. - -If you place a header in the Public folder, the Graphical Playground build system will expose its -contents to any other module that has a dependency on the current module. -Classes in outside modules will be able to extend classes contained in the Public folder, and you -will be able to create variables and references using classes, structs, and enums in the Public -folder as well. The `Private`, `Public`, and `Protected` specifiers will take effect as normal for -functions and variables. - -If you are working on a module that will not be made a dependency for others, you do not need to use -the `Private` and `Public` folders. -Any code outside of these folders will behave as if it were Private. -A typical example of this would be your game's primary module, which will likely be at the end of -the dependency chain. - -You can further organize your code by creating subfolders within the `Public` and `Private` folders. -For any new folder you create within `Public`, create a corresponding folder with the same name in -`Private`. Similarly, for any header file you place in `Public`, make sure its corresponding `.cpp` -files are always in the corresponding folder in `Private`. diff --git a/docs/Programming With C++/Engine Architecture/_category_.json b/docs/Programming With C++/Engine Architecture/_category_.json deleted file mode 100644 index fc8c07e..0000000 --- a/docs/Programming With C++/Engine Architecture/_category_.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Engine Architecture", - "position": 3, - "description": "Programming in the Graphical Playground Engine Architecture.", - "link": { - "type": "generated-index" - } -} diff --git a/docs/Programming With C++/GP Build Tool/README.md b/docs/Programming With C++/GP Build Tool/README.md deleted file mode 100644 index 9a1104c..0000000 --- a/docs/Programming With C++/GP Build Tool/README.md +++ /dev/null @@ -1,725 +0,0 @@ ---- -sidebar_position: 0 -title: GP Build Tool -description: A deep-dive into the custom CMake orchestration system that powers every module, plugin, and executable in the Graphical Playground Engine. -tags: - - c++ - - build system - - cmake - - gpbt - - architecture ---- - -# Graphical Playground Build Tool (GPBT) - -

- A custom CMake orchestration layer that manages target scopes, dependency visibility, and - topological build ordering across the entire engine, so you never have to think about it. -

- -The Graphical Playground Build Tool (GPBT) is the internal CMake layer that sits above raw CMake -and gives every engineer a clean, declarative API for defining engine targets. Instead of writing -hundreds of lines of `target_link_libraries`, `target_include_directories`, and `add_library` calls -by hand, you describe *what* your module needs and GPBT figures out *how* to build it correctly. - -This document covers everything: the internal phases, all target types, the full dependency model, -platform-conditional features, and every macro in the public API. - ---- - -## How It Works: The Three Build Phases - -Understanding the build phases is the key to understanding *why* GPBT works the way it does. A -naive CMake setup processes `CMakeLists.txt` files in discovery order, which means a module that -depends on another module discovered later would fail to configure. GPBT solves this with a -two-pass system. - -### Phase 1 - REGISTRATION - -GPBT recursively scans the source tree for every `CMakeLists.txt` file, executing each one in a -lightweight "registration" mode. During this pass, each target definition records only its name, -type, and dependency list into global CMake properties. No actual CMake targets are created yet. - -This gives GPBT a complete map of the entire dependency graph before any target is built. - -### Phase 2 - CONFIGURATION - -With the full graph known, GPBT performs a **topological sort** using a depth-first algorithm. This -determines the correct order in which targets must be configured, dependencies always come before -the targets that depend on them. - -Once sorted, GPBT re-processes each `CMakeLists.txt` in the correct order. This time, each target -definition creates the real CMake target (`add_library`, `add_executable`), sets all properties, -and links all dependencies. - -:::tip Why does this matter for students? -If module B depends on module A, but the file scanner discovers B before A, a naive system would -fail because A's CMake target doesn't exist yet when B tries to link against it. The two-phase -system avoids this entirely: by the time B is configured, A is guaranteed to already exist. -::: - -### Phase 3 - GENERATION - -This is standard CMake. After GPBT finishes configuration, CMake generates the final build system -files (Ninja, Makefile, Visual Studio `.sln`, etc.) from the configured targets. - -### Circular Dependency Detection - -During the topological sort, if two targets depend on each other (directly or transitively), the -sort algorithm will stall. GPBT detects this and emits a targeted error: - -```text -FATAL ERROR: Circular dependency detected! The following targets form an infinite dependency -loop and cannot be ordered: audio;engine -``` - -If a dependency name does not match any registered target at all (a typo or a missing module), -GPBT emits a warning identifying the exact missing name before halting. - ---- - -## Target Types - -GPBT v0.3.0 supports three target types, each with a distinct purpose. - -| Type | CMake Kind | Shared? | Use Case | -| --- | --- | --- | --- | -| `module` | Library | Follows `BUILD_SHARED_LIBS` | Core engine systems (Core, RHI, Audio, etc.) | -| `executable` | Executable | - | Final programs (Editor, Standalone) | -| `plugin` | Shared Library | Always shared | Optional runtime-loaded extensions | - -### Modules - -A module is the standard building block of the engine. It compiles to either a static or shared -library depending on the `GP_BUILD_SHARED` CMake option. Most of the engine, Core, Engine, -RHI, HAL, Renderer, are modules. - -### Executables - -An executable is a final program that links against one or more modules. The Editor and the -Standalone player launcher are executables. - -### Plugins - -A plugin is always built as a shared library, regardless of the global `GP_BUILD_SHARED` setting. -Plugins are designed to be discovered and loaded at runtime by the engine's plugin system. They -appear in the `plugins/` IDE folder and their output goes to the plugins output directory. - -:::note -Plugins are a v0.3.0 addition. Use them for optional features that the engine can load and unload -at runtime, such as scripting backends, renderer extensions, or platform-specific services. -::: - ---- - -## Creating Targets - -Every target definition follows the same bracket pattern: open with a `gpStart*` macro, configure -the target with property macros, then close with a `gpEnd*` macro. The scoping system ensures that -variables set inside a target definition cannot accidentally bleed into adjacent definitions. - -### Modules - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(my_module) - # ... configuration macros go here ... -gpEndModule() -``` - -### Executables - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartExecutable(my_program) - # ... configuration macros go here ... -gpEndExecutable() -``` - -### Plugins - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartPlugin(my_plugin) - # ... configuration macros go here ... -gpEndPlugin() -``` - ---- - -## Dependency Management - -Dependencies are the heart of GPBT. Every `gpAdd*Dependency` call maps to a `target_link_libraries` -call under the hood, but GPBT adds strict duplicate prevention, automatic name resolution (from -short names like `core` to fully-qualified CMake targets like `gp::core`), and correct -topological ordering. - -### The Four Visibility Levels - -#### `gpAddPublicDependency(dependency)` - -The dependency is linked **PUBLIC**. This means: -- Your target links against it. -- Any target that links against *your* target will also automatically link against it. - -Use this when the dependency appears in your public headers, i.e., consumers of your module need -it to compile code that uses your module. - -```cmake -gpAddPublicDependency(core) # gp::core is exposed to all consumers -``` - -#### `gpAddPrivateDependency(dependency)` - -The dependency is linked **PRIVATE**. This means: -- Your target links against it. -- Consumers of your target do **not** inherit it. - -Use this for implementation-only dependencies, libraries used only in your `.cpp` files, not in -any header that other modules include. - -```cmake -gpAddPrivateDependency(SDL3::SDL3-static) # used only internally -``` - -#### `gpAddInternalDependency(dependency)` - -The dependency is linked **PRIVATE** and is treated as an implementation detail. Use this for -dependencies that are needed to build the module's internal units but are not part of the module's -public contract. Semantically, this is the same as private at the CMake level, but it signals -intent to other engineers reading the `CMakeLists.txt`. - -```cmake -gpAddInternalDependency(spirv_cross_core) -``` - -#### `gpAddDynamicDependency(dependency)` - -A dynamic dependency creates a **build-order edge** without any link-time coupling. This means: -- The dependency target is guaranteed to be built before your target. -- Your target does **not** link against it at compile time. -- The dependency is expected to be loaded at runtime. - -This is the correct relationship for RHI backends and plugins: the base `rhi` module does not -link against `rhi/vulkan` or `rhi/d3d12`, it loads them at runtime. But the backends must -exist in the output directory before the engine runs, so they must be built first. - -```cmake -gpAddDynamicDependency(rhi/null) -gpAddDynamicDependency(rhi/vulkan) -``` - -:::note For students -Think of dynamic dependencies like a game level that needs certain DLLs in the same folder to run. -The level file does not reference them at compile time, but at runtime the engine needs to find and -load them. `add_dependencies` in CMake ensures they are built, but they are not linked. -::: - -### Platform-Conditional Dependencies - -Often, a dependency is only valid on certain platforms, a Windows-only graphics driver, a -Linux-only threading library, a macOS-only display framework. Rather than wrapping every dependency -in `if(WIN32)` blocks, GPBT provides platform-aware wrappers for all four visibility levels. - -**Supported platform tokens:** `WINDOWS`, `LINUX`, `MAC`, `UNIX`, `ALL` - -```cmake -gpAddPublicDependencyOnPlatform(dependency platform) -gpAddPrivateDependencyOnPlatform(dependency platform) -gpAddInternalDependencyOnPlatform(dependency platform) -gpAddDynamicDependencyOnPlatform(dependency platform) -``` - -#### Example: Platform-Specific RHI Dependencies - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(rhi) - gpAddPublicDependency(core) - - # The null RHI is always present as a safe fallback - gpAddDynamicDependency(rhi/null) - - # Instead of if(WIN32) blocks, use platform-conditional macros - gpAddDynamicDependencyOnPlatform(rhi/d3d11 WINDOWS) - gpAddDynamicDependencyOnPlatform(rhi/d3d12 WINDOWS) - gpAddDynamicDependencyOnPlatform(rhi/vulkan UNIX) - gpAddDynamicDependencyOnPlatform(rhi/opengl UNIX) - gpAddDynamicDependencyOnPlatform(rhi/metal MAC) -gpEndModule() -``` - -:::tip -Platform-conditional macros are evaluated at configure time. On Linux, `WINDOWS` deps are silently -skipped. On macOS, `LINUX` deps are skipped. This keeps module definitions clean and readable -without cluttering them with `if`/`endif` blocks. -::: - ---- - -## Source File Management - -### Automatic Discovery - -When a target is initialized, GPBT automatically globs all `*.cpp`, `*.cc`, and `*.cxx` files -from the `private/` and `internal/` directories relative to the target's `CMakeLists.txt` location. -Header files (`*.h`, `*.hpp`, `*.hh`, `*.hxx`) from `public/`, `internal/`, and `private/` are -collected for IDE integration. - -You do not need to list source files manually for the standard directory layout. - -### Expected Directory Structure - -``` -source/runtime/my_module/ -├── CMakeLists.txt -├── public/ # Public headers, exposed to consumers -│ └── my_module/ -│ └── MyClass.hpp -├── private/ # Implementation files, not exposed -│ └── MyClass.cpp -├── internal/ # Internal headers, used within the module -│ └── MyClassInternal.hpp -├── tests/ # Test sources (see Testing page) -│ └── MyClassTests.cpp -└── benchmarks/ # Benchmark sources (see Testing page) - └── MyClassBenchmarks.cpp -``` - -### Manual Source Management - -When you have sources outside the standard layout or need fine-grained control: - -```cmake -# Add specific files or files from a custom directory -gpTargetAddSources(${__targetLocation}/generated/MyGeneratedClass.cpp) -gpTargetAddSourcesFromDirectory(${__targetLocation}/platform/linux) - -# Remove files matching a directory name -gpTargetExcludeDirectory(windows) - -# Remove files matching a specific filename -gpTargetExcludeFile(LegacyHelper.cpp) - -# Remove files matching a regex pattern -gpTargetExcludeSourcesRegex(".*\\.generated\\.cpp$") -``` - -### Header-Only Targets - -If your target contains only headers and no compiled sources, mark it explicitly. Without this, -GPBT would add a dummy `.cpp` file to satisfy CMake's requirement that every library have at -least one source file. - -```cmake -gpStartModule(my_header_only_lib) - gpTargetSetIsHeaderOnly(TRUE) -gpEndModule() -``` - ---- - -## Compile Definitions - -### Built-In Engine Definitions - -GPBT automatically stamps a standard set of compile definitions onto every target, tests -executable, and benchmark executable. These definitions are always consistent across all targets: - -| Definition | When Active | -| --- | --- | -| `GP_BUILD_DEBUG=1` | Debug configuration | -| `GP_BUILD_RELEASE=1` | Release configuration | -| `GP_BUILD_RELWITHDEBINFO=1` | RelWithDebInfo configuration | -| `GP_BUILD_MINSIZEREL=1` | MinSizeRel configuration | -| `GP_ENABLE_PROFILING=1` | When `GP_ENABLE_PROFILING` CMake option is ON | -| `GP_BUILD_EDITOR=1` | When `GP_BUILD_EDITOR` CMake option is ON | -| `GP_USE_VULKAN=1` | When `GP_USE_VULKAN` is ON | -| `GP_USE_D3D12=1` | When `GP_USE_D3D12` is ON | -| `GP_USE_D3D11=1` | When `GP_USE_D3D11` is ON | -| `GP_USE_METAL=1` | When `GP_USE_METAL` is ON | -| `GP_USE_OPENGL=1` | When `GP_USE_OPENGL` is ON | - -Additionally, every target automatically receives a unique export macro: - -``` -GP__API_EXPORTS -``` - -For example, the `rhi/vulkan` module gets `GP_RHI_VULKAN_API_EXPORTS`. This definition is used -to tag your DLL-exported symbols correctly on Windows. - -### Custom Compile Definitions - -You can add your own compile definitions with the standard visibility rules: - -```cmake -gpAddPublicDefinitions(MY_FEATURE_ENABLED=1) # visible to consumers -gpAddPrivateDefinitions(INTERNAL_DEBUG_MODE=1) # implementation only -gpAddInternalDefinitions(ENABLE_EXTRA_LOGGING=1) # internal implementation only -``` - -Definitions must follow the format `KEY` or `KEY=VALUE`. A bare `KEY` is automatically expanded -to `KEY=1`. - ---- - -## Compile Flags - -### Adding Flags - -```cmake -gpAddPrivateCompileFlag(-ffast-math) # implementation only -gpAddPublicCompileFlag(-fopenmp) # propagated to consumers -``` - -:::warning -GPBT validates flag format and will emit a fatal error if a MSVC-style flag (starting with `/`) -is used with a non-MSVC compiler. Use compiler-conditional macros (`if(MSVC)`) for flags that -differ between compilers. -::: - -### Replacing Flags - -To replace an existing flag (for example, to switch from `-O2` to `-O3`): - -```cmake -# Remove flags matching the regex and add the new flag in their place -gpTargetReplaceCompileFlag(-O3 "-O[0-9]+" private) -``` - -### Strict Warnings - -By default, GPBT enables strict warnings for all targets. The exact flags depend on the detected -compiler: - -- **MSVC**: `/W4 /WX /permissive-` -- **Clang / AppleClang**: `-Wall -Wextra -Werror -Wno-unused-parameter -Wno-missing-field-initializers` -- **GCC**: `-Wall -Wextra -Werror -Wno-unused-parameter -Wno-missing-field-initializers` - -You can disable strict warnings for a target if needed: - -```cmake -gpStartModule(legacy_module) - gpTargetSetStrictWarningEnabled(FALSE) -gpEndModule() -``` - ---- - -## Target Properties - -### Output Name - -By default, a target's output name is `gp_`. For example, the -`rhi/vulkan` module compiles to `gp_rhi_vulkan.so` on Linux. You can override this: - -```cmake -gpSetTargetOutputName(gpeditor) # output file will be named gpeditor -``` - -### Precompiled Headers - -Add one or more precompiled headers to speed up compilation of large modules: - -```cmake -gpTargetAddPCHHeaders(${__targetLocation}/private/CorePCH.hpp) -``` - -### Unity Build - -Unity builds batch multiple `.cpp` files into a single translation unit for faster cold-build -throughput (at the cost of hiding certain `#include` hygiene issues). GPBT uses a batch size of -16 source files per unity file. - -```cmake -gpStartModule(renderer) - gpTargetSetUnityBuildEnabled(TRUE) -gpEndModule() -``` - -:::tip When to use Unity Build -Unity builds are most beneficial on large modules with many small `.cpp` files. They are -not recommended during active development because they can slow down incremental builds and make -linker errors harder to attribute to specific files. Enable them for CI release builds. -::: - -### IDE Folder Override - -By default, GPBT places targets in the following IDE folders: - -| Target Type | Default Folder | -| --- | --- | -| `module` | `modules` | -| `executable` | `executables` | -| `plugin` | `plugins` | -| `*_tests` | `tests` | -| `*_benchmarks` | `benchmarks` | - -You can override the folder for any target: - -```cmake -gpStartModule(rhi/vulkan) - gpTargetSetFolder("modules/rhi") -gpEndModule() -``` - ---- - -## Executable-Specific Features - -### GUI vs Console Window - -On Windows, executables can be either console applications or GUI applications (which suppresses -the console window at launch). The default is console (`FALSE`). - -```cmake -gpStartExecutable(editor) - gpExecutableSetIsGUI(FALSE) # FALSE = console, TRUE = GUI (no console window on Windows) -gpEndExecutable() -``` - -The macro also stamps `GP_EXECUTABLE_IS_GUI=<0|1>` as a compile definition so your C++ code can -branch on it at compile time. - -### Windows Resource Files - -On Windows, executables can embed `.rc` resource files (icons, version info, manifests): - -```cmake -gpStartExecutable(editor) - gpExecutableAddResource(${__targetLocation}/resources/AppIcon.rc) -gpEndExecutable() -``` - -### Custom Entry Point - -If your executable uses a non-standard entry point: - -```cmake -gpExecutableSetEntryPoint(${__targetLocation}/private/WinMain.cpp) -``` - ---- - -## Install Export - -Once you have defined all your targets, you can generate a proper CMake package configuration -file that allows other CMake projects to `find_package(GPEngine)` and use the engine's targets. - -Call `gpGenerateInstallExport()` once from your root `CMakeLists.txt`, after all -`add_subdirectory()` calls: - -```cmake showLineNumbers -# CMakeLists.txt (root) - -add_subdirectory(thirdparty) -add_subdirectory(source) - -# Generate the install export, call this exactly once at the root level -gpGenerateInstallExport() -``` - -This generates: -- `GPEngineTargets.cmake`, the exported target definitions -- `GPEngineConfig.cmake`, the `find_package` entry point -- `GPEngineConfigVersion.cmake`, the version compatibility file - -:::note -This feature requires a `cmake/GPEngineConfig.cmake.in` template file in your source root. -::: - ---- - -## Complete API Reference - -### Target Lifecycle - -| Macro | Description | -| --- | --- | -| `gpStartModule(name)` | Open a module (library) target scope | -| `gpStartExecutable(name)` | Open an executable target scope | -| `gpStartPlugin(name)` | Open a plugin (always-shared library) target scope | -| `gpEndModule()` | Close a module scope | -| `gpEndExecutable()` | Close an executable scope | -| `gpEndPlugin()` | Close a plugin scope | -| `gpScanForTargets()` | Trigger REGISTRATION + CONFIGURATION for a directory tree | - -### Source Management - -| Macro | Description | -| --- | --- | -| `gpTargetAddSources(files...)` | Append explicit source files | -| `gpTargetAddSourcesFromDirectory(dir)` | Glob sources from an arbitrary directory | -| `gpTargetExcludeDirectory(name)` | Remove all sources under a named directory | -| `gpTargetExcludeFile(name)` | Remove a specific source file by name | -| `gpTargetExcludeSourcesRegex(regex)` | Remove all sources matching a regex | -| `gpTargetAddPCHHeaders(header)` | Add a precompiled header | -| `gpTargetSetIsHeaderOnly(value)` | Mark the target as header-only (no compiled sources) | - -### Dependencies - -| Macro | Description | -| --- | --- | -| `gpAddPublicDependency(dep)` | Link PUBLIC, propagated to consumers | -| `gpAddPrivateDependency(dep)` | Link PRIVATE, implementation only | -| `gpAddInternalDependency(dep)` | Link PRIVATE, internal implementation detail | -| `gpAddDynamicDependency(dep)` | Build-order edge only, no link-time coupling | -| `gpAddPublicDependencyOnPlatform(dep platform)` | PUBLIC dep, active only on `platform` | -| `gpAddPrivateDependencyOnPlatform(dep platform)` | PRIVATE dep, active only on `platform` | -| `gpAddInternalDependencyOnPlatform(dep platform)` | Internal dep, active only on `platform` | -| `gpAddDynamicDependencyOnPlatform(dep platform)` | Dynamic dep, active only on `platform` | - -### Compile Definitions - -| Macro | Description | -| --- | --- | -| `gpAddPublicDefinitions(def)` | Add a PUBLIC compile definition | -| `gpAddPrivateDefinitions(def)` | Add a PRIVATE compile definition | -| `gpAddInternalDefinitions(def)` | Add a PRIVATE internal compile definition | - -### Compile Flags - -| Macro | Description | -| --- | --- | -| `gpAddPublicCompileFlag(flag)` | Add a PUBLIC compile flag | -| `gpAddPrivateCompileFlag(flag)` | Add a PRIVATE compile flag | -| `gpTargetReplaceCompileFlag(new regex visibility)` | Replace existing flags matching a regex | - -### Include Paths - -| Macro | Description | -| --- | --- | -| `gpAddPublicIncludesPath(path)` | Add a PUBLIC include directory | -| `gpAddPrivateIncludesPath(path)` | Add a PRIVATE include directory | -| `gpAddInternalIncludesPath(path)` | Add a PRIVATE internal include directory | - -### Target Flags - -| Macro | Description | -| --- | --- | -| `gpTargetSetTestsEnabled(value)` | Enable test executable generation | -| `gpTargetSetBenchmarksEnabled(value)` | Enable benchmark executable generation | -| `gpTargetSetExamplesEnabled(value)` | Enable example generation | -| `gpTargetSetISPCEnabled(value)` | Enable ISPC compilation | -| `gpTargetSetStrictWarningEnabled(value)` | Enable/disable strict warnings | -| `gpTargetSetUnityBuildEnabled(value)` | Enable unity build (batch 16 files) | -| `gpTargetSetIsHeaderOnly(value)` | Mark target as header-only | - -### Target Properties - -| Macro | Description | -| --- | --- | -| `gpSetTargetOutputName(name)` | Override the output binary name | -| `gpTargetSetFolder(path)` | Override the IDE folder | - -### Executable-Only - -| Macro | Description | -| --- | --- | -| `gpExecutableSetIsGUI(value)` | TRUE = GUI (no console), FALSE = console | -| `gpExecutableAddResource(path)` | Add a Windows `.rc` resource file | -| `gpExecutableSetEntryPoint(file)` | Set a custom entry point source file | - -### Install - -| Function | Description | -| --- | --- | -| `gpGenerateInstallExport()` | Generate CMake package config for downstream consumers | - ---- - -## Usage Examples - -### A Simple Module - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(audio) - gpAddPublicDependency(core) - gpAddPrivateDependency(SDL3::SDL3-static) - gpTargetSetTestsEnabled(TRUE) -gpEndModule() -``` - -### A Platform-Aware Module (HAL) - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(hal) - gpAddPublicDependency(core) - - # Exclude platform-specific subdirectories on irrelevant platforms - if(NOT WIN32) - gpTargetExcludeDirectory(windows) - endif() - - if(NOT (UNIX AND NOT APPLE)) - gpTargetExcludeDirectory(linux) - endif() - - if(NOT APPLE) - gpTargetExcludeDirectory(macos) - endif() - - gpAddPrivateDependency(SDL3::SDL3-static) -gpEndModule() -``` - -### A Plugin - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartPlugin(python_scripting) - # Plugins are always shared, they are loaded by the engine at runtime - gpAddPrivateDependency(core) - gpAddPrivateDependency(Python3::Python3) - gpTargetSetFolder("plugins/scripting") -gpEndPlugin() -``` - -### A Feature-Rich Executable (Editor) - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartExecutable(editor) - gpSetTargetOutputName(gpeditor) - gpExecutableSetIsGUI(FALSE) - gpExecutableAddResource(${__targetLocation}/resources/AppIcon.rc) - - gpAddPublicDependency(core) - gpAddPublicDependency(hal) - gpAddPublicDependency(engine) - gpAddPrivateDependency(rhi) - - gpTargetSetUnityBuildEnabled(TRUE) -gpEndExecutable() -``` - -### The RHI Module (Dynamic Backends) - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(rhi) - gpAddPublicDependency(core) - - # Null RHI is always present as a safe fallback - gpAddDynamicDependency(rhi/null) - - # Platform-conditional dynamic dependencies, clean, no if/endif clutter - gpAddDynamicDependencyOnPlatform(rhi/d3d11 WINDOWS) - gpAddDynamicDependencyOnPlatform(rhi/d3d12 WINDOWS) - gpAddDynamicDependencyOnPlatform(rhi/vulkan UNIX) - gpAddDynamicDependencyOnPlatform(rhi/opengl UNIX) - gpAddDynamicDependencyOnPlatform(rhi/metal MAC) -gpEndModule() -``` diff --git a/docs/Programming With C++/GP Build Tool/Testing.md b/docs/Programming With C++/GP Build Tool/Testing.md deleted file mode 100644 index c0dfe1b..0000000 --- a/docs/Programming With C++/GP Build Tool/Testing.md +++ /dev/null @@ -1,344 +0,0 @@ ---- -sidebar_position: 3 -title: Testing & Benchmarks -tags: - - c++ - - build system - - cmake - - tests - - benchmarks - - gpbt - - architecture ---- - -

- First-class automated test and benchmark generation for every engine module, zero boilerplate - required. -

- -The Graphical Playground Build Tool treats testing and performance measurement as core parts of the -build pipeline, not optional add-ons. Rather than asking you to manually create test executables, -configure linker flags, and register CTest commands for each module, GPBT does it automatically. - -Both systems are powered by [Catch2](https://github.com/catchorg/Catch2), which the engine fetches -and configures as part of its standard third-party setup. A `Catch2WithMain` target must be -available in the global CMake environment; if it is not, GPBT emits a fatal error before proceeding. - ---- - -## Tests - -### Enabling Tests for a Module - -Add a single line inside your target definition to opt in: - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(core) - gpAddPublicDependency(engine) - gpTargetSetTestsEnabled(TRUE) -gpEndModule() -``` - -Tests are only generated if the global `GP_BUILD_TESTS` CMake option is `ON`. If it is `OFF`, the -`gpTargetSetTestsEnabled` call is silently ignored. You do not need to guard it yourself. - -### Directory Structure - -GPBT expects your test sources to live in a `tests/` subdirectory next to your `CMakeLists.txt`: - -```text -source/runtime/core/ -├── CMakeLists.txt -├── public/ -│ └── core/ -│ └── Math.hpp -├── private/ -│ └── Math.cpp -└── tests/ - ├── MathTests.cpp - └── StringTests.cpp -``` - -GPBT automatically globs all `*.cpp` and `*.cc` files from that directory. If the `tests/` folder -does not exist, or if it contains no source files, GPBT emits a warning and skips test generation -for that target, it does not fail the configuration. - -### What GPBT Creates Automatically - -When test sources are found, GPBT performs the following steps automatically: - -1. **Test executable**, A new executable target is created, named - `_tests` (for example, `gp_core_tests` for the `core` module). -2. **Framework linking**, `Catch2WithMain` is linked privately so you get a pre-built `main` - entry point for free. You never need to write your own `main`. -3. **Module linking**, Your module itself is linked privately into the test executable, giving - your tests access to its public and internal APIs. -4. **C++23 standard**, The test executable is compiled with `cxx_std_23` to match the rest of - the engine. -5. **Engine definitions**, All standard GP compile definitions (`GP_BUILD_DEBUG`, `GP_USE_VULKAN`, - etc.) are stamped onto the test executable, keeping it consistent with the modules it tests. -6. **CTest registration**, The executable is registered with `add_test`, tagged with the labels - `gp`, ``, and `tests`. This makes it trivial to filter and run specific test suites - from the command line. - -### Writing Tests - -Your test files use standard Catch2 syntax: - -```cpp showLineNumbers -// tests/MathTests.cpp -#include -#include - -TEST_CASE("Vector3 addition is commutative", "[core][math][vector]") -{ - const gp::Vec3 a = { 1.0f, 2.0f, 3.0f }; - const gp::Vec3 b = { 4.0f, 5.0f, 6.0f }; - - REQUIRE(a + b == b + a); -} - -TEST_CASE("Division by zero returns NaN", "[core][math]") -{ - REQUIRE(std::isnan(gp::Math::safeDiv(1.0f, 0.0f))); -} -``` - -### Running Tests - -**Via CTest (recommended for CI):** - -```bash -# Run all GP tests -ctest --test-dir build/linux-release -L gp - -# Run only the core module tests -ctest --test-dir build/linux-release -L core - -# Run with verbose output (shows test names and pass/fail per assertion) -ctest --test-dir build/linux-release -V -L core -``` - -**Via the test binary directly (recommended during development):** - -```bash -# Run all tests in the binary -./binaries/bin/gp_core_tests - -# Run only tests tagged with [math] -./binaries/bin/gp_core_tests [math] - -# List all available test cases -./binaries/bin/gp_core_tests --list-test-names-only -``` - ---- - -## Benchmarks - -### Enabling Benchmarks for a Module - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(core) - gpTargetSetBenchmarksEnabled(TRUE) -gpEndModule() -``` - -As with tests, benchmarks are only generated when the `GP_BUILD_BENCHMARKS` CMake option is `ON`. - -### Benchmark Directory Structure - -GPBT expects your benchmark sources in a `benchmarks/` subdirectory: - -```text -source/runtime/core/ -├── CMakeLists.txt -├── public/ -├── private/ -├── tests/ -└── benchmarks/ - ├── MathBenchmarks.cpp - └── StringBenchmarks.cpp -``` - -If the `benchmarks/` folder does not exist or is empty, GPBT emits a warning and skips benchmark -generation for that target. - -### What GPBT Generates for Benchmarks - -1. **Benchmark executable**, A new executable named `_benchmarks` - (e.g., `gp_core_benchmarks`). -2. **Framework linking**, `Catch2WithMain` is linked privately. Catch2's built-in benchmarking - support is activated via the `CATCH_CONFIG_ENABLE_BENCHMARKING=1` compile definition. -3. **Module linking**, Your module is linked privately into the benchmark executable. -4. **C++23 standard** and **engine definitions**, Applied identically to tests. -5. **CTest registration**, Registered with `add_test` and tagged `gp`, ``, - and `benchmarks`. - -### Writing Benchmarks - -Benchmarks use Catch2's `BENCHMARK` macro, which integrates naturally alongside regular tests. - -```cpp showLineNumbers -// benchmarks/MathBenchmarks.cpp -#include -#include -#include - -TEST_CASE("Vec3 dot product performance", "[core][math][benchmark]") -{ - const gp::Vec3 a = { 1.0f, 2.0f, 3.0f }; - const gp::Vec3 b = { 4.0f, 5.0f, 6.0f }; - - BENCHMARK("dot product") - { - return gp::Math::dot(a, b); - }; -} - -TEST_CASE("Matrix multiplication performance", "[core][math][benchmark]") -{ - const gp::Mat4 a = gp::Mat4::identity(); - const gp::Mat4 b = gp::Mat4::identity(); - - BENCHMARK("4x4 matrix multiply") - { - return a * b; - }; - - BENCHMARK("4x4 matrix multiply inverse") - { - return gp::Math::inverse(a * b); - }; -} -``` - -:::tip For students -The `BENCHMARK` macro runs your code thousands of times and reports the median runtime, standard -deviation, and outlier counts. You do not need to write a timer loop or averaging logic yourself. -Catch2 handles all the statistical measurement. -::: - -### Running Benchmarks - -Benchmarks are registered in CTest but must be invoked with the `[benchmark]` tag filter to -avoid slowing down the standard test run: - -```bash -# Run all benchmarks for a module via CTest -ctest --test-dir build/linux-release -L benchmarks - -# Run directly with benchmark output -./binaries/bin/gp_core_benchmarks [benchmark] - -# Run benchmarks and output results to a file -./binaries/bin/gp_core_benchmarks [benchmark] --reporter xml > results.xml -``` - -:::note -Catch2 benchmarks by default run in a warm-up phase followed by multiple timed samples. Running -benchmark binaries in a Debug build will give unreliable results, always use `Release` or -`RelWithDebInfo` for performance measurement. -::: - ---- - -## Having Both Tests and Benchmarks - -Tests and benchmarks are independent and can both be enabled on the same module: - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(renderer) - gpAddPublicDependency(rhi) - gpAddPublicDependency(core) - - gpTargetSetTestsEnabled(TRUE) - gpTargetSetBenchmarksEnabled(TRUE) -gpEndModule() -``` - -This generates two separate executables: `gp_renderer_tests` and `gp_renderer_benchmarks`. They -are kept separate intentionally, test runs should be fast and suitable for CI, while benchmark -runs are longer and intended to be run on a controlled machine before and after performance-sensitive -changes. - ---- - -## Full Worked Example - -### Directory Layout - -```text -source/runtime/core/ -├── CMakeLists.txt -├── public/ -│ └── core/ -│ └── StringUtils.hpp -├── private/ -│ └── StringUtils.cpp -├── tests/ -│ └── StringUtilsTests.cpp -└── benchmarks/ - └── StringUtilsBenchmarks.cpp -``` - -### CMakeLists.txt - -```cmake showLineNumbers -include(gp-build-tool) - -gpStartModule(core) - gpTargetSetTestsEnabled(TRUE) - gpTargetSetBenchmarksEnabled(TRUE) -gpEndModule() -``` - -### StringUtilsTests.cpp - -```cpp showLineNumbers -#include -#include - -TEST_CASE("trimLeft removes leading spaces", "[core][string]") -{ - REQUIRE(gp::StringUtils::trimLeft(" hello") == "hello"); - REQUIRE(gp::StringUtils::trimLeft("hello") == "hello"); - REQUIRE(gp::StringUtils::trimLeft("") == ""); -} -``` - -### StringUtilsBenchmarks.cpp - -```cpp showLineNumbers -#include -#include -#include - -TEST_CASE("StringUtils performance", "[core][string][benchmark]") -{ - const gp::String longString(1024, ' '); - - BENCHMARK("trimLeft on 1024-char string") - { - return gp::StringUtils::trimLeft(longString); - }; -} -``` - -### Running Both - -```bash -# Tests -ctest --test-dir build/linux-release -L "core" -L "tests" -# or -./binaries/bin/gp_core_tests - -# Benchmarks (always use Release) -./binaries/bin/gp_core_benchmarks [benchmark] -``` diff --git a/docs/Programming With C++/GP Build Tool/ThirdParty.md b/docs/Programming With C++/GP Build Tool/ThirdParty.md deleted file mode 100644 index d4e9c64..0000000 --- a/docs/Programming With C++/GP Build Tool/ThirdParty.md +++ /dev/null @@ -1,270 +0,0 @@ ---- -sidebar_position: 1 -title: Third-Party Management -tags: - - c++ - - build system - - cmake - - thirdparty - - gpbt - - architecture - - fetchcontent ---- - -

- A Local-First, Fetch-Second strategy for integrating external dependencies without cluttering - the codebase or violating licenses. -

- -Managing external dependencies in C++ is notoriously brittle. Header-only libraries get copied -manually, Git submodules drift out of sync, and CMake's `find_package` fails silently on -developer machines that have the wrong version installed. GPBT solves this through the -`gp-thirdparty` module. - -The core philosophy is **Local First, Fetch Second**: for every dependency, GPBT first checks -whether a compatible version is already installed on the host system. Only if that check fails -does it fall back to fetching the exact pinned version from Git, building it from source, and -making it available, transparently and reproducibly. - ---- - -## Directory Organization and Licensing - -To maintain a healthy codebase and respect legal constraints, the engine enforces a strict layout -for all third-party code. - -:::warning Licensing is mandatory -When integrating any new third-party dependency, you must isolate it in its own dedicated -subfolder under the root `/thirdparty` directory. Within that subfolder you are required to -include: - -1. A `CMakeLists.txt` file containing the `gpFetchContent` call for that dependency. -2. A copy of the library's license file, named `LICENSE.md` (or the upstream format, e.g., - `LICENSE`, `LICENSE.txt`). - -Shipping a library without its license is a legal violation. GPBT's directory structure makes -auditing trivial, every dependency and its license live side by side. -::: - -The expected layout: - -```text -/thirdparty - /sdl3 - CMakeLists.txt - LICENSE.md - /catch2 - CMakeLists.txt - LICENSE.md - /vulkan - CMakeLists.txt - LICENSE.md -``` - -Each subdirectory is added to the build via the root `thirdparty/CMakeLists.txt`, which calls -`add_subdirectory` for each one (conditionally, for platform-specific libraries). - ---- - -## `gpFetchContent` - -This is the primary function for resolving external dependencies. It wraps CMake's standard -`find_package` and `FetchContent` modules with additional validation, logging, and option -injection. - -### Arguments - -| Argument | Required | Description | -| --- | --- | --- | -| `NAME` | Yes | The identifier for this dependency. Used as the FetchContent name. | -| `GIT_REPOSITORY` | Yes | The Git repository URL to clone if no local installation is found. | -| `GIT_TAG` | Yes | The exact tag, branch, or commit hash to clone (shallow clone). | -| `PACKAGE_NAME` | No | The name passed to `find_package`. Defaults to `NAME`. | -| `REQUIRED_VERSION` | No | The version passed to `find_package`. | -| `COMPONENTS` | No | Specific components to request from `find_package`. | -| `OPTIONS` | No | Cache variables to inject before configuring the dependency, formatted as `"KEY=VALUE"`. | - -### How It Works - -1. **Local check**, `find_package( QUIET)` is called first. - GPBT uses `QUIET` to suppress the verbose "not found" output that CMake normally emits. -2. **Local success**, If the package is found, its path and version are logged and the function - returns. The fetched sources are never touched. -3. **Fallback fetch**, If the package is not found locally, `FetchContent_Declare` registers the - Git repository with `GIT_SHALLOW TRUE` for speed. Any `OPTIONS` entries are injected into the - CMake cache as `CACHE STRING ... FORCE` before `FetchContent_MakeAvailable` is called. -4. **Available**, The dependency's targets are now visible to the rest of the build. - -:::tip For students -`GIT_SHALLOW TRUE` means CMake only downloads the single commit pointed to by `GIT_TAG`, not the -entire Git history. For large repositories like SDL3 this can reduce download time from minutes -to seconds. Always pin to a specific release tag (e.g., `release-3.4.0`) rather than a branch -name, branches move, tags do not. -::: - ---- - -## `gpSetTargetFolder` - -When third-party libraries are integrated, their CMake targets appear alongside engine targets in -your IDE. This can make the solution explorer difficult to navigate. `gpSetTargetFolder` moves a -target into a named IDE folder without affecting the build at all. - -```cmake -gpSetTargetFolder(TARGET_NAME FOLDER_NAME) -``` - -GPBT automatically skips `INTERFACE_LIBRARY` and `ALIAS_LIBRARY` targets, since CMake does not -permit setting the `FOLDER` property on them. - -```cmake showLineNumbers -if(TARGET SDL3) - gpSetTargetFolder(SDL3 "thirdparty/sdl3") - gpSetTargetFolder(SDL3-static "thirdparty/sdl3") - gpSetTargetFolder(SDL_uclibc "thirdparty/sdl3") -endif() -``` - ---- - -## Usage Examples - -### Example 1, SDL3 (Static Build) - -This example attempts to find SDL3 locally. If it is not found, it fetches release `3.4.0` from -GitHub, forces a static build, disables SDL's internal test suite (which would otherwise add -dozens of test executables to your IDE), and organizes the targets into a `thirdparty/sdl3` -folder. - -```cmake showLineNumbers -include(gp-build-tool) - -gpFetchContent( - NAME SDL3 - GIT_REPOSITORY https://github.com/libsdl-org/SDL.git - GIT_TAG release-3.4.0 - PACKAGE_NAME SDL3 - REQUIRED_VERSION 3.4.0 - OPTIONS - "SDL_SHARED=OFF" - "SDL_STATIC=ON" - "SDL_TEST=OFF" -) - -if(TARGET SDL3) - gpSetTargetFolder(SDL_uclibc "thirdparty/sdl3") - gpSetTargetFolder(SDL3 "thirdparty/sdl3") - gpSetTargetFolder(SDL3-static "thirdparty/sdl3") -endif() -``` - -### Example 2, Platform-Specific Headers (DirectX 12) - -Wrap `gpFetchContent` in a CMake `return()` guard to skip the entire file on platforms where -the dependency is irrelevant. This is cleaner than an `if/endif` around the entire block. - -```cmake showLineNumbers -include(gp-build-tool) - -if(NOT GP_USE_D3D12 OR NOT WIN32) - return() -endif() - -gpFetchContent( - NAME DirectXHeaders - GIT_REPOSITORY https://github.com/microsoft/DirectX-Headers.git - GIT_TAG v1.619.1 - REQUIRED_VERSION 1.619.1 - PACKAGE_NAME DirectX-Headers - OPTIONS - "BUILD_TESTING=OFF" -) - -if(TARGET DirectX-Headers) - gpSetTargetFolder(DirectX-Headers "thirdparty/graphics") - if(TARGET DirectX-Guids) - gpSetTargetFolder(DirectX-Guids "thirdparty/graphics") - endif() -endif() -``` - -### Example 3, Testing Frameworks (Catch2) - -Catch2 ships with its own set of examples, tests, and documentation targets. Disabling them -keeps build times fast and keeps the IDE clean. - -After fetching Catch2, its extras directory must be appended to `CMAKE_MODULE_PATH` so that -the `Catch` CMake module (which provides `catch_discover_tests`) is available to the rest -of the build. The `PARENT_SCOPE` propagates this change up to the calling `CMakeLists.txt`. - -```cmake showLineNumbers -include(gp-build-tool) - -gpFetchContent( - NAME Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.14.0 - REQUIRED_VERSION 3.14.0 - PACKAGE_NAME Catch2 - OPTIONS - "CATCH_BUILD_TESTING=OFF" - "CATCH_BUILD_EXAMPLES=OFF" - "CATCH_BUILD_EXTRA_TESTS=OFF" - "CATCH_ENABLE_COVERAGE=OFF" - "CATCH_ENABLE_WERROR=OFF" - "CATCH_INSTALL_DOCS=OFF" - "CATCH_INSTALL_EXTRAS=ON" -) - -if(TARGET Catch2) - gpSetTargetFolder(Catch2WithMain "thirdparty/testing") - gpSetTargetFolder(Catch2 "thirdparty/testing") - - list(APPEND CMAKE_MODULE_PATH "${catch2_SOURCE_DIR}/extras") - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE) -endif() -``` - -### Example 4, Shader Toolchain (glslang) - -Some dependencies need multiple targets organized. Using a helper variable keeps the -`gpSetTargetFolder` calls readable. - -```cmake showLineNumbers -include(gp-build-tool) - -gpFetchContent( - NAME glslang - GIT_REPOSITORY https://github.com/KhronosGroup/glslang.git - GIT_TAG vulkan-sdk-1.3.296.0 - OPTIONS - "GLSLANG_TESTS=OFF" - "GLSLANG_ENABLE_INSTALL=OFF" - "BUILD_EXTERNAL=OFF" - "ENABLE_GLSLANG_BINARIES=OFF" - "ENABLE_SPVREMAPPER=OFF" -) - -foreach(_glslangTarget IN ITEMS - glslang glslang-default-resource-limits - MachineIndependent OSDependent GenericCodeGen - SPIRV glslang-build-info) - gpSetTargetFolder(${_glslangTarget} "thirdparty/shaders/glslang") -endforeach() -``` - ---- - -## Adding a New Dependency Checklist - -When adding a third-party library to the engine, follow this checklist: - -1. Create `/thirdparty//CMakeLists.txt`. -2. Copy the library's license into `/thirdparty//LICENSE.md`. -3. Write a `gpFetchContent(...)` call pinned to an exact release tag, never a branch. -4. Disable the library's own tests, examples, and documentation via `OPTIONS`. -5. Add `gpSetTargetFolder(...)` calls to keep the IDE organized. -6. Add `add_subdirectory()` in `/thirdparty/CMakeLists.txt`, guarded by - platform conditions if the library is platform-specific. -7. Test the build on a clean machine (or inside the CI Docker image) to verify the fetch path - works, not just the local-installation path. diff --git a/docs/Programming With C++/GP Build Tool/Utilities.md b/docs/Programming With C++/GP Build Tool/Utilities.md deleted file mode 100644 index e7875c5..0000000 --- a/docs/Programming With C++/GP Build Tool/Utilities.md +++ /dev/null @@ -1,379 +0,0 @@ ---- -sidebar_position: 2 -title: Utilities -tags: - - c++ - - build system - - cmake - - utilities - - gpbt - - architecture ---- - -

- Logging, string manipulation, scoping, and phase management utilities that power the build tool - internals and are available to any custom CMake code in the project. -

- -GPBT exposes a set of utility modules that are used internally throughout the build tool and are -available to any CMake code that includes `gp-build-tool`. These utilities solve real pain points -in CMake development: messy output, inconsistent naming, variable leakage between scopes, and -accidental re-execution of initialization code. - ---- - -## Logging (`gp-logger`) - -CMake's default output is verbose, hard to scan, and impossible to color. When a warning fires, -CMake dumps a full stack trace that buries the actual message. When a fatal error occurs, the -user sees a wall of text. GPBT replaces all of this with a clean, color-coded logging layer. - -All log functions accept one or more arguments, which are automatically concatenated. By default, -every message is prefixed with `[GPBT]` to visually separate build-tool output from raw CMake -or third-party output. - -### Log Functions - -#### `gpLog(...)` - -Standard informational message. Use this for configuration progress and status updates. - -```cmake -gpLog("Configuring the Audio Engine...") -gpLog("Audio Engine path resolved to: " ${CMAKE_CURRENT_SOURCE_DIR}) -``` - -#### `gpSuccess(...)` - -Bold green message prefixed with `SUCCESS:`. Use this to confirm completion of significant -configuration steps. - -```cmake -gpSuccess("Vulkan backend configured and linked.") -``` - -#### `gpWarning(...)` - -Bold yellow message prefixed with `WARNING:`. GPBT deliberately uses CMake's `STATUS` level -internally, which means no stack trace is dumped. The warning is highly visible without the noise. - -```cmake -gpWarning("No test sources found in '${testDir}'. Skipping test generation.") -``` - -#### `gpFatal(...)` - -Bold red message prefixed with `FATAL ERROR:`. GPBT prints the human-readable error cleanly, -then calls `FATAL_ERROR` with a short generic message to halt CMake execution. This ensures the -user sees the colored error before CMake's own error output. - -```cmake -gpFatal("Target '${targetName}' was registered twice. Target names must be unique.") -``` - -#### `gpVerbose(...)` - -Cyan message prefixed with `VERBOSE:`. Only printed when the `GP_BUILD_TOOL_VERBOSE` CMake option -is `ON`. Essential for debugging dependency resolution, scope state, and target configuration -order. - -```cmake -# Activate with: cmake -DGP_BUILD_TOOL_VERBOSE=ON ... -gpVerbose("Public includes resolved to: ${__targetPublicIncludes}") -``` - -#### `gpNewLine()` - -Prints a blank line. Use this to separate logical groups of output for readability. - -```cmake -gpLog("Configuring shaders...") -# ... shader configuration ... -gpSuccess("Shader pipeline ready.") -gpNewLine() -``` - -### Color Constants - -The logger module exposes ANSI escape sequences as CMake variables so you can use colors in -your own formatted messages. These are automatically initialized when `gp-build-tool` is included. - -| Variable | Effect | -| --- | --- | -| `${GP_RESET}` | Reset all formatting | -| `${GP_BOLD}` | Bold text | -| `${GP_RED}` | Red foreground | -| `${GP_GREEN}` | Green foreground | -| `${GP_YELLOW}` | Yellow foreground | -| `${GP_BLUE}` | Blue foreground | -| `${GP_MAGENTA}` | Magenta foreground | -| `${GP_CYAN}` | Cyan foreground | -| `${GP_WHITE}` | White foreground | -| `${GP_BOLD_RED}` | Bold red | -| `${GP_BOLD_GREEN}` | Bold green | -| `${GP_BOLD_YELLOW}` | Bold yellow | - -```cmake -gpLog("${GP_BOLD}Initializing RHI pipeline...${GP_RESET}") -gpLog("${GP_CYAN}Selected backend: ${GP_BOLD}Vulkan${GP_RESET}") -``` - -### Prefix Management - -In some contexts you may want to suppress the `[GPBT]` prefix, for example when printing a -formatted banner or table of configuration values where the prefix would break alignment. - -```cmake -gpSetLogPrefixEnabled(FALSE) -gpLog(" Compiler: ${CMAKE_CXX_COMPILER_ID}") -gpLog(" Standard: C++23") -gpLog(" Platform: ${CMAKE_SYSTEM_NAME}") -gpRestorePreviousLogPrefixState() -# [GPBT] prefix is restored here -``` - -- `gpSetLogPrefixEnabled(value)` — Enables (`TRUE`) or disables (`FALSE`) the prefix. Saves - the previous state automatically. -- `gpRestorePreviousLogPrefixState()` — Restores the prefix to its state before the last - `gpSetLogPrefixEnabled` call. - -### Full Usage Example - -```cmake showLineNumbers -include(gp-build-tool) - -gpLog("Configuring Audio Engine...") - -gpVerbose("Audio Engine source path: ${CMAKE_CURRENT_SOURCE_DIR}") - -if(NOT GP_ENABLE_SPATIAL_AUDIO) - gpWarning("Spatial audio is disabled. Falling back to stereo-only output.") - gpNewLine() -endif() - -find_package(FMOD QUIET) -if(NOT FMOD_FOUND) - gpFatal("FMOD library not found. The Audio Engine requires FMOD to compile.") -endif() - -gpSuccess("Audio Engine configured successfully.") -``` - ---- - -## Stringification (`gp-stringify`) - -GPBT maintains consistent naming across all its generated targets, properties, and macros by -using a set of string manipulation functions. These convert between naming conventions — from a -module path like `rhi/vulkan` to a CMake target export name like `gp_rhi_vulkan`, an alias like -`gp::rhi_vulkan`, or an uppercase property key like `GPBT_TARGET_RHI_VULKAN_LOCATION`. - -All functions take an `input` string and write the result into the CMake variable named by -`outVar`. - -### Case Checking - -These functions return `TRUE` or `FALSE` in the output variable. - -| Function | Convention Checked | -| --- | --- | -| `gpIsLowerSnakeCase(input outVar)` | `lower_snake_case` | -| `gpIsUpperSnakeCase(input outVar)` | `UPPER_SNAKE_CASE` | -| `gpIsCamelCase(input outVar)` | `camelCase` | -| `gpIsPascalCase(input outVar)` | `PascalCase` | - -```cmake showLineNumbers -set(proposedName "my_render_pass") - -gpIsLowerSnakeCase("${proposedName}" isValid) -if(NOT isValid) - gpFatal("Module name '${proposedName}' must use lower_snake_case.") -endif() -``` - -### Case Conversion - -These functions transform the input into a new naming convention. Internally they tokenize the -string on case transitions (e.g., `myHTTPResponse` becomes tokens `my`, `HTTP`, `Response`) and -on separator characters (`-` and `_`). - -| Function | Output Convention | Example | -| --- | --- | --- | -| `gpToLowerSnakeCase(input outVar)` | `lower_snake_case` | `rhi/vulkan` -> `rhi_vulkan` | -| `gpToUpperSnakeCase(input outVar)` | `UPPER_SNAKE_CASE` | `rhi/vulkan` -> `RHI_VULKAN` | -| `gpToCamelCase(input outVar)` | `camelCase` | `rhi/vulkan` -> `rhiVulkan` | -| `gpToPascalCase(input outVar)` | `PascalCase` | `rhi/vulkan` -> `RhiVulkan` | - -```cmake showLineNumbers -set(moduleName "NetworkManager") - -# GPBT uses this internally to generate export macro names -gpToUpperSnakeCase("${moduleName}" macroPrefix) -set(exportMacro "GP_${macroPrefix}_API_EXPORTS") -# exportMacro = "GP_NETWORK_MANAGER_API_EXPORTS" -gpLog("Generated export macro: ${exportMacro}") - -# And lower snake case for output binary names -gpToLowerSnakeCase("${moduleName}" binaryName) -set(binaryName "gp_${binaryName}") -# binaryName = "gp_network_manager" -``` - ---- - -## Scope Management (`gp-scope`) - -CMake has no real notion of block scope. Variables set inside an `if`, `foreach`, or `function` -can bleed into the outer scope in unexpected ways. GPBT's scope system adds an explicit, opt-in -scope stack that tracks variable mutations and automatically rolls them back when the scope is -closed. - -This is the mechanism that makes the `gpStart*` / `gpEnd*` pattern safe: every variable set -inside a target definition is rolled back to its previous value when `gpEnd*` is called. - -:::note For students -Think of this like RAII in C++. When you push a scope, all subsequent variable assignments are -"registered". When you pop the scope, every registered variable is restored to the value it had -before the scope was opened (or unset, if it did not exist at all). No variable can accidentally -leak from one target definition into the next. -::: - -### Manual Scope Management - -Most code uses the named-scope variants (see below), but you can also push and pop raw scopes: - -```cmake -gpPushScope() - set(MY_VAR "hello") # MY_VAR is now tracked - # ... do work ... -gpPopScope() -# MY_VAR is now gone (or restored to its pre-push value) -``` - -### Scoped Variable Assignment - -Inside a scope, use `gpSetScoped` instead of `set`. This registers the variable for automatic -cleanup and backs up any previous value. - -```cmake showLineNumbers -gpPushScope() - gpSetScoped(CMAKE_BUILD_TYPE "Release") - # CMAKE_BUILD_TYPE is Release here -gpPopScope() -# CMAKE_BUILD_TYPE is restored to whatever it was before -``` - -For bulk initialization, use `gpSetScopedMultiple` with alternating `KEY VALUE` pairs: - -```cmake showLineNumbers -gpPushScope() - gpSetScopedMultiple( - __targetName "my_module" - __targetType "module" - __targetSources "" - ) -gpPopScope() -``` - -To register variables that already exist (so they are restored without modifying their current -value), use `gpTrackScopedMultiple`: - -```cmake -gpPushScope() - gpTrackScopedMultiple(CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS) - # Modify them freely; they will be restored on gpPopScope() -gpPopScope() -``` - -### Named Scopes - -Named scopes add an additional safety layer: only one scope with a given name can be active at -a time, and scopes must be popped with the same name they were pushed with. This prevents -accidentally nesting two `target` scopes inside each other. - -```cmake -gpPushNamedScope("target") - # ... target configuration ... -gpPopNamedScope("target") -``` - -Attempting to push the same name twice, or popping with the wrong name, emits a fatal error. - -### Scope Guards - -These macros enforce invariants at the call site: - -```cmake -# Check if a named scope is currently active -gpIsInNamedScope("target" isInsideTarget) -if(isInsideTarget) - # ... -endif() - -# Fatal error if NOT inside the named scope (used internally by all gpAdd* macros) -gpFatalIfNotInNamedScope("target" "gpAddPublicDependency can only be called within a target scope.") -``` - -### One-Time Execution Guard - -Some initialization code should run exactly once per CMake invocation, regardless of how many -times the file is included. `gpExecuteOnce` provides a global guard backed by a CMake property. - -```cmake showLineNumbers -gpExecuteOnce("MY_INIT_BANNER" _shouldRun) -if(_shouldRun) - gpLog("${GP_MAGENTA}=== My Build Tool v1.0 ===${GP_RESET}") -endif() -# On all subsequent includes of this file, _shouldRun is FALSE -``` - -GPBT uses this for the startup banner so it prints exactly once at the beginning of the -configuration run, not once per `include(gp-build-tool)` call. - ---- - -## Build Phase Management (`gp-utils`) - -GPBT's two-phase system (REGISTRATION then CONFIGURATION) is enforced through a global phase -property. The phase system prevents target-creation code from running during registration, and -prevents registration-only code from running during configuration. - -Most code never needs to interact with the phase system directly. It is documented here for -contributors working on the build tool internals. - -### Phases - -| Phase | Set By | What Happens | -| --- | --- | --- | -| `REGISTRATION` | `_implGpScanForTargets` at scan start | Targets register names and deps; no CMake targets are created | -| `CONFIGURATION` | `_implGpScanForTargets` after sorting | Targets create real CMake targets and link dependencies | -| `GENERATION` | CMake itself | CMake generates Ninja/Makefile/etc. build files | - -### Phase Query - -```cmake -_gpGetCurrentPhase(currentPhase) -if(currentPhase STREQUAL "REGISTRATION") - # Safe to register global properties -elseif(currentPhase STREQUAL "CONFIGURATION") - # Safe to call add_library / target_link_libraries / etc. -endif() -``` - -### Phase Transition - -```cmake -# Called only by the scan system -- never call these manually -_gpSetCurrentPhase("REGISTRATION") -_gpSetCurrentPhase("CONFIGURATION") -``` - -Attempting to transition to the current phase (e.g., calling REGISTRATION when already -REGISTRATION) emits a fatal error. Attempting to set an unknown phase emits a fatal error. -Phase transitions are logged so they are visible in the CMake output. - -:::warning -The phase functions are prefixed with `_gp` (single underscore) to signal they are internal -implementation details. Do not call them from module `CMakeLists.txt` files. -All public-facing GPBT API is prefixed with `gp` (no underscore). -::: diff --git a/docs/Programming With C++/GP Build Tool/_category_.json b/docs/Programming With C++/GP Build Tool/_category_.json deleted file mode 100644 index 5fef524..0000000 --- a/docs/Programming With C++/GP Build Tool/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "GP Build Tool", - "position": 4 -} diff --git a/docs/Programming With C++/README.md b/docs/Programming With C++/README.md deleted file mode 100644 index 95efcb7..0000000 --- a/docs/Programming With C++/README.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -sidebar_position: 0 -title: Programming with C++ -description: Information for programmers developing with Graphical Playground. -tags: - - c++ - - programming ---- -# Programming with C++ - -

Information for programmers developing with Graphical Playground.

- -Graphical Playground provides a robust framework for C++ programmers to help bring their vision to -life. - -:::note - -This section assumes that you have some experience with C++. - -::: - -This section covers several powerful features that you can use to accelerate your development -workflows. You can learn about: diff --git a/docs/Programming With C++/_category_.json b/docs/Programming With C++/_category_.json deleted file mode 100644 index 8c25368..0000000 --- a/docs/Programming With C++/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Programming with C++", - "position": 2 -} diff --git a/docs/ThirdParties.md b/docs/ThirdParties.md deleted file mode 100644 index 910eb32..0000000 --- a/docs/ThirdParties.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -sidebar_position: 4 -title: Third Parties -description: Information about third-party libraries and tools used in the project. -tags: - - third-party - - libraries - - tools ---- - -# Third Parties - -

Information about third-party libraries and tools used in the project.

- -`gp-engine` integrates a curated set of third-party libraries to support windowing, graphics API -abstraction, shader compilation, and performance profiling. This document lists every external -dependency, its version, and its role within the engine. We do not bundle dependencies beyond what -is listed here; all third-party code is tracked as submodules or vendored under the `third-party/` -directory. - -## Windowing & Input - -### SDL3 - -- **Version**: `3.4.0` -- **Role**: Cross-platform windowing, OpenGL/Vulkan surface creation, input event handling, and - gamepad support. -- SDL3 is the primary abstraction layer between `gp-engine` and the host operating system's - windowing system. All platform window handles passed to the rendering backends are obtained - through SDL3. -- **License**: [Zlib](https://www.libsdl.org/license.php) -- **Repository**: [libsdl-org/SDL](https://github.com/libsdl-org/SDL) - -## Testing - -### Catch2 - -- **Version**: `3.14.0` -- **Role**: Unit and integration testing framework for all engine modules. -- We use Catch2 as the sole testing framework across the codebase. All tests are located in the - `tests/` directory and are organized to mirror the module structure of the engine. - Do not introduce additional testing frameworks without prior discussion. -- **License**: [BSL-1.0](https://github.com/catchorg/Catch2/blob/devel/LICENSE.txt) -- **Repository**: [catchorg/Catch2](https://github.com/catchorg/Catch2) - -## Graphics APIs - -The engine supports multiple rendering backends. Each backend maps to one or more of the following -graphics API integrations. - -:::tip - -The active backend is selected at CMake configuration time using the `-DGP_USE_VULKAN=ON` or -`-DGP_USE_OPENGL=ON` flags. Integrated APIs such as `OpenGL`, `Metal`, and `DirectX 11` do not -require a separate installation step, as they are provided by the host platform. - -::: - -### DirectX 11 *(integrated)* - -- **Version**: Integrated, provided by the Windows SDK. -- **Role**: Legacy Direct3D 11 rendering backend targeting Windows platforms. -- No vendored headers are required. The engine links against `d3d11.lib` and `dxgi.lib` supplied - by the Windows SDK present in the build environment. - -### DirectXHeaders (D3D12) - -- **Version**: `1.619.1` -- **Role**: Provides the official D3D12 and DXGI headers for the Direct3D 12 rendering backend. -- These headers are sourced from Microsoft's official distribution and are preferred over those - bundled with older Windows SDKs to ensure access to the latest API surface. -- **License**: [MIT](https://github.com/microsoft/DirectX-Headers/blob/main/LICENSE) -- **Repository**: [microsoft/DirectX-Headers](https://github.com/microsoft/DirectX-Headers) - -### D3D12 Memory Allocator - -- **Version**: `v3.1.0` -- **Role**: GPU memory suballocation library for the Direct3D 12 rendering backend. -- We use D3D12MA to manage all D3D12 heap allocations. Do not call `ID3D12Device::CreateCommittedResource` - directly in rendering code; route all resource creation through the allocator to ensure correct - pooling and budget tracking. -- **License**: [MIT](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator/blob/master/LICENSE.txt) -- **Repository**: [GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator) - -### Metal *(integrated)* - -- **Version**: Integrated, provided by the macOS/iOS SDK. -- **Role**: Metal rendering backend targeting Apple platforms. -- No vendored headers are required. The engine links against the `Metal.framework` and - `QuartzCore.framework` supplied by Xcode. - -### OpenGL *(integrated)* - -- **Version**: Integrated, provided by the host platform's GPU drivers. -- **Role**: Cross-platform OpenGL rendering backend. -- OpenGL function pointers are loaded at runtime. We do not vendor a separate loader library; - loading is handled by SDL3's built-in OpenGL function pointer resolution. - -### Vulkan-Headers - -- **Version**: `1.4.341` -- **Role**: Provides the Vulkan C API headers (`vulkan/vulkan.h`) and the Vulkan XML registry. -- These headers are used by the Vulkan rendering backend and by all shader toolchain libraries that - consume Vulkan-specific SPIR-V metadata. -- **License**: [Apache-2.0](https://github.com/KhronosGroup/Vulkan-Headers/blob/main/LICENSE.md) -- **Repository**: [KhronosGroup/Vulkan-Headers](https://github.com/KhronosGroup/Vulkan-Headers) - -### Vulkan-Loader - -- **Version**: `1.4.341` -- **Role**: Runtime loader that resolves Vulkan instance and device function pointers from the - installed ICD (Installable Client Driver). -- On platforms where a system Vulkan loader is available, linking against the vendored loader is - optional and controlled by the `GP_USE_SYSTEM_VULKAN_LOADER` CMake flag. -- **License**: [Apache-2.0](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/LICENSE.txt) -- **Repository**: [KhronosGroup/Vulkan-Loader](https://github.com/KhronosGroup/Vulkan-Loader) - -### Vulkan Memory Allocator - -- **Version**: `v3.3.0` -- **Role**: GPU memory suballocation library for the Vulkan rendering backend. -- We use VMA to manage all `VkDeviceMemory` allocations. Do not call `vkAllocateMemory` directly - in rendering code; route all resource creation through the allocator to ensure correct pooling, - defragmentation support, and budget tracking. -- **License**: [MIT](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/LICENSE.txt) -- **Repository**: [GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) - -## Shader Toolchain - -The engine uses a SPIR-V–centric shader pipeline. GLSL source shaders are compiled to SPIR-V at -build time, reflected for resource binding metadata, and cross-compiled to backend-native shading -languages where required. - -### Glslang - -- **Role**: Reference GLSL/HLSL front-end compiler that produces SPIR-V bytecode. -- All GLSL shader sources in `shaders/` are compiled via `glslangValidator` as a build step. - Do not check in precompiled SPIR-V binaries; they are generated as part of the standard build. -- **License**: [Multiple, see repository](https://github.com/KhronosGroup/glslang/blob/main/LICENSE.txt) -- **Repository**: [KhronosGroup/glslang](https://github.com/KhronosGroup/glslang) - -### DXC - -- **Version**: `v1.9.2602` -- **Role**: Microsoft's DirectX Shader Compiler, used to compile HLSL shader sources to DXIL and - SPIR-V. -- DXC is the preferred compiler for all HLSL sources targeting the D3D12 backend. It is also used - as an alternative SPIR-V front-end for HLSL shaders on the Vulkan path. Do not use the legacy - `fxc` compiler for any new shader work. -- **License**: [University of Illinois Open Source License](https://github.com/microsoft/DirectXShaderCompiler/blob/main/LICENSE.TXT) -- **Repository**: [microsoft/DirectXShaderCompiler](https://github.com/microsoft/DirectXShaderCompiler) - -### SPIRV-Cross - -- **Role**: Transpiles SPIR-V bytecode to GLSL, HLSL, and Metal Shading Language (MSL) for - backends that do not natively consume SPIR-V. -- SPIRV-Cross is used at runtime on Metal and legacy OpenGL paths to produce backend-appropriate - shader source from the canonical SPIR-V representation. -- **License**: [Apache-2.0](https://github.com/KhronosGroup/SPIRV-Cross/blob/main/LICENSE) -- **Repository**: [KhronosGroup/SPIRV-Cross](https://github.com/KhronosGroup/SPIRV-Cross) - -### SPIRV-Tools - -- **Role**: Provides SPIR-V validation, optimization, and binary manipulation utilities. -- The optimizer pass is run as a post-processing step on all compiled SPIR-V modules in `Release` - builds. Always validate SPIR-V output during development using the `spirv-val` utility. -- **License**: [Apache-2.0](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/LICENSE) -- **Repository**: [KhronosGroup/SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools) - -### SPIRV-Reflect - -- **Role**: Lightweight library for extracting shader resource binding metadata directly from - SPIR-V bytecode. -- We use SPIRV-Reflect at runtime to automatically build pipeline layouts and descriptor set - layouts from compiled shader modules, without requiring manually authored binding tables. -- **License**: [Apache-2.0](https://github.com/KhronosGroup/SPIRV-Reflect/blob/main/LICENSE) -- **Repository**: [KhronosGroup/SPIRV-Reflect](https://github.com/KhronosGroup/SPIRV-Reflect) - -### SPIRV-Headers - -- **Role**: Provides the canonical SPIR-V header files (`spirv.h`, `GLSL.std.450.h`, etc.) and - machine-readable grammar JSON files consumed by other SPIR-V toolchain libraries. -- SPIRV-Headers is a transitive dependency of Glslang, SPIRV-Tools, and SPIRV-Cross. - Do not depend on it directly from engine code; use the higher-level toolchain libraries instead. -- **License**: [MIT](https://github.com/KhronosGroup/SPIRV-Headers/blob/main/LICENSE) -- **Repository**: [KhronosGroup/SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers) - -## Profiling - -### Tracy - -- **Version**: `0.13.1` -- **Role**: Frame profiler providing CPU and GPU timing, memory allocation tracking, and flame - graph visualization. -- Tracy instrumentation is compiled in under the `GP_ENABLE_PROFILING=ON` CMake flag and stripped - entirely from `Shipping` builds. Prefer Tracy zones over ad-hoc timing code for any performance - investigation. Do not leave profiling markers in code paths that are not intentionally - instrumented. -- **License**: [BSD-3-Clause](https://github.com/wolfpld/tracy/blob/master/LICENSE) -- **Repository**: [wolfpld/tracy](https://github.com/wolfpld/tracy) diff --git a/examples/01-hello-window/CMakeLists.txt b/examples/01-hello-window/CMakeLists.txt deleted file mode 100644 index 8f7a843..0000000 --- a/examples/01-hello-window/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -cmake_minimum_required(VERSION 3.21.0) - -project(01_HelloWindow) - -add_executable(01_HelloWindow - source/Main.cpp -) - -# TODO: Add dependencies to Graphical Playground Engine libraries here, e.g.: -# target_link_libraries(01_HelloWindow PRIVATE gp::core) diff --git a/examples/01-hello-window/source/Main.cpp b/examples/01-hello-window/source/Main.cpp deleted file mode 100644 index 7dcff13..0000000 --- a/examples/01-hello-window/source/Main.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include - -int main() -{ - // TODO: Remove this and replace it with actual code that creates a window and displays "Hello, World!" in it. - std::cout << "Hello, World!" << std::endl; - return 0; -} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a67bc89..1fe6857 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,9 +1,3 @@ # Copyright (c) - Graphical Playground. All rights reserved. # For more information, see https://graphical-playground/legal # mailto:support AT graphical-playground DOT com - -if (GP_BUILD_EXAMPLES) - return() -endif() - -add_subdirectory(01-hello-window) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt deleted file mode 100644 index 424a821..0000000 --- a/source/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpScanForTargets() diff --git a/source/docs/_category_.json b/source/docs/_category_.json deleted file mode 100644 index 364983e..0000000 --- a/source/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "C++ API Reference" -} diff --git a/source/launch/docs/_category_.json b/source/launch/docs/_category_.json deleted file mode 100644 index 36f4d56..0000000 --- a/source/launch/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Launch" -} diff --git a/source/launch/editor/.gitignore b/source/launch/editor/.gitignore index 825d71b..e69de29 100644 --- a/source/launch/editor/.gitignore +++ b/source/launch/editor/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the launch/editor directory diff --git a/source/launch/editor/CMakeLists.txt b/source/launch/editor/CMakeLists.txt index b348c9a..22fb52e 100644 --- a/source/launch/editor/CMakeLists.txt +++ b/source/launch/editor/CMakeLists.txt @@ -5,10 +5,8 @@ include(gp-build-tool) gpStartExecutable(editor) - gpSetTargetOutputName(gpeditor) - gpExecutableSetIsGUI(FALSE) - gpExecutableAddResource(${__targetLocation}/resources/AppIcon.rc) - - gpAddPublicDependency(core) - gpAddPublicDependency(hal) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC renderer) + gpAddDependency(PUBLIC engine) + gpAddDependency(PUBLIC application) gpEndExecutable() diff --git a/source/launch/editor/docs/_category_.json b/source/launch/editor/docs/_category_.json deleted file mode 100644 index ab225c8..0000000 --- a/source/launch/editor/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Editor" -} diff --git a/source/launch/editor/private/Main.cpp b/source/launch/editor/private/Main.cpp index 4d3f9e4..41c1c09 100644 --- a/source/launch/editor/private/Main.cpp +++ b/source/launch/editor/private/Main.cpp @@ -2,71 +2,10 @@ // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com -#include "container/BasicString.hpp" -#include "container/Forward.hpp" -#include "errors/Error.hpp" -#include "errors/ErrorConfig.hpp" -#include "errors/ErrorRegistry.hpp" -#include "errors/ErrorSystem.hpp" -#include "platform/PlatformMemory.hpp" #include -void tryAllocation() +int main() { - unsigned char buffer[16]; - - gp::memory::PlatformMemory::setMemory(buffer, 0xAB, sizeof(buffer)); - - for (size_t i = 0; i < sizeof(buffer); ++i) - { - if (buffer[i] != 0xAB) - { - std::cout << "memset failed at byte " << i << std::endl; - return; - } - } - - std::cout << "memset works!" << std::endl; -} - -int main(int argc, char* argv[]) -{ - std::cout << "Hello, Graphical Playground Editor!" << std::endl; - // TODO: Implement editor main function. - - gp::String str = "Hello, World!"; - std::cout << "gp::String says: " << str << std::endl; - - tryAllocation(); - - auto& registry = gp::error::ErrorRegistry::instance(); - std::cout << registry.dumpAll() << std::endl; - - gp::error::ErrorSystemConfig config = gp::error::ErrorSystemConfig::getDevelopmentConfig(); - config.abort.abortFrom = gp::error::Severity::Critical; - gp::error::ErrorSystem::initialize(config); - - gp::Vector args; - for (int i = 0; i < argc; ++i) - { - args.pushBack(argv[i]); - } - - for (const auto& arg: args) - { - // clang-format off - if (arg == "--trace") GP_TRACE("This is a trace message!"); - else if (arg == "--debug") GP_DEBUG("This is a debug message!"); - else if (arg == "--info") GP_INFO("This is an info message!"); - else if (arg == "--warn") GP_WARN("This is a warning message!"); - else if (arg == "--error") GP_ERROR("This is an error message!"); - else if (arg == "--fatal") GP_FATAL("This is a fatal message!"); - else if (arg == "--panic") GP_PANIC("This is a critical message!"); - // clang-format on - } - - gp::error::ErrorSystem::flushAll(); - gp::error::ErrorSystem::shutdown(); - + std::cout << "Hello, Editor!" << std::endl; return 0; } diff --git a/source/launch/editor/public/Editor.hpp b/source/launch/editor/public/Editor.hpp index 3113e46..88b9360 100644 --- a/source/launch/editor/public/Editor.hpp +++ b/source/launch/editor/public/Editor.hpp @@ -1,3 +1,5 @@ // Copyright (c) - Graphical Playground. All rights reserved. // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/launch/editor/resources/AppIcon.ico b/source/launch/editor/resources/AppIcon.ico deleted file mode 100644 index 3521c42..0000000 Binary files a/source/launch/editor/resources/AppIcon.ico and /dev/null differ diff --git a/source/launch/editor/resources/AppIcon.rc b/source/launch/editor/resources/AppIcon.rc deleted file mode 100644 index 7a9e848..0000000 --- a/source/launch/editor/resources/AppIcon.rc +++ /dev/null @@ -1,49 +0,0 @@ -#include - -IDI_APP_ICON ICON "AppIcon.ico" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK - FILEFLAGS 0x0L - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE VFT2_UNKNOWN -{ - BLOCK "StringFileInfo" - { - // English (U.S.) (0409) - BLOCK "040904B0" - { - VALUE "CompanyName", "Graphical Playground Inc" - VALUE "FileDescription", "GP Editor" - VALUE "FileVersion", "1.0.0.0" - VALUE "InternalName", "GPEditor.exe" - VALUE "LegalCopyright", "Copyright (C) 2026 Graphical Playground Inc" - VALUE "OriginalFilename", "GPEditor.exe" - VALUE "ProductName", "Graphical Playground Editor" - VALUE "ProductVersion", "1.0.0.0" - } - - // French (France) (040C) - BLOCK "040C04B0" - { - VALUE "CompanyName", "Graphical Playground Inc" - VALUE "FileDescription", "Éditeur GP" - VALUE "FileVersion", "1.0.0.0" - VALUE "InternalName", "GPEditor" - VALUE "LegalCopyright", "Copyright (C) 2026 Graphical Playground Inc" - VALUE "OriginalFilename", "GPEditor.exe" - VALUE "ProductName", "Graphical Playground Editor" - VALUE "ProductVersion", "1.0.0.0" - } - } - BLOCK "VarFileInfo" - { - // Must list both translations: - // 0x0409, 1200 = English (US) - // 0x040C, 1200 = French (Standard) - VALUE "Translation", 0x0409, 1200, 0x040C, 1200 - } -} diff --git a/source/launch/standalone/.gitignore b/source/launch/standalone/.gitignore deleted file mode 100644 index 05e85f4..0000000 --- a/source/launch/standalone/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the launch/standalone directory diff --git a/source/launch/standalone/CMakeLists.txt b/source/launch/standalone/CMakeLists.txt deleted file mode 100644 index 922026c..0000000 --- a/source/launch/standalone/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpStartExecutable(standalone) - gpSetTargetOutputName(gpstandalone) - gpExecutableSetIsGUI(FALSE) - gpExecutableAddResource(${__targetLocation}/resources/AppIcon.rc) - - gpAddPublicDependency(core) -gpEndExecutable() diff --git a/source/launch/standalone/docs/_category_.json b/source/launch/standalone/docs/_category_.json deleted file mode 100644 index 1757425..0000000 --- a/source/launch/standalone/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Standalone" -} diff --git a/source/launch/standalone/private/Main.cpp b/source/launch/standalone/private/Main.cpp deleted file mode 100644 index af52337..0000000 --- a/source/launch/standalone/private/Main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "container/BasicString.hpp" -#include "container/Forward.hpp" -#include - -int main() -{ - std::cout << "Hello, Graphical Playground Standalone!" << std::endl; - // TODO: Implement editor main function. - - gp::String str = "Hello, World!"; - std::cout << "gp::String says: " << str << std::endl; - - return 0; -} diff --git a/source/launch/standalone/resources/AppIcon.ico b/source/launch/standalone/resources/AppIcon.ico deleted file mode 100644 index 3521c42..0000000 Binary files a/source/launch/standalone/resources/AppIcon.ico and /dev/null differ diff --git a/source/launch/standalone/resources/AppIcon.rc b/source/launch/standalone/resources/AppIcon.rc deleted file mode 100644 index 7a9e848..0000000 --- a/source/launch/standalone/resources/AppIcon.rc +++ /dev/null @@ -1,49 +0,0 @@ -#include - -IDI_APP_ICON ICON "AppIcon.ico" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,0 - PRODUCTVERSION 1,0,0,0 - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK - FILEFLAGS 0x0L - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE VFT2_UNKNOWN -{ - BLOCK "StringFileInfo" - { - // English (U.S.) (0409) - BLOCK "040904B0" - { - VALUE "CompanyName", "Graphical Playground Inc" - VALUE "FileDescription", "GP Editor" - VALUE "FileVersion", "1.0.0.0" - VALUE "InternalName", "GPEditor.exe" - VALUE "LegalCopyright", "Copyright (C) 2026 Graphical Playground Inc" - VALUE "OriginalFilename", "GPEditor.exe" - VALUE "ProductName", "Graphical Playground Editor" - VALUE "ProductVersion", "1.0.0.0" - } - - // French (France) (040C) - BLOCK "040C04B0" - { - VALUE "CompanyName", "Graphical Playground Inc" - VALUE "FileDescription", "Éditeur GP" - VALUE "FileVersion", "1.0.0.0" - VALUE "InternalName", "GPEditor" - VALUE "LegalCopyright", "Copyright (C) 2026 Graphical Playground Inc" - VALUE "OriginalFilename", "GPEditor.exe" - VALUE "ProductName", "Graphical Playground Editor" - VALUE "ProductVersion", "1.0.0.0" - } - } - BLOCK "VarFileInfo" - { - // Must list both translations: - // 0x0409, 1200 = English (US) - // 0x040C, 1200 = French (Standard) - VALUE "Translation", 0x0409, 1200, 0x040C, 1200 - } -} diff --git a/source/runtime/animation/.gitignore b/source/runtime/animation/.gitignore deleted file mode 100644 index 21f2f1e..0000000 --- a/source/runtime/animation/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/animation directory diff --git a/source/runtime/animation/docs/_category_.json b/source/runtime/animation/docs/_category_.json deleted file mode 100644 index 8e5d95f..0000000 --- a/source/runtime/animation/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Animation" -} diff --git a/assets/editor/fonts/.gitkeep b/source/runtime/application/.gitignore similarity index 100% rename from assets/editor/fonts/.gitkeep rename to source/runtime/application/.gitignore diff --git a/source/launch/standalone/CHANGELOG.md b/source/runtime/application/CHANGELOG.md similarity index 100% rename from source/launch/standalone/CHANGELOG.md rename to source/runtime/application/CHANGELOG.md diff --git a/source/runtime/application/CMakeLists.txt b/source/runtime/application/CMakeLists.txt new file mode 100644 index 0000000..baf0aad --- /dev/null +++ b/source/runtime/application/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(application) + gpAddDependency(PUBLIC core) +gpEndModule() diff --git a/source/docs/README.md b/source/runtime/application/README.md similarity index 100% rename from source/docs/README.md rename to source/runtime/application/README.md diff --git a/source/launch/standalone/public/Standalone.hpp b/source/runtime/application/private/Application.cpp similarity index 100% rename from source/launch/standalone/public/Standalone.hpp rename to source/runtime/application/private/Application.cpp diff --git a/source/runtime/animation/public/Animation.hpp b/source/runtime/application/public/Application.hpp similarity index 100% rename from source/runtime/animation/public/Animation.hpp rename to source/runtime/application/public/Application.hpp diff --git a/source/runtime/audio/.gitignore b/source/runtime/audio/.gitignore deleted file mode 100644 index f4dd337..0000000 --- a/source/runtime/audio/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/audio directory diff --git a/assets/editor/icons/.gitkeep b/source/runtime/audio/base/.gitignore similarity index 100% rename from assets/editor/icons/.gitkeep rename to source/runtime/audio/base/.gitignore diff --git a/source/runtime/animation/CHANGELOG.md b/source/runtime/audio/base/CHANGELOG.md similarity index 100% rename from source/runtime/animation/CHANGELOG.md rename to source/runtime/audio/base/CHANGELOG.md diff --git a/source/runtime/input/CMakeLists.txt b/source/runtime/audio/base/CMakeLists.txt similarity index 78% rename from source/runtime/input/CMakeLists.txt rename to source/runtime/audio/base/CMakeLists.txt index c315cb0..0877998 100644 --- a/source/runtime/input/CMakeLists.txt +++ b/source/runtime/audio/base/CMakeLists.txt @@ -4,6 +4,6 @@ include(gp-build-tool) -gpStartModule(input) - gpAddPublicDependency(core) +gpStartModule(audio/base) + gpAddDependency(PUBLIC core) gpEndModule() diff --git a/source/launch/docs/README.md b/source/runtime/audio/base/README.md similarity index 100% rename from source/launch/docs/README.md rename to source/runtime/audio/base/README.md diff --git a/source/runtime/animation/private/Animation.cpp b/source/runtime/audio/base/private/AudioBase.cpp similarity index 100% rename from source/runtime/animation/private/Animation.cpp rename to source/runtime/audio/base/private/AudioBase.cpp diff --git a/source/runtime/audio/public/Audio.hpp b/source/runtime/audio/base/public/AudioBase.hpp similarity index 100% rename from source/runtime/audio/public/Audio.hpp rename to source/runtime/audio/base/public/AudioBase.hpp diff --git a/source/runtime/audio/docs/_category_.json b/source/runtime/audio/docs/_category_.json deleted file mode 100644 index c762891..0000000 --- a/source/runtime/audio/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Audio" -} diff --git a/assets/editor/layouts/.gitkeep b/source/runtime/audio/openal/.gitignore similarity index 100% rename from assets/editor/layouts/.gitkeep rename to source/runtime/audio/openal/.gitignore diff --git a/source/runtime/audio/CHANGELOG.md b/source/runtime/audio/openal/CHANGELOG.md similarity index 100% rename from source/runtime/audio/CHANGELOG.md rename to source/runtime/audio/openal/CHANGELOG.md diff --git a/source/runtime/audio/openal/CMakeLists.txt b/source/runtime/audio/openal/CMakeLists.txt new file mode 100644 index 0000000..efdb316 --- /dev/null +++ b/source/runtime/audio/openal/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(audio/openal) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC audio/base) +gpEndModule() diff --git a/source/launch/editor/docs/README.md b/source/runtime/audio/openal/README.md similarity index 100% rename from source/launch/editor/docs/README.md rename to source/runtime/audio/openal/README.md diff --git a/source/runtime/audio/private/Audio.cpp b/source/runtime/audio/openal/private/AudioOpenal.cpp similarity index 100% rename from source/runtime/audio/private/Audio.cpp rename to source/runtime/audio/openal/private/AudioOpenal.cpp diff --git a/source/runtime/core/public/Core.hpp b/source/runtime/audio/openal/public/AudioOpenal.hpp similarity index 100% rename from source/runtime/core/public/Core.hpp rename to source/runtime/audio/openal/public/AudioOpenal.hpp diff --git a/source/runtime/core/.gitignore b/source/runtime/core/.gitignore index 5df0890..e69de29 100644 --- a/source/runtime/core/.gitignore +++ b/source/runtime/core/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/core directory diff --git a/source/runtime/core/CMakeLists.txt b/source/runtime/core/CMakeLists.txt index 22d45b1..1539435 100644 --- a/source/runtime/core/CMakeLists.txt +++ b/source/runtime/core/CMakeLists.txt @@ -5,19 +5,4 @@ include(gp-build-tool) gpStartModule(core) - gpTargetSetTestsEnabled(TRUE) - # gpTargetSetBenchmarksEnabled(FALSE) - # gpTargetSetExamplesEnabled(FALSE) - - if (NOT WIN32) - gpTargetExcludeDirectory("platform/windows") - endif() - - if (NOT UNIX OR APPLE) - gpTargetExcludeDirectory("platform/linux") - endif() - - if (NOT APPLE) - gpTargetExcludeDirectory("platform/apple") - endif() gpEndModule() diff --git a/source/runtime/core/docs/Macros.md b/source/runtime/core/docs/Macros.md deleted file mode 100644 index 583e3df..0000000 --- a/source/runtime/core/docs/Macros.md +++ /dev/null @@ -1,187 +0,0 @@ ---- -title: Core Macros -description: Core macros for the C++ runtime. -tags: - - c++ - - macros - - runtime - - build ---- - -# Core Macros - -This document outlines the suite of preprocessor macros used across the engine to establish -compiler, platform, and architecture details, as well as essential utilities for memory alignment -and compiler hints. - -:::tip -All boolean-style detection macros in the GP engine are strictly defined to either `1` or `0`. You -can safely use them in both `#if` directives and standard `if` statements without worrying about -undefined macro warnings. -::: - -## Platform Detection - -These macros define the operating system environment where the engine is being compiled. They are -implemented in `DetectPlatform.hpp`. - -### Base Platforms - -| Macro | Description | -|-----------------------------|--------------------------------------------------------------------| -| `GP_PLATFORM_WINDOWS` | Defined to `1` when compiling for Windows. | -| `GP_PLATFORM_MACOS` | Defined to `1` when compiling for macOS. | -| `GP_PLATFORM_IOS` | Defined to `1` when compiling for iOS (device or simulator). | -| `GP_PLATFORM_LINUX` | Defined to `1` when compiling for Linux. | -| `GP_PLATFORM_ANDROID` | Defined to `1` when compiling for Android. | -| `GP_PLATFORM_WEB` | Defined to `1` when compiling for WebAssembly via Emscripten. | - -### Platform Families - -To simplify checks across related operating systems, use the following family macros: - -| Macro | Included Platforms | -|---------------------------|----------------------------------------------------------------------| -| `GP_PLATFORM_DESKTOP` | Windows, macOS, Linux | -| `GP_PLATFORM_MOBILE` | iOS, Android | -| `GP_PLATFORM_APPLE` | macOS, iOS | -| `GP_PLATFORM_UNIX` | Linux, macOS, iOS, Android | - -:::note Windows Specifics -When `GP_PLATFORM_WINDOWS` is active, the engine automatically defines `WIN32_LEAN_AND_MEAN` and -`NOMINMAX` to prevent header bloat and naming collisions with the standard library -`std::min` and `std::max`. -::: - -## Architecture Detection - -Found in `DetectArchitecture.hpp`, these macros identify the target CPU architecture. - -### Instruction Sets - -| Macro | Description | -|---------------------------|----------------------------------------------------------------------| -| `GP_ARCHITECTURE_X64` | 64-bit x86 architecture (AMD64/x86_64). | -| `GP_ARCHITECTURE_X86` | 32-bit x86 architecture. | -| `GP_ARCHITECTURE_ARM64` | 64-bit ARM architecture (AArch64). | -| `GP_ARCHITECTURE_ARM32` | 32-bit ARM architecture. | -| `GP_ARCHITECTURE_WASM` | WebAssembly target. | - -### Architecture Families & Bit-Width - -| Macro | Description | -|---------------------------------|----------------------------------------------------------------| -| `GP_ARCHITECTURE_X86_FAMILY` | Evaluates to `1` for either x86 or x64. | -| `GP_ARCHITECTURE_ARM_FAMILY` | Evaluates to `1` for either ARM32 or ARM64. | -| `GP_ARCHITECTURE_64BIT` | Evaluates to `1` for x64 or ARM64. | -| `GP_ARCHITECTURE_32BIT` | Evaluates to `1` for x86 or ARM32. | - -## SIMD Detection - -The engine detects available Single Instruction, Multiple Data (SIMD) instruction sets to allow -vectorization optimizations (`DetectSimd.hpp`). - -You can check `GP_SIMD_AVAILABLE` to quickly determine if any SIMD instruction set is supported by -the current target. -- x86/x64 Family: `GP_SIMD_SSE`, `GP_SIMD_SSE2`, `GP_SIMD_SSE3`, `GP_SIMD_SSSE3`, `GP_SIMD_SSE4_1`, `GP_SIMD_SSE4_2`, `GP_SIMD_AVX`, `GP_SIMD_AVX2`, `GP_SIMD_AVX512`, `GP_SIMD_FMA` -- ARM Family: `GP_SIMD_NEON`, `GP_SIMD_ARM_FMA` -- WebAssembly: `GP_SIMD_WASM128` - -## Compiler Detection - -Located in `DetectCompiler.hpp`, these macros identify the active C++ compiler and its version. - -| Macro | Description | -|-------------------------------|------------------------------------------------------------------| -| `GP_COMPILER_MSVC` | Microsoft Visual C++. | -| `GP_COMPILER_CLANG` | LLVM Clang. | -| `GP_COMPILER_GCC` | GNU Compiler Collection. | -| `GP_COMPILER_EMSCRIPTEN` | Emscripten compiler (WebAssembly). | -| `GP_COMPILER_INTEL` | Intel C++ Compiler (`__INTEL_COMPILER` or `__ICC`). | - -:::info -You can access the compiler's normalized version using `GP_COMPILER_VERSION`. The format varies -slightly depending on the compiler (e.g., Clang and GCC use `major * 10000 + minor * 100 + patch`). -::: - -## Build Configuration Detection - -Build configurations and language standards are managed in `DetectBuild.hpp`. - -### C++ Standard - -The engine enforces modern C++ practices. `GP_CXX_STANDARD` contains the numeric value of the active -standard (e.g., `202302L` for C++23). - -Additionally, internal macros (`GP_INTERNAL_CXX11` through `GP_INTERNAL_CXX26`) evaluate to `1` if -the current compilation targets that standard or higher. - -:::danger Minimum C++ Requirement -The Graphical Playground Engine **requires C++23 by default**. Compiling with an older standard -will trigger a hard compiler error. If you absolutely must build against an older standard, -define `GP_ALLOW_OLDER_STANDARDS` beforehand. -::: - -### Build Types - -| Macro | Description | -|---------------------------|----------------------------------------------------------------------| -| `GP_BUILD_DEBUG` | `1` when `DEBUG` or `_DEBUG` is defined; `0` otherwise. | -| `GP_BUILD_RELEASE` | `1` when debug flags are absent; `0` otherwise. | - -## Utility Macros - -Defined in `MacroUtilities.hpp`, these provide cross-platform abstractions for common compiler -attributes and memory operations. - -### String & Token Manipulation - -- `GP_CONCAT(a, b)`: Safely concatenates two tokens. -- `GP_STRINGIFY(x)`: Converts a token into a string literal. -- `GP_FIRST(...)` / `GP_FIRST_OR_DEFAULT(first, ...)`: Variadic helpers to extract the first - argument, primarily used for formatting fallbacks (GP_FORMAT_MSG). - -### Versioning - -- `GP_VERSION(major, minor, patch)`: Packs a semantic version into a single integer. -- `GP_VERSION_STRINGIFY(major, minor, patch)`: Creates a "major.minor.patch" string literal. - -### Inlining & Optimization Constraints - -| Macro | Description | -|------------------|-------------------------------------------------------------------------------| -| `GP_FORCEINLINE` | Forces the compiler to inline the function (e.g., `__forceinline` or `__attribute__((always_inline))`). | -| `GP_INLINE` | Suggests inlining, but the compiler may ignore the hint. | -| `GP_NOINLINE` | Explicitly prevents the compiler from inlining the function. | -| `GP_RESTRICT` | Asserts that a pointer does not alias any other pointer in the current scope. | - -### Code Flow & Hints - -| Macro | Description | -|-------------------|------------------------------------------------------------------------------| -| `GP_LIKELY(x)` | Hints to the branch predictor whether an expression evaluates to true or false. | -| `GP_UNLIKELY(x)` | Hints to the branch predictor whether an expression evaluates to true or false. | -| `GP_UNREACHABLE()`| Indicates a code path will never be executed, allowing the optimizer to aggressively prune logic. Undefined behavior if reached. | -| `GP_ASSUME(x)` | Provides a boolean hint to the optimizer without evaluating a branch. | -| `GP_DEBUGBREAK()` | Triggers a programmatic breakpoint in an attached debugger (`__debugbreak()` / `SIGTRAP`). | -| `GP_FUNCSIG` | Gets the full signature of the current function as a string literal. | - -### Attributes - -| Macro | Description | -|------------------------------------------|-------------------------------------------------------| -| `GP_DEPRECATED(version, msg)` | Marks a function/class as deprecated with a version reference and alternative suggestion. | -| `GP_NODISCARD` / `GP_NODISCARD_MSG(msg)` | Yields a compiler warning if the caller ignores the return value. | -| `GP_MAYBE_UNUSED` / `GP_UNUSED(x)` | Suppresses warnings for variables or parameters that might not be used in all build configs. | -| `GP_NORETURN` | Marks a function as never returning to the caller (e.g., an exception thrower or fatal error handler). | -| `GP_NO_UNIQUE_ADDRESS` | Allows empty members to occupy zero space (Empty Base Optimization). | - -### Memory & Alignment - -- `GP_ALIGN(x)`: Specifies the minimum alignment of a variable/struct in bytes. -- `GP_ALIGNED_ALLOC(size, alignment)`: Allocates heap memory aligned to the specified boundary. (Ensure size is a multiple of the alignment where required by the platform). -- `GP_ALIGNED_FREE(ptr)`: Frees memory allocated with `GP_ALIGNED_ALLOC`. - -### Assertions - -- `GP_ASSERT(condition, msg)`: Evaluates the condition and triggers a breakpoint with a message if it fails. Only active in debug builds. diff --git a/source/runtime/core/docs/_category_.json b/source/runtime/core/docs/_category_.json deleted file mode 100644 index f4620ea..0000000 --- a/source/runtime/core/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Core" -} diff --git a/source/runtime/core/docs/container/Array.md b/source/runtime/core/docs/container/Array.md deleted file mode 100644 index c2c69cb..0000000 --- a/source/runtime/core/docs/container/Array.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Array -description: Array implementation in Graphical Playground library -tags: - - c++ - - template - - container - - array ---- - -# Array - -:::warning -TODO: Add more details about the Array implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/container/BasicString.md b/source/runtime/core/docs/container/BasicString.md deleted file mode 100644 index a5fdf19..0000000 --- a/source/runtime/core/docs/container/BasicString.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: String -description: String implementation in Graphical Playground library -tags: - - c++ - - template - - container - - string ---- - -# String - -:::warning -TODO: Add more details about the String implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/container/BasicStringView.md b/source/runtime/core/docs/container/BasicStringView.md deleted file mode 100644 index ebf1da5..0000000 --- a/source/runtime/core/docs/container/BasicStringView.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: String View -description: String View implementation in Graphical Playground library -tags: - - c++ - - template - - container - - stringview ---- - -# String View - -:::warning -TODO: Add more details about the String View implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/container/Optional.md b/source/runtime/core/docs/container/Optional.md deleted file mode 100644 index 706837d..0000000 --- a/source/runtime/core/docs/container/Optional.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Optional -description: Optional implementation in Graphical Playground library -tags: - - c++ - - template - - container - - optional ---- - -# Optional - -:::warning -TODO: Add more details about the Optional implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/container/README.md b/source/runtime/core/docs/container/README.md deleted file mode 100644 index 154ad9d..0000000 --- a/source/runtime/core/docs/container/README.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -sidebar_position: 0 -title: Container -description: Reference documentation for the Container C++ API in the runtime core module. -tags: - - c++ - - container - - template ---- - -# Containers in Graphical Playground - -:::warning -This is work in progress. -The API is subject to change and may not be fully documented yet. -Please check back later for updates. -::: diff --git a/source/runtime/core/docs/container/Vector.md b/source/runtime/core/docs/container/Vector.md deleted file mode 100644 index 018d126..0000000 --- a/source/runtime/core/docs/container/Vector.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Vector -description: Vector implementation in Graphical Playground library -tags: - - c++ - - template - - container - - vector ---- - -# Vector - -:::warning -TODO: Add more details about the Vector implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/container/_category_.json b/source/runtime/core/docs/container/_category_.json deleted file mode 100644 index 0aa8a62..0000000 --- a/source/runtime/core/docs/container/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Container" -} diff --git a/source/runtime/core/docs/math/Mat2.md b/source/runtime/core/docs/math/Mat2.md deleted file mode 100644 index 846d546..0000000 --- a/source/runtime/core/docs/math/Mat2.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 2x2 Matrix -description: Mat2 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 2x2 Matrix (Mat2) - -:::warning -TODO: Add more details about the Mat2 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/Mat3.md b/source/runtime/core/docs/math/Mat3.md deleted file mode 100644 index 82c5139..0000000 --- a/source/runtime/core/docs/math/Mat3.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 3x3 Matrix -description: Mat3 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 3x3 Matrix (Mat3) - -:::warning -TODO: Add more details about the Mat3 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/Mat34.md b/source/runtime/core/docs/math/Mat34.md deleted file mode 100644 index 29f307e..0000000 --- a/source/runtime/core/docs/math/Mat34.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 3x4 Matrix -description: Mat34 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 3x4 Matrix (Mat34) - -:::warning -TODO: Add more details about the Mat34 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/Mat4.md b/source/runtime/core/docs/math/Mat4.md deleted file mode 100644 index a3e683e..0000000 --- a/source/runtime/core/docs/math/Mat4.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 4x4 Matrix -description: Mat4 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 4x4 Matrix (Mat4) - -:::warning -TODO: Add more details about the Mat4 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/README.md b/source/runtime/core/docs/math/README.md deleted file mode 100644 index aa464c7..0000000 --- a/source/runtime/core/docs/math/README.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -sidebar_position: 0 -title: Math -description: Reference documentation for the Math C++ API in the runtime core module. -tags: - - c++ - - math ---- - -# Math in Graphical Playground - -:::warning -This is work in progress. -The API is subject to change and may not be fully documented yet. -Please check back later for updates. -::: diff --git a/source/runtime/core/docs/math/Vec2.md b/source/runtime/core/docs/math/Vec2.md deleted file mode 100644 index a3dea74..0000000 --- a/source/runtime/core/docs/math/Vec2.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 2D Vector -description: Vec2 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 2D Vector (Vec2) - -:::warning -TODO: Add more details about the Vec2 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/Vec3.md b/source/runtime/core/docs/math/Vec3.md deleted file mode 100644 index bf79bf9..0000000 --- a/source/runtime/core/docs/math/Vec3.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 3D Vector -description: Vec3 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 3D Vector (Vec3) - -:::warning -TODO: Add more details about the Vec3 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/Vec4.md b/source/runtime/core/docs/math/Vec4.md deleted file mode 100644 index 60a0538..0000000 --- a/source/runtime/core/docs/math/Vec4.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: 4D Vector -description: Vec4 implementation in Graphical Playground library -tags: - - c++ - - template - - math ---- - -# 4D Vector (Vec4) - -:::warning -TODO: Add more details about the Vec4 implementation, including its features, -usage examples, and any specific optimizations or design choices made in the -Graphical Playground library. -::: diff --git a/source/runtime/core/docs/math/_category_.json b/source/runtime/core/docs/math/_category_.json deleted file mode 100644 index 564278e..0000000 --- a/source/runtime/core/docs/math/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Math" -} diff --git a/source/runtime/core/docs/memory/README.md b/source/runtime/core/docs/memory/README.md deleted file mode 100644 index 3838dbf..0000000 --- a/source/runtime/core/docs/memory/README.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -sidebar_position: 0 -title: Memory -description: Reference documentation for the Memory C++ API in the runtime core module. -tags: - - c++ - - memory ---- - -# Memory in Graphical Playground - -:::warning -This is work in progress. -The API is subject to change and may not be fully documented yet. -Please check back later for updates. -::: diff --git a/source/runtime/core/docs/memory/_category_.json b/source/runtime/core/docs/memory/_category_.json deleted file mode 100644 index 1b35165..0000000 --- a/source/runtime/core/docs/memory/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Memory" -} diff --git a/source/runtime/core/docs/memory/allocators/_category_.json b/source/runtime/core/docs/memory/allocators/_category_.json deleted file mode 100644 index 282bba4..0000000 --- a/source/runtime/core/docs/memory/allocators/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Allocators" -} diff --git a/source/runtime/core/docs/utils/Enums.md b/source/runtime/core/docs/utils/Enums.md deleted file mode 100644 index 20dda77..0000000 --- a/source/runtime/core/docs/utils/Enums.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Enumerations -description: Enumerations utilities for the C++ runtime. -tags: - - c++ - - utilities - - runtime - - enums ---- - -# Enumerations Utilities - -Modern C++ `enum class` types provide excellent type safety and scoping, but they lack the ergonomic -of C-Style enums when it comes to bitwise manipulation and logical ordering. The Graphical -Playground Enum Utilities provide a trait-based "opt-in" mechanism to restore these features safely -using C++20/23 concepts. - -## Bitwise Operators - -### Overview - -By default, scoped enumerations cannot be treated as bitmasks. Developers are usually forced to -pepper their code with `static_cast(...)` just to combine two flags. - -The `gp::BitwiseEnum` concept allows you to enable standard bitwise operators (`|`, `&`, `^`, `~`) -and their assignment variants (`|=`, `&=`, `^=`) for specific enum types. This ensures your flags -remain type-safe while behaving like the bitfields they are meant to be. - -### Usage - -To enable bitwise operations, use the `GP_ENABLE_ENUM_BITWISE_OPERATIONS` macro in the global -namespace. - -```cpp showLineNumbers -enum class MyFlags : gp::UInt8 -{ - None = 0, - FlagA = 1 << 0, - FlagB = 1 << 1, - FlagC = 1 << 2, -}; - -// Enable bitwise operations for MyFlags -GP_ENABLE_ENUM_BITWISE_OPERATIONS(MyFlags); - -// Now you can use bitwise operators without casts -MyFlags flags = MyFlags::FlagA | MyFlags::FlagC; -``` - -### Semantic Helpers - -In addition to operators, the `gp::enums` namespace provides high-level helpers for more -readable logic: - -| Function | Description | -|--------------------------------|-----------------------------------------------------------------| -| `gp::enums::hasAnyFlags` | Returns true if the value is non-zero. | -| `gp::enums::hasAllFlags` | Returns true if all specified flags are set. | -| `gp::enums::hasNoFlags` | Returns true if none of the specified flags are set. | -| `gp::enums::setFlags` | Sets the specified flags on a value. | -| `gp::enums::clearFlags` | Clears the specified flags from a value. | -| `gp::enums::toggleFlags` | Toggles the specified flags on a value. | - -## Comparison Operators - -### Overview - -While `enum class` supports basic comparison by default, it is often useful to explicitly mark an -enum as comparable. This is particularly relevant in generic programming when using the -`gp::ComparableEnum` concept to constrain templates. - -Enabling this explicitly signals that the underlying integer order of the enum is a meaningful -representation of "scale" or "priority" (e.g., `low < high`). - -### Usage - -Use the `GP_ENABLE_ENUM_COMPARISON_OPERATIONS` macro to register the enum. - -```cpp showLineNumbers -enum class ThreadPriority : gp::UInt8 -{ - Idle, - Lowest, - Normal, - Highest, - TimeCritical -}; - -GP_ENABLE_ENUM_COMPARISON_OPERATIONS(ThreadPriority); - -// Now valid for systems constrained by gp::ComparableEnum -if (currentPriority > ThreadPriority::Normal) -{ - boostPerformance(); -} -``` - -## Concept Constraints - -The primary power of these utilities lies in their integration with C++ concepts. You can write -generic code that strictly only accepts your "enhanced" enums: - -```cpp showLineNumbers -template -void processFlags(E flags) -{ - if (gp::enums::hasAnyFlags(flags)) - { - // Process flags - } -} - -template -void comparePriorities(E a, E b) -{ - if (a < b) - { - // a has lower priority than b - } -} -``` - -:::note -These operations are implemented using constexpr and `GP_INLINE`, resulting in zero runtime overhead. -The generated assembly is identical to performing operations on raw integers. -::: diff --git a/source/runtime/core/docs/utils/README.md b/source/runtime/core/docs/utils/README.md deleted file mode 100644 index b032e74..0000000 --- a/source/runtime/core/docs/utils/README.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -sidebar_position: 0 -title: Utilities -description: Reference documentation for the Utilities C++ API in the runtime core module. -tags: - - c++ - - utilities ---- - -# Utilities in Graphical Playground - -:::warning -This is work in progress. -The API is subject to change and may not be fully documented yet. -Please check back later for updates. -::: diff --git a/source/runtime/core/docs/utils/_category_.json b/source/runtime/core/docs/utils/_category_.json deleted file mode 100644 index 8c77d9c..0000000 --- a/source/runtime/core/docs/utils/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Utilities" -} diff --git a/source/runtime/core/private/Core.cpp b/source/runtime/core/private/Core.cpp index 3113e46..b635a90 100644 --- a/source/runtime/core/private/Core.cpp +++ b/source/runtime/core/private/Core.cpp @@ -1,3 +1,14 @@ // Copyright (c) - Graphical Playground. All rights reserved. // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com + +#include "platforms/base/Platform.hpp" // IWYU pragma: keep + +int somethingToCompile() +{ +#if GP_PLATFORM_WINDOWS + return 42; +#else + return 0; +#endif +} diff --git a/source/runtime/core/private/errors/ErrorContext.cpp b/source/runtime/core/private/errors/ErrorContext.cpp deleted file mode 100644 index 35a69cf..0000000 --- a/source/runtime/core/private/errors/ErrorContext.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/ErrorContext.hpp" -#include "CoreMinimal.hpp" - -namespace gp::error -{ - -void ErrorContext::push(gp::String subsystem, gp::String operation) -{ - m_stack.pushBack({ std::move(subsystem), std::move(operation), {} }); -} - -void ErrorContext::pop() noexcept -{ - if (!m_stack.isEmpty()) - { - m_stack.popBack(); - } -} - -void ErrorContext::tag(gp::String key, gp::String value) -{ - if (!m_stack.isEmpty()) - { - m_stack.back().tags.pushBack({ std::move(key), std::move(value) }); - } -} - -GP_NODISCARD bool ErrorContext::isEmpty() const noexcept -{ - return m_stack.isEmpty(); -} - -GP_NODISCARD gp::USize ErrorContext::depth() const noexcept -{ - return m_stack.size(); -} - -GP_NODISCARD const gp::Vector& ErrorContext::frames() const noexcept -{ - return m_stack; -} - -GP_NODISCARD gp::StringView ErrorContext::currentSubsystem() const noexcept -{ - return m_stack.isEmpty() ? gp::StringView{} : m_stack.back().subsystem.asView(); -} - -GP_NODISCARD MetaBag ErrorContext::flatten() const -{ - MetaBag out; - - for (gp::USize i = 0; i < m_stack.size(); ++i) - { - const auto& frame = m_stack[i]; - out.pushBack({ gp::String::format("scope[{}].subsystem", i), frame.subsystem }); - out.pushBack({ gp::String::format("scope[{}].operation", i), frame.operation }); - for (const auto& tag: frame.tags) - { - out.pushBack({ gp::String::format("scope[{}].{}", i, tag.key), tag.value }); - } - } - - return out; -} - -void ErrorContext::setThreadName(gp::String name) -{ - m_threadName = std::move(name); -} - -GP_NODISCARD const gp::String& ErrorContext::threadName() const noexcept -{ - return m_threadName; -} - -ContextScope::ContextScope(gp::String subsystem, gp::String operation) -{ - ErrorContext::current().push(std::move(subsystem), std::move(operation)); -} - -ContextScope::~ContextScope() noexcept -{ - ErrorContext::current().pop(); -} - -ContextScope& ContextScope::tag(gp::String key, gp::String value) -{ - ErrorContext::current().tag(std::move(key), std::move(value)); - return *this; -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/ErrorRecord.cpp b/source/runtime/core/private/errors/ErrorRecord.cpp deleted file mode 100644 index ba30181..0000000 --- a/source/runtime/core/private/errors/ErrorRecord.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/ErrorRecord.hpp" -#include "errors/ErrorCode.hpp" -#include "errors/ErrorSeverity.hpp" -#include -#include - -namespace gp::error -{ - -void ErrorRecord::addMetadata(gp::String key, gp::String value) -{ - metadata.pushBack({ std::move(key), std::move(value) }); -} - -GP_NODISCARD gp::StringView ErrorRecord::getMetadata(gp::StringView key) const noexcept -{ - for (const auto& entry: metadata) - { - if (entry.key == key) - { - return entry.value; - } - } - return {}; -} - -GP_NODISCARD bool ErrorRecord::hasCause() const noexcept -{ - return cause != nullptr; -} - -GP_NODISCARD gp::USize ErrorRecord::causeDepth() const noexcept -{ - gp::USize depth = 0; - const ErrorRecord* current = cause.get(); - while (current) - { - ++depth; - current = current->cause.get(); - } - return depth; -} - -GP_NODISCARD gp::String ErrorRecord::summary() const -{ - return gp::String::format( - "[{}][{}:0x{:04X}] {} ({}:{})", - getSeverityName(severity), - getDomainName(code.domain()), - code.code(), - message, - location.file_name(), - location.line() - ); -} - -GP_NODISCARD gp::String ErrorRecord::fullReport() const -{ - gp::String out; - out.reserve(2048); - - out += "╔══ GP ErrorRecord ═══════════════════════════════════════════╗\n"; - out += gp::String::format("║ Severity : {}\n", getSeverityDisplay(severity)); - out += gp::String::format("║ Code : [{}] 0x{:04X}\n", getDomainName(code.domain()), code.code()); - out += gp::String::format("║ Message : {}\n", message); - out += gp::String::format( - "║ Location : {}:{} in {}\n", location.file_name(), location.line(), location.function_name() - ); - out += gp::String::format( - "║ Thread : {} ({})\n", - threadName.isEmpty() ? "unnamed" : threadName, - [&] - { - auto id = threadId; - std::hash hashThreadId; - return gp::String::format("{:#x}", hashThreadId(id)); - }() - ); - - auto tt = std::chrono::system_clock::to_time_t(wallTime); - char tbuf[64]{}; - struct tm tm{}; -#if defined(_MSC_VER) - gmtime_s(&tm, &tt); -#else - gmtime_r(&tt, &tm); -#endif - strftime(tbuf, sizeof tbuf, "%Y-%m-%d %T UTC", &tm); - out += gp::String::format("║ Timestamp : {}\n", tbuf); - - if (!metadata.isEmpty()) - { - out += "║ Meta :\n"; - for (const auto& m: metadata) - { - out += gp::String::format("║ {} = {}\n", m.key, m.value); - } - } - -#if GP_HAS_STACKTRACE - if (!stacktrace.empty()) - { - out += "║ Stacktrace:\n"; - for (const auto& frame: stacktrace) - { - out += gp::String::format("║ {}\n", std::to_string(frame)); - } - } -#endif - - if (hasCause()) - { - out += "║ Caused by :\n"; - const ErrorRecord* c = cause.get(); - int depth = 0; - while (c && depth < 8) - { - out += gp::String::format("║ [{}] {}\n", getSeverityName(c->severity), c->message); - c = c->cause.get(); - ++depth; - } - } - - out += "╚══════════════════════════════════════════════════════════════╝\n"; - - return out; -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/ErrorRegistry.cpp b/source/runtime/core/private/errors/ErrorRegistry.cpp deleted file mode 100644 index 708148c..0000000 --- a/source/runtime/core/private/errors/ErrorRegistry.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/ErrorRegistry.hpp" -#include "container/Optional.hpp" -#include "errors/ErrorCode.hpp" - -namespace gp::error -{ - -ErrorRegistry::ErrorRegistry() -{ - registerBuiltins(); -} - -void ErrorRegistry::registerCode(ErrorCode code, ErrorEntry entry) -{ - std::lock_guard lock(m_mutex); - m_table[code.raw()] = std::move(entry); -} - -GP_NODISCARD gp::Optional ErrorRegistry::lookup(ErrorCode code) const -{ - std::lock_guard lock(m_mutex); - auto it = m_table.find(code.raw()); - if (it == m_table.end()) - { - return gp::nullOpt; - } - return it->second; -} - -GP_NODISCARD gp::String ErrorRegistry::describe(ErrorCode code) const -{ - std::lock_guard lock(m_mutex); - auto it = m_table.find(code.raw()); - if (it == m_table.end()) - { - return gp::String(""); - } - return gp::String(it->second.description); -} - -GP_NODISCARD gp::String ErrorRegistry::remediationHint(ErrorCode code) const -{ - std::lock_guard lock(m_mutex); - auto it = m_table.find(code.raw()); - if (it == m_table.end()) - { - return {}; - } - return gp::String(it->second.remediation); -} - -GP_NODISCARD gp::String ErrorRegistry::wikiUrl(ErrorCode code) const -{ - std::lock_guard lock(m_mutex); - auto it = m_table.find(code.raw()); - if (it == m_table.end()) - { - return {}; - } - return gp::String(it->second.wikiUrl); -} - -GP_NODISCARD bool ErrorRegistry::isExpected(ErrorCode code) const -{ - std::lock_guard lock(m_mutex); - auto it = m_table.find(code.raw()); - return it != m_table.end() && it->second.isExpected; -} - -GP_NODISCARD bool ErrorRegistry::isAlwaysFatal(ErrorCode code) const -{ - std::lock_guard lock(m_mutex); - auto it = m_table.find(code.raw()); - return it != m_table.end() && it->second.isAlwaysFatal; -} - -GP_NODISCARD gp::USize ErrorRegistry::size() const -{ - std::lock_guard lock(m_mutex); - return m_table.size(); -} - -GP_NODISCARD gp::String ErrorRegistry::dumpAll() const -{ - std::lock_guard lock(m_mutex); - gp::String out; - out.reserve(m_table.size() * 128); - out += gp::String::format("ErrorRegistry - {} entries\n", m_table.size()); - out += "--------------------------------\n"; - for (const auto& [raw, entry]: m_table) - { - ErrorCode code{ raw }; - out += gp::String::format( - " [{:>12}][0x{:04X}] {}\n", getDomainName(code.domain()), code.code(), entry.description - ); - if (!entry.remediation.isEmpty()) - { - out += gp::String::format(" -> {}\n", entry.remediation); - } - if (!entry.wikiUrl.isEmpty()) - { - out += gp::String::format(" See: {}\n", entry.wikiUrl); - } - if (entry.isExpected) - { - out += " (expected - not a bug)\n"; - } - if (entry.isAlwaysFatal) - { - out += " [!] always fatal\n"; - } - } - return out; -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/ErrorSink.cpp b/source/runtime/core/private/errors/ErrorSink.cpp deleted file mode 100644 index 389a232..0000000 --- a/source/runtime/core/private/errors/ErrorSink.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/ErrorSink.hpp" - -namespace gp::error -{ - -void Sink::flush() -{} - -GP_NODISCARD Severity Sink::minSeverity() const noexcept -{ - return m_minSeverity; -} - -void Sink::setMinSeverity(Severity severity) noexcept -{ - m_minSeverity = severity; -} - -void Sink::addDomainFilter(Domain domain) -{ - m_domainFilter.pushBack(domain); -} - -void Sink::clearDomainFilter() -{ - m_domainFilter.clear(); -} - -GP_NODISCARD const gp::String& Sink::name() const noexcept -{ - return m_name; -} - -void Sink::setName(gp::String name) -{ - m_name = std::move(name); -} - -void Sink::dispatch(const ErrorRecord& record) -{ - if (record.severity < m_minSeverity) - { - return; - } - if (!m_domainFilter.isEmpty()) - { - bool isAllowed = false; - for (Domain domain: m_domainFilter) - { - if (domain == record.code.domain()) - { - isAllowed = true; - break; - } - } - if (!isAllowed) - { - return; - } - } - onRecord(record); -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/ErrorSystem.cpp b/source/runtime/core/private/errors/ErrorSystem.cpp deleted file mode 100644 index 0246fdb..0000000 --- a/source/runtime/core/private/errors/ErrorSystem.cpp +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/ErrorSystem.hpp" -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorSeverity.hpp" -#include "errors/sinks/AbortSink.hpp" -#if GP_BUILD_DEBUG - #include "errors/sinks/BreakpointSink.hpp" -#endif -#include "errors/sinks/ConsoleSink.hpp" -#include "errors/sinks/FileSink.hpp" -#include "memory/ownership/UniquePtr.hpp" -#if GP_PLATFORM_WINDOWS - #include -#elif GP_PLATFORM_LINUX || GP_PLATFORM_APPLE - #include -#endif -#include -#include -#include - -namespace gp::error -{ - -std::atomic ErrorSystem::s_instance{ nullptr }; -std::mutex ErrorSystem::s_initMutex; -std::mutex ErrorSystem::m_sinkMutex; - -ErrorSystem::ErrorSystem(ErrorSystemConfig config) - : m_config(std::move(config)) - , m_rootSink(gp::makeUnique()) - , m_initTime(std::chrono::steady_clock::now()) -{ - if (m_config.addDefaultConsoleSink) - { - auto consoleSink = std::make_shared(/*useAnsiColor=*/true); - consoleSink->setMinSeverity(m_config.filter.globalMinSeverity); - m_rootSink->addSink(std::move(consoleSink)); - } - - if (!m_config.defaultLogFilePath.isEmpty()) - { - try - { - auto fileSink = std::make_shared(m_config.defaultLogFilePath); - fileSink->setMinSeverity(m_config.filter.globalMinSeverity); - m_rootSink->addSink(std::move(fileSink)); - } - catch (const std::exception& e) - { - std::fprintf(stderr, "[GP ErrorSystem] WARNING: Could not open log file: %s\n", e.what()); - } - } - -#if GP_BUILD_DEBUG - if (m_config.breakpoint.checkIsDebugged) - { - auto breakpointSink = std::make_shared(m_config.breakpoint.breakFrom); - m_rootSink->addSink(std::move(breakpointSink)); - } -#endif - - { - auto abortSink = std::make_shared( - m_config.abort.abortFrom, m_config.abort.useTerminate ? AbortSink::Mode::Terminate : AbortSink::Mode::Abort - ); - m_rootSink->addSink(std::move(abortSink)); - } -} - -ErrorSystem::~ErrorSystem() -{ - m_rootSink->flush(); -} - -void ErrorSystem::initialize(ErrorSystemConfig config) -{ - std::lock_guard lock(s_initMutex); - - if (s_instance.load(std::memory_order_acquire) != nullptr) - { - ErrorSystem::dispatch( - Severity::Warning, - codes::kAlreadyExists, - "ErrorSystem::initialize() called more than once, ignoring.", - std::source_location::current() - ); - return; - } - - auto* instance = new ErrorSystem(std::move(config)); - s_instance.store(instance, std::memory_order_release); - - if (instance->m_config.printBannerOnInit) - { - // TODO: Replace with internal logging once available - std::fprintf( - stderr, - "\033[36m[GP ErrorSystem] Initialized - build: %s %s" " | stacktrace: %s | globalMin: %s\033[0m\n", - __DATE__, - __TIME__, -#if GP_HAS_STACKTRACE - instance->m_config.stacktrace.enabled ? "on" : "off", -#else - "n/a", -#endif - getSeverityDisplay(instance->m_config.filter.globalMinSeverity).data() - ); - } -} - -void ErrorSystem::shutdown() -{ - std::lock_guard lock(s_initMutex); - ErrorSystem* instance = s_instance.exchange(nullptr, std::memory_order_acq_rel); - if (instance) - { - instance->m_rootSink->flush(); - delete instance; - } -} - -bool ErrorSystem::isInitialized() noexcept -{ - return s_instance.load(std::memory_order_acquire) != nullptr; -} - -void ErrorSystem::addSink(std::shared_ptr sink) -{ - std::lock_guard lock(m_sinkMutex); - if (auto* instance = s_instance.load(std::memory_order_acquire)) - { - instance->m_rootSink->addSink(std::move(sink)); - } -} - -void ErrorSystem::removeSink(const gp::String& name) -{ - std::lock_guard lock(m_sinkMutex); - if (auto* instance = s_instance.load(std::memory_order_acquire)) - { - instance->m_rootSink->removeSink(name); - } -} - -void ErrorSystem::clearSinks() -{ - std::lock_guard lock(m_sinkMutex); - if (auto* instance = s_instance.load(std::memory_order_acquire)) - { - instance->m_rootSink = gp::makeUnique(); - } -} - -void ErrorSystem::flushAll() -{ - std::lock_guard lock(m_sinkMutex); - if (auto* instance = s_instance.load(std::memory_order_acquire)) - { - instance->m_rootSink->flush(); - } -} - -GP_NODISCARD MultiSink& ErrorSystem::rootSink() -{ - GP_ASSERT(isInitialized() && "ErrorSystem must be initialized before accessing rootSink"); - std::lock_guard lock(m_sinkMutex); - return *s_instance.load(std::memory_order_acquire)->m_rootSink; -} - -const ErrorSystemConfig& ErrorSystem::config() noexcept -{ - GP_ASSERT(isInitialized() && "ErrorSystem must be initialized before accessing rootSink"); - return s_instance.load(std::memory_order_acquire)->m_config; -} - -void ErrorSystem::setGlobalMinSeverity(Severity severity) noexcept -{ - if (auto* inst = s_instance.load(std::memory_order_acquire)) - { - inst->m_config.filter.globalMinSeverity = severity; - } -} - -const ErrorStatistics& ErrorSystem::stats() noexcept -{ - GP_ASSERT(isInitialized() && "ErrorSystem must be initialized before accessing rootSink"); - return s_instance.load(std::memory_order_acquire)->m_stats; -} - -void ErrorSystem::resetStats() noexcept -{ - if (auto* instance = s_instance.load(std::memory_order_acquire)) - { - for (auto& counter: instance->m_stats.counts) - { - counter.store(0, std::memory_order_relaxed); - } - } -} - -void ErrorSystem::dispatch( - Severity severity, - ErrorCode code, - gp::String message, - std::source_location location, - std::shared_ptr cause -) -{ - ErrorSystem* inst = s_instance.load(std::memory_order_acquire); - if (!inst) - { - // Fallback: write to stderr if system not initialized - std::fprintf( - stderr, - "[GP] [%s] %s (%s:%u)\n", - getSeverityDisplay(severity).data(), - message.cStr(), - location.file_name(), - location.line() - ); - return; - } - inst->dispatchImpl(severity, code, std::move(message), location, std::move(cause)); -} - -void ErrorSystem::dispatchImpl( - Severity severity, - ErrorCode code, - gp::String message, - std::source_location location, - std::shared_ptr cause -) -{ - if (severity < m_config.filter.globalMinSeverity) - { - return; - } - - if (m_config.filter.deduplicate) - { - // std::size_t hashIndex = std::hash{}(message) ^ (std::hash{}(code.raw()) << 17u); - // auto now = std::chrono::steady_clock::now(); - // { - // std::lock_guard lock(m_dedupMutex); - // auto it = m_dedupTable.find(hashIndex); - // if (it != m_dedupTable.end()) - // { - // auto elapsed = std::chrono::duration_cast(now - it->second).count(); - // if (static_cast(elapsed) < m_config.filter.dedupWindowMs) - // { - // m_stats.totalDropped.fetch_add(1, std::memory_order_relaxed); - // return; - // } - // } - // m_dedupTable[hashIndex] = now; - // } - } - - auto record = std::make_shared(); - record->severity = severity; - record->code = code; - record->message = std::move(message); - record->location = location; - record->cause = std::move(cause); - record->engineTime = std::chrono::steady_clock::now(); - record->wallTime = std::chrono::system_clock::now(); - record->threadId = std::this_thread::get_id(); - record->threadName = ErrorContext::current().threadName(); - - { - gp::StringView sub = ErrorContext::current().currentSubsystem(); - if (!sub.isEmpty()) - { - record->subsystem = gp::String(sub); - } - } - - { - // MetaBag ctxMeta = ErrorContext::current().flatten(); - // record->metadata.insert( - // record->metadata.end(), std::make_move_iterator(ctxMeta.begin()), std::make_move_iterator(ctxMeta.end()) - // ); - } - -#if GP_HAS_STACKTRACE - if (m_config.stacktrace.enabled && severity >= m_config.stacktrace.captureFrom) - { - record->stacktrace = std::stacktrace::current(m_config.stacktrace.skipFrames, m_config.stacktrace.maxFrames); - } -#endif - - m_stats.increment(severity); - - m_rootSink->dispatch(*record); - - if (m_config.abort.flushBeforeAbort && severity >= Severity::Fatal) - { - m_rootSink->flush(); - } -} - -bool ErrorSystem::shouldDedup(const DedupKey&) -{ - // Full implementation in dispatchImpl. - return false; -} - -void ErrorSystem::onSignal(int sig) -{ - const char* name = "SIGUNKNOWN"; - switch (sig) - { -#if defined(SIGSEGV) - case SIGSEGV: - name = "SIGSEGV (segmentation fault)"; - break; -#endif -#if defined(SIGABRT) - case SIGABRT: - name = "SIGABRT (abort)"; - break; -#endif -#if defined(SIGFPE) - case SIGFPE: - name = "SIGFPE (floating-point exception)"; - break; -#endif -#if defined(SIGILL) - case SIGILL: - name = "SIGILL (illegal instruction)"; - break; -#endif -#if defined(SIGBUS) - case SIGBUS: - name = "SIGBUS (bus error)"; - break; -#endif - } - - ErrorSystem::dispatch( - Severity::Critical, - codes::kUnknown, - gp::String::format("Fatal signal received: {} ({})", name, sig), - std::source_location::current() - ); - - std::signal(sig, SIG_DFL); - std::raise(sig); -} - -void ErrorSystem::installSignalHandlers() -{ -#if GP_PLATFORM_WINDOWS || GP_PLATFORM_LINUX || GP_PLATFORM_APPLE - std::signal(SIGSEGV, onSignal); - std::signal(SIGABRT, onSignal); - std::signal(SIGFPE, onSignal); - std::signal(SIGILL, onSignal); - #if defined(SIGBUS) - std::signal(SIGBUS, onSignal); - #endif -#endif -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/sinks/AbortSink.cpp b/source/runtime/core/private/errors/sinks/AbortSink.cpp deleted file mode 100644 index 67e5d32..0000000 --- a/source/runtime/core/private/errors/sinks/AbortSink.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/sinks/AbortSink.hpp" -#include -#include -#include - -namespace gp::error -{ - -AbortSink::AbortSink(Severity abortAt, Mode mode) - : m_abortAt(abortAt) - , m_mode(mode) -{ - setName("AbortSink"); - setMinSeverity(abortAt); -} - -void AbortSink::onRecord(const ErrorRecord& record) -{ - if (record.severity >= m_abortAt) - { - std::fflush(stderr); - switch (m_mode) - { - case Mode::Abort: - std::abort(); - break; - case Mode::Terminate: - std::terminate(); - break; - } - } -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/sinks/BreakpointSink.cpp b/source/runtime/core/private/errors/sinks/BreakpointSink.cpp deleted file mode 100644 index c79a981..0000000 --- a/source/runtime/core/private/errors/sinks/BreakpointSink.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/sinks/BreakpointSink.hpp" - -namespace gp::error -{ - -BreakpointSink::BreakpointSink(Severity breakAt) - : m_breakAt(breakAt) -{ - setName("BreakpointSink"); - setMinSeverity(breakAt); -} - -void BreakpointSink::onRecord(const ErrorRecord& record) -{ - if (record.severity >= m_breakAt) - { - GP_DEBUGBREAK(); - } -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/sinks/ConsoleSink.cpp b/source/runtime/core/private/errors/sinks/ConsoleSink.cpp deleted file mode 100644 index 37fe43e..0000000 --- a/source/runtime/core/private/errors/sinks/ConsoleSink.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/sinks/ConsoleSink.hpp" -#include - -namespace gp::error -{ - -ConsoleSink::ConsoleSink(bool useAnsiColor, bool toStdout) - : m_useColor(useAnsiColor) - , m_stream(toStdout ? stdout : stderr) -{ - setName("ConsoleSink"); -} - -void ConsoleSink::onRecord(const ErrorRecord& record) -{ - // Format: [WRN][Window:0x0041] Window creation failed (main.cpp:42) - const bool color = m_useColor; - const auto ansi = color ? getSeverityAnsiColor(record.severity) : ""; - const auto reset = color ? "\033[0m" : ""; - const auto bold = color ? "\033[1m" : ""; - - // Wall clock ISO 8601 - auto tt = std::chrono::system_clock::to_time_t(record.wallTime); - char timebuf[32] = {}; - // Thread-safe strftime equivalent (no gmtime_r on MSVC without CRT ext) -#if defined(_MSC_VER) - struct tm tmval{}; - gmtime_s(&tmval, &tt); - strftime(timebuf, sizeof timebuf, "%T", &tmval); -#else - struct tm tmval{}; - gmtime_r(&tt, &tmval); - strftime(timebuf, sizeof timebuf, "%T", &tmval); -#endif - - gp::String line; - line.reserve(256); - line += ansi; - line += gp::String::format("[{}] ", getSeverityName(record.severity)); - line += reset; - line += gp::String::format("{} ", timebuf); - - if (!record.subsystem.isEmpty()) - { - line += gp::String::format("[{}] ", record.subsystem); - } - - line += bold; - line += record.message; - line += reset; - - // Source location (short form, basename only) - std::string_view file = record.location.file_name(); - if (auto pos = file.rfind('/'); pos != std::string_view::npos) - { - file = file.substr(pos + 1); - } - if (auto pos = file.rfind('\\'); pos != std::string_view::npos) - { - file = file.substr(pos + 1); - } - - line += gp::String::format(" ({}:{})", file, record.location.line()); - - if (!record.threadName.isEmpty()) - { - line += gp::String::format(" [{}]", record.threadName); - } - - line += '\n'; - - // Stacktrace (only for Error and above, configurable) - if (m_printStacktrace && record.severity >= Severity::Error) - { -#if GP_HAS_STACKTRACE - if (!record.stacktrace.empty()) - { - line += gp::String::format("{} Stack trace:\n{}", ansi, reset); - for (const auto& frame: record.stacktrace) - { - line += gp::String::format(" {}\n", std::to_string(frame)); - } - } -#endif - } - - // Cause chain - if (record.hasCause() && m_printCause) - { - const ErrorRecord* cause = record.cause.get(); - int depth = 0; - while (cause) - { - line += gp::String::format( - " {}Caused by [{}]{}: {}\n", ansi, getSeverityName(cause->severity), reset, cause->message - ); - cause = cause->cause.get(); - if (++depth > 8) - { - line += " ... (truncated)\n"; - break; - } - } - } - - std::lock_guard lock(m_mutex); - std::fwrite(line.data(), 1, line.size(), m_stream); -} - -void ConsoleSink::flush() -{ - std::fflush(m_stream); -} - -void ConsoleSink::setPrintStacktrace(bool enabled) noexcept -{ - m_printStacktrace = enabled; -} - -void ConsoleSink::setPrintCause(bool enabled) noexcept -{ - m_printCause = enabled; -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/sinks/FileSink.cpp b/source/runtime/core/private/errors/sinks/FileSink.cpp deleted file mode 100644 index 8c960ca..0000000 --- a/source/runtime/core/private/errors/sinks/FileSink.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/sinks/FileSink.hpp" -#include "errors/ErrorCode.hpp" -#include "errors/ErrorSeverity.hpp" -#include -#include - -namespace gp::error -{ - -FileSink::FileSink(const gp::String& path) - : m_file(path.cStr(), std::ios::app | std::ios::out) -{ - setName("FileSink:" + path); - if (!m_file.is_open()) - { - // TODO: Use a inner exception or error code instead of std::runtime_error - throw std::runtime_error(("GP FileSink: cannot open log file: " + path).cStr()); - } - - m_file << gp::String::format( - "=== GP Engine Log — opened {} ===\n", std::chrono::system_clock::now().time_since_epoch().count() - ); -} - -void FileSink::onRecord(const ErrorRecord& record) -{ - auto tt = std::chrono::system_clock::to_time_t(record.wallTime); - char buf[32] = {}; -#if defined(_MSC_VER) - struct tm tm{}; - gmtime_s(&tm, &tt); - strftime(buf, sizeof buf, "%Y-%m-%d %T", &tm); -#else - struct tm tm{}; - gmtime_r(&tt, &tm); - strftime(buf, sizeof buf, "%Y-%m-%d %T", &tm); -#endif - - std::lock_guard lock(m_mutex); - - m_file << gp::String::format( - "[{}][{}][{}:0x{:04X}] {} | {}:{}\n", - buf, - getSeverityName(record.severity), - getDomainName(record.code.domain()), - record.code.code(), - record.message, - record.location.file_name(), - record.location.line() - ); - - for (const auto& m: record.metadata) - { - m_file << gp::String::format(" meta: {}={}\n", m.key, m.value); - } - -#if GP_HAS_STACKTRACE - if (!record.stacktrace.empty()) - { - m_file << " stacktrace:\n"; - for (const auto& frame: record.stacktrace) - { - m_file << gp::String::format(" {}\n", std::to_string(frame)); - } - } -#endif -} - -void FileSink::flush() -{ - std::lock_guard lock(m_mutex); - m_file.flush(); -} - -} // namespace gp::error diff --git a/source/runtime/core/private/errors/sinks/MultiSink.cpp b/source/runtime/core/private/errors/sinks/MultiSink.cpp deleted file mode 100644 index e661c42..0000000 --- a/source/runtime/core/private/errors/sinks/MultiSink.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "errors/sinks/MultiSink.hpp" - -namespace gp::error -{ - -MultiSink::MultiSink() -{ - setName("MultiSink"); -} - -void MultiSink::addSink(std::shared_ptr sink) -{ - if (!sink) - { - return; - } - - std::lock_guard lock(m_mutex); - m_sinks.pushBack(std::move(sink)); -} - -void MultiSink::removeSink(const gp::String& name) -{ - std::lock_guard lock(m_mutex); - gp::eraseIf( - m_sinks, - [&](const auto& sink) - { - return sink->name() == name; - } - ); -} - -GP_NODISCARD gp::USize MultiSink::sinkCount() const noexcept -{ - std::lock_guard lock(m_mutex); - return m_sinks.size(); -} - -void MultiSink::onRecord(const ErrorRecord& record) -{ - decltype(m_sinks) sinks; - { - std::lock_guard lock(m_mutex); - sinks = m_sinks; - } - - for (auto& sink: sinks) - { - sink->dispatch(record); - } -} - -void MultiSink::flush() -{ - decltype(m_sinks) sinks; - { - std::lock_guard lock(m_mutex); - sinks = m_sinks; - } - - for (auto& sink: sinks) - { - sink->flush(); - } -} - -} // namespace gp::error diff --git a/source/runtime/core/private/memory/backends/Malloc.cpp b/source/runtime/core/private/memory/backends/Malloc.cpp index 4c3df88..acc45d5 100644 --- a/source/runtime/core/private/memory/backends/Malloc.cpp +++ b/source/runtime/core/private/memory/backends/Malloc.cpp @@ -3,82 +3,49 @@ // mailto:support AT graphical-playground DOT com #include "memory/backends/Malloc.hpp" -#include "platform/PlatformMemory.hpp" +#include "platforms/base/PlatformMemory.hpp" namespace gp::memory { -void* Malloc::tryMalloc(gp::USize size, gp::UInt32 alignment) +void* Malloc::tryAllocate(USize size, UInt32 alignment) noexcept { - return this->malloc(size, alignment); + return allocate(size, alignment); } -void* Malloc::tryRealloc(void* ptr, gp::USize newSize, gp::UInt32 alignment) +void* Malloc::allocateZeroed(USize size, UInt32 alignment) { - return this->realloc(ptr, newSize, alignment); -} - -void* Malloc::mallocZeroed(gp::USize size, gp::UInt32 alignment) -{ - void* memory = this->malloc(size, alignment); - - if (memory) + void* const ptr = allocate(size, alignment); + if (ptr) { - PlatformMemory::zeroMemory(memory, size); + platform::Memory::zeroMemory(ptr, size); } - - return memory; + return ptr; } -void* Malloc::tryMallocZeroed(gp::USize size, gp::UInt32 alignment) +void* Malloc::tryAllocateZeroed(USize size, UInt32 alignment) noexcept { - return this->mallocZeroed(size, alignment); -} - -gp::USize Malloc::adjustSize(gp::USize size, gp::UInt32 /* alignment */) const -{ - return size; // Default implementation has no way of determining this. -} - -bool Malloc::getAllocationSize(void* /* ptr */, gp::USize& /* outSize */) const -{ - return false; // Default implementation has no way of determining this. -} - -void Malloc::trim() -{ - // Default implementation does not manage its own memory pool, so there is nothing to trim. -} - -void Malloc::updateStatistics() -{ - // TODO: Implement this function to update the allocator's statistics. + void* const ptr = tryAllocate(size, alignment); + if (ptr) + { + platform::Memory::zeroMemory(ptr, size); + } + return ptr; } -MemoryStatistics Malloc::getAllocatorStatistics() const +void* Malloc::tryReallocate(void* ptr, USize newSize, UInt32 alignment) noexcept { - // TODO: Implement this function to return the allocator's statistics. - return {}; + return reallocate(ptr, newSize, alignment); } -void Malloc::getAllocatorStatistics(MemoryStatistics& /* outStats */) const +USize Malloc::getAllocationSize(void* /* ptr */) { - // TODO: Implement this function to fill in outStats with the allocator's statistics. + return 0; } -bool Malloc::isInternallyThreadSafe() const +bool Malloc::canGetAllocationSize() { return false; } -bool Malloc::validateHeap() const -{ - return true; -} - -const char* Malloc::getDisplayName() const -{ - return "Unspecified Malloc"; -} - } // namespace gp::memory diff --git a/source/runtime/core/private/memory/backends/MallocAnsi.cpp b/source/runtime/core/private/memory/backends/MallocAnsi.cpp index 9a86518..72b1c0d 100644 --- a/source/runtime/core/private/memory/backends/MallocAnsi.cpp +++ b/source/runtime/core/private/memory/backends/MallocAnsi.cpp @@ -3,214 +3,200 @@ // mailto:support AT graphical-playground DOT com #include "memory/backends/MallocAnsi.hpp" -#include "CoreMinimal.hpp" -#include "math/LinearAlgebra.hpp" -#include "memory/MemoryUtilities.hpp" // IWYU pragma: keep -#include "platform/PlatformMemory.hpp" #if GP_PLATFORM_USE_ANSI_POSIX_MALLOC - #include -#elif GP_PLATFORM_WINDOWS - #include "platform/windows/WindowsWrapper.hpp" + #include #endif -#if GP_PLATFORM_IOS - #include "mach/mach.h" +#if GP_PLATFORM_WINDOWS + #include // TODO: Add a wrapper around windows.h and include that instead #endif namespace gp::memory { -MallocAnsi::MallocAnsi() -{ -#if GP_PLATFORM_WINDOWS - intptr_t crtHeapHandle = _get_heap_handle(); - ULONG enableLFH = 2; - HeapSetInformation((void*)crtHeapHandle, HeapCompatibilityInformation, &enableLFH, sizeof(enableLFH)); -#endif -} - -void* MallocAnsi::malloc(gp::USize size, gp::UInt32 alignment) +namespace ansi { - void* result = this->tryMalloc(size, alignment); - - if (result == nullptr && size != 0) - { - // TODO: OnOutOfMemory(size, alignment); - } - - return result; -} -void* MallocAnsi::tryMalloc(gp::USize size, gp::UInt32 alignment) +GP_NODISCARD static void* allocate(USize size, UInt32 alignment) { - alignment = math::max(size >= 16 ? 16 : 8, alignment); - #if GP_PLATFORM_USE_ALIGNED_MALLOC - void* result = _aligned_malloc(size, alignment); + void* ptr = _aligned_malloc(size, alignment); #elif GP_PLATFORM_USE_ANSI_POSIX_MALLOC - void* result = nullptr; - if (GP_UNLIKELY(posix_memalign(&result, alignment, size) != 0)) + void* ptr = nullptr; + if (GP_UNLIKELY(posix_memalign(&ptr, alignment, size) != 0)) { - result = nullptr; + ptr = nullptr; } +#elif GP_PLATFORM_USE_ANSI_MEMALIGN + void* ptr = memalign(alignment, size); #else - void* ptr = ::malloc(size + alignment + sizeof(void*) + sizeof(gp::USize)); - void* result = nullptr; - if (ptr) + void* temp = ::malloc(size + alignment + sizeof(void*) + sizeof(USize)); + void* ptr = nullptr; + if (GP_LIKELY(temp)) { - result = alignT((gp::UInt8*)ptr + sizeof(void*) + sizeof(gp::USize), alignment); - *((void**)((gp::UInt8*)result - sizeof(void*))) = ptr; - *((gp::USize*)((gp::UInt8*)result - sizeof(void*) - sizeof(gp::USize))) = size; + ptr = memory::align((UInt8*)temp + sizeof(void*) + sizeof(USize), alignment); + *((void**)((UInt8*)ptr - sizeof(void*))) = temp; + *((USize*)((UInt8*)ptr - sizeof(void*) - sizeof(USize))) = size; } #endif - // TODO: Add memory trace (alloc). - - return result; + return ptr; } -void* MallocAnsi::realloc(void* ptr, gp::USize newSize, gp::UInt32 alignment) +GP_NODISCARD GP_MAYBE_UNUSED static USize getAllocationSize(void* ptr) { - void* result = this->tryRealloc(ptr, newSize, alignment); +#if GP_PLATFORM_USE_ALIGNED_MALLOC + // TODO: We assume that the alignment is always 16, but this may not be the case. + return _aligned_msize(ptr, 16, 0); +#elif GP_PLATFORM_USE_ANSI_POSIX_MALLOC || GP_PLATFORM_USE_ANSI_MEMALIGN + return malloc_usable_size(ptr); +#else + return *((USize*)((UInt8*)ptr - sizeof(void*) - sizeof(USize))); +#endif +} - if (result == nullptr && newSize != 0) +static void deallocate(void* ptr) +{ +#if GP_PLATFORM_USE_ALIGNED_MALLOC + _aligned_free(ptr); +#elif GP_PLATFORM_USE_ANSI_POSIX_MALLOC || GP_PLATFORM_USE_ANSI_MEMALIGN + ::free(ptr); +#else + if (ptr) { - // TODO: OnOutOfMemory(newSize, alignment); + ::free(*((void**)((UInt8*)ptr - sizeof(void*)))); } - - return result; +#endif } -void* MallocAnsi::tryRealloc(void* ptr, gp::USize newSize, gp::UInt32 alignment) +GP_NODISCARD static void* reallocate(void* ptr, USize newSize, UInt32 alignment) { - void* result = nullptr; - - alignment = math::max(newSize >= 16 ? 16 : 8, alignment); + void* newPtr = nullptr; #if GP_PLATFORM_USE_ALIGNED_MALLOC - // TODO: Add memory trace (realloc free) - if (ptr && newSize) + if (ptr && newSize != 0) { - result = _aligned_realloc(ptr, newSize, alignment); + newPtr = _aligned_realloc(ptr, newSize, alignment); } else if (ptr == nullptr) { - result = _aligned_malloc(newSize, alignment); + newPtr = _aligned_malloc(newSize, alignment); } - else + else /* newSize == 0 */ { _aligned_free(ptr); - result = nullptr; + newPtr = nullptr; } - // TODO: Add memory trace (realloc alloc) #elif GP_PLATFORM_USE_ANSI_POSIX_MALLOC - // TODO: Add memory trace (realloc free) - if (ptr && newSize) + if (ptr && newSize != 0) { - gp::USize usableSize = malloc_usable_size(ptr); - if (GP_UNLIKELY(posix_memalign(&result, alignment, newSize) != 0)) + GP_MAYBE_UNUSED USize usableSize = malloc_usable_size(ptr); + if (GP_UNLIKELY(posix_memalign(&newPtr, alignment, newSize) != 0)) { - result = nullptr; + newPtr = nullptr; } - else if (GP_LIKELY(usableSize)) + else if (GP_LIKELY(newPtr)) { - PlatformMemory::copyMemory(result, ptr, math::min(newSize, usableSize)); + // Memory::copyMemory(newPtr, ptr, math::min(newSize, usableSize)); } - free(ptr); + ::free(ptr); } else if (ptr == nullptr) { - if (GP_UNLIKELY(posix_memalign(&result, alignment, newSize) != 0)) + if (GP_UNLIKELY(posix_memalign(&newPtr, alignment, newSize) != 0)) { - result = nullptr; + newPtr = nullptr; } } - else + else /* newSize == 0 */ { ::free(ptr); - result = nullptr; + newPtr = nullptr; } - // TODO: Add memory trace (realloc alloc) +#elif GP_PLATFORM_USE_ANSI_MEMALIGN + newPtr = reallocalign(ptr, newSize, alignment); #else - if (ptr && newSize) + if (ptr && newSize != 0) { - // Can't use realloc as it might screw with alignment. - result = this->malloc(newSize, alignment); - gp::USize ptrSize = 0; - this->getAllocationSize(ptr, ptrSize); - PlatformMemory::copyMemory(result, ptr, math::min(newSize, ptrSize)); - this->free(ptr); + newPtr = ansi::allocate(newSize, alignment); + USize oldSize = getAllocationSize(ptr); + // Memory::copyMemory(newPtr, ptr, math::min(newSize, oldSize)); + ansi::deallocate(ptr); } else if (ptr == nullptr) { - result = this->malloc(newSize, alignment); + newPtr = ansi::allocate(newSize, alignment); } - else + else /* newSize == 0 */ { - // TODO: Add memory trace (free) - ::free(*((void**)((gp::UInt8*)ptr - sizeof(void*)))); - result = nullptr; + ansi::deallocate(ptr); + newPtr = nullptr; } #endif - return result; + return newPtr; } -void MallocAnsi::free(void* ptr) +} // namespace ansi + +void* MallocAnsi::allocate(USize size, UInt32 alignment) { - // TODO: Add memory trace (free) -#if GP_PLATFORM_USE_ALIGNED_MALLOC - _aligned_free(ptr); -#elif GP_PLATFORM_USE_ANSI_POSIX_MALLOC - ::free(ptr); -#else - if (ptr) + void* ptr = tryAllocate(size, alignment); + if (ptr == nullptr && size != 0) { - ::free(*((void**)((gp::UInt8*)ptr - sizeof(void*)))); + // TODO: Raise out of memory error } -#endif + return ptr; +} + +void* MallocAnsi::tryAllocate(USize size, UInt32 alignment) noexcept +{ + // alignment = math::max(size >= 16 ? 16 : 8, alignment); + void* ptr = ansi::allocate(size, alignment); + return ptr; } -bool MallocAnsi::getAllocationSize(void* ptr, GP_MAYBE_UNUSED gp::USize& outSize) const +void* MallocAnsi::reallocate(void* ptr, USize newSize, UInt32 alignment) { - if (!ptr) + void* newPtr = tryReallocate(ptr, newSize, alignment); + if (newPtr == nullptr && newSize != 0) { - return false; + // TODO: Raise out of memory error } + return newPtr; +} -#if GP_PLATFORM_USE_ALIGNED_MALLOC - return false; -#elif GP_PLATFORM_USE_ANSI_POSIX_MALLOC - outSize = malloc_usable_size(ptr); -#else - outSize = *(reinterpret_cast(reinterpret_cast(ptr) - sizeof(void*) - sizeof(gp::USize))); -#endif - return true; +void* MallocAnsi::tryReallocate(void* ptr, USize newSize, UInt32 alignment) noexcept +{ + // alignment = math::max(size >= 16 ? 16 : 8, alignment); + void* newPtr = ansi::reallocate(ptr, newSize, alignment); + return newPtr; } -bool MallocAnsi::isInternallyThreadSafe() const +void MallocAnsi::deallocate(void* ptr) { -#if GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE - return true; -#else - return false; -#endif + ansi::deallocate(ptr); } -bool MallocAnsi::validateHeap() const +USize MallocAnsi::getAllocationSize(void* ptr) { -#if GP_PLATFORM_WINDOWS // TODO: Maybe add GP_BUILD_DEBUG here as well? - gp::Int32 result = _heapchk(); - GP_ASSERT(result == _HEAPBADBEGIN, "Heap corruption detected: _HEAPBADBEGIN"); - GP_ASSERT(result == _HEAPBADNODE, "Heap corruption detected: _HEAPBADNODE"); - GP_ASSERT(result == _HEAPBADPTR, "Heap corruption detected: _HEAPBADPTR"); - GP_ASSERT(result == _HEAPEMPTY, "Heap corruption detected: _HEAPEMPTY"); - GP_ASSERT(result != _HEAPOK, "Heap corruption detected: _HEAPOK"); + if (ptr == nullptr) + { + return 0; + } + +#if GP_PLATFORM_USE_ALIGNED_MALLOC + return 0; +#else + return ansi::getAllocationSize(ptr); #endif - return true; } -const char* MallocAnsi::getDisplayName() const +bool MallocAnsi::canGetAllocationSize() { - return "ANSI Malloc"; +#if GP_PLATFORM_USE_ALIGNED_MALLOC + return false; +#else + return true; +#endif } } // namespace gp::memory diff --git a/source/runtime/core/private/memory/backends/MallocBinned64.cpp b/source/runtime/core/private/memory/backends/MallocBinned64.cpp deleted file mode 100644 index 42fafb6..0000000 --- a/source/runtime/core/private/memory/backends/MallocBinned64.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/backends/MallocBinned64.hpp" diff --git a/source/runtime/core/private/memory/backends/MallocJeMalloc.cpp b/source/runtime/core/private/memory/backends/MallocJeMalloc.cpp deleted file mode 100644 index e8980d4..0000000 --- a/source/runtime/core/private/memory/backends/MallocJeMalloc.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/backends/MallocJeMalloc.hpp" diff --git a/source/runtime/core/private/memory/backends/MallocMiMalloc.cpp b/source/runtime/core/private/memory/backends/MallocMiMalloc.cpp deleted file mode 100644 index 1454715..0000000 --- a/source/runtime/core/private/memory/backends/MallocMiMalloc.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/backends/MallocMiMalloc.hpp" diff --git a/source/runtime/core/private/memory/backends/SystemMallocObject.cpp b/source/runtime/core/private/memory/backends/SystemMallocObject.cpp deleted file mode 100644 index 3e2c2e6..0000000 --- a/source/runtime/core/private/memory/backends/SystemMallocObject.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/backends/SystemMallocObject.hpp" - -namespace gp::memory -{} // namespace gp::memory diff --git a/source/runtime/core/private/platform/apple/ApplePlatformMemory.cpp b/source/runtime/core/private/platform/apple/ApplePlatformMemory.cpp deleted file mode 100644 index e0aa4d6..0000000 --- a/source/runtime/core/private/platform/apple/ApplePlatformMemory.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "platform/apple/AppleMemoryPlatform.hpp" diff --git a/source/runtime/core/private/platform/generic/GenericPlatformMemory.cpp b/source/runtime/core/private/platform/generic/GenericPlatformMemory.cpp deleted file mode 100644 index 4d7c477..0000000 --- a/source/runtime/core/private/platform/generic/GenericPlatformMemory.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "platform/generic/GenericMemoryPlatform.hpp" diff --git a/source/runtime/core/private/platform/linux/LinuxPlatformMemory.cpp b/source/runtime/core/private/platform/linux/LinuxPlatformMemory.cpp deleted file mode 100644 index c42e400..0000000 --- a/source/runtime/core/private/platform/linux/LinuxPlatformMemory.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "platform/linux/LinuxMemoryPlatform.hpp" diff --git a/source/runtime/core/private/platform/windows/WindowsPlatformMemory.cpp b/source/runtime/core/private/platform/windows/WindowsPlatformMemory.cpp deleted file mode 100644 index 69738c2..0000000 --- a/source/runtime/core/private/platform/windows/WindowsPlatformMemory.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "platform/windows/WindowsMemoryPlatform.hpp" diff --git a/source/runtime/core/private/platform/windows/WindowsWrapper.hpp b/source/runtime/core/private/platform/windows/WindowsWrapper.hpp deleted file mode 100644 index 9b29c7d..0000000 --- a/source/runtime/core/private/platform/windows/WindowsWrapper.hpp +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "CoreMinimal.hpp" - -#if defined(WINDOWS_H_WRAPPER_GUARD) - #error "[GP] Windows.h has already been included." -#endif -#define WINDOWS_H_WRAPPER_GUARD - -#if GP_COMPILER_CLANG - #pragma warning(disable : 4103) -#endif - -#if GP_COMPILER_CLANG - #if GP_ARCHITECTURE_32BIT -_Pragma("pack(push)") _Pragma("pack(8)") - #elif GP_ARCHITECTURE_64BIT -_Pragma("pack(push)") _Pragma("pack(16)") - #endif -#else - #if GP_ARCHITECTURE_32BIT -__pragma(pack(push, 8)) - #elif GP_ARCHITECTURE_64BIT -__pragma(pack(push, 16)) - #endif -#endif - -// Save these macros for later, Windows redefines them -#pragma push_macro("MAX_uint8") -#pragma push_macro("MAX_uint16") -#pragma push_macro("MAX_uint32") -#pragma push_macro("MAX_int32") -#pragma push_macro("TEXT") -#pragma push_macro("TRUE") -#pragma push_macro("FALSE") - -#ifndef STRICT - #define STRICT -#endif - -#if defined(_WINDOWS_) && !defined(GP_MINIMAL_WINDOWS_INCLUDE) - #pragma message(" ") - #pragma message("You have included windows.h before MinWindows.h") - #pragma message("All useless stuff from the windows headers won't be excluded !!!") - #pragma message(" ") -#endif -#define GP_MINIMAL_WINDOWS_INCLUDE - -// WIN32_LEAN_AND_MEAN excludes rarely-used services from windows headers. -#define WIN32_LEAN_AND_MEAN - -// The below excludes some other unused services from the windows headers, see windows.h for details. -// clang-format off -#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_ -// #define NOVIRTUALKEYCODES // VK_* -// #define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_* -// #define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* -// #define NOSYSMETRICS // SM_* -// #define NOMENUS // MF_* -// #define NOICONS // IDI_* -// #define NOKEYSTATES // MK_* -// #define NOSYSCOMMANDS // SC_* -// #define NORASTEROPS // Binary and Tertiary raster ops -// #define NOSHOWWINDOW // SW_* -#define OEMRESOURCE // OEM Resource values -#define NOATOM // Atom Manager routines -// #define NOCLIPBOARD // Clipboard routines -// #define NOCOLOR // Screen colors -// #define NOCTLMGR // Control and Dialog routines -// #define NODRAWTEXT // DrawText() and DT_* -// #define NOGDI // All GDI #defines and routines -#define NOKERNEL // All KERNEL #defines and routines -// #define NOUSER // All USER #defines and routines -// #define NONLS // All NLS #defines and routines -// #define NOMB // MB_* and MessageBox() -#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines -#define NOMETAFILE // typedef METAFILEPICT -#define NOMINMAX // Macros min(a,b) and max(a,b) -// #define NOMSG // typedef MSG and associated routines -#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_* -#define NOSCROLL // SB_* and scrolling routines -#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. -#define NOSOUND // Sound driver routines -// #define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines -// #define NOWH // SetWindowsHook and WH_* -// #define NOWINOFFSETS // GWL_*, GCL_*, associated routines -#define NOCOMM // COMM driver routines -#define NOKANJI // Kanji support stuff. -#define NOHELP // Help engine interface. -#define NOPROFILER // Profiler interface. -#define NODEFERWINDOWPOS // DeferWindowPos routines -#define NOMCX // Modem Configuration Extensions -#define NOCRYPT -#define NOTAPE -#define NOIMAGE -#define NOPROXYSTUB -#define NORPC -// clang-format on - -// Finally include the Windows headers -#include - -// Hide Windows-only types (same as HideWindowsPlatformTypes.h) -#undef INT -#undef UINT -#undef DWORD -#undef FLOAT - -// Undo any Windows defines. -#undef uint8 -#undef uint16 -#undef uint32 -#undef int32 -#undef float -#undef CDECL -#undef PF_MAX -#undef CaptureStackBackTrace -#undef CopyFile -#undef CreateDesktop -#undef CreateDirectory -#undef CreateFont -#undef DeleteFile -#undef DrawText -#undef FindWindow -#undef GetClassInfo -#undef GetClassName -#undef GetCommandLine -#undef GetCurrentTime -#undef GetEnvironmentVariable -#undef GetFileAttributes -#undef GetFreeSpace -#undef GetMessage -#undef GetNextSibling -#undef GetObject -#undef GetProp -#undef GetTempFileName -#undef IMediaEventSink -#undef IsMaximized -#undef IsMinimized -#undef LoadString -#undef MemoryBarrier -#undef MoveFile -#undef PlaySound -#undef PostMessage -#undef ReportEvent -#undef SendMessage -#undef SetPort -#undef SetProp -#undef UpdateResource -#undef Yield - -// Restore any previously defined macros -#pragma pop_macro("MAX_uint8") -#pragma pop_macro("MAX_uint16") -#pragma pop_macro("MAX_uint32") -#pragma pop_macro("MAX_int32") -#pragma pop_macro("TEXT") -#pragma pop_macro("TRUE") -#pragma pop_macro("FALSE") - -#if GP_COMPILER_CLANG - _Pragma("pack(pop)") -#else - __pragma(pack(pop)) -#endif - -#undef WINDOWS_H_WRAPPER_GUARD diff --git a/source/runtime/core/public/CoreDefines.hpp b/source/runtime/core/public/CoreDefines.hpp deleted file mode 100644 index db83c95..0000000 --- a/source/runtime/core/public/CoreDefines.hpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "macros/DetectArchitecture.hpp" // IWYU pragma: export -#include "macros/DetectBuild.hpp" // IWYU pragma: export -#include "macros/DetectCompiler.hpp" // IWYU pragma: export -#include "macros/DetectConfig.hpp" // IWYU pragma: export -#include "macros/DetectPlatform.hpp" // IWYU pragma: export -#include "macros/DetectSimd.hpp" // IWYU pragma: export -#include "macros/MacroUtilities.hpp" // IWYU pragma: export - -// Enable Tracy profiling in Debug and RelWithDebInfo builds when profiling is enabled -#if (GP_CONFIG_DEBUG || GP_CONFIG_RELWITHDEBINFO) && GP_ENABLE_PROFILING - #ifndef TRACY_ENABLE - #define TRACY_ENABLE 1 - #endif -#endif diff --git a/source/runtime/core/public/CoreForward.hpp b/source/runtime/core/public/CoreForward.hpp deleted file mode 100644 index 2ea1e84..0000000 --- a/source/runtime/core/public/CoreForward.hpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -// Include CoreMinimal -#include "CoreMinimal.hpp" // IWYU pragma: keep - -// Forward declarations -#include "container/Forward.hpp" // IWYU pragma: export -#include "crypto/Forward.hpp" // IWYU pragma: export -#include "errors/Forward.hpp" // IWYU pragma: export -#include "math/Forward.hpp" // IWYU pragma: export -#include "memory/MemoryForward.hpp" // IWYU pragma: export -#include "utils/Forward.hpp" // IWYU pragma: export diff --git a/source/runtime/core/public/CoreMinimal.hpp b/source/runtime/core/public/CoreMinimal.hpp index 95a6914..d0405fc 100644 --- a/source/runtime/core/public/CoreMinimal.hpp +++ b/source/runtime/core/public/CoreMinimal.hpp @@ -4,94 +4,15 @@ #pragma once -#include "CoreDefines.hpp" // IWYU pragma: export -#include -#include -#include -#include // IWYU pragma: keep +#include "miscellaneous/BuildDefines.hpp" // IWYU pragma: export +#include "platforms/base/Platform.hpp" // IWYU pragma: export -namespace gp -{ - -/// @section Integer types with fixed widths. -/// @see https://en.cppreference.com/w/cpp/types/integer - -/// @brief 8-bit unsigned integer type. -/// limits: [0, 255] -using UInt8 = std::uint8_t; - -/// @brief 16-bit unsigned integer type. -/// limits: [0, 65535] -using UInt16 = std::uint16_t; - -/// @brief 32-bit unsigned integer type. -/// limits: [0, 4294967295] -using UInt32 = std::uint32_t; - -/// @brief 64-bit unsigned integer type. -/// limits: [0, 18446744073709551615] -using UInt64 = std::uint64_t; - -/// @brief 8-bit signed integer type. -/// limits: [-128, 127] -using Int8 = std::int8_t; - -/// @brief 16-bit signed integer type. -/// limits: [-32768, 32767] -using Int16 = std::int16_t; - -/// @brief 32-bit signed integer type. -/// limits: [-2147483648, 2147483647] -using Int32 = std::int32_t; - -/// @brief 64-bit signed integer type. -/// limits: [-9223372036854775808, 9223372036854775807] -using Int64 = std::int64_t; - -/// @section Floating-point types with fixed widths. - -/// @brief 32-bit floating-point type (single precision). -/// Approximate limits: [1.18e-38, 3.4e+38] -using Float32 = float; - -/// @brief 64-bit floating-point type (double precision). -/// Approximate limits: [2.22e-308, 1.8e+308] -using Float64 = double; - -/// @section Size and pointer difference types. - -using USize = std::size_t; -using ISize = std::ptrdiff_t; -using UIntPtr = std::uintptr_t; -using IntPtr = std::intptr_t; -using PtrDiff = std::ptrdiff_t; - -/// @section Character types. - -using Char8 = char8_t; -using Char16 = char16_t; -using Char32 = char32_t; -using Char = char; -using WChar = wchar_t; - -/// @section Types related to alignment. - -using MaxAlign = std::max_align_t; -using AlignVal = std::align_val_t; - -/// @section Special values. - -// use std::byte after C++17 -#if GP_INTERNAL_CXX17 -using Byte = std::byte; +#if GP_IS_MONOLITHIC + #define GP_CORE_API #else -/// @brief A type representing a byte of data. Not an arithmetic type. -enum class Byte = gp::UInt8{}; + #ifdef GP_CORE_EXPORTS + #define GP_CORE_API GP_DLLEXPORT + #else + #define GP_CORE_API GP_DLLIMPORT + #endif #endif - -using NullPtr = std::nullptr_t; - -/// @brief A special value that can be used to indicate a dynamic extent in template parameters. -inline constexpr USize DynamicExtent = static_cast(-1); - -} // namespace gp diff --git a/source/runtime/core/public/compilers/clang/ClangCompiler.hpp b/source/runtime/core/public/compilers/clang/ClangCompiler.hpp new file mode 100644 index 0000000..d216a51 --- /dev/null +++ b/source/runtime/core/public/compilers/clang/ClangCompiler.hpp @@ -0,0 +1,23 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#define GP_PLATFORM_RETURN_ADDRESS() __builtin_return_address(0) +#define GP_PLATFORM_RETURN_ADDRESS_POINTER() __builtin_frame_address(0) + +#define GP_LIFETIMEBOUND [[clang::lifetimebound]] + +#define GP_NODEBUG [[gnu::nodebug]] + +#define GP_ALLOCATION_FUNCTION_0() [[gnu::malloc]] +#define GP_ALLOCATION_FUNCTION_1(size) [[gnu::malloc, gnu::alloc_size(size)]] + +#define GP_ALLOCATION_FUNCTION_2(size, align) [[gnu::malloc, gnu::alloc_size(size)]] +#define GP_ALLOCATION_FUNCTION_X(x, size, align, func, ...) func +#define GP_ALLOCATION_FUNCTION(...) GP_ALLOCATION_FUNCTION_X(,##__VA_ARGS__, GP_ALLOCATION_FUNCTION_2(__VA_ARGS__), GP_ALLOCATION_FUNCTION_1(__VA_ARGS__), GP_ALLOCATION_FUNCTION_0(__VA_ARGS__)) + +#define GP_FUNCTION_NON_NULL_RETURN_START [[gnu::returns_nonnull]] + +#define GP_CALLSITE_FORCEINLINE [[clang::always_inline]] diff --git a/source/runtime/core/public/crypto/Forward.hpp b/source/runtime/core/public/compilers/gcc/GCCCompiler.hpp similarity index 100% rename from source/runtime/core/public/crypto/Forward.hpp rename to source/runtime/core/public/compilers/gcc/GCCCompiler.hpp diff --git a/source/runtime/core/public/compilers/intel/IntelCompiler.hpp b/source/runtime/core/public/compilers/intel/IntelCompiler.hpp new file mode 100644 index 0000000..634e07c --- /dev/null +++ b/source/runtime/core/public/compilers/intel/IntelCompiler.hpp @@ -0,0 +1,21 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#define GP_PLATFORM_RETURN_ADDRESS() __builtin_return_address(0) +#define GP_PLATFORM_RETURN_ADDRESS_POINTER() __builtin_frame_address(0) + +#define GP_LIFETIMEBOUND [[clang::lifetimebound]] + +#define GP_NODEBUG [[gnu::nodebug]] + +#define GP_ALLOCATION_FUNCTION_0() [[gnu::malloc]] +#define GP_ALLOCATION_FUNCTION_1(size) [[gnu::malloc, gnu::alloc_size(size)]] + +#define GP_ALLOCATION_FUNCTION_2(size, align) [[gnu::malloc, gnu::alloc_size(size)]] +#define GP_ALLOCATION_FUNCTION_X(x, size, align, func, ...) func +#define GP_ALLOCATION_FUNCTION(...) GP_ALLOCATION_FUNCTION_X(,##__VA_ARGS__, GP_ALLOCATION_FUNCTION_2(__VA_ARGS__), GP_ALLOCATION_FUNCTION_1(__VA_ARGS__), GP_ALLOCATION_FUNCTION_0(__VA_ARGS__)) + +#define GP_FUNCTION_NON_NULL_RETURN_START [[gnu::returns_nonnull]] diff --git a/source/runtime/core/public/compilers/msvc/MSVCCompiler.hpp b/source/runtime/core/public/compilers/msvc/MSVCCompiler.hpp new file mode 100644 index 0000000..f98ae83 --- /dev/null +++ b/source/runtime/core/public/compilers/msvc/MSVCCompiler.hpp @@ -0,0 +1,14 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#define GP_PLATFORM_RETURN_ADDRESS() _ReturnAddress() +#define GP_PLATFORM_RETURN_ADDRESS_POINTER() _AddressOfReturnAddress() + +#ifdef __has_cpp_attribute + #if __has_cpp_attribute(msvc::lifetimebound) + #define GP_LIFETIMEBOUND [[msvc::lifetimebound]] + #endif +#endif diff --git a/source/runtime/core/public/concepts/Concepts.hpp b/source/runtime/core/public/concepts/Concepts.hpp new file mode 100644 index 0000000..c8a86c7 --- /dev/null +++ b/source/runtime/core/public/concepts/Concepts.hpp @@ -0,0 +1,13 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "concepts/Construction.hpp" // IWYU pragma: export +#include "concepts/Container.hpp" // IWYU pragma: export +#include "concepts/Functional.hpp" // IWYU pragma: export +#include "concepts/Fundamental.hpp" // IWYU pragma: export +#include "concepts/Math.hpp" // IWYU pragma: export +#include "concepts/Memory.hpp" // IWYU pragma: export +#include "concepts/Relationship.hpp" // IWYU pragma: export diff --git a/source/runtime/core/public/concepts/Construction.hpp b/source/runtime/core/public/concepts/Construction.hpp new file mode 100644 index 0000000..706111b --- /dev/null +++ b/source/runtime/core/public/concepts/Construction.hpp @@ -0,0 +1,33 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include + +namespace gp::concepts +{ + +/// @brief Concept to check if a type can be default constructed. +template +concept IsDefaultConstructible = std::default_initializable; + +/// @brief Concept to check if a type can be copy constructed. +template +concept IsCopyConstructible = std::copy_constructible; + +/// @brief Concept to check if a type can be move constructed. +template +concept IsMoveConstructible = std::move_constructible; + +/// @brief Concept to check if a type can be copy assigned. +template +concept IsCopyAssignable = std::assignable_from; + +/// @brief Concept to check if a type can be move assigned. +template +concept IsMoveAssignable = std::assignable_from; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/concepts/Container.hpp b/source/runtime/core/public/concepts/Container.hpp new file mode 100644 index 0000000..89285d3 --- /dev/null +++ b/source/runtime/core/public/concepts/Container.hpp @@ -0,0 +1,25 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include + +namespace gp::concepts +{ + +/// @brief Concept to check if a type provides iterators for ranged-based loops. +template +concept IsIterable = std::ranges::range; + +/// @brief Concept to check if an iterable type guarantees contiguous memory layout. +template +concept IsContiguousRange = std::ranges::contiguous_range; + +/// @brief Concept to check if an iterable type knows its size in constant time. +template +concept IsSizedRange = std::ranges::sized_range; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/concepts/Functional.hpp b/source/runtime/core/public/concepts/Functional.hpp new file mode 100644 index 0000000..39962dc --- /dev/null +++ b/source/runtime/core/public/concepts/Functional.hpp @@ -0,0 +1,21 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include + +namespace gp::concepts +{ + +/// @brief Concept to check if a callable type can be invoked with specific arguments. +template +concept IsInvocable = std::invocable; + +/// @brief Concept to check if a callable returns a boolean when invoked. +template +concept IsPredicate = std::predicate; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/concepts/Fundamental.hpp b/source/runtime/core/public/concepts/Fundamental.hpp new file mode 100644 index 0000000..4cadfd3 --- /dev/null +++ b/source/runtime/core/public/concepts/Fundamental.hpp @@ -0,0 +1,37 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include + +namespace gp::concepts +{ + +/// @brief Concept to check if a type is a floating-point type. +template +concept IsFloatingPoint = std::is_floating_point_v; + +/// @brief Concept to check if a type is an integral type. +template +concept IsIntegral = std::is_integral_v; + +/// @brief Concept to check if a type is an arithmetic type. +template +concept IsArithmetic = std::is_arithmetic_v; + +/// @brief Concept to check if a type is a pointer type. +template +concept IsPointer = std::is_pointer_v; + +/// @brief Concept to check if a type is an enumeration. +template +concept IsEnum = std::is_enum_v; + +/// @brief Concept to check if a type is a class or struct. +template +concept IsClass = std::is_class_v; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/concepts/Math.hpp b/source/runtime/core/public/concepts/Math.hpp new file mode 100644 index 0000000..75c9080 --- /dev/null +++ b/source/runtime/core/public/concepts/Math.hpp @@ -0,0 +1,20 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "concepts/Fundamental.hpp" + +namespace gp::concepts +{ + +/// @brief Concept to check if an arithmetic type is signed. +template +concept IsSigned = IsArithmetic && std::is_signed_v; + +/// @brief Concept to check if an arithmetic type is unsigned. +template +concept IsUnsigned = IsArithmetic && std::is_unsigned_v; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/concepts/Memory.hpp b/source/runtime/core/public/concepts/Memory.hpp new file mode 100644 index 0000000..8815d71 --- /dev/null +++ b/source/runtime/core/public/concepts/Memory.hpp @@ -0,0 +1,33 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include + +namespace gp::concepts +{ + +/// @brief Concept to check if a type is trivially copyable. +template +concept IsTriviallyCopyable = std::is_trivially_copyable_v; + +/// @brief Concept to check if a type is trivially destructible. +template +concept IsTriviallyDestructible = std::is_trivially_destructible_v; + +/// @brief Concept to check if a type is trivially default constructible. +template +concept IsTriviallyConstructible = std::is_trivially_default_constructible_v; + +/// @brief Concept to check if a type has a standard layout. +template +concept IsStandardLayout = std::is_standard_layout_v; + +/// @brief Concept to check if a type is Plain Old Data (POD). +template +concept IsPod = IsStandardLayout && std::is_trivial_v; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/concepts/Relationship.hpp b/source/runtime/core/public/concepts/Relationship.hpp new file mode 100644 index 0000000..84a3f45 --- /dev/null +++ b/source/runtime/core/public/concepts/Relationship.hpp @@ -0,0 +1,25 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include + +namespace gp::concepts +{ + +/// @brief Concept to check if two types are exactly the same. +template +concept IsSameAs = std::same_as; + +/// @brief Concept to check if type Derived inherits from type Base. +template +concept IsDerivedFrom = std::derived_from; + +/// @brief Concept to check if type From is implicitly convertible to type To. +template +concept IsConvertibleTo = std::convertible_to; + +} // namespace gp::concepts diff --git a/source/runtime/core/public/container/Array.hpp b/source/runtime/core/public/container/Array.hpp deleted file mode 100644 index e9b7d8f..0000000 --- a/source/runtime/core/public/container/Array.hpp +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "macros/MacroUtilities.hpp" -#include -#include // IWYU pragma: keep -#include -#include -#include -#include -#include - -namespace gp -{ - -/// @brief Fixed-size array with stack allocation and constexpr support. -/// @details -/// Provides a simple wrapper around a C-style array with added functionality and safety checks. The size of the array -/// is fixed at compile time, and all elements are stored contiguously on the stack. The class supports aggregate -/// initialization, range-based for loops, and standard container interfaces for interoperability with . -/// Boundary checks are performed in debug builds, but not in release builds. Accessing out-of-bounds indices results in -/// undefined behavior. -template -class Array -{ - static_assert(!std::is_reference_v, "Array elements cannot be references"); - static_assert(std::is_destructible_v, "Array elements must be destructible"); - static_assert( - std::is_trivially_copyable_v || std::is_nothrow_constructible_v, - "Array elements must be trivially copyable or nothrow move constructible" - ); - -public: - using ValueType = T; - using SizeType = gp::USize; - using DifferenceType = gp::ISize; - using Reference = ValueType&; - using ConstReference = const ValueType&; - using Pointer = ValueType*; - using ConstPointer = const ValueType*; - using Iterator = Pointer; - using ConstIterator = ConstPointer; - using ReverseIterator = std::reverse_iterator; - using ConstReverseIterator = std::reverse_iterator; - -public: - static constexpr SizeType arraySize = N; - static constexpr SizeType byteSize = N * sizeof(T); - static constexpr SizeType npos = static_cast(-1); - -private: - // clang-format off - GP_ALIGN(T) T m_data[N > 0 ? N : 1]{}; // Ensure at least one element for zero-sized arrays - // clang-format on - -public: - /// @brief Constructs an empty Array, where all elements are value-initialized. - constexpr Array() noexcept = default; - - /// @brief Copy constructor and copy assignment operator. - constexpr Array(const Array&) noexcept = default; - constexpr Array& operator=(const Array&) noexcept = default; - - /// @brief Move constructor and move assignment operator. - constexpr Array(Array&&) noexcept = default; - constexpr Array& operator=(Array&&) noexcept = default; - - /// @brief Constructs an Array with the specified initializer list. - /// @param[in] init The initializer list to initialize the elements of the array. - constexpr Array(std::initializer_list init) noexcept - { - GP_ASSERT(init.size() <= N, "Too many initializers for Array"); - std::copy_n(init.begin(), init.size(), m_data); - } - - /// @brief Constructs an Array with the specified arguments. - /// @warning If the number of arguments is less than the size of the array, the remaining elements will be - /// value-initialized. - /// @param[in] args The arguments to initialize the elements of the array. - template - requires(sizeof...(U) > 0 && sizeof...(U) <= N && (std::is_convertible_v && ...)) - constexpr Array(U&&... args) noexcept - : m_data{ std::forward(args)... } - {} - -public: - /// @brief Accesses the element at the specified index. - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing out-of-bounds - /// indices results in undefined behavior. - /// @param[in] index The index of the element to access. - /// @return A reference to the element at the specified index. - GP_NODISCARD constexpr Reference operator[](SizeType index) noexcept - { - GP_ASSERT(index < N, "Array index out of bounds"); - return m_data[index]; - } - - /// @brief Accesses the element at the specified index (const version). - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing out-of-bounds - /// indices results in undefined behavior. - /// @param[in] index The index of the element to access. - /// @return A const reference to the element at the specified index. - GP_NODISCARD constexpr ConstReference operator[](SizeType index) const noexcept - { - GP_ASSERT(index < N, "Array index out of bounds"); - return m_data[index]; - } - - /// @brief Three-way comparison result between this array and another array. - /// Generates ==, !=, <, >, <=, >=. - /// @param[in] other The array to compare with. - /// @return A three-way comparison result indicating the relative order of the two arrays. - friend constexpr auto operator<=>(const Array&, const Array&) = default; - -public: - /// @brief Accesses the element at the specified index. - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing out-of-bounds - /// indices results in undefined behavior. - /// @param[in] index The index of the element to access. - /// @return A reference to the element at the specified index. - GP_NODISCARD constexpr Reference at(SizeType index) noexcept - { - GP_ASSERT(index < N, "Array index out of bounds"); - return m_data[index]; - } - - /// @brief Accesses the element at the specified index (const version). - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing out-of-bounds - /// indices results in undefined behavior. - /// @param[in] index The index of the element to access. - /// @return A const reference to the element at the specified index. - GP_NODISCARD constexpr ConstReference at(SizeType index) const noexcept - { - GP_ASSERT(index < N, "Array index out of bounds"); - return m_data[index]; - } - - /// @brief Returns a reference to the first element in the array. - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing the first element - /// of an empty array results in undefined behavior. - /// @return A reference to the first element in the array. - GP_NODISCARD constexpr Reference front() noexcept - { - GP_ASSERT(N > 0, "Array is empty"); - return m_data[0]; - } - - /// @brief Returns a const reference to the first element in the array. - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing the first element - /// of an empty array results in undefined behavior. - /// @return A const reference to the first element in the array. - GP_NODISCARD constexpr ConstReference front() const noexcept - { - GP_ASSERT(N > 0, "Array is empty"); - return m_data[0]; - } - - /// @brief Returns a reference to the last element in the array. - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing the last element of - /// an empty array results in undefined behavior. - /// @return A reference to the last element in the array. - GP_NODISCARD constexpr Reference back() noexcept - { - GP_ASSERT(N > 0, "Array is empty"); - return m_data[N - 1]; - } - - /// @brief Returns a const reference to the last element in the array. - /// @warning Boundary checks are performed in debug builds, but not in release builds. Accessing the last element of - /// an empty array results in undefined behavior. - /// @return A const reference to the last element in the array. - GP_NODISCARD constexpr ConstReference back() const noexcept - { - GP_ASSERT(N > 0, "Array is empty"); - return m_data[N - 1]; - } - - /// @brief Returns a pointer to the underlying array. - /// @return A pointer to the underlying array, or `nullptr` if the array is empty. - GP_NODISCARD constexpr Pointer data() noexcept - { - return N > 0 ? m_data : nullptr; - } - - /// @brief Returns a pointer to the underlying array. - /// @return A pointer to the underlying array, or `nullptr` if the array is empty. - GP_NODISCARD constexpr ConstPointer data() const noexcept - { - return N > 0 ? m_data : nullptr; - } - - /// @brief Returns the number of elements in the array. - /// @return The number of elements in the array. - GP_NODISCARD constexpr SizeType size() const noexcept - { - return N; - } - - /// @brief Returns the maximum number of elements that the array can hold. - /// @return The maximum number of elements that the array can hold. - GP_NODISCARD constexpr SizeType capacity() const noexcept - { - return N; - } - - /// @brief Checks if the array is empty. - /// @return True if the array is empty, false otherwise. - GP_NODISCARD constexpr bool isEmpty() const noexcept - { - return N == 0; - } - - /// @brief Fills the array with the specified value. - /// @param[in] value The value to fill the array with. - constexpr void fill(const T& value) noexcept - { - std::ranges::fill(m_data, value); - } - - /// @brief Clears the array by setting all elements to their default value. - constexpr void clear() noexcept - { - std::ranges::fill(m_data, T{}); - } - - /// @brief Returns an iterator to the beginning of the array. - /// @return An iterator to the beginning of the array. - GP_NODISCARD constexpr Iterator begin() noexcept - { - return data(); - } - - /// @brief Returns a const iterator to the beginning of the array. - /// @return A const iterator to the beginning of the array. - GP_NODISCARD constexpr ConstIterator begin() const noexcept - { - return data(); - } - - /// @brief Returns an iterator to the end of the array. - /// @return An iterator to the end of the array. - GP_NODISCARD constexpr Iterator end() noexcept - { - return data() + N; - } - - /// @brief Returns a const iterator to the end of the array. - /// @return A const iterator to the end of the array. - GP_NODISCARD constexpr ConstIterator end() const noexcept - { - return data() + N; - } - - /// @brief Returns a reverse iterator to the beginning of the array. - /// @return A reverse iterator to the beginning of the array. - GP_NODISCARD constexpr ReverseIterator rbegin() noexcept - { - return ReverseIterator(end()); - } - - /// @brief Returns a const reverse iterator to the beginning of the array. - /// @return A const reverse iterator to the beginning of the array. - GP_NODISCARD constexpr ConstReverseIterator rbegin() const noexcept - { - return ConstReverseIterator(end()); - } - - /// @brief Returns a reverse iterator to the end of the array. - /// @return A reverse iterator to the end of the array. - GP_NODISCARD constexpr ReverseIterator rend() noexcept - { - return ReverseIterator(begin()); - } - - /// @brief Returns a const reverse iterator to the end of the array. - /// @return A const reverse iterator to the end of the array. - GP_NODISCARD constexpr ConstReverseIterator rend() const noexcept - { - return ConstReverseIterator(begin()); - } - - /// @brief Returns a const iterator to the beginning of the array. - /// @return A const iterator to the beginning of the array. - GP_NODISCARD constexpr ConstIterator cbegin() const noexcept - { - return data(); - } - - /// @brief Returns a const iterator to the end of the array. - /// @return A const iterator to the end of the array. - GP_NODISCARD constexpr ConstIterator cend() const noexcept - { - return data() + N; - } - - /// @brief Returns a const reverse iterator to the beginning of the array. - /// @return A const reverse iterator to the beginning of the array. - GP_NODISCARD constexpr ConstReverseIterator crbegin() const noexcept - { - return ConstReverseIterator(end()); - } - - /// @brief Returns a const reverse iterator to the end of the array. - /// @return A const reverse iterator to the end of the array. - GP_NODISCARD constexpr ConstReverseIterator crend() const noexcept - { - return ConstReverseIterator(begin()); - } - - /// @brief Finds the first occurrence of the specified value in the array. - /// @param[in] value The value to search for. - /// @return An iterator to the first occurrence of the specified value in the array, or `end()` if the value is not - /// found. - GP_NODISCARD constexpr Iterator find(const T& value) noexcept - { - return std::ranges::find(m_data, value); - } - - /// @brief Finds the first occurrence of the specified value in the array (const version). - /// @param[in] value The value to search for. - /// @return An iterator to the first occurrence of the specified value in the array, or `end()` if the value is not - /// found. - GP_NODISCARD constexpr ConstIterator find(const T& value) const noexcept - { - return std::ranges::find(m_data, value); - } - - /// @brief Checks if the array contains the specified value. - /// @param[in] value The value to search for. - /// @return True if the array contains the specified value, false otherwise. - GP_NODISCARD constexpr bool contains(const T& value) const noexcept - { - return find(value) != end(); - } - - /// @brief Counts the number of occurrences of a value in the array. - /// @param[in] value The value to count. - /// @return The number of occurrences of the specified value in the array. - GP_NODISCARD constexpr SizeType count(const T& value) const noexcept - { - return static_cast(std::ranges::count(m_data, value)); - } - - /// @brief Finds the first index of the specified value in the array. - /// @param[in] value The value to search for. - /// @return The first index of the specified value in the array, or `npos` if the value is not found. - GP_NODISCARD constexpr SizeType indexOf(const T& value) const noexcept - { - auto it = std::ranges::find(m_data, value); - return it != end() ? static_cast(it - begin()) : npos; - } - - /// @brief Finds the last index of the specified value in the array. - /// @param[in] value The value to search for. - /// @return The last index of the specified value in the array, or `npos` if the value is not found. - GP_NODISCARD constexpr SizeType lastIndexOf(const T& value) const noexcept - { - auto it = std::ranges::find(std::views::reverse(m_data), value); - return it != std::views::reverse(m_data).end() ? static_cast(it.base() - begin() - 1) : npos; - } - - /// @brief Finds the first index of an element that does not match the specified value. - /// @param[in] value The value to compare against. - /// @return The first index of an element that does not match the specified value, or `npos` if no such element is - /// found. - GP_NODISCARD constexpr SizeType indexNotOf(const T& value) const noexcept - { - auto it = std::ranges::find_if_not( - m_data, - [&value](const T& elem) - { - return elem == value; - } - ); - return it != end() ? static_cast(it - begin()) : npos; - } - - /// @brief Finds the last index of an element that does not match the specified value. - /// @param[in] value The value to compare against. - /// @return The last index of an element that does not match the specified value, or `npos` if no such element is - /// found. - GP_NODISCARD constexpr SizeType lastIndexNotOf(const T& value) const noexcept - { - auto it = std::ranges::find_if_not( - std::views::reverse(m_data), - [&value](const T& elem) - { - return elem == value; - } - ); - return it != std::views::reverse(m_data).end() ? static_cast(it.base() - begin() - 1) : npos; - } - - /// @brief Swaps the contents of this array with another array. - /// @param[in] other The array to swap with. - constexpr void swap(Array& other) noexcept - { - if constexpr (N > 0) - { - std::ranges::swap_ranges(m_data, other.m_data); - } - } -}; - -/// @brief Swaps the contents of two arrays. -/// @param[in] lhs The first array to swap. -/// @param[in] rhs The second array to swap. -template -constexpr void swap(Array& lhs, Array& rhs) noexcept -{ - lhs.swap(rhs); -} - -} // namespace gp diff --git a/source/runtime/core/public/container/BasicString.hpp b/source/runtime/core/public/container/BasicString.hpp deleted file mode 100644 index b08f1a4..0000000 --- a/source/runtime/core/public/container/BasicString.hpp +++ /dev/null @@ -1,1675 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicStringView.hpp" -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "math/LinearAlgebra.hpp" -#include "memory/traits/AllocatorTraits.hpp" -#include -#include -#include -#include -#include -#include - -namespace gp -{ - -/// @brief Dynamically sized string with Small String Optimization (SSO). -/// @details -/// sizeof(BasicString) == 32, giving a 23-character SSO buffer. -/// Two gp::String instances fit exactly into a 64-byte cache line. -/// -/// Memory layout (little-endian, 64-bit): -/// [allocator_ptr : 8 bytes] -/// [union : 24 bytes] -/// SSO mode: [chars[23] | tag] tag = remaining_capacity (0..23) -/// Heap mode: [data_ptr:8 | size:8 | capacity_with_flag:8] -/// MSB of capacity_with_flag is set to 1 to mark heap mode. -/// tag byte (last byte of the union) will be >= 0x80. -/// -/// All allocations route through AllocatorTraits. No global new/delete. -/// @tparam CharT Character type. -/// @tparam Traits Character traits (defaults to std::char_traits). -/// @tparam Alloc Allocator type (defaults to gp::memory::PolymorphicAllocator). -template -class BasicString -{ -public: - using TraitsType = Traits; - using ValueType = CharT; - using AllocatorType = Alloc; - using AllocTraits = gp::memory::AllocatorTraits; - using SizeType = gp::USize; - using DifferenceType = gp::ISize; - using Reference = ValueType&; - using ConstReference = const ValueType&; - using Pointer = ValueType*; - using ConstPointer = const ValueType*; - using Iterator = Pointer; - using ConstIterator = ConstPointer; - using ReverseIterator = std::reverse_iterator; - using ConstReverseIterator = std::reverse_iterator; - - // std::string compatibility typedefs - using value_type = CharT; - - static constexpr SizeType npos = static_cast(-1); - -private: - static constexpr SizeType ssoUnionSize = 24; - static constexpr SizeType ssoMaxChars = ssoUnionSize / sizeof(CharT) - 1; - static constexpr gp::UInt8 heapFlag = 0x80; - - /// @brief Storage layout for heap-allocated strings. - struct HeapData - { - Pointer data; - SizeType size; - SizeType capacity; - }; - - /// @brief Union of SSO buffer and heap data, discriminated by the MSB of the last byte. - union StorageUnion - { - HeapData heap; - CharT sso[ssoUnionSize / sizeof(CharT)]; - }; - - static_assert(sizeof(StorageUnion) == ssoUnionSize, "SSO union size mismatch"); - - AllocatorType m_allocator{}; - StorageUnion m_storage{}; - -public: - /// @brief Default constructs an empty string (SSO mode, zero length). - BasicString() noexcept - { - _initSsoEmpty(); - } - - /// @brief Constructs an empty string with the given allocator. - /// @param[in] alloc The allocator instance to use for future allocations. - explicit BasicString(const AllocatorType& alloc) noexcept - : m_allocator(alloc) - { - _initSsoEmpty(); - } - - /// @brief Constructs a string from a null-terminated C string. - /// @param[in] str Pointer to a null-terminated character array. - /// @param[in] alloc The allocator instance. - BasicString(const CharT* str, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - std::memset(&m_storage, 0, ssoUnionSize); - if (str) - { - const SizeType len = Traits::length(str); - _initFrom(str, len); - } - else - { - _setSsoSize(0); - } - } - - /// @brief Constructs a string from a character buffer and length. - /// @param[in] str Pointer to the character buffer. - /// @param[in] count Number of characters. - /// @param[in] alloc The allocator instance. - BasicString(const CharT* str, SizeType count, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(str, count); - } - - /// @brief Constructs a string with count copies of character ch. - /// @param[in] count Number of characters. - /// @param[in] ch The fill character. - /// @param[in] alloc The allocator instance. - BasicString(SizeType count, CharT ch, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - std::memset(&m_storage, 0, ssoUnionSize); - if (count <= ssoMaxChars) - { - for (SizeType i = 0; i < count; ++i) - { - _ssoData()[i] = ch; - } - _ssoData()[count] = CharT{}; - _setSsoSize(count); - } - else - { - Pointer buffer = _heapAlloc(count); - for (SizeType i = 0; i < count; ++i) - { - buffer[i] = ch; - } - buffer[count] = CharT{}; - m_storage.heap.data = buffer; - m_storage.heap.size = count; - _setHeapCapacity(count); - } - } - - /// @brief Constructs from an initializer list. - /// @param[in] init The initializer list of characters. - /// @param[in] alloc The allocator instance. - BasicString(std::initializer_list init, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(init.begin(), init.size()); - } - - /// @brief Constructs from a string_view. - /// @param[in] sv The string_view to copy characters from. - /// @param[in] alloc The allocator instance. - BasicString(BasicStringView sv, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(sv.data(), sv.size()); - } - - /// @brief Copy constructor. - /// @param[in] other The string to copy from. - BasicString(const BasicString& other) - : m_allocator(AllocTraits::selectOnContainerCopyConstruction(other.m_allocator)) - { - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(other.data(), other.size()); - } - - /// @brief Copy constructor with explicit allocator. - /// @param[in] other The string to copy from. - /// @param[in] alloc The allocator instance to use for this string. - BasicString(const BasicString& other, const AllocatorType& alloc) - : m_allocator(alloc) - { - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(other.data(), other.size()); - } - - /// @brief Move constructor. - /// @param[in] other The string to move from. After moving, other is left in an empty SSO state. - BasicString(BasicString&& other) noexcept - : m_allocator(static_cast(other.m_allocator)) - { - std::memcpy(&m_storage, &other.m_storage, ssoUnionSize); - other._initSsoEmpty(); - } - - /// @brief Move constructor with explicit allocator. - /// @param[in] other The string to move from. After moving, other is left in an empty SSO state. - /// @param[in] alloc The allocator instance to use for this string. - BasicString(BasicString&& other, const AllocatorType& alloc) noexcept - : m_allocator(alloc) - { - if (m_allocator == other.m_allocator) - { - std::memcpy(&m_storage, &other.m_storage, ssoUnionSize); - other._initSsoEmpty(); - } - else - { - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(other.data(), other.size()); - } - } - - /// @brief Constructs from a substring of another string. - /// @param[in] other The source string. - /// @param[in] pos Starting position. - /// @param[in] count Number of characters (clamped to remaining). - /// @param[in] alloc The allocator instance. - BasicString( - const BasicString& other, SizeType pos, SizeType count = npos, const AllocatorType& alloc = AllocatorType{} - ) - : m_allocator(alloc) - { - GP_ASSERT(pos <= other.size()); - std::memset(&m_storage, 0, ssoUnionSize); - const SizeType rcount = gp::math::min(count, other.size() - pos); - _initFrom(other.data() + pos, rcount); - } - - /// @brief Destructor. Frees any allocated heap memory. - ~BasicString() - { - _heapFree(); - } - - /// @brief Copy assignment operator. - /// @param[in] other The string to copy from. - /// @return Reference to this string. - BasicString& operator=(const BasicString& other) - { - if (this == &other) - { - return *this; - } - - constexpr bool propagate = AllocTraits::PropagateOnContainerCopyAssignment::value; - if constexpr (propagate) - { - if (m_allocator != other.m_allocator) - { - _heapFree(); - _replaceAllocator(other.m_allocator); - } - else - { - _replaceAllocator(other.m_allocator); - } - } - - _assignChars(other.data(), other.size()); - return *this; - } - - /// @brief Move assignment operator. - /// @param[in] other The string to move from. - /// @return Reference to this string. - BasicString& operator=(BasicString&& other) noexcept - { - if (this == &other) - { - return *this; - } - - constexpr bool propagate = AllocTraits::PropagateOnContainerMoveAssignment::value; - - if constexpr (propagate) - { - _heapFree(); - _replaceAllocator(static_cast(other.m_allocator)); - std::memcpy(&m_storage, &other.m_storage, ssoUnionSize); - other._initSsoEmpty(); - } - else - { - if (m_allocator == other.m_allocator) - { - _heapFree(); - std::memcpy(&m_storage, &other.m_storage, ssoUnionSize); - other._initSsoEmpty(); - } - else - { - _assignChars(other.data(), other.size()); - } - } - return *this; - } - - /// @brief Assigns from a null-terminated C string. - /// @param[in] str The C string to assign. - /// @return Reference to this string. - BasicString& operator=(const CharT* str) - { - _assignChars(str, Traits::length(str)); - return *this; - } - - /// @brief Assigns a single character. - /// @param[in] ch The character to assign. - /// @return Reference to this string. - BasicString& operator=(CharT ch) - { - _assignChars(&ch, 1); - return *this; - } - - /// @brief Assigns from a string_view. - /// @param[in] sv The string_view to assign. - /// @return Reference to this string. - BasicString& operator=(BasicStringView sv) - { - _assignChars(sv.data(), sv.size()); - return *this; - } - -public: - /// @brief Unchecked character access. - /// @param[in] pos The index of the character to access. - /// @return Reference to the character at the specified index. - GP_NODISCARD GP_FORCEINLINE Reference operator[](SizeType pos) noexcept - { - return data()[pos]; - } - - /// @brief Unchecked const character access. - /// @param[in] pos The index of the character to access. - /// @return Const reference to the character at the specified index. - GP_NODISCARD GP_FORCEINLINE ConstReference operator[](SizeType pos) const noexcept - { - return data()[pos]; - } - - /// @brief String concatenation (append). - /// @param[in] other The string to append. - /// @return Reference to this string after appending. - BasicString& operator+=(const BasicString& other) - { - return append(other); - } - - /// @brief String concatenation with a C string. - /// @param[in] str The C string to append. - /// @return Reference to this string after appending. - BasicString& operator+=(const CharT* str) - { - return append(str); - } - - /// @brief String concatenation with a single character. - /// @param[in] ch The character to append. - /// @return Reference to this string after appending. - BasicString& operator+=(CharT ch) - { - pushBack(ch); - return *this; - } - - /// @brief String concatenation with a string_view. - /// @param[in] sv The string_view to append. - /// @return Reference to this string after appending. - BasicString& operator+=(BasicStringView sv) - { - return append(sv); - } - - /// @brief Equality comparison. - /// @param[in] other The string to compare against. - /// @return True if the strings are equal, false otherwise. - GP_NODISCARD bool operator==(const BasicString& other) const noexcept - { - return size() == other.size() && Traits::compare(data(), other.data(), size()) == 0; - } - - /// @brief Equality comparison with a C string. - /// @param[in] str The C string to compare against. - /// @return True if this string is equal to the C string, false otherwise. - GP_NODISCARD bool operator==(const CharT* str) const noexcept - { - const SizeType len = Traits::length(str); - return size() == len && Traits::compare(data(), str, len) == 0; - } - - /// @brief Inequality comparison. - /// @param[in] other The string to compare against. - /// @return True if the strings are not equal, false otherwise. - GP_NODISCARD bool operator!=(const BasicString& other) const noexcept - { - return !(*this == other); - } - - /// @brief Inequality comparison with a C string. - /// @param[in] str The C string to compare against. - /// @return True if this string is not equal to the C string, false otherwise. - GP_NODISCARD bool operator!=(const CharT* str) const noexcept - { - return !(*this == str); - } - - /// @brief Three-way comparison. - /// @param[in] other The string to compare against. - /// @return A value less than, equal to, or greater than zero if this string is found, respectively, to be less - /// than, to match, or be greater than other. - GP_NODISCARD auto operator<=>(const BasicString& other) const noexcept - { - return _view() <=> BasicStringView(other.data(), other.size()); - } - - /// @brief Three-way comparison with a C string. - /// @param[in] str The C string to compare against. - /// @return A value less than, equal to, or greater than zero if this string is found, respectively, to be less - /// than, to match, or be greater than the C string. - GP_NODISCARD auto operator<=>(const CharT* str) const noexcept - { - return _view() <=> BasicStringView(str); - } - - /// @brief Implicit conversion to string_view. - /// @return A BasicStringView representing the contents of this string. - GP_NODISCARD operator BasicStringView() const noexcept - { - return _view(); - } - -public: - /// @brief Replaces contents with count copies of character ch. - /// @param[in] count Number of characters. - /// @param[in] ch The character to assign. - /// @return Reference to this string after assignment. - BasicString& assign(SizeType count, CharT ch) - { - _heapFree(); - std::memset(&m_storage, 0, ssoUnionSize); - if (count <= ssoMaxChars) - { - for (SizeType i = 0; i < count; ++i) - { - _ssoData()[i] = ch; - } - _ssoData()[count] = CharT{}; - _setSsoSize(count); - } - else - { - Pointer buffer = _heapAlloc(count); - for (SizeType i = 0; i < count; ++i) - { - buffer[i] = ch; - } - buffer[count] = CharT{}; - m_storage.heap.data = buffer; - m_storage.heap.size = count; - _setHeapCapacity(count); - } - return *this; - } - - /// @brief Replaces contents with a substring of str. - /// @param[in] str The source string. - /// @param[in] pos Starting position in str. - /// @param[in] count Number of characters to assign (clamped to remaining). - /// @return Reference to this string after assignment. - BasicString& assign(const BasicString& str, SizeType pos = 0, SizeType count = npos) - { - GP_ASSERT(pos <= str.size()); - const SizeType rcount = gp::math::min(count, str.size() - pos); - _assignChars(str.data() + pos, rcount); - return *this; - } - - /// @brief Replaces contents from a buffer and length. - /// @param[in] str Pointer to the character buffer. - /// @param[in] count Number of characters in the buffer. - /// @return Reference to this string after assignment. - BasicString& assign(const CharT* str, SizeType count) - { - _assignChars(str, count); - return *this; - } - - /// @brief Replaces contents from a null-terminated C string. - /// @param[in] str Pointer to a null-terminated character array. - /// @return Reference to this string after assignment. - BasicString& assign(const CharT* str) - { - return *this = str; - } - - /// @brief Gets a reference to the character at the specified position with bounds checking. - /// @param[in] pos The index of the character to access. - /// @return Reference to the character at the specified index. - GP_NODISCARD Reference at(SizeType pos) - { - GP_ASSERT(pos < size()); - return data()[pos]; - } - - /// @brief Gets a const reference to the character at the specified position with bounds checking. - /// @param[in] pos The index of the character to access. - /// @return Const reference to the character at the specified index. - GP_NODISCARD ConstReference at(SizeType pos) const - { - GP_ASSERT(pos < size()); - return data()[pos]; - } - - /// @brief Returns a reference to the first character. - /// @return Reference to the first character in the string. - GP_NODISCARD GP_FORCEINLINE Reference front() noexcept - { - return data()[0]; - } - - /// @brief Returns a const reference to the first character. - /// @return Const reference to the first character in the string. - GP_NODISCARD GP_FORCEINLINE ConstReference front() const noexcept - { - return data()[0]; - } - - /// @brief Returns a reference to the last character. - /// @return Reference to the last character in the string. - GP_NODISCARD GP_FORCEINLINE Reference back() noexcept - { - return data()[size() - 1]; - } - - /// @brief Returns a const reference to the last character. - /// @return Const reference to the last character in the string. - GP_NODISCARD GP_FORCEINLINE ConstReference back() const noexcept - { - return data()[size() - 1]; - } - - /// @brief Returns a pointer to the underlying character array (always null-terminated). - /// @return Pointer to the character data. - GP_NODISCARD GP_FORCEINLINE Pointer data() noexcept - { - return _isHeap() ? m_storage.heap.data : _ssoData(); - } - - /// @brief Returns a const pointer to the underlying character array (always null-terminated). - /// @return Const pointer to the character data. - GP_NODISCARD GP_FORCEINLINE ConstPointer data() const noexcept - { - return _isHeap() ? m_storage.heap.data : _ssoData(); - } - - /// @brief Returns a null-terminated C string. - /// @return Pointer to the character data. - GP_NODISCARD GP_FORCEINLINE ConstPointer cStr() const noexcept - { - return data(); - } - - /// @brief Gets an iterator to the beginning of the string. - /// @return Iterator pointing to the first character. - GP_NODISCARD GP_FORCEINLINE Iterator begin() noexcept - { - return data(); - } - - /// @brief Gets a const iterator to the beginning of the string. - /// @return Const iterator pointing to the first character. - GP_NODISCARD GP_FORCEINLINE ConstIterator begin() const noexcept - { - return data(); - } - - /// @brief Gets an iterator to the end of the string. - /// @return Iterator pointing to one past the last character. - GP_NODISCARD GP_FORCEINLINE Iterator end() noexcept - { - return data() + size(); - } - - /// @brief Gets a const iterator to the end of the string. - /// @return Const iterator pointing to one past the last character. - GP_NODISCARD GP_FORCEINLINE ConstIterator end() const noexcept - { - return data() + size(); - } - - /// @brief Gets a const iterator to the beginning of the string. - /// @return Const iterator pointing to the first character. - GP_NODISCARD GP_FORCEINLINE ConstIterator cbegin() const noexcept - { - return data(); - } - - /// @brief Gets a const iterator to the end of the string. - /// @return Const iterator pointing to one past the last character. - GP_NODISCARD GP_FORCEINLINE ConstIterator cend() const noexcept - { - return data() + size(); - } - - /// @brief Gets a reverse iterator to the end of the string. - /// @return Reverse iterator pointing to the last character. - GP_NODISCARD GP_FORCEINLINE ReverseIterator rbegin() noexcept - { - return ReverseIterator(end()); - } - - /// @brief Gets a const reverse iterator to the end of the string. - /// @return Const reverse iterator pointing to the last character. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator rbegin() const noexcept - { - return ConstReverseIterator(end()); - } - - /// @brief Gets a reverse iterator to the beginning of the string. - /// @return Reverse iterator pointing to one before the first character. - GP_NODISCARD GP_FORCEINLINE ReverseIterator rend() noexcept - { - return ReverseIterator(begin()); - } - - /// @brief Gets a const reverse iterator to the beginning of the string. - /// @return Const reverse iterator pointing to one before the first character. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator rend() const noexcept - { - return ConstReverseIterator(begin()); - } - - /// @brief Gets a const reverse iterator to the end of the string. - /// @return Const reverse iterator pointing to the last character. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator crbegin() const noexcept - { - return ConstReverseIterator(cend()); - } - - /// @brief Gets a const reverse iterator to the beginning of the string. - /// @return Const reverse iterator pointing to one before the first character. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator crend() const noexcept - { - return ConstReverseIterator(cbegin()); - } - - /// @brief Returns the number of characters (not counting the null terminator). - /// @return The size of the string. - GP_NODISCARD GP_FORCEINLINE SizeType size() const noexcept - { - return _isHeap() ? m_storage.heap.size : _ssoSize(); - } - - /// @brief Alias for size(). - /// @return The size of the string. - GP_NODISCARD GP_FORCEINLINE SizeType length() const noexcept - { - return size(); - } - - /// @brief Checks if the string is empty. - /// @return True if the string is empty, false otherwise. - GP_NODISCARD GP_FORCEINLINE bool isEmpty() const noexcept - { - return size() == 0; - } - - /// @brief Returns the current allocated capacity (not counting the null terminator). - /// @return The capacity of the string. - GP_NODISCARD GP_FORCEINLINE SizeType capacity() const noexcept - { - return _isHeap() ? _heapCapacity() : ssoMaxChars; - } - - /// @brief Returns the maximum possible string length. - /// @return The maximum size of the string. - GP_NODISCARD constexpr SizeType maxSize() const noexcept - { - return AllocTraits::maxSize(m_allocator) - 1; - } - - /// @brief Reserves storage for at least newCap characters (not counting the null terminator). - /// @param[in] newCap The minimum capacity to reserve. - void reserve(SizeType newCap) - { - if (newCap > capacity()) - { - _ensureHeapCapacity(newCap); - } - } - - /// @brief Releases unused heap memory, or transitions back to SSO if possible. - void shrinkToFit() - { - if (!_isHeap()) - { - return; - } - const SizeType len = m_storage.heap.size; - if (len <= ssoMaxChars) - { - Pointer oldBuffer = m_storage.heap.data; - const SizeType oldCapacity = _heapCapacity(); - CharT tmp[ssoUnionSize / sizeof(CharT)]; - Traits::copy(tmp, oldBuffer, len); - tmp[len] = CharT{}; - AllocTraits::deallocate(m_allocator, oldBuffer, oldCapacity + 1); - std::memset(&m_storage, 0, ssoUnionSize); - Traits::copy(_ssoData(), tmp, len); - _ssoData()[len] = CharT{}; - _setSsoSize(len); - } - else if (_heapCapacity() > len) - { - Pointer newBuffer = _heapAlloc(len); - Traits::copy(newBuffer, m_storage.heap.data, len); - newBuffer[len] = CharT{}; - AllocTraits::deallocate(m_allocator, m_storage.heap.data, _heapCapacity() + 1); - m_storage.heap.data = newBuffer; - m_storage.heap.size = len; - _setHeapCapacity(len); - } - } - - /// @brief Erases all characters, setting size to 0. - void clear() noexcept - { - if (_isHeap()) - { - m_storage.heap.size = 0; - m_storage.heap.data[0] = CharT{}; - } - else - { - _ssoData()[0] = CharT{}; - _setSsoSize(0); - } - } - - /// @brief Appends a character. - /// @param[in] ch The character to append. - void pushBack(CharT ch) - { - const SizeType len = size(); - const SizeType cap = capacity(); - if (len == cap) - { - _ensureHeapCapacity(_growCap(cap, len + 1)); - } - Pointer d = data(); - d[len] = ch; - d[len + 1] = CharT{}; - _setSize(len + 1); - } - - /// @brief Removes the last character. - void popBack() noexcept - { - GP_ASSERT(size() > 0); - const SizeType newLen = size() - 1; - data()[newLen] = CharT{}; - _setSize(newLen); - } - - /// @brief Appends another string. - /// @param[in] other The string to append. - /// @return Reference to this string after appending. - BasicString& append(const BasicString& other) - { - return append(other.data(), other.size()); - } - - /// @brief Appends a null-terminated C string. - /// @param[in] str The C string to append. - /// @return Reference to this string after appending. - BasicString& append(const CharT* str) - { - return append(str, Traits::length(str)); - } - - /// @brief Appends a buffer of characters. - /// @param[in] str Pointer to the character buffer to append. - /// @param[in] count Number of characters to append. - /// @return Reference to this string after appending. - BasicString& append(const CharT* str, SizeType count) - { - if (count == 0) - { - return *this; - } - const SizeType oldLen = size(); - const SizeType newLen = oldLen + count; - if (newLen > capacity()) - { - _ensureHeapCapacity(_growCap(capacity(), newLen)); - } - Traits::copy(data() + oldLen, str, count); - data()[newLen] = CharT{}; - _setSize(newLen); - return *this; - } - - /// @brief Appends count copies of character ch. - /// @param[in] count Number of characters to append. - /// @param[in] ch The character to append. - /// @return Reference to this string after appending. - BasicString& append(SizeType count, CharT ch) - { - if (count == 0) - { - return *this; - } - const SizeType oldLen = size(); - const SizeType newLen = oldLen + count; - if (newLen > capacity()) - { - _ensureHeapCapacity(_growCap(capacity(), newLen)); - } - Pointer d = data() + oldLen; - for (SizeType i = 0; i < count; ++i) - { - d[i] = ch; - } - data()[newLen] = CharT{}; - _setSize(newLen); - return *this; - } - - /// @brief Appends from a string_view. - /// @param[in] sv The string_view to append. - /// @return Reference to this string after appending. - BasicString& append(BasicStringView sv) - { - return append(sv.data(), sv.size()); - } - - /// @brief Inserts count copies of ch at position pos. - /// @param[in] pos The index at which to insert. - /// @param[in] count Number of characters to insert. - /// @param[in] ch The character to insert. - /// @return Reference to this string after insertion. - BasicString& insert(SizeType pos, SizeType count, CharT ch) - { - GP_ASSERT(pos <= size()); - if (count == 0) - { - return *this; - } - const SizeType oldLen = size(); - const SizeType newLen = oldLen + count; - if (newLen > capacity()) - { - _ensureHeapCapacity(_growCap(capacity(), newLen)); - } - Pointer d = data(); - Traits::move(d + pos + count, d + pos, oldLen - pos); - for (SizeType i = 0; i < count; ++i) - { - d[pos + i] = ch; - } - d[newLen] = CharT{}; - _setSize(newLen); - return *this; - } - - /// @brief Inserts a C string at position pos. - /// @param[in] pos The index at which to insert. - /// @param[in] str The C string to insert. - /// @return Reference to this string after insertion. - BasicString& insert(SizeType pos, const CharT* str) - { - return insert(pos, str, Traits::length(str)); - } - - /// @brief Inserts a buffer at position pos. - /// @param[in] pos The index at which to insert. - /// @param[in] str Pointer to the character buffer to insert. - /// @param[in] count Number of characters to insert. - /// @return Reference to this string after insertion. - BasicString& insert(SizeType pos, const CharT* str, SizeType count) - { - GP_ASSERT(pos <= size()); - if (count == 0) - { - return *this; - } - const SizeType oldLen = size(); - const SizeType newLen = oldLen + count; - if (newLen > capacity()) - { - _ensureHeapCapacity(_growCap(capacity(), newLen)); - } - Pointer d = data(); - Traits::move(d + pos + count, d + pos, oldLen - pos); - Traits::copy(d + pos, str, count); - d[newLen] = CharT{}; - _setSize(newLen); - return *this; - } - - /// @brief Inserts another string at position pos. - /// @param[in] pos The index at which to insert. - /// @param[in] str The string to insert. - /// @return Reference to this string after insertion. - BasicString& insert(SizeType pos, const BasicString& str) - { - return insert(pos, str.data(), str.size()); - } - - /// @brief Erases count characters starting at position pos. - /// @param[in] pos The index of the first character to erase. - /// @param[in] count Number of characters to erase (clamped to remaining). - /// @return Reference to this string after erasing. - BasicString& erase(SizeType pos = 0, SizeType count = npos) - { - GP_ASSERT(pos <= size()); - const SizeType rcount = gp::math::min(count, size() - pos); - const SizeType oldLen = size(); - const SizeType newLen = oldLen - rcount; - Pointer d = data(); - Traits::move(d + pos, d + pos + rcount, oldLen - pos - rcount); - d[newLen] = CharT{}; - _setSize(newLen); - return *this; - } - - /// @brief Erases the character at the given iterator position. - /// @param[in] pos Iterator pointing to the character to erase. - /// @return Iterator pointing to the character following the erased character. - Iterator erase(ConstIterator pos) - { - const SizeType idx = static_cast(pos - data()); - erase(idx, 1); - return data() + idx; - } - - /// @brief Erases the range [first, last). - /// @param[in] first Iterator pointing to the first character to erase. - /// @param[in] last Iterator pointing to one past the last character to erase. - /// @return Iterator pointing to the character following the last erased character. - Iterator erase(ConstIterator first, ConstIterator last) - { - const SizeType idx = static_cast(first - data()); - const SizeType count = static_cast(last - first); - erase(idx, count); - return data() + idx; - } - - /// @brief Replaces count characters starting at pos with str. - /// @param[in] pos The index of the first character to replace. - /// @param[in] count Number of characters to replace (clamped to remaining). - /// @param[in] str Pointer to the character buffer to replace with. - /// @param[in] strCount Number of characters in the replacement buffer. - /// @return Reference to this string after replacement. - BasicString& replace(SizeType pos, SizeType count, const CharT* str, SizeType strCount) - { - GP_ASSERT(pos <= size()); - const SizeType rcount = gp::math::min(count, size() - pos); - const SizeType oldLen = size(); - const SizeType newLen = oldLen - rcount + strCount; - if (newLen > capacity()) - { - _ensureHeapCapacity(_growCap(capacity(), newLen)); - } - Pointer d = data(); - Traits::move(d + pos + strCount, d + pos + rcount, oldLen - pos - rcount); - Traits::copy(d + pos, str, strCount); - d[newLen] = CharT{}; - _setSize(newLen); - return *this; - } - - /// @brief Replaces count characters starting at pos with another string. - /// @param[in] pos The index of the first character to replace. - /// @param[in] count Number of characters to replace (clamped to remaining). - /// @param[in] str The string to replace with. - /// @return Reference to this string after replacement. - BasicString& replace(SizeType pos, SizeType count, const BasicString& str) - { - return replace(pos, count, str.data(), str.size()); - } - - /// @brief Replaces count characters starting at pos with a C string. - /// @param[in] pos The index of the first character to replace. - /// @param[in] count Number of characters to replace (clamped to remaining). - /// @param[in] str Pointer to a null-terminated C string to replace with. - /// @return Reference to this string after replacement. - BasicString& replace(SizeType pos, SizeType count, const CharT* str) - { - return replace(pos, count, str, Traits::length(str)); - } - - /// @brief Resizes the string to count characters. New characters are set to ch. - /// @param[in] count The new size of the string. - /// @param[in] ch The character to use for new characters if the string is grown - /// @return Reference to this string after resizing. - void resize(SizeType count, CharT ch = CharT{}) - { - const SizeType oldLen = size(); - if (count <= oldLen) - { - data()[count] = CharT{}; - _setSize(count); - } - else - { - append(count - oldLen, ch); - } - } - - /// @brief Swaps contents with another string. - /// @param[in] other The string to swap with. - void swap(BasicString& other) noexcept - { - constexpr bool propagate = AllocTraits::PropagateOnContainerSwap::value; - if constexpr (!propagate) - { - GP_ASSERT(m_allocator == other.m_allocator); - } - - StorageUnion tmp; - std::memcpy(&tmp, &m_storage, ssoUnionSize); - std::memcpy(&m_storage, &other.m_storage, ssoUnionSize); - std::memcpy(&other.m_storage, &tmp, ssoUnionSize); - - if constexpr (propagate) - { - AllocatorType tmp_alloc(m_allocator); - _replaceAllocator(other.m_allocator); - other._replaceAllocator(tmp_alloc); - } - } - - /// @brief Copies a substring into dest. - /// @param[out] dest Pointer to the destination buffer. - /// @param[in] count Number of characters to copy. - /// @param[in] pos Starting position in the string (clamped to size). - /// @return The number of characters actually copied. - SizeType copy(CharT* dest, SizeType count, SizeType pos = 0) const - { - GP_ASSERT(pos <= size()); - const SizeType rcount = gp::math::min(count, size() - pos); - Traits::copy(dest, data() + pos, rcount); - return rcount; - } - - /// @brief Returns a substring. - /// @param[in] pos Starting position in the string (clamped to size). - /// @param[in] count Number of characters in the substring (clamped to remaining). - /// @return A new BasicString containing the specified substring. - GP_NODISCARD BasicString substr(SizeType pos = 0, SizeType count = npos) const - { - GP_ASSERT(pos <= size()); - return BasicString(data() + pos, gp::math::min(count, size() - pos), m_allocator); - } - - /// @brief Compares with another string. - /// @param[in] other The string to compare against. - /// @return A value less than, equal to, or greater than zero if this string is found, respectively, to be less - /// than, to match, or be greater than other. - GP_NODISCARD int compare(const BasicString& other) const noexcept - { - return _view().compare(_viewOf(other)); - } - - /// @brief Compares with a C string. - /// @param[in] str The C string to compare against. - /// @return A value less than, equal to, or greater than zero if this string is found, respectively, to be less - /// than, to match, or be greater than the C string. - GP_NODISCARD int compare(const CharT* str) const - { - return _view().compare(BasicStringView(str)); - } - - /// @brief Compares a substring with another string. - /// @param[in] pos Starting position in this string (clamped to size). - /// @param[in] count Number of characters in the substring (clamped to remaining). - /// @param[in] other The string to compare against. - /// @return A value less than, equal to, or greater than zero if the specified substring of this string is found, - /// respectively, to be less than, to match, or be greater than other. - GP_NODISCARD int compare(SizeType pos, SizeType count, const BasicString& other) const - { - return _view().compare(pos, count, _viewOf(other)); - } - - /// @brief Compares a substring with a C string. - /// @param[in] pos Starting position in this string (clamped to size). - /// @param[in] count Number of characters in the substring (clamped to remaining). - /// @param[in] str The C string to compare against. - /// @return A value less than, equal to, or greater than zero if the specified substring of this string is found, - /// respectively, to be less than, to match, or be greater than the C string. - GP_NODISCARD int compare(SizeType pos, SizeType count, const CharT* str) const - { - return _view().compare(pos, count, BasicStringView(str)); - } - - /// @brief Finds the first occurrence of a substring. - /// @param[in] str The string to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of str, or npos if not found. - GP_NODISCARD SizeType find(const BasicString& str, SizeType pos = 0) const noexcept - { - return _view().find(_viewOf(str), pos); - } - - /// @brief Finds the first occurrence of a C string. - /// @param[in] str The C string to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of str, or npos if not found. - GP_NODISCARD SizeType find(const CharT* str, SizeType pos = 0) const - { - return _view().find(str, pos); - } - - /// @brief Finds the first occurrence of a character. - /// @param[in] ch The character to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of ch, or npos if not found. - GP_NODISCARD SizeType find(CharT ch, SizeType pos = 0) const noexcept - { - return _view().find(ch, pos); - } - - /// @brief Finds the last occurrence of a substring. - /// @param[in] str The string to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of str, or npos if not found. - GP_NODISCARD SizeType rfind(const BasicString& str, SizeType pos = npos) const noexcept - { - return _view().rfind(_viewOf(str), pos); - } - - /// @brief Finds the last occurrence of a C string. - /// @param[in] str The C string to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of str, or npos if not found. - GP_NODISCARD SizeType rfind(const CharT* str, SizeType pos = npos) const - { - return _view().rfind(str, pos); - } - - /// @brief Finds the last occurrence of a character. - /// @param[in] ch The character to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of ch, or npos if not found. - GP_NODISCARD SizeType rfind(CharT ch, SizeType pos = npos) const noexcept - { - return _view().rfind(ch, pos); - } - - /// @brief Finds the first occurrence of any character from a set. - /// @param[in] str The string containing the set of characters to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of any character from str, or npos if not found. - GP_NODISCARD SizeType findFirstOf(const BasicString& str, SizeType pos = 0) const noexcept - { - return _view().findFirstOf(_viewOf(str), pos); - } - - /// @brief Finds the first occurrence of any character from a set. - /// @param[in] str The C string containing the set of characters to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of any character from str, or npos if not found. - GP_NODISCARD SizeType findFirstOf(const CharT* str, SizeType pos = 0) const - { - return _view().findFirstOf(str, pos); - } - - /// @brief Finds the first occurrence of any character from a set. - /// @param[in] ch The character to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of ch, or npos if not found. - GP_NODISCARD SizeType findFirstOf(CharT ch, SizeType pos = 0) const noexcept - { - return _view().findFirstOf(ch, pos); - } - - /// @brief Finds the last occurrence of any character from a set. - /// @param[in] str The string containing the set of characters to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of any character from str, or npos if not found. - GP_NODISCARD SizeType findLastOf(const BasicString& str, SizeType pos = npos) const noexcept - { - return _view().findLastOf(_viewOf(str), pos); - } - - /// @brief Finds the last occurrence of any character from a set. - /// @param[in] str The C string containing the set of characters to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of any character from str, or npos if not found. - GP_NODISCARD SizeType findLastOf(const CharT* str, SizeType pos = npos) const - { - return _view().findLastOf(str, pos); - } - - /// @brief Finds the last occurrence of any character from a set. - /// @param[in] ch The character to find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of ch, or npos if not found. - GP_NODISCARD SizeType findLastOf(CharT ch, SizeType pos = npos) const noexcept - { - return _view().findLastOf(ch, pos); - } - - /// @brief Finds the first occurrence of any character not in a set. - /// @param[in] str The string containing the set of characters to not find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of any character not in str, or npos if not found. - GP_NODISCARD SizeType findFirstNotOf(const BasicString& str, SizeType pos = 0) const noexcept - { - return _view().findFirstNotOf(_viewOf(str), pos); - } - - /// @brief Finds the first occurrence of any character not in a set. - /// @param[in] str The C string containing the set of characters to not find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of any character not in str, or npos if not found. - GP_NODISCARD SizeType findFirstNotOf(const CharT* str, SizeType pos = 0) const - { - return _view().findFirstNotOf(str, pos); - } - - /// @brief Finds the first occurrence of any character not in a set. - /// @param[in] ch The character to not find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the first occurrence of any character not equal to ch, or npos if not found. - GP_NODISCARD SizeType findFirstNotOf(CharT ch, SizeType pos = 0) const noexcept - { - return _view().findFirstNotOf(ch, pos); - } - - /// @brief Finds the last occurrence of any character not in a set. - /// @param[in] str The string containing the set of characters to not find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of any character not in str, or npos if not found. - GP_NODISCARD SizeType findLastNotOf(const BasicString& str, SizeType pos = npos) const noexcept - { - return _view().findLastNotOf(_viewOf(str), pos); - } - - /// @brief Finds the last occurrence of any character not in a set. - /// @param[in] str The C string containing the set of characters to not find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of any character not in str, or npos if not found. - GP_NODISCARD SizeType findLastNotOf(const CharT* str, SizeType pos = npos) const - { - return _view().findLastNotOf(str, pos); - } - - /// @brief Finds the last occurrence of any character not in a set. - /// @param[in] ch The character to not find. - /// @param[in] pos Starting position for the search (clamped to size). - /// @return The index of the last occurrence of any character not equal to ch, or npos if not found. - GP_NODISCARD SizeType findLastNotOf(CharT ch, SizeType pos = npos) const noexcept - { - return _view().findLastNotOf(ch, pos); - } - - /// @brief Checks if the string starts with a substring. - /// @param[in] sv The substring to check. - /// @return True if this string starts with sv, false otherwise. - GP_NODISCARD bool startsWith(BasicStringView sv) const noexcept - { - return _view().startsWith(sv); - } - - /// @brief Checks if the string starts with a character. - /// @param[in] ch The character to check. - /// @return True if this string starts with ch, false otherwise. - GP_NODISCARD bool startsWith(CharT ch) const noexcept - { - return _view().startsWith(ch); - } - - /// @brief Checks if the string starts with a C string. - /// @param[in] str The C string to check. - /// @return True if this string starts with str, false otherwise. - GP_NODISCARD bool startsWith(const CharT* str) const - { - return _view().startsWith(str); - } - - /// @brief Checks if the string ends with a substring. - /// @param[in] sv The substring to check. - /// @return True if this string ends with sv, false otherwise. - GP_NODISCARD bool endsWith(BasicStringView sv) const noexcept - { - return _view().endsWith(sv); - } - - /// @brief Checks if the string ends with a character. - /// @param[in] ch The character to check. - /// @return True if this string ends with ch, false otherwise. - GP_NODISCARD bool endsWith(CharT ch) const noexcept - { - return _view().endsWith(ch); - } - - /// @brief Checks if the string ends with a C string. - /// @param[in] str The C string to check. - /// @return True if this string ends with str, false otherwise. - GP_NODISCARD bool endsWith(const CharT* str) const - { - return _view().endsWith(str); - } - - /// @brief Checks if the string contains a substring. - /// @param[in] sv The substring to check. - /// @return True if this string contains sv, false otherwise. - GP_NODISCARD bool contains(BasicStringView sv) const noexcept - { - return _view().contains(sv); - } - - /// @brief Checks if the string contains a character. - /// @param[in] ch The character to check. - /// @return True if this string contains ch, false otherwise. - GP_NODISCARD bool contains(CharT ch) const noexcept - { - return _view().contains(ch); - } - - /// @brief Checks if the string contains a C string. - /// @param[in] str The C string to check. - /// @return True if this string contains str, false otherwise. - GP_NODISCARD bool contains(const CharT* str) const - { - return _view().contains(str); - } - - /// @brief Returns a string_view of this string. - /// @return A BasicStringView representing the contents of this string. - GP_NODISCARD BasicStringView asView() const noexcept - { - return _view(); - } - - /// @brief Returns a copy of the allocator. - /// @return The allocator used by this string. - GP_NODISCARD AllocatorType getAllocator() const noexcept - { - return m_allocator; - } - -private: - /// @brief Sets the size in either SSO or heap mode. - /// @param[in] len The new size of the string (not counting null terminator). - GP_FORCEINLINE void _setSize(SizeType len) noexcept - { - if (_isHeap()) - { - m_storage.heap.size = len; - } - else - { - _setSsoSize(len); - } - } - - /// @brief Common assignment path: replaces current content with [str, str+len). - /// @param[in] str Pointer to the character buffer to assign from. - /// @param[in] len Number of characters to assign. - void _assignChars(const CharT* str, SizeType len) - { - if (len <= capacity()) - { - Traits::copy(data(), str, len); - data()[len] = CharT{}; - _setSize(len); - } - else - { - _heapFree(); - std::memset(&m_storage, 0, ssoUnionSize); - _initFrom(str, len); - } - } - - /// @brief Creates a string_view of this string. - /// @return A BasicStringView representing the contents of this string. - GP_NODISCARD GP_FORCEINLINE BasicStringView _view() const noexcept - { - return BasicStringView(data(), size()); - } - - /// @brief Creates a string_view from another BasicString. - /// @param[in] s The BasicString to create a view of. - /// @return A BasicStringView representing the contents of s. - GP_NODISCARD static GP_FORCEINLINE BasicStringView _viewOf(const BasicString& s) noexcept - { - return BasicStringView(s.data(), s.size()); - } - - /// @brief Returns the tag byte (last byte of the union). - GP_NODISCARD GP_FORCEINLINE gp::UInt8& _tag() noexcept - { - return reinterpret_cast(&m_storage)[ssoUnionSize - 1]; - } - - /// @brief Returns the tag byte (last byte of the union) as const. - GP_NODISCARD GP_FORCEINLINE gp::UInt8 _tag() const noexcept - { - return reinterpret_cast(&m_storage)[ssoUnionSize - 1]; - } - - /// @brief Returns true if the string is using heap storage. - /// @return True if in heap mode, false if in SSO mode. - GP_NODISCARD GP_FORCEINLINE bool _isHeap() const noexcept - { - return (_tag() & heapFlag) != 0; - } - - /// @brief Sets the SSO tag to indicate the current length. - /// @param[in] len The length of the string in SSO mode (not counting null terminator). - GP_FORCEINLINE void _setSsoSize(SizeType len) noexcept - { - _tag() = static_cast(ssoMaxChars - len); - } - - /// @brief Returns the string length when in SSO mode. - /// @return The length of the string in SSO mode (not counting null terminator). - GP_NODISCARD GP_FORCEINLINE SizeType _ssoSize() const noexcept - { - return ssoMaxChars - static_cast(_tag()); - } - - /// @brief Returns a mutable pointer to the SSO buffer. - /// @return Pointer to the SSO character buffer. - GP_NODISCARD GP_FORCEINLINE Pointer _ssoData() noexcept - { - return m_storage.sso; - } - - GP_NODISCARD GP_FORCEINLINE ConstPointer _ssoData() const noexcept - { - return m_storage.sso; - } - - /// @brief Sets the heap capacity with the heap flag bit set in the MSB. - /// @param[in] cap The capacity to set (not counting null terminator). - GP_FORCEINLINE void _setHeapCapacity(SizeType cap) noexcept - { - m_storage.heap.capacity = cap | (static_cast(1) << (sizeof(SizeType) * 8 - 1)); - } - - /// @brief Returns the raw heap capacity (without the flag bit). - /// @return The capacity of the heap buffer (not counting null terminator). - GP_NODISCARD GP_FORCEINLINE SizeType _heapCapacity() const noexcept - { - return m_storage.heap.capacity & ~(static_cast(1) << (sizeof(SizeType) * 8 - 1)); - } - - /// @brief Initializes SSO storage to empty. - GP_FORCEINLINE void _initSsoEmpty() noexcept - { - std::memset(&m_storage, 0, ssoUnionSize); - _setSsoSize(0); - } - - /// @brief Allocates heap storage for a string of the given capacity plus null terminator. - /// @return Pointer to the heap buffer. - GP_NODISCARD Pointer _heapAlloc(SizeType cap) - { - return AllocTraits::allocate(m_allocator, cap + 1); - } - - /// @brief Frees the heap buffer. - void _heapFree() - { - if (_isHeap() && m_storage.heap.data) - { - AllocTraits::deallocate(m_allocator, m_storage.heap.data, _heapCapacity() + 1); - } - } - - /// @brief Writes len chars from src into a fresh buffer, choosing SSO or heap. - /// @param[in] src Pointer to the character buffer to initialize from. - /// @param[in] len Number of characters to initialize from. - void _initFrom(const CharT* src, SizeType len) - { - if (len <= ssoMaxChars) - { - Traits::copy(_ssoData(), src, len); - _ssoData()[len] = CharT{}; - _setSsoSize(len); - } - else - { - Pointer buf = _heapAlloc(len); - Traits::copy(buf, src, len); - buf[len] = CharT{}; - m_storage.heap.data = buf; - m_storage.heap.size = len; - _setHeapCapacity(len); - } - } - - /// @brief Returns the 1.5x growth capacity. - /// @param[in] oldCap The current capacity. - /// @param[in] required The required capacity that must be met or exceeded. - /// @return The new capacity, which is the larger of 1.5x oldCap or required. - GP_NODISCARD static SizeType _growCap(SizeType oldCap, SizeType required) noexcept - { - SizeType newCap = oldCap + (oldCap >> 1); - return newCap > required ? newCap : required; - } - - /// @brief Ensures the heap buffer can hold at least newCap characters (not counting null). - /// @param[in] newCap The required capacity to ensure. - void _ensureHeapCapacity(SizeType newCap) - { - const SizeType oldLen = size(); - const ConstPointer oldData = data(); - const SizeType oldHeapCap = _isHeap() ? _heapCapacity() : 0; - - Pointer newBuffer = _heapAlloc(newCap); - Traits::copy(newBuffer, oldData, oldLen); - newBuffer[oldLen] = CharT{}; - - if (_isHeap() && m_storage.heap.data) - { - AllocTraits::deallocate(m_allocator, m_storage.heap.data, oldHeapCap + 1); - } - - m_storage.heap.data = newBuffer; - m_storage.heap.size = oldLen; - _setHeapCapacity(newCap); - } - - /// @brief Replaces the allocator via destroy + placement new (works even if operator= is deleted). - /// @param[in] newAlloc The new allocator to set. - void _replaceAllocator(const AllocatorType& newAlloc) noexcept - { - m_allocator.~AllocatorType(); - ::new (static_cast(&m_allocator)) AllocatorType(newAlloc); - } - - /// @brief Replaces the allocator via destroy + placement new from an rvalue. - /// @param[in] newAlloc The new allocator to set. - void _replaceAllocator(AllocatorType&& newAlloc) noexcept - { - m_allocator.~AllocatorType(); - ::new (static_cast(&m_allocator)) AllocatorType(static_cast(newAlloc)); - } - -public: - /// @brief Formats a string using std::format syntax and returns it as a gp::String. - /// @details - /// Pre-computes the required buffer size via std::formatted_size, performs exactly - /// one allocation via resize(), then writes directly to the buffer via a raw-pointer - /// output iterator. The result is always null-terminated. - /// This avoids the need for a push_back-compatible back_inserter on gp::String. - /// @tparam Args Variadic template parameters for the format arguments. - /// @param[in] format The format string, following std::format syntax. - /// @param[in] args The arguments to format. - /// @return The formatted string as a gp::String. - template - static BasicString format(std::format_string format, Args&&... args) - { - // TODO: use std::basic_format_string in order to support wide-character strings without code duplication. - BasicString result; - const size_t requiredSize = std::formatted_size(format, std::forward(args)...); - result.resize(requiredSize); - std::format_to(result.data(), format, std::forward(args)...); - return result; - } -}; - -static_assert(sizeof(BasicString) == 32, "gp::string must be exactly 32 bytes"); - -} // namespace gp - -/// @brief Addition operator for two BasicStrings. Concatenates lhs and rhs into a new BasicString. -/// @param[in] lhs The first BasicString to concatenate. -/// @param[in] rhs The second BasicString to concatenate. -/// @return A new BasicString containing the result of the concatenation. -template -GP_NODISCARD gp::BasicString - operator+(const gp::BasicString& lhs, const gp::BasicString& rhs) -{ - gp::BasicString result(lhs); - result.append(rhs); - return result; -} - -/// @brief Addition operator for BasicString and C string. -/// @param[in] lhs The BasicString to append to. -/// @param[in] rhs The C string to append. -/// @return A new BasicString containing the result of the concatenation. -template -GP_NODISCARD gp::BasicString - operator+(const gp::BasicString& lhs, const CharT* rhs) -{ - gp::BasicString result(lhs); - result.append(rhs); - return result; -} - -/// @brief Addition operator for C string and BasicString. -/// @param[in] lhs The C string to append to. -/// @param[in] rhs The BasicString to append. -/// @return A new BasicString containing the result of the concatenation. -template -GP_NODISCARD gp::BasicString - operator+(const CharT* lhs, const gp::BasicString& rhs) -{ - gp::BasicString result(lhs, rhs.getAllocator()); - result.append(rhs); - return result; -} - -/// @brief Addition operator for rvalue BasicString and lvalue BasicString. -/// @param[in] lhs The BasicString to append to (moved from). -/// @param[in] rhs The BasicString to append. -/// @return A new BasicString containing the result of the concatenation. -template -GP_NODISCARD gp::BasicString - operator+(gp::BasicString&& lhs, const gp::BasicString& rhs) -{ - lhs.append(rhs); - return static_cast&&>(lhs); -} - -/// @brief Addition operator for BasicString and C string. -/// @param[in] lhs The BasicString to append to (moved from). -/// @param[in] rhs The C string to append. -/// @return A new BasicString containing the result of the concatenation. -template -GP_NODISCARD gp::BasicString - operator+(gp::BasicString&& lhs, const CharT* rhs) -{ - lhs.append(rhs); - return static_cast&&>(lhs); -} - -/// @brief Output stream operator for BasicString. Writes the string contents to the stream. -/// @param[in] os The output stream to write to. -/// @param[in] str The BasicString to write to the stream. -/// @return A reference to the output stream after writing. -template -std::ostream& operator<<(std::ostream& os, const gp::BasicString& str) -{ - return os << str.cStr(); -} - -/// @brief std::formatter specialization for gp::BasicString. -/// @details Inherits from std::formatter to gain all standard string format specifiers. -template -struct std::formatter, CharT> - : std::formatter, CharT> -{ - template - auto format(const gp::BasicString& str, FormatContext& ctx) const - { - std::basic_string_view sv(str.data(), str.size()); - return std::formatter, CharT>::format(sv, ctx); - } -}; diff --git a/source/runtime/core/public/container/BasicStringView.hpp b/source/runtime/core/public/container/BasicStringView.hpp deleted file mode 100644 index 72a8a2e..0000000 --- a/source/runtime/core/public/container/BasicStringView.hpp +++ /dev/null @@ -1,814 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "math/LinearAlgebra.hpp" -#include -#include -#include -#include -#include - -namespace gp -{ - -/// @brief Non-owning, read-only view into a contiguous character sequence. -/// @details -/// Provides a lightweight, non-allocating interface for string inspection. -/// Aggressively constexpr to enable compile-time string processing. All search -/// methods use brute-force O(n*m) algorithms, sufficient for typical engine -/// string lengths without pulling in . -/// @tparam CharT The character type. -/// @tparam Traits The character traits type (defaults to std::char_traits). -template -class BasicStringView -{ -public: - using TraitsType = Traits; - using ValueType = CharT; - using Pointer = const CharT*; - using ConstPointer = const CharT*; - using Reference = const CharT&; - using ConstReference = const CharT&; - using SizeType = gp::USize; - using DifferenceType = gp::ISize; - using Iterator = ConstPointer; - using ConstIterator = ConstPointer; - using ReverseIterator = std::reverse_iterator; - using ConstReverseIterator = std::reverse_iterator; - -public: - static constexpr SizeType npos = static_cast(-1); - -private: - ConstPointer m_data{ nullptr }; - SizeType m_size{ 0ull }; - -public: - /// @brief Default constructs an empty string view. - constexpr BasicStringView() noexcept = default; - - /// @brief Constructs a view from a null-terminated C string. - /// @param[in] str Pointer to a null-terminated character array, or nullptr. - constexpr BasicStringView(const CharT* str) noexcept - : m_data(str) - , m_size(str ? TraitsType::length(str) : 0) - {} - - /// @brief Constructs a view from a pointer and explicit length. - /// @param[in] str Pointer to the character array. - /// @param[in] count Number of characters in the view. - constexpr BasicStringView(const CharT* str, SizeType count) noexcept - : m_data(str) - , m_size(count) - {} - - /// @brief Constructs a view from a gp::basic_string. - /// @tparam Allocator The string's allocator type. - /// @param[in] str The string to view. - template > - constexpr explicit BasicStringView(const gp::BasicString& str) noexcept - : m_data(str.data()) - , m_size(str.size()) - {} - - constexpr BasicStringView(const BasicStringView&) noexcept = default; - constexpr BasicStringView& operator=(const BasicStringView&) noexcept = default; - -public: - /// @brief Unchecked element access. - /// @param[in] pos Index of the character. - /// @return Reference to the character at pos. - GP_NODISCARD constexpr ConstReference operator[](SizeType pos) const noexcept - { - return m_data[pos]; - } - - /// @brief Equality comparison. - /// @param[in] other The view to compare against. - /// @return True if the views are equal, false otherwise. - GP_NODISCARD constexpr bool operator==(const BasicStringView& other) const noexcept - { - return m_size == other.m_size && TraitsType::compare(m_data, other.m_data, m_size) == 0; - } - - /// @brief Inequality comparison. - /// @param[in] other The view to compare against. - /// @return True if the views are not equal, false otherwise. - GP_NODISCARD constexpr bool operator!=(const BasicStringView& other) const noexcept - { - return !(*this == other); - } - - /// @brief Three-way comparison. - /// @param[in] other The view to compare against. - /// @return Strong ordering indicating the relative order of the views. - GP_NODISCARD constexpr auto operator<=>(const BasicStringView& other) const noexcept - { - const SizeType len = m_size < other.m_size ? m_size : other.m_size; - int cmp = TraitsType::compare(m_data, other.m_data, len); - if (cmp != 0) - { - return cmp < 0 ? std::strong_ordering::less : std::strong_ordering::greater; - } - return m_size <=> other.m_size; - } - -public: - /// @brief Returns a pointer to the underlying character array. - /// @return Pointer to the first character in the view, or nullptr if empty. - GP_NODISCARD constexpr ConstPointer data() const noexcept - { - return m_data; - } - - /// @brief Returns the number of characters in the view. - /// @return The length of the view (not counting any null terminator). - GP_NODISCARD constexpr SizeType size() const noexcept - { - return m_size; - } - - /// @brief Returns the number of characters in the view (alias for size). - /// @return The length of the view (not counting any null terminator). - GP_NODISCARD constexpr SizeType length() const noexcept - { - return m_size; - } - - /// @brief Returns the maximum number of characters the view can refer to. - /// @return The maximum size of the view, typically limited by SizeType. - GP_NODISCARD constexpr SizeType maxSize() const noexcept - { - return npos / sizeof(CharT); - } - - /// @brief Checks if the view is empty. - /// @return True if the view is empty, false otherwise. - GP_NODISCARD constexpr bool isEmpty() const noexcept - { - return m_size == 0; - } - - /// @brief Bounds-checked element access. - /// @param[in] pos Index of the character. - /// @return Reference to the character at pos. - GP_NODISCARD constexpr ConstReference at(SizeType pos) const - { - GP_ASSERT(pos < m_size); - return m_data[pos]; - } - - /// @brief Returns a reference to the first character. - /// @return Reference to the first character in the view. - GP_NODISCARD constexpr ConstReference front() const noexcept - { - return m_data[0]; - } - - /// @brief Returns a reference to the last character. - /// @return Reference to the last character in the view. - GP_NODISCARD constexpr ConstReference back() const noexcept - { - return m_data[m_size - 1]; - } - - /// @brief Returns an iterator to the first character. - /// @return Iterator pointing to the first character in the view. - GP_NODISCARD constexpr Iterator begin() const noexcept - { - return m_data; - } - - /// @brief Returns an iterator to one past the last character. - /// @return Iterator pointing to one past the last character in the view. - GP_NODISCARD constexpr Iterator end() const noexcept - { - return m_data + m_size; - } - - /// @brief Returns a const iterator to the first character. - /// @return Const iterator pointing to the first character in the view. - GP_NODISCARD constexpr ConstIterator cbegin() const noexcept - { - return m_data; - } - - /// @brief Returns a const iterator to one past the last character. - /// @return Const iterator pointing to one past the last character in the view. - GP_NODISCARD constexpr ConstIterator cend() const noexcept - { - return m_data + m_size; - } - - /// @brief Returns a reverse iterator to the last character. - /// @return Reverse iterator pointing to the last character in the view. - GP_NODISCARD constexpr ReverseIterator rbegin() const noexcept - { - return ReverseIterator(end()); - } - - /// @brief Returns a reverse iterator to one before the first character. - /// @return Reverse iterator pointing to one before the first character in the view. - GP_NODISCARD constexpr ReverseIterator rend() const noexcept - { - return ReverseIterator(begin()); - } - - /// @brief Returns a const reverse iterator to the last character. - /// @return Const reverse iterator pointing to the last character in the view. - GP_NODISCARD constexpr ConstReverseIterator crbegin() const noexcept - { - return ConstReverseIterator(cend()); - } - - /// @brief Returns a const reverse iterator to one before the first character. - /// @return Const reverse iterator pointing to one before the first character in the view. - GP_NODISCARD constexpr ConstReverseIterator crend() const noexcept - { - return ConstReverseIterator(cbegin()); - } - - /// @brief Shrinks the view by moving the start forward. - /// @param[in] n Number of characters to remove from the front. - constexpr void removePrefix(SizeType n) noexcept - { - GP_ASSERT(n <= m_size); - m_data += n; - m_size -= n; - } - - /// @brief Shrinks the view by moving the end backward. - /// @param[in] n Number of characters to remove from the back. - constexpr void removeSuffix(SizeType n) noexcept - { - GP_ASSERT(n <= m_size); - m_size -= n; - } - - /// @brief Swaps the contents of two string views. - /// @param[in,out] other The view to swap with. - constexpr void swap(BasicStringView& other) noexcept - { - const ConstPointer tmp_data = m_data; - const SizeType tmp_size = m_size; - m_data = other.m_data; - m_size = other.m_size; - other.m_data = tmp_data; - other.m_size = tmp_size; - } - - /// @brief Copies characters to an external buffer. - /// @param[out] dest Destination buffer. - /// @param[in] count Maximum number of characters to copy. - /// @param[in] pos Starting position. - /// @return Number of characters actually copied. - constexpr SizeType copy(CharT* dest, SizeType count, SizeType pos = 0) const - { - GP_ASSERT(pos <= m_size); - const SizeType rcount = gp::math::min(count, m_size - pos); - TraitsType::copy(dest, m_data + pos, rcount); - return rcount; - } - - /// @brief Returns a substring view. - /// @param[in] pos Starting position. - /// @param[in] count Number of characters (clamped to remaining length). - /// @return A new view over the requested range. - GP_NODISCARD constexpr BasicStringView substr(SizeType pos = 0, SizeType count = npos) const - { - GP_ASSERT(pos <= m_size); - return BasicStringView(m_data + pos, gp::math::min(count, m_size - pos)); - } - - /// @brief Compares this view with another. - /// @param[in] other The view to compare against. - /// @return Negative if less, zero if equal, positive if greater. - GP_NODISCARD constexpr int compare(BasicStringView other) const noexcept - { - const SizeType len = gp::math::min(m_size, other.m_size); - int result = TraitsType::compare(m_data, other.m_data, len); - if (result != 0) - { - return result; - } - if (m_size < other.m_size) - { - return -1; - } - if (m_size > other.m_size) - { - return 1; - } - return 0; - } - - /// @brief Compares a substring of this view with another view. - /// @param[in] pos Starting position of the substring in this view. - /// @param[in] count Number of characters in the substring (clamped to remaining). - /// @param[in] other The view to compare against. - /// @return Negative if less, zero if equal, positive if greater. - GP_NODISCARD constexpr int compare(SizeType pos, SizeType count, BasicStringView other) const - { - return substr(pos, count).compare(other); - } - - /// @brief Compares a substring of this view with a substring of another view. - /// @param[in] pos1 Starting position of the substring in this view. - /// @param[in] count1 Number of characters in the substring of this view (clamped to remaining). - /// @param[in] other The view to compare against. - /// @param[in] pos2 Starting position of the substring in the other view. - /// @param[in] count2 Number of characters in the substring of the other view (clamped to remaining). - /// @return Negative if less, zero if equal, positive if greater. - GP_NODISCARD constexpr int - compare(SizeType pos1, SizeType count1, BasicStringView other, SizeType pos2, SizeType count2) const - { - return substr(pos1, count1).compare(other.substr(pos2, count2)); - } - - /// @brief Compares this view with a null-terminated C string. - /// @param[in] str The C string to compare against. - /// @return Negative if less, zero if equal, positive if greater. - GP_NODISCARD constexpr int compare(const CharT* str) const - { - return compare(BasicStringView(str)); - } - - /// @brief Compares a substring of this view with a null-terminated C string. - /// @param[in] pos Starting position of the substring in this view. - /// @param[in] count Number of characters in the substring (clamped to remaining). - /// @param[in] str The C string to compare against. - /// @return Negative if less, zero if equal, positive if greater. - GP_NODISCARD constexpr int compare(SizeType pos, SizeType count, const CharT* str) const - { - return substr(pos, count).compare(BasicStringView(str)); - } - - /// @brief Checks if the view starts with the given prefix. - /// @param[in] prefix The prefix to check for. - /// @return True if the view starts with prefix, false otherwise. - GP_NODISCARD constexpr bool startsWith(BasicStringView prefix) const noexcept - { - return m_size >= prefix.m_size && TraitsType::compare(m_data, prefix.m_data, prefix.m_size) == 0; - } - - /// @brief Checks if the view starts with the given character. - /// @param[in] ch The character to check for. - /// @return True if the view starts with ch, false otherwise. - GP_NODISCARD constexpr bool startsWith(CharT ch) const noexcept - { - return m_size > 0 && TraitsType::eq(m_data[0], ch); - } - - /// @brief Checks if the view starts with the given C string. - /// @param[in] str The C string to check for. - /// @return True if the view starts with str, false otherwise. - GP_NODISCARD constexpr bool startsWith(const CharT* str) const - { - return startsWith(BasicStringView(str)); - } - - /// @brief Checks if the view ends with the given suffix. - /// @param[in] suffix The suffix to check for. - /// @return True if the view ends with suffix, false otherwise. - GP_NODISCARD constexpr bool endsWith(BasicStringView suffix) const noexcept - { - return m_size >= suffix.m_size && - TraitsType::compare(m_data + (m_size - suffix.m_size), suffix.m_data, suffix.m_size) == 0; - } - - /// @brief Checks if the view ends with the given character. - /// @param[in] ch The character to check for. - /// @return True if the view ends with ch, false otherwise. - GP_NODISCARD constexpr bool endsWith(CharT ch) const noexcept - { - return m_size > 0 && TraitsType::eq(m_data[m_size - 1], ch); - } - - /// @brief Checks if the view ends with the given C string. - /// @param[in] str The C string to check for. - /// @return True if the view ends with str, false otherwise. - GP_NODISCARD constexpr bool endsWith(const CharT* str) const - { - return endsWith(BasicStringView(str)); - } - - /// @brief Checks if the view contains the given substring. - /// @param[in] sv The substring to check for. - /// @return True if the view contains sv, false otherwise. - GP_NODISCARD constexpr bool contains(BasicStringView sv) const noexcept - { - return find(sv) != npos; - } - - /// @brief Checks if the view contains the given character. - /// @param[in] ch The character to check for. - /// @return True if the view contains ch, false otherwise. - GP_NODISCARD constexpr bool contains(CharT ch) const noexcept - { - return find(ch) != npos; - } - - /// @brief Checks if the view contains the given C string. - /// @param[in] str The C string to check for. - /// @return True if the view contains str, false otherwise. - GP_NODISCARD constexpr bool contains(const CharT* str) const - { - return find(str) != npos; - } - - /// @brief Finds the first occurrence of a substring. - /// @param[in] sv The substring to search for. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType find(BasicStringView sv, SizeType pos = 0) const noexcept - { - if (sv.m_size == 0) - { - return pos <= m_size ? pos : npos; - } - if (pos + sv.m_size > m_size) - { - return npos; - } - const SizeType last = m_size - sv.m_size; - for (SizeType i = pos; i <= last; ++i) - { - if (TraitsType::compare(m_data + i, sv.m_data, sv.m_size) == 0) - { - return i; - } - } - return npos; - } - - /// @brief Finds the first occurrence of a character. - /// @param[in] ch The character to search for. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType find(CharT ch, SizeType pos = 0) const noexcept - { - for (SizeType i = pos; i < m_size; ++i) - { - if (TraitsType::eq(m_data[i], ch)) - { - return i; - } - } - return npos; - } - - /// @brief Finds the first occurrence of a C string. - /// @param[in] str The C string to search for. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType find(const CharT* str, SizeType pos = 0) const - { - return find(BasicStringView(str), pos); - } - - /// @brief Finds the first occurrence of a buffer with explicit length. - /// @param[in] str Pointer to the character array to search for. - /// @param[in] pos Position to start searching from. - /// @param[in] count Number of characters in the buffer. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType find(const CharT* str, SizeType pos, SizeType count) const - { - return find(BasicStringView(str, count), pos); - } - - /// @brief Finds the last occurrence of a substring. - /// @param[in] sv The substring to search for. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType rfind(BasicStringView sv, SizeType pos = npos) const noexcept - { - if (sv.m_size == 0) - { - return gp::math::min(pos, m_size); - } - if (sv.m_size > m_size) - { - return npos; - } - SizeType i = gp::math::min(pos, m_size - sv.m_size); - for (;; --i) - { - if (TraitsType::compare(m_data + i, sv.m_data, sv.m_size) == 0) - { - return i; - } - if (i == 0) - { - break; - } - } - return npos; - } - - /// @brief Finds the last occurrence of a character. - /// @param[in] ch The character to search for. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType rfind(CharT ch, SizeType pos = npos) const noexcept - { - if (m_size == 0) - { - return npos; - } - SizeType i = gp::math::min(pos, m_size - 1); - for (;; --i) - { - if (TraitsType::eq(m_data[i], ch)) - { - return i; - } - if (i == 0) - { - break; - } - } - return npos; - } - - /// @brief Finds the last occurrence of a C string. - /// @param[in] str The C string to search for. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType rfind(const CharT* str, SizeType pos = npos) const - { - return rfind(BasicStringView(str), pos); - } - - /// @brief Finds the last occurrence of a buffer with explicit length. - /// @param[in] str Pointer to the character array to search for. - /// @param[in] pos Position to start searching backward from. - /// @param[in] count Number of characters in the buffer. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType rfind(const CharT* str, SizeType pos, SizeType count) const - { - return rfind(BasicStringView(str, count), pos); - } - - /// @brief Finds the first character that matches any character in the given view. - /// @param[in] sv The set of characters to match against. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstOf(BasicStringView sv, SizeType pos = 0) const noexcept - { - for (SizeType i = pos; i < m_size; ++i) - { - if (_charInSet(m_data[i], sv)) - { - return i; - } - } - return npos; - } - - /// @brief Finds the first occurrence of the given character. - /// @param[in] ch The character to match. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstOf(CharT ch, SizeType pos = 0) const noexcept - { - return find(ch, pos); - } - - /// @brief Finds the first character that matches any character in the given C string. - /// @param[in] str The C string containing characters to match. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstOf(const CharT* str, SizeType pos = 0) const - { - return findFirstOf(BasicStringView(str), pos); - } - - /// @brief Finds the first character that matches any character in the given buffer. - /// @param[in] str Pointer to the character array containing characters to match. - /// @param[in] pos Position to start searching from. - /// @param[in] count Number of characters in the buffer. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstOf(const CharT* str, SizeType pos, SizeType count) const - { - return findFirstOf(BasicStringView(str, count), pos); - } - - /// @brief Finds the last character that matches any character in the given view. - /// @param[in] sv The set of characters to match against. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastOf(BasicStringView sv, SizeType pos = npos) const noexcept - { - if (m_size == 0) - { - return npos; - } - SizeType i = gp::math::min(pos, m_size - 1); - for (;; --i) - { - if (_charInSet(m_data[i], sv)) - { - return i; - } - if (i == 0) - { - break; - } - } - return npos; - } - - /// @brief Finds the last occurrence of the given character. - /// @param[in] ch The character to match. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastOf(CharT ch, SizeType pos = npos) const noexcept - { - return rfind(ch, pos); - } - - /// @brief Finds the last character that matches any character in the given C string. - /// @param[in] str The C string containing characters to match. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastOf(const CharT* str, SizeType pos = npos) const - { - return findLastOf(BasicStringView(str), pos); - } - - /// @brief Finds the last character that matches any character in the given buffer. - /// @param[in] str Pointer to the character array containing characters to match. - /// @param[in] pos Position to start searching backward from. - /// @param[in] count Number of characters in the buffer. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastOf(const CharT* str, SizeType pos, SizeType count) const - { - return findLastOf(BasicStringView(str, count), pos); - } - - /// @brief Finds the first character that does not match any character in the given view. - /// @param[in] sv The set of characters to not match against. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstNotOf(BasicStringView sv, SizeType pos = 0) const noexcept - { - for (SizeType i = pos; i < m_size; ++i) - { - if (!_charInSet(m_data[i], sv)) - { - return i; - } - } - return npos; - } - - /// @brief Finds the first character that is not equal to the given character. - /// @param[in] ch The character to not match. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstNotOf(CharT ch, SizeType pos = 0) const noexcept - { - for (SizeType i = pos; i < m_size; ++i) - { - if (!TraitsType::eq(m_data[i], ch)) - { - return i; - } - } - return npos; - } - - /// @brief Finds the first character that does not match any character in the given C string. - /// @param[in] str The C string containing characters to not match. - /// @param[in] pos Position to start searching from. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstNotOf(const CharT* str, SizeType pos = 0) const - { - return findFirstNotOf(BasicStringView(str), pos); - } - - /// @brief Finds the first character that does not match any character in the given buffer. - /// @param[in] str Pointer to the character array containing characters to not match. - /// @param[in] pos Position to start searching from. - /// @param[in] count Number of characters in the buffer. - /// @return Index of the first occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findFirstNotOf(const CharT* str, SizeType pos, SizeType count) const - { - return findFirstNotOf(BasicStringView(str, count), pos); - } - - /// @brief Finds the last character that does not match any character in the given view. - /// @param[in] sv The set of characters to not match against. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastNotOf(BasicStringView sv, SizeType pos = npos) const noexcept - { - if (m_size == 0) - { - return npos; - } - SizeType i = gp::math::min(pos, m_size - 1); - for (;; --i) - { - if (!_charInSet(m_data[i], sv)) - { - return i; - } - if (i == 0) - { - break; - } - } - return npos; - } - - /// @brief Finds the last character that is not equal to the given character. - /// @param[in] ch The character to not match. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastNotOf(CharT ch, SizeType pos = npos) const noexcept - { - if (m_size == 0) - { - return npos; - } - SizeType i = gp::math::min(pos, m_size - 1); - for (;; --i) - { - if (!TraitsType::eq(m_data[i], ch)) - { - return i; - } - if (i == 0) - { - break; - } - } - return npos; - } - - /// @brief Finds the last character that does not match any character in the given C string. - /// @param[in] str The C string containing characters to not match. - /// @param[in] pos Position to start searching backward from. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastNotOf(const CharT* str, SizeType pos = npos) const - { - return findLastNotOf(BasicStringView(str), pos); - } - - /// @brief Finds the last character that does not match any character in the given buffer. - /// @param[in] str Pointer to the character array containing characters to not match. - /// @param[in] pos Position to start searching backward from. - /// @param[in] count Number of characters in the buffer. - /// @return Index of the last occurrence, or npos if not found. - GP_NODISCARD constexpr SizeType findLastNotOf(const CharT* str, SizeType pos, SizeType count) const - { - return findLastNotOf(BasicStringView(str, count), pos); - } - -private: - /// @brief Checks if a character exists in the given character set view. - /// @param[in] ch The character to check. - /// @param[in] set The view representing the set of characters. - /// @return True if ch is found in set, false otherwise. - GP_NODISCARD static constexpr bool _charInSet(CharT ch, BasicStringView set) noexcept - { - for (SizeType i = 0; i < set.m_size; ++i) - { - if (TraitsType::eq(ch, set.m_data[i])) - { - return true; - } - } - return false; - } -}; - -} // namespace gp - -/// @brief Stream insertion operator for BasicStringView, outputs the view's characters to the stream. -/// @param os The output stream to write to. -/// @param sv The BasicStringView to output. -/// @return Reference to the output stream after writing the view's characters. -template -std::ostream& operator<<(std::ostream& os, const gp::BasicStringView& sv) -{ - return os << sv.data(); -} - -/// @brief std::formatter specialization for gp::BasicStringView. -template -struct std::formatter, CharT> : std::formatter, CharT> -{ - template - auto format(gp::BasicStringView sv, FormatContext& ctx) const - { - std::basic_string_view std_sv(sv.data(), sv.size()); - return std::formatter, CharT>::format(std_sv, ctx); - } -}; diff --git a/source/runtime/core/public/container/Forward.hpp b/source/runtime/core/public/container/Forward.hpp deleted file mode 100644 index 88517f3..0000000 --- a/source/runtime/core/public/container/Forward.hpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "memory/allocators/PolymorphicAllocator.hpp" -#include "memory/MemoryForward.hpp" -#include // required for std::char_traits - -// Volountary not inside a specific namespace to avoid excessive nesting for commonly used types like string, -// vector, etc. -namespace gp -{ - -/// @section Sequences - -template -class Array; -template > -class Vector; -template > -class List; -template > -class Deque; -template > -class ForwardList; - -/// @section Specialized Sequences - -template -class Span; - -/// @section Strings - -template < - typename CharT, - typename Traits = std::char_traits, - typename Alloc = gp::memory::PolymorphicAllocator> -class BasicString; - -using String = BasicString; -using WString = BasicString; -using U8String = BasicString; -using U16String = BasicString; - -template > -class BasicStringView; - -using StringView = BasicStringView; -using WStringView = BasicStringView; -using U8StringView = BasicStringView; -using U16StringView = BasicStringView; - -/// @section Associative Containers (Ordered) - -template -class Map; -template -class MultiMap; -template -class Set; -template -class MultiSet; - -/// @section Associative Containers (Unordered / Hashed) - -template -class UnorderedMap; -template -class UnorderedMultiMap; -template -class UnorderedSet; - -/// @section Aliases for engine-specific naming conventions - -template -using HashMap = UnorderedMap; - -template -using MultiHashMap = UnorderedMultiMap; - -/// @section Other Containers - -template -class Optional; - -} // namespace gp diff --git a/source/runtime/core/public/container/Optional.hpp b/source/runtime/core/public/container/Optional.hpp deleted file mode 100644 index c94c773..0000000 --- a/source/runtime/core/public/container/Optional.hpp +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include -#include - -namespace gp -{ - -/// @brief NullOpt tag type for constructing empty optionals and comparisons. -struct NullOptT -{ - explicit constexpr NullOptT() = default; -}; - -/// @brief NullOpt constant for constructing empty optionals and comparisons. -inline constexpr NullOptT nullOpt{}; - -/// @brief Optional value container, holds a T or nothing. -/// @note No heap allocation. The value lives in aligned inline storage. Use hasValue() / operator bool to check -/// presence before access. -/// @tparam T Contained type. -template -class Optional -{ - static_assert(std::is_destructible_v, "T must be destructible"); - static_assert(!std::is_reference_v, "T must not be a reference type"); - -public: - using ValueType = T; - -private: - GP_ALIGN(alignof(T)) Byte m_storage[sizeof(T)]; - bool m_hasValue = false; - -public: - /// @brief Constructs an empty optional. - constexpr Optional() noexcept - : m_hasValue(false) - {} - - /// @brief Constructs an empty optional from NullOpt. - /// @param[in] NullOpt NullOpt tag. - constexpr Optional(NullOptT) noexcept - : m_hasValue(false) - {} - - /// @brief Copy-constructs an optional holding @p value. - /// @param[in] value Value to store. - constexpr Optional(const T& value) noexcept(noexcept(T(value))) - : m_hasValue(true) - { - ::new (&m_storage) T(value); - } - - /// @brief Move-constructs an optional holding @p value. - /// @param[in] value Value to move. - constexpr Optional(T&& value) noexcept(noexcept(T(std::move(value)))) - : m_hasValue(true) - { - ::new (&m_storage) T(std::move(value)); - } - - /// @brief Constructs a new value in-place. - /// @tparam Args Argument types. - /// @param[in] args Arguments forwarded to T's constructor. - template - requires std::is_constructible_v - explicit constexpr Optional(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - : m_hasValue(true) - { - ::new (&m_storage) T(std::forward(args)...); - } - - /// @brief Copy-constructs from another optional. - /// @param[in] other Optional to copy from. - constexpr Optional(const Optional& other) - : m_hasValue(other.m_hasValue) - { - if (m_hasValue) - { - ::new (&m_storage) T(other.value()); - } - } - - /// @brief Move-constructs from another optional. - /// @param[in] other Optional to move from. - constexpr Optional(Optional&& other) noexcept(noexcept(T(std::move(other.value())))) - : m_hasValue(other.m_hasValue) - { - if (m_hasValue) - { - ::new (&m_storage) T(std::move(other.value())); - other.reset(); - } - } - - /// @brief Destroys the contained value (if any). - ~Optional() - { - reset(); - } - - /// @brief Assigns NullOpt, destroying any contained value. - /// @param[in] NullOpt NullOpt tag. - /// @return Reference to this optional. - Optional& operator=(NullOptT) noexcept - { - reset(); - return *this; - } - - /// @brief Copy-assigns from another optional. - /// @param[in] other Optional to copy from. - /// @return Reference to this optional. - Optional& operator=(const Optional& other) - { - if (this == &other) - { - return *this; - } - if (m_hasValue && other.m_hasValue) - { - value() = other.value(); - } - else if (!m_hasValue && other.m_hasValue) - { - ::new (&m_storage) T(other.value()); - m_hasValue = true; - } - else if (m_hasValue) - { - reset(); - } - return *this; - } - - /// @brief Move-assigns from another optional. - /// @param[in] other Optional to move from. - /// @return Reference to this optional. - Optional& operator=(Optional&& other) noexcept(noexcept(T(std::move(other.value())))) - { - if (this == &other) - { - return *this; - } - if (m_hasValue && other.m_hasValue) - { - value() = std::move(other.value()); - other.reset(); - } - else if (!m_hasValue && other.m_hasValue) - { - ::new (&m_storage) T(std::move(other.value())); - m_hasValue = true; - other.reset(); - } - else if (m_hasValue) - { - reset(); - } - return *this; - } - - /// @brief Copy- or move-assigns a new value, constructing it if the optional was empty. - /// @tparam U Type of the value to assign (deduced). - /// @param[in] inValue Value to assign. - /// @return Reference to this optional. - template - requires std::is_constructible_v && (!std::is_same_v, Optional>)Optional& - operator=(U&& inValue) - { - if (m_hasValue) - { - value() = std::forward(inValue); - } - else - { - ::new (&m_storage) T(std::forward(inValue)); - m_hasValue = true; - } - return *this; - } - -public: - /// @brief Checks if the optional contains a value. - /// @param[in] other Optional to compare with. - /// @return True if both optionals are empty or both contain equal values, false otherwise. - GP_NODISCARD bool operator==(const Optional& other) const noexcept requires std::equality_comparable - { - if (m_hasValue != other.m_hasValue) - { - return false; - } - return !m_hasValue || value() == other.value(); - } - - /// @brief Checks if the optional is empty. - /// @param[in] NullOpt NullOpt tag. - /// @return True if this optional is empty, false otherwise. - GP_NODISCARD bool operator==(NullOptT) const noexcept - { - return !m_hasValue; - } - - /// @brief Checks if the optional is not empty. - /// @param[in] NullOpt NullOpt tag. - /// @return True if this optional has a value, false otherwise. - GP_NODISCARD bool operator!=(NullOptT) const noexcept - { - return m_hasValue; - } - - /// @brief Checks if the optional contains a value equal to @p inValue. - /// @param[in] inValue Value to compare with. - /// @return True if the optional has a value and it is equal to @p inValue, false otherwise. - GP_NODISCARD bool operator==(const T& inValue) const noexcept requires std::equality_comparable - { - return m_hasValue && value() == inValue; - } - - /// @brief Checks if the optional does not contain a value equal to @p value. - /// @param[in] value Value to compare with. - /// @return True if the optional is empty or its value differs from @p value, false otherwise. - GP_NODISCARD bool operator!=(const T& value) const noexcept requires std::equality_comparable - { - return !(*this == value); - } - - /// @brief Checks if this optional is not equal to another optional. - /// @param[in] other Optional to compare with. - /// @return True if the optionals differ in value presence or contained value, false otherwise. - GP_NODISCARD bool operator!=(const Optional& other) const noexcept requires std::equality_comparable - { - return !(*this == other); - } - - /// @brief Dereferences the optional to access the contained value. - /// @return Reference to the contained value. - GP_NODISCARD constexpr T& operator*() & noexcept - { - return value(); - } - - /// @brief Dereferences the optional to access the contained value. - /// @return Reference to the contained value. - GP_NODISCARD constexpr const T& operator*() const& noexcept - { - return value(); - } - - /// @brief Dereferences the optional to access the contained value. - /// @return Rvalue reference to the contained value. - GP_NODISCARD constexpr T&& operator*() && noexcept - { - return std::move(value()); - } - - /// @brief Accesses members of the contained value. - /// @return Pointer to the contained value. - GP_NODISCARD constexpr T* operator->() noexcept - { - return &value(); - } - - /// @brief Accesses members of the contained value. - /// @return Pointer to the contained value. - GP_NODISCARD constexpr const T* operator->() const noexcept - { - return &value(); - } - - /// @brief Explicitly converts to bool to check for value presence. - /// @return True if the optional has a value, false otherwise. - GP_NODISCARD constexpr explicit operator bool() const noexcept - { - return m_hasValue; - } - -public: - /// @brief Checks if the optional contains a value. - /// @return True if the optional has a value, false otherwise. - GP_NODISCARD constexpr bool hasValue() const noexcept - { - return m_hasValue; - } - - /// @brief Accesses the contained value, asserting if there is none. - /// @return Reference to the contained value. - GP_NODISCARD constexpr T& value() & noexcept - { - GP_ASSERT(m_hasValue); - return *reinterpret_cast(&m_storage); - } - - /// @brief Accesses the contained value, asserting if there is none. - /// @return Reference to the contained value. - GP_NODISCARD constexpr const T& value() const& noexcept - { - GP_ASSERT(m_hasValue); - return *reinterpret_cast(&m_storage); - } - - /// @brief Accesses the contained value, asserting if there is none. - /// @return Rvalue reference to the contained value. - GP_NODISCARD constexpr T&& value() && noexcept - { - GP_ASSERT(m_hasValue); - return std::move(*reinterpret_cast(&m_storage)); - } - - /// @brief Returns the contained value if present, otherwise returns @p defaultValue. - /// @param[in] defaultValue Value to return if the optional is empty. - /// @return The contained value or @p defaultValue. - GP_NODISCARD constexpr T valueOr(T&& defaultValue) const& noexcept - { - return m_hasValue ? value() : std::move(defaultValue); - } - - /// @brief Returns the contained value if present, otherwise returns @p defaultValue. - /// @param[in] defaultValue Value to return if the optional is empty. - /// @return The contained value or @p defaultValue. - GP_NODISCARD constexpr T valueOr(T&& defaultValue) && noexcept - { - return m_hasValue ? std::move(value()) : std::move(defaultValue); - } - - /// @brief Destroys the contained value if present, leaving the optional empty. - void reset() noexcept - { - if (m_hasValue) - { - if constexpr (!std::is_trivially_destructible_v) - { - reinterpret_cast(&m_storage)->~T(); - } - m_hasValue = false; - } - } - - /// @brief Constructs a new value in-place, destroying any existing value. - /// @tparam Args Argument types for constructing the new value. - /// @param[in] args Arguments forwarded to T's constructor. - /// @return Reference to the newly constructed value. - template - T& emplace(Args&&... args) - { - reset(); - ::new (&m_storage) T(std::forward(args)...); - m_hasValue = true; - return value(); - } - - /// @brief Swaps the contents of this optional with another optional. - /// @param[in] other Optional to swap with. - void swap(Optional& other) noexcept(noexcept(T(std::move(std::declval())))) - { - if (m_hasValue && other.m_hasValue) - { - std::swap(value(), other.value()); - } - else if (!m_hasValue && other.m_hasValue) - { - ::new (&m_storage) T(std::move(other.value())); - m_hasValue = true; - other.reset(); - } - else if (m_hasValue && !other.m_hasValue) - { - ::new (&other.m_storage) T(std::move(value())); - other.m_hasValue = true; - reset(); - } - } -}; - -/// @brief Creates a Optional with an in-place constructed value. -/// @tparam T Value type. -/// @tparam Args Constructor argument types. -/// @param args Arguments forwarded to T's constructor. -/// @return Optional with a live value. -template -GP_NODISCARD constexpr Optional makeOptional(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) -{ - return Optional(std::forward(args)...); -} - -} // namespace gp diff --git a/source/runtime/core/public/container/Vector.hpp b/source/runtime/core/public/container/Vector.hpp deleted file mode 100644 index a7f4535..0000000 --- a/source/runtime/core/public/container/Vector.hpp +++ /dev/null @@ -1,1144 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "memory/MemoryForward.hpp" -#include "memory/traits/AllocatorTraits.hpp" -#include -#include -#include -#include -#include - -namespace gp -{ - -/// @brief Contiguous dynamic array with custom allocator support and trivial-type fast-paths. -/// @details -/// Implements the standard vector interface for interoperability with . -/// Growth factor is hardcoded at 1.5x to minimize memory spikes and improve allocator -/// reuse in game engine scenarios. For trivially copyable types, reallocation and -/// element shifting use memcpy/memmove instead of per-element construct/destroy. -/// @tparam T The element type. -/// @tparam Allocator The allocator type (defaults to gp::memory::PolymorphicAllocator). -template -class Vector -{ -public: - using ValueType = T; - using AllocatorType = Allocator; - using Traits = gp::memory::AllocatorTraits; - using SizeType = gp::USize; - using DifferenceType = gp::ISize; - using Reference = ValueType&; - using ConstReference = const ValueType&; - using Pointer = ValueType*; - using ConstPointer = const ValueType*; - using Iterator = Pointer; - using ConstIterator = ConstPointer; - using ReverseIterator = std::reverse_iterator; - using ConstReverseIterator = std::reverse_iterator; - -private: - Pointer m_data{ nullptr }; - SizeType m_size{ 0 }; - SizeType m_capacity{ 0 }; - GP_NO_UNIQUE_ADDRESS AllocatorType m_allocator{}; - -public: - /// @brief Default constructs an empty vector with the default allocator. - Vector() noexcept = default; - - /// @brief Constructs an empty vector with the given allocator. - /// @param[in] alloc The allocator instance to use. - explicit Vector(const AllocatorType& alloc) noexcept - : m_allocator(alloc) - {} - - /// @brief Constructs a vector with count default-inserted elements. - /// @param[in] count Number of elements to default-insert. - /// @param[in] alloc The allocator instance to use. - explicit Vector(SizeType count, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - if (count > 0) - { - m_data = Traits::allocate(m_allocator, count); - m_capacity = count; - _defaultConstructRange(m_data, count); - m_size = count; - } - } - - /// @brief Constructs a vector with count copies of value. - /// @param[in] count Number of elements. - /// @param[in] value The value to copy. - /// @param[in] alloc The allocator instance to use. - Vector(SizeType count, const T& value, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - if (count > 0) - { - m_data = Traits::allocate(m_allocator, count); - m_capacity = count; - _fillConstructRange(m_data, count, value); - m_size = count; - } - } - - /// @brief Constructs a vector from an iterator range. - /// @tparam InputIt The input iterator type. - /// @param[in] first Iterator to the beginning of the range. - /// @param[in] last Iterator to the end of the range. - /// @param[in] alloc The allocator instance to use. - template - requires(!std::is_integral_v) - Vector(InputIt first, InputIt last, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - _rangeInit(first, last); - } - - /// @brief Constructs a vector from an initializer list. - /// @param[in] init The initializer list. - /// @param[in] alloc The allocator instance to use. - Vector(std::initializer_list init, const AllocatorType& alloc = AllocatorType{}) - : m_allocator(alloc) - { - if (init.size() > 0) - { - m_data = Traits::allocate(m_allocator, init.size()); - m_capacity = init.size(); - _copyConstructRange(m_data, init.begin(), init.size()); - m_size = init.size(); - } - } - - /// @brief Copy constructor. - /// @param[in] other The vector to copy from. - Vector(const Vector& other) - : m_allocator(Traits::selectOnContainerCopyConstruction(other.m_allocator)) - { - if (other.m_size > 0) - { - m_data = Traits::allocate(m_allocator, other.m_size); - m_capacity = other.m_size; - _copyConstructRange(m_data, other.m_data, other.m_size); - m_size = other.m_size; - } - } - - /// @brief Copy constructor with explicit allocator. - /// @param[in] other The vector to copy from. - /// @param[in] alloc The allocator instance to use. - Vector(const Vector& other, const AllocatorType& alloc) - : m_allocator(alloc) - { - if (other.m_size > 0) - { - m_data = Traits::allocate(m_allocator, other.m_size); - m_capacity = other.m_size; - _copyConstructRange(m_data, other.m_data, other.m_size); - m_size = other.m_size; - } - } - - /// @brief Move constructor. - /// @param[in] other The vector to move from. - Vector(Vector&& other) noexcept - : m_data(other.m_data) - , m_size(other.m_size) - , m_capacity(other.m_capacity) - , m_allocator(static_cast(other.m_allocator)) - { - other.m_data = nullptr; - other.m_size = 0; - other.m_capacity = 0; - } - - /// @brief Move constructor with explicit allocator. - /// @param[in] other The vector to move from. - /// @param[in] alloc The allocator instance to use. - Vector(Vector&& other, const AllocatorType& alloc) noexcept - : m_allocator(alloc) - { - if (m_allocator == other.m_allocator) - { - m_data = other.m_data; - m_size = other.m_size; - m_capacity = other.m_capacity; - other.m_data = nullptr; - other.m_size = 0; - other.m_capacity = 0; - } - else if (other.m_size > 0) - { - m_data = Traits::allocate(m_allocator, other.m_size); - m_capacity = other.m_size; - _moveConstructRange(m_data, other.m_data, other.m_size); - m_size = other.m_size; - } - } - - /// @brief Destructor destroys elements and frees memory. - ~Vector() - { - _destroyAndFree(); - } - - /// @brief Copy assignment operator. - /// @param[in] other The vector to copy from. - Vector& operator=(const Vector& other) - { - if (this == &other) - { - return *this; - } - - constexpr bool propagate = Traits::PropagateOnContainerCopyAssignment::value; - - if constexpr (propagate) - { - if (m_allocator != other.m_allocator) - { - _destroyAndFree(); - _replaceAllocator(other.m_allocator); - m_data = nullptr; - m_size = 0; - m_capacity = 0; - } - else - { - _replaceAllocator(other.m_allocator); - } - } - - _assignFrom(other.m_data, other.m_size); - return *this; - } - - /// @brief Move assignment operator. - /// @param[in] other The vector to move from. - Vector& operator=(Vector&& other) noexcept - { - if (this == &other) - { - return *this; - } - - constexpr bool propagate = Traits::PropagateOnContainerMoveAssignment::value; - - if constexpr (propagate) - { - _destroyAndFree(); - _replaceAllocator(static_cast(other.m_allocator)); - m_data = other.m_data; - m_size = other.m_size; - m_capacity = other.m_capacity; - other.m_data = nullptr; - other.m_size = 0; - other.m_capacity = 0; - } - else - { - if (m_allocator == other.m_allocator) - { - _destroyAndFree(); - m_data = other.m_data; - m_size = other.m_size; - m_capacity = other.m_capacity; - other.m_data = nullptr; - other.m_size = 0; - other.m_capacity = 0; - } - else - { - _assignFromMove(other.m_data, other.m_size); - } - } - return *this; - } - - /// @brief Initializer list assignment. - /// @param[in] init The initializer list to assign from. - Vector& operator=(std::initializer_list init) - { - _assignFrom(init.begin(), init.size()); - return *this; - } - -public: - /// @brief Unchecked element access. - /// @param[in] pos The index of the element to access. - /// @return Reference to the element at the given index. - GP_NODISCARD GP_FORCEINLINE Reference operator[](SizeType pos) noexcept - { - return m_data[pos]; - } - - /// @brief Unchecked element access (const). - /// @param[in] pos The index of the element to access. - /// @return Const reference to the element at the given index. - GP_NODISCARD GP_FORCEINLINE ConstReference operator[](SizeType pos) const noexcept - { - return m_data[pos]; - } - - /// @brief Equality comparison. - /// @param[in] other The vector to compare with. - /// @return True if the vectors are equal, false otherwise. - GP_NODISCARD bool operator==(const Vector& other) const noexcept - { - if (m_size != other.m_size) - { - return false; - } - if constexpr (std::is_trivially_copyable_v) - { - return m_size == 0 || std::memcmp(m_data, other.m_data, m_size * sizeof(T)) == 0; - } - else - { - for (SizeType i = 0; i < m_size; ++i) - { - if (!(m_data[i] == other.m_data[i])) - { - return false; - } - } - return true; - } - } - - /// @brief Inequality comparison. - /// @param[in] other The vector to compare with. - /// @return True if the vectors are not equal, false otherwise. - GP_NODISCARD bool operator!=(const Vector& other) const noexcept - { - return !(*this == other); - } - -public: - /// @brief Replaces contents with count copies of value. - /// @param[in] count Number of elements. - /// @param[in] value The value to copy. - void assign(SizeType count, const T& value) - { - _destroyRange(m_data, m_size); - m_size = 0; - if (count > m_capacity) - { - _reallocExact(count); - } - _fillConstructRange(m_data, count, value); - m_size = count; - } - - /// @brief Replaces contents with the range [first, last). - /// @tparam InputIt The input iterator type. - /// @param[in] first Iterator to the beginning of the range. - /// @param[in] last Iterator to the end of the range. - template - requires(!std::is_integral_v) void assign(InputIt first, InputIt last) - { - _destroyRange(m_data, m_size); - m_size = 0; - _rangeInit(first, last); - } - - /// @brief Replaces contents with an initializer list. - /// @param[in] init The initializer list. - void assign(std::initializer_list init) - { - _assignFrom(init.begin(), init.size()); - } - - /// @brief Bounds-checked element access. - /// @param[in] pos The index of the element to access. - /// @return Reference to the element at the given index. - GP_NODISCARD Reference at(SizeType pos) - { - GP_ASSERT(pos < m_size); - return m_data[pos]; - } - - /// @brief Bounds-checked element access (const). - /// @param[in] pos The index of the element to access. - /// @return Const reference to the element at the given index. - GP_NODISCARD ConstReference at(SizeType pos) const - { - GP_ASSERT(pos < m_size); - return m_data[pos]; - } - - /// @brief Returns a reference to the first element. - /// @return Reference to the first element. - GP_NODISCARD GP_FORCEINLINE Reference front() noexcept - { - return m_data[0]; - } - - /// @brief Returns a reference to the first element (const). - /// @return Const reference to the first element. - GP_NODISCARD GP_FORCEINLINE ConstReference front() const noexcept - { - return m_data[0]; - } - - /// @brief Returns a reference to the last element. - /// @return Reference to the last element. - GP_NODISCARD GP_FORCEINLINE Reference back() noexcept - { - return m_data[m_size - 1]; - } - - /// @brief Returns a reference to the last element (const). - /// @return Const reference to the last element. - GP_NODISCARD GP_FORCEINLINE ConstReference back() const noexcept - { - return m_data[m_size - 1]; - } - - /// @brief Returns a pointer to the underlying array. - /// @return Pointer to the underlying array. - GP_NODISCARD GP_FORCEINLINE Pointer data() noexcept - { - return m_data; - } - - /// @brief Returns a pointer to the underlying array (const). - /// @return Const pointer to the underlying array. - GP_NODISCARD GP_FORCEINLINE ConstPointer data() const noexcept - { - return m_data; - } - - /// @brief Returns an iterator to the beginning of the vector. - /// @return Iterator to the beginning of the vector. - GP_NODISCARD GP_FORCEINLINE Iterator begin() noexcept - { - return m_data; - } - - /// @brief Returns an iterator to the beginning of the vector (const). - /// @return Const iterator to the beginning of the vector. - GP_NODISCARD GP_FORCEINLINE ConstIterator begin() const noexcept - { - return m_data; - } - - /// @brief Returns an iterator to the end of the vector. - /// @return Iterator to the end of the vector. - GP_NODISCARD GP_FORCEINLINE Iterator end() noexcept - { - return m_data + m_size; - } - - /// @brief Returns an iterator to the end of the vector (const). - /// @return Const iterator to the end of the vector. - GP_NODISCARD GP_FORCEINLINE ConstIterator end() const noexcept - { - return m_data + m_size; - } - - /// @brief Returns a const iterator to the beginning of the vector. - /// @return Const iterator to the beginning of the vector. - GP_NODISCARD GP_FORCEINLINE ConstIterator cbegin() const noexcept - { - return m_data; - } - - /// @brief Returns a const iterator to the end of the vector. - /// @return Const iterator to the end of the vector. - GP_NODISCARD GP_FORCEINLINE ConstIterator cend() const noexcept - { - return m_data + m_size; - } - - /// @brief Returns a reverse iterator to the beginning of the reversed vector. - /// @return Reverse iterator to the beginning of the reversed vector. - GP_NODISCARD GP_FORCEINLINE ReverseIterator rbegin() noexcept - { - return ReverseIterator(end()); - } - - /// @brief Returns a reverse iterator to the beginning of the reversed vector (const). - /// @return Const reverse iterator to the beginning of the reversed vector. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator rbegin() const noexcept - { - return ConstReverseIterator(end()); - } - - /// @brief Returns a reverse iterator to the end of the reversed vector. - /// @return Reverse iterator to the end of the reversed vector. - GP_NODISCARD GP_FORCEINLINE ReverseIterator rend() noexcept - { - return ReverseIterator(begin()); - } - - /// @brief Returns a reverse iterator to the end of the reversed vector (const). - /// @return Const reverse iterator to the end of the reversed vector. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator rend() const noexcept - { - return ConstReverseIterator(begin()); - } - - /// @brief Returns a const reverse iterator to the beginning of the reversed vector. - /// @return Const reverse iterator to the beginning of the reversed vector. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator crbegin() const noexcept - { - return ConstReverseIterator(cend()); - } - - /// @brief Returns a const reverse iterator to the end of the reversed vector. - /// @return Const reverse iterator to the end of the reversed vector. - GP_NODISCARD GP_FORCEINLINE ConstReverseIterator crend() const noexcept - { - return ConstReverseIterator(cbegin()); - } - - /// @brief Returns the number of elements. - /// @return The number of elements in the vector. - GP_NODISCARD GP_FORCEINLINE SizeType size() const noexcept - { - return m_size; - } - - /// @brief Checks if the vector is empty. - /// @return True if the vector is empty, false otherwise. - GP_NODISCARD GP_FORCEINLINE bool isEmpty() const noexcept - { - return m_size == 0; - } - - /// @brief Returns the current allocated capacity. - /// @return The current allocated capacity. - GP_NODISCARD GP_FORCEINLINE SizeType capacity() const noexcept - { - return m_capacity; - } - - /// @brief Returns the maximum possible number of elements. - /// @return The maximum possible number of elements. - GP_NODISCARD constexpr SizeType maxSize() const noexcept - { - return Traits::maxSize(m_allocator); - } - - /// @brief Reserves storage for at least newCap elements. - /// @param[in] newCap Minimum desired capacity. - void reserve(SizeType newCap) - { - if (newCap > m_capacity) - { - _reallocExact(newCap); - } - } - - /// @brief Releases unused capacity, reallocating to fit size(). - void shrinkToFit() - { - if (m_size == 0) - { - if (m_data) - { - Traits::deallocate(m_allocator, m_data, m_capacity); - m_data = nullptr; - m_capacity = 0; - } - } - else if (m_size < m_capacity) - { - _reallocExact(m_size); - } - } - - /// @brief Erases all elements. Does not release memory. - void clear() noexcept - { - _destroyRange(m_data, m_size); - m_size = 0; - } - - /// @brief Appends an element by copy. - /// @param[in] value The value to append. - void pushBack(const T& value) - { - if (m_size == m_capacity) - { - _grow(); - } - Traits::construct(m_allocator, m_data + m_size, value); - ++m_size; - } - - /// @brief Appends an element by move. - /// @param[in] value The value to move-append. - void pushBack(T&& value) - { - if (m_size == m_capacity) - { - _grow(); - } - Traits::construct(m_allocator, m_data + m_size, static_cast(value)); - ++m_size; - } - - /// @brief Constructs an element in-place at the end. - /// @tparam Args Constructor argument types. - /// @param[in] args Arguments forwarded to T's constructor. - /// @return Reference to the newly constructed element. - template - Reference emplaceBack(Args&&... args) - { - if (m_size == m_capacity) - { - _grow(); - } - Traits::construct(m_allocator, m_data + m_size, static_cast(args)...); - return m_data[m_size++]; - } - - /// @brief Removes the last element. - void popBack() noexcept - { - GP_ASSERT(m_size > 0); - --m_size; - Traits::destroy(m_allocator, m_data + m_size); - } - - /// @brief Inserts an element at the given position by copy. - /// @param[in] pos Iterator to the insertion point. - /// @param[in] value The value to insert. - /// @return Iterator to the inserted element. - Iterator insert(ConstIterator pos, const T& value) - { - const SizeType idx = static_cast(pos - m_data); - if (m_size == m_capacity) - { - _grow(); - } - _shiftRight(m_data + idx, m_size - idx); - Traits::construct(m_allocator, m_data + idx, value); - ++m_size; - return m_data + idx; - } - - /// @brief Inserts an element at the given position by move. - /// @param[in] pos Iterator to the insertion point. - /// @param[in] value The value to move-insert. - /// @return Iterator to the inserted element. - Iterator insert(ConstIterator pos, T&& value) - { - const SizeType idx = static_cast(pos - m_data); - if (m_size == m_capacity) - { - _grow(); - } - _shiftRight(m_data + idx, m_size - idx); - Traits::construct(m_allocator, m_data + idx, static_cast(value)); - ++m_size; - return m_data + idx; - } - - /// @brief Inserts count copies of value at the given position. - /// @param[in] pos Iterator to the insertion point. - /// @param[in] count Number of copies to insert. - /// @param[in] value The value to copy. - /// @return Iterator to the first inserted element. - Iterator insert(ConstIterator pos, SizeType count, const T& value) - { - if (count == 0) - { - return const_cast(pos); - } - const SizeType idx = static_cast(pos - m_data); - _ensureCapacity(m_size + count); - _shiftRight(m_data + idx, m_size - idx, count); - for (SizeType i = 0; i < count; ++i) - { - Traits::construct(m_allocator, m_data + idx + i, value); - } - m_size += count; - return m_data + idx; - } - - /// @brief Inserts elements from an initializer list at the given position. - /// @param[in] pos Iterator to the insertion point. - /// @param[in] init The initializer list. - /// @return Iterator to the first inserted element. - Iterator insert(ConstIterator pos, std::initializer_list init) - { - if (init.size() == 0) - { - return const_cast(pos); - } - const SizeType idx = static_cast(pos - m_data); - const SizeType count = init.size(); - _ensureCapacity(m_size + count); - _shiftRight(m_data + idx, m_size - idx, count); - SizeType i = 0; - for (auto& v: init) - { - Traits::construct(m_allocator, m_data + idx + i, v); - ++i; - } - m_size += count; - return m_data + idx; - } - - /// @brief Constructs an element in-place at the given position. - /// @tparam Args Constructor argument types. - /// @param[in] pos Iterator to the insertion point. - /// @param[in] args Arguments forwarded to T's constructor. - /// @return Iterator to the emplaced element. - template - Iterator emplace(ConstIterator pos, Args&&... args) - { - const SizeType idx = static_cast(pos - m_data); - if (m_size == m_capacity) - { - _grow(); - } - _shiftRight(m_data + idx, m_size - idx); - Traits::construct(m_allocator, m_data + idx, static_cast(args)...); - ++m_size; - return m_data + idx; - } - - /// @brief Erases the element at the given position. - /// @param[in] pos Iterator to the element to erase. - /// @return Iterator to the element following the erased one. - Iterator erase(ConstIterator pos) - { - const SizeType idx = static_cast(pos - m_data); - Traits::destroy(m_allocator, m_data + idx); - _shiftLeft(m_data + idx + 1, m_size - idx - 1); - --m_size; - return m_data + idx; - } - - /// @brief Erases elements in the range [first, last). - /// @param[in] first Iterator to the first element to erase. - /// @param[in] last Iterator past the last element to erase. - /// @return Iterator to the element following the last erased one. - Iterator erase(ConstIterator first, ConstIterator last) - { - if (first == last) - { - return const_cast(first); - } - const SizeType idx = static_cast(first - m_data); - const SizeType count = static_cast(last - first); - _destroyRange(m_data + idx, count); - _shiftLeft(m_data + idx + count, m_size - idx - count, count); - m_size -= count; - return m_data + idx; - } - - /// @brief Resizes the vector to contain count elements. - /// @param[in] count New size. - void resize(SizeType count) - { - if (count < m_size) - { - _destroyRange(m_data + count, m_size - count); - m_size = count; - } - else if (count > m_size) - { - _ensureCapacity(count); - _defaultConstructRange(m_data + m_size, count - m_size); - m_size = count; - } - } - - /// @brief Resizes the vector, filling new elements with value. - /// @param[in] count New size. - /// @param[in] value The fill value for new elements. - void resize(SizeType count, const T& value) - { - if (count < m_size) - { - _destroyRange(m_data + count, m_size - count); - m_size = count; - } - else if (count > m_size) - { - _ensureCapacity(count); - _fillConstructRange(m_data + m_size, count - m_size, value); - m_size = count; - } - } - - /// @brief Swaps contents with another vector. - /// @param[in,out] other The vector to swap with. - void swap(Vector& other) noexcept - { - constexpr bool propagate = Traits::PropagateOnContainerSwap::value; - if constexpr (!propagate) - { - GP_ASSERT(m_allocator == other.m_allocator); - } - - Pointer tmp_data = m_data; - SizeType tmp_size = m_size; - SizeType tmp_cap = m_capacity; - m_data = other.m_data; - m_size = other.m_size; - m_capacity = other.m_capacity; - other.m_data = tmp_data; - other.m_size = tmp_size; - other.m_capacity = tmp_cap; - - if constexpr (propagate) - { - AllocatorType tmpAlloc(m_allocator); - _replaceAllocator(other.m_allocator); - other._replaceAllocator(tmpAlloc); - } - } - - /// @brief Returns a copy of the allocator. - /// @return A copy of the allocator used by the vector. - GP_NODISCARD AllocatorType getAllocator() const noexcept - { - return m_allocator; - } - -private: - /// @brief Replaces the allocator via destroy + placement new (works even if operator= is deleted). - /// @param[in] newAlloc The new allocator to set. - void _replaceAllocator(const AllocatorType& newAlloc) noexcept - { - m_allocator.~AllocatorType(); - ::new (static_cast(&m_allocator)) AllocatorType(newAlloc); - } - - /// @brief Replaces the allocator from an rvalue via destroy + placement new. - /// @param[in] newAlloc The new allocator to set. - void _replaceAllocator(AllocatorType&& newAlloc) noexcept - { - m_allocator.~AllocatorType(); - ::new (static_cast(&m_allocator)) AllocatorType(static_cast(newAlloc)); - } - - /// @brief 1.5x growth: newCap = old_cap + (old_cap >> 1), minimum growth of 1. - /// @return The next capacity to grow to. - GP_NODISCARD GP_FORCEINLINE SizeType _nextCapacity() const noexcept - { - if (m_capacity == 0) - { - return 1; - } - const SizeType growth = m_capacity >> 1; - return m_capacity + (growth > 0 ? growth : 1); - } - - /// @brief Grows the backing store by the 1.5x growth factor. - void _grow() - { - _reallocExact(_nextCapacity()); - } - - /// @brief Ensures capacity is at least minCap, growing by 1.5x if needed. - /// @param[in] minCap The minimum required capacity. - void _ensureCapacity(SizeType minCap) - { - if (minCap <= m_capacity) - { - return; - } - SizeType newCap = _nextCapacity(); - while (newCap < minCap) - { - const SizeType growth = newCap >> 1; - newCap = newCap + (growth > 0 ? growth : 1); - } - _reallocExact(newCap); - } - - /// @brief Reallocates storage to exactly newCap, moving existing elements. - /// @param[in] newCap The exact new capacity to allocate. - void _reallocExact(SizeType newCap) - { - Pointer newData = Traits::allocate(m_allocator, newCap); - if (m_size > 0) - { - _relocate(newData, m_data, m_size); - } - if (m_data) - { - Traits::deallocate(m_allocator, m_data, m_capacity); - } - m_data = newData; - m_capacity = newCap; - } - - /// @brief Relocates n elements from src to dst. Uses memcpy for trivial types. - /// @param[in] dst The destination pointer to move elements to. - /// @param[in] src The source pointer to move elements from. - /// @param[in] n The number of elements to relocate. - static void _relocate(Pointer dst, Pointer src, SizeType n) - { - if constexpr (std::is_trivially_copyable_v) - { - std::memcpy(dst, src, n * sizeof(T)); - } - else - { - for (SizeType i = 0; i < n; ++i) - { - ::new (static_cast(dst + i)) T(static_cast(src[i])); - src[i].~T(); - } - } - } - - /// @brief Shifts elements right by 'count' positions for insertion. - /// @param[in] pos The position to start shifting from. - /// @param[in] n The number of elements to shift. - /// @param[in] count The number of positions to shift (default is 1). - void _shiftRight(Pointer pos, SizeType n, SizeType count = 1) - { - if (n == 0) - { - return; - } - if constexpr (std::is_trivially_copyable_v) - { - std::memmove(pos + count, pos, n * sizeof(T)); - } - else - { - for (SizeType i = n; i > 0; --i) - { - ::new (static_cast(pos + i - 1 + count)) T(static_cast(pos[i - 1])); - pos[i - 1].~T(); - } - } - } - - /// @brief Shifts elements left by 'count' positions after erasure. - /// @param[in] pos The position to start shifting from. - /// @param[in] n The number of elements to shift. - /// @param[in] count The number of positions to shift (default is 1). - static void _shiftLeft(Pointer pos, SizeType n, SizeType count = 1) - { - if (n == 0) - { - return; - } - if constexpr (std::is_trivially_copyable_v) - { - std::memmove(pos - count, pos, n * sizeof(T)); - } - else - { - for (SizeType i = 0; i < n; ++i) - { - ::new (static_cast(pos - count + i)) T(static_cast(pos[i])); - pos[i].~T(); - } - } - } - - /// @brief Destroys n elements starting at ptr. - /// @param[in] ptr The pointer to the first element to destroy. - /// @param[in] n The number of elements to destroy. - void _destroyRange(Pointer ptr, SizeType n) - { - if constexpr (!std::is_trivially_destructible_v) - { - for (SizeType i = 0; i < n; ++i) - { - Traits::destroy(m_allocator, ptr + i); - } - } - } - - /// @brief Default-constructs n elements at ptr. - /// @param[in] ptr The pointer to the first element to default-construct. - /// @param[in] n The number of elements to default-construct. - void _defaultConstructRange(Pointer ptr, SizeType n) - { - if constexpr (std::is_trivially_default_constructible_v) - { - std::memset(ptr, 0, n * sizeof(T)); - } - else - { - for (SizeType i = 0; i < n; ++i) - { - Traits::construct(m_allocator, ptr + i); - } - } - } - - /// @brief Copy-constructs n elements at dst from src. - /// @param[in] dst The pointer to the first element to copy-construct. - /// @param[in] src The pointer to the first element to copy from. - /// @param[in] n The number of elements to copy-construct. - void _copyConstructRange(Pointer dst, ConstPointer src, SizeType n) - { - if constexpr (std::is_trivially_copyable_v) - { - std::memcpy(dst, src, n * sizeof(T)); - } - else - { - for (SizeType i = 0; i < n; ++i) - { - Traits::construct(m_allocator, dst + i, src[i]); - } - } - } - - /// @brief Fill-constructs n elements at ptr with value. - /// @param[in] ptr The pointer to the first element to fill-construct. - /// @param[in] n The number of elements to fill-construct. - /// @param[in] value The value to copy for fill-construction. - void _fillConstructRange(Pointer ptr, SizeType n, const T& value) - { - for (SizeType i = 0; i < n; ++i) - { - Traits::construct(m_allocator, ptr + i, value); - } - } - - /// @brief Move-constructs n elements at dst from src. - /// @param[in] dst The pointer to the first element to move-construct. - /// @param[in] src The pointer to the first element to move from. - /// @param[in] n The number of elements to move-construct. - void _moveConstructRange(Pointer dst, Pointer src, SizeType n) - { - if constexpr (std::is_trivially_copyable_v) - { - std::memcpy(dst, src, n * sizeof(T)); - } - else - { - for (SizeType i = 0; i < n; ++i) - { - Traits::construct(m_allocator, dst + i, static_cast(src[i])); - } - } - } - - /// @brief Destroys all elements and frees the backing store. - void _destroyAndFree() - { - _destroyRange(m_data, m_size); - if (m_data) - { - Traits::deallocate(m_allocator, m_data, m_capacity); - m_data = nullptr; - } - m_size = 0; - m_capacity = 0; - } - - /// @brief Common path for copy-assignment and initializer_list assignment. - /// @param[in] src The source pointer to copy from. - /// @param[in] count The number of elements to copy. - void _assignFrom(ConstPointer src, SizeType count) - { - _destroyRange(m_data, m_size); - m_size = 0; - if (count > m_capacity) - { - _reallocExact(count); - } - _copyConstructRange(m_data, src, count); - m_size = count; - } - - /// @brief Common path for move-assignment with unequal allocators. - /// @param[in] src The source pointer to move from. - /// @param[in] count The number of elements to move. - void _assignFromMove(Pointer src, SizeType count) - { - _destroyRange(m_data, m_size); - m_size = 0; - if (count > m_capacity) - { - _reallocExact(count); - } - _moveConstructRange(m_data, src, count); - m_size = count; - } - - /// @brief Initializes from an iterator range, dispatching on iterator category. - /// @tparam InputIt The input iterator type. - /// @param[in] first Iterator to the beginning of the range. - /// @param[in] last Iterator to the end of the range. - template - void _rangeInit(InputIt first, InputIt last) - { - if constexpr (std::is_base_of_v< - std::random_access_iterator_tag, - typename std::iterator_traits::iterator_category>) - { - const SizeType count = static_cast(last - first); - if (count > 0) - { - m_data = Traits::allocate(m_allocator, count); - m_capacity = count; - if constexpr (std::is_trivially_copyable_v && std::is_pointer_v) - { - std::memcpy(m_data, first, count * sizeof(T)); - } - else - { - for (SizeType i = 0; i < count; ++i) - { - Traits::construct(m_allocator, m_data + i, *first); - ++first; - } - } - m_size = count; - } - } - else - { - for (; first != last; ++first) - { - pushBack(*first); - } - } - } -}; - -/// @brief Erases all elements that satisfy the predicate from gp::Vector. -/// @tparam Predicate The type of the predicate function or function object. -/// @param[in,out] vec The vector to erase elements from. -/// @param[in] pred The predicate function or function object that returns true for elements to erase -/// @return The number of erased elements. -template -constexpr typename Vector::SizeType eraseIf(Vector& vec, Predicate pred) -{ - auto it = std::remove_if(vec.begin(), vec.end(), pred); - auto r = static_cast::SizeType>(std::distance(it, vec.end())); - vec.erase(it, vec.end()); - return r; -} - -/// @brief Erases all elements that are equal to value from gp::Vector. -/// @tparam U The type of the value to compare against (can be different from T if T supports heterogeneous equality). -/// @param[in,out] vec The vector to erase elements from. -/// @param[in] value The value to compare against for erasure. -/// @return The number of erased elements. -template -constexpr typename Vector::SizeType erase(Vector& vec, const U& value) -{ - auto it = std::remove(vec.begin(), vec.end(), value); - auto r = static_cast::SizeType>(std::distance(it, vec.end())); - vec.erase(it, vec.end()); - return r; -} - -} // namespace gp diff --git a/source/runtime/core/public/errors/Error.hpp b/source/runtime/core/public/errors/Error.hpp deleted file mode 100644 index c56c36e..0000000 --- a/source/runtime/core/public/errors/Error.hpp +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorCode.hpp" -#include "errors/ErrorRecord.hpp" -#include "errors/ErrorSeverity.hpp" -#include "errors/ErrorSystem.hpp" -#include - -namespace gp::error -{ - -/// @brief Raises an error with the specified severity, code, message, cause, and source location. -/// @param[in] severity The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] code The specific error code representing the type of error. -/// @param[in] message A descriptive message providing details about the error. -/// @param[in] cause An optional shared pointer to an ErrorRecord representing the cause of this error (can be nullptr). -/// @param[in] location The source location where the error was raised (defaults to the current location if not -/// provided). -inline void raise( - Severity severity, - ErrorCode code, - gp::String message, - std::shared_ptr cause = nullptr, - std::source_location location = std::source_location::current() -) -{ - ErrorSystem::dispatch(severity, code, std::move(message), location, std::move(cause)); -} - -/// @brief Raises an error with the specified severity and message. -/// @param[in] severity The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] message A descriptive message providing details about the error. -/// @param[in] location The source location where the error was raised (defaults to the current location if not -/// provided). -inline void - raise(Severity severity, gp::String message, std::source_location location = std::source_location::current()) -{ - ErrorSystem::dispatch(severity, codes::kUnknown, std::move(message), location, nullptr); -} - -/// @brief Wraps an existing error record with additional context and raises a new error. -/// @param[in] inner The existing ErrorRecord to be wrapped as the cause of the new error. -/// @param[in] severity The severity level of the new error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] code The specific error code representing the type of the new error. -/// @param[in] message A descriptive message providing details about the new error. -/// @param[in] location The source location where the new error was raised (defaults to the current location if not -/// provided). -inline void wrap( - const ErrorRecord& inner, - Severity severity, - ErrorCode code, - gp::String message, - std::source_location location = std::source_location::current() -) -{ - ErrorSystem::dispatch(severity, code, std::move(message), location, std::make_shared(inner)); -} - -} // namespace gp::error - -namespace gp -{ - -/// @brief Creates an ErrorRecord with the specified severity, code, message, and source location. -/// @param[in] severity The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] code The specific error code representing the type of error. -/// @param[in] message A descriptive message providing details about the error. -/// @param[in] location The source location where the error was created (defaults to the current location if not -/// provided). -/// @return An ErrorRecord containing the provided information and additional metadata such as timestamps and thread -/// info. -GP_NODISCARD inline error::ErrorRecord makeError( - error::Severity severity, - error::ErrorCode code, - gp::String message, - std::source_location location = std::source_location::current() -) -{ - error::ErrorRecord r; - r.severity = severity; - r.code = code; - r.message = std::move(message); - r.location = location; - r.wallTime = std::chrono::system_clock::now(); - r.engineTime = std::chrono::steady_clock::now(); - r.threadId = std::this_thread::get_id(); - r.threadName = error::ErrorContext::current().threadName(); - return r; -} - -} // namespace gp - -/// @brief Macro to raise an error with the specified severity, code, and message, automatically capturing the source -/// location. -/// @param[in] sev_ The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] code_ The specific error code representing the type of error. -/// @param[in] msg_ A descriptive message providing details about the error. -#define GP_DETAIL_RAISE(sev_, code_, msg_) \ - ::gp::error::ErrorSystem::dispatch((sev_),(code_),(msg_),std::source_location::current()) - -/// @brief Macro to raise an error with a specific severity and code, using the GP_DETAIL_RAISE macro. -/// @param[in] sev_ The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] code_ The specific error code representing the type of error. -/// @param[in] msg_ A descriptive message providing details about the error. -#define GP_RAISE_CODE(sev_, code_, msg_) GP_DETAIL_RAISE((sev_),(code_),(msg_)) - -/// @brief Macro to raise an error with a specific severity and message, using the GP_DETAIL_RAISE macro with an unknown -/// error code. -/// @param[in] sev_ The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] msg_ A descriptive message providing details about the error. -#define GP_RAISE(sev_, msg_) GP_DETAIL_RAISE((sev_),::gp::error::codes::kUnknown,(msg_)) - -/// @brief Macro to raise a formatted error message with a specific severity and code, using the GP_DETAIL_RAISE macro. -/// @param[in] sev_ The severity level of the error (e.g., trace, debug, info, warning, error, fatal). -/// @param[in] code_ The specific error code representing the type of error. -/// @param[in] fmt_ A format string for the error message. -/// @param[in] ... Additional arguments to be formatted into the error message. -#define GP_RAISE_FMT(sev_, code_, fmt_, ...) GP_DETAIL_RAISE((sev_),(code_),gp::String::format((fmt_),__VA_ARGS__)) - -/// @brief Macro to raise a trace-level error with a specific message. -/// @param[in] m_ A descriptive message providing details about the trace event. -#define GP_TRACE(m_) GP_RAISE(::gp::error::trace, (m_)) - -/// @brief Macro to raise a debug-level error with a specific message. -/// @param[in] m_ A descriptive message providing details about the debug event. -#define GP_DEBUG(m_) GP_RAISE(::gp::error::debug,(m_)) - -/// @brief Macro to raise an info-level error with a specific message. -/// @param[in] m_ A descriptive message providing details about the info event. -#define GP_INFO(m_) GP_RAISE(::gp::error::info,(m_)) - -/// @brief Macro to raise a warning-level error with a specific message. -/// @param[in] m_ A descriptive message providing details about the warning event. -#define GP_WARN(m_) GP_RAISE(::gp::error::warning,(m_)) - -/// @brief Macro to raise an error-level error with a specific message. -/// @param[in] m_ A descriptive message providing details about the error event. -#define GP_ERROR(m_) GP_RAISE(::gp::error::error,(m_)) - -/// @brief Macro to raise a fatal-level error with a specific message. -/// @param[in] m_ A descriptive message providing details about the fatal event. -#define GP_FATAL(m_) GP_RAISE(::gp::error::fatal,(m_)) - -/// @brief Macro to raise a critical-level error (panic) with a specific message. -/// @param[in] m_ A descriptive message providing details about the critical event. -#define GP_PANIC(m_) GP_RAISE(::gp::error::critical,(m_)) diff --git a/source/runtime/core/public/errors/ErrorCode.hpp b/source/runtime/core/public/errors/ErrorCode.hpp deleted file mode 100644 index bd650d6..0000000 --- a/source/runtime/core/public/errors/ErrorCode.hpp +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include // IWYU pragma: keep - -namespace gp::error -{ - -/// @brief Domain enumeration, each engine subsystem owns a unique domain for its error codes. -/// @note -/// - Domains 0x00–0x0F are reserved for core engine systems (e.g. memory, threading, IO). -/// - Domains 0x10–0x1F are reserved for graphics/RHI-related systems (e.g. renderer, shader, texture). -/// - Domains 0x20–0x2F are reserved for audio-related systems (e.g. audio device, mixer). -/// - Domains 0x30–0x3F are reserved for simulation-related systems (e.g. physics, animation, AI). -/// - Domains 0x40–0x4F are reserved for platform/OS-related systems (e.g. windowing, input, network). -/// - Domains 0x50–0x5F are reserved for gameplay-related systems (e.g. scripting, asset/scene management). -/// - Domains 0xE0–0xFF are reserved for user-defined project-level codes. -enum class Domain : gp::UInt8 -{ - // Core engine - Generic = 0x00, - Memory = 0x01, - Threading = 0x02, - IO = 0x03, - Serialization = 0x04, - Plugin = 0x05, - - // Graphics / RHI - RHI = 0x10, - Renderer = 0x11, - Shader = 0x12, - Texture = 0x13, - Mesh = 0x14, - - // Audio - Audio = 0x20, - AudioDevice = 0x21, - - // Simulation - Physics = 0x30, - Animation = 0x31, - AI = 0x32, - - // Platform / OS - Platform = 0x40, - Window = 0x41, - Input = 0x42, - Network = 0x43, - - // Gameplay - Script = 0x50, - Asset = 0x51, - Scene = 0x52, - Entity = 0x53, - - // User-defined range, reserve 0xE0–0xFF for project-level codes - UserDefined = 0xE0, - - COUNT = 0xFF -}; - -/// @brief Value-semantic, 32-bit error code class that encapsulates a domain and a specific error code within that -/// domain. -/// @note -/// The high 16 bits represent the domain, and the low 16 bits represent the specific error code. A value of 0 -/// represents success, while any non-zero value represents an error. The class provides utility functions for checking -/// success/failure and retrieving the domain and code. -class ErrorCode -{ -private: - gp::UInt32 m_value{ 0u }; - -public: - /// @brief Default constructor, creates a success code (0). - constexpr ErrorCode() noexcept = default; - - /// @brief Constructs an ErrorCode from a domain and a code. - /// @param[in] domain The domain of the error code. - /// @param[in] code The specific error code within the domain. - constexpr ErrorCode(Domain domain, gp::UInt16 code) noexcept - : m_value((static_cast(domain) << 16u) | static_cast(code)) - {} - - /// @brief Creates an ErrorCode from a raw 32-bit value. - /// @param[in] rawValue The raw error code value. - explicit constexpr ErrorCode(gp::UInt32 rawValue) noexcept - : m_value(rawValue) - {} - -public: - /// @brief Enables implicit conversion to bool, allowing ErrorCode to be used in boolean contexts. - /// @return True if the error code represents an error, false if it represents success. - explicit constexpr operator bool() const noexcept - { - return isError(); - } - - /// @brief Enables three-way comparison between ErrorCode instances. - /// @note This allows for comparisons using ==, !=, <, >, <=, >= operators. - /// @param[in] other The other ErrorCode to compare with. - /// @return A std::strong_ordering value indicating the result of the comparison. - constexpr auto operator<=>(const ErrorCode&) const noexcept = default; - -public: - /// @brief Returns the domain of the error code. - /// @return The domain. - GP_NODISCARD constexpr Domain domain() const noexcept - { - return static_cast((m_value >> 16u) & 0xFFu); - } - - /// @brief Returns the error code within its domain. - /// @return The error code. - GP_NODISCARD constexpr gp::UInt16 code() const noexcept - { - return static_cast(m_value & 0xFFFFu); - } - - /// @brief Returns the raw value of the error code. - /// @return The raw error code value. - GP_NODISCARD constexpr gp::UInt32 raw() const noexcept - { - return m_value; - } - - /// @brief Checks if the error code represents a successful operation. - /// @return True if the code represents a success, false otherwise. - GP_NODISCARD constexpr bool isOk() const noexcept - { - return m_value == 0u; - } - - /// @brief Checks if the error code represents an error. - /// @return True if the code represents an error, false otherwise. - GP_NODISCARD constexpr bool isError() const noexcept - { - return m_value != 0u; - } - -public: - /// @brief Returns a successful error code. - /// @return A success code (0u). - static constexpr ErrorCode ok() noexcept - { - return ErrorCode{ 0u }; - } - - /// @brief Returns an unknown error code. - /// @return An error code with all bits set (0xFFFF'FFFF), representing an unknown error. - static constexpr ErrorCode unknown() noexcept - { - return ErrorCode{ 0xFFFF'FFFFu }; - } -}; - -// Pre-defined error codes for common scenarios, organized by domain. -// Extend this list by adding new codes in the gp::error::codes namespace for your specific subsystem. -namespace codes -{ - -// Generic -inline constexpr ErrorCode kOk{ Domain::Generic, 0x0000 }; -inline constexpr ErrorCode kUnknown{ Domain::Generic, 0x0001 }; -inline constexpr ErrorCode kNotImplemented{ Domain::Generic, 0x0002 }; -inline constexpr ErrorCode kInvalidArgument{ Domain::Generic, 0x0003 }; -inline constexpr ErrorCode kOutOfRange{ Domain::Generic, 0x0004 }; -inline constexpr ErrorCode kNullPointer{ Domain::Generic, 0x0005 }; -inline constexpr ErrorCode kTimeout{ Domain::Generic, 0x0006 }; -inline constexpr ErrorCode kNotFound{ Domain::Generic, 0x0007 }; -inline constexpr ErrorCode kAlreadyExists{ Domain::Generic, 0x0008 }; -inline constexpr ErrorCode kPermission{ Domain::Generic, 0x0009 }; - -// Memory -inline constexpr ErrorCode kOutOfMemory{ Domain::Memory, 0x0001 }; -inline constexpr ErrorCode kAlignmentFault{ Domain::Memory, 0x0002 }; -inline constexpr ErrorCode kHeapCorruption{ Domain::Memory, 0x0003 }; - -// IO -inline constexpr ErrorCode kFileNotFound{ Domain::IO, 0x0001 }; -inline constexpr ErrorCode kFileOpenFailed{ Domain::IO, 0x0002 }; -inline constexpr ErrorCode kFileReadFailed{ Domain::IO, 0x0003 }; -inline constexpr ErrorCode kFileWriteFailed{ Domain::IO, 0x0004 }; -inline constexpr ErrorCode kEOF{ Domain::IO, 0x0005 }; - -// RHI -inline constexpr ErrorCode kDeviceLost{ Domain::RHI, 0x0001 }; -inline constexpr ErrorCode kSwapchainFail{ Domain::RHI, 0x0002 }; -inline constexpr ErrorCode kShaderCompile{ Domain::Shader, 0x0001 }; -inline constexpr ErrorCode kPipelineCreate{ Domain::RHI, 0x0003 }; - -// Platform -inline constexpr ErrorCode kWindowCreate{ Domain::Window, 0x0001 }; -inline constexpr ErrorCode kWindowResize{ Domain::Window, 0x0002 }; -inline constexpr ErrorCode kInputInit{ Domain::Input, 0x0001 }; -inline constexpr ErrorCode kNetConnect{ Domain::Network, 0x0001 }; - -// Audio -inline constexpr ErrorCode kAudioDeviceInit{ Domain::AudioDevice, 0x0001 }; - -} // namespace codes - -/// @brief Returns a human-readable name for a given error domain. -/// @param[in] domain The error domain to get the name of. -/// @return A string view containing the name of the domain, or "" if the domain is not recognized. -GP_NODISCARD constexpr gp::StringView getDomainName(Domain domain) noexcept -{ - switch (domain) - { - // clang-format off - case Domain::Generic: return "Generic"; - case Domain::Memory: return "Memory"; - case Domain::Threading: return "Threading"; - case Domain::IO: return "IO"; - case Domain::Serialization: return "Serialization"; - case Domain::Plugin: return "Plugin"; - case Domain::RHI: return "RHI"; - case Domain::Renderer: return "Renderer"; - case Domain::Shader: return "Shader"; - case Domain::Texture: return "Texture"; - case Domain::Mesh: return "Mesh"; - case Domain::Audio: return "Audio"; - case Domain::AudioDevice: return "AudioDevice"; - case Domain::Physics: return "Physics"; - case Domain::Animation: return "Animation"; - case Domain::AI: return "AI"; - case Domain::Platform: return "Platform"; - case Domain::Window: return "Window"; - case Domain::Input: return "Input"; - case Domain::Network: return "Network"; - case Domain::Script: return "Script"; - case Domain::Asset: return "Asset"; - case Domain::Scene: return "Scene"; - case Domain::Entity: return "Entity"; - case Domain::UserDefined: return "UserDefined"; - default: return ""; - // clang-format on - } -} - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/ErrorConfig.hpp b/source/runtime/core/public/errors/ErrorConfig.hpp deleted file mode 100644 index 26eabd1..0000000 --- a/source/runtime/core/public/errors/ErrorConfig.hpp +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorSeverity.hpp" - -namespace gp::error -{ - -/// @brief Configuration for the stacktrace capture behavior of the error system. -struct StacktraceConfig -{ - // Capture stack traces for records at or above this severity. - // Set to Severity::Critical to capture only on process-ending events. - Severity captureFrom{ Severity::Error }; - - // Maximum number of frames to capture. Higher = more overhead. - gp::USize maxFrames{ 64u }; - - // How many frames to skip from the bottom (hides the error-system internals). - gp::USize skipFrames{ 3u }; - - // Master switch, disable entirely for profiling/release. - bool enabled{ true }; -}; - -/// @brief Configuration for the error system's breakpoint behavior. -struct BreakpointConfig -{ - // Fire __debugbreak / SIGTRAP at or above this severity (Debug builds only). - Severity breakFrom{ Severity::Error }; - - // Only fire when a native debugger is attached (avoids crashing in CI). - bool checkIsDebugged{ true }; -}; - -/// @brief Configuration for the error system's process-abort behavior. -struct AbortConfig -{ - // Abort the process at or above this severity. - Severity abortFrom{ Severity::Fatal }; - - // When true, call std::terminate() instead of std::abort(). - bool useTerminate{ false }; - - // When true, flush all sinks before aborting so no records are lost. - bool flushBeforeAbort{ true }; -}; - -/// @brief Configuration for the error system's filtering behavior. -struct FilterConfig -{ - // Global minimum severity, records below this are never dispatched to any sink. - // Useful for shipping builds: set to Severity::Warning to strip all traces. - Severity globalMinSeverity{ Severity::Trace }; - - // When true, ignore duplicate records (same code + message + thread) within the dedup window below. - bool deduplicate{ false }; - - // Time window in milliseconds for deduplication. - gp::USize dedupWindowMs{ 1000u }; -}; - -/// @brief Configuration for the error system's thread handling. -struct ThreadConfig -{ - // Maximum thread-name length stored in ErrorRecord (truncated beyond this). - gp::USize maxThreadNameLength{ 32u }; -}; - -/// @brief Root configuration object for the error system, containing all sub-configurations and global settings. -struct ErrorSystemConfig -{ -public: - StacktraceConfig stacktrace; - BreakpointConfig breakpoint; - AbortConfig abort; - FilterConfig filter; - ThreadConfig thread; - - // When true, the ConsoleSink is automatically added during initialization. - bool addDefaultConsoleSink{ true }; - - // Path for the default FileSink (empty = no default file sink). - gp::String defaultLogFilePath; // TODO: gp::Path? - - // When true, emit a header banner to the console on initialization. - bool printBannerOnInit{ true }; - -public: - /// @brief Factory method for a preset development configuration (all features on). - /// @return An ErrorSystemConfig instance with development settings. - GP_NODISCARD static inline ErrorSystemConfig getDevelopmentConfig() noexcept - { - ErrorSystemConfig config; - config.stacktrace.captureFrom = Severity::Warning; - config.breakpoint.breakFrom = Severity::Error; - config.abort.abortFrom = Severity::Fatal; - config.filter.globalMinSeverity = Severity::Trace; - config.filter.deduplicate = false; - return config; - } - - /// @brief Factory method for a preset staging configuration (some features on, some off). - /// @return An ErrorSystemConfig instance with staging settings. - GP_NODISCARD static inline ErrorSystemConfig getStagingConfig() noexcept - { - ErrorSystemConfig config; - config.stacktrace.captureFrom = Severity::Error; - config.breakpoint.breakFrom = Severity::Critical; // Rarely fires in CI - config.abort.abortFrom = Severity::Fatal; - config.filter.globalMinSeverity = Severity::Info; - config.filter.deduplicate = true; - config.filter.dedupWindowMs = 2000; - return config; - } - - /// @brief Factory method for a preset shipping configuration (most features off for performance). - /// @return An ErrorSystemConfig instance with shipping settings. - GP_NODISCARD static inline ErrorSystemConfig getShippingConfig() noexcept - { - ErrorSystemConfig config; - config.stacktrace.enabled = false; // No stack traces - config.breakpoint.breakFrom = Severity::Critical; // Never in practice - config.abort.abortFrom = Severity::Fatal; - config.filter.globalMinSeverity = Severity::Warning; // Strip trace/debug/info - config.filter.deduplicate = true; - config.addDefaultConsoleSink = false; // No console in ship - config.printBannerOnInit = false; - return config; - } - - /// @brief Factory method for a preset test configuration (strict settings for testing). - /// @return An ErrorSystemConfig instance with test settings. - GP_NODISCARD static inline ErrorSystemConfig getTestConfig() noexcept - { - ErrorSystemConfig config; - config.stacktrace.captureFrom = Severity::Fatal; - config.breakpoint.breakFrom = Severity::Critical; - config.abort.abortFrom = Severity::Critical; - config.filter.globalMinSeverity = Severity::Trace; - config.addDefaultConsoleSink = false; - config.printBannerOnInit = false; - return config; - } -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/ErrorContext.hpp b/source/runtime/core/public/errors/ErrorContext.hpp deleted file mode 100644 index 4713190..0000000 --- a/source/runtime/core/public/errors/ErrorContext.hpp +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "container/Vector.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorRecord.hpp" - -namespace gp::error -{ - -/// @brief Represents a single frame in the error context stack. -struct ContextFrame -{ - gp::String subsystem; // m_stack; - gp::String m_threadName; - -private: - /// @brief Private constructor to enforce singleton pattern. Use ErrorContext::current() to access the instance. - ErrorContext() = default; - -public: - /// @brief Delete copy constructor and assignment operator to enforce singleton pattern. - ErrorContext(const ErrorContext&) = delete; - ErrorContext& operator=(const ErrorContext&) = delete; - -public: - /// @brief Push a new frame onto the stack, describing the current subsystem and operation. - /// @param[in] subsystem Typically a high-level module name, e.g. "Renderer", "Audio" - /// @param[in] operation Typically a specific action, e.g. "LoadTexture", "OpenDevice" - void push(gp::String subsystem, gp::String operation); - - /// @brief Pop the most recent frame from the stack. No-op if stack is empty. - void pop() noexcept; - - /// @brief Attach a key/value tag to the *top* frame. No-op if stack is empty. - /// @param[in] key A short identifier, e.g. "filename", "error_code" - /// @param[in] value A string representation of the value, e.g. "assets/texture.png", "0xDEADBEEF" - void tag(gp::String key, gp::String value); - - /// @brief Check if the stack is empty (i.e. no context frames). - /// @return True if the stack is empty, false otherwise. - GP_NODISCARD bool isEmpty() const noexcept; - - /// @brief Get the current depth of the stack (i.e. number of context frames). - /// @return The number of frames currently on the stack. - GP_NODISCARD gp::USize depth() const noexcept; - - /// @brief Get a const reference to the current stack of context frames. - /// @return A const reference to the vector of context frames. May be empty if no frames have been pushed. - GP_NODISCARD const gp::Vector& frames() const noexcept; - - /// @brief Get the subsystem of the current (top) frame, or an empty string if the stack is empty. - /// @return The subsystem of the current frame, or an empty string if the stack is empty. - GP_NODISCARD gp::StringView currentSubsystem() const noexcept; - - /// @brief Get the flattened context as a MetaBag, suitable for attaching to an ErrorRecord. This will include all - /// frames and tags, with keys formatted as "scope[i].subsystem", "scope[i].operation", and "scope[i].tagkey". - /// @return A MetaBag containing all context information from the stack, flattened into key/value pairs. - GP_NODISCARD MetaBag flatten() const; - - /// @brief Set the name of the current thread (for debugging purposes). - /// @note - /// This is purely informational and does not affect thread behavior. - /// It can be used to make error reports more readable by indicating which thread they came from. - /// @param[in] name A human-readable name for the thread, e.g. "MainThread", "WorkerThread1". - void setThreadName(gp::String name); - - /// @brief Get the name of the current thread. - /// @return The name of the current thread, or an empty string if no name has been set. - GP_NODISCARD const gp::String& threadName() const noexcept; - -public: - /// @brief Get the current error context instance. - /// @note This is a thread-local singleton; each thread has its own independent context stack. - /// @return A reference to the current error context instance. - static ErrorContext& current() noexcept - { - thread_local ErrorContext instance; - return instance; - } -}; - -/// @brief RAII guard that pushes a new context frame on construction and pops it on destruction. -/// This is intended to be used with the GP_ERROR_SCOPE macro for convenient scoping of error contexts. -class ContextScope -{ -public: - /// @brief Construct a new ContextScope, pushing a new frame onto the error context stack. The frame will be popped - /// automatically when this object is destroyed (e.g. at the end of the enclosing block). - /// @param[in] subsystem The subsystem name for this scope, e.g. "Renderer", "Audio" - /// @param[in] operation The operation name for this scope, e.g. "LoadTexture", "OpenDevice" - explicit ContextScope(gp::String subsystem, gp::String operation); - - /// @brief Destructor that pops the context frame from the stack. - ~ContextScope() noexcept; - - // Non-copyable, non-movable (RAII identity must be stable) - ContextScope(const ContextScope&) = delete; - ContextScope& operator=(const ContextScope&) = delete; - ContextScope(ContextScope&&) = delete; - ContextScope& operator=(ContextScope&&) = delete; - -public: - /// @brief Attach a key/value tag to this scope. Chainable. - /// @param[in] key A short identifier for the tag, e.g. "filename", "error_code" - /// @param[in] value A string representation of the value, e.g. "assets/texture.png", "0xDEADBEEF" - /// @return A reference to this ContextScope, allowing for chaining multiple tags. - ContextScope& tag(gp::String key, gp::String value); -}; - -} // namespace gp::error - -/// @brief Create a new error scope with the given subsystem and operation. -/// @param[in] subsystem The subsystem name for this scope, e.g. "Renderer", "Audio" -/// @param[in] operation The operation name for this scope, e.g. "LoadTexture", "OpenDevice", etc. -#define GP_ERROR_SCOPE(subsystem_, op_) \ - ::gp::error::ContextScope GP_CONCAT(gp_err_scope_, __LINE__){ (subsystem_), (op_) } - -/// @brief Attach a key/value tag to the innermost active scope on this thread. -/// @param[in] key A short identifier for the tag, e.g. "filename", "error_code" -/// @param[in] value A string representation of the value, e.g. "assets/texture.png", "0xDEADBEEF", etc. -#define GP_ERROR_TAG(key_, value_) \ - ::gp::error::ErrorContext::current().tag((key_), gp::String::format("{}", (value_))) - -/// @brief Set the name of the current thread (for debugging purposes). -/// @param[in] name A human-readable name for the thread, e.g. "MainThread", "WorkerThread1", etc. -#define GP_THREAD_NAME(name_) \ - ::gp::error::ErrorContext::current().setThreadName(name_) diff --git a/source/runtime/core/public/errors/ErrorFilter.hpp b/source/runtime/core/public/errors/ErrorFilter.hpp deleted file mode 100644 index f076f4e..0000000 --- a/source/runtime/core/public/errors/ErrorFilter.hpp +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorRecord.hpp" -#include "errors/ErrorRegistry.hpp" -#include "errors/ErrorSeverity.hpp" -#include // TODO: gp::Atomic? -#include // TODO: gp::TimePoint?, gp::Duration?, etc. -#include // TODO: gp::Predicate? gp::Function? -#include // TODO: gp::SharedPtr? -#include // TODO: gp::Regex? - -namespace gp::error -{ - -/// @brief A value-semantic, composable predicate for filtering ErrorRecords. -class FilterPredicate -{ -public: - using FunctionType = std::function; - -private: - FunctionType m_func; - -public: - /// @brief Construct a FilterPredicate from any callable with the appropriate signature. - /// @param[in] func A callable that takes a const ErrorRecord& and returns bool. - explicit FilterPredicate(FunctionType func) - : m_func(std::move(func)) - {} - -public: - /// @brief Evaluate the predicate on a given ErrorRecord. - /// @param[in] record The ErrorRecord to evaluate. - /// @return true if the record matches the predicate, false otherwise. - GP_NODISCARD bool operator()(const ErrorRecord& record) const - { - return m_func(record); - } - - /// @brief Combine this predicate with another using logical AND. - /// @param[in] other Another FilterPredicate to combine with. - /// @return A new FilterPredicate that represents the logical AND of this and the other predicate. - GP_NODISCARD FilterPredicate operator&&(const FilterPredicate& other) const - { - auto lhs = m_func, rhs = other.m_func; - return FilterPredicate{ [lhs, rhs](const ErrorRecord& record) - { - return lhs(record) && rhs(record); - } }; - } - - /// @brief Combine this predicate with another using logical OR. - /// @param[in] other Another FilterPredicate to combine with. - /// @return A new FilterPredicate that represents the logical OR of this and the other predicate. - GP_NODISCARD FilterPredicate operator||(const FilterPredicate& other) const - { - auto lhs = m_func, rhs = other.m_func; - return FilterPredicate{ [lhs, rhs](const ErrorRecord& record) - { - return lhs(record) || rhs(record); - } }; - } - - /// @brief Negate this predicate. - /// @return A new FilterPredicate that represents the logical NOT of this predicate. - GP_NODISCARD FilterPredicate operator!() const - { - auto lhs = m_func; - return FilterPredicate{ [lhs](const ErrorRecord& record) - { - return !lhs(record); - } }; - } -}; - -namespace filters -{ - -/// @brief Predicate that returns true for records with severity at least @p severity. -/// @param[in] severity The minimum severity level to match. -/// @return A FilterPredicate that matches records with severity >= severity. -GP_NODISCARD inline FilterPredicate atLeast(Severity severity) -{ - return FilterPredicate{ [severity](const ErrorRecord& record) - { - return record.severity >= severity; - } }; -} - -/// @brief Predicate that returns true for records with severity at most @p severity. -/// @param[in] severity The maximum severity level to match. -/// @return A FilterPredicate that matches records with severity <= severity. -GP_NODISCARD inline FilterPredicate atMost(Severity severity) -{ - return FilterPredicate{ [severity](const ErrorRecord& record) - { - return record.severity <= severity; - } }; -} - -/// @brief Predicate that returns true for records with severity exactly @p severity. -/// @param[in] severity The severity level to match. -/// @return A FilterPredicate that matches records with severity == severity. -GP_NODISCARD inline FilterPredicate exactly(Severity severity) -{ - return FilterPredicate{ [severity](const ErrorRecord& record) - { - return record.severity == severity; - } }; -} - -/// @brief Predicate that returns true for records with severity in the range [minimumSeverity, maximumSeverity]. -/// @param[in] minimumSeverity The minimum severity level to match (inclusive). -/// @param[in] maximumSeverity The maximum severity level to match (inclusive). -/// @return A FilterPredicate that matches records with severity in the specified range. -GP_NODISCARD inline FilterPredicate severityRange(Severity minimumSeverity, Severity maximumSeverity) -{ - return FilterPredicate{ [minimumSeverity, maximumSeverity](const ErrorRecord& record) - { - return record.severity >= minimumSeverity && record.severity <= maximumSeverity; - } }; -} - -/// @brief Predicate that returns true for records with a specific domain. -/// @param[in] domain The domain to match. -/// @return A FilterPredicate that matches records with the specified domain. -GP_NODISCARD inline FilterPredicate domain(Domain domain) -{ - return FilterPredicate{ [domain](const ErrorRecord& record) - { - return record.code.domain() == domain; - } }; -} - -/// @brief Predicate that returns true for records with a specific error code. -/// @param[in] code The error code to match. -/// @return A FilterPredicate that matches records with the specified error code. -GP_NODISCARD inline FilterPredicate code(ErrorCode code) -{ - return FilterPredicate{ [code](const ErrorRecord& record) - { - return record.code == code; - } }; -} - -/// @brief Predicate that returns true for records with any of the specified error codes. -/// @param[in] codes An initializer list of error codes to match. -/// @return A FilterPredicate that matches records with any of the specified error codes. -GP_NODISCARD inline FilterPredicate anyCode(std::initializer_list codes) -{ - std::vector v{ codes }; - return FilterPredicate{ [v](const ErrorRecord& record) - { - for (const auto& c: v) - { - if (record.code == c) - { - return true; - } - } - return false; - } }; -} - -/// @brief Predicate that returns true for records originating from a specific subsystem. -/// @param[in] name The name of the subsystem to match. -/// @return A FilterPredicate that matches records from the specified subsystem. -GP_NODISCARD inline FilterPredicate subsystem(gp::String name) -{ - return FilterPredicate{ [name](const ErrorRecord& record) - { - return record.subsystem == name; - } }; -} - -/// @brief Predicate that returns true for records originating from a specific thread. -/// @param[in] name The name of the thread to match. -/// @return A FilterPredicate that matches records from the specified thread. -GP_NODISCARD inline FilterPredicate thread(gp::String name) -{ - return FilterPredicate{ [name](const ErrorRecord& record) - { - return record.threadName == name; - } }; -} - -/// @brief Predicate that returns true for records whose message contains a specific substring. -/// @param[in] needle The substring to search for in the message. -/// @return A FilterPredicate that matches records whose message contains the specified substring. -GP_NODISCARD inline FilterPredicate messageContains(gp::String needle) -{ - return FilterPredicate{ [needle](const ErrorRecord& record) - { - return record.message.find(needle) != gp::String::npos; - } }; -} - -/// @brief Predicate that returns true for records whose message matches a regex pattern. -/// @param[in] pattern The regex pattern to match against the message. -/// @return A FilterPredicate that matches records whose message matches the specified regex pattern. -GP_NODISCARD inline FilterPredicate messageMatches(const gp::String& pattern) -{ - auto re = std::make_shared(pattern.cStr()); - return FilterPredicate{ [re](const ErrorRecord& record) - { - return std::regex_search(record.message.cStr(), *re); - } }; -} - -/// @brief Predicate that returns true for records originating from a source file whose path contains a specific -/// substring. -/// @param[in] path The substring to search for in the source file path. -/// @return A FilterPredicate that matches records originating from source files whose path contains the specified -/// substring. -GP_NODISCARD inline FilterPredicate sourceFile(gp::String path) -{ - return FilterPredicate{ [path](const ErrorRecord& record) - { - return gp::StringView{ record.location.file_name() }.find(path) != gp::StringView::npos; - } }; -} - -/// @brief Predicate that returns true for records that have a specific metadata key-value pair. -/// @param[in] key The metadata key to check for. -/// @param[in] value The metadata value to match for the specified key. -/// @return A FilterPredicate that matches records that have the specified metadata key-value pair. -GP_NODISCARD inline FilterPredicate hasMeta(gp::String key, gp::String value) -{ - return FilterPredicate{ [key, value](const ErrorRecord& r) - { - return r.getMetadata(key) == value; - } }; -} - -/// @brief Predicate that returns true for records that have a specific metadata key, regardless of its value. -/// @param[in] key The metadata key to check for. -/// @return A FilterPredicate that matches records that have the specified metadata key. -GP_NODISCARD inline FilterPredicate hasMetaKey(gp::String key) -{ - return FilterPredicate{ [key](const ErrorRecord& record) - { - return !record.getMetadata(key).isEmpty(); - } }; -} - -/// @brief Predicate that returns true for records raised after a specific time point (wall clock). -/// @param[in] when The time point to compare against (records raised after this time will match). -/// @return A FilterPredicate that matches records raised after the specified time point. -GP_NODISCARD inline FilterPredicate after(std::chrono::system_clock::time_point when) -{ - return FilterPredicate{ [when](const ErrorRecord& record) - { - return record.wallTime > when; - } }; -} - -/// @brief Predicate that returns true for records raised before a specific time point (wall clock). -/// @param[in] when The time point to compare against (records raised before this time will match). -/// @return A FilterPredicate that matches records raised before the specified time point. -GP_NODISCARD inline FilterPredicate before(std::chrono::system_clock::time_point when) -{ - return FilterPredicate{ [when](const ErrorRecord& record) - { - return record.wallTime < when; - } }; -} - -/// @brief Predicate that matches all records (always returns true). -/// @return A FilterPredicate that matches all records. -GP_NODISCARD inline FilterPredicate acceptAll() -{ - return FilterPredicate{ [](const ErrorRecord&) - { - return true; - } }; -} - -/// @brief Predicate that matches no records (always returns false). -/// @return A FilterPredicate that matches no records. -GP_NODISCARD inline FilterPredicate rejectAll() -{ - return FilterPredicate{ [](const ErrorRecord&) - { - return false; - } }; -} - -/// @brief Predicate that returns true for records that have a non-empty cause (i.e., were raised with a cause). -/// @return A FilterPredicate that matches records that have a cause. -GP_NODISCARD inline FilterPredicate hasCause() -{ - return FilterPredicate{ [](const ErrorRecord& record) - { - return record.hasCause(); - } }; -} - -/// @brief Predicate that returns true for records that are marked as expected in the registry. -/// @return A FilterPredicate that matches records that are expected according to the registry. -GP_NODISCARD inline FilterPredicate isExpected() -{ - return FilterPredicate{ [](const ErrorRecord& record) - { - return ErrorRegistry::instance().isExpected(record.code); - } }; -} - -/// @brief Predicate that returns true for a random sample of records, with a sampling rate of 1 in N. -/// @param[in] oneInN The sampling rate, where 1 in N records will be accepted on average. -/// @return A FilterPredicate that matches a random sample of records at the specified rate. -GP_NODISCARD inline FilterPredicate sample(gp::UInt32 oneInN) -{ - auto counter = std::make_shared>(0u); - return FilterPredicate{ [counter, oneInN](const ErrorRecord&) - { - if (oneInN == 0) - { - return true; // Avoid division by zero, treat as accept all - } - return counter->fetch_add(1, std::memory_order_relaxed) % oneInN == 0; - } }; -} - -} // namespace filters - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/ErrorRecord.hpp b/source/runtime/core/public/errors/ErrorRecord.hpp deleted file mode 100644 index 8b1c991..0000000 --- a/source/runtime/core/public/errors/ErrorRecord.hpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "container/Vector.hpp" -#include "CoreMinimal.hpp" // IWYU pragma: keep -#include "errors/ErrorCode.hpp" -#include "errors/ErrorSeverity.hpp" -#include // TODO: gp::TimePoint?, gp::Duration?, etc. -#include // TODO: gp::SharedPtr? -#include -#include // TODO: gp::Thread? - -// clang-format off -#if defined(__cpp_lib_stacktrace) && __cpp_lib_stacktrace >= 202011L - #include - #define GP_HAS_STACKTRACE 1 - using GpStacktrace = std::stacktrace; -#else - #define GP_HAS_STACKTRACE 0 - struct GpStacktrace - { - GP_NODISCARD static GpStacktrace current(std::size_t = 0, std::size_t = 0) { return {}; } - GP_NODISCARD bool empty() const { return true; } - GP_NODISCARD std::size_t size() const { return 0; } - }; -#endif -// clang-format on - -namespace gp::error -{ - -/// @brief A typed key/value pair attached to an ErrorRecord. -/// Stored inline (small-string optimized) to avoid heap allocations on the hot path when only a handful of tags are -/// attached. -struct MetaEntry -{ - gp::String key; - gp::String value; -}; - -/// @brief A vector of metadata entries attached to an ErrorRecord. -using MetaBag = gp::Vector; - -/// @brief The canonical error snapshot. -class ErrorRecord -{ -public: - Severity severity{ Severity::Error }; - ErrorCode code{ ErrorCode::ok() }; - - // Pre-formatted message string. - gp::String message; - // Optional subsystem tag ("RHI", "Audio"…). - gp::String subsystem; - - // Source location (zero overhead in release, inlined by the compiler) - std::source_location location{ std::source_location::current() }; - - // Empty when tracing is disabled. - GpStacktrace stacktrace; - - std::thread::id threadId{ std::this_thread::get_id() }; - gp::String threadName; - - // Engine uptime tick. - std::chrono::steady_clock::time_point engineTime{ std::chrono::steady_clock::now() }; - // Wall-clock instant. - std::chrono::system_clock::time_point wallTime{ std::chrono::system_clock::now() }; - - MetaBag metadata; - - // Causal error, allows wrapping lower-level failures with higher-level context. - std::shared_ptr cause; - -public: - /// @brief Adds metadata to the error record. - /// @param[in] key The metadata key (e.g. "filename", "userId", etc.) - /// @param[in] value The metadata value (arbitrary string, e.g. "foo.txt", "12345", etc.) - void addMetadata(gp::String key, gp::String value); - - /// @brief Looks up a metadata value by key. - /// @param[in] key The metadata key to look up. - /// @return The metadata value associated with the key, or empty string view if not found. - GP_NODISCARD gp::StringView getMetadata(gp::StringView key) const noexcept; - - /// @brief Checks if the error has a causal error. - /// @return True if the error has a causal error, false otherwise. - GP_NODISCARD bool hasCause() const noexcept; - - /// @brief Gets the depth of the causal error chain. - /// @return The number of levels in the causal error chain. - GP_NODISCARD gp::USize causeDepth() const noexcept; - - /// @brief Generates a summary of the error. - /// @return The error summary as a string. - GP_NODISCARD gp::String summary() const; - - /// @brief Generates a full report of the error. - /// @return The full error report as a string. - GP_NODISCARD gp::String fullReport() const; -}; - -}; // namespace gp::error diff --git a/source/runtime/core/public/errors/ErrorRegistry.hpp b/source/runtime/core/public/errors/ErrorRegistry.hpp deleted file mode 100644 index 644d648..0000000 --- a/source/runtime/core/public/errors/ErrorRegistry.hpp +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "container/Optional.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorCode.hpp" -#include // TODO: gp::Mutex? -#include // TODO: gp::HashMap? - -namespace gp::error -{ - -/// @brief Metadata registry for error codes. -struct ErrorEntry -{ - gp::String description; // m_table; - -public: - /// @brief Delete copy/move constructors and assignment operators to enforce singleton pattern. - ErrorRegistry(const ErrorRegistry&) = delete; - ErrorRegistry& operator=(const ErrorRegistry&) = delete; - -private: - /// @brief Private constructor to prevent external instantiation, registers all built-in codes. - ErrorRegistry(); - -public: - /// @brief Registers a new ErrorCode with its associated metadata in the registry. - /// @param[in] code The ErrorCode to register. - /// @param[in] entry The ErrorEntry containing the metadata for the code. - void registerCode(ErrorCode code, ErrorEntry entry); - - /// @brief Looks up the given ErrorCode in the registry and returns its associated ErrorEntry if found. - /// @param[in] code The ErrorCode to look up in the registry. - /// @return An optional ErrorEntry containing the metadata if the code is registered; otherwise, an empty optional. - GP_NODISCARD gp::Optional lookup(ErrorCode code) const; - - /// @brief Gets the human-readable description associated with the given ErrorCode. - /// @note - /// Returns a copy of the description string, safe to hold across concurrent registry mutations. - /// @param[in] code The ErrorCode for which to retrieve the description. - /// @return A String containing the description if the code is registered; otherwise, "". - GP_NODISCARD gp::String describe(ErrorCode code) const; - - /// @brief Gets the remediation hint associated with the given ErrorCode, if available. - /// @param[in] code The ErrorCode for which to retrieve the remediation hint. - /// @return A String containing the remediation hint if it exists; otherwise, an empty string. - GP_NODISCARD gp::String remediationHint(ErrorCode code) const; - - /// @brief Gets the documentation URL associated with the given ErrorCode, if available. - /// @param[in] code The ErrorCode for which to retrieve the documentation URL. - /// @return A String containing the documentation URL if it exists; otherwise, an empty string. - GP_NODISCARD gp::String wikiUrl(ErrorCode code) const; - - /// @brief Checks if the given ErrorCode is registered and marked as expected (i.e. not a bug). - /// @param[in] code The ErrorCode to check for expected status. - /// @return True if the code is registered and marked as expected; otherwise, false. - GP_NODISCARD bool isExpected(ErrorCode code) const; - - /// @brief Checks if the given ErrorCode is registered and marked as always fatal. - /// @param[in] code The ErrorCode to check for fatality. - /// @return True if the code is registered and marked as always fatal; otherwise, false. - GP_NODISCARD bool isAlwaysFatal(ErrorCode code) const; - - /// @brief Returns the total number of registered error codes in the registry. - /// @return The count of registered error codes. - GP_NODISCARD gp::USize size() const; - - /// @brief Dumps the entire registry as a human-readable string (for tooling/debug). - /// @return A formatted string containing all registered error codes and their metadata. - GP_NODISCARD gp::String dumpAll() const; - -private: - /// @brief Registers all built-in error codes with their descriptions and remediation hints. - void registerBuiltins(); - -public: - /// @brief Singleton accessor for the ErrorRegistry instance. - /// @return Reference to the singleton ErrorRegistry instance. - static ErrorRegistry& instance() noexcept - { - static ErrorRegistry s_instance; - return s_instance; - } -}; - -// Initialize the registry with built-in codes and their metadata. -inline void ErrorRegistry::registerBuiltins() -{ - auto reg = [&](ErrorCode code, - gp::String description, - gp::String remediation, - gp::String wikiUrl = {}, - bool expected = false, - bool alwaysFatal = false) - { - registerCode( - code, - ErrorEntry{ .description = std::move(description), - .remediation = std::move(remediation), - .wikiUrl = std::move(wikiUrl), - .isExpected = expected, - .isAlwaysFatal = alwaysFatal } - ); - }; - - using namespace codes; - - // clang-format off - - // Generic / Uncategorized - reg(kUnknown, "Unknown error", "Consult the full stack trace."); - reg(kNotImplemented, "Feature not implemented", "This code path is a stub. Implement or route around it."); - reg(kInvalidArgument, "Invalid argument", "Check the calling convention and argument constraints."); - reg(kOutOfRange, "Value out of range", "Clamp or validate inputs before passing to this API."); - reg(kNullPointer, "Null pointer dereference", "Ensure the object was successfully constructed before use.", {}, false, true); - reg(kTimeout, "Operation timed out", "Increase the timeout budget or check for deadlocks."); - reg(kNotFound, "Resource not found", "Verify the identifier and that the resource is registered.", {}, true); - reg(kAlreadyExists, "Resource already exists", "Use a unique identifier or destroy the existing resource first."); - reg(kPermission, "Permission denied", "Check OS permissions and file/socket ownership."); - - // Memory - reg(kOutOfMemory, "Out of memory", - "Reduce allocation pressure: pool allocators, streaming, or LOD budgets. " - "Profile with GP MemTracker.", - {}, false, true); - reg(kAlignmentFault, "Alignment fault", - "Ensure allocations meet the required alignment for SIMD types. " - "Use gp::AlignedAlloc()."); - reg(kHeapCorruption, "Heap corruption detected", - "Enable GP_HEAP_GUARD in debug builds and inspect surrounding allocations.", - {}, false, true); - - // IO - reg(kFileNotFound, "File not found", "Verify the path and check the virtual filesystem mount table.", {}, true); - reg(kFileOpenFailed, "File open failed", "Check read/write permissions and ensure the path is not locked."); - reg(kFileReadFailed, "File read failed", "The file may be truncated or the handle was closed prematurely."); - reg(kFileWriteFailed,"File write failed", "Check disk space and write permissions."); - reg(kEOF, "End of file reached", "Normal termination condition, not a bug.", {}, true); - - // RHI / Renderer - reg(kDeviceLost, "GPU device lost", - "Possible causes: driver crash, TDR timeout, GPU hot-unplug. " - "Attempt device recovery or present a safe-mode fallback.", - {}, false, true); - reg(kSwapchainFail, "Swapchain creation or present failed", - "Verify the window is valid and has a non-zero client area. " - "Handle DXGI_ERROR_INVALID_CALL / VK_ERROR_OUT_OF_DATE_KHR."); - reg(kShaderCompile, "Shader compilation failed", - "Check the shader source for syntax errors. Run with GP_SHADER_VERBOSE=1 " - "to capture the full compiler log."); - reg(kPipelineCreate,"Pipeline state object creation failed", - "Validate all PSO descriptors. Ensure shaders are compiled and " - "root signatures match."); - - // Platform / Window - reg(kWindowCreate, "Window creation failed", - "Ensure the display server is running, the resolution is supported, " - "and the platform backend is initialized."); - reg(kWindowResize, "Window resize failed", - "The OS may have rejected the requested dimensions. Clamp to monitor bounds."); - reg(kInputInit, "Input system initialization failed", - "Check device permissions (e.g. /dev/input on Linux) and platform backend."); - reg(kNetConnect, "Network connection failed", - "Verify the endpoint address, firewall rules, and that the remote " - "service is reachable."); - - // Audio - reg(kAudioDeviceInit, "Audio device initialization failed", - "Ensure an audio output device is present and not exclusively locked by " - "another process. Check WASAPI / ALSA / CoreAudio permissions."); - - // clang-format on -} - -} // namespace gp::error - -/// @brief Macro to register a custom ErrorCode in the global registry with its description, remediation hint, and -/// optional documentation URL. -/// @param[in] code_ The ErrorCode to register. -/// @param[in] desc_ A short description of what the error code means. -/// @param[in] hint_ An actionable fix or investigation hint for the error code. -/// @param[in] ... Optional variadic argument for the documentation URL (e.g. "https://wiki.mygame.dev/errors/MY_CODE"). -#define GP_REGISTER_ERROR(code_, desc_, hint_, ...) \ - ::gp::error::ErrorRegistry::instance().registerCode( \ - (code_), \ - ::gp::error::ErrorEntry{ \ - .description = (desc_), \ - .remediation = (hint_), \ - .wikiUrl = [] { \ - constexpr const char* _args[] = { __VA_ARGS__ "" }; \ - return gp::String(_args[0]); }(), \ - .isExpected = false, \ - .isAlwaysFatal = false \ - }) - -/// @brief Registers an expected error code with its description and remediation hint. -/// @param[in] code_ The ErrorCode to register as expected. -/// @param[in] desc_ A short description of what the error code means. -/// @param[in] hint_ An actionable fix or investigation hint for the error code. -#define GP_REGISTER_EXPECTED_ERROR(code_, desc_, hint_) \ - ::gp::error::ErrorRegistry::instance().registerCode( \ - (code_), \ - ::gp::error::ErrorEntry{ \ - .description = (desc_), \ - .remediation = (hint_), \ - .wikiUrl = {}, \ - .isExpected = true, \ - .isAlwaysFatal = false \ - }) diff --git a/source/runtime/core/public/errors/ErrorSeverity.hpp b/source/runtime/core/public/errors/ErrorSeverity.hpp deleted file mode 100644 index 25791be..0000000 --- a/source/runtime/core/public/errors/ErrorSeverity.hpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/Array.hpp" -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "macros/MacroUtilities.hpp" -#include "utils/Enums.hpp" - -namespace gp::error -{ - -/// @brief Represents the severity level of an error or warning. -enum class Severity : gp::UInt8 -{ - Trace = 0, //(Severity::COUNT)> kSeverityMeta -{{ - /* Trace */ { "TRC", "TRACE", "\033[90m", false, false }, - /* Debug */ { "DBG", "DEBUG", "\033[36m", false, false }, - /* Info */ { "INF", "INFO", "\033[32m", false, false }, - /* Warning */ { "WRN", "WARNING", "\033[33m", false, false }, - /* Error */ { "ERR", "ERROR", "\033[31m", true, false }, - /* Fatal */ { "FTL", "FATAL", "\033[35m", true, true }, - /* Critical */ { "CRT", "CRITICAL", "\033[1;31m",true, true }, -}}; -// clang-format on - -} // namespace detail - -/// @brief Gets the short identifier for a given severity level, used in log output and diagnostics. -/// @param[in] severity The severity level to check. -/// @return The short identifier for the specified severity level. -GP_NODISCARD constexpr gp::StringView getSeverityName(Severity severity) noexcept -{ - return detail::kSeverityMeta[static_cast(severity)].name; -} - -/// @brief Gets the human-readable label for a given severity level, used in log output and diagnostics. -/// @param[in] severity The severity level to check. -/// @return The human-readable label for the specified severity level. -GP_NODISCARD constexpr gp::StringView getSeverityDisplay(Severity severity) noexcept -{ - return detail::kSeverityMeta[static_cast(severity)].display; -} - -/// @brief Gets the ANSI escape sequence for a given severity level, used for colored terminal output. -/// @param[in] severity The severity level to check. -/// @return The ANSI escape sequence for the specified severity level. -GP_NODISCARD constexpr gp::StringView getSeverityAnsiColor(Severity severity) noexcept -{ - return detail::kSeverityMeta[static_cast(severity)].ansiColor; -} - -/// @brief Determines if the given severity level should trigger a breakpoint in the debugger. -/// @param[in] severity The severity level to check. -/// @return True if the severity level should trigger a breakpoint, false otherwise. -GP_NODISCARD constexpr bool doesSeverityBreakDebugger(Severity severity) noexcept -{ - return detail::kSeverityMeta[static_cast(severity)].breaksDebugger; -} - -/// @brief Determines if the given severity level should trigger a process abort after handlers are executed. -/// @param[in] severity The severity level to check. -/// @return True if the severity level should trigger a process abort, false otherwise. -GP_NODISCARD constexpr bool doesSeverityAbortProcess(Severity severity) noexcept -{ - return detail::kSeverityMeta[static_cast(severity)].abortsProcess; -} - -} // namespace gp::error - -// Enable comparison operators for Severity enum (e.g., severity >= Severity::Warning). -GP_ENABLE_ENUM_COMPARISON_OPERATIONS(gp::error::Severity); diff --git a/source/runtime/core/public/errors/ErrorSink.hpp b/source/runtime/core/public/errors/ErrorSink.hpp deleted file mode 100644 index 866b530..0000000 --- a/source/runtime/core/public/errors/ErrorSink.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicString.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "container/Vector.hpp" -#include "CoreMinimal.hpp" // IWYU pragma: keep -#include "errors/ErrorCode.hpp" -#include "errors/ErrorRecord.hpp" -#include "errors/ErrorSeverity.hpp" - -namespace gp::error -{ - -/// @brief Abstract base class for error sinks. Sinks receive error records that pass the global filter and process them -/// (e.g. log to console, write to file, send telemetry, etc.). -class Sink -{ -protected: - gp::String m_name{ "" }; - Severity m_minSeverity{ Severity::Trace }; - gp::Vector m_domainFilter; - -public: - /// @brief Default destructor. - virtual ~Sink() noexcept = default; - -public: - /// @brief Called by the ErrorSystem for every record that passes the global filter. - /// @param[in] record The error record to process. - virtual void onRecord(const ErrorRecord& record) = 0; - - /// @brief Flush any buffered output (file handles, network sockets, etc.). - virtual void flush(); - - /// @brief Get the minimum severity level that this sink will process. - /// @return The minimum severity level. - GP_NODISCARD Severity minSeverity() const noexcept; - - /// @brief Set the minimum severity level that this sink will process. - /// @param[in] severity The minimum severity level to set. - void setMinSeverity(Severity severity) noexcept; - - /// @brief Add a domain filter to this sink. - /// @param[in] domain The domain to filter. - void addDomainFilter(Domain domain); - - /// @brief Clear all domain filters from this sink. - void clearDomainFilter(); - - /// @brief Get the name of this sink. - /// @return The name of the sink. - GP_NODISCARD const gp::String& name() const noexcept; - - /// @brief Set the name of this sink. - /// @param[in] name The name to set. - void setName(gp::String name); - - /// @brief Dispatch an error record to this sink if it meets the severity and domain filters. - /// @param[in] record The error record to dispatch. - void dispatch(const ErrorRecord& record); -}; - -}; // namespace gp::error diff --git a/source/runtime/core/public/errors/ErrorSystem.hpp b/source/runtime/core/public/errors/ErrorSystem.hpp deleted file mode 100644 index f616c35..0000000 --- a/source/runtime/core/public/errors/ErrorSystem.hpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/Array.hpp" -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorConfig.hpp" -#include "errors/ErrorContext.hpp" -#include "errors/ErrorRecord.hpp" -#include "errors/ErrorSink.hpp" -#include "errors/sinks/MultiSink.hpp" -#include "memory/ownership/UniquePtr.hpp" -#include // TODO: gp::Atomic? -#include // TODO: gp::Chrono?, gp::TimePoint? -#include // TODO: gp::Mutex? -#include -#include // TODO: gp::Thread, gp::ThreadId? -#include // TODO: gp::UnorderedMap? - -namespace gp::error -{ - -/// @brief Statistics for error counts, tracked per severity level. Queryable at any time via ErrorSystem::stats(). -struct ErrorStatistics -{ -public: - gp::Array, static_cast(Severity::COUNT)> counts{}; - std::atomic totalDropped{ 0u }; //(severity)].load(std::memory_order_relaxed); - } - - /// @brief Increments the count for a given severity level. - /// @param[in] severity The severity level to increment the count for. - void increment(Severity severity) noexcept - { - counts[static_cast(severity)].fetch_add(1, std::memory_order_relaxed); - } -}; - -/// @brief The central error handling system, implemented as a singleton. Provides APIs for raising errors, managing -/// sinks, and querying statistics. -/// @note -/// ErrorSystem is the single-point dispatcher that: -/// 1. Owns the configuration (ErrorSystemConfig). -/// 2. Owns the root MultiSink (fan-out to all registered sinks). -/// 3. Builds ErrorRecords from raise() parameters. -/// 4. Manages deduplication, statistics counters, and crash handlers. -/// 5. Provides structured query/inspection APIs used by crash-report UIs. -class ErrorSystem -{ -private: - ErrorSystemConfig m_config; - gp::UniquePtr m_rootSink; - ErrorStatistics m_stats; - std::chrono::steady_clock::time_point m_initTime; - std::mutex m_dedupMutex; - std::unordered_map m_dedupTable; - - static std::atomic s_instance; - static std::mutex s_initMutex; - static std::mutex m_sinkMutex; - -public: - /// @brief Key used for deduplication of errors. Combines error code, message hash, and thread ID. - struct DedupKey - { - public: - gp::UInt32 codeRaw; // sink); - - /// @brief Removes a sink from the ErrorSystem. - /// @param[in] name The name of the sink to remove. - static void removeSink(const gp::String& name); - - /// @brief Clears all sinks, removing them from the ErrorSystem. - static void clearSinks(); - - /// @brief Flushes all sinks, ensuring any buffered errors are written. - static void flushAll(); - - /// @brief Returns a reference to the root MultiSink for advanced configuration. - GP_NODISCARD static MultiSink& rootSink(); - - /// @brief Returns a const reference to the current ErrorSystemConfig. - /// @return A const reference to the ErrorSystemConfig instance used by the ErrorSystem. - GP_NODISCARD static const ErrorSystemConfig& config() noexcept; - - /// @brief Set the Global Min Severity object - /// @param[in] severity The minimum severity level for errors to be processed by the system. - static void setGlobalMinSeverity(Severity severity) noexcept; - - /// @brief Dispatches an error record to the ErrorSystem, building it from the provided parameters. - /// @param[in] severity The severity level of the error being dispatched. - /// @param[in] code The error code associated with the error being dispatched. - /// @param[in] message The error message string describing the error being dispatched. - /// @param[in] location The source location where the error was raised. - /// @param[in] cause An optional shared pointer to another ErrorRecord that caused this error. - static void dispatch( - Severity severity, - ErrorCode code, - gp::String message, - std::source_location location, - std::shared_ptr cause = nullptr - ); - - /// @brief Returns a reference to the error statistics. - /// @return A const reference to the ErrorStatistics instance containing error counts. - GP_NODISCARD static const ErrorStatistics& stats() noexcept; - - /// @brief Resets all error statistics counts to zero. - static void resetStats() noexcept; - - /// @brief Installs signal handlers for handling system signals that may indicate crashes or other critical events. - static void installSignalHandlers(); - -private: - /// @brief Determines whether an error with the given deduplication key should be emitted or deduplicated based on - /// recent occurrences. - /// @param[in] key The deduplication key representing the error being evaluated for deduplication. - /// @return True if the error should be emitted, false if it should be deduplicated (i.e., suppressed). - GP_NODISCARD bool shouldDedup(const DedupKey& key); - - /// @brief Internal implementation of the dispatch function, which builds an ErrorRecord and sends it to the sinks. - /// This is called by the public static dispatch() method after performing any necessary checks (e.g., - /// deduplication). - /// @param[in] severity The severity level of the error being dispatched. - /// @param[in] code The error code associated with the error being dispatched. - /// @param[in] message The error message string describing the error being dispatched. - /// @param[in] location The source location where the error was raised. - /// @param[in] cause The cause of the error, represented as a shared pointer to another ErrorRecord. This allows for - /// chaining of errors to provide more context. - void dispatchImpl( - Severity severity, - ErrorCode code, - gp::String message, - std::source_location location, - std::shared_ptr cause - ); - - /// @brief Signal handler for handling system signals. - /// @param[in] sig The signal number. - static void onSignal(int sig); -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/Forward.hpp b/source/runtime/core/public/errors/Forward.hpp deleted file mode 100644 index b3e236f..0000000 --- a/source/runtime/core/public/errors/Forward.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -namespace gp::error -{ - -// Configurations - -struct StacktraceConfig; -struct BreakpointConfig; -struct AbortConfig; -struct FilterConfig; -struct ThreadConfig; -struct ErrorSystemConfig; -struct CrashReportConfig; - -// Sinks -class Sink; -class AbortSink; -class BreakpointSink; -class ConsoleSink; -class CallbackSink; -class DeferredSink; -class FileSink; -class MultiSink; -class RateLimitedSink; -class TelemetrySink; -class FilteredSink; -class SplitterSink; -class BroadcastSink; -class RingBufferSink; -class BinarySink; -class CrashReporter; - -// Forward declarations - -struct MetaEntry; -class ErrorCode; -class ErrorRecord; -class ErrorContext; -struct ContextFrame; -class ContextScope; -struct ErrorStatistics; -class ErrorSystem; -struct ErrorEntry; -class ErrorRegistry; -class FilterPredicate; -class ErrorScope; -class ErrorGuard; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/sinks/AbortSink.hpp b/source/runtime/core/public/errors/sinks/AbortSink.hpp deleted file mode 100644 index aca5981..0000000 --- a/source/runtime/core/public/errors/sinks/AbortSink.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "errors/ErrorSeverity.hpp" -#include "errors/ErrorSink.hpp" - -namespace gp::error -{ - -/// @brief A sink that terminates the process when an error record with severity at or above a specified threshold is -/// received. -class AbortSink final : public Sink -{ -public: - enum class Mode - { - Abort, - Terminate - }; - -private: - Severity m_abortAt; - Mode m_mode; - -public: - /// @brief Constructs an AbortSink that terminates the process when a record with severity at or above @p abortAt is - /// received. - /// @param[in] abortAt The severity threshold at which to trigger process termination (inclusive). - /// @param[in] mode The method of termination: std::abort() or std::terminate(). - explicit AbortSink(Severity abortAt = Severity::Fatal, Mode mode = Mode::Abort); - -public: - /// @brief Called by the ErrorSystem for every record that passes the global filter. - /// @param[in] record The error record to process. - void onRecord(const ErrorRecord& record) override; -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/sinks/BreakpointSink.hpp b/source/runtime/core/public/errors/sinks/BreakpointSink.hpp deleted file mode 100644 index d527a5b..0000000 --- a/source/runtime/core/public/errors/sinks/BreakpointSink.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "errors/ErrorSeverity.hpp" -#include "errors/ErrorSink.hpp" - -namespace gp::error -{ - -/// @brief A sink that triggers a debug break when an error record with severity at or above a specified threshold is -/// received. This is useful for developers who want to break into the debugger immediately when a certain level of -/// error occurs. -class BreakpointSink final : public Sink -{ -private: - Severity m_breakAt; - -public: - /// @brief Constructs a BreakpointSink that triggers a debug break at or above the specified severity level. - /// @param[in] breakAt The severity level at which to trigger a debug break (inclusive). - explicit BreakpointSink(Severity breakAt = Severity::Error); - -public: - /// @brief Called by the ErrorSystem for every record that passes the global filter. - /// @param[in] record The error record to process. - void onRecord(const ErrorRecord& record) override; -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/sinks/ConsoleSink.hpp b/source/runtime/core/public/errors/sinks/ConsoleSink.hpp deleted file mode 100644 index 5b95e15..0000000 --- a/source/runtime/core/public/errors/sinks/ConsoleSink.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "errors/ErrorSink.hpp" -#include // TODO: gp::IO? -#include // TODO: gp::Mutex? - -namespace gp::error -{ - -/// @brief ConsoleSink, ANSI-coloured stderr (or stdout) output. -class ConsoleSink final : public Sink -{ -private: - std::mutex m_mutex; - bool m_useColor{ true }; - FILE* m_stream{ nullptr }; - bool m_printStacktrace{ true }; - bool m_printCause{ true }; - -public: - /// @brief Constructs a ConsoleSink. - /// @param[in] useAnsiColor If true, ANSI color codes will be used to colorize the output based on severity. If - /// false, no color codes will be used. - /// @param[in] toStdout If true, output will be sent to stdout; otherwise, it will be sent to stderr. - explicit ConsoleSink(bool useAnsiColor = true, bool toStdout = false); - -public: - /// @brief Called by the ErrorSystem for every record that passes the global filter. - /// @param[in] record The error record to process. - void onRecord(const ErrorRecord& record) override; - /// @brief Flush any buffered output (file handles, network sockets, etc.). - void flush() override; - - /// @brief Enable or disable printing of stack traces. - /// @param[in] enabled If true, stack traces will be printed; otherwise, they will be omitted. - void setPrintStacktrace(bool enabled) noexcept; - - /// @brief Enable or disable printing of error causes. - /// @param[in] enabled If true, error causes will be printed; otherwise, they will be omitted. - void setPrintCause(bool enabled) noexcept; -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/sinks/FileSink.hpp b/source/runtime/core/public/errors/sinks/FileSink.hpp deleted file mode 100644 index 14e6eb8..0000000 --- a/source/runtime/core/public/errors/sinks/FileSink.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "errors/ErrorSink.hpp" -#include // TODO: gp::fs::FileStream? -#include // TODO: gp::Mutex? - -namespace gp::error -{ - -/// @brief A simple sink that appends UTF-8 text to a file. -class FileSink final : public Sink -{ -private: - std::mutex m_mutex; - std::ofstream m_file; - -public: - /// @brief Constructs a FileSink that appends UTF-8 text to the specified path. - /// @param[in] path The file path to write logs to. - explicit FileSink(const gp::String& path); - -public: - /// @brief Called by the ErrorSystem for every record that passes the global filter. - /// @param[in] record The error record to process. - void onRecord(const ErrorRecord& record) override; - - /// @brief Flush any buffered output (file handles, network sockets, etc.). - void flush() override; -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/errors/sinks/MultiSink.hpp b/source/runtime/core/public/errors/sinks/MultiSink.hpp deleted file mode 100644 index 4cfae1c..0000000 --- a/source/runtime/core/public/errors/sinks/MultiSink.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/Forward.hpp" -#include "container/Vector.hpp" -#include "CoreMinimal.hpp" -#include "errors/ErrorSink.hpp" -#include // TODO: gp::Mutex? - -namespace gp::error -{ - -/// @brief MultiSink is the default root sink for the ErrorSystem. It fans out to any number of child sinks, which can -/// be added and removed at runtime. -/// @note -/// MultiSink is thread-safe, but individual child sinks are not protected by any internal synchronization. -/// If you need to share a sink across threads, consider wrapping it in a RateLimitedSink or using your own -/// synchronization. -class MultiSink final : public Sink -{ -private: - mutable std::mutex m_mutex; - gp::Vector> m_sinks; - -public: - /// @brief Constructor that initializes the MultiSink with a default name and minimum severity level. - explicit MultiSink(); - -public: - /// @brief Add a sink to this MultiSink. - /// @param[in] sink The sink to add. - void addSink(std::shared_ptr sink); - - /// @brief Remove a sink from this MultiSink by name. - /// @param[in] name The name of the sink to remove. - void removeSink(const gp::String& name); - - /// @brief Get the number of sinks currently added to this MultiSink. - /// @return The number of sinks. - GP_NODISCARD gp::USize sinkCount() const noexcept; - - /// @brief Called by the ErrorSystem for every record that passes the global filter. - /// @param[in] record The error record to process. - void onRecord(const ErrorRecord& record) override; - - /// @brief Flush any buffered output (file handles, network sockets, etc.). - void flush() override; -}; - -} // namespace gp::error diff --git a/source/runtime/core/public/macros/DetectArchitecture.hpp b/source/runtime/core/public/macros/DetectArchitecture.hpp deleted file mode 100644 index cbe6e69..0000000 --- a/source/runtime/core/public/macros/DetectArchitecture.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -// Architecture detection -#if defined(_M_X64) || defined(__x86_64__) - #define GP_ARCHITECTURE_X64 1 -#elif defined(_M_IX86) || defined(__i386__) - #define GP_ARCHITECTURE_X86 1 -#elif defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM64EC) - #define GP_ARCHITECTURE_ARM64 1 -#elif defined(_M_ARM) || defined(__arm__) || defined(__ARM_NEON) - #define GP_ARCHITECTURE_ARM32 1 -#elif defined(__EMSCRIPTEN__) - #define GP_ARCHITECTURE_WASM 1 -#else - #error "[GP] Unsupported architecture." -#endif - -#ifndef GP_ARCHITECTURE_X86 - #define GP_ARCHITECTURE_X86 0 -#endif -#ifndef GP_ARCHITECTURE_X64 - #define GP_ARCHITECTURE_X64 0 -#endif -#ifndef GP_ARCHITECTURE_ARM32 - #define GP_ARCHITECTURE_ARM32 0 -#endif -#ifndef GP_ARCHITECTURE_ARM64 - #define GP_ARCHITECTURE_ARM64 0 -#endif -#ifndef GP_ARCHITECTURE_WASM - #define GP_ARCHITECTURE_WASM 0 -#endif - -// Architecture families -#define GP_ARCHITECTURE_X86_FAMILY (GP_ARCHITECTURE_X86 || GP_ARCHITECTURE_X64) -#define GP_ARCHITECTURE_ARM_FAMILY (GP_ARCHITECTURE_ARM32 || GP_ARCHITECTURE_ARM64) -#define GP_ARCHITECTURE_64BIT (GP_ARCHITECTURE_X64 || GP_ARCHITECTURE_ARM64) -#define GP_ARCHITECTURE_32BIT (GP_ARCHITECTURE_X86 || GP_ARCHITECTURE_ARM32) - -// Validate architecture macros -#if !GP_ARCHITECTURE_64BIT - #error "[GP] Graphical Playground only supports 64-bit architecture." -#endif diff --git a/source/runtime/core/public/macros/DetectBuild.hpp b/source/runtime/core/public/macros/DetectBuild.hpp deleted file mode 100644 index f38055f..0000000 --- a/source/runtime/core/public/macros/DetectBuild.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -// C++ standard detection -#if defined(__clang__) - #define GP_CXX_STANDARD __cplusplus -#elif defined(_MSVC_LANG) - #define GP_CXX_STANDARD _MSVC_LANG -#elif defined(__cplusplus) - #define GP_CXX_STANDARD __cplusplus -#else - #error "[GP] Cannot determine C++ standard version" -#endif - -#define GP_INTERNAL_CXX11 (GP_CXX_STANDARD >= 201103L) -#define GP_INTERNAL_CXX14 (GP_CXX_STANDARD >= 201402L) -#define GP_INTERNAL_CXX17 (GP_CXX_STANDARD >= 201703L) -#define GP_INTERNAL_CXX20 (GP_CXX_STANDARD >= 202002L) -#define GP_INTERNAL_CXX23 (GP_CXX_STANDARD >= 202302L) -#define GP_INTERNAL_CXX26 (GP_CXX_STANDARD >= 202602L) - -#ifndef GP_ALLOW_OLDER_STANDARDS - #if !GP_INTERNAL_CXX23 - #error "[GP] C++23 is required." - #endif -#else - #pragma message("[GP] Warning: Building with an older C++ standard than C++23 is not officially supported.") -#endif - -// Build configuration -#if !defined(GP_BUILD_DEBUG) && !defined(GP_BUILD_RELEASE) && !defined(GP_BUILD_RELWITHDEBINFO) && \ - !defined(GP_BUILD_MINSIZEREL) - // If no build configuration macros are defined, attempt to detect based on common debug macros - #if defined(DEBUG) || defined(_DEBUG) - #define GP_BUILD_DEBUG 1 - #define GP_BUILD_RELEASE 0 - #else - #define GP_BUILD_DEBUG 0 - #define GP_BUILD_RELEASE 1 - #endif - - // Assume RelWithDebInfo and MinSizeRel are not defined in this case - #define GP_BUILD_RELWITHDEBINFO 0 - #define GP_BUILD_MINSIZEREL 0 -#else - #ifndef GP_BUILD_DEBUG - #define GP_BUILD_DEBUG 0 - #endif - - #ifndef GP_BUILD_RELEASE - #define GP_BUILD_RELEASE 0 - #endif - - #ifndef GP_BUILD_RELWITHDEBINFO - #define GP_BUILD_RELWITHDEBINFO 0 - #endif - - #ifndef GP_BUILD_MINSIZEREL - #define GP_BUILD_MINSIZEREL 0 - #endif -#endif diff --git a/source/runtime/core/public/macros/DetectCompiler.hpp b/source/runtime/core/public/macros/DetectCompiler.hpp deleted file mode 100644 index 05c0cd7..0000000 --- a/source/runtime/core/public/macros/DetectCompiler.hpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -// Compiler detection -#if defined(_MSC_VER) - #define GP_COMPILER_MSVC 1 - #define GP_COMPILER_VERSION _MSC_VER -#elif defined(__clang__) - #define GP_COMPILER_CLANG 1 - #define GP_COMPILER_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) -#elif defined(__GNUC__) - #define GP_COMPILER_GCC 1 - #define GP_COMPILER_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#elif defined(__EMSCRIPTEN__) - #define GP_COMPILER_EMSCRIPTEN 1 - #define GP_COMPILER_VERSION __EMSCRIPTEN__ -#elif defined(__INTEL_COMPILER) || defined(__ICC) - #define GP_COMPILER_INTEL 1 - #define GP_COMPILER_VERSION __INTEL_COMPILER -#else - #error "[GP] Unsupported compiler." -#endif - -// Define missing compiler macros to 0 -#ifndef GP_COMPILER_MSVC - #define GP_COMPILER_MSVC 0 -#endif -#ifndef GP_COMPILER_CLANG - #define GP_COMPILER_CLANG 0 -#endif -#ifndef GP_COMPILER_GCC - #define GP_COMPILER_GCC 0 -#endif -#ifndef GP_COMPILER_EMSCRIPTEN - #define GP_COMPILER_EMSCRIPTEN 0 -#endif -#ifndef GP_COMPILER_INTEL - #define GP_COMPILER_INTEL 0 -#endif - -// Check compiler support -#if (GP_COMPILER_MSVC && GP_COMPILER_VERSION < 1920) || (!GP_COMPILER_MSVC && !defined(__cpp_if_constexpr)) - #error "[GP] Compiler is expected to support `if constexpr` statements." -#endif - -#if !defined(__cpp_fold_expressions) - #error "[GP] Compiler is expected to support fold expressions." -#endif - -#if !__has_feature(cxx_decltype_auto) - #error "[GP] Compiler is expected to support `decltype(auto)`." -#endif diff --git a/source/runtime/core/public/macros/DetectConfig.hpp b/source/runtime/core/public/macros/DetectConfig.hpp deleted file mode 100644 index 1f615b0..0000000 --- a/source/runtime/core/public/macros/DetectConfig.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#ifndef GP_USE_VULKAN - #define GP_USE_VULKAN 0 -#endif - -#ifndef GP_USE_D3D12 - #define GP_USE_D3D12 0 -#endif - -#ifndef GP_USE_D3D11 - #define GP_USE_D3D11 0 -#endif - -#ifndef GP_USE_METAL - #define GP_USE_METAL 0 -#endif - -#ifndef GP_USE_OPENGL - #define GP_USE_OPENGL 0 -#endif - -#ifndef GP_ENABLE_PROFILING - #define GP_ENABLE_PROFILING 0 -#endif - -#ifndef GP_BUILD_EDITOR - #define GP_BUILD_EDITOR 0 -#endif diff --git a/source/runtime/core/public/macros/DetectPlatform.hpp b/source/runtime/core/public/macros/DetectPlatform.hpp deleted file mode 100644 index abb0051..0000000 --- a/source/runtime/core/public/macros/DetectPlatform.hpp +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -// Detect the platform and define the corresponding macros. -#if defined(_WIN32) || defined(_WIN64) - #define GP_PLATFORM_WINDOWS 1 -#elif defined(__APPLE__) && defined(__MACH__) - #include - #if TARGET_OS_IOS - #define GP_PLATFORM_IOS 1 - #elif TARGET_OS_TV - #define GP_PLATFORM_TVOS 1 - #elif TARGET_OS_WATCH - #define GP_PLATFORM_WATCHOS 1 - #elif TARGET_OS_MAC - #define GP_PLATFORM_MACOS 1 - #else - #error "[GP] Unsupported Apple platform." - #endif -#elif defined(__ANDROID__) - #define GP_PLATFORM_ANDROID 1 -#elif defined(__linux__) - #define GP_PLATFORM_LINUX 1 -#elif defined(__EMSCRIPTEN__) - #define GP_PLATFORM_WEB 1 -#else - #error "[GP] Unsupported platform." -#endif - -// Define all platform macros to 0 if they are not defined. -#ifndef GP_PLATFORM_WINDOWS - #define GP_PLATFORM_WINDOWS 0 -#endif -#ifndef GP_PLATFORM_LINUX - #define GP_PLATFORM_LINUX 0 -#endif -#ifndef GP_PLATFORM_MACOS - #define GP_PLATFORM_MACOS 0 -#endif -#ifndef GP_PLATFORM_IOS - #define GP_PLATFORM_IOS 0 -#endif -#ifndef GP_PLATFORM_ANDROID - #define GP_PLATFORM_ANDROID 0 -#endif -#ifndef GP_PLATFORM_WEB - #define GP_PLATFORM_WEB 0 -#endif -#ifndef GP_PLATFORM_TVOS - #define GP_PLATFORM_TVOS 0 -#endif -#ifndef GP_PLATFORM_WATCHOS - #define GP_PLATFORM_WATCHOS 0 -#endif - -// Windows-specific macros -#if GP_PLATFORM_WINDOWS - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif -#endif - -// Platform families -#define GP_PLATFORM_DESKTOP (GP_PLATFORM_WINDOWS || GP_PLATFORM_LINUX || GP_PLATFORM_MACOS) -#define GP_PLATFORM_MOBILE (GP_PLATFORM_IOS || GP_PLATFORM_ANDROID || GP_PLATFORM_TVOS || GP_PLATFORM_WATCHOS) -#define GP_PLATFORM_APPLE (GP_PLATFORM_MACOS || GP_PLATFORM_IOS || GP_PLATFORM_TVOS || GP_PLATFORM_WATCHOS) -#define GP_PLATFORM_UNIX (GP_PLATFORM_LINUX || GP_PLATFORM_APPLE || GP_PLATFORM_ANDROID) -#define GP_PLATFORM_POSIX (GP_PLATFORM_UNIX || GP_PLATFORM_WEB) -#define GP_PLATFORM_MICROSOFT (GP_PLATFORM_WINDOWS) - -// ANSI Relevant macros -#if GP_PLATFORM_ANDROID - #define GP_PLATFORM_USE_ANSI_POSIX_MALLOC 1 -#elif GP_PLATFORM_APPLE - #define GP_PLATFORM_USE_ANSI_POSIX_MALLOC 1 - #define GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE 1 -#elif GP_PLATFORM_UNIX - #define GP_PLATFORM_USE_ANSI_POSIX_MALLOC 1 - #define GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE 1 -#elif GP_PLATFORM_WINDOWS - #define GP_PLATFORM_USE_ALIGNED_MALLOC 1 - #define GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE 1 -#endif - -// Default values for ANSI malloc macros if not defined by platform detection. -#ifndef GP_PLATFORM_USE_ANSI_POSIX_MALLOC - #define GP_PLATFORM_USE_ANSI_POSIX_MALLOC 0 -#endif -#ifndef GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE - #define GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE 0 -#endif -#ifndef GP_PLATFORM_USE_ALIGNED_MALLOC - #define GP_PLATFORM_USE_ALIGNED_MALLOC 0 -#endif diff --git a/source/runtime/core/public/macros/DetectSimd.hpp b/source/runtime/core/public/macros/DetectSimd.hpp deleted file mode 100644 index 1bee918..0000000 --- a/source/runtime/core/public/macros/DetectSimd.hpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "macros/DetectArchitecture.hpp" - -// SSE (x86/x64) -#if GP_ARCHITECTURE_X86_FAMILY - #if defined(__SSE__) || defined(_M_IX86_FP) || defined(_M_X64) - #define GP_SIMD_SSE 1 - #endif - #if defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(_M_X64) - #define GP_SIMD_SSE2 1 - #endif - #if defined(__SSE3__) - #define GP_SIMD_SSE3 1 - #endif - #if defined(__SSSE3__) - #define GP_SIMD_SSSE3 1 - #endif - #if defined(__SSE4_1__) - #define GP_SIMD_SSE4_1 1 - #endif - #if defined(__SSE4_2__) - #define GP_SIMD_SSE4_2 1 - #endif - #if defined(__AVX__) - #define GP_SIMD_AVX 1 - #endif - #if defined(__AVX2__) - #define GP_SIMD_AVX2 1 - #endif - #if defined(__AVX512F__) - #define GP_SIMD_AVX512 1 - #endif - #if defined(__FMA__) - #define GP_SIMD_FMA 1 - #endif -#endif - -// NEON (ARM) -#if GP_ARCHITECTURE_ARM_FAMILY - #if defined(__ARM_NEON) || defined(__ARM_NEON__) - #define GP_SIMD_NEON 1 - #endif - #if defined(__ARM_FEATURE_FMA) - #define GP_SIMD_ARM_FMA 1 - #endif -#endif - -// WASM SIMD -#if GP_ARCHITECTURE_WASM - #if defined(__wasm_simd128__) - #define GP_SIMD_WASM128 1 - #endif -#endif - -// Default values for undefined SIMD macros -#ifndef GP_SIMD_SSE - #define GP_SIMD_SSE 0 -#endif -#ifndef GP_SIMD_SSE2 - #define GP_SIMD_SSE2 0 -#endif -#ifndef GP_SIMD_SSE3 - #define GP_SIMD_SSE3 0 -#endif -#ifndef GP_SIMD_SSSE3 - #define GP_SIMD_SSSE3 0 -#endif -#ifndef GP_SIMD_SSE4_1 - #define GP_SIMD_SSE4_1 0 -#endif -#ifndef GP_SIMD_SSE4_2 - #define GP_SIMD_SSE4_2 0 -#endif -#ifndef GP_SIMD_AVX - #define GP_SIMD_AVX 0 -#endif -#ifndef GP_SIMD_AVX2 - #define GP_SIMD_AVX2 0 -#endif -#ifndef GP_SIMD_AVX512 - #define GP_SIMD_AVX512 0 -#endif -#ifndef GP_SIMD_FMA - #define GP_SIMD_FMA 0 -#endif -#ifndef GP_SIMD_NEON - #define GP_SIMD_NEON 0 -#endif -#ifndef GP_SIMD_ARM_FMA - #define GP_SIMD_ARM_FMA 0 -#endif -#ifndef GP_SIMD_WASM128 - #define GP_SIMD_WASM128 0 -#endif - -// Generic SIMD availability -#define GP_SIMD_AVAILABLE (GP_SIMD_SSE || GP_SIMD_NEON || GP_SIMD_WASM128) diff --git a/source/runtime/core/public/macros/MacroUtilities.hpp b/source/runtime/core/public/macros/MacroUtilities.hpp deleted file mode 100644 index 4951314..0000000 --- a/source/runtime/core/public/macros/MacroUtilities.hpp +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "macros/DetectBuild.hpp" -#include "macros/DetectCompiler.hpp" -#include "macros/DetectPlatform.hpp" -#if GP_COMPILER_GCC || GP_COMPILER_CLANG - #include // For malloc -#endif - -/// @brief Macro to concatenate two tokens. -#define GP_INTERNAL_CONCAT_IMPL(a, b) a##b -#define GP_CONCAT(a, b) GP_INTERNAL_CONCAT_IMPL(a, b) - -/// @brief Macro to stringify a token. -#define GP_INTERNAL_STRINGIFY_IMPL(x) #x -#define GP_STRINGIFY(x) GP_INTERNAL_STRINGIFY_IMPL(x) - -/// @brief Macro to get the first argument or a default value if no arguments are provided. -#define GP_FIRST_OR_DEFAULT(first, ...) first - -/// @brief Macro to get the first argument or an empty string if no arguments are provided. -#define GP_FIRST(...) GP_FIRST_HELPER(__VA_ARGS__, "") -#define GP_FIRST_HELPER(first, ...) first - -/// @brief Expand remaining arguments (for printf-style formatting) -#define GP_EXPAND_ARGS(...) GP_EXPAND_ARGS_HELPER(__VA_ARGS__, ) -#define GP_EXPAND_ARGS_HELPER(first, ...) , ##__VA_ARGS__ - -/// @brief Macro to get the first argument for a format string, or an empty string if no arguments are provided. -#define GP_FORMAT_MSG(...) GP_FIRST(__VA_ARGS__) - -/// @brief Macro to create a version number from major, minor, and patch components. -/// @param[in] major The major version number. -/// @param[in] minor The minor version number. -/// @param[in] patch The patch version number. -#define GP_VERSION(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) - -/// @brief Macro to convert a version number into a string format "major.minor.patch". -/// @param[in] major The major version number. -/// @param[in] minor The minor version number. -/// @param[in] patch The patch version number. -#define GP_VERSION_STRINGIFY(major, minor, patch) #major "." #minor "." #patch - -/// @brief Macro to force inline a function, depending on the compiler being used. -#if GP_COMPILER_MSVC - #define GP_FORCEINLINE __forceinline -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_FORCEINLINE inline __attribute__((always_inline)) -#else - #define GP_FORCEINLINE inline -#endif - -/// @brief Suggests the compiler to inline the decorated function, but allows it to ignore the hint. -#if GP_COMPILER_MSVC - #define GP_INLINE __inline -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_INLINE inline -#else - #define GP_INLINE inline -#endif - -/// @brief Prevents the compiler from inlining the decorated function. -#if GP_COMPILER_MSVC - #define GP_NOINLINE __declspec(noinline) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_NOINLINE __attribute__((noinline)) -#else - #define GP_NOINLINE -#endif - -/// @brief Strongly requests inlining, but explicitly suppresses compiler warnings if the compiler refuses. -#if GP_COMPILER_MSVC - // __pragma allows us to wrap the warning suppression directly inside the macro. - // This tells MSVC: "Force inline this, but if it's too complex, don't throw Warning C4714." - #define GP_FORCEINLINE_HINT __pragma(warning(suppress: 4714)) __forceinline -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - // On GCC/Clang, standard 'inline' is already a very strong hint under -O2/-O3. - // always_inline can throw strict errors (not just warnings) if used improperly. - #define GP_FORCEINLINE_HINT inline -#else - #define GP_FORCEINLINE_HINT inline -#endif - -/// @brief Uses standard inline in Debug builds to allow stepping through code, but forces inline in Release. -#if defined(GP_BUILD_DEBUG) - #define GP_FORCEINLINE_DEBUGGABLE inline -#else - #define GP_FORCEINLINE_DEBUGGABLE GP_FORCEINLINE -#endif - -/// @brief Asserts a pointer does not alias any other pointer in scope. -#if GP_COMPILER_MSVC - #define GP_RESTRICT __restrict -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_RESTRICT __restrict__ -#else - #define GP_RESTRICT -#endif - -/// @brief Macro to trigger a breakpoint in the debugger, depending on the compiler and platform being used. -#if GP_COMPILER_MSVC - #define GP_DEBUGBREAK() __debugbreak() -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #if GP_PLATFORM_WINDOWS - #define GP_DEBUGBREAK() __builtin_trap() - #else - #include - #define GP_DEBUGBREAK() raise(SIGTRAP) - #endif -#else - #define GP_DEBUGBREAK() ((void)0) -#endif - -/// @brief Macro to get the current function signature as a string, depending on the compiler being used. -#if GP_COMPILER_MSVC - #define GP_FUNCSIG __FUNCSIG__ -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_FUNCSIG __PRETTY_FUNCTION__ -#else - #define GP_FUNCSIG __func__ -#endif - -/// @brief Hints that the expression is likely to be true (hot path). -/// @brief Hints that the expression is likely to be false (cold path). -#if GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_LIKELY(x) __builtin_expect(!!(x), 1) - #define GP_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - // Additional "!!" added to silence "warning: equality comparison with exteraneous parenthese" on android. - #define GP_LIKELY(x) (!!(x)) - #define GP_UNLIKELY(x) (!!(x)) -#endif - -/// @brief Tells the compiler a code path is unreachable. Undefined behaviour if executed. -#if GP_INTERNAL_CXX23 - #define GP_UNREACHABLE() std::unreachable() -#elif GP_COMPILER_MSVC - #define GP_UNREACHABLE() __assume(0) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_UNREACHABLE() __builtin_unreachable() -#else - #define GP_UNREACHABLE() ((void)0) -#endif - -/// @brief Provides a boolean hint to the optimiser without a branch. -#if GP_COMPILER_MSVC - #define GP_ASSUME(x) __assume(x) -#elif GP_COMPILER_CLANG - #define GP_ASSUME(x) __builtin_assume(x) -#elif GP_COMPILER_GCC - #define GP_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while(0) -#else - #define GP_ASSUME(x) ((void)0) -#endif - -/// @brief Macro to mark a function or variable as deprecated, with a version and message. -/// @param[in] version The framework/engine version where this was deprecated (e.g., 5.1). -/// @param[in] msg The deprecation message, typically suggesting an alternative. -#if GP_INTERNAL_CXX14 - #define GP_DEPRECATED(version, msg) [[deprecated("Deprecated in version " GP_STRINGIFY(version) ": " msg)]] -#elif GP_COMPILER_MSVC - #define GP_DEPRECATED(version, msg) __declspec(deprecated("Deprecated in version " GP_STRINGIFY(version) ": " msg)) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in version " GP_STRINGIFY(version) ": " msg))) -#else - #define GP_DEPRECATED(version, msg) -#endif - -/// @brief Macro to mark a function's return value as "must use", with an optional message. -/// @param[in] msg An optional message to provide more context about why the return value must be used. -#if GP_INTERNAL_CXX17 - #define GP_NODISCARD [[nodiscard]] - #define GP_NODISCARD_MSG(msg) [[nodiscard(msg)]] -#elif GP_COMPILER_MSVC && _MSC_VER >= 1700 - #define GP_NODISCARD _Check_return_ - #define GP_NODISCARD_MSG(msg) _Check_return_ -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_NODISCARD __attribute__((warn_unused_result)) - #define GP_NODISCARD_MSG(msg) __attribute__((warn_unused_result(msg))) -#else - #define GP_NODISCARD - #define GP_NODISCARD_MSG(msg) -#endif - -/// @brief Macro to mark a variable or function as "maybe unused", suppressing compiler warnings about unused entities. -#if GP_INTERNAL_CXX17 - #define GP_MAYBE_UNUSED [[maybe_unused]] -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_MAYBE_UNUSED __attribute__((unused)) -#else - #define GP_MAYBE_UNUSED -#endif - -/// @brief Macro to mark a function as "noreturn", indicating that it does not return to the caller. -#if GP_INTERNAL_CXX11 - #define GP_NORETURN [[noreturn]] -#elif GP_COMPILER_MSVC - #define GP_NORETURN __declspec(noreturn) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_NORETURN __attribute__((noreturn)) -#else - #define GP_NORETURN -#endif - -/// @brief Utility macros for cpp_attributes and other compiler-specific features. -#ifndef __has_cpp_attribute - #define __has_cpp_attribute(x) 0 -#endif - -/// @brief Marks a struct as no unique address, allowing it to have zero size and be used for empty base optimization. -#if GP_INTERNAL_CXX20 - #if __has_cpp_attribute(msvc::no_unique_address) - #define GP_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] - #else - #define GP_NO_UNIQUE_ADDRESS [[no_unique_address]] - #endif -#elif GP_COMPILER_MSVC - #define GP_NO_UNIQUE_ADDRESS __declspec(empty_bases) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_NO_UNIQUE_ADDRESS __attribute__((no_unique_address)) -#else - #define GP_NO_UNIQUE_ADDRESS -#endif - -/// @brief Specifies the minimum alignment of a variable or type in bytes. -#if GP_INTERNAL_CXX11 - #define GP_ALIGN(x) alignas(x) -#elif GP_COMPILER_MSVC - #define GP_ALIGN(x) __declspec(align(x)) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_ALIGN(x) __attribute__((aligned(x))) -#else - #define GP_ALIGN(x) -#endif - -/// @brief Allocates memory with the specified alignment. Size must be a multiple of alignment for some platforms -/// (e.g. WASM). -/// @param[in] size The size of the memory block to allocate, in bytes. -/// @param[in] alignment The alignment requirement for the allocated memory, in bytes. -/// -/// @brief Frees memory allocated with GP_ALIGNED_ALLOC. -/// @param[in] ptr A pointer to the memory block to free. This pointer must have been returned by a previous call to -/// GP_ALIGNED_ALLOC. -#if GP_COMPILER_MSVC - #define GP_ALIGNED_ALLOC(size, alignment) _aligned_malloc(size, alignment) - #define GP_ALIGNED_FREE(ptr) _aligned_free(ptr) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #include - #define GP_ALIGNED_ALLOC(size, alignment) ::aligned_alloc(alignment, size) - #define GP_ALIGNED_FREE(ptr) ::free(ptr) -#else - #define GP_ALIGNED_ALLOC(size, alignment) ::malloc(size) - #define GP_ALIGNED_FREE(ptr) ::free(ptr) -#endif - -/// @brief Macro to annotate a function as an allocation function, which can help the compiler optimize calls to it. -/// @param[in] ... The argument indices that specify the size parameters for the allocation function (e.g., 1 for -/// malloc(size), or 1, 2 for realloc(ptr, size)). -#if GP_COMPILER_MSVC - #define GP_ALLOCATION_FUNCTION(...) __declspec(allocator) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_ALLOCATION_FUNCTION(...) __attribute__((alloc_size(__VA_ARGS__))) -#else - #define GP_ALLOCATION_FUNCTION(...) -#endif - -/// @brief Macro to mark a variable or function as having "selectany" linkage, allowing multiple definitions across -/// translation units without violating the One Definition Rule. -#if GP_COMPILER_MSVC - #define GP_SELECT_ANY __declspec(selectany) -#elif GP_COMPILER_GCC || GP_COMPILER_CLANG - #define GP_SELECT_ANY __attribute__((selectany)) -#else - #define GP_SELECT_ANY -#endif - -/// @brief Macro to mark a variable or parameter as intentionally unused. -#define GP_UNUSED(x) (void)(x) - -/// @brief Macro for assertions. -/// @todo Implement a custom assertion mechanism that integrates with the engine's logging system and provides more -/// context on failure. For now, this is a no-op to avoid dependencies on the logging system in core headers. -#define GP_ASSERT(expr, ...) (void)(expr) - -/// @brief Macro to define export/import symbols for shared libraries, depending on the platform and whether we're -/// building or using the library. -#if GP_PLATFORM_UNIX - #define GP_DLLEXPORT __attribute__((visibility("default"))) - #define GP_DLLIMPORT __attribute__((visibility("default"))) -#elif GP_PLATFORM_WINDOWS - #define GP_DLLEXPORT __declspec(dllexport) - #define GP_DLLIMPORT __declspec(dllimport) -#else - #define GP_DLLEXPORT - #define GP_DLLIMPORT -#endif diff --git a/source/runtime/core/public/math/Forward.hpp b/source/runtime/core/public/math/Forward.hpp deleted file mode 100644 index 2c05547..0000000 --- a/source/runtime/core/public/math/Forward.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include - -namespace gp::math -{ - -template -struct Vec2; -template -struct Vec3; -template -struct Vec4; - -template -struct Mat2; -template -struct Mat3; -template -struct Mat34; -template -struct Mat4; - -template -struct Quat; -template -struct DualQuat; -template -struct Rotator; -template -struct Rotator2; - -template -struct Transform; - -using Vec2f = Vec2; -using Vec3f = Vec3; -using Vec4f = Vec4; - -using Vec2d = Vec2; -using Vec3d = Vec3; -using Vec4d = Vec4; - -using Mat2f = Mat2; -using Mat3f = Mat3; -using Mat34f = Mat34; -using Mat4f = Mat4; - -using Mat2d = Mat2; -using Mat3d = Mat3; -using Mat34d = Mat34; -using Mat4d = Mat4; - -using Quatf = Quat; -using Quatd = Quat; -using DualQuatf = DualQuat; -using DualQuatd = DualQuat; -using Rotatorf = Rotator; -using Rotatord = Rotator; -using Rotator2f = Rotator2; -using Rotator2d = Rotator2; - -using Transformf = Transform; -using Transformd = Transform; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/LinearAlgebra.hpp b/source/runtime/core/public/math/LinearAlgebra.hpp deleted file mode 100644 index 25dd95c..0000000 --- a/source/runtime/core/public/math/LinearAlgebra.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include - -namespace gp::math -{ - -/// @brief Returns the smaller of two values. -/// @tparam T The type of the values. Must be an arithmetic type. -/// @param a The first value. -/// @param b The second value. -/// @return The smaller of the two values. -template -requires std::is_arithmetic_v GP_NODISCARD GP_FORCEINLINE constexpr T min(T a, T b) noexcept -{ - return (a < b) ? a : b; -} - -/// @brief Returns the smaller of three values. -/// @tparam T The type of the values. Must be an arithmetic type. -/// @param a The first value. -/// @param b The second value. -/// @param c The third value. -/// @return The smaller of the three values. -template -requires std::is_arithmetic_v GP_NODISCARD GP_FORCEINLINE constexpr T min(T a, T b, T c) noexcept -{ - return min(min(a, b), c); -} - -/// @brief Returns the larger of two values. -/// @tparam T The type of the values. Must be an arithmetic type. -/// @param a The first value. -/// @param b The second value. -/// @return The larger of the two values. -template -requires std::is_arithmetic_v GP_NODISCARD GP_FORCEINLINE constexpr T max(T a, T b) noexcept -{ - return (a > b) ? a : b; -} - -/// @brief Returns the larger of three values. -/// @tparam T The type of the values. Must be an arithmetic type. -/// @param a The first value. -/// @param b The second value. -/// @param c The third value. -/// @return The larger of the three values. -template -requires std::is_arithmetic_v GP_NODISCARD GP_FORCEINLINE constexpr T max(T a, T b, T c) noexcept -{ - return max(max(a, b), c); -} - -/// @brief Clamps a value between a minimum and maximum value. -/// @tparam T The type of the values. Must be an arithmetic type. -/// @param value The value to clamp. -/// @param minimum The minimum value. -/// @param maximum The maximum value. -/// @return The clamped value. -template -requires std::is_arithmetic_v GP_NODISCARD GP_FORCEINLINE constexpr T clamp(T value, T minimum, T maximum) noexcept -{ - return max(minimum, min(value, maximum)); -} - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Mat2.hpp b/source/runtime/core/public/math/Mat2.hpp deleted file mode 100644 index 89742f7..0000000 --- a/source/runtime/core/public/math/Mat2.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 2x2 matrix template struct that can be used for various mathematical operations. -/// @tparam T The type of the matrix components, which must be a floating-point type (e.g., float, double). -template -struct Mat2 -{ -public: - union - { - struct - { - T x00, x01; - T x10, x11; - }; - - T data[4]; - }; - -public: - /// @brief Default constructor. Initializes the matrix to the identity matrix. - constexpr Mat2() noexcept - // clang-format off - : x00(1), x01(0) - , x10(0), x11(1) - // clang-format on - {} - - /// @brief Constructs a matrix with the given components. - /// @param x00 The (0,0) component of the matrix. - /// @param x01 The (0,1) component of the matrix. - /// @param x10 The (1,0) component of the matrix. - /// @param x11 The (1,1) component of the matrix. - constexpr Mat2(T x00, T x01, T x10, T x11) noexcept - // clang-format off - : x00(x00), x01(x01) - , x10(x10), x11(x11) - // clang-format on - {} - - /// @brief Constructs a matrix with the same value for all diagonal components. - /// @param value The value to set for all diagonal components. - explicit constexpr Mat2(T value) noexcept - // clang-format off - : x00(value), x01(0) - , x10(0) , x11(value) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of four elements. - /// @param ptr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat2(const T* ptr) noexcept - // clang-format off - : x00(ptr[0]), x01(ptr[1]) - , x10(ptr[2]), x11(ptr[3]) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of four elements. - /// @param arr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat2(const T (&arr)[4]) noexcept - // clang-format off - : x00(arr[0]), x01(arr[1]) - , x10(arr[2]), x11(arr[3]) - // clang-format on - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Mat3.hpp b/source/runtime/core/public/math/Mat3.hpp deleted file mode 100644 index 9c0109f..0000000 --- a/source/runtime/core/public/math/Mat3.hpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 3x3 matrix template struct that can be used for various mathematical operations. -/// @tparam T The type of the matrix components, which must be a floating-point type (e.g., float, double). -template -struct Mat3 -{ -public: - union - { - struct - { - T x00, x01, x02; - T x10, x11, x12; - T x20, x21, x22; - }; - - T data[9]; - }; - -public: - /// @brief Default constructor. Initializes the matrix to the identity matrix. - constexpr Mat3() noexcept - // clang-format off - : x00(1), x01(0), x02(0) - , x10(0), x11(1), x12(0) - , x20(0), x21(0), x22(1) - // clang-format on - {} - - /// @brief Constructs a matrix with the given components. - /// @param x00 The (0,0) component of the matrix. - /// @param x01 The (0,1) component of the matrix. - /// @param x02 The (0,2) component of the matrix. - /// @param x10 The (1,0) component of the matrix. - /// @param x11 The (1,1) component of the matrix. - /// @param x12 The (1,2) component of the matrix. - /// @param x20 The (2,0) component of the matrix. - /// @param x21 The (2,1) component of the matrix. - /// @param x22 The (2,2) component of the matrix. - constexpr Mat3(T x00, T x01, T x02, T x10, T x11, T x12, T x20, T x21, T x22) noexcept - // clang-format off - : x00(x00), x01(x01), x02(x02) - , x10(x10), x11(x11), x12(x12) - , x20(x20), x21(x21), x22(x22) - // clang-format on - {} - - /// @brief Constructs a matrix with the same value for all diagonal components. - /// @param value The value to set for all diagonal components. - explicit constexpr Mat3(T value) noexcept - // clang-format off - : x00(value), x01(0) , x02(0) - , x10(0) , x11(value), x12(0) - , x20(0) , x21(0) , x22(value) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of all elements. - /// @param ptr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat3(const T* ptr) noexcept - // clang-format off - : x00(ptr[0]), x01(ptr[1]), x02(ptr[2]) - , x10(ptr[3]), x11(ptr[4]), x12(ptr[5]) - , x20(ptr[6]), x21(ptr[7]), x22(ptr[8]) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of all elements. - /// @param arr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat3(const T (&arr)[9]) noexcept - // clang-format off - : x00(arr[0]), x01(arr[1]), x02(arr[2]) - , x10(arr[3]), x11(arr[4]), x12(arr[5]) - , x20(arr[6]), x21(arr[7]), x22(arr[8]) - // clang-format on - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Mat34.hpp b/source/runtime/core/public/math/Mat34.hpp deleted file mode 100644 index c2a7cd4..0000000 --- a/source/runtime/core/public/math/Mat34.hpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 3x4 matrix template struct that can be used for various mathematical operations. -/// @tparam T The type of the matrix components, which must be a floating-point type (e.g., float, double). -template -struct Mat34 -{ -public: - union - { - struct - { - T x00, x01, x02, x03; - T x10, x11, x12, x13; - T x20, x21, x22, x23; - }; - - T data[12]; - }; - -public: - /// @brief Default constructor. Initializes the matrix to the identity matrix. - constexpr Mat34() noexcept - // clang-format off - : x00(1), x01(0), x02(0), x03(0) - , x10(0), x11(1), x12(0), x13(0) - , x20(0), x21(0), x22(1), x23(0) - // clang-format on - {} - - /// @brief Constructs a matrix with the given components. - /// @param x00 The (0,0) component of the matrix. - /// @param x01 The (0,1) component of the matrix. - /// @param x02 The (0,2) component of the matrix. - /// @param x03 The (0,3) component of the matrix. - /// @param x10 The (1,0) component of the matrix. - /// @param x11 The (1,1) component of the matrix. - /// @param x12 The (1,2) component of the matrix. - /// @param x13 The (1,3) component of the matrix. - /// @param x20 The (2,0) component of the matrix. - /// @param x21 The (2,1) component of the matrix. - /// @param x22 The (2,2) component of the matrix. - /// @param x23 The (2,3) component of the matrix. - constexpr Mat34(T x00, T x01, T x02, T x03, T x10, T x11, T x12, T x13, T x20, T x21, T x22, T x23) noexcept - // clang-format off - : x00(x00), x01(x01), x02(x02), x03(x03) - , x10(x10), x11(x11), x12(x12), x13(x13) - , x20(x20), x21(x21), x22(x22), x23(x23) - // clang-format on - {} - - /// @brief Constructs a matrix with the same value for all diagonal components. - /// @param value The value to set for all diagonal components. - explicit constexpr Mat34(T value) noexcept - // clang-format off - : x00(value), x01(0) , x02(0) , x03(0) - , x10(0) , x11(value), x12(0) , x13(0) - , x20(0) , x21(0) , x22(value), x23(0) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of all elements. - /// @param ptr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat34(const T* ptr) noexcept - // clang-format off - : x00(ptr[0]), x01(ptr[1]), x02(ptr[2]), x03(ptr[3]) - , x10(ptr[4]), x11(ptr[5]), x12(ptr[6]), x13(ptr[7]) - , x20(ptr[8]), x21(ptr[9]), x22(ptr[10]), x23(ptr[11]) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of all elements. - /// @param arr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat34(const T (&arr)[12]) noexcept - // clang-format off - : x00(arr[0]), x01(arr[1]), x02(arr[2]), x03(arr[3]) - , x10(arr[4]), x11(arr[5]), x12(arr[6]), x13(arr[7]) - , x20(arr[8]), x21(arr[9]), x22(arr[10]), x23(arr[11]) - // clang-format on - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Mat4.hpp b/source/runtime/core/public/math/Mat4.hpp deleted file mode 100644 index 82909df..0000000 --- a/source/runtime/core/public/math/Mat4.hpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 4x4 matrix template struct that can be used for various mathematical operations. -/// @tparam T The type of the matrix components, which must be a floating-point type (e.g., float, double). -template -struct Mat4 -{ -public: - union - { - struct - { - T x00, x01, x02, x03; - T x10, x11, x12, x13; - T x20, x21, x22, x23; - T x30, x31, x32, x33; - }; - - T data[16]; - }; - -public: - /// @brief Default constructor. Initializes the matrix to the identity matrix. - constexpr Mat4() noexcept - // clang-format off - : x00(1), x01(0), x02(0), x03(0) - , x10(0), x11(1), x12(0), x13(0) - , x20(0), x21(0), x22(1), x23(0) - , x30(0), x31(0), x32(0), x33(1) - // clang-format on - {} - - /// @brief Constructs a matrix with the given components. - /// @param x00 The (0,0) component of the matrix. - /// @param x01 The (0,1) component of the matrix. - /// @param x02 The (0,2) component of the matrix. - /// @param x03 The (0,3) component of the matrix. - /// @param x10 The (1,0) component of the matrix. - /// @param x11 The (1,1) component of the matrix. - /// @param x12 The (1,2) component of the matrix. - /// @param x13 The (1,3) component of the matrix. - /// @param x20 The (2,0) component of the matrix. - /// @param x21 The (2,1) component of the matrix. - /// @param x22 The (2,2) component of the matrix. - /// @param x23 The (2,3) component of the matrix. - /// @param x30 The (3,0) component of the matrix. - /// @param x31 The (3,1) component of the matrix. - /// @param x32 The (3,2) component of the matrix. - /// @param x33 The (3,3) component of the matrix. - constexpr Mat4( - T x00, T x01, T x02, T x03, T x10, T x11, T x12, T x13, T x20, T x21, T x22, T x23, T x30, T x31, T x32, T x33 - ) noexcept - // clang-format off - : x00(x00), x01(x01), x02(x02), x03(x03) - , x10(x10), x11(x11), x12(x12), x13(x13) - , x20(x20), x21(x21), x22(x22), x23(x23) - , x30(x30), x31(x31), x32(x32), x33(x33) - // clang-format on - {} - - /// @brief Constructs a matrix with the same value for all diagonal components. - /// @param value The value to set for all diagonal components. - explicit constexpr Mat4(T value) noexcept - // clang-format off - : x00(value), x01(0) , x02(0) , x03(0) - , x10(0) , x11(value), x12(0) , x13(0) - , x20(0) , x21(0) , x22(value), x23(0) - , x30(0) , x31(0) , x32(0) , x33(value) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of all elements. - /// @param ptr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat4(const T* ptr) noexcept - // clang-format off - : x00(ptr[0]), x01(ptr[1]), x02(ptr[2]), x03(ptr[3]) - , x10(ptr[4]), x11(ptr[5]), x12(ptr[6]), x13(ptr[7]) - , x20(ptr[8]), x21(ptr[9]), x22(ptr[10]), x23(ptr[11]) - , x30(ptr[12]), x31(ptr[13]), x32(ptr[14]), x33(ptr[15]) - // clang-format on - {} - - /// @brief Constructs a matrix from an array of all elements. - /// @param arr An array containing the components of the matrix. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Mat4(const T (&arr)[16]) noexcept - // clang-format off - : x00(arr[0]), x01(arr[1]), x02(arr[2]), x03(arr[3]) - , x10(arr[4]), x11(arr[5]), x12(arr[6]), x13(arr[7]) - , x20(arr[8]), x21(arr[9]), x22(arr[10]), x23(arr[11]) - , x30(arr[12]), x31(arr[13]), x32(arr[14]), x33(arr[15]) - // clang-format on - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Vec2.hpp b/source/runtime/core/public/math/Vec2.hpp deleted file mode 100644 index c31f65c..0000000 --- a/source/runtime/core/public/math/Vec2.hpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 2D vector class template that represents a vector in 2D space with components of type T. -/// @tparam T The type of the vector components, which must be a floating-point type (e.g., float, double). -template -struct Vec2 -{ -public: - union - { - struct - { - T x; - T y; - }; - - T data[2]; - }; - -public: - /// @brief Default constructor. Initializes the vector to (0, 0). - constexpr Vec2() noexcept - : x(0) - , y(0) - {} - - /// @brief Constructs a vector with the given x and y components. - /// @param x The x component of the vector. - /// @param y The y component of the vector. - constexpr Vec2(T x, T y) noexcept - : x(x) - , y(y) - {} - - /// @brief Constructs a vector with the same value for both x and y components. - /// @param value The value to set for both x and y components. - explicit constexpr Vec2(T value) noexcept - : x(value) - , y(value) - {} - - /// @brief Constructs a vector from an array of two elements. - /// @param ptr An array containing the x and y components of the vector. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Vec2(const T* ptr) noexcept - : x(ptr[0]) - , y(ptr[1]) - {} - - /// @brief Constructs a vector from an array of two elements. - /// @param arr An array containing the x and y components of the vector. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Vec2(const T (&arr)[2]) noexcept - : x(arr[0]) - , y(arr[1]) - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Vec3.hpp b/source/runtime/core/public/math/Vec3.hpp deleted file mode 100644 index 5a46629..0000000 --- a/source/runtime/core/public/math/Vec3.hpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 3D vector class template that represents a vector in 3D space with components of type T. -/// @tparam T The type of the vector components, which must be a floating-point type (e.g., float, double). -template -struct Vec3 -{ -public: - union - { - struct - { - T x; - T y; - T z; - }; - - T data[3]; - }; - -public: - /// @brief Default constructor. Initializes the vector to (0, 0, 0). - constexpr Vec3() noexcept - : x(0) - , y(0) - , z(0) - {} - - /// @brief Constructs a vector with the given x, y, and z components. - /// @param x The x component of the vector. - /// @param y The y component of the vector. - /// @param z The z component of the vector. - constexpr Vec3(T x, T y, T z) noexcept - : x(x) - , y(y) - , z(z) - {} - - /// @brief Constructs a vector with the same value for all components. - /// @param value The value to set for all components. - explicit constexpr Vec3(T value) noexcept - : x(value) - , y(value) - , z(value) - {} - - /// @brief Constructs a vector from an array of three elements. - /// @param ptr An array containing the x, y, and z components of the vector. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Vec3(const T* ptr) noexcept - : x(ptr[0]) - , y(ptr[1]) - , z(ptr[2]) - {} - - /// @brief Constructs a vector from an array of three elements. - /// @param arr An array containing the x, y, and z components of the vector. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Vec3(const T (&arr)[3]) noexcept - : x(arr[0]) - , y(arr[1]) - , z(arr[2]) - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/math/Vec4.hpp b/source/runtime/core/public/math/Vec4.hpp deleted file mode 100644 index fae324a..0000000 --- a/source/runtime/core/public/math/Vec4.hpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "math/Forward.hpp" -#include - -namespace gp::math -{ - -/// @brief A 4D vector class template that represents a vector in 4D space with components of type T. -/// @tparam T The type of the vector components, which must be a floating-point type (e.g., float, double). -template -struct Vec4 -{ -public: - union - { - struct - { - T x; - T y; - T z; - T w; - }; - - T data[4]; - }; - -public: - /// @brief Default constructor. Initializes the vector to (0, 0, 0, 0). - constexpr Vec4() noexcept - : x(0) - , y(0) - , z(0) - , w(0) - {} - - /// @brief Constructs a vector with the given x, y, z, and w components. - /// @param x The x component of the vector. - /// @param y The y component of the vector. - /// @param z The z component of the vector. - /// @param w The w component of the vector. - constexpr Vec4(T x, T y, T z, T w) noexcept - : x(x) - , y(y) - , z(z) - , w(w) - {} - - /// @brief Constructs a vector with the same value for all components. - /// @param value The value to set for all components. - explicit constexpr Vec4(T value) noexcept - : x(value) - , y(value) - , z(value) - , w(value) - {} - - /// @brief Constructs a vector from an array of four elements. - /// @param ptr An array containing the x, y, z, and w components of the vector. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Vec4(const T* ptr) noexcept - : x(ptr[0]) - , y(ptr[1]) - , z(ptr[2]) - , w(ptr[3]) - {} - - /// @brief Constructs a vector from an array of four elements. - /// @param arr An array containing the x, y, z, and w components of the vector. - /// @warning No bounds checking is performed on the input array. - explicit constexpr Vec4(const T (&arr)[4]) noexcept - : x(arr[0]) - , y(arr[1]) - , z(arr[2]) - , w(arr[3]) - {} -}; - -} // namespace gp::math diff --git a/source/runtime/core/public/maths/MathForward.hpp b/source/runtime/core/public/maths/MathForward.hpp new file mode 100644 index 0000000..144e992 --- /dev/null +++ b/source/runtime/core/public/maths/MathForward.hpp @@ -0,0 +1,41 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "concepts/Concepts.hpp" +#include "CoreMinimal.hpp" // IWYU pragma: keep + +namespace gp::math +{ + +// clang-format off + +template struct Vector2; +template struct Vector3; +template struct Vector4; + +template struct Matrix2x2; +template struct Matrix3x3; +template struct Matrix3x4; +template struct Matrix4x4; + +template struct Rotator; +template struct Rotator2D; +template struct Quaternion; +template struct DualQuaternion; + +template struct Frustum; +template struct Plane; +template struct Ray; +template struct Sphere; +template struct Triangle; + +template struct Transform; +template struct Projection; +template struct View; + +// clang-format on + +} // namespace gp::math diff --git a/source/runtime/core/public/memory/backends/MallocBinned.hpp b/source/runtime/core/public/maths/base/Constants.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocBinned.hpp rename to source/runtime/core/public/maths/base/Constants.hpp diff --git a/source/runtime/core/public/memory/backends/MallocBinned64.hpp b/source/runtime/core/public/maths/geometry/primitives/Frustum.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocBinned64.hpp rename to source/runtime/core/public/maths/geometry/primitives/Frustum.hpp diff --git a/source/runtime/core/public/memory/backends/MallocJeMalloc.hpp b/source/runtime/core/public/maths/geometry/primitives/Plane.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocJeMalloc.hpp rename to source/runtime/core/public/maths/geometry/primitives/Plane.hpp diff --git a/source/runtime/core/public/memory/backends/MallocLibPAS.hpp b/source/runtime/core/public/maths/geometry/primitives/Ray.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocLibPAS.hpp rename to source/runtime/core/public/maths/geometry/primitives/Ray.hpp diff --git a/source/runtime/core/public/memory/backends/MallocMiMalloc.hpp b/source/runtime/core/public/maths/geometry/primitives/Sphere.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocMiMalloc.hpp rename to source/runtime/core/public/maths/geometry/primitives/Sphere.hpp diff --git a/source/runtime/core/public/memory/backends/MallocStomp.hpp b/source/runtime/core/public/maths/geometry/primitives/Triangle.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocStomp.hpp rename to source/runtime/core/public/maths/geometry/primitives/Triangle.hpp diff --git a/source/runtime/core/public/memory/backends/MallocTBB.hpp b/source/runtime/core/public/maths/matrix/Matrix2x2.hpp similarity index 100% rename from source/runtime/core/public/memory/backends/MallocTBB.hpp rename to source/runtime/core/public/maths/matrix/Matrix2x2.hpp diff --git a/source/runtime/core/public/utils/Forward.hpp b/source/runtime/core/public/maths/matrix/Matrix3x3.hpp similarity index 100% rename from source/runtime/core/public/utils/Forward.hpp rename to source/runtime/core/public/maths/matrix/Matrix3x3.hpp diff --git a/source/runtime/input/public/Input.hpp b/source/runtime/core/public/maths/matrix/Matrix3x4.hpp similarity index 100% rename from source/runtime/input/public/Input.hpp rename to source/runtime/core/public/maths/matrix/Matrix3x4.hpp diff --git a/source/runtime/io/public/IO.hpp b/source/runtime/core/public/maths/matrix/Matrix4x4.hpp similarity index 100% rename from source/runtime/io/public/IO.hpp rename to source/runtime/core/public/maths/matrix/Matrix4x4.hpp diff --git a/source/runtime/network/public/Network.hpp b/source/runtime/core/public/maths/rotation/DualQuaternion.hpp similarity index 100% rename from source/runtime/network/public/Network.hpp rename to source/runtime/core/public/maths/rotation/DualQuaternion.hpp diff --git a/source/runtime/physics/public/Physics.hpp b/source/runtime/core/public/maths/rotation/Quaternion.hpp similarity index 100% rename from source/runtime/physics/public/Physics.hpp rename to source/runtime/core/public/maths/rotation/Quaternion.hpp diff --git a/source/runtime/rhi/base/public/RHI.hpp b/source/runtime/core/public/maths/rotation/Rotator.hpp similarity index 100% rename from source/runtime/rhi/base/public/RHI.hpp rename to source/runtime/core/public/maths/rotation/Rotator.hpp diff --git a/source/runtime/rhi/d3d11/public/D3D11.hpp b/source/runtime/core/public/maths/rotation/Rotator2D.hpp similarity index 100% rename from source/runtime/rhi/d3d11/public/D3D11.hpp rename to source/runtime/core/public/maths/rotation/Rotator2D.hpp diff --git a/source/runtime/rhi/d3d12/public/D3D12.hpp b/source/runtime/core/public/maths/simd/AVX.hpp similarity index 100% rename from source/runtime/rhi/d3d12/public/D3D12.hpp rename to source/runtime/core/public/maths/simd/AVX.hpp diff --git a/source/runtime/rhi/metal/public/Metal.hpp b/source/runtime/core/public/maths/simd/Common.hpp similarity index 100% rename from source/runtime/rhi/metal/public/Metal.hpp rename to source/runtime/core/public/maths/simd/Common.hpp diff --git a/source/runtime/rhi/null/public/Null.hpp b/source/runtime/core/public/maths/simd/NEON.hpp similarity index 100% rename from source/runtime/rhi/null/public/Null.hpp rename to source/runtime/core/public/maths/simd/NEON.hpp diff --git a/source/runtime/rhi/opengl/public/OpenGL.hpp b/source/runtime/core/public/maths/simd/SSE.hpp similarity index 100% rename from source/runtime/rhi/opengl/public/OpenGL.hpp rename to source/runtime/core/public/maths/simd/SSE.hpp diff --git a/source/runtime/rhi/vulkan/public/Vulkan.hpp b/source/runtime/core/public/maths/transform/Projection.hpp similarity index 100% rename from source/runtime/rhi/vulkan/public/Vulkan.hpp rename to source/runtime/core/public/maths/transform/Projection.hpp diff --git a/source/shaders/private/Common.hlsl b/source/runtime/core/public/maths/transform/Transform.hpp similarity index 100% rename from source/shaders/private/Common.hlsl rename to source/runtime/core/public/maths/transform/Transform.hpp diff --git a/source/shaders/public/Platform.hlsli b/source/runtime/core/public/maths/transform/View.hpp similarity index 100% rename from source/shaders/public/Platform.hlsli rename to source/runtime/core/public/maths/transform/View.hpp diff --git a/source/shaders/shared/hlsl/TypeAliases.hpp b/source/runtime/core/public/maths/vector/Vector2.hpp similarity index 100% rename from source/shaders/shared/hlsl/TypeAliases.hpp rename to source/runtime/core/public/maths/vector/Vector2.hpp diff --git a/source/runtime/core/private/memory/backends/MallocTBB.cpp b/source/runtime/core/public/maths/vector/Vector3.hpp similarity index 81% rename from source/runtime/core/private/memory/backends/MallocTBB.cpp rename to source/runtime/core/public/maths/vector/Vector3.hpp index 2d9662e..88b9360 100644 --- a/source/runtime/core/private/memory/backends/MallocTBB.cpp +++ b/source/runtime/core/public/maths/vector/Vector3.hpp @@ -2,4 +2,4 @@ // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com -#include "memory/backends/MallocTBB.hpp" +#pragma once diff --git a/source/runtime/core/private/memory/backends/MallocStomp.cpp b/source/runtime/core/public/maths/vector/Vector4.hpp similarity index 80% rename from source/runtime/core/private/memory/backends/MallocStomp.cpp rename to source/runtime/core/public/maths/vector/Vector4.hpp index 6670258..88b9360 100644 --- a/source/runtime/core/private/memory/backends/MallocStomp.cpp +++ b/source/runtime/core/public/maths/vector/Vector4.hpp @@ -2,4 +2,4 @@ // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com -#include "memory/backends/MallocStomp.hpp" +#pragma once diff --git a/source/runtime/core/public/memory/Memory.hpp b/source/runtime/core/public/memory/Memory.hpp new file mode 100644 index 0000000..7f0ee30 --- /dev/null +++ b/source/runtime/core/public/memory/Memory.hpp @@ -0,0 +1,206 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "concepts/Concepts.hpp" +#include "CoreMinimal.hpp" +#include "platforms/base/PlatformMemory.hpp" +#include + +namespace gp::memory +{ + +/// @brief Allocation hints that can be used to provide additional information about the intended usage of a memory +/// allocation. These hints can help the memory allocator make informed decisions about how to manage memory, such as +/// choosing the appropriate memory pool or optimizing for specific access patterns. The specific meaning and handling +/// of these hints may vary depending on the platform and memory allocator implementation. +enum class AllocationHints +{ + None = -1, + Default, + Temporary, + SmallPool, + COUNT +}; + +/// @brief Moves a block of memory from the source to the destination, handling overlapping regions correctly. +/// @note The behavior is similar to `memmove` in C/C++. +/// @param[in] destination The pointer to the destination memory block where the content will be moved. +/// @param[in] source The pointer to the source memory block from which the content will be moved. +/// @param[in] numBytes The number of bytes to move from the source to the destination. +/// @return A pointer to the destination memory block after the move operation is complete. +GP_FORCEINLINE_HINT void* moveMemory(void* destination, const void* source, USize numBytes) +{ + return gp::platform::Memory::moveMemory(destination, source, numBytes); +} + +/// @brief Compares two blocks of memory. +/// @note The behavior is similar to `memcmp` in C/C++. +/// @param[in] ptr1 The pointer to the first memory block to compare. +/// @param[in] ptr2 The pointer to the second memory block to compare. +/// @param[in] numBytes The number of bytes to compare. +/// @return An integer indicating the result of the comparison. +GP_FORCEINLINE_HINT int compareMemory(const void* ptr1, const void* ptr2, USize numBytes) +{ + return gp::platform::Memory::compareMemory(ptr1, ptr2, numBytes); +} + +/// @brief Sets a block of memory to a specified value. This function fills the first numBytes bytes of the memory +/// area pointed to by destination with the constant byte value. +/// @note The behavior is similar to `memset` in C/C++. +/// @param[in] destination The pointer to the destination memory block where the content will be set. +/// @param[in] value The value to set each byte of the memory block to. +/// @param[in] numBytes The number of bytes to set. +/// @return A pointer to the destination memory block after the set operation is complete. +GP_FORCEINLINE_HINT void* setMemory(void* destination, int value, USize numBytes) +{ + return gp::platform::Memory::setMemory(destination, value, numBytes); +} + +/// @brief Template overload of setMemory for non-pointer types. This function sets the memory of a non-pointer type to +/// a specified value. +/// @note This function is a convenience overload that allows setting the memory of non-pointer types without needing to +/// take the address of the variable. It uses the size of the type to determine how many bytes to set. +/// @tparam T The type of the variable whose memory is to be set. This type must not be a pointer type, as indicated by +/// the concept constraint. +/// @param[in] source The reference to the variable whose memory will be set. +/// @param[in] value The value to set each byte of the memory block to. +template +requires(!concepts::IsPointer) inline void setMemory(T& source, UInt8 value) +{ + setMemory(&source, value, sizeof(T)); +} + +/// @brief Sets a block of memory to zero. +/// @note The behavior is similar to `memset` with a value of 0 in C/C++. +/// @param[in] destination The pointer to the destination memory block where the content will be set to zero. +/// @param[in] numBytes The number of bytes to set to zero. +/// @return A pointer to the destination memory block after the zeroing operation is complete. +GP_FORCEINLINE_HINT void* zeroMemory(void* destination, USize numBytes) +{ + return gp::platform::Memory::zeroMemory(destination, numBytes); +} + +/// @brief Template overload of zeroMemory for non-pointer types. This function sets the memory of a non-pointer type to +/// zero. +/// @note This function is a convenience overload that allows zeroing the memory of non-pointer types without needing to +/// take the address of the variable. It uses the size of the type to determine how many bytes to set to zero. +/// @tparam T The type of the variable whose memory is to be zeroed. This type must not be a pointer type, as indicated +/// by the concept constraint. +/// @param[in] source The reference to the variable whose memory will be zeroed. +template +requires(!concepts::IsPointer) inline void zeroMemory(T& source) +{ + zeroMemory(&source, sizeof(T)); +} + +/// @brief Checks if a block of memory is zeroed (i.e., all bytes are set to zero). +/// @param[in] ptr The pointer to the memory block to check. +/// @param[in] numBytes The number of bytes to check in the memory block. +/// @return `true` if all bytes in the specified memory block are zero, otherwise `false`. +inline bool isMemoryZeroed(const void* ptr, USize numBytes) +{ + if (GP_UNLIKELY(ptr == nullptr || numBytes == 0)) + { + return true; + } + + auto* bytePtr = static_cast(ptr); + return std::ranges::all_of( + bytePtr, + bytePtr + numBytes, + [](UInt8 byte) + { + return byte == 0; + } + ); +} + +/// @brief Copies a block of memory from the source to the destination. The behavior is undefined if the source and +/// destination overlap. +/// @note The behavior is similar to `memcpy` in C/C++. +/// @param[in] destination The pointer to the destination memory block where the content will be copied. +/// @param[in] source The pointer to the source memory block from which the content will be copied. +/// @param[in] numBytes The number of bytes to copy from the source to the destination. +/// @return A pointer to the destination memory block after the copy operation is complete. +GP_FORCEINLINE_HINT void* copyMemory(void* destination, const void* source, USize numBytes) +{ + return gp::platform::Memory::copyMemory(destination, source, numBytes); +} + +/// @brief Template overload of copyMemory for non-pointer types. This function copies the memory of a non-pointer type +/// from the source to the destination. +/// @note This function is a convenience overload that allows copying the memory of non-pointer types without needing to +/// take the address of the variables. It uses the size of the type to determine how many bytes to copy. +/// @tparam T The type of the variables whose memory is to be copied. This type must not be a pointer type, as indicated +/// by the concept constraint. +/// @param[in] destination The reference to the variable where the content will be copied to. +/// @param[in] source The reference to the variable from which the content will be copied. +template +requires(!concepts::IsPointer) inline void copyMemory(T& destination, const T& source) +{ + copyMemory(&destination, &source, sizeof(T)); +} + +/// @brief Copies a block of memory from the source to the destination, optimized for large blocks of memory. +/// @note The behavior is similar to `memcpy` in C/C++, but may be optimized for larger blocks of memory. +/// @param[in] destination The pointer to the destination memory block where the content will be copied. +/// @param[in] source The pointer to the source memory block from which the content will be copied. +/// @param[in] numBytes The number of bytes to copy from the source to the destination. +/// @return A pointer to the destination memory block after the copy operation is complete. +GP_FORCEINLINE_HINT void* copyBigBlockMemory(void* destination, const void* source, USize numBytes) +{ + return gp::platform::Memory::copyBigBlockMemory(destination, source, numBytes); +} + +/// @brief Copies a block of memory from the source to the destination, optimized for streaming data. On some +/// platforms, this is optimized for big blocks that avoid L2 cache pollution. +/// @note The behavior is similar to `memcpy` in C/C++, but may be optimized for streaming data or large blocks of +/// memory. +/// @param[in] destination The pointer to the destination memory block where the content will be copied. +/// @param[in] source The pointer to the source memory block from which the content will be copied. +/// @param[in] numBytes The number of bytes to copy from the source to the destination. +/// @return A pointer to the destination memory block after the copy operation is complete. +GP_FORCEINLINE_HINT void* copyStreamingMemory(void* destination, const void* source, gp::USize numBytes) +{ + return gp::platform::Memory::copyStreamingMemory(destination, source, numBytes); +} + +/// @brief Copies a block of memory from the source to the destination, optimized for parallel execution. On some +/// platforms, memory copy operations can be distributed across multiple threads or hardware units. +/// @note The behavior is similar to `memcpy` in C/C++, but may be optimized for parallel execution on some +/// platforms. +/// @param[in] destination The pointer to the destination memory block where the content will be copied. +/// @param[in] source The pointer to the source memory block from which the content will be copied. +/// @param[in] numBytes The number of bytes to copy from the source to the destination. +/// @param[in] policy The cache policy to use for the memory copy operation. This parameter is optional and may be +/// ignored on some platforms. +/// @return A pointer to the destination memory block after the copy operation is complete. +GP_FORCEINLINE_HINT void* copyMemoryParallel( + void* destination, const void* source, gp::USize numBytes + /* MemoryCopyCachePolicy policy = MemoryCopyCachePolicy::StoreCached */ +) +{ + return gp::platform::Memory::copyMemoryParallel(destination, source, numBytes /*, policy*/); +} + +/// @brief Allocates a block of memory of the specified size. C style memory allocation stubs to fall back to the +/// standard library's `malloc` function. +/// @param[in] size The size of the memory block to allocate, in bytes. +/// @return A pointer to the allocated memory block, or `nullptr` if the allocation fails. +GP_ALLOCATION_FUNCTION(1) inline void* systemAllocate(USize size) +{ + return ::malloc(size); +} + +/// @brief Deallocates a block of memory that was previously allocated. C style memory deallocation stubs to fall back +/// to the standard library's `free` function. +/// @param[in] ptr The pointer to the memory block to deallocate. +inline void systemDeallocate(void* ptr) +{ + ::free(ptr); +} + +} // namespace gp::memory diff --git a/source/runtime/core/public/memory/MemoryBase.hpp b/source/runtime/core/public/memory/MemoryBase.hpp index 67f671b..1e78875 100644 --- a/source/runtime/core/public/memory/MemoryBase.hpp +++ b/source/runtime/core/public/memory/MemoryBase.hpp @@ -4,19 +4,86 @@ #pragma once +#include "concepts/Concepts.hpp" #include "CoreMinimal.hpp" namespace gp::memory { -/// @brief Default alignment for memory allocations. This value is used when no specific alignment is provided. -/// If the default is specified, the allocator applies to engine rules. -/// Blocks >= 16 bytes will be 16-byte-aligned, Blocks < 16 will be 8-byte aligned. If the allocator does not support -/// allocation alignment, the alignment will be ignored. -static constexpr gp::UInt32 kDefaultAlignment = 0; +static constexpr UInt32 kDefaultAlignment = 0; +static constexpr UInt32 kMinimumAlignment = 8; -/// @brief Minimum alignment for memory allocations. This value is the smallest alignment that can be requested from an -/// allocator. -static constexpr gp::UInt32 kMinAlignment = 8; +/// @brief Aligns a value to the nearest higher multiple of the specified alignment. +/// @tparam T Must be an integral or pointer type. +/// @param[in] value The value to be aligned. +/// @param[in] alignment The alignment boundary. Must be a power of two. +/// @return The aligned value. +template +requires concepts::IsIntegral || concepts::IsPointer inline constexpr T align(T value, UInt64 alignment) +{ + if constexpr (concepts::IsPointer) + { + return reinterpret_cast((reinterpret_cast(value) + alignment - 1) & ~(alignment - 1)); + } + else + { + return static_cast((static_cast(value) + alignment - 1) & ~(alignment - 1)); + } +} + +/// @brief Aligns a value to the nearest lower multiple of the specified alignment. +/// @tparam T Must be an integral or pointer type. +/// @param[in] value The value to be aligned. +/// @param[in] alignment The alignment boundary. Must be a power of two. +/// @return The aligned value. +template +requires concepts::IsIntegral || concepts::IsPointer inline constexpr T alignDown(T value, UInt64 alignment) +{ + if constexpr (concepts::IsPointer) + { + return reinterpret_cast(reinterpret_cast(value) & ~(alignment - 1)); + } + else + { + return static_cast(static_cast(value) & ~(alignment - 1)); + } +} + +/// @brief Checks if a value is already aligned to the specified alignment boundary. +/// @tparam T Must be an integral or pointer type. +/// @param[in] value The value to check for alignment. +/// @param[in] alignment The alignment boundary. Must be a power of two. +/// @return true if the value is aligned, false otherwise. +template +requires concepts::IsIntegral || concepts::IsPointer inline constexpr bool isAligned(T value, UInt64 alignment) +{ + if constexpr (concepts::IsPointer) + { + return (reinterpret_cast(value) & (alignment - 1)) == 0; + } + else + { + return (static_cast(value) & (alignment - 1)) == 0; + } +} + +/// @brief Aligns a value to the nearest higher multiple of the specified alignment without requiring the alignment to +/// be a power of two. +/// @tparam T Must be an integral or pointer type. +/// @param[in] value The value to be aligned. +/// @param[in] alignment The alignment boundary. +/// @return The aligned value. +template +requires concepts::IsIntegral || concepts::IsPointer inline constexpr T alignArbitrary(T value, UInt64 alignment) +{ + if constexpr (concepts::IsPointer) + { + return reinterpret_cast(((reinterpret_cast(value) + alignment - 1) / alignment) * alignment); + } + else + { + return static_cast(((static_cast(value) + alignment - 1) / alignment) * alignment); + } +} } // namespace gp::memory diff --git a/source/runtime/core/public/memory/MemoryForward.hpp b/source/runtime/core/public/memory/MemoryForward.hpp index 50db07d..3025c57 100644 --- a/source/runtime/core/public/memory/MemoryForward.hpp +++ b/source/runtime/core/public/memory/MemoryForward.hpp @@ -4,58 +4,33 @@ #pragma once +#include "CoreMinimal.hpp" // IWYU pragma: keep + namespace gp::memory { -/// @section Allocators Forward Declarations - -class Allocator; -class DefaultAllocator; -class StackAllocator; -class PoolAllocator; -class ArenaAllocator; -class LinearAllocator; -class InlineAllocator; -class FreeListAllocator; -class ProxyAllocator; -class TLSFAllocator; -class BuddyAllocator; - -template -class PolymorphicAllocator; - -/// @section Allocator Utilities - -template -struct AllocatorTraits; - -/// @section Malloc Backends +/// @section Malloc primitives forward declarations +class Malloc; class MallocAnsi; -class MallocBinned; -class MallocBinned64; -class MallocJeMalloc; -class MallocLibPAS; -class MallocMiMalloc; -class MallocStomp; -class MallocTBB; } // namespace gp::memory namespace gp { -/// @section Smart Pointers +/// @section Pointers forward declarations template -struct DefaultDelete; -template class UniquePtr; -template + +template class SharedPtr; -template + +template class WeakPtr; + template -class RefCountPtr; +class RefCountedPtr; } // namespace gp diff --git a/source/runtime/core/public/memory/MemoryUtilities.hpp b/source/runtime/core/public/memory/MemoryUtilities.hpp deleted file mode 100644 index 7cdf020..0000000 --- a/source/runtime/core/public/memory/MemoryUtilities.hpp +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "macros/MacroUtilities.hpp" -#include - -namespace gp::memory -{ - -/// @brief Aligns a value to the nearest multiple of the specified alignment. -/// @param[in] ptr The pointer to align. Must not be nullptr. -/// @param[in] alignment The alignment boundary (must be a power of two). -/// @return The aligned pointer. -template -requires std::is_integral_v || std::is_pointer_v GP_FORCEINLINE constexpr T alignT(T ptr, gp::UInt64 alignment) -{ - return (T)(((gp::UInt64)ptr + alignment - 1) & ~(alignment - 1)); -} - -/// @brief Rounds a value up to the nearest multiple of the given alignment. -/// @details -/// Alignment must be a power of two. This is a branchless, constexpr operation suitable for hot-path usage. -/// @param[in] value The value to align upward. -/// @param[in] alignment The alignment boundary (must be a power of two). -/// @return The smallest value >= input that is a multiple of alignment. -GP_FORCEINLINE constexpr USize alignUp(USize value, USize alignment) noexcept -{ - return (value + (alignment - 1)) & ~(alignment - 1); -} - -/// @brief Rounds a value down to the nearest multiple of the given alignment. -/// @param[in] value The value to align downward. -/// @param[in] alignment The alignment boundary (must be a power of two). -/// @return The largest value <= input that is a multiple of alignment. -GP_FORCEINLINE constexpr USize alignDown(USize value, USize alignment) noexcept -{ - return value & ~(alignment - 1); -} - -/// @brief Checks whether a value is aligned to the given boundary. -/// @param[in] value The value to check. -/// @param[in] alignment The alignment boundary (must be a power of two). -/// @return True if value is a multiple of alignment. -GP_FORCEINLINE constexpr bool isAligned(USize value, USize alignment) noexcept -{ - return (value & (alignment - 1)) == 0; -} - -/// @brief Checks whether a pointer is aligned to the given boundary. -/// @param[in] ptr The pointer to check. -/// @param[in] alignment The alignment boundary (must be a power of two). -/// @return True if the pointer address is a multiple of alignment. -GP_FORCEINLINE bool isAligned(const void* ptr, USize alignment) noexcept -{ - return isAligned(reinterpret_cast(ptr), alignment); -} - -/// @brief Low-level cross-platform aligned memory allocation. -/// @details -/// This is the single point of entry for all raw allocation in the engine. On POSIX platforms, the size is rounded up -/// to a multiple of alignment to satisfy the aligned_alloc(3) contract. On Windows, _aligned_malloc has no such -/// constraint but we round anyway for consistency. -/// @param[in] size The number of bytes to allocate. Must be > 0. -/// @param[in] alignment The required alignment (must be a power of two). -/// @return Pointer to the allocated memory, or nullptr on failure. -GP_NODISCARD GP_FORCEINLINE void* malloc(USize size, USize alignment = alignof(gp::MaxAlign)) noexcept -{ - if (size == 0) - { - return nullptr; - } - const USize alignedSize = alignUp(size, alignment); - return GP_ALIGNED_ALLOC(alignedSize, alignment); -} - -/// @brief Low-level cross-platform aligned memory deallocation. -/// @details -/// Pairs with gp::memory::malloc. Passing nullptr is a safe no-op. -/// @param[in] ptr Pointer previously returned by gp::memory::malloc. -GP_FORCEINLINE void free(void* ptr) noexcept -{ - if (ptr) - { - GP_ALIGNED_FREE(ptr); - } -} - -/// @brief Compact metadata record stamped at the base of every allocation made through Allocator::construct / -/// Allocator::destruct and gp::MakeUnique. -/// @details -/// Solves the "polymorphic size problem": the deleter or destructor always receives the true sizeof(ConcreteType) from -/// the moment of construction, independent of the static type trough which the object is later accessed (e.g a -/// base-class pointer). -/// -/// -/// Memory layout produced by mallocWithHeader(): -/// -/// @code -/// ┌───────────────────────┬──────────────┬──────────────────────────────┐ -/// │ AllocationHeader │ back-offset │ T object │ -/// │ size (8B) | align(8B)│ (USize,8B) │ sizeof(T), alignof(T)–pad │ -/// └───────────────────────┴──────────────┴──────────────────────────────┘ -/// ^rawPtr ^objPtr (the T* returned to callers) -/// │◄──────────── headerZone ────────────►│ -/// @endcode -/// -/// The **back-offset** (stored in the sizeof(USize) bytes immediately preceding objPtr) holds the byte distance from -/// rawPtr to objPtr. Given any objPtr, the back-offset is recovered at `*(USize*)(objPtr - sizeof(USize))`, which then -/// yields `rawPtr = objPtr - backOffset`. -/// -/// ### Single-inheritance polymorphism -/// For a base class `B` and derived class `D` where `static_cast(d) == d` (same address), `B*` and `D*` point to -/// the same byte, so the back-offset read from `B* - sizeof(USize)` is identical to the one written for `D*`. Recovery -/// is exact. ✓ -/// -/// ### Multiple-inheritance limitation -/// When multiple inheritance causes a pointer adjustment (`static_cast(d) != d`), `B*` points into the interior of -/// the D allocation. `B* - sizeof(USize)` then reads data from inside the object, not from the back-offset slot, -/// producing a garbage rawPtr and near-certain heap corruption. **Do not store a UniquePtr that was constructed as a -/// UniquePtr under multiple inheritance.** The converting move constructor asserts on this condition in debug builds -/// (once GP_ASSERT is wired up). -struct AllocationHeader -{ - USize size; //(alignof(AllocationHeader)) : alignment; - - const USize zone = headerZoneSize(effectiveAlign); - const USize total = zone + size; - - void* rawPtr = gp::memory::malloc(total, effectiveAlign); - if (!rawPtr) - { - return nullptr; - } - - char* const raw = static_cast(rawPtr); - - // Write AllocationHeader at the raw allocation base. - AllocationHeader* const hdr = reinterpret_cast(raw); - hdr->size = size; - hdr->alignment = alignment; // original, not clamped — preserves caller's intent - - // Write the back-offset in the sizeof(USize) bytes immediately before objPtr. - // backOffset == zone, so given objPtr: rawPtr = (char*)objPtr - zone. - USize* const backOffsetSlot = reinterpret_cast(raw + zone - sizeof(USize)); - *backOffsetSlot = zone; - - return raw + zone; -} - -/// @brief Frees memory previously allocated by mallocWithHeader and returns the stored header. -/// @details -/// Reads the back-offset from (objPtr - sizeof(USize)), recovers rawPtr, reads the AllocationHeader, then calls -/// gp::memory::free(rawPtr). -/// -/// The caller is responsible for destroying the object before calling this function. -/// -/// @param[in] objPtr Pointer to the object storage as returned by mallocWithHeader. Must not be nullptr (checked by the -/// caller; no-op guard is in Allocator::destruct / DefaultDelete). -/// @return A copy of the AllocationHeader that was recorded at construction time. -GP_NODISCARD GP_FORCEINLINE AllocationHeader freeWithHeader(void* objPtr) noexcept -{ - const char* const obj = static_cast(objPtr); - - // Recover the raw allocation base via the back-offset slot. - const USize backOffset = *reinterpret_cast(obj - sizeof(USize)); - void* const rawPtr = const_cast(obj) - backOffset; - - // Capture header before freeing (header lives in the allocation we're about to release). - const AllocationHeader hdr = *reinterpret_cast(rawPtr); - - gp::memory::free(rawPtr); - return hdr; -} - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/allocators/Allocator.hpp b/source/runtime/core/public/memory/allocators/Allocator.hpp deleted file mode 100644 index 194a6a5..0000000 --- a/source/runtime/core/public/memory/allocators/Allocator.hpp +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include - -namespace gp::memory -{ - -/// @brief Base interface for memory allocators. -/// @details -/// Defines the common virtual interface for allocating, deallocating, and querying memory. -/// All concrete allocators derive from this class. -/// GP is compiled with -fno-exceptions. All allocation methods are noexcept and return nullptr on failure. -/// Constructors invoked via construct() must not throw; doing so calls std::terminate. -class Allocator -{ -public: - Allocator() = default; - Allocator(const Allocator&) = delete; - Allocator& operator=(const Allocator&) = delete; - virtual ~Allocator() = default; - -public: - /// @brief Allocates a block of memory with the specified size and alignment. - /// @param[in] size The number of bytes to allocate. - /// @param[in] alignment The required alignment of the allocated memory. - /// @return A void pointer to the allocated memory block, or nullptr if allocation fails. - GP_NODISCARD virtual void* allocate(USize size, USize alignment = alignof(gp::MaxAlign)) noexcept = 0; - - /// @brief Deallocates a previously allocated memory block. - /// @param[in] ptr Pointer to the memory block that should be freed. - /// @param[in] size The size in bytes of the block being freed. - virtual void deallocate(void* ptr, USize size) noexcept = 0; - - /// @brief Reallocates an existing memory block to a new size, preserving existing contents. - /// @param[in] ptr Pointer to the existing memory block. May be nullptr. - /// @param[in] oldSize The original size of the memory block. Ignored when ptr is nullptr. - /// @param[in] newSize The requested new size for the memory block. - /// @param[in] alignment The required alignment of the reallocated memory. - /// @return A void pointer to the reallocated memory block, or nullptr if reallocation fails. - GP_NODISCARD virtual void* - reallocate(void* ptr, USize oldSize, USize newSize, USize alignment = alignof(gp::MaxAlign)) noexcept - { - void* newPtr = allocate(newSize, alignment); - if (newPtr && ptr && oldSize > 0) - { - std::memcpy(newPtr, ptr, oldSize < newSize ? oldSize : newSize); - deallocate(ptr, oldSize); - } - return newPtr; - } - - /// @brief Resets the allocator to its initial state, freeing all allocations. - /// @details - /// Not all allocators support reset. The default implementation is a no-op. Allocators that support bulk - /// deallocation (linear, stack, arena) override this. - virtual void reset() noexcept - {} - - /// @brief Queries whether this allocator owns the given pointer. - /// @details - /// Used by composable allocators (proxy, fallback chains) to determine which allocator should service a - /// deallocation. The default returns false. - /// @param[in] ptr Pointer to query ownership of. - /// @return True if this allocator owns the memory at ptr, false otherwise. - GP_NODISCARD virtual bool owns(GP_MAYBE_UNUSED const void* ptr) const noexcept - { - return false; - } - - /// @brief Allocates an array of elements of type T without constructing them. - /// @tparam T Type of elements in the array to allocate memory for. - /// @param[in] count Number of elements to allocate memory for. - /// @return Pointer to the allocated memory block aligned for type T, or nullptr if allocation fails. - template - GP_NODISCARD T* allocateN(USize count) noexcept - { - return static_cast(allocate(count * sizeof(T), alignof(T))); - } - - /// @brief Deallocates a memory block previously allocated for an array of elements. - /// @tparam T Type of elements in the array. - /// @param[in] ptr Pointer to the memory block containing the unconstructed elements to deallocate. - /// @param[in] count Number of elements in the array to deallocate memory for. - template - void deallocateN(T* ptr, USize count) noexcept - { - deallocate(ptr, count * sizeof(T)); - } - - /// @brief Allocates memory and constructs an object of type T in-place using the provided arguments. - /// @details - /// GP is compiled with -fno-exceptions. If T's constructor would throw, std::terminate is called. Callers must - /// ensure T's constructor is noexcept or otherwise safe. - /// @tparam T Type of the object to construct. - /// @tparam Args Parameter pack for arguments passed to T's constructor. - /// @param[in] args Arguments to forward to T's constructor. - /// @return Pointer to the newly constructed object, or nullptr if memory allocation fails. - template - GP_NODISCARD T* construct(Args&&... args) noexcept - { - void* memory = allocate(sizeof(T), alignof(T)); - if (!memory) - { - return nullptr; - } - return ::new (memory) T(static_cast(args)...); - } - - /// @brief Destructs an object and deallocates its underlying memory. - /// @tparam T Type of the object being destructed. - /// @param[in] ptr Pointer to the object to destruct and deallocate. - template - void destruct(T* ptr) noexcept - { - if (ptr) - { - ptr->~T(); - deallocate(ptr, sizeof(T)); - } - } - - /// @brief Gets the total amount of memory currently allocated by this allocator. - /// @return The number of bytes currently allocated, or 0 if tracking is unsupported. - GP_NODISCARD virtual USize getAllocatedSize() const noexcept - { - return 0; - } - - /// @brief Gets the total number of active allocations managed by this allocator. - /// @return The number of active allocation instances, or 0 if tracking is unsupported. - GP_NODISCARD virtual USize getAllocationCount() const noexcept - { - return 0; - } - - /// @brief Retrieves a human-readable name for this allocator, useful for debugging. - /// @return A null-terminated C-string representing the debug name. - GP_NODISCARD virtual const char* getDebugName() const noexcept - { - return "Allocator"; - } -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/allocators/DefaultAllocator.hpp b/source/runtime/core/public/memory/allocators/DefaultAllocator.hpp deleted file mode 100644 index d1f1ce7..0000000 --- a/source/runtime/core/public/memory/allocators/DefaultAllocator.hpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "memory/allocators/Allocator.hpp" -#include "memory/MemoryUtilities.hpp" - -#if GP_BUILD_DEBUG - #include -#endif - -namespace gp::memory -{ - -/// @brief Global allocator backed by the platform's aligned malloc/free. -/// @details -/// Thread-safe by virtue of OS-level guarantees on malloc/free. -/// Allocation statistics are tracked only in debug builds to avoid introducing atomic contention -/// on the hot path in release. -/// -/// This is a singleton-style allocator. Use get() to obtain the global instance. -class DefaultAllocator final : public Allocator -{ -private: -#if GP_BUILD_DEBUG - std::atomic m_debugAllocatedSize{ 0 }; - std::atomic m_debugAllocationCount{ 0 }; -#endif - -public: - DefaultAllocator() = default; - DefaultAllocator(const DefaultAllocator&) = delete; - DefaultAllocator& operator=(const DefaultAllocator&) = delete; - ~DefaultAllocator() override = default; - -public: - /// @brief Returns the global default allocator instance. - /// @return Reference to the singleton default_allocator. - static DefaultAllocator& get() noexcept - { - static DefaultAllocator s_instance; - return s_instance; - } - -public: - /// @brief Allocates memory using the platform's aligned allocation. - /// @param[in] size The number of bytes to allocate. - /// @param[in] alignment The required alignment (must be a power of two). - /// @return Pointer to the allocated memory, or nullptr on failure. - GP_NODISCARD void* allocate(USize size, USize alignment = alignof(gp::MaxAlign)) noexcept override - { - void* ptr = gp::memory::malloc(size, alignment); -#if GP_BUILD_DEBUG - if (ptr) - { - m_debugAllocatedSize.fetch_add(size, std::memory_order_relaxed); - m_debugAllocationCount.fetch_add(1, std::memory_order_relaxed); - } -#endif - return ptr; - } - - /// @brief Deallocates memory previously allocated by this allocator. - /// @param[in] ptr Pointer to the memory block to free. - /// @param[in] size The size in bytes of the block being freed. - void deallocate(void* ptr, USize size) noexcept override - { -#if GP_BUILD_DEBUG - if (ptr) - { - m_debugAllocatedSize.fetch_sub(size, std::memory_order_relaxed); - m_debugAllocationCount.fetch_sub(1, std::memory_order_relaxed); - } -#else - GP_UNUSED(size); -#endif - gp::memory::free(ptr); - } - -#if GP_BUILD_DEBUG - GP_NODISCARD USize getAllocatedSize() const noexcept override - { - return m_debugAllocatedSize.load(std::memory_order_relaxed); - } - - GP_NODISCARD USize getAllocationCount() const noexcept override - { - return m_debugAllocationCount.load(std::memory_order_relaxed); - } -#endif - - GP_NODISCARD const char* getDebugName() const noexcept override - { - return "DefaultAllocator"; - } -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/allocators/LinearAllocator.hpp b/source/runtime/core/public/memory/allocators/LinearAllocator.hpp deleted file mode 100644 index ea6ec94..0000000 --- a/source/runtime/core/public/memory/allocators/LinearAllocator.hpp +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "memory/allocators/Allocator.hpp" -#include "memory/MemoryUtilities.hpp" - -namespace gp::memory -{ - -/// @brief Fast monotonic bump allocator over a pre-allocated memory buffer. -/// @details -/// Allocations advance a single offset pointer. Individual deallocations are no-ops; memory is reclaimed only via -/// `reset()`. This makes it ideal for per-frame scratch memory or short-lived scoped allocations. -/// -/// Not thread-safe. Synchronization is the caller's responsibility (use TLS or job-system scheduling to guarantee -/// exclusive access). -/// -/// Statistics (allocated size and count) are always-on since they are just `USize` increments on the single-threaded -/// hot path. -/// -/// Hot data layout (32 bytes on x64): `m_buffer`, `m_capacity`, `m_offset`, `m_allocationCount` All fit within a single -/// cache line for zero-miss bump allocation. -class LinearAllocator final : public Allocator -{ -private: - gp::Byte* m_buffer{ nullptr }; - USize m_capacity{ 0ull }; - USize m_offset{ 0ull }; - USize m_allocatedSize{ 0ull }; - USize m_allocationCount{ 0ull }; - -public: - /// @brief Constructs a linear allocator over an externally owned buffer. - /// @param[in] buffer Pointer to the pre-allocated memory region. - /// @param[in] capacity Size of the buffer in bytes. - LinearAllocator(void* buffer, USize capacity) noexcept - : m_buffer(static_cast(buffer)) - , m_capacity(capacity) - {} - - ~LinearAllocator() noexcept = default; - -public: - /// @brief Bumps the offset pointer to allocate a block with the given alignment. - /// @param[in] size The number of bytes to allocate. - /// @param[in] alignment The required alignment (must be a power of two). - /// @return Pointer to the allocated block, or nullptr if the buffer is exhausted. - GP_NODISCARD void* allocate(USize size, USize alignment = alignof(gp::MaxAlign)) noexcept override - { - const USize alignedOffset = memory::alignUp(m_offset, alignment); - const USize newOffset = alignedOffset + size; - - if (GP_UNLIKELY(newOffset > m_capacity)) - { - return nullptr; - } - - m_offset = newOffset; - m_allocatedSize += size; - ++m_allocationCount; - - return m_buffer + alignedOffset; - } - - /// @brief No-op. Individual deallocation is not supported by a linear allocator. - /// @details - /// Memory is only reclaimed via reset(). The size parameter is accepted for interface compliance but ignored. - void deallocate(GP_MAYBE_UNUSED void* ptr, GP_MAYBE_UNUSED USize size) noexcept override - { - // Intentional no-op. Use reset() to reclaim all memory. - } - - /// @brief Resets the allocator to its initial state, reclaiming all memory. - /// @details - /// After reset, the full buffer is available for new allocations. All previously returned pointers become invalid. - void reset() noexcept override - { - m_offset = 0ull; - m_allocatedSize = 0ull; - m_allocationCount = 0ull; - } - - /// @brief Checks whether the given pointer falls within this allocator's buffer. - /// @param[in] ptr Pointer to query. - /// @return True if ptr is within [m_buffer, m_buffer + m_capacity). - GP_NODISCARD bool owns(const void* ptr) const noexcept override - { - const auto* p = static_cast(ptr); - return p >= m_buffer && p < m_buffer + m_capacity; - } - - /// @brief Returns the current byte offset into the buffer. - /// @return Number of bytes consumed (including alignment padding). - GP_NODISCARD GP_FORCEINLINE USize getOffset() const noexcept - { - return m_offset; - } - - /// @brief Returns the number of bytes remaining in the buffer. - /// @return Available bytes before the allocator is exhausted. - GP_NODISCARD GP_FORCEINLINE USize getRemaining() const noexcept - { - return m_capacity - m_offset; - } - - GP_NODISCARD USize getAllocatedSize() const noexcept override - { - return m_allocatedSize; - } - - GP_NODISCARD USize getAllocationCount() const noexcept override - { - return m_allocationCount; - } - - GP_NODISCARD const char* getDebugName() const noexcept override - { - return "LinearAllocator"; - } -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/allocators/PolymorphicAllocator.hpp b/source/runtime/core/public/memory/allocators/PolymorphicAllocator.hpp deleted file mode 100644 index a2493f3..0000000 --- a/source/runtime/core/public/memory/allocators/PolymorphicAllocator.hpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "memory/allocators/Allocator.hpp" -#include "memory/allocators/DefaultAllocator.hpp" - -namespace gp::memory -{ - -/// @brief Type-erased allocator wrapper for use as a container template parameter. -/// @details -/// Acts as the GP equivalent of `std::pmr::PolymorphicAllocator`. Wraps a pointer to `gp::memory::Allocator`, -/// providing a strongly-typed interface that containers interact with through `AllocatorTraits`. -/// -/// Propagation semantics follow C++17 `std::pmr`: -/// - Never propagate on copy (copy yields default_allocator) -/// - Always propagate on move (move transfers the resource) -/// - Swap: O(1) if allocators are equal, otherwise undefined -/// -/// sizeof(PolymorphicAllocator) == sizeof(void*). Zero overhead when stored inline in a container. -/// @tparam T The value type this allocator produces. -template -class PolymorphicAllocator -{ -public: - using ValueType = T; - using SizeType = USize; - using DifferenceType = ISize; - using PropagateOnContainerCopyAssignment = std::false_type; - using PropagateOnContainerMoveAssignment = std::true_type; - using PropagateOnContainerSwap = std::false_type; - using IsAlwaysEqual = std::false_type; - -private: - memory::Allocator* m_resource; - -public: - /// @brief Constructs a PolymorphicAllocator using the global default allocator. - PolymorphicAllocator() noexcept - : m_resource(&memory::DefaultAllocator::get()) - {} - - /// @brief Constructs a PolymorphicAllocator wrapping the given resource. - /// @param[in] resource Pointer to the backing allocator. Must outlive this wrapper and all containers using it. - PolymorphicAllocator(memory::Allocator* resource) noexcept - : m_resource(resource) - {} - - /// @brief Converting copy constructor for rebinding to a different value type. - /// @tparam U The source value type. - template - PolymorphicAllocator(const PolymorphicAllocator& other) noexcept - : m_resource(other.getResource()) - {} - - PolymorphicAllocator(const PolymorphicAllocator&) noexcept = default; - PolymorphicAllocator& operator=(const PolymorphicAllocator&) noexcept = default; - ~PolymorphicAllocator() = default; - -public: - /// @brief Two PolymorphicAllocators are equal if they wrap the same resource. - template - GP_NODISCARD bool operator==(const PolymorphicAllocator& other) const noexcept - { - return m_resource == other.getResource(); - } - - /// @brief Inequality comparison. - template - GP_NODISCARD bool operator!=(const PolymorphicAllocator& other) const noexcept - { - return m_resource != other.getResource(); - } - -public: - /// @brief Allocates memory for n objects of type T. - /// @param[in] n Number of objects to allocate space for. - /// @return Pointer to the allocated memory, or nullptr on failure. - GP_NODISCARD T* allocate(SizeType n) - { - return static_cast(m_resource->allocate(n * sizeof(T), alignof(T))); - } - - /// @brief Deallocates memory for n objects of type T. - /// @param[in] ptr Pointer previously returned by allocate(). - /// @param[in] n Number of objects the allocation was sized for. - void deallocate(T* ptr, SizeType n) - { - m_resource->deallocate(ptr, n * sizeof(T)); - } - - /// @brief Constructs an object at the given pointer using placement new. - /// @tparam U The type to construct. - /// @tparam Args Constructor argument types. - /// @param[in] ptr Pointer to uninitialized storage. - /// @param[in] args Arguments forwarded to U's constructor. - template - void construct(U* ptr, Args&&... args) - { - ::new (static_cast(ptr)) U(static_cast(args)...); - } - - /// @brief Destroys the object at the given pointer without deallocating. - /// @tparam U The type to destroy. - /// @param[in] ptr Pointer to the object. - template - void destroy(U* ptr) - { - ptr->~U(); - } - - /// @brief Returns a default-constructed PolymorphicAllocator for copy-constructed containers. - /// @details Per std::pmr semantics, copied containers do not inherit the source's allocator. - PolymorphicAllocator selectOnContainerCopyConstruction() const - { - return PolymorphicAllocator(); - } - - /// @brief Returns the underlying memory resource. - /// @return Pointer to the backing gp::memory::Allocator. - GP_NODISCARD GP_FORCEINLINE memory::Allocator* getResource() const noexcept - { - return m_resource; - } -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/allocators/PoolAllocator.hpp b/source/runtime/core/public/memory/allocators/PoolAllocator.hpp deleted file mode 100644 index 9cf93cf..0000000 --- a/source/runtime/core/public/memory/allocators/PoolAllocator.hpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "memory/allocators/Allocator.hpp" -#include "memory/MemoryUtilities.hpp" - -namespace gp::memory -{ - -/// @brief Fixed-size block allocator using an intrusive free-list. -/// @details -/// Manages a pre-allocated buffer divided into equal-sized blocks. Allocation and deallocation are O(1), a single -/// pointer pop/push on an embedded singly-linked list. Freed blocks are recycled immediately with zero fragmentation. -/// -/// The minimum block size is sizeof(void*), since each free block stores the intrusive next-pointer. Blocks are aligned -/// to the requested alignment at construction time. -/// -/// Not thread-safe. Synchronization is the caller's responsibility. -/// -/// Hot data layout (first 32 bytes on x64): `m_freeList`, `m_buffer`, `m_blockSize`, `m_BlockAlignment` Single cache -/// line for the pop (allocate) fast path. -class PoolAllocator final : public Allocator -{ -private: - /// @brief Intrusive node embedded in every free block. - struct FreeNode - { - FreeNode* next; - }; - -private: - FreeNode* m_freeList{ nullptr }; - gp::Byte* m_buffer{ nullptr }; - USize m_blockSize{ 0ull }; - USize m_blockAlignment{ 0ull }; - USize m_blockCount{ 0ull }; - USize m_allocatedCount{ 0ull }; - -public: - /// @brief Constructs a pool allocator over an externally owned buffer. - /// @param[in] buffer Pointer to the pre-allocated memory region. - /// @param[in] bufferSize Total size of the buffer in bytes. - /// @param[in] blockSize Size of each allocation block in bytes. Clamped to a minimum of sizeof(void*) to hold the - /// free-list pointer. - /// @param[in] blockAlignment Alignment of each block (must be a power of two). - PoolAllocator( - void* buffer, USize bufferSize, USize blockSize, USize blockAlignment = alignof(gp::MaxAlign) - ) noexcept - : m_freeList(nullptr) - , m_buffer(static_cast(buffer)) - , m_blockSize(blockSize < sizeof(FreeNode) ? sizeof(FreeNode) : blockSize) - , m_blockAlignment(blockAlignment < alignof(FreeNode) ? alignof(FreeNode) : blockAlignment) - { - // Ensure the effective block stride is aligned - const USize stride = alignUp(m_blockSize, m_blockAlignment); - - // Find the first aligned address within the buffer - const USize bufferAddr = reinterpret_cast(m_buffer); - const USize alignedStart = alignUp(bufferAddr, m_blockAlignment); - const USize startOffset = alignedStart - bufferAddr; - - // Calculate how many blocks fit - if (startOffset < bufferSize) - { - m_blockCount = (bufferSize - startOffset) / stride; - } - - // Build the free list in reverse order so the first block is at the head - gp::Byte* blockPtr = m_buffer + startOffset + (m_blockCount > 0 ? (m_blockCount - 1) * stride : 0); - for (USize i = 0; i < m_blockCount; ++i) - { - auto* node = reinterpret_cast(blockPtr); - node->next = m_freeList; - m_freeList = node; - blockPtr -= stride; - } - } - - ~PoolAllocator() override = default; - -public: - /// @brief Pops a block from the free-list. - /// @param[in] size Must be <= block_size. Ignored in release; asserted in debug. - /// @param[in] alignment Must be <= block_alignment. Ignored in release; asserted in debug. - /// @return Pointer to the allocated block, or nullptr if the pool is exhausted. - GP_NODISCARD void* - allocate(GP_MAYBE_UNUSED USize size, GP_MAYBE_UNUSED USize alignment = alignof(gp::MaxAlign)) noexcept override - { - GP_ASSERT(size <= m_blockSize, "pool_allocator: requested size exceeds block size"); - GP_ASSERT(alignment <= m_blockAlignment, "pool_allocator: requested alignment exceeds block alignment"); - - if (GP_UNLIKELY(!m_freeList)) - { - return nullptr; - } - - FreeNode* node = m_freeList; - m_freeList = node->next; - ++m_allocatedCount; - - return static_cast(node); - } - - /// @brief Pushes a block back onto the free-list. - /// @param[in] ptr Pointer to a block previously returned by allocate(). - /// @param[in] size Ignored (blocks are fixed-size). - void deallocate(void* ptr, GP_MAYBE_UNUSED USize size) noexcept override - { - if (!ptr) - { - return; - } - - GP_ASSERT(owns(ptr), "pool_allocator: deallocating a pointer not owned by this pool"); - - auto* node = static_cast(ptr); - node->next = m_freeList; - m_freeList = node; - --m_allocatedCount; - } - - /// @brief Rebuilds the free-list, reclaiming all blocks. - /// @details All previously returned pointers become invalid. - void reset() noexcept override - { - m_freeList = nullptr; - m_allocatedCount = 0; - - const USize stride = alignUp(m_blockSize, m_blockAlignment); - const USize bufferAddr = reinterpret_cast(m_buffer); - const USize alignedStart = alignUp(bufferAddr, m_blockAlignment); - const USize startOffset = alignedStart - bufferAddr; - - gp::Byte* blockPtr = m_buffer + startOffset + (m_blockCount > 0 ? (m_blockCount - 1) * stride : 0); - for (USize i = 0; i < m_blockCount; ++i) - { - auto* node = reinterpret_cast(blockPtr); - node->next = m_freeList; - m_freeList = node; - blockPtr -= stride; - } - } - - /// @brief Checks whether the given pointer falls within this pool's buffer. - /// @param[in] ptr Pointer to query. - /// @return True if ptr is within the buffer region. - GP_NODISCARD bool owns(const void* ptr) const noexcept override - { - const auto* p = static_cast(ptr); - return p >= m_buffer && p < m_buffer + getBufferSize(); - } - - /// @brief Returns the configured block size (may be larger than the requested size). - GP_NODISCARD GP_FORCEINLINE USize getBlockSize() const noexcept - { - return m_blockSize; - } - - /// @brief Returns the total number of blocks in the pool. - GP_NODISCARD GP_FORCEINLINE USize getBlockCount() const noexcept - { - return m_blockCount; - } - - /// @brief Returns the number of blocks currently available (not allocated). - GP_NODISCARD GP_FORCEINLINE USize getFreeCount() const noexcept - { - return m_blockCount - m_allocatedCount; - } - - GP_NODISCARD USize getAllocatedSize() const noexcept override - { - return m_allocatedCount * m_blockSize; - } - - GP_NODISCARD USize getAllocationCount() const noexcept override - { - return m_allocatedCount; - } - - GP_NODISCARD const char* getDebugName() const noexcept override - { - return "PoolAllocator"; - } - -private: - /// @brief Computes the total used buffer size from block geometry. - GP_NODISCARD GP_FORCEINLINE USize getBufferSize() const noexcept - { - const USize stride = alignUp(m_blockSize, m_blockAlignment); - const USize bufferAddr = reinterpret_cast(m_buffer); - const USize startOffset = alignUp(bufferAddr, m_blockAlignment) - bufferAddr; - return startOffset + m_blockCount * stride; - } -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/backends/Malloc.hpp b/source/runtime/core/public/memory/backends/Malloc.hpp index 52f95aa..d7ef527 100644 --- a/source/runtime/core/public/memory/backends/Malloc.hpp +++ b/source/runtime/core/public/memory/backends/Malloc.hpp @@ -5,113 +5,71 @@ #pragma once #include "CoreMinimal.hpp" -#include "memory/backends/MemoryStatistics.hpp" -#include "memory/backends/SystemMallocObject.hpp" #include "memory/MemoryBase.hpp" namespace gp::memory { -/// @brief A memory allocator wrapper interface for malloc-based memory allocation. This class provides an interface for -/// memory allocation and deallocation using the standard C library's malloc, realloc, and free functions. It also -/// includes additional functionality for zero-initialized allocations, adjusting allocation sizes based on alignment -/// requirements, and retrieving allocation statistics. This class is designed -class Malloc : public SystemMallocObject +/// @brief +/// @details +/// @see +class GP_CORE_API Malloc { public: - /// @brief Allocates a block of memory of the specified size and alignment. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return A pointer to the allocated memory block, or nullptr if the allocation fails. - virtual void* malloc(gp::USize size, gp::UInt32 alignment = kDefaultAlignment) = 0; + /// @brief + virtual ~Malloc() = default; - /// @brief Attempts to allocate a block of memory of the specified size and alignment. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return A pointer to the allocated memory block, or nullptr if the allocation fails. - virtual void* tryMalloc(gp::USize size, gp::UInt32 alignment = kDefaultAlignment); - - /// @brief Reallocates a block of memory to a new size and alignment. - /// @param[in] ptr A pointer to the previously allocated memory block to be reallocated. - /// @param[in] newSize The new size of the memory block, in bytes. - /// @param[in] alignment The alignment requirement for the reallocated memory block, in bytes. - /// @return A pointer to the reallocated memory block, or nullptr if the reallocation fails. - virtual void* realloc(void* ptr, gp::USize newSize, gp::UInt32 alignment = kDefaultAlignment) = 0; - - /// @brief Attempts to reallocate a block of memory to a new size and alignment. - /// @param[in] ptr A pointer to the previously allocated memory block to be reallocated. - /// @param[in] newSize The new size of the memory block, in bytes. - /// @param[in] alignment The alignment requirement for the reallocated memory block, in bytes. - /// @return A pointer to the reallocated memory block, or nullptr if the reallocation fails. - virtual void* tryRealloc(void* ptr, gp::USize newSize, gp::UInt32 alignment = kDefaultAlignment); - - /// @brief Deallocates a previously allocated block of memory. - /// @param[in] ptr A pointer to the memory block to be deallocated. The pointer must have been returned by a - /// previous call to malloc, tryMalloc, realloc, or tryRealloc. - virtual void free(void* ptr) = 0; - - /// @brief Allocates a block of memory of the specified size and alignment, and initializes it to zero. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return A pointer to the allocated and zero-initialized memory block, or nullptr if the allocation fails. - virtual void* mallocZeroed(gp::USize size, gp::UInt32 alignment = kDefaultAlignment); - - /// @brief Attempts to allocate a block of memory of the specified size and alignment, and initializes it to zero. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return A pointer to the allocated and zero-initialized memory block, or nullptr if the allocation fails. - virtual void* tryMallocZeroed(gp::USize size, gp::UInt32 alignment = kDefaultAlignment); - - /// @brief Get the size that should be requested to eliminate internal fragmentation for an allocation of the given - /// size and alignment. The return value will always be greater than or equal to the requested size, and can be used - /// to grow and shrink allocations to optimal sizes for the underlying allocator. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return The adjusted size that should be requested to eliminate internal fragmentation for an allocation of the - /// given size and alignment. - virtual gp::USize adjustSize(gp::USize size, gp::UInt32 alignment) const; - - /// @brief Retrieves the size of a previously allocated memory block. This function may not be supported by all - /// allocators, and may return false if the allocator cannot determine the size of the allocation. - /// @param[in] ptr A pointer to the memory block for which to retrieve the size. - /// @param[out] outSize The size of the allocated memory block, in bytes. This parameter is only valid if the - /// function returns true. - /// @return true if the size of the allocated memory block was successfully retrieved, or false if the allocator - /// cannot determine the size of the allocation. - virtual bool getAllocationSize(void* ptr, gp::USize& outSize) const; - - /// @brief Releases unused memory back to the system. This function may be a no-op for some allocators, but can be - /// used by allocators that manage their own memory pools to release unused memory back to the operating system. - virtual void trim(); - - /// @brief Updates the allocator's statistics. - /// @note This is called once per frame by the memory manager to allow the allocator to update any internal - /// statistics it maintains. This must be implemented thread-safely, as it may be called from a different thread - /// than the one(s) used for allocation and deallocation. - virtual void updateStatistics(); - - /// @brief Retrieves the allocator's statistics. - /// @return A MemoryStatistics structure containing the allocator's statistics. - virtual MemoryStatistics getAllocatorStatistics() const; - - /// @brief Retrieves the allocator's statistics by filling in the provided MemoryStatistics structure. - /// @param[out] outStats A reference to a MemoryStatistics structure that will be filled in with the allocator's - /// statistics. - virtual void getAllocatorStatistics(MemoryStatistics& outStats) const; - - /// @brief Indicates whether the allocator is internally thread-safe. If this function returns true, the memory - /// manager may allow concurrent allocations and deallocations from multiple threads without additional - /// synchronization. - /// @return true if the allocator is internally thread-safe, or false if it is not. If this function returns false. - virtual bool isInternallyThreadSafe() const; - - /// @brief Validates the integrity of the allocator's internal heap. - /// @return true if the heap is valid, or false if it is not. - virtual bool validateHeap() const; - - /// @brief Retrieves a human-readable name for the allocator. - /// @return A null-terminated c-string containing the human-readable name for the allocator. - virtual const char* getDisplayName() const; +public: + /// @brief + /// @param[in] size + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* allocate(USize size, UInt32 alignment = kDefaultAlignment) = 0; + + /// @brief + /// @param[in] size + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* tryAllocate(USize size, UInt32 alignment = kDefaultAlignment) noexcept; + + /// @brief + /// @param[in] size + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* allocateZeroed(USize size, UInt32 alignment = kDefaultAlignment); + + /// @brief + /// @param[in] size + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* tryAllocateZeroed(USize size, UInt32 alignment = kDefaultAlignment) noexcept; + + /// @brief + /// @param[in] ptr + /// @param[in] newSize + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* reallocate(void* ptr, USize newSize, UInt32 alignment = kDefaultAlignment) = 0; + + /// @brief + /// @param[in] ptr + /// @param[in] newSize + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* tryReallocate(void* ptr, USize newSize, UInt32 alignment = kDefaultAlignment) noexcept; + + /// @brief + /// @param[in] ptr + virtual void deallocate(void* ptr) = 0; + + /// @brief + /// @param[in] ptr + /// @return + virtual USize getAllocationSize(void* ptr); + + /// @brief + /// @return + virtual bool canGetAllocationSize(); }; } // namespace gp::memory diff --git a/source/runtime/core/public/memory/backends/MallocAnsi.hpp b/source/runtime/core/public/memory/backends/MallocAnsi.hpp index 45348b7..73c098e 100644 --- a/source/runtime/core/public/memory/backends/MallocAnsi.hpp +++ b/source/runtime/core/public/memory/backends/MallocAnsi.hpp @@ -10,71 +10,50 @@ namespace gp::memory { -/// @brief An implementation of the Malloc interface that uses the standard C library's malloc, realloc, and free -/// functions to manage memory. This allocator is designed to be a simple and portable implementation of the Malloc -/// interface, and may not provide the best performance or memory usage characteristics for all workloads. It is -/// intended to be used as a fallback allocator when more specialized allocators are not available or suitable for a -/// particular use case. -class MallocAnsi final : public Malloc +/// @brief +/// @details +/// @see +class GP_CORE_API MallocAnsi final : public Malloc { public: - /// @brief Constructs a new MallocAnsi allocator instance. - MallocAnsi(); - -public: - /// @brief Allocates a block of memory of the specified size and alignment. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return A pointer to the allocated memory block, or nullptr if the allocation fails. - virtual void* malloc(gp::USize size, gp::UInt32 alignment) override; - - /// @brief Attempts to allocate a block of memory of the specified size and alignment. - /// @param[in] size The size of the memory block to allocate, in bytes. - /// @param[in] alignment The alignment requirement for the allocated memory block, in bytes. - /// @return A pointer to the allocated memory block, or nullptr if the allocation fails. - virtual void* tryMalloc(gp::USize size, gp::UInt32 alignment) override; - - /// @brief Reallocates a block of memory to a new size and alignment. - /// @param[in] ptr A pointer to the previously allocated memory block to be reallocated. - /// @param[in] newSize The new size of the memory block, in bytes. - /// @param[in] alignment The alignment requirement for the reallocated memory block, in bytes. - /// @return A pointer to the reallocated memory block, or nullptr if the reallocation fails. - virtual void* realloc(void* ptr, gp::USize newSize, gp::UInt32 alignment) override; - - /// @brief Attempts to reallocate a block of memory to a new size and alignment. - /// @param[in] ptr A pointer to the previously allocated memory block to be reallocated. - /// @param[in] newSize The new size of the memory block, in bytes. - /// @param[in] alignment The alignment requirement for the reallocated memory block, in bytes. - /// @return A pointer to the reallocated memory block, or nullptr if the reallocation fails. - virtual void* tryRealloc(void* ptr, gp::USize newSize, gp::UInt32 alignment) override; - - /// @brief Deallocates a previously allocated block of memory. - /// @param[in] ptr A pointer to the memory block to be deallocated. The pointer must have been returned by a - /// previous call to malloc, tryMalloc, realloc, or tryRealloc. - virtual void free(void* ptr) override; - - /// @brief Retrieves the size of a previously allocated memory block. This function may not be supported by all - /// allocators, and may return false if the allocator cannot determine the size of the allocation. - /// @param[in] ptr A pointer to the memory block for which to retrieve the size. - /// @param[out] outSize The size of the allocated memory block, in bytes. This parameter is only valid if the - /// function returns true. - /// @return true if the size of the allocated memory block was successfully retrieved, or false if the allocator - /// cannot determine the size of the allocation. - virtual bool getAllocationSize(void* ptr, gp::USize& outSize) const override; - - /// @brief Indicates whether the allocator is internally thread-safe. If this function returns true, the memory - /// manager may allow concurrent allocations and deallocations from multiple threads without additional - /// synchronization. - /// @return true if the allocator is internally thread-safe, or false if it is not. If this function returns false. - virtual bool isInternallyThreadSafe() const override; - - /// @brief Validates the integrity of the allocator's internal heap. - /// @return true if the heap is valid, or false if it is not. - virtual bool validateHeap() const override; - - /// @brief Retrieves a human-readable name for the allocator. - /// @return A null-terminated c-string containing the human-readable name for the allocator. - virtual const char* getDisplayName() const override; + /// @brief + /// @param[in] size + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* allocate(USize size, UInt32 alignment) override; + + /// @brief + /// @param[in] size + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* tryAllocate(USize size, UInt32 alignment) noexcept override; + + /// @brief + /// @param[in] ptr + /// @param[in] newSize + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* reallocate(void* ptr, USize newSize, UInt32 alignment) override; + + /// @brief + /// @param[in] ptr + /// @param[in] newSize + /// @param[in] alignment + /// @return + GP_NODISCARD virtual void* tryReallocate(void* ptr, USize newSize, UInt32 alignment) noexcept override; + + /// @brief + /// @param[in] ptr + virtual void deallocate(void* ptr) override; + + /// @brief + /// @param[in] ptr + /// @return + virtual USize getAllocationSize(void* ptr) override; + + /// @brief + /// @return + virtual bool canGetAllocationSize() override; }; } // namespace gp::memory diff --git a/source/runtime/core/public/memory/backends/SystemMallocObject.hpp b/source/runtime/core/public/memory/backends/SystemMallocObject.hpp deleted file mode 100644 index 5f19c41..0000000 --- a/source/runtime/core/public/memory/backends/SystemMallocObject.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" - -namespace gp::memory -{ - -/// @brief A class that provides overloaded new and delete operators to use the system allocator for memory management. -class SystemMallocObject -{ -public: - /// @brief Overloaded new operator to use the system allocator for memory allocation. - /// @param[in] size The size of the memory block to allocate. - /// @return A pointer to the allocated memory block. - void* operator new(gp::USize size); - - /// @brief Overloaded delete operator to use the system allocator for memory deallocation. - /// @param[in] ptr A pointer to the memory block to deallocate. - void operator delete(void* ptr); - - /// @brief Overloaded new[] operator to use the system allocator for memory allocation of arrays. - /// @param[in] size The size of the memory block to allocate for the array. - /// @return A pointer to the allocated memory block for the array. - void* operator new[](gp::USize size); - - /// @brief Overloaded delete[] operator to use the system allocator for memory deallocation of arrays. - /// @param[in] ptr A pointer to the memory block to deallocate for the array. - void operator delete[](void* ptr); -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/memory/ownership/RefCountPtr.hpp b/source/runtime/core/public/memory/ownership/RefCountPtr.hpp deleted file mode 100644 index 829d056..0000000 --- a/source/runtime/core/public/memory/ownership/RefCountPtr.hpp +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "macros/MacroUtilities.hpp" -#include "memory/MemoryForward.hpp" - -namespace gp -{ - -/// @brief Concept describing types manageable by gp::RefCountPtr. -template -concept IsRefCounted = requires(T* object) { - { - object->addRef() - }; - { - object->release() - }; -}; - -/// @brief Intrusive, concept-gated smart pointer for reference-counted objects. -/// @details -/// The reference count lives inside the managed object itself (intrusive), which means a RefCountPtr is exactly -/// one pointer wide and incurs no separate control block allocation. -/// @tparam T A type satisfying gp::IsRefCounted. -template -class RefCountPtr -{ - static_assert(gp::IsRefCounted, "RefCountPtr can only be used with types that implement reference counting"); - -public: - using ValueType = T; - using Pointer = T*; - -public: - /// @brief Adopts a raw pointer without incrementing the reference count. - /// @details - /// Used when the pointer was returned by a factory function that already added a reference on behalf of the - /// caller (the idiomatic ownership-transfer pattern for COM-style APIs). - struct AttachTag - {}; - - static constexpr AttachTag attachT{}; - -private: - Pointer m_pointer{ nullptr }; - -private: - template - friend class RefCountPtr; - -public: - /// @brief Constructs an empty RefCountPtr. - constexpr RefCountPtr() noexcept = default; - - /// @brief Constructs an empty RefCountPtr. - constexpr RefCountPtr(gp::NullPtr) noexcept - {} - - /// @brief Adopts a raw pointer and adds a reference to it. - /// @param[in] ptr Pointer to adopt; may be nullptr. The refcount is incremented if non-null. - explicit RefCountPtr(Pointer ptr) noexcept - : m_pointer(ptr) - { - if (m_pointer) - { - m_pointer->addRef(); - } - } - - /// @brief Adopts a raw pointer without incrementing the reference count. - /// @param[in] ptr Pointer to adopt; may be nullptr. The refcount is not incremented. - /// @param[in] tag Tag to disambiguate from the regular constructor. - RefCountPtr(Pointer ptr, AttachTag) noexcept - : m_pointer(ptr) - {} - - /// @brief Constructs a RefCountPtr by copying from another RefCountPtr. - /// @param[in] other The RefCountPtr to copy from. The refcount of the new pointer is incremented if non-null. - RefCountPtr(const RefCountPtr& other) noexcept - : m_pointer(other.m_pointer) - { - if (m_pointer) - { - m_pointer->addRef(); - } - } - - /// @brief Constructs a RefCountPtr by copying from another RefCountPtr of a convertible type. - /// @tparam U The type of the RefCountPtr to copy from. Must be convertible to T. - /// @param[in] other The RefCountPtr to copy from. The refcount of the new pointer is incremented if non-null. - template >> - RefCountPtr(const RefCountPtr& other) noexcept - : m_pointer(other.m_pointer) - { - if (m_pointer) - { - m_pointer->addRef(); - } - } - - /// @brief Constructs a RefCountPtr by moving from another RefCountPtr. - /// @param[in] other The RefCountPtr to move from. The moved-from RefCountPtr is left empty. - RefCountPtr(RefCountPtr&& other) noexcept - : m_pointer(other.m_pointer) - { - other.m_pointer = nullptr; - } - - /// @brief Constructs a RefCountPtr by moving from another RefCountPtr of a convertible type. - /// @tparam U The type of the RefCountPtr to move from. Must be convertible to T. - /// @param[in] other The RefCountPtr to move from. The moved-from RefCountPtr is left empty. - template >> - RefCountPtr(RefCountPtr&& other) noexcept - : m_pointer(other.m_pointer) - { - other.m_pointer = nullptr; - } - - /// @brief Destroys the RefCountPtr, releasing the reference if it manages a non-null pointer. - ~RefCountPtr() noexcept - { - if (m_pointer) - { - m_pointer->release(); - } - } - - /// @brief Replaces the stored pointer with a new one, adding a reference to it. - /// @param[in] other The RefCountPtr to copy from. The refcount of the new pointer is incremented if non-null. - RefCountPtr& operator=(const RefCountPtr& other) noexcept - { - RefCountPtr(other).swap(*this); - return *this; - } - - /// @brief Replaces the stored pointer with a new one, adding a reference to it. - /// @tparam U The type of the RefCountPtr to copy from. Must be convertible to T. - /// @param[in] other The RefCountPtr to copy from. The refcount of the new pointer is incremented if non-null. - template >> - RefCountPtr& operator=(const RefCountPtr& other) noexcept - { - RefCountPtr(other).swap(*this); - return *this; - } - - /// @brief Replaces the stored pointer with a new one, adding a reference to it. - /// @param[in] other The RefCountPtr to move from. - RefCountPtr& operator=(RefCountPtr&& other) noexcept - { - RefCountPtr(std::move(other)).swap(*this); - return *this; - } - - /// @brief Replaces the stored pointer with a new one, adding a reference to it. - /// @tparam U The type of the RefCountPtr to move from. Must be convertible to T. - /// @param[in] other The RefCountPtr to move from. - template >> - RefCountPtr& operator=(RefCountPtr&& other) noexcept - { - RefCountPtr(std::move(other)).swap(*this); - return *this; - } - - /// @brief Replaces the stored pointer with a new one, adding a reference to it. - /// @param[in] ptr The new pointer to manage. The refcount is incremented if non-null. - RefCountPtr& operator=(Pointer ptr) noexcept - { - RefCountPtr(ptr).swap(*this); - return *this; - } - - /// @brief Resets to empty. - RefCountPtr& operator=(gp::NullPtr) noexcept - { - reset(); - return *this; - } - -public: - /// @brief Dereferences the stored pointer. - /// @return A reference to the managed object. The behavior is undefined if this RefCount is empty. - GP_FORCEINLINE T& operator*() const noexcept - { - GP_ASSERT(m_pointer != nullptr, "Dereferencing a null RefCountPtr"); - return *m_pointer; - } - - /// @brief Accesses members of the stored pointer. - /// @return The stored pointer. The behavior is undefined if this RefCount is empty. - GP_FORCEINLINE Pointer operator->() const noexcept - { - GP_ASSERT(m_pointer != nullptr, "Accessing a null RefCountPtr"); - return m_pointer; - } - - /// @brief Checks if the RefCountPtr is non-empty. - /// @return true if this RefCountPtr manages a non-null pointer, false otherwise. - GP_FORCEINLINE explicit operator bool() const noexcept - { - return m_pointer != nullptr; - } - -public: - /// @brief Gets the raw pointer managed by this RefCountPtr. - /// @return The raw pointer, which may be nullptr if this RefCountPtr is empty. - GP_NODISCARD GP_FORCEINLINE Pointer get() const noexcept - { - return m_pointer; - } - - /// @brief Releases ownership without calling release(). Returns the adopted pointer. - /// @return The adopted pointer, which is now detached from this RefCountPtr. - GP_NODISCARD GP_FORCEINLINE Pointer detach() noexcept - { - Pointer tmp = m_pointer; - m_pointer = nullptr; - return tmp; - } - - /// @brief Resets to an empty pointer, releasing the current reference if any. - GP_FORCEINLINE void reset() noexcept - { - if (m_pointer) - { - m_pointer->release(); - m_pointer = nullptr; - } - } - - /// @brief Checks if the RefCountPtr is non-empty. - /// @return true if this RefCountPtr manages a non-null pointer, false otherwise. - GP_FORCEINLINE bool isValid() const noexcept - { - return m_pointer != nullptr; - } - - /// @brief Replaces the stored pointer with a new one, adding a reference to it. - /// @param[in] ptr The new pointer to manage. The refcount is incremented if non-null. - GP_FORCEINLINE void reset(Pointer ptr) noexcept - { - RefCountPtr(ptr).swap(*this); - } - - /// @brief Adopts a raw pointer without adding a reference (ownership transfer). - /// @param[in] ptr The new pointer to manage. The refcount is not incremented. - GP_FORCEINLINE void attach(Pointer ptr) noexcept - { - if (m_pointer) - { - m_pointer->release(); - } - m_pointer = ptr; - } - - /// @brief Returns the address of the stored pointer after releasing any current reference. - /// @return The address of the stored pointer, which is now empty. - GP_NODISCARD GP_FORCEINLINE Pointer* getAddressOf() noexcept - { - reset(); - return &m_pointer; - } - - /// @brief Returns the address of the stored pointer without resetting. - /// @return The address of the stored pointer, which may still hold a reference. - GP_NODISCARD GP_FORCEINLINE Pointer* getAddressOfUnsafe() noexcept - { - return &m_pointer; - } - - /// @brief Swaps the managed pointers of this and another RefCountPtr. - /// @param[in] other The RefCountPtr to swap with. - GP_FORCEINLINE void swap(RefCountPtr& other) noexcept - { - Pointer tmp = m_pointer; - m_pointer = other.m_pointer; - other.m_pointer = tmp; - } -}; - -} // namespace gp - -/// @brief Equality comparison operators for RefCountPtr. -/// @param[in] lhs The left-hand side RefCountPtr. -/// @param[in] rhs The right-hand side RefCountPtr. -/// @return true if both RefCountPtrs manage the same pointer (including both being empty), false otherwise. -template -GP_FORCEINLINE bool operator==(const gp::RefCountPtr& lhs, const gp::RefCountPtr& rhs) noexcept -{ - return lhs.get() == rhs.get(); -} - -/// @brief Inequality comparison operators for RefCountPtr. -/// @param[in] lhs The left-hand side RefCountPtr. -/// @param[in] rhs The right-hand side RefCountPtr. -/// @return true if the RefCountPtrs manage different pointers, false if they manage the same pointer. -template -GP_FORCEINLINE bool operator!=(const gp::RefCountPtr& lhs, const gp::RefCountPtr& rhs) noexcept -{ - return lhs.get() != rhs.get(); -} - -/// @brief Equality comparison operators for RefCountPtr and nullptr. -/// @param[in] lhs The RefCountPtr to compare. -/// @param[in] rhs The nullptr to compare. -/// @return true if the RefCountPtr is empty (manages a null pointer), false otherwise. -template -GP_FORCEINLINE bool operator==(const gp::RefCountPtr& lhs, gp::NullPtr) noexcept -{ - return lhs.get() == nullptr; -} - -/// @brief Equality comparison operators for nullptr and RefCountPtr. -/// @param[in] lhs The nullptr to compare. -/// @param[in] rhs The RefCountPtr to compare. -/// @return true if the RefCountPtr is empty (manages a null pointer), false otherwise. -template -GP_FORCEINLINE bool operator==(gp::NullPtr, const gp::RefCountPtr& rhs) noexcept -{ - return rhs.get() == nullptr; -} - -/// @brief Inequality comparison operators for RefCountPtr and nullptr. -/// @param[in] lhs The RefCountPtr to compare. -/// @param[in] rhs The nullptr to compare. -/// @return true if the RefCountPtr is non-empty (manages a non-null pointer), false otherwise. -template -GP_FORCEINLINE bool operator!=(const gp::RefCountPtr& lhs, gp::NullPtr) noexcept -{ - return lhs.get() != nullptr; -} - -/// @brief Inequality comparison operators for nullptr and RefCountPtr. -/// @param[in] lhs The nullptr to compare. -/// @param[in] rhs The RefCountPtr to compare. -/// @return true if the RefCountPtr is non-empty (manages a non-null pointer), false otherwise. -template -GP_FORCEINLINE bool operator!=(gp::NullPtr, const gp::RefCountPtr& rhs) noexcept -{ - return rhs.get() != nullptr; -} diff --git a/source/runtime/core/public/memory/ownership/UniquePtr.hpp b/source/runtime/core/public/memory/ownership/UniquePtr.hpp deleted file mode 100644 index d872450..0000000 --- a/source/runtime/core/public/memory/ownership/UniquePtr.hpp +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "memory/allocators/DefaultAllocator.hpp" -#include "memory/MemoryForward.hpp" - -namespace gp -{ - -/// @brief Default stateless deleter for UniquePtr. -/// @details -/// Destroys the object via its destructor and releases the underlying memory through gp::memory::DefaultAllocator. -/// Being empty and trivially constructible, this deleter participates in empty-base optimization via -/// [[no_unique_address]], guaranteeing sizeof(UniquePtr) == sizeof(T*). -/// @tparam T The type of object being deleted. -template -struct DefaultDelete -{ -public: - /// @brief Default constructor. - constexpr DefaultDelete() noexcept = default; - - /// @brief Default copy constructor and copy assignment operator. - constexpr DefaultDelete(const DefaultDelete&) noexcept = default; - constexpr DefaultDelete& operator=(const DefaultDelete&) noexcept = default; - - /// @brief Default destructor. - ~DefaultDelete() noexcept = default; - - /// @brief Enables converting construction from a compatible deleter (e.g. Derived -> Base). - template >> - constexpr DefaultDelete(const DefaultDelete&) noexcept - {} - - /// @brief Enables converting assignment from a compatible deleter (e.g. Derived -> Base). - template >> - constexpr DefaultDelete& operator=(const DefaultDelete&) noexcept - { - return *this; - } - -public: - /// @brief Destroys the object and frees its memory through the engine default allocator. - /// @param[in] ptr Pointer to the object to destroy. nullptr is a safe no-op. - GP_FORCEINLINE void operator()(T* ptr) const noexcept - { - static_assert(!std::is_void_v, "gp::DefaultDelete cannot delete an incomplete type."); - if (ptr) - { - ptr->~T(); - gp::memory::DefaultAllocator::get().deallocate(ptr, sizeof(T)); - } - } -}; - -/// @brief Exclusive-ownership smart pointer with zero runtime overhead. -/// @details -/// Semantically mirrors std::unique_ptr but routes all allocations/deallocations through the engine's allocator -/// subsystem. The deleter is stored via [[no_unique_address]] so a stateless deleter collapses to zero bytes, -/// guaranteeing sizeof(UniquePtr) == sizeof(T*) on MSVC, Clang and GCC. -/// -/// Ownership is moved-only: the copy constructor and copy assignment operator are deleted. Move operations are -/// guaranteed noexcept so UniquePtr is safe to store inside noexcept-strong containers (e.g. gp::Vector with a -/// trivial-relocate optimization). -/// @tparam T The pointee type. -/// @tparam Deleter The deleter callable; defaults to gp::DefaultDelete. -template > -class UniquePtr -{ -public: - using ElementType = T; - using Pointer = T*; - using DeleterType = Deleter; - -private: - template - friend class UniquePtr; - -private: - Pointer m_pointer{ nullptr }; - GP_NO_UNIQUE_ADDRESS Deleter m_deleter{}; - -public: - /// @brief Constructs an empty UniquePtr. - constexpr UniquePtr() noexcept = default; - - /// @brief Constructs an empty UniquePtr from nullptr_t. - constexpr UniquePtr(gp::NullPtr) noexcept - {} - - /// @brief Takes exclusive ownership of the given raw pointer. - /// @param[in] ptr Pointer to adopt; may be nullptr. - explicit UniquePtr(Pointer ptr) noexcept - : m_pointer(ptr) - {} - - /// @brief Takes ownership of a raw pointer with a user-supplied deleter. - /// @param[in] ptr Pointer to adopt. - /// @param[in] deleter Deleter instance to store. - UniquePtr(Pointer ptr, const Deleter& deleter) noexcept - : m_pointer(ptr) - , m_deleter(deleter) - {} - - /// @brief Takes ownership of a raw pointer with a user-supplied deleter (rvalue overload). - /// @param[in] ptr Pointer to adopt. - /// @param[in] deleter Deleter instance to store (moved). - UniquePtr(Pointer ptr, Deleter&& deleter) noexcept - : m_pointer(ptr) - , m_deleter(std::move(deleter)) - {} - - /// @brief Deleted copy constructor to enforce unique ownership semantics. - UniquePtr(const UniquePtr&) = delete; - - /// @brief Deleted copy assignment operator to enforce unique ownership semantics. - UniquePtr& operator=(const UniquePtr&) = delete; - - /// @brief Transfers ownership from another UniquePtr. - UniquePtr(UniquePtr&& other) noexcept - : m_pointer(other.m_pointer) - , m_deleter(std::move(other.m_deleter)) - { - other.m_pointer = nullptr; - } - - /// @brief Converting move constructor for compatible pointee types (e.g. Derived -> Base). - /// @tparam U The source UniquePtr's pointee type. - /// @tparam E The source UniquePtr's deleter type. - /// @param[in] other The UniquePtr to move from; must be convertible to this UniquePtr's types. - template < - typename U, - typename E, - typename = std::enable_if_t && std::is_convertible_v>> - UniquePtr(UniquePtr&& other) noexcept - : m_pointer(other.release()) - , m_deleter(std::forward(other.getDeleter())) - {} - - /// @brief Destructor that destroys the owned object (if any) via the deleter. - ~UniquePtr() noexcept - { - reset(); - } - - /// @brief Move assignment operator. Destroys the currently owned object. - /// @param[in] other The UniquePtr to move from. - /// @return A reference to this UniquePtr. - UniquePtr& operator=(UniquePtr&& other) noexcept - { - if (this != &other) - { - reset(other.m_pointer); - other.m_pointer = nullptr; - m_deleter = std::move(other.m_deleter); - } - return *this; - } - - /// @brief Converting move assignment for compatible pointee types. - /// @tparam U The source UniquePtr's pointee type. - /// @tparam E The source UniquePtr's deleter type. - /// @param[in] other The UniquePtr to move from; must be convertible to this UniquePtr's types. - /// @return A reference to this UniquePtr. - template < - typename U, - typename E, - typename = std::enable_if_t && std::is_convertible_v>> - UniquePtr& operator=(UniquePtr&& other) noexcept - { - reset(other.release()); - m_deleter = std::forward(other.getDeleter()); - return *this; - } - - /// @brief Resets the pointer to empty on nullptr assignment. - UniquePtr& operator=(gp::NullPtr) noexcept - { - reset(); - return *this; - } - -public: - /// @brief Dereferences the owned object. - /// @return A reference to the owned object. - GP_FORCEINLINE T& operator*() const noexcept - { - GP_ASSERT(m_pointer != nullptr, "Dereferencing a null UniquePtr"); - return *m_pointer; - } - - /// @brief Member access on the owned object. - /// @return The raw pointer to the owned object. - GP_FORCEINLINE Pointer operator->() const noexcept - { - GP_ASSERT(m_pointer != nullptr, "Accessing a null UniquePtr"); - return m_pointer; - } - - /// @brief Tests whether the pointer is non-null. - /// @return true if the UniquePtr owns an object; false if it is empty. - GP_FORCEINLINE explicit operator bool() const noexcept - { - return m_pointer != nullptr; - } - -public: - /// @brief Returns the underlying raw pointer without releasing ownership. - /// @return The raw pointer to the owned object, or nullptr if empty. - GP_NODISCARD GP_FORCEINLINE Pointer get() const noexcept - { - return m_pointer; - } - - /// @brief Returns a mutable reference to the stored deleter. - /// @return A reference to the deleter. - GP_NODISCARD GP_FORCEINLINE Deleter& getDeleter() noexcept - { - return m_deleter; - } - - /// @brief Returns a const reference to the stored deleter. - /// @return A const reference to the deleter. - GP_NODISCARD GP_FORCEINLINE const Deleter& getDeleter() const noexcept - { - return m_deleter; - } - - /// @brief Relinquishes ownership, returning the raw pointer without destroying the object. - /// @return The previously owned pointer; the UniquePtr becomes empty. - GP_NODISCARD GP_FORCEINLINE Pointer release() noexcept - { - Pointer result = m_pointer; - m_pointer = nullptr; - return result; - } - - /// @brief Destroys the currently owned object (if any) and adopts a new pointer. - /// @param[in] ptr New pointer to adopt; defaults to nullptr. - GP_FORCEINLINE void reset(Pointer ptr = nullptr) noexcept - { - Pointer old = m_pointer; - m_pointer = ptr; - if (old) - { - m_deleter(old); - } - } - - /// @brief Swaps the contents of this UniquePtr with another. - /// @param[in] other The UniquePtr to swap with. - GP_FORCEINLINE void swap(UniquePtr& other) noexcept - { - Pointer tmpPtr = m_pointer; - m_pointer = other.m_pointer; - other.m_pointer = tmpPtr; - - using std::swap; - swap(m_deleter, other.m_deleter); - } -}; - -/// @brief Constructs a T in allocator-backed memory and wraps it in a UniquePtr. -/// @details -/// Allocates through gp::memory::DefaultAllocator and uses placement-new to construct the object. If T's -/// constructor throws (only possible in builds compiled with exceptions enabled), the freshly allocated memory is -/// released before the exception propagates. In GP's default -fno-exceptions builds this function is -/// unconditionally noexcept and simply returns a default-constructed UniquePtr on allocation failure. -/// @tparam T The object type to construct. -/// @tparam Args Parameter pack forwarded to T's constructor. -/// @param[in] args Arguments forwarded to T's constructor. -/// @return A UniquePtr owning the newly constructed object, or an empty UniquePtr if allocation fails. -template -GP_NODISCARD UniquePtr makeUnique(Args&&... args) noexcept -{ - auto& allocator = gp::memory::DefaultAllocator::get(); - void* memory = allocator.allocate(sizeof(T), alignof(T)); - if (!memory) - { - return UniquePtr{}; - } - T* object = ::new (memory) T(std::forward(args)...); - return UniquePtr(object); -} - -/// @brief Non-member swap matching the standard convention. -/// @param[in] lhs The first UniquePtr to swap. -/// @param[in] rhs The second UniquePtr to swap. -template -GP_FORCEINLINE void swap(UniquePtr& lhs, UniquePtr& rhs) noexcept -{ - lhs.swap(rhs); -} - -} // namespace gp - -/// @brief Equality and ordering comparisons. -/// @param[in] lhs The left-hand side UniquePtr in the comparison. -/// @param[in] rhs The right-hand side UniquePtr in the comparison. -/// @return true if the raw pointers owned by lhs and rhs are equal; false otherwise. -template -GP_FORCEINLINE bool operator==(const gp::UniquePtr& lhs, const gp::UniquePtr& rhs) noexcept -{ - return lhs.get() == rhs.get(); -} - -/// @brief Inequality comparison. -/// @param[in] lhs The left-hand side UniquePtr in the comparison. -/// @param[in] rhs The right-hand side UniquePtr in the comparison. -/// @return true if the raw pointers owned by lhs and rhs are not equal; false otherwise. -template -GP_FORCEINLINE bool operator!=(const gp::UniquePtr& lhs, const gp::UniquePtr& rhs) noexcept -{ - return lhs.get() != rhs.get(); -} - -/// @brief Equality comparison with nullptr. -/// @param[in] lhs The UniquePtr to compare. -/// @param[in] rhs The nullptr to compare against. -/// @return true if lhs is empty (owns no object); false otherwise. -template -GP_FORCEINLINE bool operator==(const gp::UniquePtr& lhs, gp::NullPtr) noexcept -{ - return lhs.get() == nullptr; -} - -/// @brief Equality comparison with nullptr (reversed). -/// @param[in] lhs The nullptr to compare against. -/// @param[in] rhs The UniquePtr to compare. -/// @return true if rhs is empty (owns no object); false otherwise. -template -GP_FORCEINLINE bool operator==(gp::NullPtr, const gp::UniquePtr& rhs) noexcept -{ - return rhs.get() == nullptr; -} - -/// @brief Inequality comparison with nullptr. -/// @param[in] lhs The UniquePtr to compare. -/// @param[in] rhs The nullptr to compare against. -/// @return true if lhs is non-empty (owns an object); false otherwise. -template -GP_FORCEINLINE bool operator!=(const gp::UniquePtr& lhs, gp::NullPtr) noexcept -{ - return lhs.get() != nullptr; -} - -/// @brief Inequality comparison with nullptr (reversed). -/// @param[in] lhs The nullptr to compare against. -/// @param[in] rhs The UniquePtr to compare. -/// @return true if rhs is non-empty (owns an object); false otherwise. -template -GP_FORCEINLINE bool operator!=(gp::NullPtr, const gp::UniquePtr& rhs) noexcept -{ - return rhs.get() != nullptr; -} diff --git a/source/runtime/core/private/memory/backends/MallocLibPAS.cpp b/source/runtime/core/public/memory/pointers/RefCountedPtr.hpp similarity index 80% rename from source/runtime/core/private/memory/backends/MallocLibPAS.cpp rename to source/runtime/core/public/memory/pointers/RefCountedPtr.hpp index a40e00a..88b9360 100644 --- a/source/runtime/core/private/memory/backends/MallocLibPAS.cpp +++ b/source/runtime/core/public/memory/pointers/RefCountedPtr.hpp @@ -2,4 +2,4 @@ // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com -#include "memory/backends/MallocLibPAS.hpp" +#pragma once diff --git a/source/runtime/core/private/memory/backends/MallocBinned.cpp b/source/runtime/core/public/memory/pointers/SharedPtr.hpp similarity index 80% rename from source/runtime/core/private/memory/backends/MallocBinned.cpp rename to source/runtime/core/public/memory/pointers/SharedPtr.hpp index e130a22..88b9360 100644 --- a/source/runtime/core/private/memory/backends/MallocBinned.cpp +++ b/source/runtime/core/public/memory/pointers/SharedPtr.hpp @@ -2,4 +2,4 @@ // For more information, see https://graphical-playground/legal // mailto:support AT graphical-playground DOT com -#include "memory/backends/MallocBinned.hpp" +#pragma once diff --git a/source/runtime/core/public/memory/pointers/UniquePtr.hpp b/source/runtime/core/public/memory/pointers/UniquePtr.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/core/public/memory/pointers/UniquePtr.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/core/public/memory/pointers/WeakPtr.hpp b/source/runtime/core/public/memory/pointers/WeakPtr.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/core/public/memory/pointers/WeakPtr.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/core/public/memory/traits/AllocatorTraits.hpp b/source/runtime/core/public/memory/traits/AllocatorTraits.hpp deleted file mode 100644 index 56ac144..0000000 --- a/source/runtime/core/public/memory/traits/AllocatorTraits.hpp +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include - -namespace gp::memory -{ - -namespace detail -{ - -/// @brief Checks if the allocator type has a construct method with the expected signature. -template -struct HasConstruct : std::false_type -{}; - -/// @brief Checks if the allocator type has a construct method with the expected signature. -template -struct HasConstruct< - Alloc, - std::void_t().construct(std::declval()))>> - : std::true_type -{}; - -/// @brief Checks if the allocator type has a destroy method with the expected signature. -template -struct HasDestroy : std::false_type -{}; - -/// @brief Checks if the allocator type has a destroy method with the expected signature. -template -struct HasDestroy< - Alloc, - std::void_t().destroy(std::declval()))>> : std::true_type -{}; - -/// @brief If the allocator type has a maxSize member, it is used. Otherwise, the allocator does not report a maximum -/// size. -template -struct HasMaxSize : std::false_type -{}; - -/// @brief If the allocator type has a maxSize member, it is used. Otherwise, the allocator does not report a maximum -/// size. -template -struct HasMaxSize().maxSize())>> : std::true_type -{}; - -/// @brief If the allocator type has a selectOnContainerCopyConstruction member, it is used. Otherwise, it is not -/// propagated. -template -struct HasSelectOnContainerCopyConstruction : std::false_type -{}; - -/// @brief If the allocator type has a selectOnContainerCopyConstruction member, it is used. Otherwise, it is not -/// propagated. -template -struct HasSelectOnContainerCopyConstruction< - Alloc, - std::void_t().selectOnContainerCopyConstruction())>> : std::true_type -{}; - -/// @brief If the allocator type has a PropagateOnContainerCopyAssignment member, it is used. Otherwise, it is not -/// propagated. -template -struct HasPropagateOnCopy : std::false_type -{}; - -/// @brief If the allocator type has a PropagateOnContainerCopyAssignment member, it is used. Otherwise, it is not -/// propagated. -template -struct HasPropagateOnCopy> : std::true_type -{}; - -/// @brief If the allocator type has a PropagateOnContainerMoveAssignment member, it is used. Otherwise, it is not -/// propagated. -template -struct HasPropagateOnMove : std::false_type -{}; - -/// @brief If the allocator type has a PropagateOnContainerMoveAssignment member, it is used. Otherwise, it is not -/// propagated. -template -struct HasPropagateOnMove> : std::true_type -{}; - -/// @brief If the allocator type has a PropagateOnContainerSwap member, it is used. Otherwise, it is not propagated. -template -struct HasPropagateOnSwap : std::false_type -{}; - -/// @brief If the allocator type has a PropagateOnContainerSwap member, it is used. Otherwise, it is not propagated. -template -struct HasPropagateOnSwap> : std::true_type -{}; - -/// @brief If the allocator type has an IsAlwaysEqual member, it is used. Otherwise, if the allocator type is empty, it -/// is considered always equal. Otherwise, it is not always equal. -template -struct HasIsAlwaysEqual : std::false_type -{}; - -/// @brief If the allocator type has an IsAlwaysEqual member, it is used. Otherwise, if the allocator type is empty, it -/// is considered always equal. Otherwise, it is not always equal. -template -struct HasIsAlwaysEqual> : std::true_type -{}; - -} // namespace detail - -/// @brief Allocator traits class template. Provides a uniform interface to access allocator properties and operations. -/// @tparam Alloc Allocator type. -template -struct AllocatorTraits -{ - using AllocatorType = Alloc; - using ValueType = typename Alloc::ValueType; - using Pointer = ValueType*; - using ConstPointer = const ValueType*; - using VoidPointer = void*; - using ConstVoidPointer = const void*; - using SizeType = USize; - using DifferenceType = ISize; - - /// @brief If the allocator type has a PropagateOnContainerCopyAssignment member, it is used. Otherwise, it is not - /// propagated. - using PropagateOnContainerCopyAssignment = typename std::conditional_t< - detail::HasPropagateOnCopy::value, - typename Alloc::PropagateOnContainerCopyAssignment, - std::false_type>; - - /// @brief If the allocator type has a PropagateOnContainerMoveAssignment member, it is used. Otherwise, it is not - /// propagated. - using PropagateOnContainerMoveAssignment = typename std::conditional_t< - detail::HasPropagateOnMove::value, - typename Alloc::PropagateOnContainerMoveAssignment, - std::true_type>; - - /// @brief If the allocator type has a PropagateOnContainerSwap member, it is used. Otherwise, it is not propagated. - using PropagateOnContainerSwap = typename std::conditional_t< - detail::HasPropagateOnSwap::value, - typename Alloc::PropagateOnContainerSwap, - std::false_type>; - - /// @brief If the allocator type has an IsAlwaysEqual member, it is used. Otherwise, if the allocator type is empty, - /// it is considered always equal. Otherwise, it is not always equal. - using IsAlwaysEqual = typename std::conditional_t< - detail::HasIsAlwaysEqual::value, - typename Alloc::IsAlwaysEqual, - typename std::is_empty::type>; - - /// @brief Allocates memory for n objects of type value_type using the allocator alloc. - /// @param[in] alloc The allocator to use for memory allocation. - /// @param[in] n The number of objects to allocate memory for. - /// @return A pointer to the allocated memory. - GP_NODISCARD static Pointer allocate(Alloc& alloc, SizeType n) - { - return alloc.allocate(n); - } - - /// @brief Deallocates memory pointed to by ptr using the allocator alloc. - /// @param[in] alloc The allocator to use for memory deallocation. - /// @param[in] ptr The pointer to the memory location to deallocate. - /// @param[in] n The number of objects to deallocate. - static void deallocate(Alloc& alloc, Pointer ptr, SizeType n) - { - alloc.deallocate(ptr, n); - } - - /// @brief Constructs an object of type T at the location pointed to by ptr using the allocator alloc and the - /// provided arguments. - /// @tparam T The type of the object to construct. - /// @tparam Args The types of the arguments to forward to the constructor of T. - /// @param[in] alloc The allocator to use for construction. - /// @param[in] ptr The pointer to the memory location where the object should be constructed. - /// @param[in] args The arguments to forward to the constructor of T. - template - static void construct(Alloc& alloc, T* ptr, Args&&... args) - { - if constexpr (detail::HasConstruct::value) - { - alloc.construct(ptr, static_cast(args)...); - } - else - { - ::new (static_cast(ptr)) T(static_cast(args)...); - } - } - - /// @brief Destroys the object of type T at the location pointed to by ptr using the allocator alloc. - /// @tparam T The type of the object to destroy. - /// @param[in] alloc The allocator to use for destruction. - /// @param[in] ptr The pointer to the memory location where the object should be destroyed. - template - static void destroy(Alloc& alloc, T* ptr) - { - if constexpr (detail::HasDestroy::value) - { - alloc.destroy(ptr); - } - else - { - ptr->~T(); - } - } - - /// @brief Returns the maximum number of elements that can be allocated by the allocator alloc. - /// @param[in] alloc The allocator to query for the maximum size. - /// @return The maximum number of elements that can be allocated by the allocator alloc. - static constexpr SizeType maxSize(const Alloc& alloc) noexcept - { - if constexpr (detail::HasMaxSize::value) - { - return alloc.maxSize(); - } - else - { - return static_cast(-1) / sizeof(ValueType); - } - } - - /// @brief Returns a copy of the allocator alloc to be used for copy construction of a container. If the allocator - /// type has a selectOnContainerCopyConstruction member function, it is called to obtain the copy. Otherwise, a copy - /// of the allocator is returned. - /// @param[in] alloc The allocator to copy for container copy construction. - /// @return A copy of the allocator alloc to be used for copy construction of a container. - static Alloc selectOnContainerCopyConstruction(const Alloc& alloc) - { - if constexpr (detail::HasSelectOnContainerCopyConstruction::value) - { - return alloc.selectOnContainerCopyConstruction(); - } - else - { - return alloc; - } - } -}; - -} // namespace gp::memory diff --git a/source/runtime/core/public/miscellaneous/BuildDefines.hpp b/source/runtime/core/public/miscellaneous/BuildDefines.hpp new file mode 100644 index 0000000..54dab1d --- /dev/null +++ b/source/runtime/core/public/miscellaneous/BuildDefines.hpp @@ -0,0 +1,173 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "miscellaneous/PreProcessorUtilities.hpp" + +/// @section Defines for build configurations. + +#ifndef GP_BUILD_DEBUG + #define GP_BUILD_DEBUG GP_FALSE +#endif +#ifndef GP_BUILD_DEVELOPMENT + #define GP_BUILD_DEVELOPMENT GP_FALSE +#endif +#ifndef GP_BUILD_TEST + #define GP_BUILD_TEST GP_FALSE +#endif +#ifndef GP_BUILD_SHIPPING + #define GP_BUILD_SHIPPING GP_FALSE +#endif + +#if (GP_BUILD_DEBUG + GP_BUILD_DEVELOPMENT + GP_BUILD_TEST + GP_BUILD_SHIPPING != 1) + #error "Exactly one build configuration must be defined as true." +#endif + +/// @section Mandatory bridge options definitions (Provided by GPBT). + +/// @brief Indicates whether the build includes the editor module. +#ifndef GP_WITH_EDITOR + #define GP_WITH_EDITOR GP_FALSE +#endif + +/// @brief Indicates whether the build includes the engine module. +#ifndef GP_WITH_ENGINE + #define GP_WITH_ENGINE GP_FALSE +#endif + +/// @brief Indicates whether the build includes the plugin support. +#ifndef GP_WITH_PLUGIN_SUPPORT + #define GP_WITH_PLUGIN_SUPPORT GP_FALSE +#endif + +/// @brief Indicates whether the build is a monolithic build (no DLLs) or a modular build (DLLs). +#ifndef GP_IS_MONOLITHIC + #define GP_IS_MONOLITHIC GP_FALSE +#endif + +/// @brief Indicates whether hot reload is supported in this build configuration. +#ifndef GP_HAS_HOT_RELOAD + #define GP_HAS_HOT_RELOAD (!GP_IS_MONOLITHIC && !GP_BUILD_SHIPPING && !GP_BUILD_TEST) +#endif + +/// @section Optional bridge options definitions (Not necessarily provided by GPBT). + +/// @brief Indicates whether to use the null RHI. +#ifndef GP_USE_NULL_RHI + #define GP_USE_NULL_RHI GP_FALSE +#endif + +/// @brief Indicates whether to log to the console in shipping builds. +#ifndef GP_USE_LOGGING_IN_SHIPPING + #define GP_USE_LOGGING_IN_SHIPPING GP_FALSE +#endif + +/// @brief Indicates whether to include checks in shipping builds. +#ifndef GP_USE_CHECKS_IN_SHIPPING + #define GP_USE_CHECKS_IN_SHIPPING GP_FALSE +#endif + +/// @brief Indicates whether to include ensures in shipping builds. +/// @note If not defined, it defaults to the value of GP_USE_CHECKS_IN_SHIPPING, as ensures are a type of check. +#ifndef GP_USE_ENSURES_IN_SHIPPING + #define GP_USE_ENSURES_IN_SHIPPING GP_USE_CHECKS_IN_SHIPPING +#endif + +/// @brief Indicates whether to allow console access in shipping builds. +#ifndef GP_ALLOW_CONSOLE_IN_SHIPPING + #define GP_ALLOW_CONSOLE_IN_SHIPPING GP_FALSE +#endif + +/// @brief Indicates whether to force the use of stats in shipping builds. +#ifndef GP_FORCE_USE_STATS + #define GP_FORCE_USE_STATS GP_FALSE +#endif + +/// @brief Indicates whether to force the use of the ANSI allocator instead of redirecting to memory subsystem. +#ifndef GP_FORCE_ANSI_ALLOCATOR + #define GP_FORCE_ANSI_ALLOCATOR GP_FALSE +#endif + +/// @section Baisc options that by default depend on the build configuration. + +#if GP_BUILD_DEBUG + #ifndef GP_DO_GUARD_SLOW + #define GP_DO_GUARD_SLOW GP_TRUE + #endif + #ifndef GP_DO_CHECK + #define GP_DO_CHECK GP_TRUE + #endif + #ifndef GP_DO_ENSURE + #define GP_DO_ENSURE GP_TRUE + #endif + #ifndef GP_ALLOW_DEBUG_FILES + #define GP_ALLOW_DEBUG_FILES GP_TRUE + #endif + #ifndef GP_ALLOW_CONSOLE + #define GP_ALLOW_CONSOLE GP_TRUE + #endif + #ifndef GP_NO_LOGGING + #define GP_NO_LOGGING GP_FALSE + #endif +#elif GP_BUILD_DEVELOPMENT + #ifndef GP_DO_GUARD_SLOW + #define GP_DO_GUARD_SLOW GP_FALSE + #endif + #ifndef GP_DO_CHECK + #define GP_DO_CHECK GP_TRUE + #endif + #ifndef GP_DO_ENSURE + #define GP_DO_ENSURE GP_TRUE + #endif + #ifndef GP_ALLOW_DEBUG_FILES + #define GP_ALLOW_DEBUG_FILES GP_TRUE + #endif + #ifndef GP_ALLOW_CONSOLE + #define GP_ALLOW_CONSOLE GP_TRUE + #endif + #ifndef GP_NO_LOGGING + #define GP_NO_LOGGING GP_FALSE + #endif +#elif GP_BUILD_TEST + #ifndef GP_DO_GUARD_SLOW + #define GP_DO_GUARD_SLOW GP_FALSE + #endif + #ifndef GP_DO_CHECK + #define GP_DO_CHECK GP_USE_CHECKS_IN_SHIPPING + #endif + #ifndef GP_DO_ENSURE + #define GP_DO_ENSURE GP_USE_ENSURES_IN_SHIPPING + #endif + #ifndef GP_ALLOW_DEBUG_FILES + #define GP_ALLOW_DEBUG_FILES GP_TRUE + #endif + #ifndef GP_ALLOW_CONSOLE + #define GP_ALLOW_CONSOLE GP_TRUE + #endif + #ifndef GP_NO_LOGGING + #define GP_NO_LOGGING !GP_USE_LOGGING_IN_SHIPPING + #endif +#elif GP_BUILD_SHIPPING + #ifndef GP_DO_GUARD_SLOW + #define GP_DO_GUARD_SLOW GP_FALSE + #endif + #ifndef GP_DO_CHECK + #define GP_DO_CHECK GP_USE_CHECKS_IN_SHIPPING + #endif + #ifndef GP_DO_ENSURE + #define GP_DO_ENSURE GP_USE_ENSURES_IN_SHIPPING + #endif + #ifndef GP_ALLOW_DEBUG_FILES + #define GP_ALLOW_DEBUG_FILES GP_WITH_EDITOR + #endif + #ifndef GP_ALLOW_CONSOLE + #define GP_ALLOW_CONSOLE GP_ALLOW_CONSOLE_IN_SHIPPING + #endif + #ifndef GP_NO_LOGGING + #define GP_NO_LOGGING !GP_USE_LOGGING_IN_SHIPPING + #endif +#else + #error "Exactly one build configuration must be defined as true." +#endif diff --git a/source/runtime/core/public/miscellaneous/PreProcessorUtilities.hpp b/source/runtime/core/public/miscellaneous/PreProcessorUtilities.hpp new file mode 100644 index 0000000..dfd9de6 --- /dev/null +++ b/source/runtime/core/public/miscellaneous/PreProcessorUtilities.hpp @@ -0,0 +1,82 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +/// @brief Defines a boolean false value for preprocessor conditions. +/// @see GP_TRUE +#define GP_FALSE (0) + +/// @brief Defines a boolean true value for preprocessor conditions. +/// @see GP_FALSE +#define GP_TRUE (1) + +/// @brief Defines an empty value for preprocessor conditions. +/// @see GP_EMPTY_FUNCTION +#define GP_EMPTY + +/// @brief Defines an empty function for preprocessor conditions. +/// @see GP_EMPTY +#define GP_EMPTY_FUNCTION(...) + +/// @brief Stringifies a token for preprocessor conditions. +/// @param[in] token The token to stringify. +/// @return The stringified token. +#define GP_STRINGIFY(token) GP_IMPL_STRINGIFY(token) +#define GP_IMPL_STRINGIFY(token) #token + +/// @brief Concatenates two tokens for preprocessor conditions. +/// @param[in] tokenA The first token to concatenate. +/// @param[in] tokenB The second token to concatenate. +/// @return The concatenated tokens. +#define GP_JOIN(tokenA, tokenB) GP_IMPL_JOIN(tokenA, tokenB) +#define GP_IMPL_JOIN(tokenA, tokenB) tokenA##tokenB + +/// @brief Concatenates the first token with the rest of the tokens for preprocessor conditions. +/// @param[in] token The first token to concatenate. +/// @param[in] __VA_ARGS__ The rest of the tokens to concatenate. +/// @return The concatenated tokens. +#define GP_JOIN_FIRST(token, ...) GP_IMPL_JOIN_FIRST(token, __VA_ARGS__) +#define GP_IMPL_JOIN_FIRST(token, ...) token##__VA_ARGS__ + +/// @brief Evaluates a condition and expands to the corresponding token for preprocessor conditions. +/// @param[in] condition The condition to evaluate. Must be either GP_TRUE or GP_FALSE. +/// @param[in] tokenTrue The token to expand if the condition is true. +/// @param[in] tokenFalse The token to expand if the condition is false. +/// @return The token corresponding to the evaluated condition. +#define GP_IF(condition, tokenTrue, tokenFalse) GP_IMPL_JOIN(GP_IMPL_IF_, condition)(tokenTrue, tokenFalse) +#define GP_IMPL_IF_TRUE(tokenTrue, tokenFalse) tokenTrue +#define GP_IMPL_IF_FALSE(tokenTrue, tokenFalse) tokenFalse + +/// @brief Generates a comma-separated list of tokens for preprocessor conditions. +/// @param[in] first The first token in the list. +/// @param[in] __VA_ARGS__ The rest of the tokens in the list. +/// @return A comma-separated list of the provided tokens. +#define GP_COMMA_SEPARATED(first, ...) first, __VA_ARGS__ + +/// @brief Generates a source location string for preprocessor conditions. +/// @return A string in the format "filename:line" representing the current source location. +#define GP_SOURCE_LOCATION __FILE__ ":" GP_STRINGIFY(__LINE__) + +// clang-format off +#if !defined(_MSVC_TRADITIONAL) || !_MSVC_TRADITIONAL + /// @brief Appends the count of variadic arguments to a prefix for preprocessor conditions. + /// @details Supports up to 26 variadic arguments. If no variadic arguments are provided, the count will be 0. + /// @param[in] prefix The prefix to which the count will be appended. + /// @param[in] __VA_ARGS__ The variadic arguments whose count will be appended to the prefix. + /// @return The prefix concatenated with the count of the variadic arguments. + #define GP_APPEND_VA_ARG_COUNT(prefix, ...) GP_IMPL_APPEND_VA_ARG_COUNT(prefix, ##__VA_ARGS__, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#else + /// @brief Appends the count of variadic arguments to a prefix for preprocessor conditions. + /// @details Supports up to 26 variadic arguments. If no variadic arguments are provided, the count will be 0. + /// @note MSVC's traditional preprocessor doesn't handle the zero-argument case correctly, so we use a workaround. + /// @param[in] prefix The prefix to which the count will be appended. + /// @param[in] __VA_ARGS__ The variadic arguments whose count will be appended to the prefix. + /// @return The prefix concatenated with the count of the variadic arguments. + #define GP_APPEND_VA_ARG_COUNT(prefix, ...) GP_IMPL_APPEND_VA_ARG_COUNT_INVOKE(GP_IMPL_APPEND_VA_ARG_COUNT, (prefix, ##__VA_ARGS__, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) + #define GP_IMPL_APPEND_VA_ARG_COUNT_INVOKE(macro, args) GP_IMPL_APPEND_VA_ARG_COUNT_EXPAND(macro##args) + #define GP_IMPL_APPEND_VA_ARG_COUNT_EXPAND(arg) arg +#endif +#define GP_IMPL_APPEND_VA_ARG_COUNT(prefix,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,count,...) prefix##count +// clang-format on diff --git a/source/runtime/core/public/platform/PlatformMemory.hpp b/source/runtime/core/public/platform/PlatformMemory.hpp deleted file mode 100644 index 0a46c34..0000000 --- a/source/runtime/core/public/platform/PlatformMemory.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" // IWYU pragma: export -#if GP_PLATFORM_WINDOWS - #include "platform/windows/WindowsMemoryPlatform.hpp" -#elif GP_PLATFORM_LINUX - #include "platform/linux/LinuxMemoryPlatform.hpp" -#elif GP_PLATFORM_MACOS || GP_PLATFORM_IOS - #include "platform/apple/AppleMemoryPlatform.hpp" -#else - #include "platform/generic/GenericMemoryPlatform.hpp" -#endif - -namespace gp::memory -{ - -#if GP_PLATFORM_WINDOWS -/// @brief Defines the platform-specific memory management implementation for Windows. -using PlatformMemory = gp::memory::impl::WindowsMemoryPlatform; -#elif GP_PLATFORM_LINUX -/// @brief Defines the platform-specific memory management implementation for Linux. -using PlatformMemory = gp::memory::impl::LinuxMemoryPlatform; -#elif GP_PLATFORM_MACOS || GP_PLATFORM_IOS -/// @brief Defines the platform-specific memory management implementation for macOS. -using PlatformMemory = gp::memory::impl::AppleMemoryPlatform; -#else -/// @brief Defines the generic memory management implementation. -using PlatformMemory = gp::memory::impl::GenericMemoryPlatform; -#endif - -} // namespace gp::memory diff --git a/source/runtime/core/public/platform/PlatformMemoryDefines.hpp b/source/runtime/core/public/platform/PlatformMemoryDefines.hpp deleted file mode 100644 index 87f598a..0000000 --- a/source/runtime/core/public/platform/PlatformMemoryDefines.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" - -namespace gp::memory -{ - -/// @brief Memory counter regions used for tracking and categorizing memory usage in the engine. -enum class MemoryCounterRegion -{ - Invalid, // + +// Automatically detect the platform, architecture and compiler if not already defined by GPBT +#if !defined(GP_SKIP_BUILD_DETECTION) || !GP_SKIP_BUILD_DETECTION + #include "platforms/base/PlatformDetection.hpp" +#endif + +/// @section Platform Detection. + +#ifndef GP_PLATFORM_WINDOWS + #define GP_PLATFORM_WINDOWS GP_FALSE +#endif +#ifndef GP_PLATFORM_LINUX + #define GP_PLATFORM_LINUX GP_FALSE +#endif +#ifndef GP_PLATFORM_MACOS + #define GP_PLATFORM_MACOS GP_FALSE +#endif + +#if (GP_PLATFORM_WINDOWS + GP_PLATFORM_LINUX + GP_PLATFORM_MACOS != 1) + #error "Exactly one platform must be defined as true!" +#endif + +#define GP_PLATFORM_DESKTOP (GP_PLATFORM_WINDOWS || GP_PLATFORM_LINUX || GP_PLATFORM_MACOS) +#define GP_PLATFORM_APPLE (GP_PLATFORM_MACOS) +#define GP_PLATFORM_UNIX (GP_PLATFORM_LINUX || GP_PLATFORM_APPLE) +#define GP_PLATFORM_POSIX (GP_PLATFORM_UNIX) +#define GP_PLATFORM_MICROSOFT (GP_PLATFORM_WINDOWS) + +/// @section Architecture Detection. + +#ifndef GP_ARCHITECTURE_X86 + #define GP_ARCHITECTURE_X86 GP_FALSE +#endif +#ifndef GP_ARCHITECTURE_X64 + #define GP_ARCHITECTURE_X64 GP_FALSE +#endif +#ifndef GP_ARCHITECTURE_ARM32 + #define GP_ARCHITECTURE_ARM32 GP_FALSE +#endif +#ifndef GP_ARCHITECTURE_ARM64 + #define GP_ARCHITECTURE_ARM64 GP_FALSE +#endif + +#if (GP_ARCHITECTURE_X86 + GP_ARCHITECTURE_X64 + GP_ARCHITECTURE_ARM32 + GP_ARCHITECTURE_ARM64 != 1) + #error "Exactly one architecture must be defined as true!" +#endif + +#define GP_ARCHITECTURE_X86_FAMILY (GP_ARCHITECTURE_X86 || GP_ARCHITECTURE_X64) +#define GP_ARCHITECTURE_ARM_FAMILY (GP_ARCHITECTURE_ARM32 || GP_ARCHITECTURE_ARM64) +#define GP_ARCHITECTURE_64BIT (GP_ARCHITECTURE_X64 || GP_ARCHITECTURE_ARM64) +#define GP_ARCHITECTURE_32BIT (GP_ARCHITECTURE_X86 || GP_ARCHITECTURE_ARM32) + +/// @section Compiler Detection. + +#ifndef GP_COMPILER_MSVC + #define GP_COMPILER_MSVC GP_FALSE +#endif +#ifndef GP_COMPILER_CLANG + #define GP_COMPILER_CLANG GP_FALSE +#endif +#ifndef GP_COMPILER_GCC + #define GP_COMPILER_GCC GP_FALSE +#endif +#ifndef GP_COMPILER_INTEL + #define GP_COMPILER_INTEL GP_FALSE +#endif + +#if (GP_COMPILER_MSVC + GP_COMPILER_CLANG + GP_COMPILER_GCC + GP_COMPILER_INTEL == 0) + #error "At least one compiler must be defined as true!" +#endif + +#if (GP_COMPILER_MSVC && _MSC_VER < 1920) || (!GP_COMPILER_MSVC && !defined(__cpp_if_constexpr)) + #error "Compiler is expected to support `if constexpr` statements." +#endif + +#if !defined(__cpp_fold_expressions) + #error "Compiler is expected to support fold expressions." +#endif + +#if !__has_feature(cxx_decltype_auto) + #error "Compiler is expected to support `decltype(auto)`." +#endif + +/// @section Platform-Specific / Compiler Specific Headers. + +// Include Generic Platform-Specific Headers +#include "platforms/generic/GenericPlatform.hpp" // IWYU pragma: export + +#if GP_PLATFORM_WINDOWS + #include "platforms/windows/WindowsPlatform.hpp" // IWYU pragma: export +#elif GP_PLATFORM_LINUX + #include "platforms/linux/LinuxPlatform.hpp" // IWYU pragma: export +#elif GP_PLATFORM_MACOS + #include "platforms/macos/MacOSPlatform.hpp" // IWYU pragma: export +#endif + +#if GP_COMPILER_CLANG + #include "compilers/clang/ClangCompiler.hpp" // IWYU pragma: export +#elif GP_COMPILER_MSVC + #include "compilers/msvc/MSVCCompiler.hpp" // IWYU pragma: export +#elif GP_COMPILER_GCC + #include "compilers/gcc/GCCCompiler.hpp" // IWYU pragma: export +#elif GP_COMPILER_INTEL + #include "compilers/intel/IntelCompiler.hpp" // IWYU pragma: export +#endif + +/// @section Platform supports features flags. + +#ifndef GP_PLATFORM_SUPPORTS_TEXTURE_STREAMING + #define GP_PLATFORM_SUPPORTS_TEXTURE_STREAMING GP_TRUE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_VIRTUAL_TEXTURES + #define GP_PLATFORM_SUPPORTS_VIRTUAL_TEXTURES GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_VARIABLE_RATE_SHADING + #define GP_PLATFORM_SUPPORTS_VARIABLE_RATE_SHADING GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_GEOMETRY_SHADERS + #define GP_PLATFORM_SUPPORTS_GEOMETRY_SHADERS GP_TRUE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_MESH_SHADERS + #define GP_PLATFORM_SUPPORTS_MESH_SHADERS GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_WORKGRAPH_SHADERS + #define GP_PLATFORM_SUPPORTS_WORKGRAPH_SHADERS GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_BINDLESS_RENDERING + #define GP_PLATFORM_SUPPORTS_BINDLESS_RENDERING GP_FALSE +#endif + +#ifndef GP_PLATFORM_BUILTIN_VERTEX_HALF_FLOAT + #define GP_PLATFORM_BUILTIN_VERTEX_HALF_FLOAT GP_TRUE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_TBB + #define GP_PLATFORM_SUPPORTS_TBB GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_JEMALLOC + #define GP_PLATFORM_SUPPORTS_JEMALLOC GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_MIMALLOC + #define GP_PLATFORM_SUPPORTS_MIMALLOC GP_FALSE +#endif + +#ifndef GP_PLATFORM_USE_ANSI_POSIX_MALLOC + #define GP_PLATFORM_USE_ANSI_POSIX_MALLOC GP_FALSE +#endif + +#ifndef GP_PLATFORM_USE_ALIGNED_MALLOC + #define GP_PLATFORM_USE_ALIGNED_MALLOC GP_FALSE +#endif + +#ifndef GP_PLATFORM_USE_ANSI_MEMALIGN + #define GP_PLATFORM_USE_ANSI_MEMALIGN GP_FALSE +#endif + +#ifndef GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE + #define GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_NAMED_PIPES + #define GP_PLATFORM_SUPPORTS_NAMED_PIPES GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_BORDERLESS_WINDOW + #define GP_PLATFORM_SUPPORTS_BORDERLESS_WINDOW GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_MULTIPLE_NATIVE_WINDOWS + #define GP_PLATFORM_SUPPORTS_MULTIPLE_NATIVE_WINDOWS GP_TRUE +#endif + +#ifndef GP_PLATFORM_HAS_128BIT_ATOMICS + #define GP_PLATFORM_HAS_128BIT_ATOMICS GP_FALSE +#endif + +#ifndef GP_PLATFORM_SUPPORTS_ASYMMETRIC_FENCES + #define GP_PLATFORM_SUPPORTS_ASYMMETRIC_FENCES GP_FALSE +#endif + +/// @section Platform-Independent Function Specifiers. + +#ifndef GP_VARARGS + #define GP_VARARGS +#endif +#ifndef GP_CDECL + #define GP_CDECL +#endif +#ifndef GP_STDCALL + #define GP_STDCALL +#endif +#ifndef GP_FORCEINLINE + #define GP_FORCEINLINE +#endif +#ifndef GP_FORCENOINLINE + #define GP_FORCENOINLINE +#endif +#ifndef GP_RESTRICT + #define GP_RESTRICT __restrict +#endif +#ifndef GP_CALLSITE_FORCEINLINE + #define GP_CALLSITE_FORCEINLINE +#endif + +#ifndef GP_DEFINE_FORCEINLINE_HINT_TO_INLINE + #define GP_DEFINE_FORCEINLINE_HINT_TO_INLINE GP_FALSE +#endif + +#if GP_DEFINE_FORCEINLINE_HINT_TO_INLINE + #define GP_FORCEINLINE_HINT inline +#else + #define GP_FORCEINLINE_HINT GP_FORCEINLINE +#endif + +#if !defined(GP_NODISCARD) && defined(__has_cpp_attribute) + #if __has_cpp_attribute(nodiscard) + #if (defined(_MSC_VER) && _MSC_VER >= 1924) || (defined(__clang__) && __clang_major__ >= 10) + #define GP_NODISCARD [[nodiscard]] + #endif + #endif +#endif +#ifndef GP_NODISCARD + #define GP_NODISCARD +#endif + +#if !defined(GP_MAYBE_UNUSED) && defined(__has_cpp_attribute) + #if __has_cpp_attribute(maybe_unused) + #define GP_MAYBE_UNUSED [[maybe_unused]] + #endif +#endif +#ifndef GP_MAYBE_UNUSED + #define GP_MAYBE_UNUSED +#endif + +#ifndef GP_SELECT_ANY + #if GP_COMPILER_MSVC + #define GP_SELECT_ANY __declspec(selectany) + #else + #define GP_SELECT_ANY __attribute__((selectany)) + #endif +#endif + +#if !defined(GP_NO_UNIQUE_ADDRESS) && defined(__has_cpp_attribute) + #if __has_cpp_attribute(msvc::no_unique_address) + #define GP_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] + #elif __has_cpp_attribute(no_unique_address) + #define GP_NO_UNIQUE_ADDRESS [[no_unique_address]] + #endif +#endif +#ifndef GP_NO_UNIQUE_ADDRESS + #define GP_NO_UNIQUE_ADDRESS +#endif + +#ifndef GP_FUNCTION_NON_NULL_RETURN_START + #define GP_FUNCTION_NON_NULL_RETURN_START +#endif +#ifndef GP_FUNCTION_NON_NULL_RETURN_END + #define GP_FUNCTION_NON_NULL_RETURN_END +#endif + +#ifndef GP_LIFETIMEBOUND + #define GP_LIFETIMEBOUND +#endif + +#ifndef GP_NODEBUG + #define GP_NODEBUG +#endif + +#ifndef GP_ALLOCATION_FUNCTION + #define GP_ALLOCATION_FUNCTION(...) +#endif + +#ifndef GP_ASSUME + #if GP_COMPILER_CLANG + #define GP_ASSUME(x) __builtin_assume(x) + #elif GP_COMPILER_MSVC + #define GP_ASSUME(x) __assume(x) + #else + #define GP_ASSUME(x) + #endif +#endif + +#ifndef GP_INTRINSIC_CAST + #define GP_INTRINSIC_CAST +#endif + +#ifndef GP_LIKELY + #if GP_COMPILER_CLANG || GP_COMPILER_GCC + #define GP_LIKELY(x) __builtin_expect(!!(x), 1) + #else + #define GP_LIKELY(x) (!!(x)) + #endif +#endif + +#ifndef GP_UNLIKELY + #if GP_COMPILER_CLANG || GP_COMPILER_GCC + #define GP_UNLIKELY(x) __builtin_expect(!!(x), 0) + #else + #define GP_UNLIKELY(x) (!!(x)) + #endif +#endif + +#ifndef GP_PLATFORM_CACHE_LINE_SIZE + #define GP_PLATFORM_CACHE_LINE_SIZE 64 +#endif + +#if !defined(GP_COLD) + #if GP_COMPILER_MSVC + #define GP_COLD __declspec(noinline) + #elif GP_COMPILER_CLANG || GP_COMPILER_GCC + #define GP_COLD __attribute__((cold)) + #else + #define GP_COLD + #endif +#endif + +#ifndef GP_DLLEXPORT + #define GP_DLLEXPORT +#endif +#ifndef GP_DLLIMPORT + #define GP_DLLIMPORT +#endif + +#include +#include + +namespace gp +{ + +/// @section Integer types with fixed widths. +/// @see https://en.cppreference.com/w/cpp/types/integer + +/// @brief 8-bit unsigned integer type. +/// limits: [0, 255] +using UInt8 = std::uint8_t; + +/// @brief 16-bit unsigned integer type. +/// limits: [0, 65535] +using UInt16 = std::uint16_t; + +/// @brief 32-bit unsigned integer type. +/// limits: [0, 4294967295] +using UInt32 = std::uint32_t; + +/// @brief 64-bit unsigned integer type. +/// limits: [0, 18446744073709551615] +using UInt64 = std::uint64_t; + +/// @brief 8-bit signed integer type. +/// limits: [-128, 127] +using Int8 = std::int8_t; + +/// @brief 16-bit signed integer type. +/// limits: [-32768, 32767] +using Int16 = std::int16_t; + +/// @brief 32-bit signed integer type. +/// limits: [-2147483648, 2147483647] +using Int32 = std::int32_t; + +/// @brief 64-bit signed integer type. +/// limits: [-9223372036854775808, 9223372036854775807] +using Int64 = std::int64_t; + +/// @section Floating-point types with fixed widths. + +/// @brief 32-bit floating-point type (single precision). +/// Approximate limits: [1.18e-38, 3.4e+38] +using Float32 = float; + +/// @brief 64-bit floating-point type (double precision). +/// Approximate limits: [2.22e-308, 1.8e+308] +using Float64 = double; + +/// @section Size and pointer difference types. + +using USize = std::size_t; +using ISize = std::ptrdiff_t; +using UIntPtr = std::uintptr_t; +using IntPtr = std::intptr_t; +using PtrDiff = std::ptrdiff_t; + +/// @section Character types. + +using Char8 = char8_t; +using Char16 = char16_t; +using Char32 = char32_t; +using Char = char; +using AnsiChar = char; +using WChar = wchar_t; + +/// @section Special values. + +using Byte = std::byte; +using NullPtrT = std::nullptr_t; + +} // namespace gp + +namespace +{ + +static_assert(char(-1) < char(0), "Unsigned char type test failed."); + +static_assert(!std::is_same_v, "AnsiChar and WChar types should be different."); + +static_assert(sizeof(gp::UInt8) == 1, "UInt8 type size test failed."); +static_assert(gp::Int32(gp::UInt8(-1)) == 0xFF, "UInt8 type sign test failed."); + +static_assert(sizeof(gp::UInt16) == 2, "UInt16 type size test failed."); +static_assert(gp::Int32(gp::UInt16(-1)) == 0xFFFF, "UInt16 type sign test failed."); + +static_assert(sizeof(gp::UInt32) == 4, "UInt32 type size test failed."); +static_assert(gp::Int64(gp::UInt32(-1)) == gp::Int64(0xFFFFFFFF), "UInt32 type sign test failed."); + +static_assert(sizeof(gp::UInt64) == 8, "UInt64 type size test failed."); +static_assert(gp::UInt64(-1) > gp::UInt64(0), "UInt64 type sign test failed."); + +static_assert(sizeof(gp::Int8) == 1, "Int8 type size test failed."); +static_assert(gp::Int32(gp::Int8(-1)) == -1, "Int8 type sign test failed."); + +static_assert(sizeof(gp::Int16) == 2, "Int16 type size test failed."); +static_assert(gp::Int32(gp::Int16(-1)) == -1, "Int16 type sign test failed."); + +static_assert(sizeof(gp::Int32) == 4, "Int32 type size test failed."); +static_assert(gp::Int64(gp::Int32(-1)) == gp::Int64(-1), "Int32 type sign test failed."); + +static_assert(sizeof(gp::Int64) == 8, "Int64 type size test failed."); +static_assert(gp::Int64(-1) < gp::Int64(0), "Int64 type sign test failed."); + +} // namespace diff --git a/source/runtime/core/public/platforms/base/PlatformDetection.hpp b/source/runtime/core/public/platforms/base/PlatformDetection.hpp new file mode 100644 index 0000000..99a7e9f --- /dev/null +++ b/source/runtime/core/public/platforms/base/PlatformDetection.hpp @@ -0,0 +1,59 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "miscellaneous/PreProcessorUtilities.hpp" + +#define GP_SKIP_PLATFORM_DETECTION (GP_PLATFORM_WINDOWS || GP_PLATFORM_LINUX || GP_PLATFORM_MACOS || GP_PLATFORM_IOS || GP_PLATFORM_ANDROID) + +#if !GP_SKIP_PLATFORM_DETECTION + #if defined(_WIN32) || defined(_WIN64) + #define GP_PLATFORM_WINDOWS GP_TRUE + #elif defined(__APPLE__) && defined(__MACH__) + #include + #if TARGET_OS_MAC + #define GP_PLATFORM_MACOS GP_TRUE + #else + #error "Unsupported Apple platform" + #endif + #elif defined(__linux__) && !defined(__ANDROID__) + #define GP_PLATFORM_LINUX GP_TRUE + #else + #error "Unsupported platform" + #endif +#endif + +#define GP_SKIP_ARCHITECTURE_DETECTION (GP_ARCHITECTURE_X86 || GP_ARCHITECTURE_X64 || GP_ARCHITECTURE_ARM32 || GP_ARCHITECTURE_ARM64) + +#if !GP_SKIP_ARCHITECTURE_DETECTION + #if defined(_M_X64) || defined(__x86_64__) + #define GP_ARCHITECTURE_X64 GP_TRUE + #elif defined(_M_IX86) || defined(__i386__) + #define GP_ARCHITECTURE_X86 GP_TRUE + #elif defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM64EC) + #define GP_ARCHITECTURE_ARM64 GP_TRUE + #elif defined(_M_ARM) || defined(__arm__) || defined(__ARM_NEON) + #define GP_ARCHITECTURE_ARM32 GP_TRUE + #else + #error "Unsupported architecture" + #endif +#endif + +#define GP_SKIP_COMPILER_DETECTION (GP_COMPILER_MSVC || GP_COMPILER_CLANG || GP_COMPILER_GCC || GP_COMPILER_INTEL) + +#if !GP_SKIP_COMPILER_DETECTION + #if defined(_MSC_VER) + #define GP_COMPILER_MSVC GP_TRUE + #endif + #if defined(__clang__) + #define GP_COMPILER_CLANG GP_TRUE + #endif + #if defined(__GNUC__) + #define GP_COMPILER_GCC GP_TRUE + #endif + #if defined(__INTEL_COMPILER) || defined(__ICC) + #define GP_COMPILER_INTEL GP_TRUE + #endif +#endif diff --git a/source/runtime/core/public/platforms/base/PlatformMemory.hpp b/source/runtime/core/public/platforms/base/PlatformMemory.hpp new file mode 100644 index 0000000..4cf28ce --- /dev/null +++ b/source/runtime/core/public/platforms/base/PlatformMemory.hpp @@ -0,0 +1,31 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "platforms/base/Platform.hpp" // IWYU pragma: keep +#if GP_PLATFORM_WINDOWS + #include "platforms/windows/WindowsPlatformMemory.hpp" +#elif GP_PLATFORM_LINUX + #include "platforms/linux/LinuxPlatformMemory.hpp" +#elif GP_PLATFORM_MACOS + #include "platforms/macos/MacOSPlatformMemory.hpp" +#else + #include "platforms/generic/GenericPlatformMemory.hpp" +#endif + +namespace gp::platform +{ + +#if GP_PLATFORM_WINDOWS +using Memory = gp::platform::windows::Memory; +#elif GP_PLATFORM_LINUX +using Memory = gp::platform::linux::Memory; +#elif GP_PLATFORM_MACOS +using Memory = gp::platform::macos::Memory; +#else +using Memory = gp::platform::generic::Memory; +#endif + +} // namespace gp::platform diff --git a/source/runtime/core/public/platforms/generic/GenericPlatform.hpp b/source/runtime/core/public/platforms/generic/GenericPlatform.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/core/public/platforms/generic/GenericPlatform.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/core/public/platform/generic/GenericMemoryPlatform.hpp b/source/runtime/core/public/platforms/generic/GenericPlatformMemory.hpp similarity index 86% rename from source/runtime/core/public/platform/generic/GenericMemoryPlatform.hpp rename to source/runtime/core/public/platforms/generic/GenericPlatformMemory.hpp index 84f2ab2..0d45fb6 100644 --- a/source/runtime/core/public/platform/generic/GenericMemoryPlatform.hpp +++ b/source/runtime/core/public/platforms/generic/GenericPlatformMemory.hpp @@ -5,35 +5,20 @@ #pragma once #include "CoreMinimal.hpp" -#include "platform/PlatformMemoryDefines.hpp" #include -namespace gp::memory::impl +namespace gp::platform::generic { /// @brief Generic implementation of the memory management platform for unsupported platforms. -class GenericPlatformMemory +class Memory { -public: - /// @brief Indicates whether the system is currently in an out of memory condition. - static bool isOutOfMemory; - - /// @brief The size of the allocation that caused the out of memory condition. - static gp::UInt64 outOfMemoryAllocationSize; - - /// @brief The alignment used for out of memory allocations. - static gp::UInt32 outOfMemoryAllocationAlignment; - - /// @brief A backup memory pool used when the system runs out of memory. Thiqs is used by Out Of Memory handling and - /// crash reporting to ensure that there is some memory available to report the OOM condition and capture a crash - /// dump. - static void* backupOutOfMemoryMemoryPool; - - /// @brief The size of the backup memory pool used when the system runs out of memory. - static gp::UInt32 backupOutOfMemoryMemoryPoolSize; +private: + /// @brief Deleted constructor prevent instantiation of the Memory class, as it is intended to be used. + Memory() = delete; - /// @brief The actual memory allocator type used by this platform. - static MemoryAllocatorType allocatorType; + /// @brief Deleted destructor prevent instantiation of the Memory class, as it is intended to be used. + ~Memory() = delete; public: /// @brief Moves a block of memory from the source to the destination, handling overlapping regions correctly. @@ -135,4 +120,4 @@ class GenericPlatformMemory } }; -} // namespace gp::memory::impl +} // namespace gp::platform::generic diff --git a/source/runtime/core/public/memory/backends/MemoryStatistics.hpp b/source/runtime/core/public/platforms/linux/LinuxPlatform.hpp similarity index 59% rename from source/runtime/core/public/memory/backends/MemoryStatistics.hpp rename to source/runtime/core/public/platforms/linux/LinuxPlatform.hpp index a211a5e..a75e2b1 100644 --- a/source/runtime/core/public/memory/backends/MemoryStatistics.hpp +++ b/source/runtime/core/public/platforms/linux/LinuxPlatform.hpp @@ -4,12 +4,6 @@ #pragma once -#include "CoreMinimal.hpp" +#include "platforms/unix/UnixPlatform.hpp" // IWYU pragma: export -namespace gp::memory -{ - -struct MemoryStatistics -{}; - -} // namespace gp::memory +#define GP_PLATFORM_SUPPORTS_BORDERLESS_WINDOW GP_TRUE diff --git a/source/runtime/core/public/platforms/linux/LinuxPlatformMemory.hpp b/source/runtime/core/public/platforms/linux/LinuxPlatformMemory.hpp new file mode 100644 index 0000000..1a0aa74 --- /dev/null +++ b/source/runtime/core/public/platforms/linux/LinuxPlatformMemory.hpp @@ -0,0 +1,24 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include "platforms/unix/UnixPlatformMemory.hpp" + +namespace gp::platform::linux +{ + +/// @brief Linux-specific implementation of the memory management platform. +class Memory final : public gp::platform::unix::Memory +{ +private: + /// @brief Deleted constructor prevent instantiation of the Memory class, as it is intended to be used. + Memory() = delete; + + /// @brief Deleted destructor prevent instantiation of the Memory class, as it is intended to be used. + ~Memory() = delete; +}; + +} // namespace gp::platform::linux diff --git a/source/runtime/core/public/platforms/macos/MacOSPlatform.hpp b/source/runtime/core/public/platforms/macos/MacOSPlatform.hpp new file mode 100644 index 0000000..95e2ff9 --- /dev/null +++ b/source/runtime/core/public/platforms/macos/MacOSPlatform.hpp @@ -0,0 +1,36 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "miscellaneous/PreProcessorUtilities.hpp" +#include "platforms/apple/ApplePlatform.hpp" // IWYU pragma: export + +#if __is_target_arch(arm64) || __is_target_arch(arm64e) + #define GP_PLATFORM_MAC_ARM64 GP_TRUE + #define GP_PLATFORM_MAC_X86 GP_FALSE +#else + #define GP_PLATFORM_MAC_ARM64 GP_FALSE + #define GP_PLATFORM_MAC_X86 GP_TRUE +#endif + +#define _GP_IS_PLATFORM_64BIT (GP_PLATFORM_MAC_ARM64 || GP_PLATFORM_MAC_X86) + +#define GP_PLATFORM_SUPPORTS_TBB GP_TRUE +#define GP_PLATFORM_SUPPORTS_MIMALLOC _GP_IS_PLATFORM_64BIT +#define GP_PLATFORM_SUPPORTS_MESH_SHADERS GP_TRUE +#define GP_PLATFORM_SUPPORTS_BINDLESS_RENDERING GP_TRUE +#define GP_PLATFORM_SUPPORTS_GEOMETRY_SHADERS GP_TRUE + +#ifdef GP_PLATFORM_MAC_ARM64 + #define GP_PLATFORM_CACHE_LINE_SIZE 128 +#else + #define GP_PLATFORM_CACHE_LINE_SIZE 64 +#endif + +#if GP_BUILD_DEBUG + #define GP_FORCEINLINE inline +#else + #define GP_FORCEINLINE inline __attribute__ ((always_inline)) +#endif diff --git a/source/runtime/core/public/platforms/macos/MacOSPlatformMemory.hpp b/source/runtime/core/public/platforms/macos/MacOSPlatformMemory.hpp new file mode 100644 index 0000000..8e32d03 --- /dev/null +++ b/source/runtime/core/public/platforms/macos/MacOSPlatformMemory.hpp @@ -0,0 +1,24 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include "platforms/apple/ApplePlatformMemory.hpp" + +namespace gp::platform::macos +{ + +/// @brief macOS-specific implementation of the memory management platform. +class Memory final : public gp::platform::apple::Memory +{ +private: + /// @brief Deleted constructor prevent instantiation of the Memory class, as it is intended to be used. + Memory() = delete; + + /// @brief Deleted destructor prevent instantiation of the Memory class, as it is intended to be used. + ~Memory() = delete; +}; + +} // namespace gp::platform::macos diff --git a/source/runtime/core/public/platforms/unix/UnixPlatform.hpp b/source/runtime/core/public/platforms/unix/UnixPlatform.hpp new file mode 100644 index 0000000..8fd1e32 --- /dev/null +++ b/source/runtime/core/public/platforms/unix/UnixPlatform.hpp @@ -0,0 +1,40 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "miscellaneous/PreProcessorUtilities.hpp" +#include +#include + +#define _GP_IS_PLATFORM_64BIT GP_TRUE + +#define GP_PLATFORM_SUPPORTS_MIMALLOC _GP_IS_PLATFORM_64BIT +#define GP_PLATFORM_IS_ANSI_MALLOC_THREADSAFE GP_TRUE +#define GP_PLATFORM_USE_ANSI_POSIX_MALLOC GP_TRUE +#define GP_PLATFORM_SUPPORTS_BINDLESS_RENDERING GP_TRUE +#define GP_PLATFORM_SUPPORTS_MESH_SHADERS GP_TRUE + +#if GP_ARCHITECTURE_X86_FAMILY + #define GP_PLATFORM_BREAK() { __asm__ volatile("int $0x03"); } +#else + #define GP_PLATFORM_BREAK() raise(SIGTRAP) +#endif + +#define GP_VARARGS +#define GP_CDECL +#define GP_STDCALL +#if GP_BUILD_DEBUG + #define GP_FORCEINLINE inline +#else + #define GP_FORCEINLINE inline __attribute__ ((always_inline)) +#endif +#define GP_FORCENOINLINE __attribute__((noinline)) +#define GP_FUNCTION_CHECK_RETURN_END __attribute__ ((warn_unused_result)) +#define GP_FUNCTION_NO_RETURN_END __attribute__ ((noreturn)) + +#define ABSTRACT abstract + +#define DLLEXPORT __attribute__((visibility("default"))) +#define DLLIMPORT __attribute__((visibility("default"))) diff --git a/source/runtime/core/public/platforms/unix/UnixPlatformMemory.hpp b/source/runtime/core/public/platforms/unix/UnixPlatformMemory.hpp new file mode 100644 index 0000000..3a056d9 --- /dev/null +++ b/source/runtime/core/public/platforms/unix/UnixPlatformMemory.hpp @@ -0,0 +1,25 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include "platforms/generic/GenericPlatformMemory.hpp" + +namespace gp::platform::unix +{ + +/// @brief Unix-specific implementation of the memory management platform. +/// @note This class is not `final` to allow for platform-specific overrides in derived classes (e.g., Linux, macOS). +class Memory : public gp::platform::generic::Memory +{ +private: + /// @brief Deleted constructor prevent instantiation of the Memory class, as it is intended to be used. + Memory() = delete; + + /// @brief Deleted destructor prevent instantiation of the Memory class, as it is intended to be used. + ~Memory() = delete; +}; + +} // namespace gp::platform::unix diff --git a/source/runtime/core/public/platforms/windows/WindowsPlatform.hpp b/source/runtime/core/public/platforms/windows/WindowsPlatform.hpp new file mode 100644 index 0000000..df4804e --- /dev/null +++ b/source/runtime/core/public/platforms/windows/WindowsPlatform.hpp @@ -0,0 +1,49 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "miscellaneous/PreProcessorUtilities.hpp" + +// Include the header for Windows-specific annotations and macros +#include + +#if defined(_WIN64) + #define _GP_IS_PLATFORM_64BIT GP_TRUE +#else + #define _GP_IS_PLATFORM_64BIT GP_FALSE +#endif + +#define GP_PLATFORM_SUPPORTS_TBB GP_TRUE +#define GP_PLATFORM_SUPPORTS_MIMALLOC _GP_IS_PLATFORM_64BIT +#define GP_PLATFORM_SUPPORTS_NAMED_PIPES GP_TRUE +#define GP_PLATFORM_SUPPORTS_VARIABLE_RATE_SHADING GP_TRUE +#define GP_PLATFORM_SUPPORTS_MESH_SHADERS GP_TRUE +#define GP_PLATFORM_SUPPORTS_WORKGRAPH_SHADERS GP_TRUE +#define GP_PLATFORM_SUPPORTS_BINDLESS_RENDERING GP_TRUE +#define GP_PLATFORM_USE_ALIGNED_MALLOC GP_TRUE +#define GP_PLATFORM_SUPPORTS_BORDERLESS_WINDOW GP_TRUE + +#define GP_PLATFORM_BREAK() (__nop(), __debugbreak()) + +#define PLATFORM_HAS_128BIT_ATOMICS (_GP_IS_PLATFORM_64BIT && (WINVER >= 0x602)) + +#ifdef CDECL + #undef CDECL +#endif + +#define GP_VARARGS __cdecl +#define GP_CDECL __cdecl +#define GP_STDCALL __stdcall +#define GP_FORCEINLINE __forceinline +#define GP_FORCENOINLINE __declspec(noinline) + +#pragma warning(disable : 4481) + +#define GP_ABSTRACT abstract + +#define GP_PLATFORM_CACHE_LINE_SIZE 64 + +#define GP_DLLEXPORT __declspec(dllexport) +#define GP_DLLIMPORT __declspec(dllimport) diff --git a/source/runtime/core/public/platforms/windows/WindowsPlatformMemory.hpp b/source/runtime/core/public/platforms/windows/WindowsPlatformMemory.hpp new file mode 100644 index 0000000..8acf536 --- /dev/null +++ b/source/runtime/core/public/platforms/windows/WindowsPlatformMemory.hpp @@ -0,0 +1,24 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once + +#include "CoreMinimal.hpp" // IWYU pragma: keep +#include "platforms/generic/GenericPlatformMemory.hpp" + +namespace gp::platform::windows +{ + +/// @brief Windows-specific implementation of the memory management platform. +class Memory final : public gp::platform::generic::Memory +{ +private: + /// @brief Deleted constructor prevent instantiation of the Memory class, as it is intended to be used. + Memory() = delete; + + /// @brief Deleted destructor prevent instantiation of the Memory class, as it is intended to be used. + ~Memory() = delete; +}; + +} // namespace gp::platform::windows diff --git a/source/runtime/core/public/utils/Enums.hpp b/source/runtime/core/public/utils/Enums.hpp deleted file mode 100644 index 9c1c2b6..0000000 --- a/source/runtime/core/public/utils/Enums.hpp +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include - -/// @brief Enables bitwise operators for the specified enum type. -/// @param[in] enumType The enum type for which to enable bitwise operators. -/// @attention This macro should be used with caution, as it may lead to unintended consequences if the enum values are -/// not designed for bitwise operations. Make sure that the enum values are unique and meaningful for bitwise -/// operations before enabling this macro. -/// @example -/// @code -/// enum class MyFlags -/// { -/// None = 0, -/// FlagA = 1 << 0, -/// FlagB = 1 << 1, -/// FlagC = 1 << 2 -/// }; -/// GP_ENABLE_ENUM_BITWISE_OPERATIONS(MyFlags); -/// -/// MyFlags flags = MyFlags::FlagA | MyFlags::FlagB; // Bitwise OR -/// @endcode -#define GP_ENABLE_ENUM_BITWISE_OPERATIONS(enumType) \ - template <> \ - struct ::gp::EnableBitwiseOperators : std::true_type {} - -/// @brief Enables comparison operators for the specified enum type. -/// @param[in] enumType The enum type for which to enable comparison operators. -/// @attention This macro should be used with caution, as it may lead to unintended consequences if the enum values are -/// not designed for comparison operations. Make sure that the enum values are unique and meaningful for -/// comparison before enabling this macro. -/// @example -/// @code -/// enum class MyEnum -/// { -/// Minimum = 0, -/// Medium = 1, -/// Maximum = 2 -/// }; -/// GP_ENABLE_ENUM_COMPARISON_OPERATIONS(MyEnum); -/// -/// MyEnum a = MyEnum::Minimum; -/// MyEnum b = MyEnum::Medium; -/// bool areEqual = (a <= b); // Comparison operators enabled -/// @endcode -#define GP_ENABLE_ENUM_COMPARISON_OPERATIONS(enumType) \ - template <> \ - struct ::gp::EnableComparisonOperators : std::true_type {} - -namespace gp -{ - -/// @brief General template specialization to enable bitwise operators for enum types. -/// @note By default, bitwise operators are disabled for all enum types. To enable bitwise operators for a specific enum -/// type, specialize this template for that type and set it to `std::true_type` or use the -/// `GP_ENABLE_ENUM_BITWISE_OPERATIONS` macro. -template -struct EnableBitwiseOperators : std::false_type -{}; - -/// @brief Variable template to check if bitwise operators are enabled for a given type. -template -inline constexpr bool HasBitwiseOperatorsV = EnableBitwiseOperators::value; - -/// @brief Concept to check if a type is an enum and has bitwise operators enabled. -template -concept BitwiseEnum = std::is_enum_v && HasBitwiseOperatorsV; - -/// @brief General template specialization to enable comparison operators for enum types. -/// @note By default, comparison operators are disabled for all enum types. To enable comparison operators for a -/// specific enum type, specialize this template for that type and set it to `std::true_type` or use the -/// `GP_ENABLE_ENUM_COMPARISON_OPERATIONS` macro. -template -struct EnableComparisonOperators : std::false_type -{}; - -/// @brief Variable template to check if comparison operators are enabled for a given type. -template -inline constexpr bool HasComparisonOperatorsV = EnableComparisonOperators::value; - -/// @brief Concept to check if a type is an enum and has comparison operators enabled. -template -concept ComparableEnum = std::is_enum_v && HasComparisonOperatorsV; - -namespace enums -{ - -/// @brief Checks if any of the specified flags are set in the given enum value. -/// @tparam E The enum type, which must satisfy the `BitwiseEnum` concept. -/// @param[in] value The enum value to check for the specified flags. -template -GP_INLINE constexpr bool hasAnyFlags(E value) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(value) != 0; -} - -/// @brief Checks if all of the specified flags are set in the given enum value. -/// @tparam E The enum type, which must satisfy the `BitwiseEnum` concept. -/// @param[in] value The enum value to check for the specified flags. -/// @param[in] flags The flags to check for in the enum value. -template -GP_INLINE constexpr bool hasAllFlags(E value, E flags) noexcept -{ - using Underlying = std::underlying_type_t; - return (static_cast(value) & static_cast(flags)) == static_cast(flags); -} - -/// @brief Checks if none of the specified flags are set in the given enum value. -/// @tparam E The enum type, which must satisfy the `BitwiseEnum` concept. -/// @param[in] value The enum value to check for the specified flags. -/// @param[in] flags The flags to check for in the enum value. -template -GP_INLINE constexpr bool hasNoFlags(E value, E flags) noexcept -{ - using Underlying = std::underlying_type_t; - return (static_cast(value) & static_cast(flags)) == 0; -} - -/// @brief Sets the specified flags in the given enum value. -/// @tparam E The enum type, which must satisfy the `BitwiseEnum` concept. -/// @param[in] value The enum value to set the flags in. -/// @param[in] flags The flags to set in the enum value. -template -GP_INLINE constexpr E setFlags(E value, E flags) noexcept -{ - return value | flags; -} - -/// @brief Clears the specified flags in the given enum value. -/// @tparam E The enum type, which must satisfy the `BitwiseEnum` concept. -/// @param[in] value The enum value to clear the flags in. -/// @param[in] flags The flags to clear in the enum value. -template -GP_INLINE constexpr E clearFlags(E value, E flags) noexcept -{ - return value & ~flags; -} - -/// @brief Toggles the specified flags in the given enum value. -/// @tparam E The enum type, which must satisfy the `BitwiseEnum` concept. -/// @param[in] value The enum value to toggle the flags in. -/// @param[in] flags The flags to toggle in the enum value. -template -GP_INLINE constexpr E toggleFlags(E value, E flags) noexcept -{ - return value ^ flags; -} - -} // namespace enums - -} // namespace gp - -/// @brief Bitwise OR operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E operator|(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -/// @brief Bitwise AND operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E operator&(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(static_cast(lhs) & static_cast(rhs)); -} - -/// @brief Bitwise XOR operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E operator^(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(static_cast(lhs) ^ static_cast(rhs)); -} - -/// @brief Bitwise NOT operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E operator~(E value) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(~static_cast(value)); -} - -/// @brief Bitwise OR assignment operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E& operator|=(E& lhs, E rhs) noexcept -{ - lhs = lhs | rhs; - return lhs; -} - -/// @brief Bitwise AND assignment operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E& operator&=(E& lhs, E rhs) noexcept -{ - lhs = lhs & rhs; - return lhs; -} - -/// @brief Bitwise XOR assignment operator for enum types that satisfy the `BitwiseEnum` concept. -template -GP_INLINE constexpr E& operator^=(E& lhs, E rhs) noexcept -{ - lhs = lhs ^ rhs; - return lhs; -} - -/// @brief Equality operator for enum types that satisfy the `ComparableEnum` concept. -template -GP_INLINE constexpr bool operator==(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(lhs) == static_cast(rhs); -} - -/// @brief Inequality operator for enum types that satisfy the `ComparableEnum` concept. -template -GP_INLINE constexpr bool operator!=(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(lhs) != static_cast(rhs); -} - -/// @brief Less-than operator for enum types that satisfy the `ComparableEnum` concept. -template -GP_INLINE constexpr bool operator<(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(lhs) < static_cast(rhs); -} - -/// @brief Less-than or equal operator for enum types that satisfy the `ComparableEnum` concept. -template -GP_INLINE constexpr bool operator<=(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(lhs) <= static_cast(rhs); -} - -/// @brief Greater-than operator for enum types that satisfy the `ComparableEnum` concept. -template -GP_INLINE constexpr bool operator>(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(lhs) > static_cast(rhs); -} - -/// @brief Greater-than or equal operator for enum types that satisfy the `ComparableEnum` concept. -template -GP_INLINE constexpr bool operator>=(E lhs, E rhs) noexcept -{ - using Underlying = std::underlying_type_t; - return static_cast(lhs) >= static_cast(rhs); -} diff --git a/source/runtime/core/tests/container/Array.tests.cpp b/source/runtime/core/tests/container/Array.tests.cpp deleted file mode 100644 index 02ea53a..0000000 --- a/source/runtime/core/tests/container/Array.tests.cpp +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "container/Array.hpp" -#include -#include - -namespace gp::tests -{ - -consteval bool testConstexprArray() -{ - gp::Array arr{ 1, 2, 3, 4, 5 }; - arr.fill(10); - arr[2] = 42; - arr.clear(); - - gp::Array arr2{ 1, 1, 1, 1, 1 }; - arr.swap(arr2); - - return arr[0] == 1 && arr2[0] == 0 && arr.size() == 5; -} - -static_assert(testConstexprArray(), "Array must be fully usable in constant expressions"); - -static_assert(std::is_trivially_copyable_v>); -static_assert(std::is_trivially_copy_assignable_v>); -static_assert(std::is_nothrow_move_constructible_v>); - -TEST_CASE("Array - Initialization and Capacity", "[container][Array]") -{ - SECTION("Default Construction") - { - gp::Array arr; - REQUIRE(arr.size() == 3); - REQUIRE(arr.capacity() == 3); - REQUIRE(arr.isEmpty() == false); - // Value initialization ensures elements are zero - REQUIRE(arr[0] == 0); - REQUIRE(arr[1] == 0); - REQUIRE(arr[2] == 0); - } - - SECTION("Initializer List Construction") - { - gp::Array arr{ 1, 2, 3, 4 }; - REQUIRE(arr.size() == 4); - REQUIRE(arr.capacity() == 4); - REQUIRE(arr.isEmpty() == false); - REQUIRE(arr[0] == 1); - REQUIRE(arr[3] == 4); - } - - SECTION("Variadic Initialization") - { - gp::Array arr{ 10, 20, 30, 40 }; - REQUIRE(arr[0] == 10); - REQUIRE(arr[3] == 40); - } - - SECTION("Partial Variadic Initialization") - { - gp::Array arr{ 1, 2 }; // Remaining should be 0 - REQUIRE(arr[0] == 1); - REQUIRE(arr[1] == 2); - REQUIRE(arr[2] == 0); - REQUIRE(arr[4] == 0); - } - - SECTION("Zero-sized Array Edge Case") - { - gp::Array emptyArr; - REQUIRE(emptyArr.size() == 0); - REQUIRE(emptyArr.capacity() == 0); - REQUIRE(emptyArr.isEmpty() == true); - REQUIRE(emptyArr.data() == nullptr); - REQUIRE(emptyArr.begin() == emptyArr.end()); - } -} - -TEST_CASE("Array - Element Access", "[container][Array]") -{ - gp::Array arr{ 5, 10, 15 }; - const gp::Array carr{ 5, 10, 15 }; - - SECTION("operator[]") - { - REQUIRE(arr[0] == 5); - REQUIRE(arr[2] == 15); - REQUIRE(carr[1] == 10); - - arr[1] = 99; - REQUIRE(arr[1] == 99); - } - - SECTION("at()") - { - REQUIRE(arr.at(0) == 5); - REQUIRE(arr.at(2) == 15); - REQUIRE(carr.at(1) == 10); - - arr.at(1) = 99; - REQUIRE(arr.at(1) == 99); - } - - SECTION("front() and back()") - { - REQUIRE(arr.front() == 5); - REQUIRE(arr.back() == 15); - REQUIRE(carr.front() == 5); - REQUIRE(carr.back() == 15); - - arr.front() = 1; - arr.back() = 3; - REQUIRE(arr[0] == 1); - REQUIRE(arr[2] == 3); - } - - SECTION("data()") - { - REQUIRE(arr.data() == &arr[0]); - REQUIRE(carr.data() == &carr[0]); - - arr.data()[0] = 42; - REQUIRE(arr[0] == 42); - } -} - -TEST_CASE("Array - Iterators", "[container][Array]") -{ - gp::Array arr{ 1, 2, 3, 4 }; - const gp::Array carr{ 1, 2, 3, 4 }; - - SECTION("Forward Iterators") - { - int sum = 0; - for (auto it = arr.begin(); it != arr.end(); ++it) - { - sum += *it; - } - REQUIRE(sum == 10); - - sum = 0; - for (auto it = carr.begin(); it != carr.end(); ++it) - { - sum += *it; - } - REQUIRE(sum == 10); - } - - SECTION("Reverse Iterators") - { - REQUIRE(*arr.rbegin() == 4); - REQUIRE(*(arr.rend() - 1) == 1); - REQUIRE(*carr.crbegin() == 4); - - int sum = 0; - for (auto it = arr.rbegin(); it != arr.rend(); ++it) - { - sum += *it; - } - REQUIRE(sum == 10); - } - - SECTION("Const Iterators (cbegin/cend)") - { - REQUIRE(*arr.cbegin() == 1); - REQUIRE(*(arr.cend() - 1) == 4); - } - - SECTION("Standard library compatibility") - { - gp::Array target; - std::copy(carr.begin(), carr.end(), target.begin()); - REQUIRE(target == carr); - } -} - -TEST_CASE("Array - Modifiers", "[container][Array]") -{ - SECTION("fill()") - { - gp::Array arr; - arr.fill(42); - // clang-format off - REQUIRE((arr[0] == 42 && arr[1] == 42 && arr[2] == 42)); - // clang-format on - } - - SECTION("clear()") - { - gp::Array arr{ 1, 2, 3 }; - arr.clear(); - // clang-format off - REQUIRE((arr[0] == 0 && arr[1] == 0 && arr[2] == 0)); - // clang-format on - } - - SECTION("swap() method") - { - gp::Array arr1{ 1, 2, 3 }; - gp::Array arr2{ 7, 8, 9 }; - - arr1.swap(arr2); - - REQUIRE(arr1[0] == 7); - REQUIRE(arr2[0] == 1); - } - - SECTION("ADL swap free function") - { - gp::Array arr1{ 1, 2, 3 }; - gp::Array arr2{ 7, 8, 9 }; - - using std::swap; - swap(arr1, arr2); // Should resolve to gp::swap - - REQUIRE(arr1[0] == 7); - REQUIRE(arr2[0] == 1); - } -} - -TEST_CASE("Array - Operations and Search Algorithms", "[container][Array]") -{ - const gp::Array arr{ 10, 20, 20, 30, 20, 40 }; - - SECTION("find()") - { - REQUIRE(*arr.find(30) == 30); - REQUIRE(arr.find(99) == arr.end()); - - gp::Array mutArr = arr; - *mutArr.find(10) = 15; - REQUIRE(mutArr[0] == 15); - } - - SECTION("contains()") - { - REQUIRE(arr.contains(20) == true); - REQUIRE(arr.contains(99) == false); - } - - SECTION("count()") - { - REQUIRE(arr.count(20) == 3); - REQUIRE(arr.count(10) == 1); - REQUIRE(arr.count(99) == 0); - } - - SECTION("indexOf() and lastIndexOf()") - { - REQUIRE(arr.indexOf(20) == 1); - REQUIRE(arr.lastIndexOf(20) == 4); - - REQUIRE(arr.indexOf(99) == gp::Array::npos); - REQUIRE(arr.lastIndexOf(99) == gp::Array::npos); - } - - SECTION("indexNotOf() and lastIndexNotOf()") - { - gp::Array uniform{ 5, 5, 5, 5 }; - REQUIRE(uniform.indexNotOf(5) == gp::Array::npos); - REQUIRE(uniform.lastIndexNotOf(5) == gp::Array::npos); - - gp::Array mixed{ 5, 5, 7, 5, 8 }; - REQUIRE(mixed.indexNotOf(5) == 2); - REQUIRE(mixed.lastIndexNotOf(5) == 4); - } -} - -TEST_CASE("Array - Rule of Zero and Comparisons", "[container][Array]") -{ - gp::Array arr1{ 1, 2, 3 }; - gp::Array arr2{ 1, 2, 3 }; - gp::Array arr3{ 1, 9, 3 }; - - SECTION("Copy Semantics") - { - gp::Array copyConstructed = arr1; - REQUIRE(copyConstructed == arr1); - - gp::Array copyAssigned; - copyAssigned = arr1; - REQUIRE(copyAssigned == arr1); - } - - SECTION("Move Semantics") - { - gp::Array moveConstructed = std::move(arr1); - REQUIRE(moveConstructed[0] == 1); // Note: moving trivial types is just a copy - - gp::Array moveAssigned; - moveAssigned = std::move(arr2); - REQUIRE(moveAssigned[1] == 2); - } - - SECTION("Spaceship Operator (<=>)") - { - // Equality - REQUIRE(arr1 == arr2); - REQUIRE(arr1 != arr3); - - // Lexicographical ordering - REQUIRE(arr1 < arr3); // 1,2,3 < 1,9,3 - REQUIRE(arr3 > arr1); - REQUIRE(arr1 <= arr2); - REQUIRE(arr2 >= arr1); - } -} - -} // namespace gp::tests diff --git a/source/runtime/core/tests/container/BasicString.tests.cpp b/source/runtime/core/tests/container/BasicString.tests.cpp deleted file mode 100644 index 4b55ef2..0000000 --- a/source/runtime/core/tests/container/BasicString.tests.cpp +++ /dev/null @@ -1,771 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "container/BasicString.hpp" -#include "container/BasicStringView.hpp" -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "memory/allocators/DefaultAllocator.hpp" -#include "memory/allocators/LinearAllocator.hpp" -#include "memory/allocators/PolymorphicAllocator.hpp" -#include - -namespace gp::tests -{ - -TEST_CASE("String - sizeof is exactly 32 bytes", "[container][String]") -{ - STATIC_REQUIRE(sizeof(gp::String) == 32); -} - -TEST_CASE("String - SSO threshold is 23 characters", "[container][String]") -{ - // 23 chars should stay in SSO - gp::String sso("12345678901234567890123"); - REQUIRE(sso.size() == 23); - REQUIRE(sso.capacity() == 23); - - // 24 chars should hit the heap - gp::String heap("123456789012345678901234"); - REQUIRE(heap.size() == 24); - REQUIRE(heap.capacity() >= 24); -} - -TEST_CASE("String - default construction", "[container][String]") -{ - gp::String s; - REQUIRE(s.size() == 0); - REQUIRE(s.isEmpty()); - REQUIRE(s.capacity() == 23); - REQUIRE(s[0] == '\0'); -} - -TEST_CASE("String - construction from C string", "[container][String]") -{ - gp::String s("hello"); - REQUIRE(s.size() == 5); - REQUIRE(s == "hello"); - REQUIRE(s.cStr()[5] == '\0'); -} - -TEST_CASE("String - construction from nullptr", "[container][String]") -{ - gp::String s(static_cast(nullptr)); - REQUIRE(s.isEmpty()); -} - -TEST_CASE("String - construction from pointer and count", "[container][String]") -{ - gp::String s("hello world", 5); - REQUIRE(s.size() == 5); - REQUIRE(s == "hello"); -} - -TEST_CASE("String - construction with fill character", "[container][String]") -{ - gp::String s(10, 'x'); - REQUIRE(s.size() == 10); - for (gp::USize i = 0; i < 10; ++i) - { - REQUIRE(s[i] == 'x'); - } -} - -TEST_CASE("String - construction with fill character (heap)", "[container][String]") -{ - gp::String s(30, 'A'); - REQUIRE(s.size() == 30); - for (gp::USize i = 0; i < 30; ++i) - { - REQUIRE(s[i] == 'A'); - } -} - -TEST_CASE("String - initializer list construction", "[container][String]") -{ - gp::String s({ 'a', 'b', 'c' }); - REQUIRE(s.size() == 3); - REQUIRE(s == "abc"); -} - -TEST_CASE("String - construction from StringView", "[container][String]") -{ - gp::StringView sv("hello world"); - gp::String s(sv); - REQUIRE(s.size() == 11); - REQUIRE(s == "hello world"); -} - -TEST_CASE("String - substring construction", "[container][String]") -{ - gp::String full("hello world"); - gp::String sub(full, 6); - REQUIRE(sub == "world"); - REQUIRE(sub.size() == 5); - - gp::String sub2(full, 0, 5); - REQUIRE(sub2 == "hello"); -} - -TEST_CASE("String - copy construction (SSO)", "[container][String]") -{ - gp::String a("short"); - gp::String b(a); - REQUIRE(b == "short"); - REQUIRE(a.data() != b.data()); -} - -TEST_CASE("String - copy construction (heap)", "[container][String]") -{ - gp::String a("this is a long string that exceeds SSO"); - gp::String b(a); - REQUIRE(b == a); - REQUIRE(b.data() != a.data()); -} - -TEST_CASE("String - move construction", "[container][String]") -{ - gp::String a("hello"); - gp::String b(static_cast(a)); - REQUIRE(b == "hello"); - REQUIRE(a.isEmpty()); -} - -TEST_CASE("String - move construction from heap", "[container][String]") -{ - gp::String a("this is a long string that exceeds SSO buffer"); - const char* old_data = a.data(); - gp::String b(static_cast(a)); - REQUIRE(b.data() == old_data); - REQUIRE(a.isEmpty()); -} - -TEST_CASE("String - copy assignment", "[container][String]") -{ - gp::String a("hello"); - gp::String b("world"); - b = a; - REQUIRE(b == "hello"); -} - -TEST_CASE("String - move assignment", "[container][String]") -{ - gp::String a("hello"); - gp::String b; - b = static_cast(a); - REQUIRE(b == "hello"); - REQUIRE(a.isEmpty()); -} - -TEST_CASE("String - self-copy assignment", "[container][String]") -{ - gp::String a("hello"); - a = a; - REQUIRE(a == "hello"); -} - -TEST_CASE("String - assign from C string", "[container][String]") -{ - gp::String s; - s = "hello"; - REQUIRE(s == "hello"); -} - -TEST_CASE("String - assign single char", "[container][String]") -{ - gp::String s; - s = 'x'; - REQUIRE(s.size() == 1); - REQUIRE(s[0] == 'x'); -} - -TEST_CASE("String - assign from StringView", "[container][String]") -{ - gp::String s; - s = gp::StringView("test"); - REQUIRE(s == "test"); -} - -TEST_CASE("String - assign count and char", "[container][String]") -{ - gp::String s("something"); - s.assign(5, 'z'); - REQUIRE(s.size() == 5); - REQUIRE(s == "zzzzz"); -} - -TEST_CASE("String - assign from substring", "[container][String]") -{ - gp::String a("hello world"); - gp::String b; - b.assign(a, 6, 5); - REQUIRE(b == "world"); -} - -TEST_CASE("String - operator+=", "[container][String]") -{ - gp::String s("hello"); - s += " world"; - REQUIRE(s == "hello world"); - - s += gp::String("!"); - REQUIRE(s == "hello world!"); - - s += '?'; - REQUIRE(s == "hello world!?"); -} - -TEST_CASE("String - operator+ concatenation", "[container][String]") -{ - gp::String a("hello"); - gp::String b(" world"); - gp::String c = a + b; - REQUIRE(c == "hello world"); - - gp::String d = a + " there"; - REQUIRE(d == "hello there"); - - gp::String e = "hey " + b; - REQUIRE(e == "hey world"); -} - -TEST_CASE("String - equality and inequality", "[container][String]") -{ - gp::String a("hello"); - gp::String b("hello"); - gp::String c("world"); - REQUIRE(a == b); - REQUIRE(a != c); - REQUIRE(a == "hello"); - REQUIRE(a != "world"); -} - -TEST_CASE("String - spaceship operator", "[container][String]") -{ - gp::String a("abc"); - gp::String b("abd"); - CHECK((a <=> b) == std::strong_ordering::less); - CHECK((b <=> a) == std::strong_ordering::greater); - CHECK((a <=> a) == std::strong_ordering::equal); - CHECK((a <=> "abd") == std::strong_ordering::less); -} - -TEST_CASE("String - implicit conversion to StringView", "[container][String]") -{ - gp::String s("hello"); - gp::StringView sv = s; - REQUIRE(sv.size() == 5); - REQUIRE(sv == gp::StringView("hello")); -} - -TEST_CASE("String - at / operator[]", "[container][String]") -{ - gp::String s("abcdef"); - REQUIRE(s.at(0) == 'a'); - REQUIRE(s.at(5) == 'f'); - REQUIRE(s[3] == 'd'); -} - -TEST_CASE("String - front and back", "[container][String]") -{ - gp::String s("abc"); - REQUIRE(s.front() == 'a'); - REQUIRE(s.back() == 'c'); -} - -TEST_CASE("String - data and cStr are null-terminated", "[container][String]") -{ - gp::String s("test"); - REQUIRE(s.data()[4] == '\0'); - REQUIRE(s.cStr()[4] == '\0'); -} - -TEST_CASE("String - iterators", "[container][String]") -{ - gp::String s("abc"); - REQUIRE(*s.begin() == 'a'); - REQUIRE(*(s.end() - 1) == 'c'); - - gp::USize count = 0; - for (char ch: s) - { - (void)ch; - ++count; - } - REQUIRE(count == 3); -} - -TEST_CASE("String - reverse iterators", "[container][String]") -{ - gp::String s("abc"); - REQUIRE(*s.rbegin() == 'c'); - REQUIRE(*(s.rend() - 1) == 'a'); -} - -TEST_CASE("String - reserve transitions SSO to heap", "[container][String]") -{ - gp::String s("hi"); - REQUIRE(s.capacity() == 23); // SSO - s.reserve(100); - REQUIRE(s.capacity() >= 100); - REQUIRE(s == "hi"); -} - -TEST_CASE("String - shrinkToFit back to SSO", "[container][String]") -{ - gp::String s("hi"); - s.reserve(100); - REQUIRE(s.capacity() >= 100); - s.shrinkToFit(); - REQUIRE(s.capacity() == 23); // Back to SSO - REQUIRE(s == "hi"); -} - -TEST_CASE("String - shrinkToFit on heap", "[container][String]") -{ - gp::String s(50, 'x'); - s.reserve(200); - REQUIRE(s.capacity() >= 200); - s.shrinkToFit(); - REQUIRE(s.capacity() == 50); - REQUIRE(s.size() == 50); -} - -TEST_CASE("String - clear", "[container][String]") -{ - gp::String s("hello"); - s.clear(); - REQUIRE(s.isEmpty()); - REQUIRE(s[0] == '\0'); -} - -TEST_CASE("String - clear on heap preserves capacity", "[container][String]") -{ - gp::String s(50, 'x'); - gp::USize cap = s.capacity(); - s.clear(); - REQUIRE(s.isEmpty()); - REQUIRE(s.capacity() == cap); -} - -TEST_CASE("String - pushBack", "[container][String]") -{ - gp::String s; - for (char c = 'a'; c <= 'z'; ++c) - { - s.pushBack(c); - } - REQUIRE(s.size() == 26); - REQUIRE(s[0] == 'a'); - REQUIRE(s[25] == 'z'); -} - -TEST_CASE("String - pushBack triggers SSO to heap transition", "[container][String]") -{ - gp::String s(23, 'a'); - REQUIRE(s.capacity() == 23); - s.pushBack('b'); - REQUIRE(s.size() == 24); - REQUIRE(s.capacity() > 23); - REQUIRE(s[23] == 'b'); -} - -TEST_CASE("String - popBack", "[container][String]") -{ - gp::String s("hello"); - s.popBack(); - REQUIRE(s == "hell"); - REQUIRE(s.size() == 4); -} - -TEST_CASE("String - append string", "[container][String]") -{ - gp::String s("hello"); - s.append(" world"); - REQUIRE(s == "hello world"); -} - -TEST_CASE("String - append buffer", "[container][String]") -{ - gp::String s("ab"); - s.append("cdef", 2); - REQUIRE(s == "abcd"); -} - -TEST_CASE("String - append fill", "[container][String]") -{ - gp::String s("ab"); - s.append(3, 'c'); - REQUIRE(s == "abccc"); -} - -TEST_CASE("String - append crossing SSO boundary", "[container][String]") -{ - gp::String s(20, 'a'); - s.append("bbbb"); - REQUIRE(s.size() == 24); - REQUIRE(s[23] == 'b'); -} - -TEST_CASE("String - insert", "[container][String]") -{ - gp::String s("helo"); - s.insert(2, "l"); - REQUIRE(s == "hello"); -} - -TEST_CASE("String - insert fill", "[container][String]") -{ - gp::String s("hlo"); - s.insert(1, 2, 'e'); - REQUIRE(s == "heelo"); -} - -TEST_CASE("String - insert at beginning", "[container][String]") -{ - gp::String s("world"); - s.insert(0, "hello "); - REQUIRE(s == "hello world"); -} - -TEST_CASE("String - erase", "[container][String]") -{ - gp::String s("hello world"); - s.erase(5, 6); - REQUIRE(s == "hello"); -} - -TEST_CASE("String - erase to end", "[container][String]") -{ - gp::String s("hello world"); - s.erase(5); - REQUIRE(s == "hello"); -} - -TEST_CASE("String - erase iterator", "[container][String]") -{ - gp::String s("hello"); - auto it = s.erase(s.begin() + 1); - REQUIRE(*it == 'l'); - REQUIRE(s == "hllo"); -} - -TEST_CASE("String - erase iterator range", "[container][String]") -{ - gp::String s("hello world"); - s.erase(s.begin() + 5, s.end()); - REQUIRE(s == "hello"); -} - -TEST_CASE("String - replace", "[container][String]") -{ - gp::String s("hello world"); - s.replace(6, 5, "there"); - REQUIRE(s == "hello there"); -} - -TEST_CASE("String - replace with different length", "[container][String]") -{ - gp::String s("abc"); - s.replace(1, 1, "xyz"); - REQUIRE(s == "axyzc"); -} - -TEST_CASE("String - resize grow", "[container][String]") -{ - gp::String s("hi"); - s.resize(5, '!'); - REQUIRE(s.size() == 5); - REQUIRE(s == gp::StringView("hi!!!", 5)); -} - -TEST_CASE("String - resize shrink", "[container][String]") -{ - gp::String s("hello world"); - s.resize(5); - REQUIRE(s == "hello"); -} - -TEST_CASE("String - swap SSO strings", "[container][String]") -{ - gp::String a("hello"); - gp::String b("world"); - a.swap(b); - REQUIRE(a == "world"); - REQUIRE(b == "hello"); -} - -TEST_CASE("String - swap heap strings", "[container][String]") -{ - gp::String a(30, 'a'); - gp::String b(30, 'b'); - const char* a_data = a.data(); - const char* b_data = b.data(); - a.swap(b); - REQUIRE(a.data() == b_data); - REQUIRE(b.data() == a_data); -} - -TEST_CASE("String - swap SSO and heap", "[container][String]") -{ - gp::String sso("short"); - gp::String heap(30, 'x'); - sso.swap(heap); - REQUIRE(sso.size() == 30); - REQUIRE(heap == "short"); -} - -TEST_CASE("String - copy", "[container][String]") -{ - gp::String s("hello world"); - char buf[6] = {}; - gp::USize n = s.copy(buf, 5, 6); - REQUIRE(n == 5); - REQUIRE(gp::StringView(buf, 5) == gp::StringView("world")); -} - -TEST_CASE("String - substr", "[container][String]") -{ - gp::String s("hello world"); - gp::String sub = s.substr(6); - REQUIRE(sub == "world"); - - gp::String sub2 = s.substr(0, 5); - REQUIRE(sub2 == "hello"); -} - -TEST_CASE("String - compare", "[container][String]") -{ - gp::String a("abc"); - gp::String b("abd"); - REQUIRE(a.compare(b) < 0); - REQUIRE(b.compare(a) > 0); - REQUIRE(a.compare(a) == 0); - REQUIRE(a.compare("abc") == 0); -} - -TEST_CASE("String - find", "[container][String]") -{ - gp::String s("hello hello world"); - REQUIRE(s.find("hello") == 0); - REQUIRE(s.find("hello", 1) == 6); - REQUIRE(s.find('w') == 12); - REQUIRE(s.find("xyz") == gp::String::npos); -} - -TEST_CASE("String - rfind", "[container][String]") -{ - gp::String s("hello hello"); - REQUIRE(s.rfind("hello") == 6); - REQUIRE(s.rfind("hello", 5) == 0); - REQUIRE(s.rfind('o') == 10); -} - -TEST_CASE("String - findFirstOf and findLastOf", "[container][String]") -{ - gp::String s("hello world"); - REQUIRE(s.findFirstOf("aeiou") == 1); - REQUIRE(s.findLastOf("aeiou") == 7); -} - -TEST_CASE("String - findFirstNotOf and findLastNotOf", "[container][String]") -{ - gp::String s("aaabbb"); - REQUIRE(s.findFirstNotOf("a") == 3); - REQUIRE(s.findLastNotOf("b") == 2); -} - -TEST_CASE("String - startsWith", "[container][String]") -{ - gp::String s("hello world"); - REQUIRE(s.startsWith("hello")); - REQUIRE(s.startsWith('h')); - REQUIRE_FALSE(s.startsWith("world")); -} - -TEST_CASE("String - endsWith", "[container][String]") -{ - gp::String s("hello world"); - REQUIRE(s.endsWith("world")); - REQUIRE(s.endsWith('d')); - REQUIRE_FALSE(s.endsWith("hello")); -} - -TEST_CASE("String - contains", "[container][String]") -{ - gp::String s("hello world"); - REQUIRE(s.contains("lo wo")); - REQUIRE(s.contains('w')); - REQUIRE_FALSE(s.contains("xyz")); -} - -TEST_CASE("String - copy uses select_on_container_copy_construction", "[string][allocator]") -{ - alignas(16) gp::UInt8 buf[4096]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator custom(&lin); - - gp::String a("hello", custom); - gp::String b(a); - REQUIRE(b == "hello"); - REQUIRE(b.getAllocator().getResource() == &gp::memory::DefaultAllocator::get()); -} - -TEST_CASE("String - move transfers allocator", "[string][allocator]") -{ - alignas(16) gp::UInt8 buf[4096]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator custom(&lin); - - gp::String a("hello", custom); - gp::String b(static_cast(a)); - REQUIRE(b.getAllocator().getResource() == &lin); -} - -TEST_CASE("String - custom allocator with heap allocation", "[string][allocator]") -{ - alignas(16) gp::UInt8 buf[8192]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator alloc(&lin); - - gp::String s(50, 'x', alloc); - REQUIRE(s.size() == 50); - REQUIRE(lin.getAllocatedSize() > 0); - for (gp::USize i = 0; i < 50; ++i) - { - REQUIRE(s[i] == 'x'); - } -} - -TEST_CASE("String - exactly at SSO boundary (23 chars)", "[string][sso]") -{ - gp::String s("12345678901234567890123"); - REQUIRE(s.size() == 23); - REQUIRE(s.capacity() == 23); // Still in SSO - REQUIRE(s.cStr()[23] == '\0'); -} - -TEST_CASE("String - one past SSO boundary (24 chars)", "[string][sso]") -{ - gp::String s("123456789012345678901234"); - REQUIRE(s.size() == 24); - REQUIRE(s.capacity() >= 24); - REQUIRE(s.cStr()[24] == '\0'); -} - -TEST_CASE("String - grow from SSO to heap via append", "[string][sso]") -{ - gp::String s(23, 'a'); - REQUIRE(s.capacity() == 23); - s.append("b"); - REQUIRE(s.size() == 24); - REQUIRE(s.capacity() > 23); - REQUIRE(s[0] == 'a'); - REQUIRE(s[23] == 'b'); -} - -TEST_CASE("String - empty string is in SSO mode", "[string][sso]") -{ - gp::String s; - REQUIRE(s.capacity() == 23); - REQUIRE(s.data() != nullptr); -} - -TEST_CASE("String - repeated pushBack across SSO boundary", "[container][String]") -{ - gp::String s; - for (int i = 0; i < 200; ++i) - { - s.pushBack(static_cast('a' + (i % 26))); - } - REQUIRE(s.size() == 200); - for (int i = 0; i < 200; ++i) - { - REQUIRE(s[i] == static_cast('a' + (i % 26))); - } -} - -TEST_CASE("String - formatting a string via gp::String::format", "[container][String][format]") -{ - SECTION("Standard types (integers, floats, C-strings)") - { - gp::String s = gp::String::format("Hello, {}! The answer is {}.", "world", 42); - REQUIRE(s == "Hello, world! The answer is 42."); - - gp::String f = gp::String::format("Pi is roughly {:.2f}", 3.14159); - REQUIRE(f == "Pi is roughly 3.14"); - } - - SECTION("Formatting with gp::String as an argument") - { - gp::String name = "Alice"; - gp::String s = gp::String::format("User name: {}", name); - REQUIRE(s == "User name: Alice"); - } - - SECTION("Formatting with gp::StringView as an argument") - { - // Assuming gp::StringView is the typedef for your BasicStringView - gp::String original = "Bob"; - gp::BasicStringView> view = original; - - gp::String s = gp::String::format("User view: {}", view); - REQUIRE(s == "User view: Bob"); - } - - SECTION("Multiple gp::String and gp::StringView arguments combined") - { - gp::String first = "Graphical"; - gp::StringView second = "Playground"; - - gp::String s = gp::String::format("{} {}", first, second); - REQUIRE(s == "Graphical Playground"); - } - - SECTION("Format specifiers: Width, Fill, and Alignment") - { - // Because we inherited from std::formatter, - // these should work automatically for gp::String and gp::StringView! - gp::String str = "C++"; - gp::StringView view = "20"; - - // Right align, width 6, padded with spaces - REQUIRE(gp::String::format("{:>6}", str) == " C++"); - - // Left align, width 6, padded with dashes - REQUIRE(gp::String::format("{:-<6}", view) == "20----"); - - // Center align, width 9, padded with asterisks - REQUIRE(gp::String::format("{:*^9}", str) == "***C++***"); - } - - SECTION("Empty strings and views") - { - gp::String emptyStr; - gp::StringView emptyView; - - REQUIRE(gp::String::format("[{}]", emptyStr) == "[]"); - REQUIRE(gp::String::format("[{}]", emptyView) == "[]"); - REQUIRE(gp::String::format("{}", gp::String("")) == ""); - } - - SECTION("Heap allocation (Exceeding SSO buffer)") - { - // gp::BasicString has a 23-character SSO limit. - // We want to format a string that guarantees a heap allocation. - gp::String s1 = "This is a string "; - gp::String s2 = "that is definitely way longer than 23 characters."; - - gp::String result = gp::String::format("{}{}", s1, s2); - - REQUIRE(result.size() > 23); - REQUIRE(result == "This is a string that is definitely way longer than 23 characters."); - - // Verify formatting a long gp::String into another format works - gp::String wrapped = gp::String::format("<<{}>>", result); - REQUIRE(wrapped == "<>"); - } -} - -} // namespace gp::tests diff --git a/source/runtime/core/tests/container/BasicStringView.tests.cpp b/source/runtime/core/tests/container/BasicStringView.tests.cpp deleted file mode 100644 index 03c98e4..0000000 --- a/source/runtime/core/tests/container/BasicStringView.tests.cpp +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "container/BasicStringView.hpp" -#include "container/Forward.hpp" -#include - -namespace gp::tests -{ - -TEST_CASE("StringView - default construction", "[container][StringView]") -{ - gp::StringView v; - REQUIRE(v.data() == nullptr); - REQUIRE(v.size() == 0); - REQUIRE(v.isEmpty()); -} - -TEST_CASE("StringView - construct from C string", "[container][StringView]") -{ - gp::StringView v("hello"); - REQUIRE(v.size() == 5); - REQUIRE(v[0] == 'h'); - REQUIRE(v[4] == 'o'); -} - -TEST_CASE("StringView - construct from nullptr", "[container][StringView]") -{ - gp::StringView v(nullptr); - REQUIRE(v.size() == 0); - REQUIRE(v.data() == nullptr); -} - -TEST_CASE("StringView - construct from pointer and length", "[container][StringView]") -{ - const char* str = "hello world"; - gp::StringView v(str, 5); - REQUIRE(v.size() == 5); - REQUIRE(v[4] == 'o'); -} - -TEST_CASE("StringView - at", "[container][StringView]") -{ - gp::StringView v("abcdef"); - REQUIRE(v.at(0) == 'a'); - REQUIRE(v.at(5) == 'f'); -} - -TEST_CASE("StringView - front and back", "[container][StringView]") -{ - gp::StringView v("abc"); - REQUIRE(v.front() == 'a'); - REQUIRE(v.back() == 'c'); -} - -TEST_CASE("StringView - length and maxSize", "[container][StringView]") -{ - gp::StringView v("test"); - REQUIRE(v.length() == 4); - REQUIRE(v.maxSize() > 0); -} - -TEST_CASE("StringView - iterators", "[container][StringView]") -{ - gp::StringView v("abc"); - REQUIRE(*v.begin() == 'a'); - REQUIRE(*(v.end() - 1) == 'c'); - REQUIRE(*v.cbegin() == 'a'); - - gp::USize count = 0; - for (auto it = v.begin(); it != v.end(); ++it) - { - ++count; - } - REQUIRE(count == 3); -} - -TEST_CASE("StringView - reverse iterators", "[container][StringView]") -{ - gp::StringView v("abc"); - REQUIRE(*v.rbegin() == 'c'); - REQUIRE(*(v.rend() - 1) == 'a'); - REQUIRE(*v.crbegin() == 'c'); -} - -TEST_CASE("StringView - removePrefix", "[container][StringView]") -{ - gp::StringView v("hello world"); - v.removePrefix(6); - REQUIRE(v.size() == 5); - REQUIRE(v == gp::StringView("world")); -} - -TEST_CASE("StringView - removeSuffix", "[container][StringView]") -{ - gp::StringView v("hello world"); - v.removeSuffix(6); - REQUIRE(v.size() == 5); - REQUIRE(v == gp::StringView("hello")); -} - -TEST_CASE("StringView - swap", "[container][StringView]") -{ - gp::StringView a("hello"); - gp::StringView b("world"); - a.swap(b); - REQUIRE(a == gp::StringView("world")); - REQUIRE(b == gp::StringView("hello")); -} - -TEST_CASE("StringView - copy", "[container][StringView]") -{ - gp::StringView v("hello world"); - char buf[6] = {}; - gp::USize n = v.copy(buf, 5, 6); - REQUIRE(n == 5); - REQUIRE(gp::StringView(buf, 5) == gp::StringView("world")); -} - -TEST_CASE("StringView - copy clamped to remaining", "[container][StringView]") -{ - gp::StringView v("hi"); - char buf[10] = {}; - gp::USize n = v.copy(buf, 100); - REQUIRE(n == 2); -} - -TEST_CASE("StringView - substr", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.substr(0, 5) == gp::StringView("hello")); - REQUIRE(v.substr(6) == gp::StringView("world")); - REQUIRE(v.substr(6, 100) == gp::StringView("world")); - REQUIRE(v.substr(0, 0).isEmpty()); -} - -TEST_CASE("StringView - compare", "[container][StringView]") -{ - REQUIRE(gp::StringView("abc").compare(gp::StringView("abc")) == 0); - REQUIRE(gp::StringView("abc").compare(gp::StringView("abd")) < 0); - REQUIRE(gp::StringView("abd").compare(gp::StringView("abc")) > 0); - REQUIRE(gp::StringView("ab").compare(gp::StringView("abc")) < 0); - REQUIRE(gp::StringView("abc").compare(gp::StringView("ab")) > 0); -} - -TEST_CASE("StringView - compare substrings", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.compare(0, 5, gp::StringView("hello")) == 0); - REQUIRE(v.compare(6, 5, gp::StringView("world")) == 0); -} - -TEST_CASE("StringView - compare with C string", "[container][StringView]") -{ - REQUIRE(gp::StringView("abc").compare("abc") == 0); - REQUIRE(gp::StringView("abc").compare("abd") < 0); -} - -TEST_CASE("StringView - equality operators", "[container][StringView]") -{ - REQUIRE(gp::StringView("abc") == gp::StringView("abc")); - REQUIRE(gp::StringView("abc") != gp::StringView("def")); - REQUIRE_FALSE(gp::StringView("abc") == gp::StringView("ab")); -} - -TEST_CASE("StringView - spaceship operator", "[container][StringView]") -{ - CHECK((gp::StringView("abc") <=> gp::StringView("abd")) == std::strong_ordering::less); - CHECK((gp::StringView("abd") <=> gp::StringView("abc")) == std::strong_ordering::greater); - CHECK((gp::StringView("abc") <=> gp::StringView("abc")) == std::strong_ordering::equal); - CHECK((gp::StringView("ab") <=> gp::StringView("abc")) == std::strong_ordering::less); -} - -TEST_CASE("StringView - startsWith", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.startsWith(gp::StringView("hello"))); - REQUIRE(v.startsWith('h')); - REQUIRE(v.startsWith("hello")); - REQUIRE_FALSE(v.startsWith(gp::StringView("world"))); - REQUIRE(v.startsWith(gp::StringView(""))); -} - -TEST_CASE("StringView - endsWith", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.endsWith(gp::StringView("world"))); - REQUIRE(v.endsWith('d')); - REQUIRE(v.endsWith("world")); - REQUIRE_FALSE(v.endsWith(gp::StringView("hello"))); - REQUIRE(v.endsWith(gp::StringView(""))); -} - -TEST_CASE("StringView - contains", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.contains(gp::StringView("lo wo"))); - REQUIRE(v.contains('w')); - REQUIRE(v.contains("world")); - REQUIRE_FALSE(v.contains(gp::StringView("xyz"))); - REQUIRE(v.contains(gp::StringView(""))); -} - -TEST_CASE("StringView - find substring", "[container][StringView]") -{ - gp::StringView v("hello hello world"); - REQUIRE(v.find(gp::StringView("hello")) == 0); - REQUIRE(v.find(gp::StringView("hello"), 1) == 6); - REQUIRE(v.find(gp::StringView("world")) == 12); - REQUIRE(v.find(gp::StringView("xyz")) == gp::StringView::npos); -} - -TEST_CASE("StringView - find char", "[container][StringView]") -{ - gp::StringView v("abcabc"); - REQUIRE(v.find('a') == 0); - REQUIRE(v.find('a', 1) == 3); - REQUIRE(v.find('z') == gp::StringView::npos); -} - -TEST_CASE("StringView - find empty substring", "[container][StringView]") -{ - gp::StringView v("hello"); - REQUIRE(v.find(gp::StringView("")) == 0); - REQUIRE(v.find(gp::StringView(""), 3) == 3); - REQUIRE(v.find(gp::StringView(""), 5) == 5); - REQUIRE(v.find(gp::StringView(""), 6) == gp::StringView::npos); -} - -TEST_CASE("StringView - find with C string", "[container][StringView]") -{ - gp::StringView v("test string"); - REQUIRE(v.find("string") == 5); - REQUIRE(v.find("string", 6) == gp::StringView::npos); -} - -TEST_CASE("StringView - find with pointer and count", "[container][StringView]") -{ - gp::StringView v("abcdef"); - REQUIRE(v.find("cde_extra", 0, 3) == 2); -} - -TEST_CASE("StringView - rfind substring", "[container][StringView]") -{ - gp::StringView v("hello hello world"); - REQUIRE(v.rfind(gp::StringView("hello")) == 6); - REQUIRE(v.rfind(gp::StringView("hello"), 5) == 0); - REQUIRE(v.rfind(gp::StringView("xyz")) == gp::StringView::npos); -} - -TEST_CASE("StringView - rfind char", "[container][StringView]") -{ - gp::StringView v("abcabc"); - REQUIRE(v.rfind('c') == 5); - REQUIRE(v.rfind('c', 4) == 2); - REQUIRE(v.rfind('z') == gp::StringView::npos); -} - -TEST_CASE("StringView - rfind empty substring", "[container][StringView]") -{ - gp::StringView v("hello"); - REQUIRE(v.rfind(gp::StringView("")) == 5); - REQUIRE(v.rfind(gp::StringView(""), 3) == 3); -} - -TEST_CASE("StringView - rfind on empty view", "[container][StringView]") -{ - gp::StringView v; - REQUIRE(v.rfind('a') == gp::StringView::npos); - REQUIRE(v.rfind(gp::StringView("")) == 0); -} - -TEST_CASE("StringView - findFirstOf", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.findFirstOf(gp::StringView("aeiou")) == 1); - REQUIRE(v.findFirstOf(gp::StringView("xyz")) == gp::StringView::npos); - REQUIRE(v.findFirstOf('o') == 4); - REQUIRE(v.findFirstOf("ow") == 4); -} - -TEST_CASE("StringView - findLastOf", "[container][StringView]") -{ - gp::StringView v("hello world"); - REQUIRE(v.findLastOf(gp::StringView("aeiou")) == 7); - REQUIRE(v.findLastOf(gp::StringView("xyz")) == gp::StringView::npos); - REQUIRE(v.findLastOf('l') == 9); - REQUIRE(v.findLastOf("ld") == 10); -} - -TEST_CASE("StringView - findFirstOf and findLastOf on empty", "[container][StringView]") -{ - gp::StringView v; - REQUIRE(v.findFirstOf(gp::StringView("abc")) == gp::StringView::npos); - REQUIRE(v.findLastOf(gp::StringView("abc")) == gp::StringView::npos); -} - -TEST_CASE("StringView - findFirstNotOf", "[container][StringView]") -{ - gp::StringView v("aaabbbccc"); - REQUIRE(v.findFirstNotOf(gp::StringView("a")) == 3); - REQUIRE(v.findFirstNotOf('a') == 3); - REQUIRE(v.findFirstNotOf(gp::StringView("abc")) == gp::StringView::npos); - REQUIRE(v.findFirstNotOf("ab") == 6); -} - -TEST_CASE("StringView - findLastNotOf", "[container][StringView]") -{ - gp::StringView v("aaabbbccc"); - REQUIRE(v.findLastNotOf(gp::StringView("c")) == 5); - REQUIRE(v.findLastNotOf('c') == 5); - REQUIRE(v.findLastNotOf(gp::StringView("abc")) == gp::StringView::npos); - REQUIRE(v.findLastNotOf("bc") == 2); -} - -TEST_CASE("StringView - findFirstNotOf and findLastNotOf on empty", "[container][StringView]") -{ - gp::StringView v; - REQUIRE(v.findFirstNotOf(gp::StringView("a")) == gp::StringView::npos); - REQUIRE(v.findLastNotOf(gp::StringView("a")) == gp::StringView::npos); -} - -TEST_CASE("StringView - single character view", "[container][StringView]") -{ - gp::StringView v("x"); - REQUIRE(v.size() == 1); - REQUIRE(v.front() == 'x'); - REQUIRE(v.back() == 'x'); - REQUIRE(v.find('x') == 0); - REQUIRE(v.rfind('x') == 0); - REQUIRE(v.startsWith('x')); - REQUIRE(v.endsWith('x')); - REQUIRE(v.contains('x')); -} - -TEST_CASE("StringView - find pattern larger than view", "[container][StringView]") -{ - gp::StringView v("ab"); - REQUIRE(v.find(gp::StringView("abc")) == gp::StringView::npos); - REQUIRE(v.rfind(gp::StringView("abc")) == gp::StringView::npos); -} - -TEST_CASE("StringView - substr with pos == size", "[container][StringView]") -{ - gp::StringView v("hello"); - gp::StringView sub = v.substr(5); - REQUIRE(sub.isEmpty()); -} - -} // namespace gp::tests diff --git a/source/runtime/core/tests/container/Optional.tests.cpp b/source/runtime/core/tests/container/Optional.tests.cpp deleted file mode 100644 index caca940..0000000 --- a/source/runtime/core/tests/container/Optional.tests.cpp +++ /dev/null @@ -1,693 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "container/Optional.hpp" -#include "CoreMinimal.hpp" -#include - -namespace gp::tests -{ - -struct DestroyTracker -{ - Int32* m_count; - - explicit DestroyTracker(Int32& count) - : m_count(&count) - {} - - DestroyTracker(const DestroyTracker&) = default; - DestroyTracker(DestroyTracker&&) noexcept = default; - DestroyTracker& operator=(const DestroyTracker&) = default; - DestroyTracker& operator=(DestroyTracker&&) noexcept = default; - - ~DestroyTracker() - { - ++(*m_count); - } -}; - -struct MoveSpy -{ - Int32 value{ 0 }; - bool moved{ false }; - - MoveSpy() = default; - - explicit MoveSpy(Int32 v) - : value(v) - {} - - MoveSpy(const MoveSpy&) = default; - - MoveSpy(MoveSpy&& other) noexcept - : value(other.value) - , moved(false) - { - other.moved = true; - } - - MoveSpy& operator=(const MoveSpy&) = default; - - MoveSpy& operator=(MoveSpy&& other) noexcept - { - value = other.value; - other.moved = true; - return *this; - } - - bool operator==(const MoveSpy& other) const noexcept - { - return value == other.value; - } - - bool operator!=(const MoveSpy& other) const noexcept - { - return value != other.value; - } -}; - -struct MultiArg -{ - Int32 x{ 0 }; - Int32 y{ 0 }; - Float32 z{ 0.0f }; - - MultiArg(Int32 inX, Int32 inY, Float32 inZ) - : x(inX) - , y(inY) - , z(inZ) - {} - - bool operator==(const MultiArg& other) const noexcept - { - return x == other.x && y == other.y && z == other.z; - } -}; - -TEST_CASE("Optional - Default construction yields empty optional", "[container][Optional]") -{ - const Optional opt; - REQUIRE_FALSE(opt.hasValue()); - REQUIRE_FALSE(static_cast(opt)); -} - -TEST_CASE("Optional - Default construction is noexcept", "[container][Optional]") -{ - STATIC_REQUIRE(noexcept(Optional{})); -} - -TEST_CASE("Optional - gp::nullOpt construction yields empty optional", "[container][Optional]") -{ - const Optional opt(gp::nullOpt); - REQUIRE_FALSE(opt.hasValue()); - REQUIRE_FALSE(static_cast(opt)); -} - -TEST_CASE("Optional - gp::nullOpt construction is noexcept", "[container][Optional]") -{ - STATIC_REQUIRE(noexcept(Optional{ gp::nullOpt })); -} - -TEST_CASE("Optional - Copy-construction from value stores the value", "[container][Optional]") -{ - const Int32 val = 42; - const Optional opt(val); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 42); -} - -TEST_CASE("Optional - Move-construction from value stores the value and moves the source", "[container][Optional]") -{ - MoveSpy src(99); - Optional opt(std::move(src)); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value().value == 99); - REQUIRE(src.moved); -} - -TEST_CASE("Optional - In-place construction from multiple arguments", "[container][Optional]") -{ - Optional opt(10, 20, 3.14f); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value().x == 10); - REQUIRE(opt.value().y == 20); - REQUIRE(opt.value().z == 3.14f); -} - -TEST_CASE("Optional - Copy-construction from non-empty optional copies value", "[container][Optional]") -{ - const Optional src(7); - const Optional opt(src); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 7); - REQUIRE(src.hasValue()); - REQUIRE(src.value() == 7); -} - -TEST_CASE("Optional - Copy-construction from empty optional yields empty optional", "[container][Optional]") -{ - const Optional src; - const Optional opt(src); - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE( - "Optional - Move-construction from non-empty optional transfers value and empties source", "[container][Optional]" -) -{ - Optional src(MoveSpy(55)); - Optional opt(std::move(src)); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value().value == 55); - REQUIRE_FALSE(src.hasValue()); -} - -TEST_CASE("Optional - Move-construction from empty optional yields empty optional", "[container][Optional]") -{ - Optional src; - const Optional opt(std::move(src)); - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE("Optional - Destructor destroys the contained value exactly once", "[container][Optional]") -{ - Int32 destroyCount = 0; - { - Optional opt{ DestroyTracker(destroyCount) }; - destroyCount = 0; - } - REQUIRE(destroyCount == 1); -} - -TEST_CASE("Optional - Destructor of empty optional does not invoke any destructor", "[container][Optional]") -{ - Int32 destroyCount = 0; - { - Optional opt; - } - REQUIRE(destroyCount == 0); -} - -TEST_CASE("Optional - gp::nullOpt assignment to non-empty resets the optional", "[container][Optional]") -{ - Optional opt(42); - opt = gp::nullOpt; - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE("Optional - gp::nullOpt assignment to empty remains empty", "[container][Optional]") -{ - Optional opt; - opt = gp::nullOpt; - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE("Optional - gp::nullOpt assignment destroys the contained value", "[container][Optional]") -{ - Int32 destroyCount = 0; - Optional opt{ DestroyTracker(destroyCount) }; - destroyCount = 0; - opt = gp::nullOpt; - REQUIRE(destroyCount == 1); -} - -TEST_CASE("Optional - Copy-assignment from non-empty to non-empty updates the value", "[container][Optional]") -{ - Optional dst(1); - const Optional src(2); - dst = src; - REQUIRE(dst.hasValue()); - REQUIRE(dst.value() == 2); -} - -TEST_CASE("Optional - Copy-assignment from non-empty to empty constructs the value", "[container][Optional]") -{ - Optional dst; - const Optional src(99); - dst = src; - REQUIRE(dst.hasValue()); - REQUIRE(dst.value() == 99); -} - -TEST_CASE("Optional - Copy-assignment from empty to non-empty resets the destination", "[container][Optional]") -{ - Optional dst(10); - const Optional src; - dst = src; - REQUIRE_FALSE(dst.hasValue()); -} - -TEST_CASE("Optional - Copy-assignment from empty to empty remains empty", "[container][Optional]") -{ - Optional dst; - const Optional src; - dst = src; - REQUIRE_FALSE(dst.hasValue()); -} - -TEST_CASE("Optional - Copy self-assignment is safe for non-empty optional", "[container][Optional]") -{ - Optional opt(7); - opt = opt; - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 7); -} - -TEST_CASE( - "Optional - Move-assignment from non-empty to non-empty updates destination and clears source", - "[container][Optional]" -) -{ - Optional dst(MoveSpy(1)); - Optional src(MoveSpy(2)); - dst = std::move(src); - REQUIRE(dst.hasValue()); - REQUIRE(dst.value().value == 2); - REQUIRE_FALSE(src.hasValue()); -} - -TEST_CASE( - "Optional - Move-assignment from non-empty to empty constructs destination and clears source", - "[container][Optional]" -) -{ - Optional dst; - Optional src(MoveSpy(42)); - dst = std::move(src); - REQUIRE(dst.hasValue()); - REQUIRE(dst.value().value == 42); - REQUIRE_FALSE(src.hasValue()); -} - -TEST_CASE("Optional - Move-assignment from empty to non-empty resets the destination", "[container][Optional]") -{ - Optional dst(MoveSpy(10)); - Optional src; - dst = std::move(src); - REQUIRE_FALSE(dst.hasValue()); -} - -TEST_CASE("Optional - Move self-assignment is safe for non-empty optional", "[container][Optional]") -{ - Optional opt(5); - opt = std::move(opt); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 5); -} - -TEST_CASE("Optional - Value-assignment to empty constructs the value", "[container][Optional]") -{ - Optional opt; - opt = 100; - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 100); -} - -TEST_CASE("Optional - Value-assignment to non-empty updates the value", "[container][Optional]") -{ - Optional opt(5); - opt = 50; - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 50); -} - -TEST_CASE("Optional - operator== two non-empty optionals with equal values returns true", "[container][Optional]") -{ - const Optional a(3); - const Optional b(3); - REQUIRE(a == b); -} - -TEST_CASE("Optional - operator== two non-empty optionals with different values returns false", "[container][Optional]") -{ - const Optional a(3); - const Optional b(4); - REQUIRE_FALSE(a == b); -} - -TEST_CASE("Optional - operator== two empty optionals returns true", "[container][Optional]") -{ - const Optional a; - const Optional b; - REQUIRE(a == b); -} - -TEST_CASE("Optional - operator== empty and non-empty returns false", "[container][Optional]") -{ - const Optional a; - const Optional b(1); - REQUIRE_FALSE(a == b); - REQUIRE_FALSE(b == a); -} - -TEST_CASE("Optional - operator!= two non-empty optionals with different values returns true", "[container][Optional]") -{ - const Optional a(1); - const Optional b(2); - REQUIRE(a != b); -} - -TEST_CASE("Optional - operator!= two non-empty optionals with equal values returns false", "[container][Optional]") -{ - const Optional a(5); - const Optional b(5); - REQUIRE_FALSE(a != b); -} - -TEST_CASE("Optional - operator!= empty and non-empty returns true", "[container][Optional]") -{ - const Optional a; - const Optional b(1); - REQUIRE(a != b); - REQUIRE(b != a); -} - -TEST_CASE("Optional - operator== with gp::nullOpt returns true for empty optional", "[container][Optional]") -{ - const Optional opt; - REQUIRE(opt == gp::nullOpt); -} - -TEST_CASE("Optional - operator== with gp::nullOpt returns false for non-empty optional", "[container][Optional]") -{ - const Optional opt(1); - REQUIRE_FALSE(opt == gp::nullOpt); -} - -TEST_CASE("Optional - operator!= with gp::nullOpt returns false for empty optional", "[container][Optional]") -{ - const Optional opt; - REQUIRE_FALSE(opt != gp::nullOpt); -} - -TEST_CASE("Optional - operator!= with gp::nullOpt returns true for non-empty optional", "[container][Optional]") -{ - const Optional opt(1); - REQUIRE(opt != gp::nullOpt); -} - -TEST_CASE("Optional - operator== with value returns true when value matches", "[container][Optional]") -{ - const Optional opt(42); - REQUIRE(opt == 42); -} - -TEST_CASE("Optional - operator== with value returns false for empty optional", "[container][Optional]") -{ - const Optional opt; - REQUIRE_FALSE(opt == 42); -} - -TEST_CASE("Optional - operator== with value returns false when value differs", "[container][Optional]") -{ - const Optional opt(42); - REQUIRE_FALSE(opt == 43); -} - -TEST_CASE("Optional - operator!= with value returns true for empty optional", "[container][Optional]") -{ - const Optional opt; - REQUIRE(opt != 42); -} - -TEST_CASE("Optional - operator!= with value returns true when values differ", "[container][Optional]") -{ - const Optional opt(1); - REQUIRE(opt != 2); -} - -TEST_CASE("Optional - operator!= with value returns false when value matches", "[container][Optional]") -{ - const Optional opt(7); - REQUIRE_FALSE(opt != 7); -} - -TEST_CASE("Optional - operator* on lvalue returns reference to contained value", "[container][Optional]") -{ - Optional opt(10); - REQUIRE(*opt == 10); -} - -TEST_CASE("Optional - operator* returns a mutable reference", "[container][Optional]") -{ - Optional opt(10); - *opt = 20; - REQUIRE(opt.value() == 20); -} - -TEST_CASE("Optional - operator* on const lvalue returns const reference", "[container][Optional]") -{ - const Optional opt(15); - REQUIRE(*opt == 15); -} - -TEST_CASE("Optional - operator* on rvalue moves out the value", "[container][Optional]") -{ - Optional opt(MoveSpy(77)); - MoveSpy val = *std::move(opt); - REQUIRE(val.value == 77); -} - -TEST_CASE("Optional - operator-> accesses members of the contained value", "[container][Optional]") -{ - Optional opt(MoveSpy(88)); - REQUIRE(opt->value == 88); -} - -TEST_CASE("Optional - operator-> const accesses members of the contained value", "[container][Optional]") -{ - const Optional opt(MoveSpy(88)); - REQUIRE(opt->value == 88); -} - -TEST_CASE("Optional - hasValue returns true when value is present", "[container][Optional]") -{ - const Optional opt(1); - REQUIRE(opt.hasValue()); -} - -TEST_CASE("Optional - hasValue returns false when empty", "[container][Optional]") -{ - const Optional opt; - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE("Optional - hasValue is noexcept", "[container][Optional]") -{ - const Optional opt; - STATIC_REQUIRE(noexcept(opt.hasValue())); -} - -TEST_CASE("Optional - operator bool returns true for non-empty optional", "[container][Optional]") -{ - const Optional opt(1); - REQUIRE(static_cast(opt)); -} - -TEST_CASE("Optional - operator bool returns false for empty optional", "[container][Optional]") -{ - const Optional opt; - REQUIRE_FALSE(static_cast(opt)); -} - -TEST_CASE("Optional - operator bool is noexcept", "[container][Optional]") -{ - const Optional opt; - STATIC_REQUIRE(noexcept(static_cast(opt))); -} - -TEST_CASE("Optional - Value lvalue overload returns reference to stored value", "[container][Optional]") -{ - Optional opt(55); - REQUIRE(opt.value() == 55); - opt.value() = 66; - REQUIRE(opt.value() == 66); -} - -TEST_CASE("Optional - Value const lvalue overload returns const reference", "[container][Optional]") -{ - const Optional opt(55); - REQUIRE(opt.value() == 55); -} - -TEST_CASE("Optional - Value rvalue overload moves out the value", "[container][Optional]") -{ - Optional opt(MoveSpy(33)); - MoveSpy val = std::move(opt).value(); - REQUIRE(val.value == 33); -} - -TEST_CASE("Optional - valueOr returns contained value when present", "[container][Optional]") -{ - const Optional opt(42); - REQUIRE(opt.valueOr(0) == 42); -} - -TEST_CASE("Optional - valueOr returns default when empty", "[container][Optional]") -{ - const Optional opt; - REQUIRE(opt.valueOr(99) == 99); -} - -TEST_CASE("Optional - valueOr rvalue overload returns contained value when present", "[container][Optional]") -{ - Optional opt(42); - REQUIRE(std::move(opt).valueOr(0) == 42); -} - -TEST_CASE("Optional - valueOr rvalue overload returns default when empty", "[container][Optional]") -{ - Optional opt; - REQUIRE(std::move(opt).valueOr(99) == 99); -} - -TEST_CASE("Optional - Reset destroys the contained value and marks optional as empty", "[container][Optional]") -{ - Int32 destroyCount = 0; - Optional opt{ DestroyTracker(destroyCount) }; - destroyCount = 0; - opt.reset(); - REQUIRE(destroyCount == 1); - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE("Optional - Reset on empty optional is a no-op", "[container][Optional]") -{ - Optional opt; - opt.reset(); - REQUIRE_FALSE(opt.hasValue()); -} - -TEST_CASE("Optional - Double Reset does not double-destroy the value", "[container][Optional]") -{ - Int32 destroyCount = 0; - Optional opt{ DestroyTracker(destroyCount) }; - destroyCount = 0; - opt.reset(); - opt.reset(); - REQUIRE(destroyCount == 1); -} - -TEST_CASE("Optional - Emplace constructs a value in-place from multiple arguments", "[container][Optional]") -{ - Optional opt; - opt.emplace(1, 2, 3.0f); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value().x == 1); - REQUIRE(opt.value().y == 2); - REQUIRE(opt.value().z == 3.0f); -} - -TEST_CASE("Optional - Emplace on non-empty destroys the old value first", "[container][Optional]") -{ - Int32 destroyCount = 0; - Optional opt{ DestroyTracker(destroyCount) }; - destroyCount = 0; - opt.emplace(destroyCount); - REQUIRE(destroyCount == 1); -} - -TEST_CASE("Optional - Emplace returns a reference to the newly constructed value", "[container][Optional]") -{ - Optional opt; - Int32& ref = opt.emplace(77); - REQUIRE(ref == 77); - ref = 88; - REQUIRE(opt.value() == 88); -} - -TEST_CASE("Optional - Emplace replaces the existing value", "[container][Optional]") -{ - Optional opt(1); - opt.emplace(99); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 99); -} - -TEST_CASE("Optional - Swap exchanges values of two non-empty optionals", "[container][Optional]") -{ - Optional a(1); - Optional b(2); - a.swap(b); - REQUIRE(a.value() == 2); - REQUIRE(b.value() == 1); -} - -TEST_CASE("Optional - Swap transfers value from non-empty to empty", "[container][Optional]") -{ - Optional a; - Optional b(5); - a.swap(b); - REQUIRE(a.hasValue()); - REQUIRE(a.value() == 5); - REQUIRE_FALSE(b.hasValue()); -} - -TEST_CASE("Optional - Swap transfers value from empty to non-empty", "[container][Optional]") -{ - Optional a(3); - Optional b; - a.swap(b); - REQUIRE_FALSE(a.hasValue()); - REQUIRE(b.hasValue()); - REQUIRE(b.value() == 3); -} - -TEST_CASE("Optional - Swap two empty optionals stays empty", "[container][Optional]") -{ - Optional a; - Optional b; - a.swap(b); - REQUIRE_FALSE(a.hasValue()); - REQUIRE_FALSE(b.hasValue()); -} - -TEST_CASE( - "Optional - Swap preserves both values alive and destroys each exactly once on scope exit", "[container][Optional]" -) -{ - Int32 destroyA = 0; - Int32 destroyB = 0; - { - Optional a{ DestroyTracker(destroyA) }; - Optional b{ DestroyTracker(destroyB) }; - destroyA = 0; - destroyB = 0; - a.swap(b); - destroyA = 0; - destroyB = 0; - } - REQUIRE(destroyA == 1); - REQUIRE(destroyB == 1); -} - -TEST_CASE("Optional - MakeOptional constructs a non-empty optional", "[container][Optional]") -{ - auto opt = gp::makeOptional(42); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value() == 42); -} - -TEST_CASE("Optional - MakeOptional with multiple arguments constructs value in-place", "[container][Optional]") -{ - auto opt = gp::makeOptional(3, 4, 1.5f); - REQUIRE(opt.hasValue()); - REQUIRE(opt.value().x == 3); - REQUIRE(opt.value().y == 4); - REQUIRE(opt.value().z == 1.5f); -} - -TEST_CASE("Optional - Storage alignment is correct for the contained type", "[container][Optional]") -{ - const Optional opt(3.14); - REQUIRE(reinterpret_cast(&opt.value()) % alignof(Float64) == 0); -} - -TEST_CASE("Optional - ValueType alias resolves to the contained type", "[container][Optional]") -{ - STATIC_REQUIRE(std::is_same_v::ValueType, Int32>); -} - -} // namespace gp::tests diff --git a/source/runtime/core/tests/container/Vector.tests.cpp b/source/runtime/core/tests/container/Vector.tests.cpp deleted file mode 100644 index 8efd082..0000000 --- a/source/runtime/core/tests/container/Vector.tests.cpp +++ /dev/null @@ -1,762 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. - -#include "container/Vector.hpp" -#include "memory/allocators/DefaultAllocator.hpp" -#include "memory/allocators/LinearAllocator.hpp" -#include "memory/allocators/PolymorphicAllocator.hpp" -#include -#include - -namespace gp::tests -{ - -struct NonTrivial -{ - int value; - static int constructions; - static int destructions; - - NonTrivial() - : value(0) - { - ++constructions; - } - - explicit NonTrivial(int v) - : value(v) - { - ++constructions; - } - - NonTrivial(const NonTrivial& o) - : value(o.value) - { - ++constructions; - } - - NonTrivial(NonTrivial&& o) noexcept - : value(o.value) - { - o.value = -1; - ++constructions; - } - - ~NonTrivial() - { - ++destructions; - } - - NonTrivial& operator=(const NonTrivial& o) - { - value = o.value; - return *this; - } - - NonTrivial& operator=(NonTrivial&& o) noexcept - { - value = o.value; - o.value = -1; - return *this; - } - - bool operator==(const NonTrivial& o) const - { - return value == o.value; - } -}; - -int NonTrivial::constructions = 0; -int NonTrivial::destructions = 0; - -static void resetNonTrivialCounts() -{ - NonTrivial::constructions = 0; - NonTrivial::destructions = 0; -} - -TEST_CASE("Vector - default construction", "[container][Vector]") -{ - gp::Vector v; - REQUIRE(v.size() == 0); - REQUIRE(v.capacity() == 0); - REQUIRE(v.isEmpty()); - REQUIRE(v.data() == nullptr); -} - -TEST_CASE("Vector - construction with allocator", "[container][Vector]") -{ - gp::memory::PolymorphicAllocator alloc; - gp::Vector v(alloc); - REQUIRE(v.isEmpty()); - REQUIRE(v.getAllocator() == alloc); -} - -TEST_CASE("Vector - count construction with default value", "[container][Vector]") -{ - gp::Vector v(5); - REQUIRE(v.size() == 5); - for (gp::USize i = 0; i < 5; ++i) - { - REQUIRE(v[i] == 0); - } -} - -TEST_CASE("Vector - count construction with fill value", "[container][Vector]") -{ - gp::Vector v(3, 42); - REQUIRE(v.size() == 3); - REQUIRE(v[0] == 42); - REQUIRE(v[1] == 42); - REQUIRE(v[2] == 42); -} - -TEST_CASE("Vector - initializer list construction", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3, 4, 5 }; - REQUIRE(v.size() == 5); - REQUIRE(v[0] == 1); - REQUIRE(v[4] == 5); -} - -TEST_CASE("Vector - iterator range construction", "[container][Vector]") -{ - int arr[] = { 10, 20, 30 }; - gp::Vector v(arr, arr + 3); - REQUIRE(v.size() == 3); - REQUIRE(v[0] == 10); - REQUIRE(v[2] == 30); -} - -TEST_CASE("Vector - zero-count construction", "[container][Vector]") -{ - gp::Vector v(static_cast(0)); - REQUIRE(v.isEmpty()); - REQUIRE(v.data() == nullptr); -} - -TEST_CASE("Vector - copy construction", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - gp::Vector b(a); - REQUIRE(b.size() == 3); - REQUIRE(b[0] == 1); - REQUIRE(b[2] == 3); - REQUIRE(a.data() != b.data()); -} - -TEST_CASE("Vector - move construction", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - int* old_data = a.data(); - gp::Vector b(static_cast&&>(a)); - REQUIRE(b.size() == 3); - REQUIRE(b.data() == old_data); - REQUIRE(a.isEmpty()); - REQUIRE(a.data() == nullptr); -} - -TEST_CASE("Vector - copy assignment", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - gp::Vector b{ 4, 5 }; - b = a; - REQUIRE(b.size() == 3); - REQUIRE(b[0] == 1); -} - -TEST_CASE("Vector - move assignment", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - gp::Vector b{ 4, 5 }; - int* old_data = a.data(); - b = static_cast&&>(a); - REQUIRE(b.size() == 3); - REQUIRE(b.data() == old_data); - REQUIRE(a.isEmpty()); -} - -TEST_CASE("Vector - self-copy assignment", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - a = a; - REQUIRE(a.size() == 3); - REQUIRE(a[0] == 1); -} - -TEST_CASE("Vector - initializer list assignment", "[container][Vector]") -{ - gp::Vector v; - v = { 10, 20, 30 }; - REQUIRE(v.size() == 3); - REQUIRE(v[1] == 20); -} - -TEST_CASE("Vector - assign count and value", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - v.assign(5, 99); - REQUIRE(v.size() == 5); - for (gp::USize i = 0; i < 5; ++i) - { - REQUIRE(v[i] == 99); - } -} - -TEST_CASE("Vector - assign initializer list", "[container][Vector]") -{ - gp::Vector v{ 1 }; - v.assign({ 10, 20, 30 }); - REQUIRE(v.size() == 3); - REQUIRE(v[2] == 30); -} - -TEST_CASE("Vector - at / operator[] / front / back", "[container][Vector]") -{ - gp::Vector v{ 10, 20, 30 }; - REQUIRE(v.at(0) == 10); - REQUIRE(v.at(2) == 30); - REQUIRE(v[1] == 20); - REQUIRE(v.front() == 10); - REQUIRE(v.back() == 30); -} - -TEST_CASE("Vector - data pointer", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - int* p = v.data(); - REQUIRE(p[0] == 1); - REQUIRE(p[2] == 3); -} - -TEST_CASE("Vector - begin / end iteration", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - int sum = 0; - for (auto it = v.begin(); it != v.end(); ++it) - { - sum += *it; - } - REQUIRE(sum == 6); -} - -TEST_CASE("Vector - const iterators", "[container][Vector]") -{ - const gp::Vector v{ 1, 2, 3 }; - int sum = 0; - for (auto it = v.cbegin(); it != v.cend(); ++it) - { - sum += *it; - } - REQUIRE(sum == 6); -} - -TEST_CASE("Vector - reverse iterators", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - REQUIRE(*v.rbegin() == 3); - REQUIRE(*(v.rend() - 1) == 1); -} - -TEST_CASE("Vector - range-for loop", "[container][Vector]") -{ - gp::Vector v{ 10, 20, 30 }; - int sum = 0; - for (int x: v) - { - sum += x; - } - REQUIRE(sum == 60); -} - -TEST_CASE("Vector - reserve", "[container][Vector]") -{ - gp::Vector v; - v.reserve(100); - REQUIRE(v.capacity() >= 100); - REQUIRE(v.size() == 0); -} - -TEST_CASE("Vector - reserve does not shrink", "[container][Vector]") -{ - gp::Vector v; - v.reserve(100); - v.reserve(10); - REQUIRE(v.capacity() >= 100); -} - -TEST_CASE("Vector - shrinkToFit", "[container][Vector]") -{ - gp::Vector v; - v.reserve(100); - v.pushBack(1); - v.pushBack(2); - v.shrinkToFit(); - REQUIRE(v.capacity() == 2); - REQUIRE(v.size() == 2); - REQUIRE(v[0] == 1); -} - -TEST_CASE("Vector - shrinkToFit on empty", "[container][Vector]") -{ - gp::Vector v; - v.reserve(100); - v.shrinkToFit(); - REQUIRE(v.capacity() == 0); - REQUIRE(v.data() == nullptr); -} - -TEST_CASE("Vector - 1.5x growth factor", "[container][Vector]") -{ - gp::Vector v; - v.pushBack(1); - REQUIRE(v.capacity() == 1); - - v.pushBack(2); - REQUIRE(v.capacity() >= 2); - - // After cap=1, next should be 1 + 0 = 1 (min growth to 2 happens from _next_capacity) - // Capacity goes: 0->1->1 (but must fit 2, so realloc to 1.5 rounded) - // Actually: _next_capacity when cap=1 returns 1+0=1, but pushBack calls _grow which - // calls _realloc_exact(1). Then pushBack again triggers _grow again with cap=1 -> 1. - // This is a degenerate case. Let's test from larger capacity. - gp::Vector v2; - v2.reserve(4); - for (int i = 0; i < 5; ++i) - { - v2.pushBack(i); - } - // After 4 elements (cap=4), 5th triggers grow: 4 + 4/2 = 6 - REQUIRE(v2.capacity() == 6); - - for (int i = 5; i < 7; ++i) - { - v2.pushBack(i); - } - // Now at 7 elements, cap=6 triggers grow: 6 + 6/2 = 9 - REQUIRE(v2.capacity() == 9); -} - -TEST_CASE("Vector - pushBack", "[container][Vector]") -{ - gp::Vector v; - for (int i = 0; i < 100; ++i) - { - v.pushBack(i); - } - REQUIRE(v.size() == 100); - for (int i = 0; i < 100; ++i) - { - REQUIRE(v[i] == i); - } -} - -TEST_CASE("Vector - pushBack move", "[container][Vector]") -{ - gp::Vector v; - std::string s = "hello"; - v.pushBack(static_cast(s)); - REQUIRE(v.size() == 1); - REQUIRE(v[0] == "hello"); -} - -TEST_CASE("Vector - emplaceBack", "[container][Vector]") -{ - gp::Vector> v; - auto& ref = v.emplaceBack(1, 2); - REQUIRE(ref.first == 1); - REQUIRE(ref.second == 2); - REQUIRE(v.size() == 1); -} - -TEST_CASE("Vector - popBack", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - v.popBack(); - REQUIRE(v.size() == 2); - REQUIRE(v.back() == 2); -} - -TEST_CASE("Vector - clear", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - gp::USize old_cap = v.capacity(); - v.clear(); - REQUIRE(v.size() == 0); - REQUIRE(v.isEmpty()); - REQUIRE(v.capacity() == old_cap); -} - -TEST_CASE("Vector - insert single element", "[container][Vector]") -{ - gp::Vector v{ 1, 3, 4 }; - auto it = v.insert(v.begin() + 1, 2); - REQUIRE(*it == 2); - REQUIRE(v.size() == 4); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 2); - REQUIRE(v[2] == 3); - REQUIRE(v[3] == 4); -} - -TEST_CASE("Vector - insert at beginning", "[container][Vector]") -{ - gp::Vector v{ 2, 3 }; - v.insert(v.begin(), 1); - REQUIRE(v[0] == 1); - REQUIRE(v.size() == 3); -} - -TEST_CASE("Vector - insert at end", "[container][Vector]") -{ - gp::Vector v{ 1, 2 }; - v.insert(v.end(), 3); - REQUIRE(v.back() == 3); - REQUIRE(v.size() == 3); -} - -TEST_CASE("Vector - insert count copies", "[container][Vector]") -{ - gp::Vector v{ 1, 5 }; - v.insert(v.begin() + 1, 3, 99); - REQUIRE(v.size() == 5); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 99); - REQUIRE(v[2] == 99); - REQUIRE(v[3] == 99); - REQUIRE(v[4] == 5); -} - -TEST_CASE("Vector - insert initializer list", "[container][Vector]") -{ - gp::Vector v{ 1, 5 }; - v.insert(v.begin() + 1, { 2, 3, 4 }); - REQUIRE(v.size() == 5); - for (int i = 0; i < 5; ++i) - { - REQUIRE(v[i] == i + 1); - } -} - -TEST_CASE("Vector - emplace", "[container][Vector]") -{ - gp::Vector> v; - v.emplaceBack(1, 1); - v.emplaceBack(3, 3); - v.emplace(v.begin() + 1, 2, 2); - REQUIRE(v.size() == 3); - REQUIRE(v[1].first == 2); -} - -TEST_CASE("Vector - erase single element", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3, 4 }; - auto it = v.erase(v.begin() + 1); - REQUIRE(*it == 3); - REQUIRE(v.size() == 3); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 3); - REQUIRE(v[2] == 4); -} - -TEST_CASE("Vector - erase range", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3, 4, 5 }; - auto it = v.erase(v.begin() + 1, v.begin() + 4); - REQUIRE(*it == 5); - REQUIRE(v.size() == 2); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 5); -} - -TEST_CASE("Vector - erase empty range is no-op", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3 }; - auto it = v.erase(v.begin() + 1, v.begin() + 1); - REQUIRE(*it == 2); - REQUIRE(v.size() == 3); -} - -TEST_CASE("Vector - resize grow", "[container][Vector]") -{ - gp::Vector v{ 1, 2 }; - v.resize(5); - REQUIRE(v.size() == 5); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 2); - REQUIRE(v[2] == 0); -} - -TEST_CASE("Vector - resize grow with fill value", "[container][Vector]") -{ - gp::Vector v{ 1 }; - v.resize(4, 99); - REQUIRE(v.size() == 4); - REQUIRE(v[0] == 1); - REQUIRE(v[3] == 99); -} - -TEST_CASE("Vector - resize shrink", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 3, 4, 5 }; - v.resize(2); - REQUIRE(v.size() == 2); - REQUIRE(v[1] == 2); -} - -TEST_CASE("Vector - swap", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - gp::Vector b{ 4, 5 }; - a.swap(b); - REQUIRE(a.size() == 2); - REQUIRE(a[0] == 4); - REQUIRE(b.size() == 3); - REQUIRE(b[0] == 1); -} - -TEST_CASE("Vector - equality comparison", "[container][Vector]") -{ - gp::Vector a{ 1, 2, 3 }; - gp::Vector b{ 1, 2, 3 }; - gp::Vector c{ 1, 2, 4 }; - gp::Vector d{ 1, 2 }; - REQUIRE(a == b); - REQUIRE(a != c); - REQUIRE(a != d); -} - -TEST_CASE("Vector - trivial type memcpy reallocation", "[container][Vector]") -{ - static_assert(std::is_trivially_copyable_v, "int should be trivially copyable"); - gp::Vector v; - for (int i = 0; i < 50; ++i) - { - v.pushBack(i); - } - REQUIRE(v.size() == 50); - for (int i = 0; i < 50; ++i) - { - REQUIRE(v[i] == i); - } -} - -TEST_CASE("Vector - trivial type insert shifts via memmove", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 5, 6 }; - v.insert(v.begin() + 2, { 3, 4 }); - REQUIRE(v.size() == 6); - for (int i = 0; i < 6; ++i) - { - REQUIRE(v[i] == i + 1); - } -} - -TEST_CASE("Vector - trivial type erase shifts via memmove", "[container][Vector]") -{ - gp::Vector v{ 1, 2, 99, 98, 3, 4 }; - v.erase(v.begin() + 2, v.begin() + 4); - REQUIRE(v.size() == 4); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 2); - REQUIRE(v[2] == 3); - REQUIRE(v[3] == 4); -} - -TEST_CASE("Vector - non-trivial construction and destruction counts", "[container][Vector]") -{ - resetNonTrivialCounts(); - { - gp::Vector v; - v.pushBack(NonTrivial(1)); - v.pushBack(NonTrivial(2)); - v.pushBack(NonTrivial(3)); - } - REQUIRE(NonTrivial::destructions >= NonTrivial::constructions); -} - -TEST_CASE("Vector - non-trivial erase calls destructor", "[container][Vector]") -{ - resetNonTrivialCounts(); - { - gp::Vector v; - v.emplaceBack(1); - v.emplaceBack(2); - v.emplaceBack(3); - int before = NonTrivial::destructions; - v.erase(v.begin()); - REQUIRE(NonTrivial::destructions > before); - REQUIRE(v.size() == 2); - REQUIRE(v[0].value == 2); - } -} - -TEST_CASE("Vector - non-trivial clear calls destructors", "[container][Vector]") -{ - resetNonTrivialCounts(); - { - gp::Vector v; - v.emplaceBack(1); - v.emplaceBack(2); - v.emplaceBack(3); - int before = NonTrivial::destructions; - v.clear(); - REQUIRE(NonTrivial::destructions == before + 3); - } -} - -TEST_CASE("Vector - copy uses select_on_container_copy_construction", "[container][Vector][allocator]") -{ - // PolymorphicAllocator returns default allocator on copy - alignas(16) gp::UInt8 buf[4096]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator custom(&lin); - - gp::Vector a(custom); - a.pushBack(1); - a.pushBack(2); - - // Copy should use default allocator (per PolymorphicAllocator semantics) - gp::Vector b(a); - REQUIRE(b.size() == 2); - REQUIRE(b[0] == 1); - REQUIRE(b.getAllocator().getResource() == &gp::memory::DefaultAllocator::get()); -} - -TEST_CASE("Vector - move transfers allocator", "[container][Vector][allocator]") -{ - alignas(16) gp::UInt8 buf[4096]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator custom(&lin); - - gp::Vector a(custom); - a.pushBack(1); - - gp::Vector b(static_cast&&>(a)); - REQUIRE(b.getAllocator().getResource() == &lin); - REQUIRE(a.isEmpty()); -} - -TEST_CASE("Vector - move assignment with propagation", "[container][Vector][allocator]") -{ - alignas(16) gp::UInt8 buf[4096]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator custom(&lin); - - gp::Vector a(custom); - a.pushBack(42); - - gp::Vector b; - b = static_cast&&>(a); - REQUIRE(b.getAllocator().getResource() == &lin); - REQUIRE(b.size() == 1); - REQUIRE(b[0] == 42); -} - -TEST_CASE("Vector - custom allocator basic operations", "[container][Vector][allocator]") -{ - alignas(16) gp::UInt8 buf[4096]; - gp::memory::LinearAllocator lin(buf, sizeof(buf)); - gp::memory::PolymorphicAllocator alloc(&lin); - - gp::Vector v(alloc); - for (int i = 0; i < 20; ++i) - { - v.pushBack(i); - } - REQUIRE(v.size() == 20); - for (int i = 0; i < 20; ++i) - { - REQUIRE(v[i] == i); - } - REQUIRE(lin.getAllocatedSize() > 0); -} - -TEST_CASE("Vector - eraseIf", "[container][Vector]") -{ - gp::Vector v = { 1, 2, 3, 4, 5, 6 }; - - SECTION("Removes elements matching the predicate and returns count") - { - auto removedCount = gp::eraseIf( - v, - [](int x) - { - return x % 2 == 0; - } - ); // Remove evens - - REQUIRE(removedCount == 3); - REQUIRE(v.size() == 3); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 3); - REQUIRE(v[2] == 5); - } - - SECTION("Returns 0 and modifies nothing if no elements match") - { - auto removedCount = gp::eraseIf( - v, - [](int x) - { - return x > 10; - } - ); - - REQUIRE(removedCount == 0); - REQUIRE(v.size() == 6); - REQUIRE(v[0] == 1); // Spot check - } - - SECTION("Clears the vector if all elements match") - { - auto removedCount = gp::eraseIf( - v, - [](int) - { - return true; - } - ); - - REQUIRE(removedCount == 6); - REQUIRE(v.isEmpty()); - REQUIRE(v.size() == 0); - } -} - -TEST_CASE("Vector - erase", "[container][Vector]") -{ - gp::Vector v = { 1, 2, 3, 2, 4, 2, 5 }; - - SECTION("Removes all exact matches of a value and returns count") - { - auto removedCount = gp::erase(v, 2); - - REQUIRE(removedCount == 3); - REQUIRE(v.size() == 4); - REQUIRE(v[0] == 1); - REQUIRE(v[1] == 3); - REQUIRE(v[2] == 4); - REQUIRE(v[3] == 5); - } - - SECTION("Returns 0 and modifies nothing if value is not found") - { - auto removedCount = gp::erase(v, 99); - - REQUIRE(removedCount == 0); - REQUIRE(v.size() == 7); - } - - SECTION("Works correctly when the target value is at the boundaries") - { - gp::Vector edgeVector = { 9, 1, 2, 9 }; - auto removedCount = gp::erase(edgeVector, 9); - - REQUIRE(removedCount == 2); - REQUIRE(edgeVector.size() == 2); - REQUIRE(edgeVector[0] == 1); - REQUIRE(edgeVector[1] == 2); - } -} - -} // namespace gp::tests diff --git a/source/runtime/core/tests/math/LinearAlgebra.tests.cpp b/source/runtime/core/tests/math/LinearAlgebra.tests.cpp deleted file mode 100644 index f233d1a..0000000 --- a/source/runtime/core/tests/math/LinearAlgebra.tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "math/LinearAlgebra.hpp" -#include - -namespace gp::math::tests -{ - -TEST_CASE("min - two values (int)", "[math][LinearAlgebra][min]") -{ - REQUIRE(min(3, 5) == 3); - REQUIRE(min(-1, 1) == -1); - REQUIRE(min(0, 0) == 0); -} - -TEST_CASE("min - three values (int)", "[math][LinearAlgebra][min]") -{ - REQUIRE(min(3, 5, 2) == 2); - REQUIRE(min(-1, 1, -2) == -2); - REQUIRE(min(0, 0, 0) == 0); -} - -TEST_CASE("max - two values (int)", "[math][LinearAlgebra][max]") -{ - REQUIRE(max(3, 5) == 5); - REQUIRE(max(-1, 1) == 1); - REQUIRE(max(0, 0) == 0); -} - -TEST_CASE("max - three values (int)", "[math][LinearAlgebra][max]") -{ - REQUIRE(max(3, 5, 2) == 5); - REQUIRE(max(-1, 1, -2) == 1); - REQUIRE(max(0, 0, 0) == 0); -} - -TEST_CASE("clamp (int)", "[math][LinearAlgebra][clamp]") -{ - REQUIRE(clamp(5, 1, 10) == 5); // Within range - REQUIRE(clamp(0, 1, 10) == 1); // Below range - REQUIRE(clamp(15, 1, 10) == 10); // Above range -} - -TEST_CASE("min - two values (float)", "[math][LinearAlgebra][min]") -{ - REQUIRE(min(3.f, 5.f) == 3.f); - REQUIRE(min(-1.f, 1.f) == -1.f); - REQUIRE(min(0.f, 0.f) == 0.f); -} - -TEST_CASE("min - three values (float)", "[math][LinearAlgebra][min]") -{ - REQUIRE(min(3.f, 5.f, 2.f) == 2.f); - REQUIRE(min(-1.f, 1.f, -2.f) == -2.f); - REQUIRE(min(0.f, 0.f, 0.f) == 0.f); -} - -TEST_CASE("max - two values (float)", "[math][LinearAlgebra][max]") -{ - REQUIRE(max(3.f, 5.f) == 5.f); - REQUIRE(max(-1.f, 1.f) == 1.f); - REQUIRE(max(0.f, 0.f) == 0.f); -} - -TEST_CASE("max - three values (float)", "[math][LinearAlgebra][max]") -{ - REQUIRE(max(3.f, 5.f, 2.f) == 5.f); - REQUIRE(max(-1.f, 1.f, -2.f) == 1.f); - REQUIRE(max(0.f, 0.f, 0.f) == 0.f); -} - -TEST_CASE("clamp (float)", "[math][LinearAlgebra][clamp]") -{ - REQUIRE(clamp(5.f, 1.f, 10.f) == 5.f); // Within range - REQUIRE(clamp(0.f, 1.f, 10.f) == 1.f); // Below range - REQUIRE(clamp(15.f, 1.f, 10.f) == 10.f); // Above range -} - -} // namespace gp::math::tests diff --git a/source/runtime/core/tests/memory/allocators/DefaultAllocator.tests.cpp b/source/runtime/core/tests/memory/allocators/DefaultAllocator.tests.cpp deleted file mode 100644 index 5cdfd5e..0000000 --- a/source/runtime/core/tests/memory/allocators/DefaultAllocator.tests.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/allocators/DefaultAllocator.hpp" -#include -#include -#include -#include -#include - -namespace gp::memory::tests -{ - -TEST_CASE("DefaultAllocator - Singleton identity", "[memory][DefaultAllocator]") -{ - // Ensure the allocator is a true singleton and returns the exact same memory address. - auto& allocator1 = DefaultAllocator::get(); - auto& allocator2 = DefaultAllocator::get(); - - REQUIRE(&allocator1 == &allocator2); -} - -TEST_CASE("DefaultAllocator - Basic allocation", "[memory][DefaultAllocator]") -{ - auto& allocator = DefaultAllocator::get(); - constexpr USize allocSize = 256; - - void* ptr = allocator.allocate(allocSize); - REQUIRE(ptr != nullptr); - - // Verify memory is accessible and writable (will segfault/ASAN trigger if invalid) - auto* bytes = static_cast(ptr); - for (USize i = 0; i < allocSize; ++i) - { - bytes[i] = static_cast(i % 256); - } - - // Verify written data remains intact - volatile gp::UInt8 checkSum = bytes[128]; - REQUIRE(checkSum == 128); - - REQUIRE_NOTHROW(allocator.deallocate(ptr, allocSize)); -} - -TEST_CASE("DefaultAllocator - Alignment guarantees", "[memory][DefaultAllocator]") -{ - auto& allocator = DefaultAllocator::get(); - constexpr USize allocSize = 64; - - // Test a spectrum of power-of-two alignments critical for SIMD and cache lines - constexpr std::array alignments = { 8, 16, 32, 64, 128, 256 }; - - for (const USize alignment: alignments) - { - void* ptr = allocator.allocate(allocSize, alignment); - REQUIRE(ptr != nullptr); - - // Verify the hardware address is a multiple of the requested alignment - const auto address = reinterpret_cast(ptr); - REQUIRE((address % alignment) == 0); - - allocator.deallocate(ptr, allocSize); - } -} - -TEST_CASE("DefaultAllocator - Nullptr Handling", "[memory][DefaultAllocator]") -{ - auto& allocator = DefaultAllocator::get(); - - // The deallocate interface must safely ignore nullptr requests. - REQUIRE_NOTHROW(allocator.deallocate(nullptr, 1024)); -} - -TEST_CASE("DefaultAllocator - Debug Name", "[memory][DefaultAllocator]") -{ - const auto& allocator = DefaultAllocator::get(); - - // Using string_view for allocation-free string comparison - REQUIRE(std::string_view(allocator.getDebugName()) == "DefaultAllocator"); -} - -#if GP_BUILD_DEBUG -TEST_CASE("DefaultAllocator - Debug Allocation Statistics", "[memory][DefaultAllocator]") -{ - auto& allocator = DefaultAllocator::get(); - - // Cache initial state to ensure tests run reliably independent of execution order - const auto initialSize = allocator.getAllocatedSize(); - const auto initialCount = allocator.getAllocationCount(); - - void* ptr1 = allocator.allocate(128); - REQUIRE(allocator.getAllocatedSize() == initialSize + 128); - REQUIRE(allocator.getAllocationCount() == initialCount + 1); - - void* ptr2 = allocator.allocate(256); - REQUIRE(allocator.getAllocatedSize() == initialSize + 128 + 256); - REQUIRE(allocator.getAllocationCount() == initialCount + 2); - - allocator.deallocate(ptr1, 128); - REQUIRE(allocator.getAllocatedSize() == initialSize + 256); - REQUIRE(allocator.getAllocationCount() == initialCount + 1); - - // Nullptr deallocation should strictly NOT modify statistics - allocator.deallocate(nullptr, 512); - REQUIRE(allocator.getAllocatedSize() == initialSize + 256); - REQUIRE(allocator.getAllocationCount() == initialCount + 1); - - allocator.deallocate(ptr2, 256); - REQUIRE(allocator.getAllocatedSize() == initialSize); - REQUIRE(allocator.getAllocationCount() == initialCount); -} -#endif // GP_BUILD_DEBUG - -TEST_CASE("DefaultAllocator - Multithreaded Contention", "[memory][DefaultAllocator]") -{ - // Validates the class comment: "Thread-safe by virtue of OS-level guarantees on malloc/free." - auto& allocator = DefaultAllocator::get(); - - constexpr USize numThreads = 8; - constexpr USize allocationsPerThread = 5000; - constexpr USize allocSize = 32; - -#if GP_BUILD_DEBUG - const auto initialSize = allocator.getAllocatedSize(); - const auto initialCount = allocator.getAllocationCount(); -#endif - - auto worker = [&allocator]() - { - std::vector ptrs; - ptrs.reserve(allocationsPerThread); - - // Heavy allocation phase - for (USize i = 0; i < allocationsPerThread; ++i) - { - ptrs.push_back(allocator.allocate(allocSize)); - } - - // Deallocation phase - for (void* ptr: ptrs) - { - allocator.deallocate(ptr, allocSize); - } - }; - - std::vector threads; - threads.reserve(numThreads); - - for (USize i = 0; i < numThreads; ++i) - { - threads.emplace_back(worker); - } - - for (auto& t: threads) - { - t.join(); - } - - // Ensure atomic counters are perfectly resolved after high contention -#if GP_BUILD_DEBUG - REQUIRE(allocator.getAllocatedSize() == initialSize); - REQUIRE(allocator.getAllocationCount() == initialCount); -#endif -} - -} // namespace gp::memory::tests diff --git a/source/runtime/core/tests/memory/ownership/RefCountPtr.tests.cpp b/source/runtime/core/tests/memory/ownership/RefCountPtr.tests.cpp deleted file mode 100644 index 13d0c2b..0000000 --- a/source/runtime/core/tests/memory/ownership/RefCountPtr.tests.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/ownership/RefCountPtr.hpp" -#include -#include -#include - -namespace gp::tests -{ - -namespace -{ - -/// @brief GP-native refcounted object exposing addRef/release (lowerCamelCase). -class GpRefCounted -{ -public: - static inline std::atomic s_aliveCount{ 0 }; - - GpRefCounted() noexcept - { - s_aliveCount.fetch_add(1, std::memory_order_relaxed); - } - - virtual ~GpRefCounted() noexcept - { - s_aliveCount.fetch_sub(1, std::memory_order_relaxed); - } - - void addRef() noexcept - { - m_count.fetch_add(1, std::memory_order_relaxed); - } - - void release() noexcept - { - if (m_count.fetch_sub(1, std::memory_order_acq_rel) == 1) - { - delete this; - } - } - - gp::Int32 getRefCount() const noexcept - { - return m_count.load(std::memory_order_acquire); - } - -private: - std::atomic m_count{ 1 }; -}; - -class DerivedGpRefCounted : public GpRefCounted -{ -public: - gp::Int32 identifier{ 42 }; -}; - -} // namespace - -TEST_CASE("RefCountPtr - Size guarantee", "[memory][RefCountPtr]") -{ - STATIC_REQUIRE(sizeof(gp::RefCountPtr) == sizeof(void*)); -} - -TEST_CASE("RefCountPtr - Concept accepts both naming conventions", "[memory][RefCountPtr]") -{ - STATIC_REQUIRE(gp::IsRefCounted); - STATIC_REQUIRE_FALSE(gp::IsRefCounted); -} - -TEST_CASE("RefCountPtr - Default construction is empty", "[memory][RefCountPtr]") -{ - gp::RefCountPtr p; - REQUIRE_FALSE(static_cast(p)); - REQUIRE(p.get() == nullptr); - REQUIRE(p == nullptr); -} - -TEST_CASE("RefCountPtr - Explicit construction increments count", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* raw = new GpRefCounted(); - REQUIRE(raw->getRefCount() == 1); - { - gp::RefCountPtr p(raw); - REQUIRE(raw->getRefCount() == 2); - } - REQUIRE(raw->getRefCount() == 1); - raw->release(); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - attach adopts without AddRef", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* raw = new GpRefCounted(); - REQUIRE(raw->getRefCount() == 1); - - gp::RefCountPtr p(raw, gp::RefCountPtr::attachT); - REQUIRE(raw->getRefCount() == 1); // no bump - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Copy construction shares ownership", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* raw = new GpRefCounted(); - gp::RefCountPtr a(raw, gp::RefCountPtr::attachT); - { - gp::RefCountPtr b(a); - REQUIRE(raw->getRefCount() == 2); - } - REQUIRE(raw->getRefCount() == 1); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Move construction transfers without bump", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* raw = new GpRefCounted(); - gp::RefCountPtr a(raw, gp::RefCountPtr::attachT); - gp::RefCountPtr b(std::move(a)); - REQUIRE(raw->getRefCount() == 1); - REQUIRE(a.get() == nullptr); - REQUIRE(b.get() == raw); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Copy assignment balances old and new refs", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* rawA = new GpRefCounted(); - auto* rawB = new GpRefCounted(); - gp::RefCountPtr a(rawA, gp::RefCountPtr::attachT); - gp::RefCountPtr b(rawB, gp::RefCountPtr::attachT); - REQUIRE(GpRefCounted::s_aliveCount == 2); - - b = a; - REQUIRE(GpRefCounted::s_aliveCount == 1); // rawB deleted - REQUIRE(rawA->getRefCount() == 2); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Move assignment", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* rawA = new GpRefCounted(); - auto* rawB = new GpRefCounted(); - gp::RefCountPtr a(rawA, gp::RefCountPtr::attachT); - gp::RefCountPtr b(rawB, gp::RefCountPtr::attachT); - - b = std::move(a); - REQUIRE(GpRefCounted::s_aliveCount == 1); - REQUIRE(b.get() == rawA); - REQUIRE(a.get() == nullptr); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - reset / detach", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* raw = new GpRefCounted(); - gp::RefCountPtr p(raw, gp::RefCountPtr::attachT); - - GpRefCounted* detached = p.detach(); - REQUIRE(p.get() == nullptr); - REQUIRE(detached == raw); - REQUIRE(raw->getRefCount() == 1); - raw->release(); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); - - { - auto* raw = new GpRefCounted(); - gp::RefCountPtr p(raw, gp::RefCountPtr::attachT); - p.reset(); - REQUIRE_FALSE(p); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - getAddressOf resets and exposes slot", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - gp::RefCountPtr p(new GpRefCounted(), gp::RefCountPtr::attachT); - GpRefCounted** slot = p.getAddressOf(); - REQUIRE(p.get() == nullptr); - - // Simulate a COM-style factory filling the slot. - *slot = new GpRefCounted(); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Polymorphic conversion", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - gp::RefCountPtr d( - new DerivedGpRefCounted(), gp::RefCountPtr::attachT - ); - gp::RefCountPtr b(d); - REQUIRE(b.get() == d.get()); - REQUIRE(d->getRefCount() == 2); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Nullptr assignment", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - gp::RefCountPtr p(new GpRefCounted(), gp::RefCountPtr::attachT); - p = nullptr; - REQUIRE_FALSE(p); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -TEST_CASE("RefCountPtr - Equality comparisons", "[memory][RefCountPtr]") -{ - GpRefCounted::s_aliveCount = 0; - { - auto* raw = new GpRefCounted(); - gp::RefCountPtr a(raw, gp::RefCountPtr::attachT); - gp::RefCountPtr b(a); - gp::RefCountPtr empty; - - REQUIRE(a == b); - REQUIRE_FALSE(a != b); - REQUIRE(empty == nullptr); - REQUIRE(a != nullptr); - REQUIRE(a != empty); - } - REQUIRE(GpRefCounted::s_aliveCount == 0); -} - -} // namespace gp::tests diff --git a/source/runtime/core/tests/memory/ownership/UniquePtr.tests.cpp b/source/runtime/core/tests/memory/ownership/UniquePtr.tests.cpp deleted file mode 100644 index 91b9947..0000000 --- a/source/runtime/core/tests/memory/ownership/UniquePtr.tests.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#include "memory/ownership/UniquePtr.hpp" -#include -#include - -namespace gp::tests -{ - -namespace -{ - -/// @brief Tracks construction and destruction for lifetime verification. -struct LifetimeProbe -{ - static inline gp::Int32 s_aliveCount = 0; - gp::Int32 value{ 0 }; - - LifetimeProbe() noexcept - { - ++s_aliveCount; - } - - explicit LifetimeProbe(gp::Int32 v) noexcept - : value(v) - { - ++s_aliveCount; - } - - LifetimeProbe(const LifetimeProbe& other) noexcept - : value(other.value) - { - ++s_aliveCount; - } - - LifetimeProbe(LifetimeProbe&& other) noexcept - : value(other.value) - { - ++s_aliveCount; - } - - ~LifetimeProbe() noexcept - { - --s_aliveCount; - } - - LifetimeProbe& operator=(const LifetimeProbe&) noexcept = default; - LifetimeProbe& operator=(LifetimeProbe&&) noexcept = default; -}; - -struct Base -{ - virtual ~Base() noexcept = default; - - virtual gp::Int32 tag() const noexcept - { - return 1; - } -}; - -struct Derived : Base -{ - gp::Int32 tag() const noexcept override - { - return 2; - } -}; - -} // namespace - -TEST_CASE("UniquePtr - Size guarantee", "[memory][UniquePtr]") -{ - // The core contract: zero overhead with stateless deleter. - STATIC_REQUIRE(sizeof(gp::UniquePtr) == sizeof(int*)); - STATIC_REQUIRE(sizeof(gp::UniquePtr) == sizeof(void*)); -} - -TEST_CASE("UniquePtr - Default construction is empty", "[memory][UniquePtr]") -{ - gp::UniquePtr p; - REQUIRE_FALSE(static_cast(p)); - REQUIRE(p.get() == nullptr); - REQUIRE(p == nullptr); -} - -TEST_CASE("UniquePtr - Nullptr construction", "[memory][UniquePtr]") -{ - gp::UniquePtr p{ nullptr }; - REQUIRE(p.get() == nullptr); - REQUIRE(nullptr == p); -} - -TEST_CASE("UniquePtr - makeUnique constructs with arguments", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - { - auto p = gp::makeUnique(42); - REQUIRE(p); - REQUIRE(p->value == 42); - REQUIRE((*p).value == 42); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - } - REQUIRE(LifetimeProbe::s_aliveCount == 0); -} - -TEST_CASE("UniquePtr - Destructor destroys the object", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - { - auto p = gp::makeUnique(); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - } - REQUIRE(LifetimeProbe::s_aliveCount == 0); -} - -TEST_CASE("UniquePtr - Move construction transfers ownership", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - auto a = gp::makeUnique(7); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - const auto* raw = a.get(); - - gp::UniquePtr b(std::move(a)); - REQUIRE(a.get() == nullptr); - REQUIRE(b.get() == raw); - REQUIRE(b->value == 7); - REQUIRE(LifetimeProbe::s_aliveCount == 1); -} - -TEST_CASE("UniquePtr - Move assignment destroys previous owner", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - auto a = gp::makeUnique(1); - auto b = gp::makeUnique(2); - REQUIRE(LifetimeProbe::s_aliveCount == 2); - - b = std::move(a); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - REQUIRE(b->value == 1); - REQUIRE(a.get() == nullptr); -} - -TEST_CASE("UniquePtr - release relinquishes ownership without destruction", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - auto p = gp::makeUnique(99); - LifetimeProbe* raw = p.release(); - REQUIRE(p.get() == nullptr); - REQUIRE(raw != nullptr); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - - // Manually re-adopt and destroy via reset to keep the allocator account balanced. - gp::UniquePtr rewrapped(raw); - rewrapped.reset(); - REQUIRE(LifetimeProbe::s_aliveCount == 0); -} - -TEST_CASE("UniquePtr - reset replaces the owned pointer", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - auto p = gp::makeUnique(1); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - - p.reset(); - REQUIRE_FALSE(p); - REQUIRE(LifetimeProbe::s_aliveCount == 0); - - auto q = gp::makeUnique(2); - REQUIRE(LifetimeProbe::s_aliveCount == 1); - q.reset(nullptr); - REQUIRE(LifetimeProbe::s_aliveCount == 0); -} - -TEST_CASE("UniquePtr - swap exchanges two pointers", "[memory][UniquePtr]") -{ - auto a = gp::makeUnique(1); - auto b = gp::makeUnique(2); - const auto* rawA = a.get(); - const auto* rawB = b.get(); - - a.swap(b); - REQUIRE(a.get() == rawB); - REQUIRE(b.get() == rawA); - REQUIRE(a->value == 2); - REQUIRE(b->value == 1); - - gp::swap(a, b); - REQUIRE(a.get() == rawA); - REQUIRE(b.get() == rawB); -} - -TEST_CASE("UniquePtr - Nullptr assignment resets", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - auto p = gp::makeUnique(); - p = nullptr; - REQUIRE_FALSE(p); - REQUIRE(LifetimeProbe::s_aliveCount == 0); -} - -TEST_CASE("UniquePtr - Polymorphic conversion", "[memory][UniquePtr]") -{ - gp::UniquePtr d = gp::makeUnique(); - gp::UniquePtr b(std::move(d)); - REQUIRE(d.get() == nullptr); - REQUIRE(b); - REQUIRE(b->tag() == 2); -} - -TEST_CASE("UniquePtr - Equality comparisons", "[memory][UniquePtr]") -{ - gp::UniquePtr empty; - auto p = gp::makeUnique(5); - - REQUIRE(empty == nullptr); - REQUIRE(nullptr == empty); - REQUIRE(p != nullptr); - REQUIRE(nullptr != p); - REQUIRE(p != empty); -} - -TEST_CASE("UniquePtr - Self-move assignment is safe", "[memory][UniquePtr]") -{ - LifetimeProbe::s_aliveCount = 0; - auto p = gp::makeUnique(11); - - // Use a reference to opaque the compiler's view of self-assignment; this is intentional to - // exercise the guard inside the move assignment operator. - auto& ref = p; - p = std::move(ref); - - REQUIRE(p); - REQUIRE(p->value == 11); - REQUIRE(LifetimeProbe::s_aliveCount == 1); -} - -} // namespace gp::tests diff --git a/source/runtime/docs/_category_.json b/source/runtime/docs/_category_.json deleted file mode 100644 index a8d245d..0000000 --- a/source/runtime/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Runtime" -} diff --git a/source/runtime/engine/.gitignore b/source/runtime/engine/.gitignore index 21f2f1e..e69de29 100644 --- a/source/runtime/engine/.gitignore +++ b/source/runtime/engine/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/animation directory diff --git a/source/runtime/engine/CMakeLists.txt b/source/runtime/engine/CMakeLists.txt index 5f888e2..ee96660 100644 --- a/source/runtime/engine/CMakeLists.txt +++ b/source/runtime/engine/CMakeLists.txt @@ -5,5 +5,5 @@ include(gp-build-tool) gpStartModule(engine) - gpAddPublicDependency(core) + gpAddDependency(PUBLIC core) gpEndModule() diff --git a/source/runtime/engine/docs/_category_.json b/source/runtime/engine/docs/_category_.json deleted file mode 100644 index 4820b20..0000000 --- a/source/runtime/engine/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Engine" -} diff --git a/source/runtime/hal/.gitignore b/source/runtime/hal/.gitignore deleted file mode 100644 index 3975f65..0000000 --- a/source/runtime/hal/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/hal directory diff --git a/source/runtime/hal/CMakeLists.txt b/source/runtime/hal/CMakeLists.txt deleted file mode 100644 index 21d0d27..0000000 --- a/source/runtime/hal/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpStartModule(hal) - gpAddPublicDependency(core) - - if (NOT WIN32) - gpTargetExcludeDirectory("windows") - endif() - - if (NOT UNIX OR APPLE) - gpTargetExcludeDirectory("linux") - endif() - - if (NOT APPLE) - gpTargetExcludeDirectory("macos") - endif() - - gpAddPrivateDependency(SDL3::SDL3-static) -gpEndModule() diff --git a/source/runtime/hal/docs/README.md b/source/runtime/hal/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/hal/docs/_category_.json b/source/runtime/hal/docs/_category_.json deleted file mode 100644 index f2f1865..0000000 --- a/source/runtime/hal/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Hardware Abstraction Layer (HAL)" -} diff --git a/source/runtime/hal/public/window/CursorEnums.hpp b/source/runtime/hal/public/window/CursorEnums.hpp deleted file mode 100644 index c0c0ae9..0000000 --- a/source/runtime/hal/public/window/CursorEnums.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" - -namespace gp -{ - -/// @brief Defines how the system cursor behaves and interacts with the window. -enum class CursorMode : gp::UInt8 -{ - /// @brief Standard behavior: Cursor is visible and moves freely. - Normal, - - /// @brief The cursor is hidden when over the window client area but functions normally. - Hidden, - - /// @brief Cursor is hidden, locked to the window center, and provides unlimited relative motion. - /// @note Essential for FPS games and 3D camera control. - Locked, - - /// @brief The cursor is visible but cannot leave the window boundaries. - /// @note Common in RTS games to allow for edge-scrolling without clicking outside the game. - Confined -}; - -/// @brief Defines the visual icon used for the system cursor. -enum class CursorShape : gp::UInt8 -{ - /// @brief The standard OS arrow. - Arrow, - - /// @brief A text input "I-Beam" cursor. - IBeam, - - /// @brief A crosshair icon, often used for precision tools. - Crosshair, - - /// @brief A hand icon, typically used for clicking links or grabbing objects. - Hand, - - /// @brief Horizontal resize arrows (West-East). - ResizeEW, - - /// @brief Vertical resize arrows (North-South). - ResizeNS, - - /// @brief Diagonal resize arrows (NorthWest-SouthEast). - ResizeNWSE, - - /// @brief Diagonal resize arrows (NorthEast-SouthWest). - ResizeNESW, - - /// @brief Four-way movement arrows. - ResizeAll, - - /// @brief A circle with a slash or "blocked" icon. - NotAllowed, - - /// @brief The "Waiting" or "Busy" spinning icon. - Wait -}; - -} // namespace gp diff --git a/source/runtime/hal/public/window/Window.hpp b/source/runtime/hal/public/window/Window.hpp deleted file mode 100644 index d9c6a4e..0000000 --- a/source/runtime/hal/public/window/Window.hpp +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "window/WindowDesc.hpp" -#include "window/WindowEnums.hpp" -#include "window/WindowTypes.hpp" - -namespace gp::hal -{ - -/// @section Forward declarations - -class Display; - -/// @brief Interface for platform-agnostic window management. -class Window -{ -protected: - -public: - /// @brief Virtual destructor to ensure proper cleanup in derived classes. - virtual ~Window() = default; - -public: - /// @brief Checks if the window is currently open and has not been closed by the user or the application. - /// @return True if the window is open, false if it has been closed. - GP_NODISCARD virtual bool isOpen() const noexcept = 0; - - /// @brief Checks if the window is currently valid and can be interacted with. - /// @return True if the window is valid, false if it is in an invalid state (e.g., failed to initialize). - GP_NODISCARD virtual bool isValid() const noexcept = 0; - - /// @brief Checks if the window is currently active (focused and receiving input). - /// @return True if the window is active, false otherwise. - GP_NODISCARD virtual bool isActive() const noexcept = 0; - - /// @brief Checks if the window is currently focused (has input focus). - /// @return True if the window is focused, false otherwise. - GP_NODISCARD virtual bool isFocused() const noexcept = 0; - - /// @brief Checks if the window is currently minimized (iconified). - /// @return True if the window is minimized, false otherwise. - GP_NODISCARD virtual bool isMinimized() const noexcept = 0; - - /// @brief Checks if the window is currently maximized. - /// @return True if the window is maximized, false otherwise. - GP_NODISCARD virtual bool isMaximized() const noexcept = 0; - - /// @brief Checks if the window is resizable by the user. - /// @return True if the window is resizable, false otherwise. - GP_NODISCARD virtual bool isResizable() const noexcept = 0; - - /// @brief Checks if the window is currently in fullscreen mode. - /// @return True if the window is in fullscreen mode, false otherwise. - GP_NODISCARD virtual bool isFullscreen() const noexcept = 0; - - /// @brief Checks if the window is currently in borderless mode. - /// @return True if the window is in borderless mode, false otherwise. - GP_NODISCARD virtual bool isBorderless() const noexcept = 0; - - /// @brief Checks if the window is transparent (allows underlying windows to show through). - /// @return True if the window is transparent, false otherwise. - GP_NODISCARD virtual bool isTransparent() const noexcept = 0; - - /// @brief Checks if the window is set to always be on top of other windows. - /// @return True if the window is always on top, false otherwise. - GP_NODISCARD virtual bool isAlwaysOnTop() const noexcept = 0; - - /// @brief Checks if the window is currently hovered by the mouse cursor. - /// @return True if the window is hovered, false otherwise. - GP_NODISCARD virtual bool isHovered() const noexcept = 0; - - /// @brief Checks if the window is currently visible to the user (not minimized or hidden). - /// @return True if the window is visible, false otherwise. - GP_NODISCARD virtual bool isVisible() const noexcept = 0; - - /// @brief Checks if the window is currently hidden from the user (minimized or explicitly hidden). - /// @return True if the window is hidden, false otherwise. - GP_NODISCARD virtual bool isHidden() const noexcept = 0; - - /// @brief Checks if the window has vertical synchronization (VSync) enabled for buffer swapping. - /// @return True if VSync is enabled, false otherwise. - GP_NODISCARD virtual bool isVSyncEnabled() const noexcept = 0; - - /// @brief Checks if the window is using a high-DPI backbuffer for rendering on supported displays. - /// @return True if high-DPI mode is enabled, false otherwise. - GP_NODISCARD virtual bool isHighDPI() const noexcept = 0; - - /// @brief Checks if the window has input focus grabbed. - /// @return True if the window has input focus grabbed, false otherwise. - GP_NODISCARD virtual bool isInputGrabbed() const noexcept = 0; - - /// @brief Checks if the window has mouse input grabbed. - /// @return True if the window has mouse input grabbed, false otherwise. - GP_NODISCARD virtual bool isMouseGrabbed() const noexcept = 0; - - /// @brief Checks if the window has keyboard input grabbed. - /// @return True if the window has keyboard input grabbed, false otherwise. - GP_NODISCARD virtual bool isKeyboardGrabbed() const noexcept = 0; - - /// @brief Checks if the system cursor is currently visible when over the window. - /// @return True if the cursor is visible, false otherwise. - GP_NODISCARD virtual bool isCursorVisible() const noexcept = 0; - - /// @brief Checks if the system cursor is currently hidden when over the window. - /// @return True if the cursor is hidden, false otherwise. - GP_NODISCARD virtual bool isCursorHidden() const noexcept = 0; - - /// @brief Checks if the system cursor is currently confined to the window's client area. - /// @return True if the cursor is confined, false otherwise. - GP_NODISCARD virtual bool isCursorConfined() const noexcept = 0; - - /// @brief Checks if the window is currently occluded (completely covered by other windows or off-screen). - /// @return True if the window is occluded, false otherwise. - GP_NODISCARD virtual bool isOccluded() const noexcept = 0; - - /// @brief Get the current position of the window's top-left corner in screen coordinates. - /// @return The current position of the window's top-left corner in screen coordinates. - /// @see getFullPosition() for the position of the entire window including non-client areas. - GP_NODISCARD virtual Point2D getPosition() const noexcept = 0; - - /// @brief Get the current position of the entire window including non-client areas in screen coordinates. - /// @return The current position of the entire window including non-client areas in screen coordinates. - /// @see getPosition() for the position of the client area (drawable region). - GP_NODISCARD virtual Point2D getFullPosition() const noexcept = 0; - - /// @brief Get the current size of the window's client area (drawable region) in pixels. - /// @return The current size of the window's client area (drawable region) in pixels. - /// @see getFullSize() for the total window size including non-client areas. - GP_NODISCARD virtual Extent2D getSize() const noexcept = 0; - - /// @brief Get the current size of the entire window including non-client areas in pixels. - /// @return The current size of the entire window including non-client areas in pixels. - /// @see getSize() for the size of the client area (drawable region). - GP_NODISCARD virtual Extent2D getFullSize() const noexcept = 0; - - /// @brief Get the current size of the framebuffer or backbuffer used for rendering, which may differ from the - /// window's client area size on high-DPI displays. - /// @return The current size of the framebuffer or backbuffer used for rendering. - /// @see getSize() for the size of the client area (drawable region). - GP_NODISCARD virtual Extent2D getFramebufferSize() const noexcept = 0; - - /// @brief Get the minimum size constraints of the window's client area (drawable region) in pixels. - /// @return The minimum size constraints of the window's client area (drawable region) in pixels. - /// @see getMaximumSize() for the maximum size constraints of the window. - GP_NODISCARD virtual Extent2D getMinimumSize() const noexcept = 0; - - /// @brief Get the maximum size constraints of the window's client area (drawable region) in pixels. - /// @return The maximum size constraints of the window's client area (drawable region) in pixels. - /// @see getMinimumSize() for the minimum size constraints of the window. - GP_NODISCARD virtual Extent2D getMaximumSize() const noexcept = 0; - - /// @brief Gets a pointer to the underlying native window handle or object. The actual type and meaning of this - /// handle is platform-specific. It may be used for advanced operations that are not covered by this - /// interface, but the caller must know the expected type and semantics of the handle for the specific - /// platform. This may return nullptr if no native handle is available. - /// @return A pointer to the underlying native window handle or object, or nullptr if no native handle is available. - GP_NODISCARD virtual void* getNativeHandle() const noexcept = 0; - - /// @brief Gets a pointer to the Display that the window is currently associated with. This may return nullptr if - /// the window is not currently associated with any display. The returned Display pointer should not be owned - /// or deleted by the caller, - /// @return A pointer to the Display that the window is currently associated with, or nullptr if the window is not - /// associated with any display. - GP_NODISCARD virtual const Display* getCurrentDisplay() const noexcept = 0; - - /// @brief Sets the position of the window's top-left corner in screen coordinates. - /// @param[in] position The new position of the window's top-left corner in screen coordinates. - virtual void setPosition(const Point2D& position) noexcept = 0; - - /// @brief Sets the position of the window's top-left corner in screen coordinates. - /// @param[in] x The new X coordinate of the window's top-left corner in screen coordinates. - /// @param[in] y The new Y coordinate of the window's top-left corner in screen coordinates. - virtual void setPosition(const Int32 x, const Int32 y) noexcept = 0; - - /// @brief Sets the size of the window's client area (drawable region) in pixels. - /// @param[in] size The new size of the window's client area (drawable region) in pixels. - virtual void setSize(const Extent2D& size) noexcept = 0; - - /// @brief Sets the size of the window's client area (drawable region) in pixels. - /// @param[in] width The new width of the window's client area (drawable region) in pixels. - /// @param[in] height The new height of the window's client area (drawable region) in pixels. - virtual void setSize(const UInt32 width, const UInt32 height) noexcept = 0; - - /// @brief Sets the size of the entire window including non-client areas in pixels. - /// @param[in] size The new size of the entire window including non-client areas in pixels. - virtual void setFullSize(const Extent2D& size) noexcept = 0; - - /// @brief Sets the size of the entire window including non-client areas in pixels. - /// @param[in] width The new width of the entire window including non-client areas in pixels. - /// @param[in] height The new height of the entire window including non-client areas in pixels. - virtual void setFullSize(const UInt32 width, const UInt32 height) noexcept = 0; - - /// @brief Set the minimum and maximum size constraints of the window's client area (drawable region) in pixels. The - /// window will not be resizable to sizes outside of these constraints. - /// @param[in] minimum The minimum size constraints of the window's client area (drawable region) in pixels. - /// @param[in] maximum The maximum size constraints of the window's client area (drawable region) in pixels. - virtual void setSizeLimits(const Extent2D& minimum, const Extent2D& maximum) noexcept = 0; - - /// @brief Set the minimum size constraints of the window's client area (drawable region) in pixels. The window will - /// not be resizable to sizes smaller than these constraints. - /// @param[in] size The minimum size constraint of the window's client area (drawable region) in pixels. - virtual void setMinimumSize(const Extent2D& size) noexcept = 0; - - /// @brief Set the minimum size constraints of the window's client area (drawable region) in pixels. The window will - /// not be resizable to sizes smaller than these constraints. - /// @param[in] width The minimum width constraint of the window's client area (drawable region) in pixels. - /// @param[in] height The minimum height constraint of the window's client area (drawable region) in pixels. - virtual void setMinimumSize(const UInt32 width, const UInt32 height) noexcept = 0; - - /// @brief Set the maximum size constraints of the window's client area (drawable region) in pixels. The window will - /// not be resizable to sizes larger than these constraints. - /// @param[in] size The maximum size constraint of the window's client area (drawable region) in pixels. - virtual void setMaximumSize(const Extent2D& size) noexcept = 0; - - /// @brief Set the maximum size constraints of the window's client area (drawable region) in pixels. The window will - /// not be resizable to sizes larger than these constraints. - /// @param[in] width The maximum width constraint of the window's client area (drawable region) in pixels. - /// @param[in] height The maximum height constraint of the window's client area (drawable region) in pixels. - virtual void setMaximumSize(const UInt32 width, const UInt32 height) noexcept = 0; - - /// @brief Opens the window and makes it ready for use. This may involve creating the underlying native window - /// resources and making the window visible on the screen. If the window is already open, this function may - /// have no effect or may reset the window state depending on the implementation. - virtual void open() = 0; - - /// @brief Closes the window and releases any associated resources. After calling this function, the window should - /// no longer be - /// considered valid or open. If the window is already closed, this function may have no effect. - /// @see requestClose() for requesting the window to close without immediately destroying it, allowing for cleanup - /// or user confirmation. - virtual void close() = 0; - - /// @brief Requests the window to close, which may trigger a close event that can be handled by the application. - /// This allows the application to perform any necessary cleanup or prompt the user for confirmation before - /// the window is actually closed. The window may not close immediately after this call, and the application - /// can choose to ignore the close request if desired. - virtual void requestClose() = 0; - - /// @brief Shows the window if it is currently hidden. - virtual void show() = 0; - - /// @brief Hides the window if it is currently visible. - virtual void hide() = 0; - - /// @brief Minimizes the window if it is currently not minimized. - virtual void minimize() = 0; - - /// @brief Maximizes the window if it is currently not maximized. - virtual void maximize() = 0; - - /// @brief Restores the window to its normal state if it is currently minimized or maximized. - virtual void restore() = 0; - - /// @brief Focuses the window, bringing it to the foreground and giving it input focus if possible. - virtual void focus() = 0; - - /// @brief Requests the user's attention to the window, which may cause the window to flash or bounce in the taskbar - /// or dock depending on the platform and the specified flash mode. This can be used to notify the user of - /// important events when the window is not currently focused. - /// @param[in] mode The flash mode that determines how the window should request the user's attention. - virtual void requestAttention(WindowFlashMode mode = WindowFlashMode::UntilFocused) = 0; - - /// @brief Centers the window on the specified display. - /// @param[in] display The display on which to center the window. - /// @note If the display parameter is nullptr, the window will be centered on the display that it is currently - /// associated with, or on the primary display if it is not currently associated with any display. - virtual void centerOnDisplay(const Display* display = nullptr) = 0; - - /// @brief Dispatches any pending events for the window. - virtual void dispatchEvents() noexcept = 0; -}; - -} // namespace gp::hal diff --git a/source/runtime/hal/public/window/WindowDesc.hpp b/source/runtime/hal/public/window/WindowDesc.hpp deleted file mode 100644 index 46707eb..0000000 --- a/source/runtime/hal/public/window/WindowDesc.hpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "container/BasicStringView.hpp" // IWYU pragma: keep -#include "container/Forward.hpp" -#include "CoreMinimal.hpp" -#include "window/CursorEnums.hpp" -#include "window/WindowEnums.hpp" -#include "window/WindowTypes.hpp" - -namespace gp::hal -{ - -/// @section Forward declarations - -class Display; - -/// @brief Configuration settings used to initialize a new Window instance. -/// @details This structure defines the initial state, look, and OS-level behavior of a window. -struct WindowDesc -{ - /// @brief The text displayed in the window's title bar and taskbar entry. - StringView title{ "Graphical Playground" }; - - /// @brief The initial top-left position of the window in screen coordinates. - /// @note If targetDisplay is non-null, this is often treated as an offset from that display's origin. - Point2D position{ 100, 100 }; - - /// @brief The preferred display to spawn the window on. If nullptr, the OS determines the best display. - const Display* targetDisplay{ nullptr }; - - /// @brief The initial size of the window's client area (drawable region) in pixels. - Extent2D size{ 1280u, 720u }; - - /// @brief The minimum allowed dimensions for the window. Set to (0,0) for no limit. - Extent2D minimumSize{ 0u, 0u }; - - /// @brief The maximum allowed dimensions for the window. Set to (0,0) for no limit. - Extent2D maximumSize{ 0u, 0u }; - - /// @brief The display mode (Windowed, Fullscreen, etc.) to use upon creation. - WindowMode mode{ WindowMode::Windowed }; - - /// @brief The initial visibility state (Normal, Minimized, etc.). - WindowState initialState{ WindowState::Normal }; - - /// @brief Bitmask of aesthetic and functional flags (Resizable, TitleBar, etc.). - WindowStyle style{ WindowStyle::Default }; - - /// @brief Defines how the mouse cursor behaves when interacting with this window. - CursorMode cursorMode{ CursorMode::Normal }; - - /// @brief The default system icon shape for the cursor when over this window. - CursorShape cursorShape{ CursorShape::Arrow }; - - /// @brief The global transparency of the window. Range: [0.0 (Invisible) to 1.0 (Opaque)]. - /// @note Requires EWindowStyle::Transparent to be set in most platform implementations. - Float32 opacity{ 1.0f }; - - /// @brief If true, the window will request a high-resolution backbuffer on supported DPI-aware displays. - bool useHighDPI{ true }; - - /// @brief Whether to synchronize the buffer swap with the display's vertical refresh rate. - bool useVSync{ true }; - - /// @brief If true, the window will be created without a visible framebuffer and will not render any content. This - /// is useful for headless applications or when the window is only used for input handling without any visual - /// output. - /// @note This has absolute priority over all other settings. If useHeadless is true, the window will be created in - /// a headless state regardless of the values of other fields in this struct. In headless mode, the window - /// will not be visible, will not have a framebuffer, and will not render any content, but it can still - /// receive input events and be manipulated through the IWindow interface. - bool useHeadless{ false }; - - /// @brief If true, the window will be created in an open/visible state. If false, the window will not be created - /// until Open() is called. - bool startOpened{ true }; - - /// @brief If true, the window will attempt to take input focus immediately upon creation. - /// @note This may be ignored by the OS or window manager if it deems it inappropriate to steal focus from the - /// currently active application. Additionally, if startVisible is false, the window will be created hidden - /// regardless of the value of startFocused. - bool startFocused{ true }; - - /// @brief If true, the window will be visible immediately upon creation. If false, the window will be created - /// hidden and must be shown explicitly by the caller. - /// @note This has priority over initialState. If startVisible is false, the window will be created hidden - /// regardless of the value of initialState. - bool startVisible{ true }; - - /// @brief If true, the window will automatically request focus whenever it transitions to a visible state. - bool focusOnShow{ true }; - - /// @brief If true, the window will be created with the mouse input grabbed, meaning it will receive all mouse - /// events regardless of whether it is the active/focused window. - bool grabMouse{ false }; - - /// @brief If true, the window will be created with the keyboard input grabbed, meaning it will receive all keyboard - /// events regardless of whether it is the active/focused window. - bool grabKeyboard{ false }; - - /// @brief Optional native handle to a parent window. If provided, this window becomes a child. - /// @details This is used for embedding the engine into external tools or editor environments (e.g., Win32 HWND). - void* nativeParentHandle{ nullptr }; - - // TODO: Add more fields as needed, such as: - // - Whether to enable per-monitor DPI awareness on Windows. - // - Custom cursor images or icons. - // - Custom icon image for the window (e.g. taskbar and title bar icon on Windows). -}; - -} // namespace gp::hal diff --git a/source/runtime/hal/public/window/WindowEnums.hpp b/source/runtime/hal/public/window/WindowEnums.hpp deleted file mode 100644 index 1b1c94c..0000000 --- a/source/runtime/hal/public/window/WindowEnums.hpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" -#include "utils/Enums.hpp" - -namespace gp::hal -{ - -/// @brief Defines the flashing behavior of a window when requesting user attention. -enum class WindowFlashMode : gp::UInt8 -{ - /// @brief Stop flashing the window. - None, - - /// @brief Flash the window until it receives focus. - UntilFocused, - - /// @brief Flash the window for a short period of time. - Briefly -}; - -/// @brief Defines the primary display mode of the window. -enum class WindowMode : gp::UInt8 -{ - /// @brief Standard window with borders and title bar. - Windowed, - - /// @brief Windowed mode without borders, typically matching display resolution. - Borderless, - - /// @brief Exclusive hardware control of the display (Legacy/Performance). - Fullscreen, - - /// @brief Borderless window that spans across all available monitors. - FullscreenDesktop -}; - -/// @brief Defines the current runtime state or "visibility" of the window. -enum class WindowState : gp::UInt8 -{ - /// @brief The window is visible and rendered normally. - Normal, - - /// @brief The window is minimized to the taskbar/dock and likely not rendering. - Minimized, - - /// @brief The window is expanded to fill the workspace. - Maximized, - - /// @brief The window is hidden from the user and taskbar. - Hidden, - - /// @brief The window is visible but currently being occluded by another application. - Occluded -}; - -/// @brief Bitmask defining the aesthetic and functional properties of the window. -enum class WindowStyle : gp::UInt32 -{ - None = 0, - - /// @brief The window has a visible title bar. - TitleBar = 1 << 0, - - /// @brief The window has a system menu / close button. - Closable = 1 << 1, - - /// @brief The user can drag the edges to resize the window. - Resizable = 1 << 2, - - /// @brief The window has minimize and maximize buttons. - MinMaxButtons = 1 << 3, - - /// @brief The window is always rendered on top of other non-topmost windows. - AlwaysOnTop = 1 << 4, - - /// @brief The window's background can be partially or fully transparent. - Transparent = 1 << 5, - - /// @brief Useful for splash screens or tooltips; window doesn't appear in taskbar. - NoTaskbar = 1 << 6, - - /// @brief A standard decorative window. - Default = TitleBar | Closable | Resizable | MinMaxButtons -}; - -} // namespace gp::hal - -GP_ENABLE_ENUM_BITWISE_OPERATIONS(gp::hal::WindowStyle); diff --git a/source/runtime/hal/public/window/WindowTypes.hpp b/source/runtime/hal/public/window/WindowTypes.hpp deleted file mode 100644 index 56ba04c..0000000 --- a/source/runtime/hal/public/window/WindowTypes.hpp +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" - -namespace gp::hal -{ - -/// @brief Simple structure representing a 2D point with integer coordinates, commonly used for window positions and -/// sizes. -struct Point2D -{ -public: - Int32 x; - Int32 y; - -public: - /// @brief Default constructor initializes point to (0, 0). - constexpr Point2D() noexcept - : x(0) - , y(0) - {} - - /// @brief Constructs a point with the given coordinates. - /// @param[in] inX X coordinate of the point. - /// @param[in] inY Y coordinate of the point. - constexpr Point2D(const Int32 inX, const Int32 inY) noexcept - : x(inX) - , y(inY) - {} - - /// @brief Constructs a point from an array of 2 elements, where data[0] is x and data[1] is y. - /// @param[in] arr Pointer to an array of 2 elements representing the point's coordinates. - /// @warning The caller must ensure that `arr` points to at least 2 valid elements. No bounds checking is performed. - constexpr Point2D(const Int32* arr) noexcept - : x(arr[0]) - , y(arr[1]) - {} - - /// @brief Constructs a point from a reference to a C-style array of 2 elements, where arr[0] is x and arr[1] is y. - /// @param[in] arr Reference to a C-style array of 2 elements representing the point's coordinates. - /// @warning The caller must ensure that `arr` has at least 2 elements. No bounds checking is performed. - constexpr Point2D(const Int32 (&arr)[2]) noexcept - : x(arr[0]) - , y(arr[1]) - {} - - /// @brief Copy constructor. - /// @param[in] extent Point to copy from. - constexpr Point2D(const Point2D& extent) noexcept = default; - - /// @brief Move constructor. - /// @param[in] extent Point to move from. - constexpr Point2D(Point2D&& extent) noexcept = default; - -public: - /// @brief Copy assignment operator. - /// @param[in] other Point to copy from. - /// @return Reference to the assigned point. - constexpr Point2D& operator=(const Point2D& other) noexcept = default; - - /// @brief Move assignment operator. - /// @param[in] other Point to move from. - /// @return Reference to the assigned point. - constexpr Point2D& operator=(Point2D&& other) noexcept = default; - - /// @brief Equality comparison operator. - /// @param[in] other Point to compare with. - /// @return true if both points have the same coordinates, false otherwise. - GP_NODISCARD constexpr bool operator==(const Point2D& other) const noexcept - { - return x == other.x && y == other.y; - } - - /// @brief Inequality comparison operator. - /// @param[in] other Point to compare with. - /// @return true if the points have different coordinates, false if they are equal. - GP_NODISCARD constexpr bool operator!=(const Point2D& other) const noexcept - { - return !(*this == other); - } - - /// @brief Unary negation operator, which negates both coordinates of the point. - /// @return A new point with both coordinates negated. - GP_NODISCARD constexpr Point2D operator-() const noexcept - { - return Point2D(-x, -y); - } - - /// @brief Addition operator, which adds the corresponding coordinates of two points. - /// @param[in] other Point to add. - /// @return A new point resulting from the coordinate-wise addition of the two points. - GP_NODISCARD constexpr Point2D operator+(const Point2D& other) const noexcept - { - return Point2D(x + other.x, y + other.y); - } - - /// @brief Subtraction operator, which subtracts the corresponding coordinates of two points. - /// @param[in] other Point to subtract. - /// @return A new point resulting from the coordinate-wise subtraction of the two points. - GP_NODISCARD constexpr Point2D operator-(const Point2D& other) const noexcept - { - return Point2D(x - other.x, y - other.y); - } -}; - -/// @brief Simple structure representing a 2D extent (width and height) with unsigned integer values, commonly used for -/// window sizes and dimension constraints. -struct Extent2D -{ -public: - UInt32 width; - UInt32 height; - -public: - /// @brief Default constructor initializes extent to (0, 0). - constexpr Extent2D() noexcept - : width(0) - , height(0) - {} - - /// @brief Constructs an extent with the given dimensions. - /// @param[in] inWidth Width of the extent. - /// @param[in] inHeight Height of the extent. - constexpr Extent2D(const UInt32 inWidth, const UInt32 inHeight) noexcept - : width(inWidth) - , height(inHeight) - {} - - /// @brief Constructs an extent from an array of 2 elements, where data[0] is width and data[1] is height. - /// @param[in] arr Pointer to an array of 2 elements representing the extent's dimensions. - /// @warning The caller must ensure that `arr` points to at least 2 valid elements. No bounds checking is performed. - constexpr Extent2D(const UInt32* arr) noexcept - : width(arr[0]) - , height(arr[1]) - {} - - /// @brief Constructs an extent from a reference to a C-style array of 2 elements, where arr[0] is width and arr[1] - /// is height. - /// @param[in] arr Reference to a C-style array of 2 elements representing the extent's dimensions. - /// @warning The caller must ensure that `arr` has at least 2 elements. No bounds checking is performed. - constexpr Extent2D(const UInt32 (&arr)[2]) noexcept - : width(arr[0]) - , height(arr[1]) - {} - - /// @brief Copy constructor. - /// @param[in] extent Extent to copy from. - constexpr Extent2D(const Extent2D& extent) noexcept = default; - - /// @brief Move constructor. - /// @param[in] extent Extent to move from. - constexpr Extent2D(Extent2D&& extent) noexcept = default; - -public: - /// @brief Copy assignment operator. - /// @param[in] other Source extent to copy from. - /// @return Reference to this. - constexpr Extent2D& operator=(const Extent2D& other) noexcept = default; - - /// @brief Move assignment operator. - /// @param[in] other Source extent to move from. - /// @return Reference to this. - constexpr Extent2D& operator=(Extent2D&& other) noexcept = default; - - /// @brief Equality operator. - /// @param[in] other Source extent to compare with. - /// @return True if this extent is equal to the other, false otherwise. - GP_NODISCARD constexpr bool operator==(const Extent2D& other) const noexcept - { - return width == other.width && height == other.height; - } - - /// @brief Inequality operator. - /// @param[in] other Source extent to compare with. - /// @return True if this extent is not equal to the other, false otherwise. - GP_NODISCARD constexpr bool operator!=(const Extent2D& other) const noexcept - { - return !(*this == other); - } -}; - -} // namespace gp::hal diff --git a/source/runtime/input/.gitignore b/source/runtime/input/.gitignore deleted file mode 100644 index c672976..0000000 --- a/source/runtime/input/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/input directory diff --git a/source/runtime/input/README.md b/source/runtime/input/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/input/docs/README.md b/source/runtime/input/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/input/docs/_category_.json b/source/runtime/input/docs/_category_.json deleted file mode 100644 index b1159f3..0000000 --- a/source/runtime/input/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Input" -} diff --git a/source/runtime/io/.gitignore b/source/runtime/io/.gitignore deleted file mode 100644 index f9a949f..0000000 --- a/source/runtime/io/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/io directory diff --git a/source/runtime/io/README.md b/source/runtime/io/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/io/docs/README.md b/source/runtime/io/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/io/docs/_category_.json b/source/runtime/io/docs/_category_.json deleted file mode 100644 index 00013ea..0000000 --- a/source/runtime/io/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "I/O" -} diff --git a/source/runtime/network/.gitignore b/source/runtime/network/.gitignore deleted file mode 100644 index e650e21..0000000 --- a/source/runtime/network/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/network directory diff --git a/source/runtime/network/CMakeLists.txt b/source/runtime/network/CMakeLists.txt deleted file mode 100644 index e15fac3..0000000 --- a/source/runtime/network/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpStartModule(network) - gpAddPublicDependency(core) -gpEndModule() diff --git a/source/runtime/network/README.md b/source/runtime/network/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/network/docs/README.md b/source/runtime/network/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/network/docs/_category_.json b/source/runtime/network/docs/_category_.json deleted file mode 100644 index bdd2d41..0000000 --- a/source/runtime/network/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Network" -} diff --git a/assets/editor/themes/.gitkeep b/source/runtime/parser/fbx/.gitignore similarity index 100% rename from assets/editor/themes/.gitkeep rename to source/runtime/parser/fbx/.gitignore diff --git a/source/runtime/hal/CHANGELOG.md b/source/runtime/parser/fbx/CHANGELOG.md similarity index 100% rename from source/runtime/hal/CHANGELOG.md rename to source/runtime/parser/fbx/CHANGELOG.md diff --git a/source/runtime/audio/CMakeLists.txt b/source/runtime/parser/fbx/CMakeLists.txt similarity index 78% rename from source/runtime/audio/CMakeLists.txt rename to source/runtime/parser/fbx/CMakeLists.txt index fa6eff1..50b40f8 100644 --- a/source/runtime/audio/CMakeLists.txt +++ b/source/runtime/parser/fbx/CMakeLists.txt @@ -4,6 +4,6 @@ include(gp-build-tool) -gpStartModule(audio) - gpAddPublicDependency(core) +gpStartModule(parser/fbx) + gpAddDependency(PUBLIC core) gpEndModule() diff --git a/source/launch/standalone/README.md b/source/runtime/parser/fbx/README.md similarity index 100% rename from source/launch/standalone/README.md rename to source/runtime/parser/fbx/README.md diff --git a/source/runtime/hal/private/HAL.cpp b/source/runtime/parser/fbx/private/ParserFBX.cpp similarity index 100% rename from source/runtime/hal/private/HAL.cpp rename to source/runtime/parser/fbx/private/ParserFBX.cpp diff --git a/source/runtime/parser/fbx/public/ParserFBX.hpp b/source/runtime/parser/fbx/public/ParserFBX.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/fbx/public/ParserFBX.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/assets/engine/animations/.gitkeep b/source/runtime/parser/gltf/.gitignore similarity index 100% rename from assets/engine/animations/.gitkeep rename to source/runtime/parser/gltf/.gitignore diff --git a/source/runtime/input/CHANGELOG.md b/source/runtime/parser/gltf/CHANGELOG.md similarity index 100% rename from source/runtime/input/CHANGELOG.md rename to source/runtime/parser/gltf/CHANGELOG.md diff --git a/source/runtime/parser/gltf/CMakeLists.txt b/source/runtime/parser/gltf/CMakeLists.txt new file mode 100644 index 0000000..d7a4c31 --- /dev/null +++ b/source/runtime/parser/gltf/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(parser/gltf) + gpAddDependency(PUBLIC core) +gpEndModule() diff --git a/source/launch/standalone/docs/README.md b/source/runtime/parser/gltf/README.md similarity index 100% rename from source/launch/standalone/docs/README.md rename to source/runtime/parser/gltf/README.md diff --git a/source/runtime/hal/private/linux/Linux.cpp b/source/runtime/parser/gltf/private/ParserGLTF.cpp similarity index 100% rename from source/runtime/hal/private/linux/Linux.cpp rename to source/runtime/parser/gltf/private/ParserGLTF.cpp diff --git a/source/runtime/parser/gltf/public/ParserGLTF.hpp b/source/runtime/parser/gltf/public/ParserGLTF.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/gltf/public/ParserGLTF.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/assets/engine/audios/.gitkeep b/source/runtime/parser/ini/.gitignore similarity index 100% rename from assets/engine/audios/.gitkeep rename to source/runtime/parser/ini/.gitignore diff --git a/source/runtime/io/CHANGELOG.md b/source/runtime/parser/ini/CHANGELOG.md similarity index 100% rename from source/runtime/io/CHANGELOG.md rename to source/runtime/parser/ini/CHANGELOG.md diff --git a/source/runtime/animation/CMakeLists.txt b/source/runtime/parser/ini/CMakeLists.txt similarity index 78% rename from source/runtime/animation/CMakeLists.txt rename to source/runtime/parser/ini/CMakeLists.txt index b19df6a..47be3be 100644 --- a/source/runtime/animation/CMakeLists.txt +++ b/source/runtime/parser/ini/CMakeLists.txt @@ -4,6 +4,6 @@ include(gp-build-tool) -gpStartModule(animation) - gpAddPublicDependency(core) +gpStartModule(parser/ini) + gpAddDependency(PUBLIC core) gpEndModule() diff --git a/source/runtime/animation/README.md b/source/runtime/parser/ini/README.md similarity index 100% rename from source/runtime/animation/README.md rename to source/runtime/parser/ini/README.md diff --git a/source/runtime/hal/private/macos/MacOS.cpp b/source/runtime/parser/ini/private/ParserINI.cpp similarity index 100% rename from source/runtime/hal/private/macos/MacOS.cpp rename to source/runtime/parser/ini/private/ParserINI.cpp diff --git a/source/runtime/parser/ini/public/ParserINI.hpp b/source/runtime/parser/ini/public/ParserINI.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/ini/public/ParserINI.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/assets/engine/debug/.gitkeep b/source/runtime/parser/json/.gitignore similarity index 100% rename from assets/engine/debug/.gitkeep rename to source/runtime/parser/json/.gitignore diff --git a/source/runtime/network/CHANGELOG.md b/source/runtime/parser/json/CHANGELOG.md similarity index 100% rename from source/runtime/network/CHANGELOG.md rename to source/runtime/parser/json/CHANGELOG.md diff --git a/source/runtime/parser/json/CMakeLists.txt b/source/runtime/parser/json/CMakeLists.txt new file mode 100644 index 0000000..afd1ca5 --- /dev/null +++ b/source/runtime/parser/json/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(parser/json) + gpAddDependency(PUBLIC core) +gpEndModule() diff --git a/source/runtime/animation/docs/README.md b/source/runtime/parser/json/README.md similarity index 100% rename from source/runtime/animation/docs/README.md rename to source/runtime/parser/json/README.md diff --git a/source/runtime/hal/private/windows/Windows.cpp b/source/runtime/parser/json/private/ParserJSON.cpp similarity index 100% rename from source/runtime/hal/private/windows/Windows.cpp rename to source/runtime/parser/json/private/ParserJSON.cpp diff --git a/source/runtime/parser/json/public/ParserJSON.hpp b/source/runtime/parser/json/public/ParserJSON.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/json/public/ParserJSON.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/assets/engine/effects/.gitkeep b/source/runtime/parser/obj/.gitignore similarity index 100% rename from assets/engine/effects/.gitkeep rename to source/runtime/parser/obj/.gitignore diff --git a/source/runtime/physics/CHANGELOG.md b/source/runtime/parser/obj/CHANGELOG.md similarity index 100% rename from source/runtime/physics/CHANGELOG.md rename to source/runtime/parser/obj/CHANGELOG.md diff --git a/source/runtime/io/CMakeLists.txt b/source/runtime/parser/obj/CMakeLists.txt similarity index 78% rename from source/runtime/io/CMakeLists.txt rename to source/runtime/parser/obj/CMakeLists.txt index fdb5d57..598ff67 100644 --- a/source/runtime/io/CMakeLists.txt +++ b/source/runtime/parser/obj/CMakeLists.txt @@ -4,6 +4,6 @@ include(gp-build-tool) -gpStartModule(io) - gpAddPublicDependency(core) +gpStartModule(parser/obj) + gpAddDependency(PUBLIC core) gpEndModule() diff --git a/source/runtime/audio/README.md b/source/runtime/parser/obj/README.md similarity index 100% rename from source/runtime/audio/README.md rename to source/runtime/parser/obj/README.md diff --git a/source/runtime/hal/public/HAL.hpp b/source/runtime/parser/obj/private/ParserOBJ.cpp similarity index 100% rename from source/runtime/hal/public/HAL.hpp rename to source/runtime/parser/obj/private/ParserOBJ.cpp diff --git a/source/runtime/parser/obj/public/ParserOBJ.hpp b/source/runtime/parser/obj/public/ParserOBJ.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/obj/public/ParserOBJ.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/assets/engine/fonts/.gitkeep b/source/runtime/parser/xml/.gitignore similarity index 100% rename from assets/engine/fonts/.gitkeep rename to source/runtime/parser/xml/.gitignore diff --git a/assets/engine/materials/.gitkeep b/source/runtime/parser/xml/CHANGELOG.md similarity index 100% rename from assets/engine/materials/.gitkeep rename to source/runtime/parser/xml/CHANGELOG.md diff --git a/source/runtime/parser/xml/CMakeLists.txt b/source/runtime/parser/xml/CMakeLists.txt new file mode 100644 index 0000000..4485aaa --- /dev/null +++ b/source/runtime/parser/xml/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(parser/xml) + gpAddDependency(PUBLIC core) +gpEndModule() diff --git a/source/runtime/audio/docs/README.md b/source/runtime/parser/xml/README.md similarity index 100% rename from source/runtime/audio/docs/README.md rename to source/runtime/parser/xml/README.md diff --git a/source/runtime/input/private/Input.cpp b/source/runtime/parser/xml/private/ParserXML.cpp similarity index 100% rename from source/runtime/input/private/Input.cpp rename to source/runtime/parser/xml/private/ParserXML.cpp diff --git a/source/runtime/parser/xml/public/ParserXML.hpp b/source/runtime/parser/xml/public/ParserXML.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/xml/public/ParserXML.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/assets/engine/scenes/.gitkeep b/source/runtime/parser/yaml/.gitignore similarity index 100% rename from assets/engine/scenes/.gitkeep rename to source/runtime/parser/yaml/.gitignore diff --git a/assets/engine/scripts/.gitkeep b/source/runtime/parser/yaml/CHANGELOG.md similarity index 100% rename from assets/engine/scripts/.gitkeep rename to source/runtime/parser/yaml/CHANGELOG.md diff --git a/source/runtime/parser/yaml/CMakeLists.txt b/source/runtime/parser/yaml/CMakeLists.txt new file mode 100644 index 0000000..451d5a9 --- /dev/null +++ b/source/runtime/parser/yaml/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(parser/yaml) + gpAddDependency(PUBLIC core) +gpEndModule() diff --git a/source/runtime/core/docs/README.md b/source/runtime/parser/yaml/README.md similarity index 100% rename from source/runtime/core/docs/README.md rename to source/runtime/parser/yaml/README.md diff --git a/source/runtime/io/private/IO.cpp b/source/runtime/parser/yaml/private/ParserYAML.cpp similarity index 100% rename from source/runtime/io/private/IO.cpp rename to source/runtime/parser/yaml/private/ParserYAML.cpp diff --git a/source/runtime/parser/yaml/public/ParserYAML.hpp b/source/runtime/parser/yaml/public/ParserYAML.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/parser/yaml/public/ParserYAML.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/physics/.gitignore b/source/runtime/physics/.gitignore deleted file mode 100644 index 1452264..0000000 --- a/source/runtime/physics/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/physics directory diff --git a/source/runtime/physics/CMakeLists.txt b/source/runtime/physics/CMakeLists.txt deleted file mode 100644 index 4bc9d7a..0000000 --- a/source/runtime/physics/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpStartModule(physics) - gpAddPublicDependency(core) -gpEndModule() diff --git a/source/runtime/physics/README.md b/source/runtime/physics/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/core/docs/memory/Utilities.md b/source/runtime/physics/base/.gitignore similarity index 100% rename from source/runtime/core/docs/memory/Utilities.md rename to source/runtime/physics/base/.gitignore diff --git a/source/runtime/core/docs/memory/allocators/Allocator.md b/source/runtime/physics/base/CHANGELOG.md similarity index 100% rename from source/runtime/core/docs/memory/allocators/Allocator.md rename to source/runtime/physics/base/CHANGELOG.md diff --git a/source/runtime/physics/base/CMakeLists.txt b/source/runtime/physics/base/CMakeLists.txt new file mode 100644 index 0000000..63e378b --- /dev/null +++ b/source/runtime/physics/base/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(physics/base) + gpAddDependency(PUBLIC core) +gpEndModule() diff --git a/source/runtime/docs/README.md b/source/runtime/physics/base/README.md similarity index 100% rename from source/runtime/docs/README.md rename to source/runtime/physics/base/README.md diff --git a/source/runtime/network/private/Network.cpp b/source/runtime/physics/base/private/PhysicsBase.cpp similarity index 100% rename from source/runtime/network/private/Network.cpp rename to source/runtime/physics/base/private/PhysicsBase.cpp diff --git a/source/runtime/physics/base/public/PhysicsBase.hpp b/source/runtime/physics/base/public/PhysicsBase.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/physics/base/public/PhysicsBase.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/physics/docs/README.md b/source/runtime/physics/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/physics/docs/_category_.json b/source/runtime/physics/docs/_category_.json deleted file mode 100644 index 927d8fb..0000000 --- a/source/runtime/physics/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Physics" -} diff --git a/source/runtime/core/docs/memory/allocators/Default.md b/source/runtime/physics/jolt/.gitignore similarity index 100% rename from source/runtime/core/docs/memory/allocators/Default.md rename to source/runtime/physics/jolt/.gitignore diff --git a/source/runtime/core/docs/memory/allocators/Linear.md b/source/runtime/physics/jolt/CHANGELOG.md similarity index 100% rename from source/runtime/core/docs/memory/allocators/Linear.md rename to source/runtime/physics/jolt/CHANGELOG.md diff --git a/source/runtime/physics/jolt/CMakeLists.txt b/source/runtime/physics/jolt/CMakeLists.txt new file mode 100644 index 0000000..f3d41b2 --- /dev/null +++ b/source/runtime/physics/jolt/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(physics/jolt) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC physics/base) +gpEndModule() diff --git a/source/runtime/engine/docs/README.md b/source/runtime/physics/jolt/README.md similarity index 100% rename from source/runtime/engine/docs/README.md rename to source/runtime/physics/jolt/README.md diff --git a/source/runtime/physics/private/Physics.cpp b/source/runtime/physics/jolt/private/PhysicsJolt.cpp similarity index 100% rename from source/runtime/physics/private/Physics.cpp rename to source/runtime/physics/jolt/private/PhysicsJolt.cpp diff --git a/source/runtime/physics/jolt/public/PhysicsJolt.hpp b/source/runtime/physics/jolt/public/PhysicsJolt.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/physics/jolt/public/PhysicsJolt.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/core/docs/memory/allocators/Polymorphic.md b/source/runtime/physics/physx/.gitignore similarity index 100% rename from source/runtime/core/docs/memory/allocators/Polymorphic.md rename to source/runtime/physics/physx/.gitignore diff --git a/source/runtime/core/docs/memory/allocators/Pool.md b/source/runtime/physics/physx/CHANGELOG.md similarity index 100% rename from source/runtime/core/docs/memory/allocators/Pool.md rename to source/runtime/physics/physx/CHANGELOG.md diff --git a/source/runtime/physics/physx/CMakeLists.txt b/source/runtime/physics/physx/CMakeLists.txt new file mode 100644 index 0000000..5a555b6 --- /dev/null +++ b/source/runtime/physics/physx/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) - Graphical Playground. All rights reserved. +# For more information, see https://graphical-playground/legal +# mailto:support AT graphical-playground DOT com + +include(gp-build-tool) + +gpStartModule(physics/physx) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC physics/base) +gpEndModule() diff --git a/source/runtime/hal/README.md b/source/runtime/physics/physx/README.md similarity index 100% rename from source/runtime/hal/README.md rename to source/runtime/physics/physx/README.md diff --git a/source/runtime/rhi/base/private/RHI.cpp b/source/runtime/physics/physx/private/PhysicsPhysx.cpp similarity index 100% rename from source/runtime/rhi/base/private/RHI.cpp rename to source/runtime/physics/physx/private/PhysicsPhysx.cpp diff --git a/source/runtime/physics/physx/public/PhysicsPhysx.hpp b/source/runtime/physics/physx/public/PhysicsPhysx.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/physics/physx/public/PhysicsPhysx.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/renderer/.gitignore b/source/runtime/renderer/.gitignore index e7e0b29..e69de29 100644 --- a/source/runtime/renderer/.gitignore +++ b/source/runtime/renderer/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/renderer directory diff --git a/source/runtime/renderer/CMakeLists.txt b/source/runtime/renderer/CMakeLists.txt index d44682b..5445b21 100644 --- a/source/runtime/renderer/CMakeLists.txt +++ b/source/runtime/renderer/CMakeLists.txt @@ -5,5 +5,5 @@ include(gp-build-tool) gpStartModule(renderer) - gpAddPublicDependency(core) + gpAddDependency(PUBLIC core) gpEndModule() diff --git a/source/runtime/renderer/docs/README.md b/source/runtime/renderer/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/renderer/docs/_category_.json b/source/runtime/renderer/docs/_category_.json deleted file mode 100644 index 54306c1..0000000 --- a/source/runtime/renderer/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Renderer" -} diff --git a/source/runtime/rhi/base/.gitignore b/source/runtime/rhi/base/.gitignore index c54663b..e69de29 100644 --- a/source/runtime/rhi/base/.gitignore +++ b/source/runtime/rhi/base/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/base directory diff --git a/source/runtime/rhi/base/CMakeLists.txt b/source/runtime/rhi/base/CMakeLists.txt index c9653dd..71df50c 100644 --- a/source/runtime/rhi/base/CMakeLists.txt +++ b/source/runtime/rhi/base/CMakeLists.txt @@ -4,28 +4,22 @@ include(gp-build-tool) -gpStartModule(rhi) - gpAddPublicDependency(core) +gpStartModule(rhi/base) + gpAddDependency(PUBLIC core) - gpAddDynamicDependency(rhi/null) + gpAddDependency(DYNAMIC rhi/null) - if (WIN32 AND GP_USE_D3D11) - gpAddDynamicDependency(rhi/d3d11) + if(WIN32) + gpAddDependency(DYNAMIC rhi/d3d11) + gpAddDependency(DYNAMIC rhi/d3d12) endif() - if (WIN32 AND GP_USE_D3D12) - gpAddDynamicDependency(rhi/d3d12) + if(UNIX OR WIN32) + gpAddDependency(DYNAMIC rhi/vulkan) + gpAddDependency(DYNAMIC rhi/opengl) endif() - if ((UNIX OR WIN32) AND GP_USE_VULKAN) - gpAddDynamicDependency(rhi/vulkan) - endif() - - if ((WIN32 OR UNIX) AND GP_USE_OPENGL) - gpAddDynamicDependency(rhi/opengl) - endif() - - if (APPLE AND GP_USE_METAL) - gpAddDynamicDependency(rhi/metal) + if(APPLE) + gpAddDependency(DYNAMIC rhi/metal) endif() gpEndModule() diff --git a/source/runtime/rhi/base/docs/README.md b/source/runtime/rhi/base/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/base/docs/_category_.json b/source/runtime/rhi/base/docs/_category_.json deleted file mode 100644 index 7c6c55d..0000000 --- a/source/runtime/rhi/base/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Base" -} diff --git a/source/runtime/rhi/d3d11/private/D3D11.cpp b/source/runtime/rhi/base/private/RHIBase.cpp similarity index 100% rename from source/runtime/rhi/d3d11/private/D3D11.cpp rename to source/runtime/rhi/base/private/RHIBase.cpp diff --git a/source/runtime/rhi/base/public/RHIBase.hpp b/source/runtime/rhi/base/public/RHIBase.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/base/public/RHIBase.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/rhi/base/public/RHIDefinitions.hpp b/source/runtime/rhi/base/public/RHIDefinitions.hpp deleted file mode 100644 index e832f49..0000000 --- a/source/runtime/rhi/base/public/RHIDefinitions.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) - Graphical Playground. All rights reserved. -// For more information, see https://graphical-playground/legal -// mailto:support AT graphical-playground DOT com - -#pragma once - -#include "CoreMinimal.hpp" - -namespace gp::rhi -{ - -/// @brief The type of the graphics interface. -enum class InterfaceType -{ - Hidden, - Null, - D3D11, - D3D12, - Vulkan, - Metal, - OpenGL -}; - -/// @brief The feature support level of the graphics interface. -enum class FeatureSupport : gp::UInt8 -{ - Unsupported, //; -using BlendStateRef = gp::RefCountPtr; -using BoundShaderStateRef = gp::RefCountPtr; -using BufferRef = gp::RefCountPtr; -using ComputePipelineStateRef = gp::RefCountPtr; -using ComputeShaderRef = gp::RefCountPtr; -using CustomPresentRef = gp::RefCountPtr; -using DepthStencilStateRef = gp::RefCountPtr; -using GeometryShaderRef = gp::RefCountPtr; -using GPUFenceRef = gp::RefCountPtr; -using GraphicsPipelineStateRef = gp::RefCountPtr; -using MeshShaderRef = gp::RefCountPtr; -using PixelShaderRef = gp::RefCountPtr; -using RasterizerStateRef = gp::RefCountPtr; -using RayTracingGeometryRef = gp::RefCountPtr; -using RayTracingPipelineStateRef = gp::RefCountPtr; -using RayTracingSceneRef = gp::RefCountPtr; -using RayTracingShaderRef = gp::RefCountPtr; -using ShaderBindingTableRef = gp::RefCountPtr; -using RenderQueryPoolRef = gp::RefCountPtr; -using RenderQueryRef = gp::RefCountPtr; -using ResourceCollectRef = gp::RefCountPtr; -using ShaderLibrRef = gp::RefCountPtr; -using ShaderResourceVRef = gp::RefCountPtr; -using SamplerStateRef = gp::RefCountPtr; -using ShaderResourceViewRef = gp::RefCountPtr; -using ShaderBundleRef = gp::RefCountPtr; -using StagingBufferRef = gp::RefCountPtr; -using TextureReferenceRef = gp::RefCountPtr; -using TextureRef = gp::RefCountPtr; -#if !defined(GP_RHI_NEW_GPU_PROFILER) || (GP_RHI_NEW_GPU_PROFILER == 0) -using TimestampCalibrationQueryRef = gp::RefCountPtr; -#endif -using UniformBufferLayoutRef = gp::RefCountPtr; -using UniformBufferRef = gp::RefCountPtr; -using UnorderedAccessViewRef = gp::RefCountPtr; -using VertexDeclarationRef = gp::RefCountPtr; -using VertexShaderRef = gp::RefCountPtr; -using ViewportRef = gp::RefCountPtr; -using WorkGraphPipelineStateRef = gp::RefCountPtr; -using StreamSourceSlotRef = gp::RefCountPtr; -using WorkGraphShaderRef = gp::RefCountPtr; - -} // namespace gp::rhi diff --git a/source/runtime/rhi/d3d11/.gitignore b/source/runtime/rhi/d3d11/.gitignore index 409ee4e..e69de29 100644 --- a/source/runtime/rhi/d3d11/.gitignore +++ b/source/runtime/rhi/d3d11/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/d3d11 directory diff --git a/source/runtime/rhi/d3d11/CMakeLists.txt b/source/runtime/rhi/d3d11/CMakeLists.txt index fe3964d..cbed2e7 100644 --- a/source/runtime/rhi/d3d11/CMakeLists.txt +++ b/source/runtime/rhi/d3d11/CMakeLists.txt @@ -4,9 +4,7 @@ include(gp-build-tool) -if (NOT GP_USE_D3D11 OR NOT WIN32) - return() -endif() - gpStartModule(rhi/d3d11) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC rhi/base) gpEndModule() diff --git a/source/runtime/rhi/d3d11/docs/README.md b/source/runtime/rhi/d3d11/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/d3d11/docs/_category_.json b/source/runtime/rhi/d3d11/docs/_category_.json deleted file mode 100644 index 4d8f5c2..0000000 --- a/source/runtime/rhi/d3d11/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "DirectX 11" -} diff --git a/source/runtime/rhi/d3d12/private/D3D12.cpp b/source/runtime/rhi/d3d11/private/RHID3D11.cpp similarity index 100% rename from source/runtime/rhi/d3d12/private/D3D12.cpp rename to source/runtime/rhi/d3d11/private/RHID3D11.cpp diff --git a/source/runtime/rhi/d3d11/public/RHID3D11.hpp b/source/runtime/rhi/d3d11/public/RHID3D11.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/d3d11/public/RHID3D11.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/rhi/d3d12/.gitignore b/source/runtime/rhi/d3d12/.gitignore index 43fc545..e69de29 100644 --- a/source/runtime/rhi/d3d12/.gitignore +++ b/source/runtime/rhi/d3d12/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/d3d12 directory diff --git a/source/runtime/rhi/d3d12/CMakeLists.txt b/source/runtime/rhi/d3d12/CMakeLists.txt index a6ca040..a0ba305 100644 --- a/source/runtime/rhi/d3d12/CMakeLists.txt +++ b/source/runtime/rhi/d3d12/CMakeLists.txt @@ -4,9 +4,7 @@ include(gp-build-tool) -if (NOT GP_USE_D3D12 OR NOT WIN32) - return() -endif() - gpStartModule(rhi/d3d12) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC rhi/base) gpEndModule() diff --git a/source/runtime/rhi/d3d12/docs/README.md b/source/runtime/rhi/d3d12/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/d3d12/docs/_category_.json b/source/runtime/rhi/d3d12/docs/_category_.json deleted file mode 100644 index 16efc29..0000000 --- a/source/runtime/rhi/d3d12/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "DirectX 12" -} diff --git a/source/runtime/rhi/metal/private/Metal.cpp b/source/runtime/rhi/d3d12/private/RHID3D12.cpp similarity index 100% rename from source/runtime/rhi/metal/private/Metal.cpp rename to source/runtime/rhi/d3d12/private/RHID3D12.cpp diff --git a/source/runtime/rhi/d3d12/public/RHID3D12.hpp b/source/runtime/rhi/d3d12/public/RHID3D12.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/d3d12/public/RHID3D12.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/rhi/docs/README.md b/source/runtime/rhi/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/docs/_category_.json b/source/runtime/rhi/docs/_category_.json deleted file mode 100644 index 29546de..0000000 --- a/source/runtime/rhi/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Render Hardware Interface (RHI)" -} diff --git a/source/runtime/rhi/metal/.gitignore b/source/runtime/rhi/metal/.gitignore index a15d3f2..e69de29 100644 --- a/source/runtime/rhi/metal/.gitignore +++ b/source/runtime/rhi/metal/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/metal directory diff --git a/source/runtime/rhi/metal/CMakeLists.txt b/source/runtime/rhi/metal/CMakeLists.txt index 26fd3f2..dbdffb8 100644 --- a/source/runtime/rhi/metal/CMakeLists.txt +++ b/source/runtime/rhi/metal/CMakeLists.txt @@ -4,9 +4,7 @@ include(gp-build-tool) -if (NOT GP_USE_METAL OR NOT APPLE) - return() -endif() - gpStartModule(rhi/metal) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC rhi/base) gpEndModule() diff --git a/source/runtime/rhi/metal/docs/README.md b/source/runtime/rhi/metal/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/metal/docs/_category_.json b/source/runtime/rhi/metal/docs/_category_.json deleted file mode 100644 index cfade5c..0000000 --- a/source/runtime/rhi/metal/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Metal" -} diff --git a/source/runtime/rhi/null/private/Null.cpp b/source/runtime/rhi/metal/private/RHIMetal.cpp similarity index 100% rename from source/runtime/rhi/null/private/Null.cpp rename to source/runtime/rhi/metal/private/RHIMetal.cpp diff --git a/source/runtime/rhi/metal/public/RHIMetal.hpp b/source/runtime/rhi/metal/public/RHIMetal.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/metal/public/RHIMetal.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/rhi/null/.gitignore b/source/runtime/rhi/null/.gitignore index c62423c..e69de29 100644 --- a/source/runtime/rhi/null/.gitignore +++ b/source/runtime/rhi/null/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/null directory diff --git a/source/runtime/rhi/null/CMakeLists.txt b/source/runtime/rhi/null/CMakeLists.txt index d5fcd2e..d3fb21b 100644 --- a/source/runtime/rhi/null/CMakeLists.txt +++ b/source/runtime/rhi/null/CMakeLists.txt @@ -5,4 +5,6 @@ include(gp-build-tool) gpStartModule(rhi/null) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC rhi/base) gpEndModule() diff --git a/source/runtime/rhi/null/docs/README.md b/source/runtime/rhi/null/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/null/docs/_category_.json b/source/runtime/rhi/null/docs/_category_.json deleted file mode 100644 index be6a06e..0000000 --- a/source/runtime/rhi/null/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Null" -} diff --git a/source/runtime/rhi/opengl/private/OpenGL.cpp b/source/runtime/rhi/null/private/RHINull.cpp similarity index 100% rename from source/runtime/rhi/opengl/private/OpenGL.cpp rename to source/runtime/rhi/null/private/RHINull.cpp diff --git a/source/runtime/rhi/null/public/RHINull.hpp b/source/runtime/rhi/null/public/RHINull.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/null/public/RHINull.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/rhi/opengl/.gitignore b/source/runtime/rhi/opengl/.gitignore index d1b4045..e69de29 100644 --- a/source/runtime/rhi/opengl/.gitignore +++ b/source/runtime/rhi/opengl/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/opengl directory diff --git a/source/runtime/rhi/opengl/CMakeLists.txt b/source/runtime/rhi/opengl/CMakeLists.txt index c8dcb53..38df969 100644 --- a/source/runtime/rhi/opengl/CMakeLists.txt +++ b/source/runtime/rhi/opengl/CMakeLists.txt @@ -4,9 +4,7 @@ include(gp-build-tool) -if (NOT GP_USE_OPENGL) - return() -endif() - gpStartModule(rhi/opengl) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC rhi/base) gpEndModule() diff --git a/source/runtime/rhi/opengl/docs/README.md b/source/runtime/rhi/opengl/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/opengl/docs/_category_.json b/source/runtime/rhi/opengl/docs/_category_.json deleted file mode 100644 index 886bac8..0000000 --- a/source/runtime/rhi/opengl/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "OpenGL" -} diff --git a/source/runtime/rhi/vulkan/private/Vulkan.cpp b/source/runtime/rhi/opengl/private/RHIOpenGL.cpp similarity index 100% rename from source/runtime/rhi/vulkan/private/Vulkan.cpp rename to source/runtime/rhi/opengl/private/RHIOpenGL.cpp diff --git a/source/runtime/rhi/opengl/public/RHIOpenGL.hpp b/source/runtime/rhi/opengl/public/RHIOpenGL.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/opengl/public/RHIOpenGL.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/runtime/rhi/vulkan/.gitignore b/source/runtime/rhi/vulkan/.gitignore index 3bdc930..e69de29 100644 --- a/source/runtime/rhi/vulkan/.gitignore +++ b/source/runtime/rhi/vulkan/.gitignore @@ -1,2 +0,0 @@ -# Inherit from the root .gitignore -# This file is for ignoring files specific to the runtime/rhi/vulkan directory diff --git a/source/runtime/rhi/vulkan/CMakeLists.txt b/source/runtime/rhi/vulkan/CMakeLists.txt index 0bc92a3..e557adf 100644 --- a/source/runtime/rhi/vulkan/CMakeLists.txt +++ b/source/runtime/rhi/vulkan/CMakeLists.txt @@ -4,9 +4,7 @@ include(gp-build-tool) -if (NOT GP_USE_VULKAN) - return() -endif() - gpStartModule(rhi/vulkan) + gpAddDependency(PUBLIC core) + gpAddDependency(PUBLIC rhi/base) gpEndModule() diff --git a/source/runtime/rhi/vulkan/docs/README.md b/source/runtime/rhi/vulkan/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/runtime/rhi/vulkan/docs/_category_.json b/source/runtime/rhi/vulkan/docs/_category_.json deleted file mode 100644 index feebd21..0000000 --- a/source/runtime/rhi/vulkan/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Vulkan" -} diff --git a/source/runtime/rhi/vulkan/private/RHIVulkan.cpp b/source/runtime/rhi/vulkan/private/RHIVulkan.cpp new file mode 100644 index 0000000..3113e46 --- /dev/null +++ b/source/runtime/rhi/vulkan/private/RHIVulkan.cpp @@ -0,0 +1,3 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com diff --git a/source/runtime/rhi/vulkan/public/RHIVulkan.hpp b/source/runtime/rhi/vulkan/public/RHIVulkan.hpp new file mode 100644 index 0000000..88b9360 --- /dev/null +++ b/source/runtime/rhi/vulkan/public/RHIVulkan.hpp @@ -0,0 +1,5 @@ +// Copyright (c) - Graphical Playground. All rights reserved. +// For more information, see https://graphical-playground/legal +// mailto:support AT graphical-playground DOT com + +#pragma once diff --git a/source/shaders/CMakeLists.txt b/source/shaders/CMakeLists.txt deleted file mode 100644 index 94fa359..0000000 --- a/source/shaders/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -# TODO: Add proper shaders build system diff --git a/source/shaders/docs/README.md b/source/shaders/docs/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/source/shaders/docs/_category_.json b/source/shaders/docs/_category_.json deleted file mode 100644 index 1b81a49..0000000 --- a/source/shaders/docs/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "Shaders" -} diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index c7cf76f..1fe6857 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,30 +1,3 @@ # Copyright (c) - Graphical Playground. All rights reserved. # For more information, see https://graphical-playground/legal # mailto:support AT graphical-playground DOT com - -# Cross-platform dependencies -add_subdirectory(catch2) -add_subdirectory(sdl3) - -# Graphics Backends -# Note: Automatically be excluded from the build if the platform doesn't support it -add_subdirectory(d3d12) -add_subdirectory(d3d11) -add_subdirectory(vulkan) -add_subdirectory(metal) -add_subdirectory(opengl) - -# Allocation Libraries -add_subdirectory(vma) -add_subdirectory(d3d12ma) - -# Shader Toolchain -add_subdirectory(spirv-cross) -add_subdirectory(spirv-headers) -add_subdirectory(spirv-tools) -add_subdirectory(spirv-reflect) -add_subdirectory(glslang) -add_subdirectory(dxc) - -# Profiling Tools -add_subdirectory(tracy) diff --git a/thirdparty/catch2/CMakeLists.txt b/thirdparty/catch2/CMakeLists.txt deleted file mode 100644 index 25b87d5..0000000 --- a/thirdparty/catch2/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if(NOT GP_BUILD_TESTS AND NOT GP_BUILD_BENCHMARKS) - return() -endif() - -gpFetchContent( - NAME Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.14.0 - REQUIRED_VERSION 3.14.0 - PACKAGE_NAME Catch2 - OPTIONS - "CATCH_BUILD_TESTING=OFF" - "CATCH_BUILD_EXAMPLES=OFF" - "CATCH_BUILD_EXTRA_TESTS=OFF" - "CATCH_ENABLE_COVERAGE=OFF" - "CATCH_ENABLE_WERROR=OFF" - "CATCH_INSTALL_DOCS=OFF" - "CATCH_INSTALL_EXTRAS=ON" -) - -if(TARGET Catch2) - gpSetTargetFolder(Catch2 "thirdparty/testing") - gpSetTargetFolder(Catch2WithMain "thirdparty/testing") - - list(APPEND CMAKE_MODULE_PATH "${catch2_SOURCE_DIR}/extras") - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE) -endif() diff --git a/thirdparty/catch2/LICENSE.md b/thirdparty/catch2/LICENSE.md deleted file mode 100644 index 36b7cd9..0000000 --- a/thirdparty/catch2/LICENSE.md +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/thirdparty/d3d11/CMakeLists.txt b/thirdparty/d3d11/CMakeLists.txt deleted file mode 100644 index b0cb4ad..0000000 --- a/thirdparty/d3d11/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_D3D11 OR NOT WIN32) - return() -endif() - -message(STATUS "[GP] D3D11 enabled (Provided by Windows SDK).") diff --git a/thirdparty/d3d11/LICENSE.md b/thirdparty/d3d11/LICENSE.md deleted file mode 100644 index cd72793..0000000 --- a/thirdparty/d3d11/LICENSE.md +++ /dev/null @@ -1,9 +0,0 @@ -# Direct3D 11 - -This project uses the Direct3D 11 API from Microsoft. - -Direct3D 11 is part of the Microsoft Windows SDK and is not open source. -Use of this API is subject to the Microsoft Software License Terms included with the Windows SDK -and/or Visual Studio. - -No Direct3D source code is distributed with this project. diff --git a/thirdparty/d3d12/CMakeLists.txt b/thirdparty/d3d12/CMakeLists.txt deleted file mode 100644 index 88578d7..0000000 --- a/thirdparty/d3d12/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_D3D12 OR NOT WIN32) - return() -endif() - -gpFetchContent( - NAME DirectXHeaders - GIT_REPOSITORY https://github.com/microsoft/DirectX-Headers.git - GIT_TAG v1.619.1 - REQUIRED_VERSION 1.619.1 - PACKAGE_NAME DirectX-Headers - OPTIONS - "BUILD_TESTING=OFF" -) - -if(TARGET DirectX-Headers) - gpSetTargetFolder(DirectX-Headers "thirdparty/graphics") - # DirectX-Headers also generates a GUIDs target - if(TARGET DirectX-Guids) - gpSetTargetFolder(DirectX-Guids "thirdparty/graphics") - endif() -endif() diff --git a/thirdparty/d3d12/LICENSE.md b/thirdparty/d3d12/LICENSE.md deleted file mode 100644 index b2f52a2..0000000 --- a/thirdparty/d3d12/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) Microsoft Corporation. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/thirdparty/d3d12ma/CMakeLists.txt b/thirdparty/d3d12ma/CMakeLists.txt deleted file mode 100644 index cc5ee6e..0000000 --- a/thirdparty/d3d12ma/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_D3D12 OR NOT WIN32) - return() -endif() - -gpFetchContent( - NAME D3D12MemoryAllocator - GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator.git - GIT_TAG v3.1.0 - REQUIRED_VERSION 3.1.0 - PACKAGE_NAME D3D12MemoryAllocator - OPTIONS - "D3D12MA_BUILD_SAMPLE=OFF" -) - -if(TARGET D3D12MemoryAllocator) - gpSetTargetFolder(D3D12MemoryAllocator "thirdparty/graphics/allocators") -endif() diff --git a/thirdparty/d3d12ma/LICENSE.md b/thirdparty/d3d12ma/LICENSE.md deleted file mode 100644 index 3d5a69a..0000000 --- a/thirdparty/d3d12ma/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/thirdparty/dxc/CMakeLists.txt b/thirdparty/dxc/CMakeLists.txt deleted file mode 100644 index 347593f..0000000 --- a/thirdparty/dxc/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(FetchContent) - -if(CMAKE_HOST_WIN32) - set(DXC_URL "https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.9.2602/dxc_2026_02_20.zip") -elseif(CMAKE_HOST_UNIX) - set(DXC_URL "https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.9.2602/linux_dxc_2026_02_20.x86_64.tar.gz") -else() - message(FATAL_ERROR "Unsupported host OS for pre-compiled DXC") -endif() - -FetchContent_Declare( - DXC_Binaries - URL ${DXC_URL} - DOWNLOAD_EXTRACT_TIMESTAMP TRUE -) - -FetchContent_MakeAvailable(DXC_Binaries) - -if(NOT TARGET dxcompiler) - add_library(dxcompiler SHARED IMPORTED) - - if(CMAKE_HOST_WIN32) - # On Windows, you link against the .lib and need the headers from /inc - set_target_properties(dxcompiler PROPERTIES - IMPORTED_LOCATION "${dxc_binaries_SOURCE_DIR}/bin/x64/dxcompiler.dll" - IMPORTED_IMPLIB "${dxc_binaries_SOURCE_DIR}/lib/x64/dxcompiler.lib" - INTERFACE_INCLUDE_DIRECTORIES "${dxc_binaries_SOURCE_DIR}/inc" - ) - elseif(CMAKE_HOST_UNIX) - # On Linux, you link directly to the .so and need headers from /include - set_target_properties(dxcompiler PROPERTIES - IMPORTED_LOCATION "${dxc_binaries_SOURCE_DIR}/lib/libdxcompiler.so" - INTERFACE_INCLUDE_DIRECTORIES "${dxc_binaries_SOURCE_DIR}/include" - ) - endif() -endif() - -# TODO: -# Because you are linking a pre-compiled shared library, the dxcompiler.dll (or .so) won't automatically move to -# your build folder where your executable is generated. When you try to run your asset compiler, your OS -# will complain that the DLL is missing. -# -# add_custom_command(TARGET __myTargetExportName POST_BUILD -# COMMAND ${CMAKE_COMMAND} -E copy_if_different -# "$" # Grabs the .dll/.so path automatically -# "$" # Where your .exe lives -# ) diff --git a/thirdparty/dxc/LICENSE.md b/thirdparty/dxc/LICENSE.md deleted file mode 100644 index 8987f9b..0000000 --- a/thirdparty/dxc/LICENSE.md +++ /dev/null @@ -1,601 +0,0 @@ -============================================================================== -LLVM Release License -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== -Copyrights and Licenses for Third Party Software Distributed with LLVM: -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - ------------------- - -Files: lib/Miniz/* include/miniz/* - -Copyright 2013-2014 RAD Game Tools and Valve Software -Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - -All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------------------- - -Files: lib/Miniz/miniz.c - -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to - ------------------- - -Files: lib/Support/* docs/SystemLibrary.rst - -Written by Henry Spencer. Not derived from licensed software. - -Permission is granted to anyone to use this software for any -purpose on any computer system, and to redistribute it freely, -subject to the following restrictions: - -1. The author is not responsible for the consequences of use of - this software, no matter how awful, even if they arise - from defects in it. - -2. The origin of this software must not be misrepresented, either - by explicit claim or by omission. - -3. Altered versions must be plainly marked as such, and must not - be misrepresented as being the original software. - ------------------- - -Files: include/llvm/Support/ConvertUTF.h - -Copyright 2001-2004 Unicode, Inc. - -Disclaimer - -This source code is provided as is by Unicode, Inc. No claims are -made as to fitness for any particular purpose. No warranties of any -kind are expressed or implied. The recipient agrees to determine -applicability of information provided. If this file has been -purchased on magnetic or optical media from Unicode, Inc., the -sole remedy for any claim will be exchange of defective media -within 90 days of receipt. - -Limitations on Rights to Redistribute This Code - -Unicode, Inc. hereby grants the right to freely use the information -supplied in this file in the creation of products supporting the -Unicode Standard, and to make copies of this file in any form -for internal or external distribution as long as this notice -remains attached. - ------------------- - -Files: include/llvm/Support/MD5.h - -This software was written by Alexander Peslyak in 2001. No copyright is -claimed, and the software is hereby placed in the public domain. -In case this attempt to disclaim copyright and place the software in the -public domain is deemed null and void, then the software is -Copyright (c) 2001 Alexander Peslyak and it is hereby released to the -general public under the following terms: - -Redistribution and use in source and binary forms, with or without -modification, are permitted. - -There's ABSOLUTELY NO WARRANTY, express or implied. - ------------------- - -Files: lib/Support/regstrlcpy.c - -Copyright (c) 1998 Todd C. Miller - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - - - ------------------- ------------------- - -THE FOLLOWING LICENSES ARE FOR BUILD AND TEST DEPENDENCIES ONLY. - ------------------- ------------------- - -Files: utils/unittest/googletest/* - -Copyright 2008, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------- - -Files: utils/unittest/googlemock/* - -Copyright 2008, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------- - -Files: test/YamlParser/* - -Copyright (c) 2006 Kirill Simonov - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------------------- - -Files: autoconf/config.guess - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - -Autoconf Exception - -As a special exception, the Free Software Foundation gives unlimited -permission to copy, distribute and modify the configure scripts that are the -output of Autoconf. You need not follow the terms of the GNU General Public -License when using or distributing such scripts, even though portions of the -text of Autoconf appear in them. The GNU General Public License (GPL) does -govern all other use of the material that constitutes the Autoconf program. - -Certain portions of the Autoconf source text are designed to be copied (in -certain cases, depending on the input) into the output of Autoconf. We call -these the "data" portions. The rest of the Autoconf source text consists of -comments plus executable code that decides which of the data portions to -output in any given case. We call these comments and executable code the "non- -data" portions. Autoconf never copies any of the non-data portions into its -output. - -This special exception to the GPL applies to versions of Autoconf released by -the Free Software Foundation. When you make and distribute a modified version -of Autoconf, you may extend this special exception to the GPL to apply to your -modified version as well, *unless* your modified version has the potential to -copy into its output some of the text that was the non-data portion of the -version that you started with. (In other words, unless your change moves or -copies text from the non-data portions to the data portions.) If your -modification has such potential, you must delete any notice of this special -exception to the GPL from your modified version. - - END OF TERMS AND CONDITIONS diff --git a/thirdparty/glslang/CMakeLists.txt b/thirdparty/glslang/CMakeLists.txt deleted file mode 100644 index 73f6477..0000000 --- a/thirdparty/glslang/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpFetchContent( - NAME Glslang - GIT_REPOSITORY https://github.com/KhronosGroup/glslang.git - GIT_TAG vulkan-sdk-1.4.341.0 - REQUIRED_VERSION 1.4.341 - PACKAGE_NAME Glslang - OPTIONS - "GLSLANG_TESTS=OFF" - "ENABLE_GLSLANG_INSTALL=OFF" - "ENABLE_HLSL=ON" -) - -if(TARGET glslang) - gpSetTargetFolder(glslang "thirdparty/graphics") - gpSetTargetFolder(glslang-default-resource-limits "thirdparty/graphics") - gpSetTargetFolder(MachineIndependent "thirdparty/graphics") - gpSetTargetFolder(GenericCodeGen "thirdparty/graphics") - gpSetTargetFolder(OSDependent "thirdparty/graphics") - gpSetTargetFolder(SPIRV "thirdparty/graphics") -endif() diff --git a/thirdparty/glslang/LICENSE.md b/thirdparty/glslang/LICENSE.md deleted file mode 100644 index 1ea89c0..0000000 --- a/thirdparty/glslang/LICENSE.md +++ /dev/null @@ -1,1013 +0,0 @@ -Here, glslang proper means core GLSL parsing, HLSL parsing, and SPIR-V code -generation. Glslang proper requires use of a number of licenses, one that covers -preprocessing and others that covers non-preprocessing. - -Bison was removed long ago. You can build glslang from the source grammar, -using tools of your choice, without using bison or any bison files. - -Other parts, outside of glslang proper, include: - -- gl_types.h, only needed for OpenGL-like reflection, and can be left out of - a parse and codegen project. See it for its license. - -- update_glslang_sources.py, which is not part of the project proper and does - not need to be used. - -- Google tests and SPIR-V tools, and anything in the external subdirectory - are external and optional; see them for their respective licenses. - --------------------------------------------------------------------------------- - -The core of glslang-proper, minus the preprocessor is licenced as follows: - --------------------------------------------------------------------------------- -3-Clause BSD License --------------------------------------------------------------------------------- - -// -// Copyright (C) 2015-2018 Google, Inc. -// Copyright (C) -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// Neither the name of 3Dlabs Inc. Ltd. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// - - --------------------------------------------------------------------------------- -2-Clause BSD License --------------------------------------------------------------------------------- - -Copyright 2020 The Khronos Group Inc - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -The MIT License --------------------------------------------------------------------------------- - -Copyright 2020 The Khronos Group Inc - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --------------------------------------------------------------------------------- -APACHE LICENSE, VERSION 2.0 --------------------------------------------------------------------------------- - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - --------------------------------------------------------------------------------- -GPL 3 with special bison exception --------------------------------------------------------------------------------- - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - -Bison Exception - -As a special exception, you may create a larger work that contains part or all -of the Bison parser skeleton and distribute that work under terms of your -choice, so long as that work isn't itself a parser generator using the skeleton -or a modified version thereof as a parser skeleton. Alternatively, if you -modify or redistribute the parser skeleton itself, you may (at your option) -remove this special exception, which will cause the skeleton and the resulting -Bison output files to be licensed under the GNU General Public License without -this special exception. - -This special exception was added by the Free Software Foundation in version -2.2 of Bison. - - END OF TERMS AND CONDITIONS - --------------------------------------------------------------------------------- -================================================================================ --------------------------------------------------------------------------------- - -The preprocessor has the core licenses stated above, plus additional licences: - -/****************************************************************************\ -Copyright (c) 2002, NVIDIA Corporation. - -NVIDIA Corporation("NVIDIA") supplies this software to you in -consideration of your agreement to the following terms, and your use, -installation, modification or redistribution of this NVIDIA software -constitutes acceptance of these terms. If you do not agree with these -terms, please do not use, install, modify or redistribute this NVIDIA -software. - -In consideration of your agreement to abide by the following terms, and -subject to these terms, NVIDIA grants you a personal, non-exclusive -license, under NVIDIA's copyrights in this original NVIDIA software (the -"NVIDIA Software"), to use, reproduce, modify and redistribute the -NVIDIA Software, with or without modifications, in source and/or binary -forms; provided that if you redistribute the NVIDIA Software, you must -retain the copyright notice of NVIDIA, this notice and the following -text and disclaimers in all such redistributions of the NVIDIA Software. -Neither the name, trademarks, service marks nor logos of NVIDIA -Corporation may be used to endorse or promote products derived from the -NVIDIA Software without specific prior written permission from NVIDIA. -Except as expressly stated in this notice, no other rights or licenses -express or implied, are granted by NVIDIA herein, including but not -limited to any patent rights that may be infringed by your derivative -works or by other works in which the NVIDIA Software may be -incorporated. No hardware is licensed hereunder. - -THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, -INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR -ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER -PRODUCTS. - -IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, -INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY -OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE -NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, -TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF -NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -\****************************************************************************/ - -/* -** Copyright (c) 2014-2016 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and/or associated documentation files (the "Materials"), -** to deal in the Materials without restriction, including without limitation -** the rights to use, copy, modify, merge, publish, distribute, sublicense, -** and/or sell copies of the Materials, and to permit persons to whom the -** Materials are furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Materials. -** -** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS -** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS -** IN THE MATERIALS. -*/ diff --git a/thirdparty/gp-build-tool b/thirdparty/gp-build-tool new file mode 160000 index 0000000..74f0939 --- /dev/null +++ b/thirdparty/gp-build-tool @@ -0,0 +1 @@ +Subproject commit 74f09393100c37d104ba75cabbddb847b3e9e64a diff --git a/thirdparty/metal/CMakeLists.txt b/thirdparty/metal/CMakeLists.txt deleted file mode 100644 index 971754c..0000000 --- a/thirdparty/metal/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_METAL OR NOT APPLE) - return() -endif() - -find_library(METAL_FRAMEWORK Metal REQUIRED) -if(METAL_FRAMEWORK) - # You will link your rendering target against ${METAL_FRAMEWORK} - message(STATUS "[GP] Metal system framework found.") -endif() diff --git a/thirdparty/metal/LICENSE.md b/thirdparty/metal/LICENSE.md deleted file mode 100644 index 98112c5..0000000 --- a/thirdparty/metal/LICENSE.md +++ /dev/null @@ -1,8 +0,0 @@ -# Metal - -This project uses the Metal graphics API from Apple. - -Metal is provided as part of Apple’s developer tools and SDKs and is not open source. -Use of this API is subject to the Apple Developer Program License Agreement and Xcode license terms. - -No Metal source code is distributed with this project. diff --git a/thirdparty/opengl/CMakeLists.txt b/thirdparty/opengl/CMakeLists.txt deleted file mode 100644 index eac8495..0000000 --- a/thirdparty/opengl/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_OPENGL) - return() -endif() - -find_package(OpenGL REQUIRED) -if(OpenGL_FOUND) - # You will link your rendering target against OpenGL::GL - message(STATUS "[GP] OpenGL system library found.") -endif() diff --git a/thirdparty/opengl/LICENSE.md b/thirdparty/opengl/LICENSE.md deleted file mode 100644 index 261eeb9..0000000 --- a/thirdparty/opengl/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/thirdparty/sdl3/CMakeLists.txt b/thirdparty/sdl3/CMakeLists.txt deleted file mode 100644 index b9ed773..0000000 --- a/thirdparty/sdl3/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -gpFetchContent( - NAME SDL3 - GIT_REPOSITORY https://github.com/libsdl-org/SDL.git - GIT_TAG release-3.4.0 - PACKAGE_NAME SDL3 - REQUIRED_VERSION 3.4.0 - OPTIONS - "SDL_SHARED=OFF" - "SDL_STATIC=ON" - "SDL_TEST=OFF" -) - -if(TARGET SDL3) - gpSetTargetFolder(SDL_uclibc "thirdparty/sdl3") - gpSetTargetFolder(SDL3 "thirdparty/sdl3") - gpSetTargetFolder(SDL3-static "thirdparty/sdl3") -endif() diff --git a/thirdparty/sdl3/LICENSE.md b/thirdparty/sdl3/LICENSE.md deleted file mode 100644 index 36b7cd9..0000000 --- a/thirdparty/sdl3/LICENSE.md +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/thirdparty/spirv-cross/CMakeLists.txt b/thirdparty/spirv-cross/CMakeLists.txt deleted file mode 100644 index 683df39..0000000 --- a/thirdparty/spirv-cross/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if(NOT GP_BUILD_EDITOR) - return() -endif() - -gpFetchContent( - NAME SPIRV-Cross - GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Cross.git - GIT_TAG vulkan-sdk-1.4.341.0 - REQUIRED_VERSION 1.4.341 - PACKAGE_NAME SPIRV-Cross - OPTIONS - "SPIRV_CROSS_CLI=OFF" - "SPIRV_CROSS_TESTING=OFF" - "SPIRV_CROSS_SHARED=OFF" - "SPIRV_CROSS_STATIC=ON" -) - -if(TARGET spirv-cross-core) - gpSetTargetFolder(spirv-cross-core "thirdparty/graphics") - gpSetTargetFolder(spirv-cross-glsl "thirdparty/graphics") - gpSetTargetFolder(spirv-cross-hlsl "thirdparty/graphics") - gpSetTargetFolder(spirv-cross-msl "thirdparty/graphics") - gpSetTargetFolder(spirv-cross-cpp "thirdparty/graphics") - gpSetTargetFolder(spirv-cross-reflect "thirdparty/graphics") - gpSetTargetFolder(spirv-cross-c "thirdparty/graphics") -endif() diff --git a/thirdparty/spirv-cross/LICENSE.md b/thirdparty/spirv-cross/LICENSE.md deleted file mode 100644 index d645695..0000000 --- a/thirdparty/spirv-cross/LICENSE.md +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/thirdparty/spirv-headers/CMakeLists.txt b/thirdparty/spirv-headers/CMakeLists.txt deleted file mode 100644 index 82d11ab..0000000 --- a/thirdparty/spirv-headers/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if(NOT GP_BUILD_EDITOR) - return() -endif() - -gpFetchContent( - NAME SPIRV-Headers - GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Headers.git - GIT_TAG vulkan-sdk-1.4.341.0 - REQUIRED_VERSION 1.4.341 - PACKAGE_NAME SPIRV-Headers - OPTIONS - "SPIRV_HEADERS_ENABLE_TESTS=OFF" - "SPIRV_HEADERS_ENABLE_INSTALL=OFF" -) - -if(TARGET SPIRV-Headers) - gpSetTargetFolder(SPIRV-Headers "thirdparty/graphics") -endif() diff --git a/thirdparty/spirv-headers/LICENSE.md b/thirdparty/spirv-headers/LICENSE.md deleted file mode 100644 index 845537e..0000000 --- a/thirdparty/spirv-headers/LICENSE.md +++ /dev/null @@ -1,501 +0,0 @@ -Files: All files except for those called out below. -Copyright (c) 2015-2024 The Khronos Group Inc. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. - -MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS -KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS -SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT - https://www.khronos.org/registry/ - -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ---- - -Files: include/spirv/spir-v.xml -Copyright (c) 2015-2024 The Khronos Group Inc. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. - -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ---- - -Files: tools/buildHeaders/jsoncpp/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== - ---- - -Files: **.md, WORKSPACE, .git** - -Attribution 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution 4.0 International Public License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution 4.0 International Public License ("Public License"). To the -extent this Public License may be interpreted as a contract, You are -granted the Licensed Rights in consideration of Your acceptance of -these terms and conditions, and the Licensor grants You such rights in -consideration of benefits the Licensor receives from making the -Licensed Material available under these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - d. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - e. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - f. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - g. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - h. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - i. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - j. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - k. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material; and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/thirdparty/spirv-reflect/CMakeLists.txt b/thirdparty/spirv-reflect/CMakeLists.txt deleted file mode 100644 index a0b0118..0000000 --- a/thirdparty/spirv-reflect/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if(NOT GP_BUILD_EDITOR) - return() -endif() - -gpFetchContent( - NAME SPIRV-Reflect - GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Reflect.git - GIT_TAG vulkan-sdk-1.4.341.0 - REQUIRED_VERSION 1.4.341 - PACKAGE_NAME SPIRV-Reflect - OPTIONS - "SPIRV_REFLECT_BUILD_TESTS=OFF" - "SPIRV_REFLECT_BUILD_EXECUTABLES=OFF" -) - -if(TARGET spirv-reflect) - # SPIRV-Reflect exposes three linkable targets; all three need warning suppression - # because they share the same problematic headers (spirv.h trailing-comma enumerators). - set(_SPIRV_REFLECT_TARGETS spirv-reflect spirv-reflect-static spirv-reflect-pp) - - foreach(_target IN LISTS _SPIRV_REFLECT_TARGETS) - if(TARGET ${_target}) - if(MSVC) - # /W0 - suppress all MSVC-level diagnostics - # /WX- - prevent any remaining warnings from being promoted to errors - target_compile_options(${_target} PRIVATE /W0 /WX-) - - # clang-cl accepts MSVC flags at the driver level, but clang-specific - # diagnostics (like -Wc++98-compat-pedantic) live in the clang frontend - # and must be silenced through the /clang: passthrough prefix. - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - target_compile_options(${_target} PRIVATE /clang:-Wno-everything) - endif() - else() - # GCC / vanilla Clang: -w disables all warnings outright - target_compile_options(${_target} PRIVATE -w) - endif() - - gpSetTargetFolder(${_target} "thirdparty/graphics") - endif() - endforeach() -endif() diff --git a/thirdparty/spirv-reflect/LICENSE.md b/thirdparty/spirv-reflect/LICENSE.md deleted file mode 100644 index 261eeb9..0000000 --- a/thirdparty/spirv-reflect/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/thirdparty/spirv-tools/CMakeLists.txt b/thirdparty/spirv-tools/CMakeLists.txt deleted file mode 100644 index fe7649b..0000000 --- a/thirdparty/spirv-tools/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if(NOT GP_BUILD_EDITOR) - return() -endif() - -gpFetchContent( - NAME SPIRV-Tools - GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Tools.git - GIT_TAG vulkan-sdk-1.4.341.0 - REQUIRED_VERSION 1.4.341 - PACKAGE_NAME SPIRV-Tools - OPTIONS - "SPIRV_SKIP_TESTS=ON" - "SPIRV_SKIP_EXECUTABLES=ON" - "SPIRV_WERROR=OFF" -) - -if(TARGET SPIRV-Tools) - gpSetTargetFolder(SPIRV-Tools "thirdparty/graphics") - gpSetTargetFolder(SPIRV-Tools-opt "thirdparty/graphics") - gpSetTargetFolder(SPIRV-Tools-link "thirdparty/graphics") - gpSetTargetFolder(SPIRV-Tools-reduce "thirdparty/graphics") - gpSetTargetFolder(SPIRV-Tools-shared "thirdparty/graphics") -endif() diff --git a/thirdparty/spirv-tools/LICENSE.md b/thirdparty/spirv-tools/LICENSE.md deleted file mode 100644 index d645695..0000000 --- a/thirdparty/spirv-tools/LICENSE.md +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/thirdparty/tracy/CMakeLists.txt b/thirdparty/tracy/CMakeLists.txt deleted file mode 100644 index a2d169f..0000000 --- a/thirdparty/tracy/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if(NOT GP_ENABLE_PROFILING) - return() -endif() - -gpFetchContent( - NAME Tracy - GIT_REPOSITORY https://github.com/wolfpld/tracy.git - GIT_TAG v0.13.1 - REQUIRED_VERSION 0.13.1 - PACKAGE_NAME Tracy - OPTIONS - "TRACY_ENABLE=ON" - "TRACY_STATIC=ON" -) - -if(TARGET TracyClient) - gpSetTargetFolder(TracyClient "thirdparty/profiling") -endif() diff --git a/thirdparty/tracy/LICENSE.md b/thirdparty/tracy/LICENSE.md deleted file mode 100644 index 5abdf12..0000000 --- a/thirdparty/tracy/LICENSE.md +++ /dev/null @@ -1,27 +0,0 @@ -Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the -3-clause BSD license. - -Copyright (c) 2017-2026, Bartosz Taudul -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/vma/CMakeLists.txt b/thirdparty/vma/CMakeLists.txt deleted file mode 100644 index 4e9fb87..0000000 --- a/thirdparty/vma/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_VULKAN) - return() -endif() - -gpFetchContent( - NAME VulkanMemoryAllocator - GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git - GIT_TAG v3.3.0 - REQUIRED_VERSION 3.3.0 - PACKAGE_NAME VulkanMemoryAllocator - OPTIONS - "VMA_BUILD_SAMPLE=OFF" - "VMA_BUILD_DOCUMENTATION=OFF" -) - -if(TARGET VulkanMemoryAllocator) - gpSetTargetFolder(VulkanMemoryAllocator "thirdparty/graphics/allocators") -endif() diff --git a/thirdparty/vma/LICENSE.md b/thirdparty/vma/LICENSE.md deleted file mode 100644 index be95175..0000000 --- a/thirdparty/vma/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2017-2026 Advanced Micro Devices, Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/thirdparty/vulkan/CMakeLists.txt b/thirdparty/vulkan/CMakeLists.txt deleted file mode 100644 index 3c65fe0..0000000 --- a/thirdparty/vulkan/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) - Graphical Playground. All rights reserved. -# For more information, see https://graphical-playground/legal -# mailto:support AT graphical-playground DOT com - -include(gp-build-tool) - -if (NOT GP_USE_VULKAN) - return() -endif() - -gpFetchContent( - NAME VulkanHeaders - GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers.git - GIT_TAG v1.4.341 - REQUIRED_VERSION 1.4.341 - PACKAGE_NAME VulkanHeaders - OPTIONS - "VULKAN_HEADERS_ENABLE_TESTS=OFF" - "VULKAN_HEADERS_ENABLE_INSTALL=OFF" -) - -if(TARGET Vulkan-Headers) - gpSetTargetFolder(Vulkan-Headers "thirdparty/graphics") -endif() diff --git a/thirdparty/vulkan/LICENSE.md b/thirdparty/vulkan/LICENSE.md deleted file mode 100644 index d6a0648..0000000 --- a/thirdparty/vulkan/LICENSE.md +++ /dev/null @@ -1,18 +0,0 @@ -Copyright 2015-2023 The Khronos Group Inc. - -Files in this repository fall under one of these licenses: - -- `Apache-2.0` -- `MIT` - -Note: With the exception of `parse_dependency.py` the files using `MIT` license -also fall under `Apache-2.0`. Example: - -``` -SPDX-License-Identifier: Apache-2.0 OR MIT -``` - -Full license text of these licenses is available at: - - * Apache-2.0: https://opensource.org/licenses/Apache-2.0 - * MIT: https://opensource.org/licenses/MIT