Compare commits
88 Commits
bbae30b244
...
custom_pla
| Author | SHA1 | Date | |
|---|---|---|---|
| 086c73f058 | |||
| 339f5c8cd8 | |||
| 18c0a7099d | |||
| 540c7fbce8 | |||
| cbcd699ab0 | |||
| ff27caab4f | |||
| fe4c49d092 | |||
| 037c62bf12 | |||
| 494d766741 | |||
| 83f0c01e29 | |||
| 4ff739d625 | |||
| 7cd38604a7 | |||
| 733fca41ef | |||
| 55a8c54119 | |||
| 27754a56d7 | |||
| fcf9c6adcb | |||
| e6c0a60ea9 | |||
| 5252ba84c9 | |||
| 73041e994d | |||
| 3ddc2b3d97 | |||
| e91c2aa9f1 | |||
| 38b7221fa0 | |||
| 8bfb59cd20 | |||
| 2535e1ac4b | |||
| f173c3e7cd | |||
| cc4d85c393 | |||
| d6e31a89b0 | |||
| 74fb525453 | |||
| b9de039a10 | |||
| 9f96155856 | |||
| d2be083a8f | |||
| efe56b3699 | |||
| b7d8426e86 | |||
| 2cb41e1437 | |||
| 0f721f57ea | |||
| 4a3639ecb4 | |||
| ff4d6efedc | |||
| 9dc9ed4ed1 | |||
| 5e04eb0ca6 | |||
| 3d42dea9eb | |||
| 3d4ea4398a | |||
| 7aafa4c9aa | |||
| 8124ea2ae5 | |||
| d02a51fd8d | |||
| 7493b5252a | |||
| 7ea2710ee0 | |||
| f9de242b87 | |||
| 2117e4347c | |||
| 5ab2952e83 | |||
| 65573f28e4 | |||
| 73333b4c67 | |||
| ab1c7d94be | |||
| 86286e84d7 | |||
| c72d1afe32 | |||
| f1552b89b1 | |||
| 89f59c75f3 | |||
| 6ae682aff6 | |||
| 5e0dc78210 | |||
| 4c0d36c933 | |||
| cc20af7504 | |||
| 649e39c70e | |||
| 2573de0904 | |||
| 17d8218124 | |||
| 012052641d | |||
| a33bf5206f | |||
| 0afaae72ac | |||
| 0eeb7ae3cf | |||
| e2ea22f12d | |||
| 9ea63478e5 | |||
| 9010650ceb | |||
| 516d9f4977 | |||
| f38cf5fb51 | |||
| f2ff863b3a | |||
| 1573033b52 | |||
| 37fba8faad | |||
| cbaf69310e | |||
| d8954eafe5 | |||
| 2541c8c637 | |||
| bd7f0829f4 | |||
| 31e3c26b66 | |||
| 4d8466851c | |||
| 909be55ed3 | |||
| 6d3c276bfe | |||
| 9d35daa494 | |||
| 079b0b27ee | |||
| 1c67c13a27 | |||
| db7d52c86c | |||
| 096e82f47a |
7
.gdbinit
Normal file
7
.gdbinit
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
python
|
||||||
|
import sys, os.path
|
||||||
|
print(os.path.abspath("./gdb"))
|
||||||
|
sys.path.insert(0, os.path.abspath("./gdb"))
|
||||||
|
import fennec
|
||||||
|
fennec.register_printers(gdb.current_objfile())
|
||||||
|
end
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,2 +1,6 @@
|
|||||||
|
.*/
|
||||||
/build/
|
/build/
|
||||||
/docs/
|
/docs/
|
||||||
|
/bin/
|
||||||
|
/lib/
|
||||||
|
/doxy/README.md
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "external/cpptrace"]
|
||||||
|
path = external/cpptrace
|
||||||
|
url = https://github.com/jeremy-rifkin/cpptrace.git
|
||||||
221
CMakeLists.txt
221
CMakeLists.txt
@@ -1,56 +1,161 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.30)
|
cmake_minimum_required(VERSION 3.30)
|
||||||
project(fennec)
|
project(fennec)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 26)
|
# External dependencies should be loaded here
|
||||||
set(CMAKE_C_STANDARD 26)
|
add_subdirectory(external/cpptrace)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
set(CMAKE_C_STANDARD 23)
|
||||||
|
set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
add_custom_target(fennec-dependencies
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo "Running dependencies."
|
||||||
|
COMMENT "Running dependencies."
|
||||||
|
)
|
||||||
|
|
||||||
|
macro(fennec_add_sources)
|
||||||
|
list(APPEND FENNEC_EXTRA_SOURCES ${ARGN})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(fennec_add_definitions)
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS ${ARGN})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(fennec_add_link_libraries)
|
||||||
|
list(APPEND FENNEC_LINK_LIBRARIES ${ARGN})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# include scripts
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/build.cmake")
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/compiler.cmake")
|
||||||
|
|
||||||
|
# common defines
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS "NULL=0")
|
||||||
|
|
||||||
# find dependencies
|
# find dependencies
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
|
fennec_check_platform()
|
||||||
|
|
||||||
# any necessary include directories
|
# any necessary include directories
|
||||||
include_directories(include)
|
include_directories(${FENNEC_SOURCE_DIR}/include)
|
||||||
|
|
||||||
# Metaprogramming is a dependency for generating various type info before compilation of the engine.
|
# Metaprogramming is a dependency for generating various type info before compilation of the engine.
|
||||||
add_subdirectory(metaprogramming)
|
add_subdirectory(metaprogramming)
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME})
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME})
|
||||||
|
|
||||||
|
# add the test suite as a sub-project
|
||||||
|
add_subdirectory(test)
|
||||||
|
|
||||||
add_library(fennec STATIC
|
add_library(fennec STATIC
|
||||||
|
|
||||||
# CORE =================================================================================================================
|
# CORE =================================================================================================================
|
||||||
include/fennec/core/engine.h source/core/engine.cpp
|
include/fennec/core/engine.h source/core/engine.cpp
|
||||||
|
include/fennec/core/event.h source/core/event.cpp
|
||||||
|
|
||||||
|
include/fennec/core/system.h
|
||||||
|
|
||||||
|
|
||||||
|
# SCENE ================================================================================================================
|
||||||
|
include/fennec/scene/scene.h
|
||||||
|
include/fennec/scene/component.h
|
||||||
|
|
||||||
|
|
||||||
# CONTAINERS ===========================================================================================================
|
# CONTAINERS ===========================================================================================================
|
||||||
|
include/fennec/containers/containers.h
|
||||||
|
|
||||||
include/fennec/containers/array.h
|
include/fennec/containers/array.h
|
||||||
|
include/fennec/containers/deque.h
|
||||||
include/fennec/containers/dynarray.h
|
include/fennec/containers/dynarray.h
|
||||||
|
include/fennec/containers/graph.h
|
||||||
|
include/fennec/containers/list.h
|
||||||
|
include/fennec/containers/map.h
|
||||||
|
include/fennec/containers/object_pool.h
|
||||||
|
include/fennec/containers/optional.h
|
||||||
|
include/fennec/containers/pair.h
|
||||||
|
include/fennec/containers/rdtree.h
|
||||||
|
include/fennec/containers/set.h
|
||||||
|
include/fennec/containers/traversal.h
|
||||||
|
include/fennec/containers/tuple.h
|
||||||
|
include/fennec/containers/variant.h
|
||||||
|
|
||||||
|
|
||||||
|
include/fennec/containers/detail/_tuple.h
|
||||||
|
|
||||||
|
|
||||||
# LANG =================================================================================================================
|
# LANG =================================================================================================================
|
||||||
|
include/fennec/lang/lang.h
|
||||||
|
include/fennec/lang/metaprogramming.h
|
||||||
|
|
||||||
|
include/fennec/lang/bits.h
|
||||||
include/fennec/lang/constants.h
|
include/fennec/lang/constants.h
|
||||||
include/fennec/lang/conditional_types.h
|
include/fennec/lang/conditional_types.h
|
||||||
|
include/fennec/lang/hashing.h
|
||||||
include/fennec/lang/intrinsics.h
|
include/fennec/lang/intrinsics.h
|
||||||
include/fennec/lang/limits.h
|
include/fennec/lang/limits.h
|
||||||
include/fennec/lang/numeric_transforms.h
|
include/fennec/lang/numeric_transforms.h
|
||||||
include/fennec/lang/sequences.h
|
include/fennec/lang/const_sequences.h
|
||||||
|
include/fennec/lang/startup.h
|
||||||
|
include/fennec/lang/type_identity.h
|
||||||
|
include/fennec/lang/type_operators.h
|
||||||
|
include/fennec/lang/type_sequences.h
|
||||||
include/fennec/lang/type_traits.h
|
include/fennec/lang/type_traits.h
|
||||||
include/fennec/lang/type_transforms.h
|
include/fennec/lang/type_transforms.h
|
||||||
|
include/fennec/lang/typeuuid.h
|
||||||
include/fennec/lang/types.h
|
include/fennec/lang/types.h
|
||||||
include/fennec/lang/utility.h
|
include/fennec/lang/utility.h
|
||||||
include/fennec/lang/variadics.h
|
include/fennec/lang/integer.h
|
||||||
|
|
||||||
include/fennec/lang/detail/__numeric_transforms.h
|
include/fennec/lang/assert.h source/lang/assert.cpp
|
||||||
include/fennec/lang/detail/__type_traits.h
|
|
||||||
include/fennec/lang/detail/__variadics.h
|
|
||||||
|
include/fennec/lang/detail/_bits.h
|
||||||
|
include/fennec/lang/detail/_int.h
|
||||||
|
include/fennec/lang/detail/_numeric_transforms.h
|
||||||
|
include/fennec/lang/detail/_stdlib.h
|
||||||
|
include/fennec/lang/detail/_type_traits.h
|
||||||
|
include/fennec/lang/detail/_type_transforms.h
|
||||||
|
include/fennec/lang/detail/_type_sequences.h
|
||||||
|
include/fennec/lang/detail/_typeuuid.h
|
||||||
|
|
||||||
|
|
||||||
# MEMORY ===============================================================================================================
|
# MEMORY ===============================================================================================================
|
||||||
include/fennec/memory/allocator.h
|
|
||||||
include/fennec/lang/bits.h
|
|
||||||
include/fennec/memory/memory.h
|
|
||||||
include/fennec/memory/new.h source/memory/new.cpp
|
include/fennec/memory/new.h source/memory/new.cpp
|
||||||
include/fennec/memory/pointers.h
|
|
||||||
include/fennec/memory/ptr_traits.h
|
|
||||||
|
|
||||||
include/fennec/memory/detail/__ptr_traits.h
|
include/fennec/memory/allocator.h
|
||||||
|
include/fennec/memory/bytes.h
|
||||||
|
include/fennec/memory/common.h
|
||||||
|
include/fennec/memory/memory.h
|
||||||
|
include/fennec/memory/pointers.h
|
||||||
|
include/fennec/memory/pointer_traits.h
|
||||||
|
|
||||||
|
include/fennec/memory/detail/_ptr_traits.h
|
||||||
|
|
||||||
|
# DEBUG ================================================================================================================
|
||||||
|
source/debug/assert_impl.cpp
|
||||||
|
|
||||||
|
|
||||||
# MATH =================================================================================================================
|
# MATH =================================================================================================================
|
||||||
@@ -74,35 +179,65 @@ add_library(fennec STATIC
|
|||||||
include/fennec/math/trigonometric.h
|
include/fennec/math/trigonometric.h
|
||||||
include/fennec/math/relational.h
|
include/fennec/math/relational.h
|
||||||
|
|
||||||
include/fennec/math/detail/__fwd.h
|
include/fennec/math/ext/common.h
|
||||||
include/fennec/math/detail/__types.h
|
include/fennec/math/ext/constants.h
|
||||||
include/fennec/math/detail/__vector_traits.h
|
include/fennec/math/ext/primes.h
|
||||||
include/fennec/lang/lang.h
|
include/fennec/math/ext/quaternion.h
|
||||||
|
include/fennec/math/ext/transform.h
|
||||||
|
include/fennec/math/ext/trigonometric.h
|
||||||
|
|
||||||
|
|
||||||
|
include/fennec/math/detail/_fwd.h
|
||||||
|
include/fennec/math/detail/_math.h
|
||||||
|
include/fennec/math/detail/_matrix.h
|
||||||
|
include/fennec/math/detail/_types.h
|
||||||
|
include/fennec/math/detail/_vector_traits.h
|
||||||
|
|
||||||
|
|
||||||
|
# langproc ================================================================================================================
|
||||||
|
|
||||||
|
# Strings
|
||||||
|
include/fennec/langproc/strings/cstring.h
|
||||||
|
include/fennec/langproc/strings/locale.h
|
||||||
|
include/fennec/langproc/strings/string.h
|
||||||
|
|
||||||
|
include/fennec/langproc/strings/detail/_ctype.h
|
||||||
|
|
||||||
|
# Filesystem
|
||||||
|
include/fennec/langproc/filesystem/file.h source/langproc/filesystem/file.cpp
|
||||||
|
include/fennec/langproc/filesystem/path.h source/langproc/filesystem/path.cpp
|
||||||
|
|
||||||
|
|
||||||
|
# PLATFORM =============================================================================================================
|
||||||
|
|
||||||
|
include/fennec/platform/interface/fwd.h
|
||||||
|
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
|
||||||
|
include/fennec/platform/interface/display.h source/platform/interface/display.cpp
|
||||||
|
include/fennec/platform/interface/gfxcontext.h
|
||||||
|
include/fennec/platform/interface/gfxsurface.h
|
||||||
|
|
||||||
|
|
||||||
|
# EXTRA SOURCES ========================================================================================================
|
||||||
|
|
||||||
|
${FENNEC_EXTRA_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
# add metaprogramming templates as a dependency and also force documentation to be generated when fennec is compiled
|
add_dependencies(fennec metaprogramming fennec-dependencies)
|
||||||
if(DOXYGEN_FOUND)
|
|
||||||
add_dependencies(fennec fennecdocs metaprogramming)
|
|
||||||
else()
|
|
||||||
add_dependencies(fennec metaprogramming)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Compiler Warning Flags
|
target_compile_definitions(fennec PUBLIC
|
||||||
if(MSVC)
|
${FENNEC_COMPILE_DEFINITIONS}
|
||||||
add_compile_options("/W4" "/WX") # All MSVC Warnings throw as Errors
|
)
|
||||||
else()
|
|
||||||
add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror") # All gcc/etc. Warnings throw as errors
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#target_compile_options(fennec PUBLIC "-mavx" "-mavx2" "-mavx512f") # SIMD Instructions, currently unused
|
|
||||||
|
|
||||||
target_link_options(fennec PRIVATE "-nostdlib") # Do not compile base fennec library with c++ stdlib
|
target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not compile base fennec library with c++ stdlib
|
||||||
# fennec does not use the C++ stdlib because it is bloated, difficult to read, and implementation defined.
|
# fennec does not use the C++ stdlib because it is bloated, difficult to read, and implementation defined.
|
||||||
# This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated
|
# This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated
|
||||||
|
|
||||||
|
target_link_libraries(fennec PRIVATE
|
||||||
|
${FENNEC_LINK_LIBRARIES}
|
||||||
|
|
||||||
# add the test suite as a sub-project
|
cpptrace::cpptrace
|
||||||
add_subdirectory(test)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -112,10 +247,12 @@ add_subdirectory(test)
|
|||||||
file(COPY logo DESTINATION docs/logo)
|
file(COPY logo DESTINATION docs/logo)
|
||||||
|
|
||||||
if(DOXYGEN_FOUND)
|
if(DOXYGEN_FOUND)
|
||||||
set(DOXY_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/docs")
|
add_dependencies(fennec fennecdocs)
|
||||||
get_filename_component(DOXYGEN_PROJECT_NAME ${PROJECT_SOURCE_DIR} NAME) # Set Doxy Project name to the name of the root dir
|
set(DOXY_OUTPUT_DIR "${FENNEC_SOURCE_DIR}/docs")
|
||||||
set(DOXYGEN_CONFIG_IN "${PROJECT_SOURCE_DIR}/doxy/Doxyfile.in") # Input config file with preprocessor arguments
|
set(DOXY_EXAMPLES_DIR "${FENNEC_SOURCE_DIR}/examples")
|
||||||
set(DOXYGEN_CONFIG_OUT "${PROJECT_SOURCE_DIR}/doxy/Doxyfile") # Generated config file from input
|
get_filename_component(DOXYGEN_PROJECT_NAME ${FENNEC_SOURCE_DIR} NAME) # Set Doxy Project name to the name of the root dir
|
||||||
|
set(DOXYGEN_CONFIG_IN "${FENNEC_SOURCE_DIR}/doxy/Doxyfile.in") # Input config file with preprocessor arguments
|
||||||
|
set(DOXYGEN_CONFIG_OUT "${FENNEC_SOURCE_DIR}/doxy/Doxyfile") # Generated config file from input
|
||||||
|
|
||||||
configure_file(${DOXYGEN_CONFIG_IN} ${DOXYGEN_CONFIG_OUT} @ONLY) # Execute preprocessing step
|
configure_file(${DOXYGEN_CONFIG_IN} ${DOXYGEN_CONFIG_OUT} @ONLY) # Execute preprocessing step
|
||||||
message("Doxygen Build Started.")
|
message("Doxygen Build Started.")
|
||||||
@@ -124,15 +261,17 @@ if(DOXYGEN_FOUND)
|
|||||||
# Target for building docs
|
# Target for building docs
|
||||||
add_custom_target(fennecdocs ALL
|
add_custom_target(fennecdocs ALL
|
||||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT}
|
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT}
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
WORKING_DIRECTORY ${FENNEC_SOURCE_DIR}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/logo/raster.png
|
COMMAND ${CMAKE_COMMAND} -E copy ${FENNEC_SOURCE_DIR}/logo/raster.png
|
||||||
${DOXY_OUTPUT_DIR}/logo/raster.png
|
${DOXY_OUTPUT_DIR}/logo/raster.png
|
||||||
COMMENT "Generating Doxygen Documentation"
|
COMMENT "Generating Doxygen Documentation"
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
|
add_dependencies(fennecdocs fennecdocs-clean)
|
||||||
|
|
||||||
# Target for cleaning docs
|
# Target for cleaning docs
|
||||||
add_custom_target(fennecdocs-clean ALL
|
add_custom_target(fennecdocs-clean ALL
|
||||||
COMMAND rm -r "${PROJECT_SOURCE_DIR}/docs/"
|
COMMAND ${CMAKE_COMMAND} -E remove -f "${FENNEC_SOURCE_DIR}/docs"
|
||||||
COMMENT "Cleaning Doxygen Documentation"
|
COMMENT "Cleaning Doxygen Documentation"
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
else()
|
else()
|
||||||
|
|||||||
394
PLANNING.md
394
PLANNING.md
@@ -1,394 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# Planning Documentation for fennec
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Introduction](#introduction)
|
|
||||||
2. [TODO](#todo)
|
|
||||||
3. [C++ Language](#c-language-library-lang)
|
|
||||||
4. [Math Library](#math-library-math)
|
|
||||||
5. [Memory Library](#memory-library-memory)
|
|
||||||
6. [Containers Library](#containers-containers)
|
|
||||||
7. [Language Processing](#language-processing-proclang)
|
|
||||||
8. [Core](#core-core)
|
|
||||||
1. [Tick](#tick)
|
|
||||||
2. [Frame](#frame)
|
|
||||||
9. [Scene](#scene-scene)
|
|
||||||
10. [3D Graphics](#3d-graphics-gfx3d)
|
|
||||||
11.
|
|
||||||
12. [3D Physics](#3d-physics-physics3d)
|
|
||||||
13. [Artificial Intelligence](#artificial-intelligence-ai)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
This file serves as a general planning document for engine structure, systems, pipelines, and implementation.
|
|
||||||
|
|
||||||
|
|
||||||
Implementations of core engine systems should strive to be `O(1)` in implementations,
|
|
||||||
both in terms of runtime and memory performance. This is obviously not a realistic goal,
|
|
||||||
so rather than the entire engine striving to be `O(1)` we should more specifically look
|
|
||||||
at achieving `O(1)` performance on hot paths.
|
|
||||||
|
|
||||||
Functions should be highly verbose, and in debug mode any bugprone or erroneous behaviour should throw
|
|
||||||
assertions. **DO NOT USE EXCEPTIONS**.
|
|
||||||
|
|
||||||
System implementations should be independent of architecture or platforms. i.e. the code of the graphics system should
|
|
||||||
not care if OpenGL or Vulkan is used and should not use any direct calls to OpenGL or Vulkan.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- 2D Graphics (`gfx2d`)
|
|
||||||
- 2D Physics (`physics2d`)
|
|
||||||
- 2D & 3D Audio (`audio`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## C++ Language Library (`lang`)
|
|
||||||
|
|
||||||
Implement header files for standard functions relating to the C++ Language.
|
|
||||||
So far this is implemented on an as-needed basis. A full implementation should be worked on continuously.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Math Library (`math`)
|
|
||||||
|
|
||||||
Implement math functions according to the [OpenGL 4.6 Shading Language Specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf).
|
|
||||||
|
|
||||||
Additional extensions should be implemented to provide standard definitions for functions predominantly related
|
|
||||||
to Linear Algebra, Mathematical Analysis, and Discrete Analysis. Additional extensions will be implemented on a
|
|
||||||
as-needed basis.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Memory Library (`memory`)
|
|
||||||
|
|
||||||
Implement headers related to memory allocation in C++.
|
|
||||||
|
|
||||||
* Smart Pointers
|
|
||||||
- Memory Allocation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Containers (`containers`)
|
|
||||||
|
|
||||||
All containers of the [C++ Standard Library](https://cppreference.com/w/cpp/container.html) should be implemented.
|
|
||||||
|
|
||||||
Here are essential data-structures not specified in the C++ stdlib:
|
|
||||||
- Graph → AI `graph`
|
|
||||||
- Necessary for 2D and 3D navigation.
|
|
||||||
- Rooted Directed Tree `rd_tree`
|
|
||||||
- Defines the scene structure.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Language Processing (`proclang`)
|
|
||||||
|
|
||||||
Pronounced [pɹˈɒkh,læŋ](https://itinerarium.github.io/phoneme-synthesis/?w=pɹˈɒkh,læŋ)
|
|
||||||
|
|
||||||
No, this won't include Machine Learning, it will mostly include tools for processing human-readable files.
|
|
||||||
fennec should be able to use Doxygen and LaTeX externally. Consider including binaries with releases.
|
|
||||||
|
|
||||||
* String Analysis (`proclang/strings`)
|
|
||||||
* Search
|
|
||||||
* Manipulation
|
|
||||||
* Delimiting
|
|
||||||
* Regex
|
|
||||||
|
|
||||||
- File Formats (`proclang/formats`)
|
|
||||||
- Serialization
|
|
||||||
- JSON
|
|
||||||
- HTML
|
|
||||||
- XML
|
|
||||||
- YAML
|
|
||||||
- Configuration
|
|
||||||
- INI
|
|
||||||
- TOML
|
|
||||||
- Documents
|
|
||||||
- ODF
|
|
||||||
- Markdown
|
|
||||||
- PDF
|
|
||||||
- Spreadsheets & Tables
|
|
||||||
- ODS
|
|
||||||
- CSV
|
|
||||||
- Graphics Formats
|
|
||||||
- BMP
|
|
||||||
- JPG
|
|
||||||
- PNG
|
|
||||||
- TIFF
|
|
||||||
- DDS
|
|
||||||
- Wavefront OBJ
|
|
||||||
- FBX
|
|
||||||
|
|
||||||
**MAYBE**
|
|
||||||
* Compilation (`proclang/code`)
|
|
||||||
* Lexical Analysis
|
|
||||||
* Syntax Analysis
|
|
||||||
* Semantic Analysis
|
|
||||||
* Intermediate Code Generation
|
|
||||||
* Optimization
|
|
||||||
* Target Code Generation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Core (`core`)
|
|
||||||
|
|
||||||
This will be the core of the engine.
|
|
||||||
|
|
||||||
- Event System
|
|
||||||
- Core Engine Loop
|
|
||||||
- System Manager
|
|
||||||
- Ticks vs. Frames
|
|
||||||
|
|
||||||
The following systems are not essential to the core engine, but are instead major systems that should be defined
|
|
||||||
in their operation order:
|
|
||||||
|
|
||||||
### Tick
|
|
||||||
- **Update**
|
|
||||||
- Events
|
|
||||||
- Scripts
|
|
||||||
- AI
|
|
||||||
- **Physics**
|
|
||||||
- Newtonian Commit
|
|
||||||
- Apply Forces (Updates Acceleration and Torque)
|
|
||||||
- Apply Torque & Acceleration (Updates Velocities)
|
|
||||||
- Apply Velocities (Updates Position and Rotation)
|
|
||||||
- Constraint Resolution
|
|
||||||
- Collision Detection
|
|
||||||
- Collision Resolution (Adjust for Clipping)
|
|
||||||
- Soft Bodies resolve before Rigid Bodies
|
|
||||||
- Collision Response
|
|
||||||
- Calculate Forces
|
|
||||||
|
|
||||||
|
|
||||||
### Frame
|
|
||||||
- **Graphics**
|
|
||||||
- Physics Interpolation
|
|
||||||
- [2D Graphics](#2d-graphics-gfx2d)
|
|
||||||
- Generate 3D Mask
|
|
||||||
- [3D Graphics](#3d-graphics-gfx3d)
|
|
||||||
- **Audio**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Application Layer (`app`)
|
|
||||||
|
|
||||||
This is the core windowing system of fennec. The implementation will initially be an SDL3 wrapper.
|
|
||||||
Custom implementation may be further down the roadmap, however this is extremely complicated and there are better
|
|
||||||
implementations than I could write.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Scene (`scene`)
|
|
||||||
|
|
||||||
* In-Array Directed Tree
|
|
||||||
* Elegant method for providing `O(1)` insertions and `O(log(n))` deletions.
|
|
||||||
* Bounding Volume Hierarchy
|
|
||||||
* Octree
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 2D Graphics (`gfx2d`)
|
|
||||||
|
|
||||||
- BVH
|
|
||||||
- Quadtree
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 3D Graphics (`gfx3d`)
|
|
||||||
|
|
||||||
Links:
|
|
||||||
- https://en.wikipedia.org/wiki/Octree
|
|
||||||
- https://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/
|
|
||||||
- https://learnopengl.com/PBR/Lighting
|
|
||||||
- https://learnopengl.com/PBR/IBL/Diffuse-irradiance
|
|
||||||
- https://en.wikipedia.org/wiki/Schlick%27s_approximation
|
|
||||||
- https://pixelandpoly.com/ior.html
|
|
||||||
- https://developer.download.nvidia.com/SDK/10/opengl/screenshots/samples/dual_depth_peeling.html
|
|
||||||
|
|
||||||
**DirectX will never have official support.**
|
|
||||||
If you would like to make a fork, have at it, but know that I will hold a deep disdain for you.
|
|
||||||
|
|
||||||
The graphics pipeline will have a buffer with a list of objects and their rendering data.
|
|
||||||
This will be referred to as the Object Buffer. There will be two, for both the Deferred and Forward Passes.
|
|
||||||
|
|
||||||
The buffers will be optimized by scene prediction. This involves tracking the meshes directly and indirectly used by a scene.
|
|
||||||
|
|
||||||
Materials and Lighting models will be run via a shader metaprogram to make the pipeline independent of this aspect.
|
|
||||||
This allows the GPU to draw every single deferred rendered mesh in a single draw call for each stage of the renderer.
|
|
||||||
|
|
||||||
Specifications for debugging views via early breaks are included in the stages.
|
|
||||||
|
|
||||||
|
|
||||||
### Stages (`gfx3d`)
|
|
||||||
|
|
||||||
This is the set of stages for the graphics pipeline that runs every frame:
|
|
||||||
|
|
||||||
- BVH
|
|
||||||
- Octree
|
|
||||||
- Leaf Size and Tree Depth should be calculated by the scene, constraints are as follows:
|
|
||||||
- Min Object Size
|
|
||||||
- Max Object Size
|
|
||||||
- Scene Center
|
|
||||||
- Scene Edge
|
|
||||||
- Buffer has implicit locations due to the tree having 8 children.
|
|
||||||
- Insertions and Updates are done on the CPU
|
|
||||||
- Nodes
|
|
||||||
- ID 16-bits
|
|
||||||
- Start Index 32-bits
|
|
||||||
- Object Count 16-bits
|
|
||||||
- Objects
|
|
||||||
- Buffer of Object IDs grouped by Octree Node
|
|
||||||
- Culling
|
|
||||||
- Starting at each Octree Leaf, traverse upwards.
|
|
||||||
- Insert Visible Leaf IDs
|
|
||||||
- Track using atomic buffer
|
|
||||||
- At the second level, if a node is an edge, add the sister nodes to the visible buffer.
|
|
||||||
- Output: Buffer of Visible Leaves
|
|
||||||
|
|
||||||
* LOD Selection
|
|
||||||
* Generate the Command Buffer for Culled Mesh LODs from the Visible Leaf Buffer
|
|
||||||
* Track counts using atomic buffers
|
|
||||||
* To avoid double counting due to the structure of the Octree output, we have some options
|
|
||||||
* Ignore Leaf Instances based on occurrences of the mesh in the surrounding 26 Octree Leaves. This would require
|
|
||||||
a bias towards a specific corner of the filter.
|
|
||||||
* Perform a preprocessing step on the CPU to erase duplicate elements and fix the buffer continuity.
|
|
||||||
* Let the duplicates be rendered.
|
|
||||||
* Generate the Culled Object Buffer by copying objects from the Object Buffer
|
|
||||||
* Adjust Buffer Size using the counts
|
|
||||||
* Insert using another atomic buffer
|
|
||||||
|
|
||||||
Debug View: Object ID, Mesh ID, LOD
|
|
||||||
|
|
||||||
- Visibility
|
|
||||||
- Buffer - RGB32I w/ Depth24
|
|
||||||
- G = Object ID
|
|
||||||
- B = Mesh ID
|
|
||||||
- Regenerate the Command Buffer for Visible Mesh LODs
|
|
||||||
- Regenerate the Culled Object Buffer
|
|
||||||
|
|
||||||
Debug View: Visibility Buffer
|
|
||||||
|
|
||||||
* G-Buffer Pass
|
|
||||||
* Depth - Stencil
|
|
||||||
* 24-Bit Depth Buffer
|
|
||||||
* 8-Bit Stencil Buffer, used to represent the lighting model.
|
|
||||||
* Diffuse - RGB8
|
|
||||||
* Emission - RGB8
|
|
||||||
* Normal - RGB8
|
|
||||||
* Specular - RGB8
|
|
||||||
* R → Roughness
|
|
||||||
* G → Specularity (sometimes called metallicism)
|
|
||||||
* B → Index of Refraction (IOR)
|
|
||||||
|
|
||||||
Debug View: Depth, Stencil, Diffuse, Emission, Normal, Specularity
|
|
||||||
|
|
||||||
- Lighting Pass
|
|
||||||
- Generate Dynamic Shadows
|
|
||||||
- Generate Dynamic Reflections (Optional)
|
|
||||||
- SSAO (Optional)
|
|
||||||
- Apply Lighting Model
|
|
||||||
- Output → RGB16
|
|
||||||
|
|
||||||
Debug View: Shadows, Reflections, SSAO, Deferred Lighting
|
|
||||||
|
|
||||||
* Forward Pass
|
|
||||||
* BVH, Same as Above
|
|
||||||
* LOD Selection, Same as Above
|
|
||||||
* Translucent Materials
|
|
||||||
* Dual Depth Peeling
|
|
||||||
|
|
||||||
Debug View: Deferred and Forward Mask
|
|
||||||
|
|
||||||
- Post Processing
|
|
||||||
- Depth of Field (Optional) → Poisson Sampling
|
|
||||||
- Bloom (Optional) → Mipmap Blurring
|
|
||||||
- Tonemapping (Optional)
|
|
||||||
- HDR Correction
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 3D Physics `(physics3d)`
|
|
||||||
|
|
||||||
Links:
|
|
||||||
- https://www.researchgate.net/publication/264839743_Simulating_Ocean_Water
|
|
||||||
- https://arxiv.org/pdf/2109.00104
|
|
||||||
- https://www.youtube.com/watch?v=rSKMYc1CQHE
|
|
||||||
- https://tflsguoyu.github.io/webpage/pdf/2013ICIA.pdf
|
|
||||||
- https://animation.rwth-aachen.de/publication/0557/
|
|
||||||
- https://github.com/InteractiveComputerGraphics/PositionBasedDynamics?tab=readme-ov-file
|
|
||||||
- https://www.cs.umd.edu/class/fall2019/cmsc828X/LEC/PBD.pdf
|
|
||||||
|
|
||||||
Systems
|
|
||||||
|
|
||||||
* Rigid Body Physics
|
|
||||||
* Newtonian Physics and Collision Resolution
|
|
||||||
* Articulated Skeletal Systems
|
|
||||||
* Inverse Kinematics
|
|
||||||
* Stiff Rods
|
|
||||||
- Particle Physics
|
|
||||||
* Soft Body Physics
|
|
||||||
* Elastics → Finite Element Simulation
|
|
||||||
* Cloth → Position-Based Dynamics
|
|
||||||
* Water
|
|
||||||
* Oceans → iWave
|
|
||||||
* Reasoning: iWave provides interactive lightweight fluid dynamics suitable for flat planes of water. Simulat
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
* 3D Fluid Dynamics → Smoothed-Particle Hydrodynamics
|
|
||||||
* Reasoning: This is the simplest method for simulating 3D bodies of water. This should exclusively be
|
|
||||||
used for small scale simulations where self-interactive fluids are necessary. I.E. pouring water into
|
|
||||||
a glass.
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
* 2D Fluid Dynamics → Force-Based Dynamics
|
|
||||||
* Reasoning: This model, like iWave, provides lightweight interactive fluid dynamics, but is more easily
|
|
||||||
adapted to flowing surfaces such as streams and rivers.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Artificial Intelligence (`ai`)
|
|
||||||
|
|
||||||
This artificial intelligence method only differs in static generation between 2D and 3D.
|
|
||||||
The solvers are dimension independent since they work on a graph.
|
|
||||||
|
|
||||||
The general process is;
|
|
||||||
|
|
||||||
Static:
|
|
||||||
- generate a static navigation graph (sometimes called a NavMesh)
|
|
||||||
|
|
||||||
Update:
|
|
||||||
* resolve dynamic blockers
|
|
||||||
* update paths using dijkstra's algorithm
|
|
||||||
* apply rigid-body forces with constraints
|
|
||||||
|
|
||||||
The update loop for artificial intelligence should only update every `n` ticks. Where `n <= k`, with `k` being the
|
|
||||||
tick rate of the physics engine.
|
|
||||||
16
READINGS.md
Normal file
16
READINGS.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Readings
|
||||||
|
|
||||||
|
Here is a list of relevant books and articles on various concepts related to
|
||||||
|
developing a game engine and its subsystems.
|
||||||
|
|
||||||
|
- Game Engine Architecture, Ed. 3 – Jason Gregory
|
||||||
|
- https://www.gameenginebook.com/
|
||||||
|
- OpenGL 4 Shading Language Cookbook, Ed. 3 – David A. Wolff
|
||||||
|
- https://www.packtpub.com/en-us/product/opengl-4-shading-language-cookbook-9781789340662
|
||||||
|
- Design Patterns: Elements of Reusable Object-Oriented Software – Erich Gamma, Richard Helm, Ralph Johnson, John Vilssides
|
||||||
|
- https://www.oreilly.com/library/view/design-patterns-elements/0201633612/
|
||||||
|
- Head First Design Patterns – Eric FReeman, Elisabeth Robson, Bert Bates, Kathy Sierra
|
||||||
|
- https://www.oreilly.com/library/view/head-first-design/0596007124/
|
||||||
236
README.md
236
README.md
@@ -8,16 +8,23 @@
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
## Table of Contents
|
<a id="table-of-contents"></a>
|
||||||
|
<h2>Table of Contents</h2>
|
||||||
|
|
||||||
|
* [Table of Contents](#table-of-contents)
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Coding Standards](#coding-standards)
|
||||||
|
* [Building from Source](#building-from-source)
|
||||||
|
* [Building from Terminal](#building-from-terminal)
|
||||||
|
* [Debian](#debian) → `apt`
|
||||||
|
* [Arch](#arch) → `pacman`
|
||||||
|
* [Fedora](#fedora) → `dnf`
|
||||||
|
* [Building on Windows](#building-on-windows)
|
||||||
|
* [Running the Test Suite](#running-the-test-suite)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [Licensing](#licensing)
|
||||||
|
* [Contribution](#contribution)
|
||||||
|
|
||||||
1. [Introduction](#introduction)
|
|
||||||
1. [Coding Standards](#coding-standards)
|
|
||||||
2. [Building from Source](#building-from-source)
|
|
||||||
1. [Building from Terminal](#building-from-terminal)
|
|
||||||
2. [Building on Windows](#building-on-windows)
|
|
||||||
3. [Running the Test Suite](#running-the-test-suite)
|
|
||||||
4. [Usage](#usage)
|
|
||||||
5. [Contribution](#contribution)
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -26,9 +33,11 @@
|
|||||||
<a id="introduction"></a>
|
<a id="introduction"></a>
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
fennec is designed to be a general purpose, educational game engine.
|
  fennec is designed to be a general purpose, educational game engine. fennec
|
||||||
fennec may be used through the provided editor application, or as a standalone
|
may be used through the provided editor application, or as a standalone library to
|
||||||
library to link against your application.
|
link against your application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -50,18 +59,38 @@ Some main areas where the engine strays from the GNU standard includes the follo
|
|||||||
|
|
||||||
fennec Standards:
|
fennec Standards:
|
||||||
|
|
||||||
* As per the GNU standard, macros should be `SCREAMING_SNAKE_CASE`. Additionally, Macros should be preceded by `<APP_NAME>_`.
|
* As per the GNU standard, macros should be `SCREAMING_SNAKE_CASE`. Additionally, Macros should be preceded by
|
||||||
Macros that wrap C-Style functions may use normal `snake_case`.
|
`<APP_NAME>_`. Macros that wrap C-Style functions may use normal `snake_case`.
|
||||||
|
|
||||||
- Header Guards should be implemented using `#ifndef`, `#define`, and `#endif` for portability.
|
- Header Guards should be implemented using `#ifndef`, `#define`, and `#endif` for portability.
|
||||||
The naming convention for Header Guards is as follows: `<APP_NAME>_<DIRECTORY_PATH>_<FILE_NAME>_H`.
|
The naming convention for Header Guards is as follows: `<APP_NAME>_<DIRECTORY_PATH>_<FILE_NAME>_H`.
|
||||||
I.E. the engine file `fennec/lang/utility.h` has the Header Guard `FENNEC_LANG_UTILITY_H`.
|
I.E. the engine file `fennec/lang/utility.h` has the Header Guard `FENNEC_LANG_UTILITY_H`.
|
||||||
|
|
||||||
* Helper Functions, in the case of classes, should be private.
|
* Helper Functions, in the case of classes, should be private.
|
||||||
In the case of global functions, helpers should be placed in a similarly named file in a subdirectory and namespace called `detail`.
|
In the case of global functions, helpers should be placed in a similarly named file in a subdirectory and namespace
|
||||||
Helper functions should be documented with C-Style comments, however it is not necessary to provide Doxygen documentation.
|
called `detail`. Helper functions should be documented with C-Style comments, however it is not necessary to provide
|
||||||
|
Doxygen documentation.
|
||||||
|
|
||||||
|
- **DO NOT USE C++ EXCEPTIONS** they will not be supported because they are shit.<sup>[[1]](#f1)</sup>
|
||||||
|
|
||||||
|
* Most behaviours should be type independent. Specifically interactions with the core systems of the engine.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<a id="f1"></a>
|
||||||
|
<sup>[1]</sup> If we were to use the exception paradigm for all erroneous behaviour, we couldn't guarantee
|
||||||
|
that the state will not be corrupted when an exception is thrown. The behaviour afterward is undefined
|
||||||
|
because of this, and we also don't really know when, how, or where that exception will be handled.
|
||||||
|
The assertion paradigm is better at handling this because you are defining erroneous behaviour in the
|
||||||
|
code and how it is handled. In a debug build we can immediately halt the program, we don't care about
|
||||||
|
the state afterward, only beforehand. Now for a release build, this is first and foremost a game engine,
|
||||||
|
so we want to crash as gracefully as possible, prevent data loss, and get some debug information for it.
|
||||||
|
fennec defines its own `assert` macro to be used, defining a hook in the private version of the
|
||||||
|
function. This hook is used to clean up any state information within the engine and may be used to send
|
||||||
|
immediate events to listeners so that outside functionality may decide how to handle the impending crash.
|
||||||
|
In Debug Mode there is nothing that can be done to stop the crash, as soon as the branch finishes,
|
||||||
|
`abort()` will be called.
|
||||||
|
|
||||||
- **DO NOT USE C++ EXCEPTIONS** they will not be supported because they are shit. No, I won't elaborate.
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -81,10 +110,10 @@ There are a few reasons for this:
|
|||||||
<a id="building-from-source"></a>
|
<a id="building-from-source"></a>
|
||||||
## Building from Source
|
## Building from Source
|
||||||
|
|
||||||
fennec uses the CMake build manager. The CMake build script provides several
|
  fennec uses the CMake build manager. The CMake build script provides several
|
||||||
targets for building parts of the engine.
|
targets for building parts of the engine.
|
||||||
|
|
||||||
Using an IDE will streamline the build process for you and add additional configuration
|
  Using an IDE will streamline the build process for you and add additional configuration
|
||||||
options. Eclipse, Visual Studio, and CLion provide built-in support for CMake. VSCode
|
options. Eclipse, Visual Studio, and CLion provide built-in support for CMake. VSCode
|
||||||
is also a viable IDE but involves some extra setup.
|
is also a viable IDE but involves some extra setup.
|
||||||
|
|
||||||
@@ -102,6 +131,7 @@ is also a viable IDE but involves some extra setup.
|
|||||||
|-------------------|----------------------------------------------------------------------------------------------------------|
|
|-------------------|----------------------------------------------------------------------------------------------------------|
|
||||||
| C/C++ Compiler | GCC/G++ is the compiler that fennec is designed around, however, Clang, MSVC, and MinGW may also be used |
|
| C/C++ Compiler | GCC/G++ is the compiler that fennec is designed around, however, Clang, MSVC, and MinGW may also be used |
|
||||||
| CMake | The build manager used by the engine |
|
| CMake | The build manager used by the engine |
|
||||||
|
| glew | OpenGL Extension Wrangler, necessary for modern OpenGL |
|
||||||
| A build system | Any build system will work, however, `build.sh` uses Ninja by default. |
|
| A build system | Any build system will work, however, `build.sh` uses Ninja by default. |
|
||||||
| A memory debugger | Any memory debugger will work, however, `test.sh` uses Valgrind by default. |
|
| A memory debugger | Any memory debugger will work, however, `test.sh` uses Valgrind by default. |
|
||||||
| Doxygen | Doxygen is required for building the documentation for fennec. This is an optional dependency |
|
| Doxygen | Doxygen is required for building the documentation for fennec. This is an optional dependency |
|
||||||
@@ -115,20 +145,66 @@ is also a viable IDE but involves some extra setup.
|
|||||||
`build.sh` provides profiles for building the main engine. Run `./build.sh --help`
|
`build.sh` provides profiles for building the main engine. Run `./build.sh --help`
|
||||||
for more info.
|
for more info.
|
||||||
|
|
||||||
By default, the CMake generator
|
  By default, the CMake generator used is Ninja, which requires Ninja to be installed. You can modify the
|
||||||
used is Ninja, which requires Ninja to be installed.
|
build scripts to use another build manager, see the [CMake documentation for available generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).
|
||||||
You can modify the build scripts to use another build manager, see the [CMake documentation for available generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).
|
|
||||||
|
  I will at no point provide official cross-compilation toolchains for fennec. However, I will provide tools for
|
||||||
|
using specific toolchains for specific platforms that necessitate this. The primary examples would be Android and iOS.
|
||||||
|
If you wish to build for Windows *and* Linux, your options are WSL or Dual Boot. I recommend Dual Boot over WSL.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="debian"></a>
|
||||||
|
#### Debian
|
||||||
|
|
||||||
|
On Debian-based distributions, you can install dependencies using the following command:
|
||||||
|
```shell
|
||||||
|
sudo apt install build-essential cmake ninja-build libglew-dev valgrind
|
||||||
|
git submodule update --force --init --recursive --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
for Doxygen run:
|
||||||
|
```shell
|
||||||
|
sudo apt install doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="arch"></a>
|
||||||
|
#### Arch
|
||||||
|
|
||||||
|
On Arch-based distributions, you can install dependencies using the following command:
|
||||||
|
```shell
|
||||||
|
sudo pacman -S base-devel cmake ninja glew valgrind
|
||||||
|
git submodule update --force --init --recursive --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
for Doxygen run:
|
||||||
|
```shell
|
||||||
|
sudo pacman -S doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="fedora"></a>
|
||||||
|
#### Fedora
|
||||||
|
|
||||||
|
On Fedora-based distributions, you can install dependencies using the following command:
|
||||||
|
```shell
|
||||||
|
sudo dnf install build-essential g++ cmake ninja-build glew-devel valgrind
|
||||||
|
git submodule update --force --init --recursive --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
for Doxygen run:
|
||||||
|
```shell
|
||||||
|
sudo dnf install doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<a id="building-on-windows"></a>
|
<a id="building-on-windows"></a>
|
||||||
### Building on Windows
|
### Building on Windows
|
||||||
|
|
||||||
The bash script can be run natively on Windows when WSL is enabled.
|
  The bash script can be run natively on Windows when WSL is enabled. You do not need to run the
|
||||||
You do not need to run the script in WSL, simply use the "bash" command in Command Prompt or PowerShell.
|
script in WSL, simply use the "bash" command in Command Prompt or PowerShell. The script will require
|
||||||
The script will require the build [dependencies](#dependencies) installed and configured to be available on the `PATH` environment variable.
|
the build [dependencies](#dependencies) installed and configured to be available on the `PATH` environment variable.
|
||||||
|
|
||||||
Fore more details, [see this blog post](https://blogs.windows.com/windows-insider/2016/04/06/announcing-windows-10-insider-preview-build-14316/) for Windows Build 14316.
|
For more details, [see this blog post](https://blogs.windows.com/windows-insider/2016/04/06/announcing-windows-10-insider-preview-build-14316/) for Windows Build 14316.
|
||||||
|
|
||||||
Otherwise, follow the sequence of commands provided in the bash script.
|
Otherwise, follow the sequence of commands provided in the bash script.
|
||||||
|
|
||||||
@@ -151,10 +227,9 @@ The value of `<profile>` may be one of the following:
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
If you would like to use Visual Studio without CMake, you can use the build
|
  If you would like to use Visual Studio without CMake, you can use the build script to generate
|
||||||
script to generate a Visual Studio project for the source. For a list of available
|
a Visual Studio project for the source. For a list of available Visual Studio generators, [see this section](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html)
|
||||||
Visual Studio generators, [see this section](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).
|
of the CMake docs. Running the following command will generate the Visual Studio project.
|
||||||
Running the following command will generate the Visual Studio project.
|
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
cmake -G "Visual Studio 17 2022" -A x64
|
cmake -G "Visual Studio 17 2022" -A x64
|
||||||
@@ -168,10 +243,10 @@ cmake -G "Visual Studio 17 2022" -A x64
|
|||||||
|
|
||||||
`test.sh` provides profiles for building the test suite and executes them.
|
`test.sh` provides profiles for building the test suite and executes them.
|
||||||
|
|
||||||
By default, it runs in debug mode and the first failed test will throw an assertion.
|
  By default, the program runs in debug mode and the first failed test will throw an assertion.
|
||||||
Any tests that involve running as an application will spawn a subprocess with a window,
|
Any tests that involve running as an application will spawn a subprocess with a window, and give
|
||||||
and give a short description of the behaviour in the terminal. It will then have you confirm
|
a short description of the behaviour in the terminal. It will then have you confirm whether the
|
||||||
whether the information displayed is correct.
|
information displayed is correct.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -179,6 +254,95 @@ whether the information displayed is correct.
|
|||||||
<a id="usage"></a>
|
<a id="usage"></a>
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
||||||
|
<a id="licensing"></a>
|
||||||
|
### Licensing
|
||||||
|
|
||||||
|
The following content of this section is not legal advice, nor is it legally binding, and nor does it change the terms
|
||||||
|
of the license. Please seek legal council if you have any concerns.
|
||||||
|
|
||||||
|
TLDR; You may license your game under whichever license you please. Any C++ code that is by definition a derivative work
|
||||||
|
must be licensed under GPLv3 and freely available, everything else; assets, scripts, design documents, etc. may be under
|
||||||
|
the license of your choosing and remain proprietary.
|
||||||
|
|
||||||
|
  fennec is licensed under GPLv3. The primary reason for the choice of license is to dissuade corporations from
|
||||||
|
modifying fennec and using it in a commercial manner. This of course does not bar them from using fennec commercially,
|
||||||
|
however it will prevent them from being able to make the derivative work proprietary. You are free to use and redistribute
|
||||||
|
fennec however you wish according to the terms of the license, which does not bar you from commercializing software based
|
||||||
|
on fennec.
|
||||||
|
|
||||||
|
  If you wish to protect your game files, assets and generated content do not constitute a covered work and may be
|
||||||
|
copyrighted under a non-compliant license. Think of it in terms of using Blender to create a mesh for a game, then
|
||||||
|
licensing that mesh under another license.
|
||||||
|
|
||||||
|
  Later down the line, I plan on implementing scripts in a manner that allows the script itself to remain proprietary.
|
||||||
|
The scripts will likely be trans-compiled to another language before being compiled to binary, but this is only an
|
||||||
|
intermediate step and will be erased when no longer needed.
|
||||||
|
|
||||||
|
  As long as you use the official editor, it will properly include licenses in project content when provided a license
|
||||||
|
and the name of the license holder. Archive packs will include the license holders non-GPLv3 license in them and any
|
||||||
|
linked code will be covered by GPLv3 under the name of the license holder. Be aware that the parts of your project
|
||||||
|
licensed under GPLv3 must be available upon request.
|
||||||
|
|
||||||
|
  A release project will consist of an executable, a shared library for your code, an archive pak, and streamable assets.
|
||||||
|
The executable and shared library are under the GPLv3 license, while the archive pak and streamable assets are under your license.
|
||||||
|
|
||||||
|
It is to my discretion whether I enforce the terms of the license on a party.
|
||||||
|
|
||||||
|
The following practices are more likely to get my attention and enforcement:
|
||||||
|
- Redistributing a modified version of fennec that is not licensed under GPLv3
|
||||||
|
- Distributing an engine that is, by definition, a derivative work of fennec that is not licensed under GPLv3
|
||||||
|
- Distributing an editor that runs on fennec or its derivatives that is not licensed under GPLv3
|
||||||
|
- Using fennec to train a Machine Learning or Artificial Intelligence algorithm that is not licensed under GPLv3
|
||||||
|
- Non-compliance of GPLv3 in games with the following mechanics:
|
||||||
|
- Gacha Mechanics
|
||||||
|
- Gambling with real currency
|
||||||
|
- Subscription-Based Sales Model
|
||||||
|
- NFTs or Nonfungible Tokens
|
||||||
|
|
||||||
|
I encourage those who wish to commercialize derivative works crowdfund rather than use a sales model. I also ask
|
||||||
|
that you kindly support me as a developer, I will set up a Buy Me a Coffee link at some point.
|
||||||
|
|
||||||
|
GPLv3 is bound by fair use; here is the clause, 17 U.S. Code § 107:
|
||||||
|
|
||||||
|
```
|
||||||
|
107. Limitations on exclusive rights: Fair use
|
||||||
|
|
||||||
|
Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by
|
||||||
|
reproduction in copies or phonorecords or by any other means specified by that section, for purposes such as criticism,
|
||||||
|
comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an
|
||||||
|
infringement of copyright. In determining whether the use made of a work in any particular case is a fair use the
|
||||||
|
factors to be considered shall include—
|
||||||
|
|
||||||
|
(1) the purpose and character of the use, including whether such use is of a commercial nature or is for nonprofit
|
||||||
|
educational purposes;
|
||||||
|
(2) the nature of the copyrighted work;
|
||||||
|
(3) the amount and substantiality of the portion used in relation to the copyrighted work as a whole; and
|
||||||
|
(4) the effect of the use upon the potential market for or value of the copyrighted work.
|
||||||
|
|
||||||
|
The fact that a work is unpublished shall not itself bar a finding of fair use if such finding is made upon
|
||||||
|
consideration of all the above factors.
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have any questions or concerns, please seek legal council. If you believe someone else has violated the terms
|
||||||
|
of this license, please contact me at [mslockbo@gmail.com](mailto:mslockbo@gmail.com).
|
||||||
|
|
||||||
|
I am aware of Universities with Game Development programs such as DigiPen Institute of Technology and Full-Sail
|
||||||
|
University which license student work to protect them and the faculty.
|
||||||
|
|
||||||
|
Champlain College does not license student projects and constitutes fair use.
|
||||||
|
|
||||||
|
I have not worked with Full-Sail University before, so I am not familiar with any of their staff members, and I will
|
||||||
|
require legal council to consult with them which may dissuade permission to use my engine.
|
||||||
|
|
||||||
|
I hold a Bachelor's Degree in Computer Science and Real-Time Interactive Simulation from DigiPen Institute of Technology,
|
||||||
|
so I am familiar with their copyright policy. Ask your professor about usage of my engine, and they or someone with
|
||||||
|
appropriate standing will reach out to me. Eventually, with interest, I may reach out on my own terms to negotiate usage
|
||||||
|
of fennec for educative purposes at DigiPen while retaining their license on student work.
|
||||||
|
|
||||||
|
If your University is not listed here, reach out to your professor for permission. Ask them to reach out to me, I am
|
||||||
|
willing to work with educational institutes to protect both fennec and student work in accordance to university policy.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -187,5 +351,5 @@ whether the information displayed is correct.
|
|||||||
|
|
||||||
There are some principles to keep in mind when contributing to fennec.
|
There are some principles to keep in mind when contributing to fennec.
|
||||||
|
|
||||||
1. You must follow the style guide provided by the [GNU Coding Standard](https://www.gnu.org/prep/standards/html_node/Writing-C.html).
|
1. You must follow the [standards provided above](#coding-standards).
|
||||||
2. Any changes must allow all projects to be forward compatible with newer engine verisons.
|
2. Any changes must allow all projects to be forward compatible with newer engine versions.
|
||||||
|
|||||||
8
build.sh
8
build.sh
@@ -38,7 +38,7 @@ Help()
|
|||||||
Debug()
|
Debug()
|
||||||
{
|
{
|
||||||
mkdir -p build/debug
|
mkdir -p build/debug
|
||||||
cd ./build/debug
|
cd ./build/debug || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -47,7 +47,7 @@ Debug()
|
|||||||
Release()
|
Release()
|
||||||
{
|
{
|
||||||
mkdir -p build/release
|
mkdir -p build/release
|
||||||
cd ./build/release
|
cd ./build/release || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -56,7 +56,7 @@ Release()
|
|||||||
RelWithDebInfo()
|
RelWithDebInfo()
|
||||||
{
|
{
|
||||||
mkdir -p build/relwithdebinfo
|
mkdir -p build/relwithdebinfo
|
||||||
cd ./build/relwithdebinfo
|
cd ./build/relwithdebinfo || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -65,7 +65,7 @@ RelWithDebInfo()
|
|||||||
MinSizeRel()
|
MinSizeRel()
|
||||||
{
|
{
|
||||||
mkdir -p build/minsizerel
|
mkdir -p build/minsizerel
|
||||||
cd ./build/minsizerel
|
cd ./build/minsizerel || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
|
|||||||
28
cmake/build.cmake
Normal file
28
cmake/build.cmake
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script handles functionality related to the build process and its info
|
||||||
|
|
||||||
|
string(TOLOWER ${CMAKE_BUILD_TYPE} FENNEC_BUILD_NAME)
|
||||||
|
message(STATUS "Build: ${FENNEC_BUILD_NAME}")
|
||||||
|
|
||||||
|
if(${FENNEC_BUILD_NAME} MATCHES "debug")
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=false)
|
||||||
|
else()
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=true)
|
||||||
|
endif()
|
||||||
24
cmake/compiler.cmake
Normal file
24
cmake/compiler.cmake
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script finds the compiler being used
|
||||||
|
|
||||||
|
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||||
|
set(FENNEC_COMPILER "GCC")
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")
|
||||||
|
endif()
|
||||||
35
cmake/default_user.cmake
Normal file
35
cmake/default_user.cmake
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# sets up cmake variables for client vs server
|
||||||
|
if(FENNEC_USER_CLIENT)
|
||||||
|
set(FENNEC_USER_CLIENT 1)
|
||||||
|
set(FENNEC_USER_SERVER 0)
|
||||||
|
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_USER_CLIENT=1)
|
||||||
|
elseif(FENNEC_USER_SERVER)
|
||||||
|
set(FENNEC_USER_CLIENT 0)
|
||||||
|
set(FENNEC_USER_SERVER 1)
|
||||||
|
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_USER_SERVER=1)
|
||||||
|
else()
|
||||||
|
set(FENNEC_USER_CLIENT 1)
|
||||||
|
set(FENNEC_USER_SERVER 0)
|
||||||
|
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_USER_CLIENT=1)
|
||||||
|
endif()
|
||||||
25
cmake/gcc.cmake
Normal file
25
cmake/gcc.cmake
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script sets flags and variables for gnu and gnu-like compilers
|
||||||
|
|
||||||
|
add_compile_options("-mxsave" "-Wall" "-Wextra" "-pedantic" "-Werror")
|
||||||
|
|
||||||
|
set(FENNEC_PRIVATE_LINK_OPTIONS "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
|
||||||
|
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS _GLIBCXX_INCLUDE_NEXT_C_HEADERS=1 FENNEC_COMPILER_GCC=1 FENNEC_NO_INLINE=[[gnu::noinline]])
|
||||||
43
cmake/linux.cmake
Normal file
43
cmake/linux.cmake
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script finds and loads libraries related to the Linux operating system. It also sets platform specific variables.
|
||||||
|
|
||||||
|
macro(fennec_check_platform)
|
||||||
|
# unix
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/unix.cmake")
|
||||||
|
|
||||||
|
# compile definitions
|
||||||
|
fennec_add_definitions(
|
||||||
|
FENNEC_PLATFORM_NAME="Linux"
|
||||||
|
FENNEC_PLATFORM_LINUX=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# extra source files
|
||||||
|
fennec_add_sources(
|
||||||
|
include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(FENNEC_USER_CLIENT)
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/wayland.cmake")
|
||||||
|
|
||||||
|
fennec_check_wayland()
|
||||||
|
fennec_init_graphics()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
57
cmake/opengl.cmake
Normal file
57
cmake/opengl.cmake
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
if(FENNEC_GRAPHICS_WANT_EGL)
|
||||||
|
find_package(OpenGL REQUIRED COMPONENTS EGL)
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
|
message(STATUS "EGL Requested")
|
||||||
|
else()
|
||||||
|
find_package(OpenGL)
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
|
||||||
|
message(STATUS "Found OpenGL: ${OPENGL_gl_LIBRARY}")
|
||||||
|
fennec_add_link_libraries(OpenGL::GL GLEW::GLEW)
|
||||||
|
fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "No Suitable OpenGL implementation found.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FENNEC_GRAPHICS_WANT_EGL)
|
||||||
|
if(NOT TARGET OpenGL::EGL)
|
||||||
|
message(FATAL_ERROR "EGL Library not found.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Found EGL: ${OPENGL_egl_LIBRARY}")
|
||||||
|
|
||||||
|
fennec_add_link_libraries(OpenGL::EGL)
|
||||||
|
fennec_add_definitions(FENNEC_GRAPHICS_EGL=1)
|
||||||
|
|
||||||
|
fennec_add_sources(
|
||||||
|
include/fennec/platform/opengl/lib/fwd.h
|
||||||
|
include/fennec/platform/opengl/lib/enum.h
|
||||||
|
include/fennec/platform/opengl/lib/buffer.h
|
||||||
|
include/fennec/platform/opengl/lib/texture.h
|
||||||
|
include/fennec/platform/opengl/lib/vertex_array.h
|
||||||
|
|
||||||
|
include/fennec/platform/opengl/egl/fwd.h
|
||||||
|
include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp
|
||||||
|
include/fennec/platform/opengl/egl/surface.h source/platform/opengl/egl/surface.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
34
cmake/platform.cmake
Normal file
34
cmake/platform.cmake
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script finds the operating system of the build environment
|
||||||
|
|
||||||
|
message(STATUS "OS: ${CMAKE_SYSTEM_NAME}")
|
||||||
|
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/default_user.cmake")
|
||||||
|
|
||||||
|
# Graphics APIs
|
||||||
|
macro(fennec_init_graphics)
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/opengl.cmake")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Check for Linux
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
set(FENNEC_PLATFORM "Linux")
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/linux.cmake")
|
||||||
|
endif ()
|
||||||
29
cmake/unix.cmake
Normal file
29
cmake/unix.cmake
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# generic unix functionality
|
||||||
|
|
||||||
|
# compile definitions
|
||||||
|
fennec_add_definitions(
|
||||||
|
FENNEC_PLATFORM_UNIX=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# extra source files
|
||||||
|
fennec_add_sources(
|
||||||
|
include/fennec/platform/unix/platform.h source/platform/unix/platform.cpp
|
||||||
|
)
|
||||||
33
cmake/version.cmake
Normal file
33
cmake/version.cmake
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script contains the main version
|
||||||
|
|
||||||
|
set(FENNEC_VERSION_MAJOR 0)
|
||||||
|
set(FENNEC_VERSION_MINOR 1)
|
||||||
|
set(FENNEC_VERSION_PATCH 0)
|
||||||
|
set(FENNEC_VERSION_STRING "${FENNEC_VERSION_MAJOR}.${FENNEC_VERSION_MINOR}.${FENNEC_VERSION_PATCH}")
|
||||||
|
math(EXPR FENNEC_VERSION_NUM "(${FENNEC_VERSION_MAJOR} << 16) | (${FENNEC_VERSION_MINOR} << 8) | ${FENNEC_VERSION_PATCH}")
|
||||||
|
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
||||||
|
FENNEC_VERSION_MAJOR=${FENNEC_VERSION_MAJOR}
|
||||||
|
FENNEC_VERSION_MINOR=${FENNEC_VERSION_MINOR}
|
||||||
|
FENNEC_VERSION_PATCH=${FENNEC_VERSION_PATCH}
|
||||||
|
FENNEC_VERSION_STRING=${FENNEC_VERSION_STRING}
|
||||||
|
FENNEC_VERSION_NUM=${FENNEC_VERSION_NUM}
|
||||||
|
)
|
||||||
122
cmake/wayland.cmake
Normal file
122
cmake/wayland.cmake
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# https://gist.github.com/mariobadr/acc3c8adf4b4e722705be38c3deac59a
|
||||||
|
# this script finds libwayland and dependencies
|
||||||
|
|
||||||
|
# some of this code is based on SDL3's use of wayland-scanner
|
||||||
|
|
||||||
|
macro(fennec_wayland_get_header _SCANNER _XML _FILE)
|
||||||
|
set(_WAYLAND_PROT_H_CODE "${WAYLAND_HEADERS_DIR}/${_FILE}-client-protocols.h")
|
||||||
|
set(_WAYLAND_PROT_C_CODE "${WAYLAND_SOURCES_DIR}/${_FILE}-client.c")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_SCANNER} client-header "${_XML}" "${_WAYLAND_PROT_H_CODE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_SCANNER} private-code "${_XML}" "${_WAYLAND_PROT_C_CODE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
fennec_add_sources(${_WAYLAND_PROT_C_CODE} ${_WAYLAND_PROT_H_CODE})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(fennec_check_wayland)
|
||||||
|
set(WAYLAND_CLIENT_FOUND 0)
|
||||||
|
|
||||||
|
find_path(
|
||||||
|
WAYLAND_CLIENT_INCLUDE_DIR
|
||||||
|
NAMES wayland-client.h
|
||||||
|
)
|
||||||
|
find_library(
|
||||||
|
WAYLAND_CLIENT_LIBRARY
|
||||||
|
NAMES wayland-client libwayland-client
|
||||||
|
)
|
||||||
|
find_program(WAYLAND_SCANNER NAMES wayland-scanner)
|
||||||
|
|
||||||
|
# EGL is required
|
||||||
|
find_path(
|
||||||
|
WAYLAND_EGL_INCLUDE_DIR
|
||||||
|
NAMES wayland-egl.h
|
||||||
|
)
|
||||||
|
find_library(
|
||||||
|
WAYLAND_EGL_LIBRARY
|
||||||
|
NAMES wayland-egl libwayland-egl
|
||||||
|
)
|
||||||
|
|
||||||
|
if( (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY AND WAYLAND_SCANNER)
|
||||||
|
AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARY))
|
||||||
|
message(STATUS "Found Wayland: ${WAYLAND_CLIENT_LIBRARY}")
|
||||||
|
|
||||||
|
set(WAYLAND_PROTOCOLS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/protocols)
|
||||||
|
set(WAYLAND_HEADERS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/headers)
|
||||||
|
set(WAYLAND_SOURCES_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/sources)
|
||||||
|
|
||||||
|
# Search for base protocol xml
|
||||||
|
find_file(WAYLAND_PROTOCOL NAMES wayland.xml PATHS /usr/share/wayland /usr/share/wayland-protocols)
|
||||||
|
file(COPY ${WAYLAND_PROTOCOL} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
|
||||||
|
|
||||||
|
# search for xdg protocols
|
||||||
|
find_file(XDG_SHELL_PROTOCOL NAMES xdg-shell.xml PATHS /usr/share/wayland-protocols/stable/xdg-shell)
|
||||||
|
file(COPY ${XDG_SHELL_PROTOCOL} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
|
||||||
|
|
||||||
|
# include sub-dependencies
|
||||||
|
include("${FENNEC_SOURCE_DIR}/cmake/xkb.cmake")
|
||||||
|
fennec_check_xkb()
|
||||||
|
|
||||||
|
# generate protocols, based on SDL3
|
||||||
|
file(GLOB WAYLAND_PROTOCOLS_XML RELATIVE "${WAYLAND_PROTOCOLS_DIR}" "${WAYLAND_PROTOCOLS_DIR}/*.xml")
|
||||||
|
foreach(_XML IN LISTS WAYLAND_PROTOCOLS_XML)
|
||||||
|
get_filename_component(_FILE ${_XML} NAME_WLE)
|
||||||
|
fennec_wayland_get_header("${WAYLAND_SCANNER}" "${WAYLAND_PROTOCOLS_DIR}/${_XML}" "${_FILE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add sources and libraries
|
||||||
|
get_filename_component(
|
||||||
|
WAYLAND_CLIENT_LIBRARY
|
||||||
|
${WAYLAND_CLIENT_LIBRARY}
|
||||||
|
NAME
|
||||||
|
)
|
||||||
|
get_filename_component(
|
||||||
|
WAYLAND_EGL_LIBRARY
|
||||||
|
${WAYLAND_EGL_LIBRARY}
|
||||||
|
NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
set(WAYLAND_CLIENT_FOUND 1)
|
||||||
|
set(WAYLAND_EGL_FOUND 1)
|
||||||
|
set(FENNEC_GRAPHICS_WANT_EGL 1)
|
||||||
|
|
||||||
|
fennec_add_sources(
|
||||||
|
# Dynamic Library Files
|
||||||
|
include/fennec/platform/linux/wayland/lib/sym.h
|
||||||
|
include/fennec/platform/linux/wayland/lib/wayland.h
|
||||||
|
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
|
||||||
|
|
||||||
|
# Fennec Files
|
||||||
|
include/fennec/platform/linux/wayland/display.h source/platform/linux/wayland/display.cpp
|
||||||
|
include/fennec/platform/linux/wayland/window.h source/platform/linux/wayland/window.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
fennec_add_definitions(
|
||||||
|
FENNEC_HAS_WAYLAND=1
|
||||||
|
FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"
|
||||||
|
FENNEC_LIB_WAYLAND_EGL="${WAYLAND_EGL_LIBRARY}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
58
cmake/xkb.cmake
Normal file
58
cmake/xkb.cmake
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
# this script finds libxkbcommon and dependencies
|
||||||
|
|
||||||
|
macro(fennec_check_xkb)
|
||||||
|
set(XKB_FOUND 0)
|
||||||
|
|
||||||
|
find_path(
|
||||||
|
XKB_INCLUDE_DIR
|
||||||
|
NAMES xkbcommon/xkbcommon.h
|
||||||
|
)
|
||||||
|
find_library(
|
||||||
|
XKB_LIBRARY
|
||||||
|
NAMES xkbcommon libxkbcommon
|
||||||
|
)
|
||||||
|
|
||||||
|
if(XKB_INCLUDE_DIR AND XKB_LIBRARY)
|
||||||
|
message(STATUS "Found XKB: ${XKB_LIBRARY}")
|
||||||
|
|
||||||
|
get_filename_component(
|
||||||
|
XKB_LIBRARY
|
||||||
|
${XKB_LIBRARY}
|
||||||
|
NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
set(XKB_FOUND 1)
|
||||||
|
|
||||||
|
fennec_add_sources(
|
||||||
|
# Dynamic Library Files
|
||||||
|
include/fennec/platform/linux/xkb/lib/sym.h
|
||||||
|
include/fennec/platform/linux/xkb/lib/xkb.h
|
||||||
|
include/fennec/platform/linux/xkb/lib/loader.h source/platform/linux/xkb/lib/loader.cpp
|
||||||
|
|
||||||
|
# Fennec files
|
||||||
|
)
|
||||||
|
|
||||||
|
fennec_add_definitions(
|
||||||
|
FENNEC_HAS_XKB=1
|
||||||
|
FENNEC_LIB_XKB="${XKB_LIBRARY}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
417774
conv/GLSLangSpec.4.60.pdf
Normal file
417774
conv/GLSLangSpec.4.60.pdf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
conv/GNUCodingStandards.pdf
Normal file
BIN
conv/GNUCodingStandards.pdf
Normal file
Binary file not shown.
265
doxy/DoxyLayout.xml
Normal file
265
doxy/DoxyLayout.xml
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<doxygenlayout version="1.0">
|
||||||
|
<!-- Generated by doxygen 1.9.8 -->
|
||||||
|
<!-- Navigation index tabs for HTML output -->
|
||||||
|
<navindex>
|
||||||
|
<tab type="mainpage" visible="yes" title=""/>
|
||||||
|
<tab type="pages" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="topics" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="modules" visible="yes" title="" intro="">
|
||||||
|
<tab type="modulelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="modulemembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="namespaces" visible="yes" title="">
|
||||||
|
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="concepts" visible="yes" title="">
|
||||||
|
</tab>
|
||||||
|
<tab type="interfaces" visible="yes" title="">
|
||||||
|
<tab type="interfacelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="classes" visible="yes" title="">
|
||||||
|
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="structs" visible="yes" title="">
|
||||||
|
<tab type="structlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="exceptions" visible="yes" title="">
|
||||||
|
<tab type="exceptionlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="files" visible="yes" title="">
|
||||||
|
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="globals" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="examples" visible="yes" title="" intro=""/>
|
||||||
|
</navindex>
|
||||||
|
|
||||||
|
<!-- Layout definition for a class page -->
|
||||||
|
<class>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
|
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||||
|
<collaborationgraph visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedclasses visible="yes" title=""/>
|
||||||
|
<publictypes title=""/>
|
||||||
|
<services title=""/>
|
||||||
|
<interfaces title=""/>
|
||||||
|
<publicslots title=""/>
|
||||||
|
<signals title=""/>
|
||||||
|
<publicmethods title=""/>
|
||||||
|
<publicstaticmethods title=""/>
|
||||||
|
<publicattributes title=""/>
|
||||||
|
<publicstaticattributes title=""/>
|
||||||
|
<protectedtypes title=""/>
|
||||||
|
<protectedslots title=""/>
|
||||||
|
<protectedmethods title=""/>
|
||||||
|
<protectedstaticmethods title=""/>
|
||||||
|
<protectedattributes title=""/>
|
||||||
|
<protectedstaticattributes title=""/>
|
||||||
|
<packagetypes title=""/>
|
||||||
|
<packagemethods title=""/>
|
||||||
|
<packagestaticmethods title=""/>
|
||||||
|
<packageattributes title=""/>
|
||||||
|
<packagestaticattributes title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
<privatetypes title=""/>
|
||||||
|
<privateslots title=""/>
|
||||||
|
<privatemethods title=""/>
|
||||||
|
<privatestaticmethods title=""/>
|
||||||
|
<privateattributes title=""/>
|
||||||
|
<privatestaticattributes title=""/>
|
||||||
|
<friends title=""/>
|
||||||
|
<related title="" subtitle=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<services title=""/>
|
||||||
|
<interfaces title=""/>
|
||||||
|
<constructors title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<related title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<allmemberslink visible="yes"/>
|
||||||
|
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<!-- Layout definition for a namespace page -->
|
||||||
|
<namespace>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestednamespaces visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<structs visible="yes" title=""/>
|
||||||
|
<exceptions visible="yes" title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<sequences title=""/>
|
||||||
|
<dictionaries title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<sequences title=""/>
|
||||||
|
<dictionaries title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</namespace>
|
||||||
|
|
||||||
|
<!-- Layout definition for a concept page -->
|
||||||
|
<concept>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
|
<definition visible="yes" title=""/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</concept>
|
||||||
|
|
||||||
|
<!-- Layout definition for a file page -->
|
||||||
|
<file>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||||
|
<includegraph visible="yes"/>
|
||||||
|
<includedbygraph visible="yes"/>
|
||||||
|
<sourcelink visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<structs visible="yes" title=""/>
|
||||||
|
<exceptions visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<sequences title=""/>
|
||||||
|
<dictionaries title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<sequences title=""/>
|
||||||
|
<dictionaries title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection/>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<!-- Layout definition for a group page -->
|
||||||
|
<group>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<groupgraph visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedgroups visible="yes" title=""/>
|
||||||
|
<modules visible="yes" title=""/>
|
||||||
|
<dirs visible="yes" title=""/>
|
||||||
|
<files visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<sequences title=""/>
|
||||||
|
<dictionaries title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<enumvalues title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<signals title=""/>
|
||||||
|
<publicslots title=""/>
|
||||||
|
<protectedslots title=""/>
|
||||||
|
<privateslots title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<friends title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<memberdef>
|
||||||
|
<pagedocs/>
|
||||||
|
<inlineclasses title=""/>
|
||||||
|
<defines title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<sequences title=""/>
|
||||||
|
<dictionaries title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<enumvalues title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<signals title=""/>
|
||||||
|
<publicslots title=""/>
|
||||||
|
<protectedslots title=""/>
|
||||||
|
<privateslots title=""/>
|
||||||
|
<events title=""/>
|
||||||
|
<properties title=""/>
|
||||||
|
<friends title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<!-- Layout definition for a C++20 module page -->
|
||||||
|
<module>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<exportedmodules visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<enums title=""/>
|
||||||
|
<typedefs title=""/>
|
||||||
|
<functions title=""/>
|
||||||
|
<variables title=""/>
|
||||||
|
<membergroups title=""/>
|
||||||
|
</memberdecl>
|
||||||
|
<memberdecl>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- Layout definition for a directory page -->
|
||||||
|
<directory>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<directorygraph visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<dirs visible="yes"/>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
</directory>
|
||||||
|
</doxygenlayout>
|
||||||
@@ -784,7 +784,7 @@ SHOW_USED_FILES = YES
|
|||||||
# (if specified).
|
# (if specified).
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
SHOW_FILES = NO
|
SHOW_FILES = YES
|
||||||
|
|
||||||
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
|
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
|
||||||
# page. This will remove the Namespaces entry from the Quick Index and from the
|
# page. This will remove the Namespaces entry from the Quick Index and from the
|
||||||
@@ -815,7 +815,7 @@ FILE_VERSION_FILTER =
|
|||||||
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
|
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
|
||||||
# tag is left empty.
|
# tag is left empty.
|
||||||
|
|
||||||
LAYOUT_FILE =
|
LAYOUT_FILE = /home/medusa/Documents/Work/Personal/fennec/doxy/DoxyLayout.xml
|
||||||
|
|
||||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
||||||
# the reference definitions. This must be a list of .bib files. The .bib
|
# the reference definitions. This must be a list of .bib files. The .bib
|
||||||
@@ -943,8 +943,8 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = "/home/medusa/Documents/Work/Personal/fennec/include/" \
|
INPUT = "/home/medusa/Documents/Work/Personal/fennec/include" \
|
||||||
"/home/medusa/Documents/Work/Personal/fennec/source/" \
|
"/home/medusa/Documents/Work/Personal/fennec/source" \
|
||||||
"/home/medusa/Documents/Work/Personal/fennec/README.md"
|
"/home/medusa/Documents/Work/Personal/fennec/README.md"
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
@@ -1079,7 +1079,7 @@ EXCLUDE_SYMBOLS =
|
|||||||
# that contain example code fragments that are included (see the \include
|
# that contain example code fragments that are included (see the \include
|
||||||
# command).
|
# command).
|
||||||
|
|
||||||
EXAMPLE_PATH = "/home/medusa/Documents/Work/Personal/fennec"
|
EXAMPLE_PATH = "/home/medusa/Documents/Work/Personal/fennec/examples"
|
||||||
|
|
||||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
||||||
@@ -1099,7 +1099,7 @@ EXAMPLE_RECURSIVE = NO
|
|||||||
# that contain images that are to be included in the documentation (see the
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH =
|
IMAGE_PATH = "/home/medusa/Documents/Work/Personal/fennec/doxy/static"
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
@@ -1306,7 +1306,7 @@ CLANG_DATABASE_PATH =
|
|||||||
# classes, structs, unions or interfaces.
|
# classes, structs, unions or interfaces.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
ALPHABETICAL_INDEX = NO
|
ALPHABETICAL_INDEX = YES
|
||||||
|
|
||||||
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
||||||
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
||||||
@@ -1981,7 +1981,7 @@ GENERATE_LATEX = NO
|
|||||||
# The default directory is: latex.
|
# The default directory is: latex.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
LATEX_OUTPUT = latex
|
LATEX_OUTPUT = ./latex
|
||||||
|
|
||||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||||
# invoked.
|
# invoked.
|
||||||
@@ -2664,7 +2664,7 @@ TEMPLATE_RELATIONS = NO
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDE_GRAPH = YES
|
INCLUDE_GRAPH = NO
|
||||||
|
|
||||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||||
# set to YES then doxygen will generate a graph for each documented file showing
|
# set to YES then doxygen will generate a graph for each documented file showing
|
||||||
@@ -2676,7 +2676,7 @@ INCLUDE_GRAPH = YES
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDED_BY_GRAPH = YES
|
INCLUDED_BY_GRAPH = NO
|
||||||
|
|
||||||
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
||||||
# dependency graph for every global function or class method.
|
# dependency graph for every global function or class method.
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ SHOW_USED_FILES = YES
|
|||||||
# (if specified).
|
# (if specified).
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
SHOW_FILES = NO
|
SHOW_FILES = YES
|
||||||
|
|
||||||
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
|
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
|
||||||
# page. This will remove the Namespaces entry from the Quick Index and from the
|
# page. This will remove the Namespaces entry from the Quick Index and from the
|
||||||
@@ -815,7 +815,7 @@ FILE_VERSION_FILTER =
|
|||||||
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
|
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
|
||||||
# tag is left empty.
|
# tag is left empty.
|
||||||
|
|
||||||
LAYOUT_FILE =
|
LAYOUT_FILE = @PROJECT_SOURCE_DIR@/doxy/DoxyLayout.xml
|
||||||
|
|
||||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
||||||
# the reference definitions. This must be a list of .bib files. The .bib
|
# the reference definitions. This must be a list of .bib files. The .bib
|
||||||
@@ -943,8 +943,8 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = "@PROJECT_SOURCE_DIR@/include/" \
|
INPUT = "@PROJECT_SOURCE_DIR@/include" \
|
||||||
"@PROJECT_SOURCE_DIR@/source/" \
|
"@PROJECT_SOURCE_DIR@/source" \
|
||||||
"@PROJECT_SOURCE_DIR@/README.md"
|
"@PROJECT_SOURCE_DIR@/README.md"
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
@@ -1079,7 +1079,7 @@ EXCLUDE_SYMBOLS =
|
|||||||
# that contain example code fragments that are included (see the \include
|
# that contain example code fragments that are included (see the \include
|
||||||
# command).
|
# command).
|
||||||
|
|
||||||
EXAMPLE_PATH = "@PROJECT_SOURCE_DIR@"
|
EXAMPLE_PATH = "@PROJECT_SOURCE_DIR@/examples"
|
||||||
|
|
||||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
||||||
@@ -1099,7 +1099,7 @@ EXAMPLE_RECURSIVE = NO
|
|||||||
# that contain images that are to be included in the documentation (see the
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH =
|
IMAGE_PATH = "@PROJECT_SOURCE_DIR@/doxy/static"
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
@@ -1306,7 +1306,7 @@ CLANG_DATABASE_PATH =
|
|||||||
# classes, structs, unions or interfaces.
|
# classes, structs, unions or interfaces.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
ALPHABETICAL_INDEX = NO
|
ALPHABETICAL_INDEX = YES
|
||||||
|
|
||||||
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
||||||
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
||||||
@@ -1981,7 +1981,7 @@ GENERATE_LATEX = NO
|
|||||||
# The default directory is: latex.
|
# The default directory is: latex.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
LATEX_OUTPUT = latex
|
LATEX_OUTPUT = ./latex
|
||||||
|
|
||||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||||
# invoked.
|
# invoked.
|
||||||
@@ -2664,7 +2664,7 @@ TEMPLATE_RELATIONS = NO
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDE_GRAPH = YES
|
INCLUDE_GRAPH = NO
|
||||||
|
|
||||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||||
# set to YES then doxygen will generate a graph for each documented file showing
|
# set to YES then doxygen will generate a graph for each documented file showing
|
||||||
@@ -2676,7 +2676,7 @@ INCLUDE_GRAPH = YES
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDED_BY_GRAPH = YES
|
INCLUDED_BY_GRAPH = NO
|
||||||
|
|
||||||
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
||||||
# dependency graph for every global function or class method.
|
# dependency graph for every global function or class method.
|
||||||
|
|||||||
@@ -287,3 +287,8 @@ html.dark-mode {
|
|||||||
td.odd_c {
|
td.odd_c {
|
||||||
background-color: var(--odd-color)
|
background-color: var(--odd-color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a + h2.groupheader {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||||
<!--BEGIN DISABLE_INDEX-->
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
<!--BEGIN FULL_SIDEBAR-->
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
<script type="text/javascript">var page_layout=1;</script>
|
<script type="text/javascript">var layout=1;</script>
|
||||||
<!--END FULL_SIDEBAR-->
|
<!--END FULL_SIDEBAR-->
|
||||||
<!--END DISABLE_INDEX-->
|
<!--END DISABLE_INDEX-->
|
||||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||||
|
|||||||
71
doxy/retrieve-emojis.py
Normal file
71
doxy/retrieve-emojis.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# script to download the emoticons from GitHub and to produce a table for
|
||||||
|
# inclusion in Doxygen. Works with python 2.7+ and python 3.x
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
try:
|
||||||
|
import urllib.request as urlrequest
|
||||||
|
except ImportError:
|
||||||
|
import urllib as urlrequest
|
||||||
|
|
||||||
|
unicode_re = re.compile(r'.*?/unicode/(.*?).png\?.*')
|
||||||
|
|
||||||
|
def get_emojis():
|
||||||
|
response = urlrequest.urlopen('https://api.github.com/emojis')
|
||||||
|
raw_data = response.read()
|
||||||
|
return json.loads(raw_data)
|
||||||
|
|
||||||
|
def download_images(dir_name, silent):
|
||||||
|
if not os.path.exists(dir_name):
|
||||||
|
os.makedirs(dir_name)
|
||||||
|
json_data = get_emojis()
|
||||||
|
num_items = len(json_data)
|
||||||
|
cur_item=0
|
||||||
|
for image,url in sorted(json_data.items()):
|
||||||
|
image_name = image+'.png'
|
||||||
|
cur_item=cur_item+1
|
||||||
|
if url.find('/unicode/')==-1 or not os.path.isfile(dir_name+'/'+image_name):
|
||||||
|
success = True
|
||||||
|
with open(dir_name+'/'+image_name,'wb') as file:
|
||||||
|
if not silent:
|
||||||
|
print('%s/%s: fetching %s' % (cur_item,num_items,image_name))
|
||||||
|
try:
|
||||||
|
file.write(urlrequest.urlopen(url).read())
|
||||||
|
except:
|
||||||
|
print('Unable to fetch %s' % (image_name))
|
||||||
|
success = False
|
||||||
|
if not success:
|
||||||
|
os.remove(dir_name+'/'+image_name)
|
||||||
|
else:
|
||||||
|
if not silent:
|
||||||
|
print('%s/%s: skipping %s' % (cur_item,num_items,image_name))
|
||||||
|
|
||||||
|
def produce_table():
|
||||||
|
json_data = get_emojis()
|
||||||
|
lines = []
|
||||||
|
for image,url in sorted(json_data.items()):
|
||||||
|
match = unicode_re.match(url)
|
||||||
|
if match:
|
||||||
|
unicodes = match.group(1).split('-')
|
||||||
|
unicodes_html = ''.join(["&#x"+x+";" for x in unicodes])
|
||||||
|
image_str = "\":"+image+":\","
|
||||||
|
unicode_str = "\""+unicodes_html+"\""
|
||||||
|
lines.append(' { %-42s %-38s }' % (image_str,unicode_str))
|
||||||
|
out_str = ',\n'.join(lines)
|
||||||
|
print("{")
|
||||||
|
print(out_str)
|
||||||
|
print("};")
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument('-d','--dir',help='directory to place images in')
|
||||||
|
parser.add_argument('-t','--table',help='generate code fragment',action='store_true')
|
||||||
|
parser.add_argument('-s','--silent',help='silent mode',action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.table:
|
||||||
|
produce_table()
|
||||||
|
if args.dir:
|
||||||
|
download_images(args.dir, args.silent)
|
||||||
4
doxy/static/graphs/containers/rdtree.svg
Normal file
4
doxy/static/graphs/containers/rdtree.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 60 KiB |
1
external/cpptrace
vendored
Submodule
1
external/cpptrace
vendored
Submodule
Submodule external/cpptrace added at 787d8af6f6
36
gdb/fennec/__init__.py
Normal file
36
gdb/fennec/__init__.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# GDB CODE =============================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
from . import containers
|
||||||
|
from . import strings
|
||||||
|
from . import memory
|
||||||
|
from . import utility
|
||||||
|
from . import filesystem
|
||||||
|
from . import math
|
||||||
|
|
||||||
|
def register_printers(obj):
|
||||||
|
gdb.printing.register_pretty_printer(obj, containers.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, strings.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, memory.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, filesystem.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, math.printer)
|
||||||
481
gdb/fennec/containers.py
Normal file
481
gdb/fennec/containers.py
Normal file
@@ -0,0 +1,481 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
# OPTIONAL =============================================================================================================
|
||||||
|
class OptionalPrinter:
|
||||||
|
"""Print a fennec::optional"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
is_initialized = self.val['_set']
|
||||||
|
if is_initialized:
|
||||||
|
return "{{ value = {} }}".format(self.val['_val'])
|
||||||
|
else:
|
||||||
|
return "{ empty }"
|
||||||
|
|
||||||
|
# PAIR =================================================================================================================
|
||||||
|
class PairPrinter:
|
||||||
|
"""Print a fennec::optional"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ first = " + str(self.val['first']) + ", second = " + str(self.val['second']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return ("first", self.val['first']), ("second", self.val['second'])
|
||||||
|
|
||||||
|
|
||||||
|
# TUPLE ================================================================================================================
|
||||||
|
|
||||||
|
class TuplePrinter:
|
||||||
|
"""Print a fennec::tuple"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.fields = val.type.fields()[0].type.fields()
|
||||||
|
self.elems = val
|
||||||
|
self.count = len(self.fields)
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return " { size = " + str(len(self.fields)) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.elems.cast(self.fields[i].type)['value']) for i in range(self.count))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ARRAY ================================================================================================================
|
||||||
|
class ArrayPrinter:
|
||||||
|
"""Print a fennec::array"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length = " + str(self.val['elements'].type.range()[1] + 1) + " }"
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
start = self.val['elements']
|
||||||
|
return (('[{}]'.format(i), start[i]) for i in range(0, self.val['elements'].type.range()[1] + 1))
|
||||||
|
|
||||||
|
|
||||||
|
# DYNARRAY =============================================================================================================
|
||||||
|
class DynArrayPrinter:
|
||||||
|
"""Print a fennec::dynarray"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_alloc']['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
size = int(self.val['_size'])
|
||||||
|
start = self.val['_alloc']['_data']
|
||||||
|
return (('[{}]'.format(i), start[i]) for i in range(size))
|
||||||
|
|
||||||
|
|
||||||
|
# LIST =================================================================================================================
|
||||||
|
class ListPrinter:
|
||||||
|
"""Print a fennec::list"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.list = val
|
||||||
|
self.node = self.list['_root']
|
||||||
|
self.index = 0
|
||||||
|
self.table = self.list['_table']['_data']
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.node == 18446744073709551615:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
value = self.table[self.node]['value']['_val']
|
||||||
|
self.node = self.table[self.node]['next']
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_table']['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.val)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# DEQUE ================================================================================================================
|
||||||
|
|
||||||
|
class DequePrinter:
|
||||||
|
"""Print a fennec::deque"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, start):
|
||||||
|
self.node = start
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.node is None:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
value = self.node.dereference()['value']
|
||||||
|
|
||||||
|
self.node = self.node.dereference()['next']
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.first = val['_first']
|
||||||
|
self.last = val['_last']
|
||||||
|
self.size = val['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.first is None:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ length " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.first)
|
||||||
|
|
||||||
|
|
||||||
|
# SET ==================================================================================================================
|
||||||
|
|
||||||
|
class SetPrinter:
|
||||||
|
"""Print a fennec::set"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, table, capacity):
|
||||||
|
self.table = table
|
||||||
|
self.capacity = capacity
|
||||||
|
self.node = 0
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
while self.node < self.capacity:
|
||||||
|
if self.table[self.node]['value']['_set']:
|
||||||
|
break
|
||||||
|
self.node = self.node + 1
|
||||||
|
|
||||||
|
if self.node >= self.capacity:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
value = self.table[self.node]['value']['_val']
|
||||||
|
self.node = self.node + 1
|
||||||
|
self.index = self.index + 1
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.table = val['_alloc']['_data']
|
||||||
|
self.capacity = val['_alloc']['_capacity']
|
||||||
|
self.size = val['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.table, self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
# MAP ==================================================================================================================
|
||||||
|
|
||||||
|
class MapPrinter:
|
||||||
|
"""Print a fennec::map"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, table, capacity):
|
||||||
|
self.table = table
|
||||||
|
self.capacity = capacity
|
||||||
|
self.node = 0
|
||||||
|
self.index = 0
|
||||||
|
self.move = False
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
while self.node < self.capacity:
|
||||||
|
if self.table[self.node]['value']['_set']:
|
||||||
|
break
|
||||||
|
self.node = self.node + 1
|
||||||
|
|
||||||
|
if self.node >= self.capacity:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
pair = self.table[self.node]['value']['_val']
|
||||||
|
key = pair['first']
|
||||||
|
val = pair['second']
|
||||||
|
|
||||||
|
if not self.move:
|
||||||
|
self.move = True
|
||||||
|
return 'key' + str(i), key
|
||||||
|
else:
|
||||||
|
self.move = False
|
||||||
|
self.index = self.index + 1
|
||||||
|
self.node = self.node + 1
|
||||||
|
return 'value' + str(i), val
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.table = val['_set']['_alloc']['_data']
|
||||||
|
self.capacity = val['_set']['_alloc']['_capacity']
|
||||||
|
self.size = val['_set']['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.table, self.capacity)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'map'
|
||||||
|
|
||||||
|
|
||||||
|
# OBJECT_POOL ==========================================================================================================
|
||||||
|
class ObjectPoolPrinter:
|
||||||
|
"""Print a fennec::object_pool"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.list = val
|
||||||
|
self.index = 0
|
||||||
|
self.capacity = self.list['_table']['_alloc']['_capacity']
|
||||||
|
self.table = self.list['_table']['_alloc']['_data']
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
while True:
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
if self.index >= self.capacity:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
if bool(self.table[i]['_set']):
|
||||||
|
value = self.table[i]['_val']
|
||||||
|
break
|
||||||
|
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_table']['_alloc']['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.val)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# RDTREE ===============================================================================================================
|
||||||
|
|
||||||
|
class RDTreePrinter:
|
||||||
|
"""Print a fennec::rdtree"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, tree, node, capacity):
|
||||||
|
self.tree = tree
|
||||||
|
self.capacity = capacity
|
||||||
|
self.visit = deque()
|
||||||
|
|
||||||
|
self.visit.append((node, 0, 0))
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if len(self.visit) == 0:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
node = self.visit[0][0]
|
||||||
|
i = self.visit[0][1]
|
||||||
|
depth = self.visit[0][2]
|
||||||
|
self.visit.popleft()
|
||||||
|
|
||||||
|
value = self.tree[node]['value']
|
||||||
|
|
||||||
|
nnext = self.tree[node]['next']
|
||||||
|
nprev = self.tree[node]['prev']
|
||||||
|
nprevc = self.tree[nprev]['child'] if nprev != 18446744073709551615 else 18446744073709551615
|
||||||
|
child = self.tree[node]['child']
|
||||||
|
n_chld = self.tree[node]['num_children']
|
||||||
|
|
||||||
|
index = '⠀' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
|
||||||
|
|
||||||
|
if nnext < self.capacity:
|
||||||
|
self.visit.appendleft((nnext, i + 1, depth))
|
||||||
|
|
||||||
|
if child < self.capacity:
|
||||||
|
self.visit.appendleft((child, 0, depth + 1))
|
||||||
|
|
||||||
|
# ┌ ─ ├ └
|
||||||
|
|
||||||
|
if nnext != 18446744073709551615:
|
||||||
|
index += '├'
|
||||||
|
else:
|
||||||
|
index += '└'
|
||||||
|
|
||||||
|
index += '─'
|
||||||
|
index += '[{}, {}]'.format(node, i)
|
||||||
|
return index, value
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.tree = val['_table']['_data']
|
||||||
|
self.size = val['_size']
|
||||||
|
self.capacity = val['_table']['_capacity']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.tree, 0, self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
# Graph ================================================================================================================
|
||||||
|
|
||||||
|
class GraphPrinter:
|
||||||
|
"""Print a fennec::graph"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.node_pool = val['_vertex_pool']['_table']['_alloc']['_data']
|
||||||
|
self.max_nodes = val['_vertex_pool']['_table']['_alloc']['_capacity']
|
||||||
|
self.conn_map = val['_edge_map']['_alloc']['_data']
|
||||||
|
self.max_conn = val['_edge_map']['_size']
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.index >= self.max_nodes:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
while not bool(self.node_pool[i]['_set']):
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
conns = self.get_conns(i)
|
||||||
|
value = self.node_pool[i]['_val']
|
||||||
|
|
||||||
|
return '[{} -> {{{}}}]'.format(i, str(conns)), value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_conns(self, index):
|
||||||
|
indices = []
|
||||||
|
|
||||||
|
if index >= self.max_conn:
|
||||||
|
return indices
|
||||||
|
|
||||||
|
map = self.conn_map[index]['_set']
|
||||||
|
max_conns = map['_alloc']['_capacity']
|
||||||
|
conns = map['_alloc']['_data']
|
||||||
|
|
||||||
|
print(max_conns)
|
||||||
|
|
||||||
|
if max_conns == 0:
|
||||||
|
return indices
|
||||||
|
|
||||||
|
for i in range(0, max_conns):
|
||||||
|
if bool(conns[i]['value']['_set']):
|
||||||
|
conn = conns[i]['value']['_val']
|
||||||
|
indices.append(str(int(conn['first'])))
|
||||||
|
|
||||||
|
return indices
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.size = val['_vertex_pool']['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.val)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering containers")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::containers")
|
||||||
|
pp.add_printer('fennec::array', '^fennec::array<.*>$', ArrayPrinter)
|
||||||
|
pp.add_printer('fennec::deque', '^fennec::deque<.*>$', DequePrinter)
|
||||||
|
pp.add_printer('fennec::dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter)
|
||||||
|
pp.add_printer('fennec::graph', '^fennec::graph<.*>$', GraphPrinter)
|
||||||
|
pp.add_printer('fennec::list', '^fennec::list<.*>$', ListPrinter)
|
||||||
|
pp.add_printer('fennec::map', '^fennec::map<.*>$', MapPrinter)
|
||||||
|
pp.add_printer('fennec::object_pool', '^fennec::object_pool<.*>$', ObjectPoolPrinter)
|
||||||
|
pp.add_printer('fennec::optional', '^fennec::optional<.*>$', OptionalPrinter)
|
||||||
|
pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter)
|
||||||
|
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
|
||||||
|
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
|
||||||
|
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
60
gdb/fennec/filesystem.py
Normal file
60
gdb/fennec/filesystem.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
|
||||||
|
# PATH =================================================================================================================
|
||||||
|
class PathPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val['_str']['_str']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
value = "\"" + self.val['_data'].string('', 'replace', self.val['_capacity'] - 1) + "\""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# PATH =================================================================================================================
|
||||||
|
class FilePrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.path = val['_path']['_str']['_str']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.val['_handle']:
|
||||||
|
value = "{ path = \"" + self.path['_data'].string('', 'replace', self.path['_capacity'] - 1) + "\" }"
|
||||||
|
return value
|
||||||
|
return "{ closed }"
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering filesystem")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::filesystem")
|
||||||
|
pp.add_printer('fennec::path', '^fennec::path$', PathPrinter)
|
||||||
|
pp.add_printer('fennec::file', '^fennec::file$', FilePrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
99
gdb/fennec/math.py
Normal file
99
gdb/fennec/math.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
import os
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
from . import utility
|
||||||
|
|
||||||
|
# VECTOR =================================================================================================================
|
||||||
|
class VectorPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.base = val['data']['elements']
|
||||||
|
self.len = self.base.type.range()[1] + 1
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
res = "< "
|
||||||
|
if self.len > 0:
|
||||||
|
res += "x = " + str(self.val['x'])
|
||||||
|
if self.len > 1:
|
||||||
|
res += ", y = " + str(self.val['y'])
|
||||||
|
if self.len > 2:
|
||||||
|
res += ", z = " + str(self.val['z'])
|
||||||
|
if self.len > 3:
|
||||||
|
res += ", w = " + str(self.val['w'])
|
||||||
|
res += " >"
|
||||||
|
return res
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.base[i]) for i in range(self.len))
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# PATH =================================================================================================================
|
||||||
|
class QuaternionPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.base = val['data']['elements']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
res = ("< "
|
||||||
|
+ str(self.val['x']) + " i + "
|
||||||
|
+ str(self.val['y']) + " j + "
|
||||||
|
+ str(self.val['z']) + " k + "
|
||||||
|
+ str(self.val['w']))
|
||||||
|
res += " >"
|
||||||
|
return res
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.base[i]) for i in range(4))
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# VECTOR =================================================================================================================
|
||||||
|
class MatrixPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.columns = val['data']['elements']
|
||||||
|
self.num_columns = self.columns.type.range()[1] + 1
|
||||||
|
self.num_rows = val.type.template_argument(1)
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ rows = " + str(self.num_rows) + ", columns = " + str(self.num_columns) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.columns[i]) for i in range(self.num_columns))
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering filesystem")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::math")
|
||||||
|
pp.add_printer('fennec::vector', '^fennec::vector<.*>$', VectorPrinter)
|
||||||
|
pp.add_printer('fennec::quaternion', '^fennec::quaternion<.*>$', QuaternionPrinter)
|
||||||
|
pp.add_printer('fennec::matrix', '^fennec::matrix<.*>$', MatrixPrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
43
gdb/fennec/memory.py
Normal file
43
gdb/fennec/memory.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# ALLOCATION ===========================================================================================================
|
||||||
|
class AllocationPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ capacity = " + str(self.val['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
size = int(self.val['_capacity'])
|
||||||
|
start = self.val['_data']
|
||||||
|
return (('[{}]'.format(i), start[i]) for i in range(size))
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering memory")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::memory")
|
||||||
|
pp.add_printer('fennec::allocation', '^fennec::allocation<.*>$', AllocationPrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
61
gdb/fennec/strings.py
Normal file
61
gdb/fennec/strings.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# CSTRING ==============================================================================================================
|
||||||
|
class CStringPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
value = "\"" + self.val['_str'].string('', 'replace', self.val['_size']) + "\""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# STRING ===============================================================================================================
|
||||||
|
class StringPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val['_str']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
value = "\"" + self.val['_data'].string('', 'replace', self.val['_capacity'] - 1) + "\""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering strings")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::strings")
|
||||||
|
pp.add_printer('fennec::cstring', '^fennec::cstring$', CStringPrinter)
|
||||||
|
pp.add_printer('fennec::wcstring', '^fennec::wcstring$', CStringPrinter)
|
||||||
|
pp.add_printer('fennec::string', '^fennec::_string<.*>$', StringPrinter)
|
||||||
|
pp.add_printer('fennec::wstring', '^fennec::_wstring<.*>$', StringPrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
20
gdb/fennec/utility.py
Normal file
20
gdb/fennec/utility.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
def printMembers(obj):
|
||||||
|
print(str(dir(obj)))
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file array.h
|
/// \file array.h
|
||||||
/// \brief fennec::array definition & implementation
|
/// \brief A header containing the definition for a static/stack allocated array
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -33,72 +33,55 @@
|
|||||||
#define FENNEC_CONTAINERS_ARRAY_H
|
#define FENNEC_CONTAINERS_ARRAY_H
|
||||||
|
|
||||||
#include <fennec/lang/types.h>
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \brief wrapper for fixed size arrays
|
/// \brief Data Structure that defines a compile-time allocated array
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ✅ |
|
||||||
|
/// | dynamic | ⛔ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | ⛔ |
|
||||||
|
/// | deletion | ⛔ |
|
||||||
|
///
|
||||||
/// \tparam ValueT value type
|
/// \tparam ValueT value type
|
||||||
/// \tparam ElemV number of elements
|
/// \tparam ElemV number of elements
|
||||||
///
|
|
||||||
///
|
|
||||||
template<typename ValueT, size_t ElemV>
|
template<typename ValueT, size_t ElemV>
|
||||||
struct array
|
struct array {
|
||||||
{
|
|
||||||
///
|
|
||||||
/// \brief backing c-style array handle
|
|
||||||
ValueT elements[ElemV];
|
|
||||||
|
|
||||||
/// \name Element Access
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using value_t = ValueT; ///< Alias for `ValueT`
|
||||||
|
|
||||||
|
// Public Members ======================================================================================================
|
||||||
|
|
||||||
|
/// \name Public Members
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \copydetails array::at(size_t) const
|
/// \brief backing c-style array handle
|
||||||
constexpr ValueT& at(size_t i) { static_assert(i < ElemV); assert(i < ElemV); return elements[i]; }
|
value_t data[ElemV];
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief access specified element, **with bounds checking**
|
|
||||||
/// \details Returns a reference to the element at \c i
|
|
||||||
/// \param i index of the element to return
|
|
||||||
/// \return reference to the requested element
|
|
||||||
///
|
|
||||||
/// \par Time-Complexity
|
|
||||||
/// Constant
|
|
||||||
///
|
|
||||||
/// \par Space-Complexity
|
|
||||||
/// Constant
|
|
||||||
constexpr const ValueT& at(size_t i) const { static_assert(i < ElemV); assert(i < ElemV); return elements[i]; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \copydetails array::operator[](size_t) const
|
|
||||||
constexpr ValueT& operator[](size_t i) { return elements[i]; }
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief access specified element
|
|
||||||
/// \details Returns a reference to the element at \c i
|
|
||||||
/// \param i index of the element to return
|
|
||||||
/// \return reference to the requested element
|
|
||||||
///
|
|
||||||
/// \par Time-Complexity
|
|
||||||
/// Constant
|
|
||||||
///
|
|
||||||
/// \par Space-Complexity
|
|
||||||
/// Constant
|
|
||||||
constexpr const ValueT& operator[](size_t i) const { return elements[i]; }
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \name Capacity
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -115,21 +98,128 @@ struct array
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Element Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \copydetails array::operator[](size_t) const
|
||||||
|
constexpr value_t& operator[](size_t i) {
|
||||||
|
assertd(i < ElemV, "Array Out of Bounds");
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief access specified element
|
||||||
|
/// \details Returns a reference to the element at \c i
|
||||||
|
/// \param i index of the element to return
|
||||||
|
/// \return reference to the requested element
|
||||||
|
///
|
||||||
|
/// \par Time-Complexity
|
||||||
|
/// Constant
|
||||||
|
///
|
||||||
|
/// \par Space-Complexity
|
||||||
|
/// Constant
|
||||||
|
constexpr const value_t& operator[](size_t i) const {
|
||||||
|
assertd(i < ElemV, "Array Out of Bounds");
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access the first element
|
||||||
|
/// \returns A reference to the element at `elements[0]`
|
||||||
|
constexpr value_t& front() {
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access the first element
|
||||||
|
/// \returns A const-qualified reference to the element at `elements[0]`
|
||||||
|
constexpr const value_t& front() const {
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access the first element
|
||||||
|
/// \returns A reference to the element at `elements[ElemV - 1]`
|
||||||
|
constexpr value_t& back() {
|
||||||
|
return data[ElemV - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access the first element
|
||||||
|
/// \returns A const-qualified reference to the element at `elements[ElemV - 1]`
|
||||||
|
constexpr const value_t& back() const {
|
||||||
|
return data[ElemV - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Comparison ==========================================================================================================
|
||||||
|
|
||||||
/// \name Comparison Operators
|
/// \name Comparison Operators
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief
|
/// \brief Checks if all elements in the arrays are equal
|
||||||
friend constexpr bool_t operator==(const array& lhs, const array& rhs)
|
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
|
||||||
{ return [lhs, rhs]<size_t...i>(index_sequence<i...>) -> bool_t // Lambda Declaration, Creates Indices at Compile Time
|
return array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
||||||
{ return ((lhs[i] == rhs[i]) && ...); }(make_index_sequence<ElemV>{}); } // Lambda Implementation,
|
}
|
||||||
|
|
||||||
friend constexpr bool_t operator!=(const array& lhs, const array& rhs)
|
///
|
||||||
{ return [lhs, rhs]<size_t...i>(index_sequence<i...>) -> bool_t
|
/// \brief Checks if any element in the arrays is not equal
|
||||||
{ return ((lhs[i] != rhs[i]) || ...); }(make_index_sequence<ElemV>{}); }
|
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
|
||||||
|
return not array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
||||||
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns A pointer to the first element of the array
|
||||||
|
constexpr value_t* begin() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns A pointer to one after the end of the array
|
||||||
|
constexpr value_t* end() {
|
||||||
|
return data + ElemV;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `begin()`
|
||||||
|
/// \returns A const-qualified pointer to the first element of the array
|
||||||
|
constexpr const value_t* begin() const {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `end()`
|
||||||
|
/// \returns A const-qualified pointer to one after the end of the array
|
||||||
|
constexpr const value_t* end() const {
|
||||||
|
return data + ElemV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<size_t...i>
|
||||||
|
static bool _compare(const array& lhs, const array& rhs, const_index_sequence<i...>) {
|
||||||
|
return ((lhs[i] == rhs[i]) && ...);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
94
include/fennec/containers/containers.h
Normal file
94
include/fennec/containers/containers.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file containers.h
|
||||||
|
/// \brief fennec containers library main header
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_CONTAINERS_H
|
||||||
|
#define FENNEC_CONTAINERS_CONTAINERS_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_containers Containers Library
|
||||||
|
///
|
||||||
|
/// \brief The fennec Containers Library.
|
||||||
|
/// Includes various data structures, those specified in the C++ Standard Library, and custom data structures
|
||||||
|
/// that fennec uses.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/containers/containers.h> \endcode
|
||||||
|
///
|
||||||
|
/// \section fennec_containers_cppstdlib C++ Standard Template Library
|
||||||
|
///
|
||||||
|
/// | Symbol | Implemented | Passed |
|
||||||
|
/// |:----------------------------------------------------------------------------|:-----------:|:------:|
|
||||||
|
/// | \ref fennec::any "fennec::any" | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::array "fennec::array" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::bitset "fennec::bitset" | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::deque "fennec::deque" | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::dynarray "fennec::dynarray" `std::vector` | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::list "fennec::list" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::map "fennec::map" `std::unordered_map` | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::map_sequence "fennec::map_sequence" `std::map` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multiset "fennec::multiset" `std::unordered_multiset` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multisequence "fennec::multisequence" `std::multiset` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multimap "fennec::multimap" `std::unordered_multimap` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multimap_sequence "fennec::multimap_sequence" `std::multimap` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::optional "fennec::optional" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::pair "fennec::pair" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::sequence "fennec::sequence" `std::set` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::set "fennec::set" `std::unordered_set` | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::tuple "fennec::tuple" | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::variant "fennec::variant" | ⛔ | ⛔ |
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \section fennec_containers_fennec fennec
|
||||||
|
///
|
||||||
|
/// | Symbol | Implemented | Passed |
|
||||||
|
/// |:-------------------------|:-----------:|:------:|
|
||||||
|
/// | \ref fennec::graph | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::object_pool | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::rdtree | ✅ | ✅ |
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <fennec/containers/traversal.h>
|
||||||
|
|
||||||
|
#include <fennec/containers/array.h>
|
||||||
|
#include <fennec/containers/deque.h>
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/graph.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/map.h>
|
||||||
|
#include <fennec/containers/object_pool.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/pair.h>
|
||||||
|
#include <fennec/containers/rdtree.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
|
#include <fennec/containers/tuple.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_CONTAINERS_H
|
||||||
345
include/fennec/containers/deque.h
Normal file
345
include/fennec/containers/deque.h
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file deque.h
|
||||||
|
/// \brief A header containing the definition for a double-ended queue
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_DEQUE_H
|
||||||
|
#define FENNEC_CONTAINERS_DEQUE_H
|
||||||
|
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \brief Data structure defining a double-ended queue.
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// This behaves the similar to fennec::list, however it does not allow arbitrary access, insertion, or deletion.
|
||||||
|
/// It is one of the few data structures in this library that is stable, i.e. pointers to elements do not change.
|
||||||
|
///
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ✅ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ⛔ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT value type
|
||||||
|
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||||
|
struct deque {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using value_t = TypeT; ///< Alias for the value type
|
||||||
|
class iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node {
|
||||||
|
value_t value;
|
||||||
|
node *prev, *next;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
node(node* prev, node* next, ArgsT&&...args)
|
||||||
|
: value(fennec::forward<ArgsT>(args)...)
|
||||||
|
, prev(prev), next(next) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~node() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
|
||||||
|
using elem_t = node*;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an empty deque
|
||||||
|
deque()
|
||||||
|
: _alloc()
|
||||||
|
, _first(nullptr)
|
||||||
|
, _last(nullptr)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Constructor, initializes an empty deque with the specified allocator
|
||||||
|
/// \param alloc the allocator to copy
|
||||||
|
deque(const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _first(nullptr)
|
||||||
|
, _last(nullptr)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor
|
||||||
|
/// \param deque the deque to copy
|
||||||
|
deque(const deque& deque)
|
||||||
|
: _alloc(deque._alloc)
|
||||||
|
, _first(nullptr)
|
||||||
|
, _last(nullptr)
|
||||||
|
, _size(0) {
|
||||||
|
const elem_t node = deque._first;
|
||||||
|
while (node) {
|
||||||
|
this->push_back(node->value);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Deque Move Constructor
|
||||||
|
/// \param deque the deque to move
|
||||||
|
deque(deque&& deque) noexcept
|
||||||
|
: _alloc(deque._alloc)
|
||||||
|
, _first(deque._first)
|
||||||
|
, _last(deque._last)
|
||||||
|
, _size(deque._size) {
|
||||||
|
deque._first = nullptr;
|
||||||
|
deque._last = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, calls deque::clear
|
||||||
|
~deque() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the deque is empty, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the number of elements in size()
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a reference to the first element in the deque
|
||||||
|
value_t& front() {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _first->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a const-qualified reference to the first element in the deque
|
||||||
|
const value_t& front() const {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _first->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a reference to the last element in the deque
|
||||||
|
value_t& back() {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _last->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a const-qualified reference to the last element in the deque
|
||||||
|
const value_t& back() const {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _last->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Move, moves a value to the front of the deque
|
||||||
|
/// \param elem the value to move
|
||||||
|
void push_front(value_t&& elem) {
|
||||||
|
this->_push_front(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Copy, copies a value to the front of the deque
|
||||||
|
/// \param elem the value to copy
|
||||||
|
void push_front(const value_t& elem) {
|
||||||
|
this->_push_front(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Front, constructs a new value at the front of the deque
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments used to construct the value
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void emplace_front(ArgsT&&...args) {
|
||||||
|
this->_push_front(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Move, moves a value to the back of the deque
|
||||||
|
/// \param elem the value to move
|
||||||
|
void push_back(value_t&& elem) {
|
||||||
|
this->_push_back(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Copy, copies a value to the back of the deque
|
||||||
|
/// \param elem the value to copy
|
||||||
|
void push_back(const value_t& elem) {
|
||||||
|
this->_push_back(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Back, constructs a new value at the back of the deque
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments used to construct the value
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void emplace_back(ArgsT&&...args) {
|
||||||
|
this->_push_back(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the contents of the deque
|
||||||
|
void clear() {
|
||||||
|
elem_t it = _first;
|
||||||
|
while (it) {
|
||||||
|
elem_t next = it->next;
|
||||||
|
fennec::destruct(it);
|
||||||
|
_alloc.deallocate(it);
|
||||||
|
it = next;
|
||||||
|
}
|
||||||
|
_first = nullptr;
|
||||||
|
_last = nullptr;
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase the First Element
|
||||||
|
void pop_front() {
|
||||||
|
if (_first == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elem_t next = _first->next;
|
||||||
|
fennec::destruct(_first);
|
||||||
|
_alloc.deallocate(_first);
|
||||||
|
_first = next;
|
||||||
|
_last = next ? _last : nullptr;
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase the Last Element
|
||||||
|
void pop_back() {
|
||||||
|
if (_last == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elem_t prev = _last->prev;
|
||||||
|
fennec::destruct(_last);
|
||||||
|
_alloc.deallocate(_last);
|
||||||
|
_last = prev;
|
||||||
|
_first = prev ? _first : nullptr;
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Decide whether you should be able to iterate over a deque
|
||||||
|
*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
alloc_t _alloc;
|
||||||
|
node *_first, *_last;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void _push_front(ArgsT&&...args) {
|
||||||
|
elem_t next = _first;
|
||||||
|
_first = _alloc.allocate(1);
|
||||||
|
fennec::construct(_first, nullptr, next, fennec::forward<ArgsT>(args)...);
|
||||||
|
if (next) {
|
||||||
|
next->prev = _first;
|
||||||
|
} else {
|
||||||
|
_last = _first;
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void _push_back(ArgsT&&...args) {
|
||||||
|
elem_t prev = _last;
|
||||||
|
_last = _alloc.allocate(1);
|
||||||
|
fennec::construct(_last, prev, nullptr, fennec::forward<ArgsT>(args)...);
|
||||||
|
if (prev) {
|
||||||
|
prev->next = _last;
|
||||||
|
} else {
|
||||||
|
_first = _last;
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_DEQUE_H
|
||||||
61
include/fennec/containers/detail/_tuple.h
Normal file
61
include/fennec/containers/detail/_tuple.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||||
|
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||||
|
#include <fennec/lang/const_sequences.h>
|
||||||
|
#include <fennec/lang/utility.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template <std::size_t I, typename T>
|
||||||
|
struct _tuple_leaf
|
||||||
|
{
|
||||||
|
template <typename ArgT>
|
||||||
|
constexpr _tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {}
|
||||||
|
|
||||||
|
constexpr ~_tuple_leaf() = default;
|
||||||
|
|
||||||
|
constexpr _tuple_leaf& operator=(const _tuple_leaf&) = default;
|
||||||
|
constexpr _tuple_leaf& operator=(_tuple_leaf&&) noexcept = default;
|
||||||
|
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename, typename...>
|
||||||
|
struct _tuple;
|
||||||
|
|
||||||
|
template <size_t...IndicesV, typename...TypesT>
|
||||||
|
struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
|
||||||
|
{
|
||||||
|
template <typename...ArgsT>
|
||||||
|
constexpr _tuple(ArgsT&&... args)
|
||||||
|
: _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _tuple& operator=(const _tuple&) = default;
|
||||||
|
constexpr _tuple& operator=(_tuple&&) noexcept = default;
|
||||||
|
|
||||||
|
constexpr ~_tuple() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file dynarray.h
|
/// \file dynarray.h
|
||||||
/// \brief fennec::array definition & implementation
|
/// \brief A header containing the definition for a dynamically allocated array
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -38,126 +38,445 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class TypeT, class Alloc>
|
///
|
||||||
class dynarray
|
///
|
||||||
{
|
/// \brief Wrapper for dynamically sized and allocated arrays
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | \f$O(N)\f$ |
|
||||||
|
/// | deletion | \f$O(N)\f$ |
|
||||||
|
///
|
||||||
|
/// This structure prefers shallow moves and deep copies.
|
||||||
|
///
|
||||||
|
/// \tparam TypeT value type
|
||||||
|
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||||
|
class dynarray {
|
||||||
public:
|
public:
|
||||||
using element_t = TypeT;
|
|
||||||
using alloc_t = Alloc;
|
// Definitions =========================================================================================================
|
||||||
|
|
||||||
|
using value_t = TypeT; ///< Alias for the value type
|
||||||
|
using alloc_t = Alloc; ///< Alias for the allocator type
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Default Constructor, initializes an empty allocation.
|
/// \brief Default Constructor, initializes an empty allocation.
|
||||||
dynarray() : _alloc(8), _size(0) {}
|
constexpr dynarray()
|
||||||
|
: _alloc(8)
|
||||||
///
|
, _size(0) {
|
||||||
/// \breif Alloc Constructor, initalize empty allocation with allocator instance.
|
|
||||||
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some data.
|
|
||||||
dynarray(const alloc_t& alloc) : _alloc(8, alloc), _size(0) {}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Create an allocation with a size of `n` elements. All elements are initialized with the default constructor.
|
|
||||||
dynarray(size_t n) : _alloc(n), _size(n)
|
|
||||||
{
|
|
||||||
element_t* addr = _alloc.data();
|
|
||||||
for(; n > 0; --n, ++addr) { fennec::construct(addr); }
|
|
||||||
}
|
|
||||||
|
|
||||||
dynarray(size_t n, const alloc_t& alloc) : _alloc(n, alloc), _size(n)
|
|
||||||
{
|
|
||||||
element_t* addr = _alloc.data();
|
|
||||||
for(; n > 0; --n, ++addr) { fennec::construct(addr); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Create an allocation of size `n`, with each element constructed using the copy constructor
|
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
|
||||||
/// \brief n the number of elements
|
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||||
dynarray(size_t n, const TypeT& val)
|
/// data.
|
||||||
{
|
explicit constexpr dynarray(const alloc_t& alloc)
|
||||||
element_t* addr = _alloc.data();
|
: _alloc(8, alloc)
|
||||||
for(; n > 0; --n, ++addr) { fennec::construct(addr, val); }
|
, _size(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Move Constructor, initialize empty allocation with allocator instance.
|
||||||
|
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||||
|
/// data.
|
||||||
|
explicit constexpr dynarray(alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(8, alloc)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Allocation, initializes a dynarray with `n` elements using the default constructor.
|
||||||
|
/// \param n The number of elements.
|
||||||
|
explicit constexpr dynarray(size_t n)
|
||||||
|
: _alloc(n)
|
||||||
|
, _size(n)
|
||||||
|
{
|
||||||
|
value_t* addr = _alloc.data();
|
||||||
|
for(; n > 0; --n, ++addr) {
|
||||||
|
fennec::construct(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator `alloc` and `n` elements
|
||||||
|
/// using the default constructor.
|
||||||
|
/// \param n The number of elements
|
||||||
|
/// \param alloc The allocator object to copy
|
||||||
|
constexpr dynarray(size_t n, const alloc_t& alloc)
|
||||||
|
: _alloc(n, alloc)
|
||||||
|
, _size(n) {
|
||||||
|
value_t* addr = _alloc.data();
|
||||||
|
for(; n > 0; --n, ++addr) {
|
||||||
|
fennec::construct(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Allocation Alloc Move Constructor, initializes a dynarray with allocator `alloc` and `n` elements
|
||||||
|
/// using the default constructor.
|
||||||
|
/// \param n The number of elements
|
||||||
|
/// \param alloc The allocator object to copy
|
||||||
|
constexpr dynarray(size_t n, alloc_t&& alloc)
|
||||||
|
: _alloc(n, alloc)
|
||||||
|
, _size(n) {
|
||||||
|
value_t* addr = _alloc.data();
|
||||||
|
for(; n > 0; --n, ++addr) {
|
||||||
|
fennec::construct(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Allocation Copy Constructor, Create an allocation of size `n` elements, with each element
|
||||||
|
/// constructed using the copy constructor
|
||||||
|
/// \param n the number of elements
|
||||||
|
/// \param val the value to copy
|
||||||
|
constexpr dynarray(size_t n, const TypeT& val)
|
||||||
|
: _alloc(n)
|
||||||
|
, _size(n) {
|
||||||
|
value_t* addr = _alloc.data();
|
||||||
|
for(; n > 0; --n, ++addr) {
|
||||||
|
fennec::construct(addr, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This constructor should not be invokable since moving is a single object operation and will cause undefined
|
||||||
|
// behaviour when moving to multiple elements
|
||||||
|
constexpr dynarray(size_t n, TypeT&&) = delete;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Constructor
|
||||||
|
/// \tparam ArgsT A sequence of argument types
|
||||||
|
/// \param n The number of objects to create
|
||||||
|
/// \param args The arguments to create each object with
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
dynarray(size_t n, ArgsT...args)
|
constexpr explicit dynarray(size_t n, ArgsT&&...args)
|
||||||
{
|
: _alloc(n)
|
||||||
element_t* addr = _alloc.data();
|
, _size(n) {
|
||||||
for(; n > 0; --n, ++addr) { fennec::construct(addr, args...); }
|
for(; n > 0; --n) {
|
||||||
|
fennec::construct(&_alloc[n], fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~dynarray()
|
///
|
||||||
{
|
/// \brief Copy Constructor, uses the copy constructor to copy each element
|
||||||
element_t* addr = _alloc.data();
|
/// \param arr the dynarray to copy
|
||||||
for(; n > 0; --n, ++addr) { fennec::destruct(addr); }
|
constexpr dynarray(const dynarray& arr)
|
||||||
|
: _alloc(arr._size)
|
||||||
|
, _size(arr._size) {
|
||||||
|
for (size_t i = 0; i < _size; ++i) {
|
||||||
|
fennec::construct(&_alloc[i], arr[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return _size; }
|
///
|
||||||
|
/// \brief Move Constructor, takes ownership of the allocation
|
||||||
|
/// \param arr the dynarray to move
|
||||||
|
constexpr dynarray(dynarray&& arr) noexcept
|
||||||
|
: _alloc(fennec::move(arr._alloc))
|
||||||
|
, _size(arr._size) {
|
||||||
|
arr._size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t capacity() const { return _alloc.capacity(); }
|
///
|
||||||
|
/// \brief Default Destructor, destructs all elements and frees the underlying allocation
|
||||||
|
constexpr ~dynarray() {
|
||||||
|
value_t* addr = _alloc.data();
|
||||||
|
if (addr == nullptr) return;
|
||||||
|
for(int n = _size; n > 0; --n, ++addr) {
|
||||||
|
fennec::destruct(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypeT& operator[](size_t i) { return _alloc.data()[i]; }
|
/// @}
|
||||||
const TypeT& operator[](size_t i) const { return _alloc.data()[i]; }
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param arr the array to copy
|
||||||
|
/// \returns A dynarray after having copied each element of `arr`
|
||||||
|
constexpr dynarray& operator=(const dynarray& arr) {
|
||||||
|
this->clear();
|
||||||
|
_alloc.creallocate(_size = arr._size);
|
||||||
|
for (size_t i = 0; i < _size; ++i) {
|
||||||
|
fennec::construct(&_alloc[i], fennec::copy(arr[i]));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param arr the array to move
|
||||||
|
/// \returns A dynarray after having taken ownership of the contents of `arr`
|
||||||
|
constexpr dynarray& operator=(dynarray&& arr) noexcept {
|
||||||
|
this->clear();
|
||||||
|
_alloc = fennec::move(arr._alloc);
|
||||||
|
_size = arr._size;
|
||||||
|
arr._size = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the dynarray in elements
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The current capacity, in elements, of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _alloc.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns True when there are no elements active, otherwise false
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Element Access ======================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i The index to access
|
||||||
|
/// \returns A reference to the element at index `i`
|
||||||
|
constexpr TypeT& operator[](size_t i) {
|
||||||
|
assertd(i < _size, "Array Out of Bounds");
|
||||||
|
return _alloc.data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator (const)
|
||||||
|
/// \param i The index to access
|
||||||
|
/// \returns A const qualified reference to the element at index `i`
|
||||||
|
constexpr const TypeT& operator[](size_t i) const {
|
||||||
|
assertd(i < _size, "Array Out of Bounds");
|
||||||
|
return _alloc.data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Reference to the first element in the dynarray
|
||||||
|
constexpr TypeT& front() {
|
||||||
|
return this->operator[](0);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A const-qualified reference to the first element in the dynarray
|
||||||
|
constexpr const TypeT& front() const {
|
||||||
|
return this->operator[](0);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A reference to the last element in the dynarray
|
||||||
|
constexpr TypeT& back() {
|
||||||
|
return this->operator[](size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A const-qualified reference to the last element in the dynarray
|
||||||
|
constexpr const TypeT& back() const {
|
||||||
|
return this->operator[](size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param i index to insert at
|
||||||
|
/// \param val the value to initialize with
|
||||||
|
constexpr void insert(size_t i, TypeT&& val) {
|
||||||
|
|
||||||
void insert(size_t i, const TypeT& val)
|
|
||||||
{
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
if(_size == capacity()) _grow();
|
if(_size == capacity()) {
|
||||||
|
_grow();
|
||||||
|
}
|
||||||
|
|
||||||
// Move the data if we are not inserting at the end of the array
|
// Move the data if we are not inserting at the end of the array
|
||||||
if((i = fennec::min(i, _size) < _size) {
|
if((i = min(i, _size)) < _size) {
|
||||||
fennec::memmove(
|
fennec::memmove(
|
||||||
_alloc.data() + i
|
(void*)(_alloc.data() + i + 1)
|
||||||
, _alloc.data() + i + 1
|
, (void*)(_alloc.data() + i)
|
||||||
, (_size - i) * sizeof(TypeT));
|
, (_size - i) * sizeof(TypeT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert the element
|
||||||
|
fennec::construct(_alloc.data() + i, fennec::forward<TypeT>(val));
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param i index to insert at
|
||||||
|
/// \param val the value to initialize with
|
||||||
|
constexpr void insert(size_t i, const TypeT& val) {
|
||||||
|
|
||||||
|
// Grow if the size has reached the capacity of the allocation
|
||||||
|
if(_size == capacity()) {
|
||||||
|
_grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the data if we are not inserting at the end of the array
|
||||||
|
if((i = min(i, _size)) < _size) {
|
||||||
|
fennec::memmove(
|
||||||
|
(void*)(_alloc.data() + i),
|
||||||
|
(void*)(_alloc.data() + i + 1),
|
||||||
|
(_size - i) * sizeof(TypeT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Insert the element
|
// Insert the element
|
||||||
fennec::construct(_alloc.data() + i, val);
|
fennec::construct(_alloc.data() + i, val);
|
||||||
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(size_t i, TypeT&& val)
|
///
|
||||||
{
|
/// \brief Emplace Insertion
|
||||||
// Grow if the size has reached the capacity of the allocation
|
/// \param i index to insert at
|
||||||
if(_size == capacity()) _grow();
|
/// \param args Arguments to construct with
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
// Move the data if we are not inserting at the end of the array
|
|
||||||
if((i = fennec::min(i, _size) < _size) {
|
|
||||||
fennec::memmove(
|
|
||||||
_alloc.data() + i
|
|
||||||
, _alloc.data() + i + 1
|
|
||||||
, (_size - i) * sizeof(TypeT));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert the element
|
|
||||||
fennec::construct(_alloc.data() + i, fennec::forward(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
void emplace(size_t i, ArgsT...args)
|
constexpr void emplace(size_t i, ArgsT&&...args) {
|
||||||
{
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
if(_size == capacity()) _grow();
|
if(_size == capacity()) {
|
||||||
|
_grow();
|
||||||
|
}
|
||||||
|
|
||||||
// Move the data if we are not inserting at the end of the array
|
// Move the data if we are not inserting at the end of the array
|
||||||
if((i = fennec::min(i, _size) < _size) {
|
if((i = min(i, _size)) < _size) {
|
||||||
fennec::memmove(
|
fennec::memmove(
|
||||||
_alloc.data() + i
|
(void*)(_alloc.data() + i)
|
||||||
, _alloc.data() + i + 1
|
, (void*)(_alloc.data() + i + 1)
|
||||||
, (_size - i) * sizeof(TypeT));
|
, (_size - i) * sizeof(TypeT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the element
|
// Insert the element
|
||||||
fennec::construct(_alloc.data() + i, fennec::forward<ArgsT>(args)...);
|
fennec::construct(_alloc.data() + i, fennec::forward<ArgsT>(args)...);
|
||||||
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const TypeT& val) { insert(_size, val); }
|
///
|
||||||
void push_back(TypeT&& val) { insert(_size, fennec::forward(val)); }
|
/// \brief Push Back Copy
|
||||||
|
/// \param val Value to initialize with
|
||||||
|
constexpr void push_back(const TypeT& val) {
|
||||||
|
dynarray::insert(_size, val);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename...ArgsT> void emplace_back(ArgsT...args) { emplace(_size, fennec::forward<ArgsT>(args)...); }
|
///
|
||||||
|
/// \brief Push Back Move
|
||||||
|
/// \param val Value to initialize with
|
||||||
|
constexpr void push_back(TypeT&& val) {
|
||||||
|
dynarray::insert(_size, fennec::forward<TypeT>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Back
|
||||||
|
/// \tparam ArgsT Argument Types
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace_back(ArgsT...args) {
|
||||||
|
dynarray::emplace(_size, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase last element
|
||||||
|
constexpr void pop_back() {
|
||||||
|
fennec::destruct(&_alloc[--_size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Resize the dynarray, invoking the default constructor for all new elements
|
||||||
|
/// \param n The new size in elements
|
||||||
|
constexpr void resize(size_t n) {
|
||||||
|
_alloc.creallocate(n);
|
||||||
|
|
||||||
|
while (_size < n) {
|
||||||
|
emplace_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
|
||||||
|
constexpr void clear() {
|
||||||
|
while (_size > 0) {
|
||||||
|
fennec::destruct(&_alloc[--_size]);
|
||||||
|
}
|
||||||
|
_alloc.deallocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief "Iterator" Begin Function
|
||||||
|
/// \returns A pointer to the first element in the dynarray
|
||||||
|
constexpr TypeT* begin() { return _alloc.data(); }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief "Iterator" End Function
|
||||||
|
/// \return A pointer to the address after the last element in the dynarray
|
||||||
|
constexpr TypeT* end() { return begin() + _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const "Iterator" Begin Function
|
||||||
|
/// \returns A const qualified pointer to the first element in the dynarray
|
||||||
|
constexpr const TypeT* begin() const { return _alloc; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const "Iterator" End Function
|
||||||
|
/// \return A const qualified pointer to the address after the last element in the dynarray
|
||||||
|
constexpr const TypeT* end() const { return begin() + _size; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _grow() const { _alloc.reallocate(_alloc.capacity() * 2); }
|
constexpr void _grow() {
|
||||||
|
_alloc.creallocate(_alloc.capacity() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
allocation<element_t, alloc_t> _alloc;
|
allocation<value_t, alloc_t> _alloc;
|
||||||
size_t _size;
|
size_t _size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
518
include/fennec/containers/graph.h
Normal file
518
include/fennec/containers/graph.h
Normal file
@@ -0,0 +1,518 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file graph.h
|
||||||
|
/// \brief A header containing the definition for a graph of vertices connected by edges
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_GRAPH_H
|
||||||
|
#define FENNEC_CONTAINERS_GRAPH_H
|
||||||
|
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/map.h>
|
||||||
|
#include <fennec/containers/object_pool.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the directed tree we were able to cheat a little, the structure has more rules to it which allows
|
||||||
|
* tighter constraints. A graph is basically no rules whatsoever. Some variants, such as weighted graphs, assign
|
||||||
|
* properties or rules to edges which can simply be an extension to this graph.
|
||||||
|
*
|
||||||
|
* The most effective way to do this is to have a dynarray of lists, however this results in double the
|
||||||
|
* memory being used. This can also result in two edge objects being created.
|
||||||
|
*
|
||||||
|
* There is no nice way to avoid the problem of mapping vertices to edges
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Graph Data Structure, describes sets of arbitrarily connected vertices
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(N)\f$ |
|
||||||
|
///
|
||||||
|
/// Graphs contain vertices and edges. Graphs are either directed
|
||||||
|
/// or undirected. This structure allows the creation of both directed and undirected edges. As
|
||||||
|
/// far as what that means; a directed graph means that edges have direction, where there are edges
|
||||||
|
/// that are "to" and "from," rather than "between" which is used in undirected graphs.
|
||||||
|
///
|
||||||
|
/// An undirected graph is connected if there is a path between every pair of vertices in the graph.
|
||||||
|
///
|
||||||
|
/// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would
|
||||||
|
/// produce a connected graph. We will call this "disjointed"
|
||||||
|
///
|
||||||
|
/// A directed graph is semi-connected if there is a directed path p for `u` → `v` *or* `v` → `u` for every
|
||||||
|
/// pair of vertices `u, v`. We will call this "unilateral"
|
||||||
|
///
|
||||||
|
/// A directed graph is strongly-connected if there is a directed path p for `u` → `v` *and* `v` → `u` for every pair
|
||||||
|
/// of vertices `u, v`. We will call this "connected"
|
||||||
|
///
|
||||||
|
/// \tparam VertexT The type associated with each vertex
|
||||||
|
/// \tparam EdgeT The type associated with each edge
|
||||||
|
template<typename VertexT, typename EdgeT = empty_t>
|
||||||
|
struct graph {
|
||||||
|
public:
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
|
||||||
|
using edge_t = EdgeT; ///< Alias for the edge type
|
||||||
|
using vertex_t = VertexT; ///< Alias for the vertex type
|
||||||
|
using vertex_pool_t = object_pool<vertex_t>; ///< Alias for a pool of vertices
|
||||||
|
using edge_map_t = dynarray<map<size_t, size_t>>; ///< Alias for edge mapping
|
||||||
|
using edge_pool_t = object_pool<edge_t>; ///< Alias for a pool of edges
|
||||||
|
|
||||||
|
static constexpr size_t npos = -1; ///< Constant for a non-existent vertex
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty graph
|
||||||
|
constexpr graph() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor
|
||||||
|
constexpr ~graph() = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
/// \name Assignment Operators
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param g The graph to copy
|
||||||
|
/// \returns A reference to this after assigning g
|
||||||
|
constexpr graph& operator=(const graph& g) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param g The graph to copy
|
||||||
|
/// \returns A reference to this after assigning g
|
||||||
|
constexpr graph& operator=(graph&& g) = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of vertices in the graph
|
||||||
|
constexpr size_t num_vertices() const {
|
||||||
|
return _vertex_pool.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of edges in the graph
|
||||||
|
constexpr size_t num_edges() const {
|
||||||
|
return _edge_pool.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the vertex pool
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _vertex_pool.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no vertices in the graph, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return num_vertices() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if there exists an edge `e` that starts from `a` and ends at `b`
|
||||||
|
/// \param a The first vertex
|
||||||
|
/// \param b The second vertex
|
||||||
|
/// \returns `true` if the edge exists, `false` otherwise
|
||||||
|
constexpr bool exists(size_t a, size_t b) const {
|
||||||
|
return _edge_map[a][b] != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if there exists an edge `e0` that starts from `a` and ends at `b` and `e1` that starts from `b`
|
||||||
|
/// and ends at `a`
|
||||||
|
/// \param a The first vertex
|
||||||
|
/// \param b The second vertex
|
||||||
|
/// \returns `true` if both edges exist, `false` otherwise
|
||||||
|
constexpr bool is_symmetric(size_t a, size_t b) const {
|
||||||
|
return exists(a, b) and exists(b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if there exists an edge `e` between `a` and `b`
|
||||||
|
/// \param a The first vertex
|
||||||
|
/// \param b The second vertex
|
||||||
|
/// \returns `true` if both edges exist, `false` otherwise
|
||||||
|
constexpr bool is_undirected(size_t a, size_t b) const {
|
||||||
|
const auto* e0 = _edge_map[a][b];
|
||||||
|
const auto* e1 = _edge_map[b][a];
|
||||||
|
if (not (e0 != nullptr && e1 != nullptr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return *e0 == *e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: connected, disjoint, unilateral, get_component
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief vertex Access Operator
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A reference to the value stored in the vertex
|
||||||
|
constexpr vertex_t& operator[](size_t vertex) {
|
||||||
|
return _vertex_pool[vertex];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief vertex Const Access Operator
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A reference to the value stored in the vertex
|
||||||
|
constexpr const vertex_t& operator[](size_t vertex) const {
|
||||||
|
return _vertex_pool[vertex];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief edge Access Operator
|
||||||
|
/// \param a The id of the first vertex
|
||||||
|
/// \param b The id of the second vertex
|
||||||
|
/// \returns A pointer to the value stored in the edge, `nullptr` if not found
|
||||||
|
constexpr edge_t* operator[](size_t a, size_t b) {
|
||||||
|
if (empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
edge_t* it = _edge_map[a][b];
|
||||||
|
if (it) {
|
||||||
|
return _edge_pool[*it];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief edge Const Access Operator
|
||||||
|
/// \param a The id of the first vertex
|
||||||
|
/// \param b The id of the second vertex
|
||||||
|
/// \returns A const-qualified pointer to the value stored in the edge, `nullptr` if not found
|
||||||
|
constexpr const edge_t* operator[](size_t a, size_t b) const {
|
||||||
|
if (empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const edge_t* it = _edge_map[a][b];
|
||||||
|
if (it) {
|
||||||
|
return _edge_pool[*it];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to `x...`
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` with edges from `vertex` to `x...`
|
||||||
|
list<size_t> outgoing(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (const auto& it : _edge_map[vertex]) {
|
||||||
|
res.push_back(it.first);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge from `x...`
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` with edges from `x...` to `vertex`
|
||||||
|
list<size_t> incoming(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (size_t n = 0; n < _edge_map.size(); ++n) {
|
||||||
|
if (_edge_map[n][vertex]) {
|
||||||
|
res.push_back(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...`
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex`
|
||||||
|
list<size_t> symmetric(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (const auto& it : _edge_map[vertex]) {
|
||||||
|
if (_edge_map[it.first][vertex]) {
|
||||||
|
res.push_back(it.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...` and share the same value
|
||||||
|
/// \details
|
||||||
|
/// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be
|
||||||
|
/// turned into a directed edge by changing the weight object associated with the edge, or by
|
||||||
|
/// removing one of the sub-edges.
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex`
|
||||||
|
list<size_t> undirected(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (const auto& it : _edge_map[vertex]) {
|
||||||
|
const auto* at = _edge_map[it.first][vertex];
|
||||||
|
if (at != nullptr && *at == it.second) {
|
||||||
|
res.push_back(it.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for the internal storage of mapped edges from this vertex.
|
||||||
|
/// Use this when you want to iterate over edges that start from this vertex.
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A pointer to a map containing edges mapped from this vertex
|
||||||
|
const auto* edges(size_t vertex) {
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &_edge_map[vertex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move a new vertex into the graph
|
||||||
|
/// \param vertex The vertex to move into the graph
|
||||||
|
/// \returns The id of the new vertex
|
||||||
|
constexpr size_t insert(vertex_t&& vertex) {
|
||||||
|
return this->_insert(fennec::forward<vertex_t>(vertex));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy a new vertex into the graph
|
||||||
|
/// \param vertex The vertex to copy into the graph
|
||||||
|
/// \returns The id of the new vertex
|
||||||
|
constexpr size_t insert(const vertex_t& vertex) {
|
||||||
|
return this->_insert(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Construct a new vertex in the graph
|
||||||
|
/// \tparam ArgsT The types of the arguments
|
||||||
|
/// \param args The arguments to construct the vertex with
|
||||||
|
/// \returns The id of the new vertex
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(ArgsT&&...args) {
|
||||||
|
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a vertex from the graph
|
||||||
|
/// \param vertex The id of the vertex to erase
|
||||||
|
constexpr void erase(size_t vertex) {
|
||||||
|
cut(vertex);
|
||||||
|
_vertex_pool.erase(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Form an edge from vertex `a` to vertex `b`
|
||||||
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
/// \param args The arguments to construct the edge with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void make_edge(size_t a, size_t b, ArgsT&&...args) {
|
||||||
|
if (a == b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_edge_map.size() < _vertex_pool.capacity()) {
|
||||||
|
_edge_map.resize(_vertex_pool.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = _edge_map[a][b];
|
||||||
|
size_t conn;
|
||||||
|
if (it != nullptr) {
|
||||||
|
conn = *it;
|
||||||
|
_edge_pool[conn] = vertex_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
conn = _edge_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
_edge_map[a].emplace(b, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Form an undirected edge between vertex `a` and vertex `b`
|
||||||
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
/// \param args The arguments to construct the edge with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void make_edge2(size_t a, size_t b, ArgsT&&...args) {
|
||||||
|
if (a == b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_edge_map.size() < _vertex_pool.capacity()) {
|
||||||
|
_edge_map.resize(_vertex_pool.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = _edge_map[a][b];
|
||||||
|
size_t conn;
|
||||||
|
if (it != nullptr) {
|
||||||
|
conn = *it;
|
||||||
|
_edge_pool[conn] = vertex_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
conn = _edge_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
_edge_map[a].emplace(b, conn);
|
||||||
|
_edge_map[b].emplace(a, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Disconnect an edge from vertex `a` to vertex `b`
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
constexpr void cut_edge(size_t a, size_t b) {
|
||||||
|
|
||||||
|
// Find the edge object
|
||||||
|
const auto* it = _edge_map[a][b];
|
||||||
|
if (not it) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t c = *it;
|
||||||
|
|
||||||
|
// Check if undirected
|
||||||
|
const auto* at = _edge_map[b][a];
|
||||||
|
if (not at || *at != c) {
|
||||||
|
_edge_pool.erase(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the edge mapping
|
||||||
|
_edge_map[a].erase(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Disconnect both directed edges between vertices `a` and `b`
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
constexpr void cut_edge2(size_t a, size_t b) {
|
||||||
|
const auto* ita = _edge_map[a][b];
|
||||||
|
const auto* itb = _edge_map[a][b];
|
||||||
|
if (not (ita || itb)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ita) _edge_pool.erase(*ita);
|
||||||
|
if (itb) _edge_pool.erase(*itb);
|
||||||
|
_edge_map[a].erase(b);
|
||||||
|
_edge_map[b].erase(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Break *all* edges to and from `n`
|
||||||
|
/// \param n The vertex id
|
||||||
|
void cut(size_t n) {
|
||||||
|
for (const auto it : outgoing(n)) {
|
||||||
|
cut_edge(n, it);
|
||||||
|
}
|
||||||
|
for (const auto it : incoming(n)) {
|
||||||
|
cut_edge(it, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clear the graph, destructing all vertices and edges.
|
||||||
|
void clear() {
|
||||||
|
_vertex_pool.clear();
|
||||||
|
_edge_pool.clear();
|
||||||
|
_edge_map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// edges =========================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
vertex_pool_t _vertex_pool;
|
||||||
|
edge_pool_t _edge_pool;
|
||||||
|
edge_map_t _edge_map;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
size_t _insert(ArgsT&&...args) {
|
||||||
|
return _vertex_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_GRAPH_H
|
||||||
655
include/fennec/containers/list.h
Normal file
655
include/fennec/containers/list.h
Normal file
@@ -0,0 +1,655 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file list.h
|
||||||
|
/// \brief A header containing the definition for a linked list of values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_LIST_H
|
||||||
|
#define FENNEC_CONTAINERS_LIST_H
|
||||||
|
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
#include <fennec/math/common.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \brief Data Structure defining lists of elements
|
||||||
|
/// \details
|
||||||
|
/// This data-structure behaves like a linked list, but does not use pointers. Instead, it is in-array. This creates the
|
||||||
|
/// following properties:
|
||||||
|
///
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | \f$O(N)\f$ |
|
||||||
|
/// | deletion | \f$O(N)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT value type
|
||||||
|
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||||
|
struct list {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// \brief Alias for the allocator type, rebound to list nodes
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<node>;
|
||||||
|
|
||||||
|
using value_t = TypeT; ///< Alias for the value type
|
||||||
|
|
||||||
|
static constexpr size_t npos = -1; ///< Constant representing a non-existant position
|
||||||
|
|
||||||
|
class iterator; ///< Iterator type for forward iteration over the list
|
||||||
|
class const_iterator; ///< Iterator type for forward iteration over a constant list
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an empty list.
|
||||||
|
constexpr list()
|
||||||
|
: _table(), _freed(), _root(npos), _last(npos), _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor, copies all elements in `l` with optimized layout
|
||||||
|
/// \param l The list to copy
|
||||||
|
constexpr list(const list& l)
|
||||||
|
: list() {
|
||||||
|
for (const value_t& it : l) {
|
||||||
|
this->push_back(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor, takes ownership of the list
|
||||||
|
/// \param l The list to move
|
||||||
|
constexpr list(list&& l) noexcept
|
||||||
|
: _table(fennec::move(l._table))
|
||||||
|
, _freed(fennec::move(l._freed))
|
||||||
|
, _root(l._root)
|
||||||
|
, _last(l._last)
|
||||||
|
, _size(l._size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, destructs all elements then releases the allocation.
|
||||||
|
constexpr ~list() {
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
_table[i].value = nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Assignment
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param l the list to copy
|
||||||
|
/// \returns `this` after having copied all elements of `l`
|
||||||
|
constexpr list& operator=(const list& l) {
|
||||||
|
this->clear();
|
||||||
|
for (const value_t& it : l) {
|
||||||
|
this->push_back(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param l the list to copy
|
||||||
|
/// \returns `this` after having taken ownership over the contents of `l`
|
||||||
|
constexpr list& operator=(list&& l) noexcept {
|
||||||
|
this->clear();
|
||||||
|
_table = fennec::move(l._table);
|
||||||
|
_freed = fennec::move(l._freed);
|
||||||
|
_root = l._root; _last = l._last;
|
||||||
|
_size = l._size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the list in elements.
|
||||||
|
constexpr size_t size() const { return _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the list in elements.
|
||||||
|
constexpr size_t capacity() const { return _table.capacity(); }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the list is empty, `false` otherwise.
|
||||||
|
constexpr bool empty() const { return _root == npos; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i Index to access
|
||||||
|
/// \returns A reference to the element at `i`
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
constexpr value_t& operator[](int i) {
|
||||||
|
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
||||||
|
size_t n = _walk(i);
|
||||||
|
assertd(n != npos, "Index out of Bounds");
|
||||||
|
return *_table[n].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Array Access Operator
|
||||||
|
/// \param i Index to access
|
||||||
|
/// \returns A const-qualified reference to the element at `i`
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
constexpr const value_t& operator[](int i) const {
|
||||||
|
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
||||||
|
size_t n = _walk(i);
|
||||||
|
assertd(n != npos, "Index out of Bounds");
|
||||||
|
return *_table[n].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access Front Element
|
||||||
|
/// \returns A reference to the first element in the list
|
||||||
|
constexpr value_t& front() {
|
||||||
|
return *_table[_root].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access Front Element
|
||||||
|
/// \returns A const-qualified reference to the first element in the list
|
||||||
|
constexpr const value_t& front() const {
|
||||||
|
return *_table[_root].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access Back Element
|
||||||
|
/// \returns A reference to the last element in the list
|
||||||
|
constexpr value_t& back() {
|
||||||
|
return *_table[_last].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access Back Element
|
||||||
|
/// \returns A const-qualified reference to the last element in the list
|
||||||
|
constexpr const value_t& back() const {
|
||||||
|
return *_table[_last].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param it Location to insert at
|
||||||
|
/// \param x value to copy
|
||||||
|
///
|
||||||
|
/// \details \f$O(1)\f$
|
||||||
|
constexpr size_t insert(const iterator& it, const value_t& x) {
|
||||||
|
return this->_insert(it._n, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param it Location to insert at
|
||||||
|
/// \param x value to move
|
||||||
|
///
|
||||||
|
/// \details \f$O(1)\f$
|
||||||
|
constexpr size_t insert(const iterator& it, value_t&& x) {
|
||||||
|
return this->_insert(it._n, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param i Index to insert at
|
||||||
|
/// \param x value to copy
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
constexpr size_t insert(size_t i, const value_t& x) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
|
||||||
|
size_t n = _walk(min(i, size_t(size() - 1)));
|
||||||
|
return this->_insert(n, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param i Index to insert at
|
||||||
|
/// \param x value to move
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
constexpr size_t insert(size_t i, value_t&& x) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
|
||||||
|
size_t n = _walk(min(i, size_t(size() - 1)));
|
||||||
|
return this->_insert(n, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param i Index to insert at
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(size_t i, ArgsT&&...args) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
|
||||||
|
size_t n = _walk(min(i, size_t(size() - 1)));
|
||||||
|
return this->_insert(n, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Copy
|
||||||
|
/// \param x Value to copy
|
||||||
|
constexpr size_t push_front(const value_t& x) {
|
||||||
|
return this->_insert(_root, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Move
|
||||||
|
/// \param x Value to move
|
||||||
|
constexpr size_t push_front(value_t&& x) {
|
||||||
|
return this->_insert(_root, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Front
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace_front(ArgsT&&...args) {
|
||||||
|
return this->_insert(_root, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Copy
|
||||||
|
/// \param x Value to copy
|
||||||
|
constexpr size_t push_back(const value_t& x) {
|
||||||
|
return this->_insert(npos, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Move
|
||||||
|
/// \param x Value to move
|
||||||
|
constexpr size_t push_back(value_t&& x) {
|
||||||
|
return this->_insert(npos, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Back
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace_back(ArgsT&&...args) {
|
||||||
|
return this->_insert(npos, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase Element
|
||||||
|
/// \param i Index to erase
|
||||||
|
constexpr void erase(size_t i) {
|
||||||
|
assert(i < size(), "Index out of Bounds!");
|
||||||
|
size_t n = _walk(i);
|
||||||
|
_erase(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase Element
|
||||||
|
/// \param it Location to Erase
|
||||||
|
constexpr void erase(const iterator& it) {
|
||||||
|
_erase(it._n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pop Front, erases first element
|
||||||
|
constexpr void pop_front() {
|
||||||
|
_erase(_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pop Back, erases first element
|
||||||
|
constexpr void pop_back() {
|
||||||
|
_erase(_last);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the list, destructing all elements in order
|
||||||
|
constexpr void clear() {
|
||||||
|
size_t i = _root;
|
||||||
|
while (i != npos) {
|
||||||
|
fennec::destruct(_table[i]);
|
||||||
|
i = this->_next(i);
|
||||||
|
}
|
||||||
|
_table.deallocate(_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// ITERATOR ============================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns An iterator for the first element in the list
|
||||||
|
constexpr iterator begin() {
|
||||||
|
return iterator(this, _root);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns An iterator for the end of the list
|
||||||
|
constexpr iterator end() {
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `begin()`
|
||||||
|
/// \returns A const iterator for the first element in the list
|
||||||
|
constexpr const_iterator begin() const {
|
||||||
|
return const_iterator(this, _root);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `end()`
|
||||||
|
/// \returns A const iterator for the end of the list
|
||||||
|
constexpr const_iterator end() const {
|
||||||
|
return const_iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Class
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
~iterator() {
|
||||||
|
_list = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr friend iterator& operator++(iterator& rhs) {
|
||||||
|
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
rhs._n = npos;
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend iterator operator++(iterator& lhs, int) {
|
||||||
|
iterator prev = lhs;
|
||||||
|
++lhs;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr value_t& operator*() {
|
||||||
|
return *(_list->_table[_n].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr value_t* operator->() {
|
||||||
|
return &*(_list->_table[_n].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) {
|
||||||
|
return _list == it._list and _n == it._n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const iterator& it) {
|
||||||
|
return _list != it._list or _n != it._n;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
list* _list;
|
||||||
|
size_t _n;
|
||||||
|
friend list;
|
||||||
|
|
||||||
|
iterator(list* ls, size_t n)
|
||||||
|
: _list(ls)
|
||||||
|
, _n(n) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Class for Const Access
|
||||||
|
class const_iterator {
|
||||||
|
public:
|
||||||
|
~const_iterator() {
|
||||||
|
_list = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr friend const_iterator& operator++(const_iterator& rhs) {
|
||||||
|
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
rhs._n = npos;
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend const_iterator operator++(const_iterator& lhs, int) {
|
||||||
|
const_iterator prev = lhs;
|
||||||
|
++lhs;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const value_t& operator*() {
|
||||||
|
return *(_list->_table[_n].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const value_t* operator->() {
|
||||||
|
return &*(_list->_table[_n].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const const_iterator& it) {
|
||||||
|
return _list == it._list and _n == it._n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const const_iterator& it) {
|
||||||
|
return _list != it._list or _n != it._n;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const list* _list;
|
||||||
|
size_t _n;
|
||||||
|
friend list;
|
||||||
|
|
||||||
|
const_iterator(const list* ls, size_t n)
|
||||||
|
: _list(ls)
|
||||||
|
, _n(n) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
allocation<node, alloc_t> _table;
|
||||||
|
dynarray<size_t> _freed;
|
||||||
|
size_t _root, _last, _size;
|
||||||
|
|
||||||
|
friend class iterator;
|
||||||
|
|
||||||
|
constexpr void _expand() {
|
||||||
|
_table.creallocate(fennec::max(_table.capacity(), size_t(1)) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node {
|
||||||
|
optional<value_t> value;
|
||||||
|
size_t prev, next;
|
||||||
|
|
||||||
|
constexpr node()
|
||||||
|
: value()
|
||||||
|
, prev(npos)
|
||||||
|
, next(npos) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node(size_t p, size_t n)
|
||||||
|
: value()
|
||||||
|
, prev(p)
|
||||||
|
, next(n) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node(size_t p, size_t n, value_t&& val)
|
||||||
|
: value(fennec::forward<value_t>(val))
|
||||||
|
, prev(p)
|
||||||
|
, next(n) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~node() = default;
|
||||||
|
|
||||||
|
constexpr void clear() {
|
||||||
|
value = nullopt;
|
||||||
|
prev = npos;
|
||||||
|
next = npos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr size_t _next(size_t n) const {
|
||||||
|
return _table[n].next;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t _prev(size_t n) const {
|
||||||
|
return _table[n].prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t _walk(size_t i) const {
|
||||||
|
size_t n = _root;
|
||||||
|
if (n == npos) return n;
|
||||||
|
while (i > 0 && n != npos) {
|
||||||
|
n = _next(n); --i;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t _next_free() {
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
size_t n = _freed.back();
|
||||||
|
_freed.pop_back();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t _insert(size_t n, ArgsT&&...args) {
|
||||||
|
if (size() == capacity()) {
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = _next_free();
|
||||||
|
++_size;
|
||||||
|
fennec::construct(&_table[i].value, fennec::forward<ArgsT>(args)...);
|
||||||
|
|
||||||
|
if (_root == npos) {
|
||||||
|
_table[i].prev = npos;
|
||||||
|
_table[i].next = npos;
|
||||||
|
_root = _last = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == npos) {
|
||||||
|
_table[_last].next = i;
|
||||||
|
_table[i].prev = _last;
|
||||||
|
_table[i].next = npos;
|
||||||
|
_last = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
_table[i].prev = _prev(n);
|
||||||
|
_table[i].next = n;
|
||||||
|
_table[n].prev = i;
|
||||||
|
_root = n == _root ? i : _root;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void _erase(size_t n) {
|
||||||
|
if (n == npos) return;
|
||||||
|
|
||||||
|
fennec::destruct(&_table[n].value);
|
||||||
|
_freed.push_back(n);
|
||||||
|
--_size;
|
||||||
|
|
||||||
|
size_t prev = _prev(n);
|
||||||
|
size_t next = _next(n);
|
||||||
|
|
||||||
|
if (prev != npos) {
|
||||||
|
_table[prev].next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next != npos) {
|
||||||
|
_table[next].prev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
_root = (n == _root) ? next : _root;
|
||||||
|
_last = (n == _last) ? prev : _last;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_LIST_H
|
||||||
312
include/fennec/containers/map.h
Normal file
312
include/fennec/containers/map.h
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file map.h
|
||||||
|
/// \brief A header containing the definition for a mapping of keys to values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_MAP_H
|
||||||
|
#define FENNEC_CONTAINERS_MAP_H
|
||||||
|
|
||||||
|
#include <fennec/containers/pair.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Ramblings
|
||||||
|
*
|
||||||
|
* Definitions:
|
||||||
|
* user = Programmer using this data structure
|
||||||
|
*
|
||||||
|
* The STL maps are very contrived. Some of its functionality encourages younger programmers to use
|
||||||
|
* the exception model. Ideally, I would like this structure to never throw an error with typical use.
|
||||||
|
*
|
||||||
|
* The array access operator is, in my opinion, poorly implemented. I do not think that this operator should handle
|
||||||
|
* insertions and should handle access only. This is the only data structure in STL that has this behavior, no other
|
||||||
|
* data structure modifies contents by inherently calling operator[].
|
||||||
|
*
|
||||||
|
* Currently, I am considering implementing this as the following:
|
||||||
|
* Access will be handled only via operator[]. Return value will be a pointer which forces user validation.
|
||||||
|
* Insertions will be handled only via an insert/emplace function.
|
||||||
|
* Deletions will be handled only via an erase function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Structure defining a mapping of `key` \f$KeyT\f$ to `value` \f$ValueT\f$
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ✅ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam KeyT The Key Type
|
||||||
|
/// \tparam ValueT The Value Type
|
||||||
|
/// \tparam Hash The Hash to Use
|
||||||
|
/// \tparam Alloc The Allocator to Use
|
||||||
|
template<typename KeyT, typename ValueT, typename Hash = hash<KeyT>, typename Alloc = allocator<pair<KeyT, ValueT>>>
|
||||||
|
struct map {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
struct key_hash; ///< Hash for node keys
|
||||||
|
struct key_equals; ///< Comparison for node keys
|
||||||
|
using key_t = KeyT; ///< The key type
|
||||||
|
using value_t = ValueT; ///< The value type
|
||||||
|
using elem_t = pair<KeyT, ValueT>; ///< then node type
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>; ///< Rebinds the allocator type to nodes
|
||||||
|
using hash_t = Hash; ///< The hash type
|
||||||
|
using set_t = set<elem_t, key_hash, key_equals, alloc_t>; ///< The underlying set
|
||||||
|
using iterator = set_t::iterator; ///< Iterator type
|
||||||
|
|
||||||
|
// We only want to hash the key
|
||||||
|
struct key_hash : hash_t {
|
||||||
|
constexpr size_t operator()(const elem_t& p) const {
|
||||||
|
return hash_t::operator()(p.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// We only want to compare the keys
|
||||||
|
struct key_equals : equality<KeyT> {
|
||||||
|
constexpr bool operator()(const elem_t& a, const elem_t& b) const {
|
||||||
|
return equality<KeyT>::operator()(a.first, b.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty map
|
||||||
|
constexpr map() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, Destructs all elements and releases the allocation
|
||||||
|
constexpr ~map() = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the set
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no elements in the set, `false` otherwise
|
||||||
|
constexpr size_t empty() const {
|
||||||
|
return _set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _set.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key Access Operator
|
||||||
|
/// \param key Key value to access
|
||||||
|
/// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
|
constexpr value_t* operator[](const KeyT& key) {
|
||||||
|
auto it = _set.at(this->_find(key));
|
||||||
|
return it ? &it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key Const Access Operator
|
||||||
|
/// \param key Key value to access
|
||||||
|
/// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
|
constexpr const value_t* operator[](const KeyT& key) const {
|
||||||
|
auto it = _set.at(this->_find(key));
|
||||||
|
return it ? &it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Argument Key Access Operator
|
||||||
|
/// \tparam ArgT Argument Type
|
||||||
|
/// \param arg Argument to construct the key with
|
||||||
|
/// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr value_t* operator[](ArgsT&&...args) {
|
||||||
|
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
|
||||||
|
return it ? &it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Argument Key Const Access Operator
|
||||||
|
/// \tparam ArgsT Argument Type
|
||||||
|
/// \param args Argument to construct the key with
|
||||||
|
/// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr const value_t* operator[](ArgsT&&...args) const {
|
||||||
|
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
|
||||||
|
return it ? &it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key-Value Insertion
|
||||||
|
/// \param pair a pair containing the key and its value
|
||||||
|
constexpr void insert(elem_t&& pair) {
|
||||||
|
this->_insert(fennec::forward<elem_t>(pair));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key-Value Insertion
|
||||||
|
/// \param args Arguments for constructing the key-value pair
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace(const KeyT& key, ArgsT&&...args) {
|
||||||
|
this->_insert(key, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key-Value Insertion
|
||||||
|
/// \param args Arguments for constructing the key-value pair
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace(ArgsT&&...args) {
|
||||||
|
this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a key
|
||||||
|
/// \param key key to erase
|
||||||
|
constexpr void erase(KeyT&& key) {
|
||||||
|
_set.erase(this->_find(fennec::forward<KeyT>(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a key
|
||||||
|
/// \param key key to erase
|
||||||
|
constexpr void erase(const KeyT& key) {
|
||||||
|
_set.erase(this->_find(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Argument Erase
|
||||||
|
/// \tparam ArgsT Argument Types
|
||||||
|
/// \param args Arguments to construct a key to erase
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void erase(ArgsT&&...args) {
|
||||||
|
_set.erase(this->_find(fennec::forward<ArgsT>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the map destructing all elements
|
||||||
|
void clear() {
|
||||||
|
_set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns an iterator at the start of the map
|
||||||
|
constexpr iterator begin() {
|
||||||
|
return _set.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns an iterator at the end of the map
|
||||||
|
constexpr iterator end() {
|
||||||
|
return _set.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
set_t _set;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
set_t::iterator _find(ArgsT&&...args) const {
|
||||||
|
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||||
|
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||||
|
pair<KeyT, ValueT> val;
|
||||||
|
|
||||||
|
~U() {
|
||||||
|
fennec::destruct(&root);
|
||||||
|
}
|
||||||
|
} trick = { .root = { KeyT(fennec::forward<ArgsT>(args)...), 0 } };
|
||||||
|
return _set.find(trick.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void _insert(ArgsT&&...args) {
|
||||||
|
elem_t elem(fennec::forward<ArgsT>(args)...);
|
||||||
|
auto it = this->_find(elem.first);
|
||||||
|
if (it != _set.end()) {
|
||||||
|
_set.at(it)->second = fennec::move(elem.second);
|
||||||
|
} else {
|
||||||
|
_set.insert(fennec::move(elem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_MAP_H
|
||||||
586
include/fennec/containers/multiset.h
Normal file
586
include/fennec/containers/multiset.h
Normal file
@@ -0,0 +1,586 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file multiset.h
|
||||||
|
/// \brief A header containing the definition for a set of repeating values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_MULTISET_H
|
||||||
|
#define FENNEC_CONTAINERS_MULTISET_H
|
||||||
|
|
||||||
|
// https://programming.guide/robin-hood-hashing.html
|
||||||
|
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/multiset.h>
|
||||||
|
#include <fennec/lang/compare.h>
|
||||||
|
#include <fennec/math/ext/primes.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
#include <fennec/lang/hashing.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \brief A Data Structure that defines a set of elements that may repeat
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT The type to contain
|
||||||
|
template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
|
||||||
|
struct multiset {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
||||||
|
using hash_t = Hash;
|
||||||
|
using equal_t = Equals;
|
||||||
|
using elem_t = TypeT;
|
||||||
|
|
||||||
|
class iterator;
|
||||||
|
class value_iterator;
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
static constexpr double default_load = 0.8;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node {
|
||||||
|
optional<elem_t> value;
|
||||||
|
int psl;
|
||||||
|
|
||||||
|
constexpr node() = default;
|
||||||
|
constexpr ~node() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty multiset
|
||||||
|
constexpr multiset()
|
||||||
|
: _alloc()
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Copy Constructor, initializes empty multiset with a hash
|
||||||
|
constexpr multiset(const hash_t& hash)
|
||||||
|
: _alloc()
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Move Constructor, initializes empty multiset with a hash
|
||||||
|
constexpr multiset(hash_t&& hash) noexcept
|
||||||
|
: _alloc()
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Copy Constructor, initializes empty multiset with an allocator
|
||||||
|
constexpr multiset(const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Move Constructor, initializes empty multiset with an allocator
|
||||||
|
constexpr multiset(alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Alloc Copy Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(const hash_t& hash, const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Copy Alloc Move Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(const hash_t& hash, alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Move Alloc Move Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(hash_t&& hash, alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Move Alloc Copy Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(hash_t&& hash, const alloc_t& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Copy Constructor
|
||||||
|
/// \param multiset Set to copy
|
||||||
|
constexpr multiset(const multiset& multiset)
|
||||||
|
: _alloc( multiset._alloc)
|
||||||
|
, _hash( multiset._hash)
|
||||||
|
, _size( multiset._size)
|
||||||
|
, _sumpsl( multiset._sumpsl)
|
||||||
|
, _load( multiset._load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Move Constructor
|
||||||
|
/// \param multiset Set to move
|
||||||
|
constexpr multiset(multiset&& multiset) noexcept
|
||||||
|
: _alloc(fennec::move( multiset._alloc))
|
||||||
|
, _hash(fennec::move( multiset._hash))
|
||||||
|
, _size(fennec::move( multiset._size))
|
||||||
|
, _sumpsl( multiset._sumpsl)
|
||||||
|
, _load( multiset._load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, destructs all elements and releases the allocation
|
||||||
|
constexpr ~multiset() {
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Size of the multiset in elements
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the set is empty, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Capacity of the multiset in elements
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _alloc.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Find an Element
|
||||||
|
/// \param val Value to find
|
||||||
|
/// \returns An iterator at the location of the first instance of `value`
|
||||||
|
constexpr iterator find(const elem_t& val, size_t c = 0) const {
|
||||||
|
if (capacity() == 0) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
size_t s = _hash(val) % capacity(); // Initial search index
|
||||||
|
int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl
|
||||||
|
size_t i = (s + psl) % capacity(); // Median search
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
// Check the first element;
|
||||||
|
if (_alloc[i].psl >= psl && _alloc[i].value) {
|
||||||
|
if (*_alloc[i].value == val) {
|
||||||
|
return iterator(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop while there is a value and its psl is greater than our probe
|
||||||
|
while (c > 0) {
|
||||||
|
++n;
|
||||||
|
size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow
|
||||||
|
size_t i1 = (i + n) % capacity();
|
||||||
|
int p0 = psl - n, p1 = psl + n;
|
||||||
|
bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
|
||||||
|
|
||||||
|
if (c0 && _alloc[i0].value) {
|
||||||
|
if (*_alloc[i0].value == val) {
|
||||||
|
if (c-- == 0) {
|
||||||
|
return iterator(this, i0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 && _alloc[i1].value) {
|
||||||
|
if (*_alloc[i1].value == val) {
|
||||||
|
if (c-- == 0) {
|
||||||
|
return iterator(this, i1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not(c0 or c1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if a multiset contains a value
|
||||||
|
/// \param val Value to check
|
||||||
|
/// \returns `true` if `val` can be found, `false` otherwise
|
||||||
|
constexpr bool contains(const elem_t& val) const {
|
||||||
|
return this->find(val) != end();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A pointer to the element, `nullptr` if not found.
|
||||||
|
/// The value should not be changed in a manner that will change the hash of the element.
|
||||||
|
constexpr elem_t* at(const iterator& it) {
|
||||||
|
if (it == end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Const Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A const-qualified pointer to the element, `nullptr` if not found.
|
||||||
|
constexpr const elem_t* at(const iterator& it) const {
|
||||||
|
if (not _alloc[it._i].value) return nullptr;
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr void insert(elem_t&& val) {
|
||||||
|
this->_insert(fennec::forward<elem_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr void insert(const elem_t& val) {
|
||||||
|
this->_insert(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace(ArgsT&&...args) {
|
||||||
|
this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param it Location to erase
|
||||||
|
constexpr void erase(iterator it) {
|
||||||
|
size_t i = it._i;
|
||||||
|
if (i >= capacity()) {
|
||||||
|
return;
|
||||||
|
} // These are separated due to compilers being inconsistent
|
||||||
|
if (not _alloc[i].value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
_sumpsl -= _alloc[i].psl;
|
||||||
|
--_size;
|
||||||
|
size_t p = i;
|
||||||
|
while (_alloc[i = (i + 1) % capacity()].value) {
|
||||||
|
if (_alloc[i].psl == 0) break;
|
||||||
|
|
||||||
|
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
|
||||||
|
--_alloc[p].psl, --_sumpsl;
|
||||||
|
p = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param val Value to erase
|
||||||
|
constexpr void erase(const elem_t& val) {
|
||||||
|
this->erase(this->find(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// ITERATOR ============================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns An iterator for all elements of the set in no particular order
|
||||||
|
constexpr iterator begin() const {
|
||||||
|
iterator it(this, 0);
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns An iterator representing the end of the set
|
||||||
|
constexpr iterator end() const {
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Class for Iterating the Set
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
constexpr ~iterator() {
|
||||||
|
_set = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr iterator& operator++() {
|
||||||
|
while (++_i < _set->capacity()) {
|
||||||
|
if (_set->_alloc[_i].value) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_i = npos;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator operator++(int) {
|
||||||
|
iterator prev = *this;
|
||||||
|
this->operator++();
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t& operator*() const {
|
||||||
|
return *_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t* operator->() const {
|
||||||
|
if (not _set->_alloc[_i].value) return nullptr;
|
||||||
|
return &*_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) const {
|
||||||
|
return _set == it._set and _i == it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const iterator& it) const {
|
||||||
|
return _set != it._set or _i != it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const multiset* _set;
|
||||||
|
size_t _i;
|
||||||
|
friend multiset;
|
||||||
|
|
||||||
|
constexpr iterator(const multiset* multiset, size_t i)
|
||||||
|
: _set(multiset)
|
||||||
|
, _i(i) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class value_iterator {
|
||||||
|
public:
|
||||||
|
constexpr ~value_iterator() {
|
||||||
|
_set = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr value_iterator& operator++() {
|
||||||
|
while (_psl <= _set->_alloc[_i].psl) {
|
||||||
|
if (not _set->_alloc[_i].value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_i = npos;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr value_iterator operator++(int) {
|
||||||
|
value_iterator prev = *this;
|
||||||
|
this->operator++();
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t& operator*() const {
|
||||||
|
return *_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t* operator->() const {
|
||||||
|
if (not _set->_alloc[_i].value) return nullptr;
|
||||||
|
return &*_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) const {
|
||||||
|
return _set == it._set and _i == it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const iterator& it) const {
|
||||||
|
return _set != it._set or _i != it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const multiset* _set;
|
||||||
|
size_t _i;
|
||||||
|
int _psl;
|
||||||
|
elem_t _value;
|
||||||
|
friend multiset;
|
||||||
|
|
||||||
|
constexpr value_iterator(const multiset* multiset, size_t i, int psl, const elem_t& value)
|
||||||
|
: _set(multiset)
|
||||||
|
, _i(i)
|
||||||
|
, _value(value) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// PRIVATE =============================================================================================================
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr void _expand() {
|
||||||
|
multiset cpy; // Create a new multiset
|
||||||
|
cpy._alloc.callocate(
|
||||||
|
fennec::next_prime2(_alloc.capacity())
|
||||||
|
);
|
||||||
|
|
||||||
|
// rehash
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
if (_alloc[i].value) {
|
||||||
|
cpy.insert(fennec::move(*_alloc[i].value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
|
fennec::swap(_alloc, cpy._alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void _insert(ArgsT&&...args) {
|
||||||
|
if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
elem_t value(fennec::forward<ArgsT>(args)...);
|
||||||
|
size_t i = _hash(value) % capacity(); // Initial search index
|
||||||
|
int psl = 0;
|
||||||
|
while (_alloc[i].value) { // Search for empty cell
|
||||||
|
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||||
|
_sumpsl += psl - _alloc[i].psl;
|
||||||
|
fennec::swap(_alloc[i].psl, psl);
|
||||||
|
fennec::swap(*_alloc[i].value, value);
|
||||||
|
}
|
||||||
|
i = (i + 1) % capacity(); ++psl;
|
||||||
|
}
|
||||||
|
_alloc[i].value = fennec::move(value);
|
||||||
|
_sumpsl += (_alloc[i].psl = psl);
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocation<node, alloc_t> _alloc;
|
||||||
|
hash_t _hash;
|
||||||
|
equal_t _equal;
|
||||||
|
size_t _size;
|
||||||
|
size_t _sumpsl;
|
||||||
|
float _load;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_SET_H
|
||||||
209
include/fennec/containers/object_pool.h
Normal file
209
include/fennec/containers/object_pool.h
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file object_pool.h
|
||||||
|
/// \brief A header containing the definition for a pool of objects associated by ids
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||||
|
#define FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||||
|
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Struct which holds a pool of objects associated with ids
|
||||||
|
/// \tparam TypeT The value type
|
||||||
|
/// \tparam AllocT The allocator type
|
||||||
|
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||||
|
struct object_pool {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using value_t = TypeT;
|
||||||
|
using elem_t = optional<TypeT>;
|
||||||
|
using table_t = dynarray<elem_t, AllocT>;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an empty object pool
|
||||||
|
constexpr object_pool()
|
||||||
|
: _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Destructor, destructs objects then releases the allocation.
|
||||||
|
constexpr ~object_pool() = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of active objects in the pool
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _table.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no objects in the pool, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Retrieve the next id `i` that would be assigned to an object `o` were it added to the object pool
|
||||||
|
///
|
||||||
|
/// \details This can be useful if there are constant members that need to be assigned at construction.
|
||||||
|
/// \returns The id of the next inserted node
|
||||||
|
constexpr size_t next_id() const {
|
||||||
|
size_t next = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
next = _freed.front();
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i id of the object
|
||||||
|
/// \returns a reference to the object with id `i`
|
||||||
|
constexpr value_t& operator[](size_t i) {
|
||||||
|
assert(i < capacity(), "Index out of Bounds!");
|
||||||
|
assert(_table[i], "Attempted to access Null Object.");
|
||||||
|
return *_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Const Access Operator
|
||||||
|
/// \param i id of the object
|
||||||
|
/// \returns a const-qualified reference to the object with id `i`
|
||||||
|
constexpr const value_t& operator[](size_t i) const {
|
||||||
|
assert(i < capacity(), "Index out of Bounds!");
|
||||||
|
assert(_table[i], "Attempted to access Null Object.");
|
||||||
|
return *_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion, inserts `x` into the pool
|
||||||
|
/// \param x the object to move
|
||||||
|
/// \returns An integer corresponding to the id of the node
|
||||||
|
constexpr size_t insert(value_t&& x) {
|
||||||
|
return this->_insert(fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion, inserts a copy of `x` into the pool
|
||||||
|
/// \param x the object to copy
|
||||||
|
/// \returns An integer corresponding to the id of the node
|
||||||
|
constexpr size_t insert(const value_t& x) {
|
||||||
|
return this->_insert(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplacement, constructs a new object using `args...`
|
||||||
|
/// \param args The arguments to construct the new object with
|
||||||
|
/// \returns An integer corresponding to the id of the node
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(ArgsT&&...args) {
|
||||||
|
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase an object from the pool
|
||||||
|
/// \param i The id of the object
|
||||||
|
constexpr void erase(size_t i) {
|
||||||
|
_table[i] = nullopt;
|
||||||
|
_freed.push_back(i);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
dynarray<elem_t, AllocT> _table;
|
||||||
|
list<size_t> _freed;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
size_t _next_free() {
|
||||||
|
size_t next = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
next = _freed.front();
|
||||||
|
_freed.pop_front();
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
size_t _insert(ArgsT&&...args) {
|
||||||
|
size_t i = _next_free();
|
||||||
|
if (i >= _table.size()) {
|
||||||
|
_table.emplace_back();
|
||||||
|
}
|
||||||
|
_table[i].emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||||
332
include/fennec/containers/optional.h
Normal file
332
include/fennec/containers/optional.h
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file optional.h
|
||||||
|
/// \brief A header containing the definition for a container with an optionally present variable
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_OPTIONAL_H
|
||||||
|
#define FENNEC_CONTAINERS_OPTIONAL_H
|
||||||
|
|
||||||
|
#include <fennec/lang/utility.h>
|
||||||
|
#include <fennec/memory/new.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
struct nullopt_t {};
|
||||||
|
constexpr nullopt_t nullopt_v = {};
|
||||||
|
|
||||||
|
#define nullopt nullopt_v
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Structure to hold an optional value.
|
||||||
|
/// \tparam T
|
||||||
|
template<typename T>
|
||||||
|
struct optional {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using reference_t = T&;
|
||||||
|
using pointer_t = T*;
|
||||||
|
using const_reference_t = T&;
|
||||||
|
using const_pointer_t = const T*;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor
|
||||||
|
constexpr optional()
|
||||||
|
: _root(0)
|
||||||
|
, _set(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor
|
||||||
|
constexpr optional(nullopt_t)
|
||||||
|
: _root(0)
|
||||||
|
, _set(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Type Copy Constructor
|
||||||
|
/// \param val the value to initialize the underlying object with
|
||||||
|
constexpr optional(const T& val)
|
||||||
|
: _val(val)
|
||||||
|
, _set(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Type Move Constructor
|
||||||
|
/// \param val the value to initialize the underlying object with
|
||||||
|
constexpr optional(T&& val)
|
||||||
|
: _val(fennec::forward<T>(val))
|
||||||
|
, _set(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor
|
||||||
|
/// \param opt the optional to copy
|
||||||
|
constexpr optional(const optional& opt) requires is_copy_assignable_v<T>
|
||||||
|
: optional() {
|
||||||
|
_set = opt._set;
|
||||||
|
if (_set) {
|
||||||
|
_val = opt._val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor
|
||||||
|
/// \param opt the optional to move
|
||||||
|
constexpr optional(optional&& opt) noexcept requires is_move_assignable_v<T>
|
||||||
|
: optional() {
|
||||||
|
_set = opt._set;
|
||||||
|
if (_set) {
|
||||||
|
_val = fennec::move(opt._val);
|
||||||
|
}
|
||||||
|
opt = nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr optional(ArgsT&&...args)
|
||||||
|
: _val(fennec::forward<ArgsT>(args)...)
|
||||||
|
, _set(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~optional() {
|
||||||
|
if constexpr(is_fundamental_v<T>) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_set) {
|
||||||
|
fennec::destruct(&_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Implicit Boolean Check, returns `true` when there is a value contained
|
||||||
|
constexpr operator bool() const {
|
||||||
|
return _set;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there is no held value, `false` otherwise.
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return not _set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Assignment Operators ================================================================================================
|
||||||
|
|
||||||
|
/// \name Assignment
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Fundamental Type Assignment
|
||||||
|
/// \param val The value to set with
|
||||||
|
constexpr optional& operator=(nullopt_t) {
|
||||||
|
if constexpr(not is_fundamental_v<T>) {
|
||||||
|
if (_set) {
|
||||||
|
fennec::destruct(&_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_root = '\0';
|
||||||
|
_set = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Type Copy Assignment
|
||||||
|
/// \param val The value to set with
|
||||||
|
constexpr optional& operator=(const T& val) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
|
||||||
|
if (_set) {
|
||||||
|
_val = val;
|
||||||
|
} else {
|
||||||
|
fennec::construct(&_val, val);
|
||||||
|
_set = true;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Type Move Assignment
|
||||||
|
/// \param val The value to set with
|
||||||
|
constexpr optional& operator=(T&& val) requires is_move_constructible_v<T> and is_move_assignable_v<T> {
|
||||||
|
if (_set) {
|
||||||
|
_val = fennec::forward<T>(val);
|
||||||
|
} else {
|
||||||
|
fennec::construct(&_val, fennec::forward<T>(val));
|
||||||
|
_set = true;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment
|
||||||
|
/// \param opt The optional to copy
|
||||||
|
constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
|
||||||
|
if (_set != opt._set) {
|
||||||
|
_set = opt._set;
|
||||||
|
if (_set) { // Construct
|
||||||
|
fennec::construct(&_val, opt._val);
|
||||||
|
} else { // Destruct
|
||||||
|
fennec::destruct(&_val);
|
||||||
|
_root = 0;
|
||||||
|
}
|
||||||
|
} else if (_set) { // Copy Assignment
|
||||||
|
_val = opt._val;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment
|
||||||
|
/// \param opt The optional to move
|
||||||
|
constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v<T> and is_move_assignable_v<T> {
|
||||||
|
if (_set != opt._set) {
|
||||||
|
_set = opt._set;
|
||||||
|
if (_set) { // Construct
|
||||||
|
fennec::construct(&_val, fennec::move(opt._val));
|
||||||
|
} else { // Destruct
|
||||||
|
fennec::destruct(&_val);
|
||||||
|
_root = 0;
|
||||||
|
}
|
||||||
|
} else if (_set) { // Copy Assignment
|
||||||
|
_val = fennec::move(opt._val);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A pointer to the value, `nullptr` if there is no value
|
||||||
|
constexpr pointer_t operator->() noexcept {
|
||||||
|
return _set ? &_val : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A const-qualified pointer to the value, `nullptr` if there is no value
|
||||||
|
constexpr const_pointer_t operator->() const noexcept {
|
||||||
|
return _set ? &_val : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Dereference Operator
|
||||||
|
/// \returns A reference to the value
|
||||||
|
constexpr T& operator*() & noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Dereference Operator
|
||||||
|
/// \returns A const-qualified reference to the value
|
||||||
|
constexpr const T& operator*() const& noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Dereference Operator
|
||||||
|
/// \returns A reference to the value
|
||||||
|
constexpr T&& operator*() && noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Dereference Operator
|
||||||
|
/// \returns A const-qualified reference to the value
|
||||||
|
constexpr const T&& operator*() const&& noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Assignment
|
||||||
|
/// \val The optional to move
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr T& emplace(ArgsT&&...args) {
|
||||||
|
if (_set) {
|
||||||
|
_val = T(fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
fennec::construct(&_val, fennec::forward<ArgsT>(args)...);
|
||||||
|
_set = true;
|
||||||
|
}
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Reset the Optional
|
||||||
|
void reset() {
|
||||||
|
this->operator=(nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
char _root;
|
||||||
|
T _val;
|
||||||
|
};
|
||||||
|
bool _set;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_OPTIONAL_H
|
||||||
187
include/fennec/containers/pair.h
Normal file
187
include/fennec/containers/pair.h
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file pair.h
|
||||||
|
/// \brief A header containing the definition for a container holding a pair of values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_PAIR_H
|
||||||
|
#define FENNEC_CONTAINERS_PAIR_H
|
||||||
|
|
||||||
|
#include <fennec/containers/tuple.h>
|
||||||
|
#include <fennec/lang/hashing.h>
|
||||||
|
#include <fennec/lang/utility.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Struct for holding a pair of values
|
||||||
|
/// \tparam TypeT0 The type of the first value
|
||||||
|
/// \tparam TypeT1 The type of the second value
|
||||||
|
template<typename TypeT0, typename TypeT1>
|
||||||
|
struct pair {
|
||||||
|
|
||||||
|
// Members =============================================================================================================
|
||||||
|
|
||||||
|
TypeT0 first; ///< The first value in the pair
|
||||||
|
TypeT1 second; ///< The second value in the pair
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, invokes default constructor for both elements
|
||||||
|
constexpr pair() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, invokes destructor for both elements
|
||||||
|
constexpr ~pair() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pair Copy Constructor
|
||||||
|
/// \param x Value to copy for the first element
|
||||||
|
/// \param y Value to copy for the first element
|
||||||
|
constexpr pair(const TypeT0& x, const TypeT1& y)
|
||||||
|
: first(x)
|
||||||
|
, second(y) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pair Move Constructor
|
||||||
|
/// \param x Value to move for the first element
|
||||||
|
/// \param y Value to move for the first element
|
||||||
|
constexpr pair(TypeT0&& x, TypeT1&& y) noexcept
|
||||||
|
: first(fennec::forward<TypeT0>(x))
|
||||||
|
, second(fennec::forward<TypeT1>(y)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pair Implicit Constructor
|
||||||
|
/// \param arg1 Value to initialize the first element
|
||||||
|
/// \param arg2 Value to initialize the first element
|
||||||
|
template<typename Arg1T, typename Arg2T>
|
||||||
|
constexpr pair(Arg1T&& arg1, Arg2T&& arg2)
|
||||||
|
: first(fennec::forward<Arg1T>(arg1))
|
||||||
|
, second(fennec::forward<Arg2T>(arg2)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor, copies both elements
|
||||||
|
constexpr pair(const pair&) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor, moves both elements
|
||||||
|
constexpr pair(pair&&) noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment, copies both elements
|
||||||
|
constexpr pair& operator=(const pair&) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment, moves both elements
|
||||||
|
constexpr pair& operator=(pair&&) noexcept = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Comparison ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Comparison
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Equality Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns `true` when both elements of each pair are equal
|
||||||
|
constexpr bool operator==(const pair& p) const {
|
||||||
|
return first == p.first and second == p.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Inequality Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns `true` when either element of each pair are equal
|
||||||
|
constexpr bool operator!=(const pair& p) const {
|
||||||
|
return first != p.first or second != p.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Less Than Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is less, or they are
|
||||||
|
/// equal and the second element is less
|
||||||
|
constexpr bool operator<(const pair& p) const {
|
||||||
|
return first < p.first or (first == p.first and second < p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Less Equal Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is less, or they are
|
||||||
|
/// equal and the second element is less or equal
|
||||||
|
constexpr bool operator<=(const pair& p) const {
|
||||||
|
return first < p.first or (first == p.first and second <= p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Greater Than Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is greater, or they are
|
||||||
|
/// equal and the second element is greater
|
||||||
|
constexpr bool operator>(const pair& p) const {
|
||||||
|
return first > p.first or (first == p.first and second > p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Greater Equal Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is greater, or they are
|
||||||
|
/// equal and the second element is greater or equal
|
||||||
|
constexpr bool operator>=(const pair& p) const {
|
||||||
|
return first > p.first or (first == p.first and second >= p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TypeT0, typename TypeT1>
|
||||||
|
struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> {
|
||||||
|
constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const {
|
||||||
|
return fennec::pair_hash( // pair the hashes of both elements
|
||||||
|
hash<TypeT0>::operator()(p.first),
|
||||||
|
hash<TypeT1>::operator()(p.second)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_PAIR_H
|
||||||
626
include/fennec/containers/rdtree.h
Normal file
626
include/fennec/containers/rdtree.h
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file rdtree.h
|
||||||
|
/// \brief A header containing the definition for a tree with a root and directed edges
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_RDTREE_H
|
||||||
|
#define FENNEC_CONTAINERS_RDTREE_H
|
||||||
|
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/traversal.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Rooted-Directed Tree
|
||||||
|
/// \tparam TypeT Data type
|
||||||
|
/// \tparam AllocT Allocator Type
|
||||||
|
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||||
|
struct rdtree {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
protected:
|
||||||
|
struct node;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_t = TypeT;
|
||||||
|
using alloc_t = typename allocator_traits<AllocT>::template rebind<node>;
|
||||||
|
static constexpr size_t root = 0;
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct node {
|
||||||
|
optional<TypeT> value;
|
||||||
|
size_t parent, child, prev, next;
|
||||||
|
size_t depth, num_children;
|
||||||
|
|
||||||
|
constexpr node()
|
||||||
|
: value(nullopt)
|
||||||
|
, parent(npos), child(npos)
|
||||||
|
, prev(npos), next(npos)
|
||||||
|
, depth(0), num_children(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr node(size_t p, size_t c, size_t v, size_t n, size_t d, ArgsT&&...args)
|
||||||
|
: value(fennec::forward<ArgsT>(args)...)
|
||||||
|
, parent(p), child(c), prev(v), next(n)
|
||||||
|
, depth(d), num_children(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~node() {
|
||||||
|
parent = npos;
|
||||||
|
child = npos;
|
||||||
|
prev = npos;
|
||||||
|
next = npos;
|
||||||
|
depth = 0;
|
||||||
|
num_children = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Root Constructor, constructs the root node of the tree
|
||||||
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param args The arguments to construct the root with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
explicit constexpr rdtree(ArgsT&&...args)
|
||||||
|
: _table(), _freed(), _size(1) {
|
||||||
|
_table.creallocate(8);
|
||||||
|
fennec::construct(&_table[0], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor, copies the contents of `tree`
|
||||||
|
/// \param tree the rdtree to copy
|
||||||
|
constexpr rdtree(const rdtree& tree)
|
||||||
|
: _table(tree._table), _freed(tree._freed), _size(tree._size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor, takes ownership over the contents of `tree`
|
||||||
|
/// \param tree the rdtree to move
|
||||||
|
constexpr rdtree(rdtree&& tree) noexcept
|
||||||
|
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Assignment
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param rhs the rdtree to copy
|
||||||
|
/// \returns `this` after copying the contents of `rhs`
|
||||||
|
constexpr rdtree& operator=(const rdtree& rhs) {
|
||||||
|
for (value_t* it : this->_table) {
|
||||||
|
fennec::destruct(it);
|
||||||
|
}
|
||||||
|
_table = rhs._table;
|
||||||
|
_freed = rhs._freed;
|
||||||
|
_size = rhs._size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param rhs the rdtree to move
|
||||||
|
/// \returns `this` after taking ownership over the contents of `rhs`
|
||||||
|
constexpr rdtree& operator=(rdtree&& rhs) noexcept {
|
||||||
|
for (value_t* it : _table) {
|
||||||
|
fennec::destruct(it);
|
||||||
|
}
|
||||||
|
_table = fennec::move(rhs._table);
|
||||||
|
_freed = fennec::move(rhs._freed);
|
||||||
|
_size = rhs._size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of nodes in the tree
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _table.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no nodes in the tree, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the parent node
|
||||||
|
constexpr size_t parent(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
return i == npos ? npos : _table[i].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the child node
|
||||||
|
constexpr size_t child(size_t i, size_t n = 0) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
size_t c = i == npos ? npos : _table[i].child;
|
||||||
|
if (n != 0)
|
||||||
|
return next(c, n == npos ? npos : n - 1);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the next node
|
||||||
|
constexpr size_t next(size_t i, size_t n = 0) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
if (i == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t org = i;
|
||||||
|
size_t nxt = _table[i].next;
|
||||||
|
while (nxt != npos) {
|
||||||
|
i = nxt;
|
||||||
|
nxt = _table[i].next;
|
||||||
|
if (n != npos) {
|
||||||
|
if (n-- == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == org && n != npos ? npos : i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the previous node
|
||||||
|
constexpr size_t prev(size_t i, size_t n = 0) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
if (i == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t org = i;
|
||||||
|
size_t prv = _table[i].prev;
|
||||||
|
while (prv != npos) {
|
||||||
|
i = prv;
|
||||||
|
prv = _table[i].prev;
|
||||||
|
if (n != npos) {
|
||||||
|
if (n-- == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == org && n != npos ? npos : i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i the node to start at
|
||||||
|
/// \returns the left-most child of node `i`
|
||||||
|
constexpr size_t left_most(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
size_t n = i;
|
||||||
|
if ((n = child(n)) == npos) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
size_t p = n;
|
||||||
|
if ((n = child(n)) == npos) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i the node to start at
|
||||||
|
/// \returns the right-most child of node `i`
|
||||||
|
constexpr size_t right_most(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
if ((i = child(i)) == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
size_t n;
|
||||||
|
while ((n = next(i)) != npos) {
|
||||||
|
i = n;
|
||||||
|
}
|
||||||
|
n = i;
|
||||||
|
if ((i = child(i)) == npos) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The depth of the node
|
||||||
|
constexpr size_t depth(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
return i == npos ? npos : _table[i].depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The number of children the node has
|
||||||
|
constexpr size_t num_children(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return 0;
|
||||||
|
return i == npos ? 0 : _table[i].num_children;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The next node id were `insert` or `emplace` to be called
|
||||||
|
constexpr size_t next_id() const {
|
||||||
|
size_t i = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
i = _freed.front();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to access
|
||||||
|
/// \returns A reference to the value of the node wrapped in an optional
|
||||||
|
constexpr value_t* operator[](size_t i) {
|
||||||
|
auto& it = _table[i].value;
|
||||||
|
if (it) {
|
||||||
|
return &*_table[i].value;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to access
|
||||||
|
/// \returns A const-qualified reference to the value of the node wrapped in an optional
|
||||||
|
constexpr const value_t* operator[](size_t i) const {
|
||||||
|
const auto& it = _table[i].value;
|
||||||
|
if (it) {
|
||||||
|
return &*_table[i].value;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Insertion & Deletion ================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||||
|
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||||
|
/// \param next the next node, as an index relative to the parent
|
||||||
|
/// \param val the value to insert
|
||||||
|
/// \returns the index of the created node
|
||||||
|
constexpr size_t insert(size_t parent, size_t next, const value_t& val) {
|
||||||
|
return this->_insert(parent, next, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||||
|
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||||
|
/// \param next the next node, as an index relative to the parent
|
||||||
|
/// \param val the value to insert
|
||||||
|
/// \returns the index of the created node
|
||||||
|
constexpr size_t insert(size_t parent, size_t next, value_t&& val) {
|
||||||
|
return this->_insert(parent, next, fennec::forward<value_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||||
|
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||||
|
/// \param next the next node, as an index relative to the parent
|
||||||
|
/// \param args the args to construct the value to insert
|
||||||
|
/// \returns the index of the created node
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(size_t parent, size_t next, ArgsT&&...args) {
|
||||||
|
return this->_insert(parent, next, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Swap two nodes
|
||||||
|
/// \param i0 The id of the first node
|
||||||
|
/// \param i1 The id of the second node
|
||||||
|
constexpr void swap(size_t i0, size_t i1) {
|
||||||
|
assertf(i0 != root and i1 != root, "Cannot Swap With Root");
|
||||||
|
|
||||||
|
size_t p0 = parent(i0);
|
||||||
|
size_t p1 = parent(i1);
|
||||||
|
|
||||||
|
fennec::swap(_table[i0].parent, _table[i1].parent);
|
||||||
|
fennec::swap(_table[i0].child, _table[i1].child);
|
||||||
|
fennec::swap(_table[i0].next, _table[i1].next);
|
||||||
|
fennec::swap(_table[i0].prev, _table[i1].prev);
|
||||||
|
fennec::swap(_table[i0].depth, _table[i1].depth);
|
||||||
|
fennec::swap(_table[i0].num_children, _table[i1].num_children);
|
||||||
|
|
||||||
|
if (child(p0) == i0) _table[p0].child = i1;
|
||||||
|
if (child(p1) == i1) _table[p1].child = i0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a node in the tree and all of it's children
|
||||||
|
/// \param i the index of the node
|
||||||
|
constexpr void erase(size_t i) {
|
||||||
|
_erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Traversal ===========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Traverse the tree using a specified order and visiting functor
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// The visitor should accept a reference to a value of type `TypeT` and a `size_t` which contains the node's id.
|
||||||
|
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum
|
||||||
|
///
|
||||||
|
/// \tparam OrderT The order with which to traverse the tree.
|
||||||
|
/// \tparam VisitorT The visitor, should fulfill the signature `uint8_t visit(TypeT&, size_t)`
|
||||||
|
/// \param visit The visiting object
|
||||||
|
/// \param i The node to start at
|
||||||
|
template<typename OrderT, typename VisitorT>
|
||||||
|
void traverse(VisitorT&& visit, size_t i = root) {
|
||||||
|
OrderT order;
|
||||||
|
i = order(*this, i);
|
||||||
|
while (i != npos) {
|
||||||
|
uint8_t mode = traversal_control_continue;
|
||||||
|
if (_table[i].value) {
|
||||||
|
mode = visit(*_table[i].value, i);
|
||||||
|
}
|
||||||
|
if (mode == traversal_control_break) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = order[*this, i, mode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pre_order {
|
||||||
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
|
size_t operator()(const rdtree&, size_t start) {
|
||||||
|
head = start;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
|
||||||
|
if (node == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nxt = tree.next(node);
|
||||||
|
size_t chd = tree.child(node);
|
||||||
|
|
||||||
|
if (nxt != npos && node != head) {
|
||||||
|
visit.push_front(nxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chd != npos && mode != traversal_control_jump_over) {
|
||||||
|
visit.push_front(chd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not visit.empty()) {
|
||||||
|
node = visit.front();
|
||||||
|
visit.pop_front();
|
||||||
|
} else {
|
||||||
|
node = npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct in_order {
|
||||||
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
|
size_t operator()(const rdtree& tree, size_t start) {
|
||||||
|
head = start;
|
||||||
|
return tree.left_most(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator[](const rdtree& tree, size_t node, uint8_t) {
|
||||||
|
if (node == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t prnt = tree.parent(node);
|
||||||
|
size_t next = tree.next(node);
|
||||||
|
if (node != head) {
|
||||||
|
if (tree.child(prnt) == node) {
|
||||||
|
visit.push_back(prnt);
|
||||||
|
if (next != npos) {
|
||||||
|
visit.push_back(tree.left_most(next));
|
||||||
|
}
|
||||||
|
} else if (next != npos) {
|
||||||
|
visit.push_front(tree.left_most(next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not visit.empty()) {
|
||||||
|
node = visit.front();
|
||||||
|
visit.pop_front();
|
||||||
|
} else {
|
||||||
|
node = npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct post_order {
|
||||||
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
|
size_t operator()(const rdtree& tree, size_t start) {
|
||||||
|
head = start;
|
||||||
|
return tree.left_most(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator[](const rdtree& tree, size_t node, uint8_t) {
|
||||||
|
if (node == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t prnt = tree.parent(node);
|
||||||
|
size_t next = tree.next(node);
|
||||||
|
|
||||||
|
if (node != head) {
|
||||||
|
if (next != npos) {
|
||||||
|
visit.push_front(tree.left_most(next));
|
||||||
|
} else {
|
||||||
|
visit.push_front(prnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not visit.empty()) {
|
||||||
|
node = visit.front();
|
||||||
|
visit.pop_front();
|
||||||
|
} else {
|
||||||
|
node = npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
allocation<node, alloc_t> _table;
|
||||||
|
list<size_t> _freed;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
void _expand() {
|
||||||
|
_table.creallocate(_table.capacity() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _next_free() {
|
||||||
|
size_t next = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
next = _freed.front();
|
||||||
|
_freed.pop_front();
|
||||||
|
}
|
||||||
|
if (_size >= capacity()) {
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t _insert(size_t p, size_t n, ArgsT&&...args) {
|
||||||
|
if (_size == 0) {
|
||||||
|
fennec::construct(&_table[root], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||||
|
_size = 1;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == npos) {
|
||||||
|
_table[root].value = value_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
_size = _size == 0 ? 1 : _size;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = _next_free();
|
||||||
|
size_t nxt = child(p, n);
|
||||||
|
size_t prv = n == npos ? npos : prev(n);
|
||||||
|
|
||||||
|
++_table[p].num_children;
|
||||||
|
if ((nxt == child(p) && n != npos) || nxt == npos) {
|
||||||
|
_table[p].child = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == npos) {
|
||||||
|
if (nxt != npos) {
|
||||||
|
_table[nxt].next = idx;
|
||||||
|
}
|
||||||
|
fennec::construct(&_table[idx], p, npos, nxt, npos, depth(p) + 1, fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
if (nxt != npos) {
|
||||||
|
_table[nxt].prev = idx;
|
||||||
|
}
|
||||||
|
if (prv != npos) {
|
||||||
|
_table[prv].next = idx;
|
||||||
|
}
|
||||||
|
fennec::construct(&_table[idx], p, npos, prv, nxt, depth(p) + 1, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void _erase(size_t i) {
|
||||||
|
list<size_t> queue;
|
||||||
|
queue.push_back(child(i));
|
||||||
|
while (not queue.empty()) {
|
||||||
|
size_t n = queue.front(); queue.pop_front();
|
||||||
|
if (n == npos) continue;
|
||||||
|
queue.push_back(next(n));
|
||||||
|
queue.push_back(child(n));
|
||||||
|
fennec::destruct(&_table[n]);
|
||||||
|
_freed.push_back(n);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fennec::destruct(&_table[i]);
|
||||||
|
if (i != root) _freed.push_back(i);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_RDTREE_H
|
||||||
492
include/fennec/containers/set.h
Normal file
492
include/fennec/containers/set.h
Normal file
@@ -0,0 +1,492 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file set.h
|
||||||
|
/// \brief A header containing the definition for a set of unique values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_SET_H
|
||||||
|
#define FENNEC_CONTAINERS_SET_H
|
||||||
|
|
||||||
|
// https://programming.guide/robin-hood-hashing.html
|
||||||
|
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
|
#include <fennec/lang/compare.h>
|
||||||
|
#include <fennec/math/ext/primes.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
#include <fennec/lang/hashing.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \brief wrapper for sets of elements
|
||||||
|
/// \details
|
||||||
|
/// This data-structure behaves like a set, but does not use pointers, instead storing the table in-array
|
||||||
|
///
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ✅ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT The type to contain
|
||||||
|
template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
|
||||||
|
struct set {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
||||||
|
using hash_t = Hash;
|
||||||
|
using equal_t = Equals;
|
||||||
|
using elem_t = TypeT;
|
||||||
|
|
||||||
|
class iterator;
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
static constexpr double default_load = 0.8;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node {
|
||||||
|
optional<elem_t> value;
|
||||||
|
int psl;
|
||||||
|
|
||||||
|
constexpr node() = default;
|
||||||
|
constexpr ~node() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty set
|
||||||
|
constexpr set()
|
||||||
|
: _alloc()
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Copy Constructor, initializes empty set with a hash
|
||||||
|
/// \param hash the hash object
|
||||||
|
constexpr set(const hash_t& hash)
|
||||||
|
: _alloc()
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Copy Constructor, initializes empty set with an allocator
|
||||||
|
/// \param alloc the allocator object
|
||||||
|
constexpr set(const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Alloc Copy Constructor, initializes empty set with a hash and allocator
|
||||||
|
/// \param hash the hash object
|
||||||
|
/// \param alloc the allocator object
|
||||||
|
constexpr set(const hash_t& hash, const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Copy Constructor
|
||||||
|
/// \param set Set to copy
|
||||||
|
constexpr set(const set& set)
|
||||||
|
: _alloc(set._alloc)
|
||||||
|
, _hash(set._hash)
|
||||||
|
, _size(set._size)
|
||||||
|
, _sumpsl(set._sumpsl)
|
||||||
|
, _load(set._load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Move Constructor
|
||||||
|
/// \param set Set to move
|
||||||
|
constexpr set(set&& set) noexcept
|
||||||
|
: _alloc(fennec::move(set._alloc))
|
||||||
|
, _hash(fennec::move(set._hash))
|
||||||
|
, _size(fennec::move(set._size))
|
||||||
|
, _sumpsl(set._sumpsl)
|
||||||
|
, _load(set._load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, destructs all elements and releases the allocation
|
||||||
|
constexpr ~set() {
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Size of the set in elements
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the set is empty, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Capacity of the set in elements
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _alloc.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Find an Element
|
||||||
|
/// \param val Value to find
|
||||||
|
/// \returns An iterator at the location of the value
|
||||||
|
constexpr iterator find(const elem_t& val) const {
|
||||||
|
if (capacity() == 0) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
size_t s = _hash(val) % capacity(); // Initial search index
|
||||||
|
int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl
|
||||||
|
size_t i = (s + psl) % capacity(); // Median search
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
// Check the first element;
|
||||||
|
if (_alloc[i].psl >= psl && _alloc[i].value) {
|
||||||
|
if (_equal(*_alloc[i].value, val)) {
|
||||||
|
return iterator(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop while there is a value and its psl is greater than our probe
|
||||||
|
while (true) {
|
||||||
|
++n;
|
||||||
|
size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow
|
||||||
|
size_t i1 = (i + n) % capacity();
|
||||||
|
int p0 = psl - n, p1 = psl + n;
|
||||||
|
bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
|
||||||
|
|
||||||
|
if (c0 && _alloc[i0].value) {
|
||||||
|
if (_equal(*_alloc[i0].value, val)) {
|
||||||
|
return iterator(this, i0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 && _alloc[i1].value) {
|
||||||
|
if (_equal(*_alloc[i1].value, val)) {
|
||||||
|
return iterator(this, i1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not(c0 or c1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if a set contains a value
|
||||||
|
/// \param val Value to check
|
||||||
|
/// \returns `true` if `val` can be found, `false` otherwise
|
||||||
|
constexpr bool contains(const elem_t& val) const {
|
||||||
|
return this->find(val) != end();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A pointer to the element, `nullptr` if not found.
|
||||||
|
/// The value should not be changed in a manner that will change the hash of the element.
|
||||||
|
constexpr elem_t* at(const iterator& it) {
|
||||||
|
if (it == end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Const Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A const-qualified pointer to the element, `nullptr` if not found.
|
||||||
|
constexpr const elem_t* at(const iterator& it) const {
|
||||||
|
if (not _alloc[it._i].value) return nullptr;
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr iterator insert(elem_t&& val) {
|
||||||
|
return this->_insert(fennec::forward<elem_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr iterator insert(const elem_t& val) {
|
||||||
|
return this->_insert(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr iterator emplace(ArgsT&&...args) {
|
||||||
|
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param it Location to erase
|
||||||
|
constexpr void erase(iterator it) {
|
||||||
|
size_t i = it._i;
|
||||||
|
if (i >= capacity()) {
|
||||||
|
return;
|
||||||
|
} // These are separated due to compilers being inconsistent
|
||||||
|
if (not _alloc[i].value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
_sumpsl -= _alloc[i].psl;
|
||||||
|
--_size;
|
||||||
|
size_t p = i;
|
||||||
|
while (_alloc[i = (i + 1) % capacity()].value) {
|
||||||
|
if (_alloc[i].psl == 0) break;
|
||||||
|
|
||||||
|
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
|
||||||
|
--_alloc[p].psl, --_sumpsl;
|
||||||
|
p = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param val Value to erase
|
||||||
|
constexpr void erase(const elem_t& val) {
|
||||||
|
this->erase(this->find(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief
|
||||||
|
constexpr void clear() {
|
||||||
|
for (size_t i = 0; i < _alloc.capacity(); ++i) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// ITERATOR ============================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns An iterator for all elements of the set in no particular order
|
||||||
|
constexpr iterator begin() const {
|
||||||
|
iterator it(this, 0);
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns An iterator representing the end of the set
|
||||||
|
constexpr iterator end() const {
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Class for Iterating the Set
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
constexpr iterator(const set* set, size_t i)
|
||||||
|
: _set(set)
|
||||||
|
, _i(i) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~iterator() {
|
||||||
|
_set = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr friend iterator& operator++(iterator& rhs) {
|
||||||
|
while (++rhs._i < rhs._set->capacity()) {
|
||||||
|
if (rhs._set->_alloc[rhs._i].value) {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rhs._i = npos;
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend iterator operator++(iterator& lhs, int) {
|
||||||
|
iterator prev = lhs;
|
||||||
|
++lhs;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t& operator*() const {
|
||||||
|
return *_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t* operator->() const {
|
||||||
|
if (not _set->_alloc[_i].value) return nullptr;
|
||||||
|
return &*_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) const {
|
||||||
|
return _set == it._set and _i == it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const iterator& it) const {
|
||||||
|
return _set != it._set or _i != it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t index() const { return _i; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const set* _set;
|
||||||
|
size_t _i;
|
||||||
|
friend set;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// PRIVATE =============================================================================================================
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr void _expand() {
|
||||||
|
set cpy; // Create a new set
|
||||||
|
cpy._alloc.resize(
|
||||||
|
fennec::next_prime2(_alloc.capacity())
|
||||||
|
);
|
||||||
|
|
||||||
|
// rehash
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
if (_alloc[i].value) {
|
||||||
|
cpy.insert(fennec::move(*_alloc[i].value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
|
fennec::swap(_alloc, cpy._alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr iterator _insert(ArgsT&&...args) {
|
||||||
|
if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
elem_t value(fennec::forward<ArgsT>(args)...);
|
||||||
|
size_t i = _hash(value) % capacity(); // Initial search index
|
||||||
|
int psl = 0;
|
||||||
|
while (_alloc[i].value) { // Search for empty cell
|
||||||
|
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
|
||||||
|
return iterator(this, i);
|
||||||
|
}
|
||||||
|
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||||
|
_sumpsl += psl - _alloc[i].psl;
|
||||||
|
fennec::swap(_alloc[i].psl, psl);
|
||||||
|
fennec::swap(*_alloc[i].value, value);
|
||||||
|
}
|
||||||
|
i = (i + 1) % capacity(); ++psl;
|
||||||
|
}
|
||||||
|
_alloc[i].value = fennec::move(value);
|
||||||
|
_sumpsl += (_alloc[i].psl = psl);
|
||||||
|
++_size;
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynarray<node, alloc_t> _alloc;
|
||||||
|
hash_t _hash;
|
||||||
|
equal_t _equal;
|
||||||
|
size_t _size;
|
||||||
|
size_t _sumpsl;
|
||||||
|
float _load;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_SET_H
|
||||||
47
include/fennec/containers/traversal.h
Normal file
47
include/fennec/containers/traversal.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file traversal.h
|
||||||
|
/// \brief a header containing constants and utilities related to traversal
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_TRAVERSAL_H
|
||||||
|
#define FENNEC_CONTAINERS_TRAVERSAL_H
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief A set of constants used in the traverser-visitor pattern
|
||||||
|
enum traversal_control_ {
|
||||||
|
traversal_control_continue = 0,
|
||||||
|
traversal_control_break = 1,
|
||||||
|
traversal_control_jump_over = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_TRAVERSAL_H
|
||||||
106
include/fennec/containers/tuple.h
Normal file
106
include/fennec/containers/tuple.h
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file tuple.h
|
||||||
|
/// \brief A header containing the definition for a container with multiple values of differing types
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_TUPLE_H
|
||||||
|
#define FENNEC_CONTAINERS_TUPLE_H
|
||||||
|
|
||||||
|
#include <fennec/containers/detail/_tuple.h>
|
||||||
|
#include <fennec/lang/type_sequences.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Tuple, holds a collection of values of different types
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ⛔ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | ⛔ |
|
||||||
|
/// | deletion | ⛔ |
|
||||||
|
///
|
||||||
|
/// \tparam TypesT The types to store
|
||||||
|
template<typename...TypesT> struct tuple;
|
||||||
|
|
||||||
|
|
||||||
|
template<size_t i, typename...TypesT>
|
||||||
|
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
||||||
|
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||||
|
auto& it = *static_cast<detail::_tuple_leaf<i, elem_t>*>(&x);
|
||||||
|
return it.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t i, typename...TypesT>
|
||||||
|
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) {
|
||||||
|
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||||
|
const auto& it = *static_cast<const detail::_tuple_leaf<i, elem_t>*>(&x);
|
||||||
|
return it.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ...TypesT>
|
||||||
|
struct tuple : public detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>
|
||||||
|
{
|
||||||
|
using base_t = detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>;
|
||||||
|
|
||||||
|
template<size_t i>
|
||||||
|
using elem_t = typename nth_element<i, TypesT...>::type;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
tuple(ArgsT&&...args)
|
||||||
|
: base_t(fennec::forward<ArgsT>(args)...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple(const tuple& cpy)
|
||||||
|
: base_t(cpy) {
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple(tuple&& cpy)
|
||||||
|
: base_t(cpy) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is needed for
|
||||||
|
template<typename...TypesT>
|
||||||
|
tuple(TypesT...) -> tuple<TypesT...>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_TUPLE_H
|
||||||
34
include/fennec/containers/variant.h
Normal file
34
include/fennec/containers/variant.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file variant.h
|
||||||
|
/// \brief Contains the definition for a structure that holds a single value from multiple types
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_VARIANT_H
|
||||||
|
#define FENNEC_CONTAINERS_VARIANT_H
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_VARIANT_H
|
||||||
@@ -29,31 +29,42 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \page page_fennec_documentation Documentation
|
/// \page contents Contents
|
||||||
///
|
///
|
||||||
/// \section page_fennec_documentation_pages Pages
|
|
||||||
/// 1. \ref introduction "Introduction"
|
/// 1. \ref introduction "Introduction"
|
||||||
/// 1. \ref coding-standards "Coding Standards"
|
/// 1. \ref coding-standards "Coding Standards"
|
||||||
/// 2. \ref building-from-source "Building from Source"
|
/// 2. \ref building-from-source "Building from Source"
|
||||||
/// 1. \ref building-from-terminal "Building from Terminal"
|
/// 1. \ref building-from-terminal "Building from Terminal"
|
||||||
|
/// 1. \ref debian "Debian"
|
||||||
|
/// 2. \ref arch "Arch"
|
||||||
|
/// 3. \ref fedora "Fedora"
|
||||||
/// 2. \ref building-on-windows "Building on Windows"
|
/// 2. \ref building-on-windows "Building on Windows"
|
||||||
/// 3. \ref running-the-test-suite "Running the Test Suite"
|
/// 3. \ref running-the-test-suite "Running the Test Suite"
|
||||||
/// 4. \ref usage "Usage"
|
/// 4. \ref usage "Usage"
|
||||||
|
/// 1. \ref licensing "Licensing"
|
||||||
/// 5. \ref contribution "Contribution"
|
/// 5. \ref contribution "Contribution"
|
||||||
/// 6. \subpage page_fennec_libraries
|
/// 6. \subpage libraries
|
||||||
/// 1. \ref page_fennec_lang "C++ Language Library"
|
/// 1. \ref fennec_lang "C++ Language Library"
|
||||||
/// 2. \ref page_fennec_math "Math Library"
|
/// 2. \ref fennec_math "Math Library"
|
||||||
|
/// 2. \ref fennec_memory "Memory Management Library"
|
||||||
|
/// 2. \ref fennec_containers "Containers Library"
|
||||||
///
|
///
|
||||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
///
|
///
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \page page_fennec_libraries Libraries
|
/// \page libraries Libraries
|
||||||
///
|
///
|
||||||
/// | Library | Brief |
|
/// | Library | Brief |
|
||||||
/// | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
/// |:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
/// | \subpage page_fennec_lang | Implementation for functions and classes related to the C++ Language, including base types, common utility functions, and metaprogramming templates |
|
/// | \subpage fennec_lang | Implementation for functions and classes related to the C++ Language, including base types, common utility functions, and metaprogramming templates |
|
||||||
/// | \subpage page_fennec_math | Implementation of math functions according to the [OpenGL 4.6 Shading Language Specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf). Additional extensions are provided for other common math functions. |
|
/// | \subpage fennec_math | Implementation of math functions according to the [OpenGL 4.6 Shading Language Specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf). Additional extensions are provided for other common math functions. |
|
||||||
|
/// | \subpage fennec_memory | Implementation of functions related to memory management. |
|
||||||
|
/// | \subpage fennec_containers | Implementation of common data structures, those that are specified in the C++ STD Library, and custom data structures that fennec uses. |
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CORE_ENGINE_H
|
#ifndef FENNEC_CORE_ENGINE_H
|
||||||
#define FENNEC_CORE_ENGINE_H
|
#define FENNEC_CORE_ENGINE_H
|
||||||
|
|||||||
61
include/fennec/core/event.h
Normal file
61
include/fennec/core/event.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_CORE_EVENT_H
|
||||||
|
#define FENNEC_CORE_EVENT_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/typeuuid.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
struct event;
|
||||||
|
|
||||||
|
class event_listener {
|
||||||
|
public:
|
||||||
|
virtual ~event_listener() = default;
|
||||||
|
virtual void handle_event(event* event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct event {
|
||||||
|
const uint64_t type;
|
||||||
|
|
||||||
|
event() = delete;
|
||||||
|
|
||||||
|
template<typename EventT>
|
||||||
|
event() : type(typeuuid<EventT>()) { }
|
||||||
|
|
||||||
|
template<typename EventT>
|
||||||
|
static void add_listener(event_listener* listener) {
|
||||||
|
event::add_listener(listener, typeuuid<EventT, event>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename EventT>
|
||||||
|
static void dispatch(EventT* event) {
|
||||||
|
dispatch(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_listener(event_listener* listener, uint64_t type);
|
||||||
|
static void remove_listener(event_listener* listener);
|
||||||
|
static void dispatch(event* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CORE_EVENT_H
|
||||||
47
include/fennec/core/system.h
Normal file
47
include/fennec/core/system.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_CORE_SYSTEM_H
|
||||||
|
#define FENNEC_CORE_SYSTEM_H
|
||||||
|
#include <fennec/langproc/strings/string.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
class system {
|
||||||
|
public:
|
||||||
|
using tick_f = void (*)(system*, double);
|
||||||
|
using frame_f = void (*)(system*, size_t);
|
||||||
|
|
||||||
|
const string name;
|
||||||
|
const tick_f tick;
|
||||||
|
const frame_f frame;
|
||||||
|
|
||||||
|
system(const cstring& name, tick_f tick, frame_f frame)
|
||||||
|
: name(name), tick(tick), frame(frame) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~system() = default;
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void shutdown() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CORE_SYSTEM_H
|
||||||
92
include/fennec/lang/assert.h
Normal file
92
include/fennec/lang/assert.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file assert.h
|
||||||
|
/// \brief \ref fennec_lang_assert
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_ASSERT_H
|
||||||
|
#define FENNEC_LANG_ASSERT_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_assert Assertions
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/assert.h> \endcode
|
||||||
|
///
|
||||||
|
/// This header contains macros for making assertions about code behaviour.
|
||||||
|
///
|
||||||
|
/// fennec defines the following assert implementations:
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_bits">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// assert(expr, desc)
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Make an assertion with expression `expr` and provide a description `desc`. Only halts in debug mode.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// assertf(expr, desc)
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Make an assertion with expression `expr` and provide a description `desc`. Always halts.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// assertd(expr, desc)
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Make an assertion, ***only in debug mode***, with expression `expr` and provide a description `desc`.
|
||||||
|
/// This should be used when the branching caused by `assert` would hinder performance in release mode.
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#if FENNEC_COMPILER_MSVC
|
||||||
|
#define __PRETTY_FUNCTION__ __FUNCSIG__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using assert_handler = void (*)(const char *, const char *, int , const char *);
|
||||||
|
|
||||||
|
void _assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc, bool halt);
|
||||||
|
|
||||||
|
// flagged unlikely to optimize branch prediction
|
||||||
|
#define assert(expression, description) \
|
||||||
|
if(not(expression)) [[unlikely]] { \
|
||||||
|
_assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, not FENNEC_RELEASE); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define assertf(expression, description) \
|
||||||
|
if(not(expression)) [[unlikely]] { \
|
||||||
|
_assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, true); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FENNEC_RELEASE
|
||||||
|
#define assertd(expression, description)
|
||||||
|
#else
|
||||||
|
#define assertd(expression, description) assert(expression, description)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_ASSERT_H
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,36 +16,217 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file bits.h
|
||||||
|
/// \brief \ref fennec_lang_bit_manipulation
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_BITS_H
|
#ifndef FENNEC_LANG_BITS_H
|
||||||
#define FENNEC_LANG_BITS_H
|
#define FENNEC_LANG_BITS_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_bit_manipulation Bit Manipulation
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/bits.h> \endcode
|
||||||
|
///
|
||||||
|
/// This header contains definitions for manipulating the bits of a provided object or pointer.
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_bits">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_cast "ToT bit_cast(const FromT& x)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_cast
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_and "void* bit_and(void* arr, const void* mask, size_t n)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_and
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_and_s "void* bit_and_s(void* arr, size_t n0, const void* mask, size_t n1)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_and_s
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_or "void* bit_or(void* arr, const void* mask, size_t n)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_or
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_or_s "void* bit_or_s(void* arr, size_t n0, const void* mask, size_t n1)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_or_s
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_xor "void* bit_xor(void* arr, const void* mask, size_t n)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_xor
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bit_xor_s "void* bit_xor_s(void* arr, size_t n0, const void* mask, size_t n1)"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bit_xor_s
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#include <fennec/lang/intrinsics.h>
|
#include <fennec/lang/intrinsics.h>
|
||||||
#include <fennec/memory/memory.h>
|
#include <fennec/memory/common.h>
|
||||||
|
#include <fennec/lang/detail/_bits.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \fn fennec::bit_cast(const FromT&)
|
/// \brief Perform a bitcast of FromT to ToT
|
||||||
/// \brief
|
///
|
||||||
|
/// \details Perform a bitcast of FromT to ToT
|
||||||
/// \tparam ToT Type to cast to
|
/// \tparam ToT Type to cast to
|
||||||
/// \tparam FromT Type of the value
|
/// \tparam FromT Type of the value
|
||||||
/// \param from Value to bit cast
|
/// \param from Value to bit cast
|
||||||
/// \return A value containing a bitwise copy of the input
|
/// \returns A value containing a bitwise copy of the input
|
||||||
template<typename ToT, typename FromT> requires(sizeof(ToT) == sizeof(FromT))
|
template<typename ToT, typename FromT> requires(sizeof(ToT) == sizeof(FromT))
|
||||||
constexpr ToT bit_cast(const FromT& from)
|
constexpr ToT bit_cast(const FromT& from) {
|
||||||
{
|
if constexpr(FENNEC_HAS_BUILTIN_BIT_CAST) {
|
||||||
if constexpr(FENNEC_HAS_BUILTIN_BIT_CAST)
|
|
||||||
return FENNEC_BUILTIN_BIT_CAST(ToT, from);
|
return FENNEC_BUILTIN_BIT_CAST(ToT, from);
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
ToT to;
|
ToT to;
|
||||||
memcpy(&to, &from, sizeof(ToT));
|
fennec::memcpy(&to, &from, sizeof(ToT));
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Perform a bit-wise and over an array of bytes
|
||||||
|
///
|
||||||
|
/// \details Perform a bitcast of FromT to ToT
|
||||||
|
/// \param arr the array of bytes to modify
|
||||||
|
/// \param mask the mask to and against arr
|
||||||
|
/// \param n the number of bytes
|
||||||
|
/// \returns the pointer \f$arr\f$
|
||||||
|
constexpr void* bit_and(void* arr, const void* mask, size_t n) {
|
||||||
|
if (arr == mask) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* d = static_cast<uint8_t*>(arr);
|
||||||
|
const uint8_t* s = static_cast<const uint8_t*>(mask);
|
||||||
|
|
||||||
|
while (n > 0) {
|
||||||
|
const size_t step = detail::_bit_and(d, s, n);
|
||||||
|
d += step; s += step; n -= step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Safe version of fennec::bit_and
|
||||||
|
///
|
||||||
|
/// \details Safe version of fennec::bit_and
|
||||||
|
/// \param arr the array of bytes to modify
|
||||||
|
/// \param n0 the size of arr in bytes
|
||||||
|
/// \param mask the mask to and against arr
|
||||||
|
/// \param n1 the size of mask in bytes
|
||||||
|
/// \returns the pointer arr
|
||||||
|
constexpr void* bit_and_s(void* arr, size_t n0, const void* mask, size_t n1) {
|
||||||
|
return bit_and(arr, mask, n0 < n1 ? n0 : n1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Perform a bit-wise or over an array of bytes
|
||||||
|
///
|
||||||
|
/// \details Perform a bit-wise or over an array of bytes
|
||||||
|
/// \param arr the array of bytes to modify
|
||||||
|
/// \param mask the mask to or against arr
|
||||||
|
/// \param n the number of bytes
|
||||||
|
/// \returns the pointer arr
|
||||||
|
constexpr void* bit_or(void* arr, const void* mask, size_t n) {
|
||||||
|
if (arr == mask) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* d = static_cast<uint8_t*>(arr);
|
||||||
|
const uint8_t* s = static_cast<const uint8_t*>(mask);
|
||||||
|
while (n > 0)
|
||||||
|
{
|
||||||
|
const size_t step = detail::_bit_or(d, s, n);
|
||||||
|
d += step; s += step; n -= step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Safe version of fennec::bit_or
|
||||||
|
///
|
||||||
|
/// \details Safe version of fennec::bit_or
|
||||||
|
/// \param arr the array of bytes to modify
|
||||||
|
/// \param n0 the size of arr in bytes
|
||||||
|
/// \param mask the mask to or against arr
|
||||||
|
/// \param n1 the size of mask in bytes
|
||||||
|
/// \returns the pointer arr
|
||||||
|
constexpr void* bit_or_s(void* arr, size_t n0, const void* mask, size_t n1) {
|
||||||
|
return bit_or(arr, mask, n0 < n1 ? n0 : n1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Perform a bit-wise or over an array of bytes
|
||||||
|
///
|
||||||
|
/// \details Perform a bit-wise or over an array of bytes
|
||||||
|
/// \param arr the array of bytes to modify
|
||||||
|
/// \param mask the mask to or against arr
|
||||||
|
/// \param n the number of bytes
|
||||||
|
/// \returns the pointer arr
|
||||||
|
constexpr void* bit_xor(void* arr, const void* mask, size_t n) {
|
||||||
|
if (arr == mask) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* d = static_cast<uint8_t*>(arr);
|
||||||
|
const uint8_t* s = static_cast<const uint8_t*>(mask);
|
||||||
|
while (n > 0) {
|
||||||
|
const size_t step = detail::_bit_xor(d, s, n);
|
||||||
|
d += step; s += step; n -= step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Safe version of fennec::bit_xor
|
||||||
|
///
|
||||||
|
/// \details Safe version of fennec::bit_xor
|
||||||
|
/// \param arr the array of bytes to modify
|
||||||
|
/// \param n0 the size of arr in bytes
|
||||||
|
/// \param mask the mask to or against arr
|
||||||
|
/// \param n1 the size of mask in bytes
|
||||||
|
/// \returns the pointer arr
|
||||||
|
constexpr void* bit_xor_s(void* arr, size_t n0, const void* mask, size_t n1) {
|
||||||
|
return bit_xor(arr, mask, n0 < n1 ? n0 : n1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_LANG_BITS_H
|
#endif // FENNEC_LANG_BITS_H
|
||||||
|
|||||||
123
include/fennec/lang/compare.h
Normal file
123
include/fennec/lang/compare.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_COMPARE_H
|
||||||
|
#define FENNEC_LANG_COMPARE_H
|
||||||
|
|
||||||
|
#include <fennec/lang/type_operators.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// equality ============================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> struct equality;
|
||||||
|
|
||||||
|
template<typename T0, typename T1> requires has_equals_v<T0, T1>
|
||||||
|
struct equality<T0, T1> {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return x == y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1> requires(not has_equals_v<T0, T1>
|
||||||
|
and has_less_v<T0, T1> and has_less_v<T1, T0>)
|
||||||
|
struct equality<T0, T1> {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return not(x < y) and not(y < x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1> requires(not(has_equals_v<T0, T1>)
|
||||||
|
and(not has_less_v<T0, T1> or not has_less_v<T1, T0>)
|
||||||
|
and(has_greater_v<T0, T1> and has_greater_v<T1, T0>))
|
||||||
|
struct equality<T0, T1> {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return not(x > y) and not(y > x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// inequality ==========================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> struct inequality;
|
||||||
|
|
||||||
|
template<typename T0, typename T1> requires has_nequals_v<T0, T1>
|
||||||
|
struct inequality<T0, T1> {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return x != y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0>
|
||||||
|
struct inequality<T0, T1> {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return (x < y) or (y < x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0>
|
||||||
|
struct inequality<T0, T1> {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return (x > y) or (y > x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// less ================================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> requires has_less_v<T0, T1>
|
||||||
|
struct less {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// less_equal ==========================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1>
|
||||||
|
struct less_equals {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// less ================================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1>
|
||||||
|
struct greater {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// less_equal ==========================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1>
|
||||||
|
struct greater_equals {
|
||||||
|
constexpr bool operator()(const T0& x, const T1& y) const {
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_COMPARE_H
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file conditional_types.h
|
/// \file conditional_types.h
|
||||||
/// \brief metaprogramming to conditionally set a type
|
/// \brief \ref fennec_lang_conditional_types
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -32,43 +32,72 @@
|
|||||||
#ifndef FENNEC_LANG_CONDITIONAL_TYPES_H
|
#ifndef FENNEC_LANG_CONDITIONAL_TYPES_H
|
||||||
#define FENNEC_LANG_CONDITIONAL_TYPES_H
|
#define FENNEC_LANG_CONDITIONAL_TYPES_H
|
||||||
|
|
||||||
#include <fennec/lang/type_transforms.h>
|
#include <fennec/lang/type_identity.h>
|
||||||
#include <fennec/lang/types.h>
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_conditional_types Conditional Types
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/conditional_types.h> \endcode
|
||||||
|
///
|
||||||
|
/// This header contains various compile-time functions for conditionally setting types, detecting types, or
|
||||||
|
/// conditionally enabling functions. <br><br>
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_conditional_types">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::conditional "typename conditional<bool B, TrueT, FalseT>::type"<br>
|
||||||
|
/// \ref fennec::conditional_t "conditional_t<bool B, TrueT, FalseT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::conditional
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::detect "typename detect<DefaultT, DetectT<...>, ArgsT...>::type"<br>
|
||||||
|
/// \ref fennec::detect_t "detect_t<DefaultT, DetectT<...>, ArgsT...>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::detect
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::enable_if "typename enable_if<bool B, TypeT>::type"<br>
|
||||||
|
/// \ref fennec::enable_if_t "enable_if_t<bool B, TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::enable_if
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
// fennec::conditional =================================================================================================
|
// fennec::conditional =================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief select between two types based on a condition
|
/// \brief select between two types based on a condition
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Selects between \p TrueT and \p FalseT based on the boolean value \p b.
|
||||||
|
/// The chosen type is stored in `conditional::type`.
|
||||||
/// \tparam B the value of the condition
|
/// \tparam B the value of the condition
|
||||||
/// \tparam T type to use when \f$B == true\f$
|
/// \tparam TrueT type to use when \f$B == true\f$
|
||||||
/// \tparam F type to use when \f$B == false\f$
|
/// \tparam FalseT type to use when \f$B == false\f$
|
||||||
template<bool_t B, typename T, typename F>
|
template<bool B, typename TrueT, typename FalseT>
|
||||||
struct conditional;
|
struct conditional;
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Shorthand for ```typename conditional<ConditionV, TrueT, FalseT>::type```
|
/// \brief Shorthand for ```typename conditional<ConditionV, TrueT, FalseT>::type```
|
||||||
template<bool_t B, typename T, typename F>
|
template<bool B, typename TrueT, typename FalseT>
|
||||||
using conditional_t
|
using conditional_t
|
||||||
= typename conditional<B, T, F>::type;
|
= typename conditional<B, TrueT, FalseT>::type;
|
||||||
|
|
||||||
|
|
||||||
// specialization of fennec::conditional for `true` case
|
// specialization of fennec::conditional for `true` case
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
struct conditional<true, T, F>
|
struct conditional<true, T, F> : type_identity<T>{};
|
||||||
: type_transform<T>{};
|
|
||||||
|
|
||||||
|
|
||||||
// specialization of fennec::conditional for `false` case
|
// specialization of fennec::conditional for `false` case
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
struct conditional<false, T, F>
|
struct conditional<false, T, F> : type_identity<F>{};
|
||||||
: type_transform<F>{};
|
|
||||||
|
|
||||||
|
|
||||||
// fennec::detect ======================================================================================================
|
// fennec::detect ======================================================================================================
|
||||||
@@ -76,8 +105,8 @@ struct conditional<false, T, F>
|
|||||||
///
|
///
|
||||||
/// \brief Detect whether `DetectT<ArgsT...>` is a valid type
|
/// \brief Detect whether `DetectT<ArgsT...>` is a valid type
|
||||||
///
|
///
|
||||||
/// \details The chosen type is stored in `detect::type` and
|
/// \details Selects `DetectT<ArgsT...>` if it exists, otherwise selects `DefaultT` The chosen type is stored in `detect::type` and
|
||||||
/// a boolean value is stored in `detect::is_detected` representing whether `DetectT<ArgsT>`
|
/// a boolean value is stored in `detect::is_detected` representing whether `DetectT<ArgsT...>` is found.
|
||||||
/// \tparam DefaultT Default type
|
/// \tparam DefaultT Default type
|
||||||
/// \tparam DetectT Type to detect
|
/// \tparam DetectT Type to detect
|
||||||
/// \tparam ArgsT Any template arguments for `DetectT<ArgsT>`
|
/// \tparam ArgsT Any template arguments for `DetectT<ArgsT>`
|
||||||
@@ -88,6 +117,12 @@ struct detect
|
|||||||
static constexpr bool is_detected = false;
|
static constexpr bool is_detected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for ```typename detect<DefaultT, DetectT, ArgsT...>::type```
|
||||||
|
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
|
||||||
|
using detect_t = typename detect<DefaultT, DetectT, ArgsT...>::type;
|
||||||
|
|
||||||
|
|
||||||
// true case
|
// true case
|
||||||
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
|
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
|
||||||
requires requires { typename DetectT<ArgsT...>; }
|
requires requires { typename DetectT<ArgsT...>; }
|
||||||
@@ -98,11 +133,32 @@ struct detect<DefaultT, DetectT, ArgsT...>
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::enable_if ===================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Shorthand for ```typename detect<DefaultT, DetectT, ArgsT...>::type```
|
/// \brief Leverage SFINAE to conditionally enable a function or class at compile-time
|
||||||
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
|
///
|
||||||
using detect_t
|
/// \details If `B` is `true`, define a public member type `type`. Otherwise, there is no member. <br>
|
||||||
= typename detect<DefaultT, DetectT, ArgsT...>::type;
|
/// **Example Usage**
|
||||||
|
/// \code{.cpp}
|
||||||
|
/// template<typename TypeT,
|
||||||
|
/// enable_if_t<is_integral_v<TypeT>, bool> = true>
|
||||||
|
/// TypeT conditional_func() { return 0; }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \tparam B A boolean value
|
||||||
|
/// \tparam T The type to conditionally define
|
||||||
|
template<bool B, typename T = void>
|
||||||
|
struct enable_if {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for ```typename enable_if<B, T>::type```
|
||||||
|
template<bool B, typename T = void>
|
||||||
|
using enable_if_t = typename enable_if<B, T>::type;
|
||||||
|
|
||||||
|
// true case
|
||||||
|
template<typename T>
|
||||||
|
struct enable_if<true, T> { using type = T; };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
246
include/fennec/lang/const_sequences.h
Normal file
246
include/fennec/lang/const_sequences.h
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file sequences.h
|
||||||
|
/// \brief \ref fennec_lang_sequences
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_SEQUENCES_H
|
||||||
|
#define FENNEC_LANG_SEQUENCES_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_sequences Sequences
|
||||||
|
///
|
||||||
|
/// \brief This header is part of the metaprogramming library. It defines structures for sequences of values, used during compile time.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/sequences.h> \endcode
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_sequences">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::sequence "sequence<ValueT, Values...>"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::sequence
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::integer_sequence "integer_sequence<IntT, Values...>"<br>
|
||||||
|
/// \ref fennec::make_integer_sequence "typename make_integer_sequence<IntT, N>::type"<br>
|
||||||
|
/// \ref fennec::make_integer_sequence_t "make_integer_sequence_t<IntT, N>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::integer_sequence
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::index_sequence "index_sequence<Indices...>"<br>
|
||||||
|
/// \ref fennec::make_index_sequence "typename make_index_sequence<N>::type"<br>
|
||||||
|
/// \ref fennec::make_index_sequence_t "make_index_sequence_t<N>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::index_sequence
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::concat_sequence "typename concat_sequence<SequenceT0, SequenceT1>::type"<br>
|
||||||
|
/// \ref fennec::concat_sequence_t "concat_sequence_t<SequenceT0, SequenceT1>"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::concat_sequence
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <fennec/lang/type_traits.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// fennec::sequence ====================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief metaprogramming sequence
|
||||||
|
///
|
||||||
|
/// \details Stores a sequence of values of type `ValueT` as a template pack.
|
||||||
|
/// You can access the parameter pack in another template function, i.e.
|
||||||
|
/// \code{cpp}
|
||||||
|
/// template<typename TypeT, TypeT...Values>
|
||||||
|
/// constexpr TypeT summation(sequence<TypeT, Values...>)
|
||||||
|
/// {
|
||||||
|
/// return (Values + ...);
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
/// \tparam ValueT type of the values
|
||||||
|
/// \tparam Values sequence values
|
||||||
|
template<typename ValueT, ValueT...Values> struct const_sequence
|
||||||
|
{
|
||||||
|
/// \brief type of the sequence
|
||||||
|
using value_type = ValueT;
|
||||||
|
|
||||||
|
/// \brief self-referential type
|
||||||
|
using type = const_sequence;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief returns the number of elements
|
||||||
|
///
|
||||||
|
/// \return number of elements in the array
|
||||||
|
inline static constexpr size_t size() noexcept {
|
||||||
|
return sizeof...(Values);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::integer_sequence ============================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief metaprogramming integral sequence
|
||||||
|
///
|
||||||
|
/// \details A `fennec::sequence` specialized integer types.
|
||||||
|
/// \tparam IntT type of the values, must satisfy ```fennec::is_integral<T>```
|
||||||
|
/// \tparam Values sequence values
|
||||||
|
template<typename IntT, IntT...Values> requires(is_integral_v<IntT>)
|
||||||
|
struct const_integer_sequence : const_sequence<IntT, Values...>
|
||||||
|
{
|
||||||
|
/// \brief type of the sequence
|
||||||
|
using value_type = IntT;
|
||||||
|
|
||||||
|
/// \brief self-referential type
|
||||||
|
using type = const_integer_sequence;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief returns the number of elements
|
||||||
|
///
|
||||||
|
/// \return number of elements in the array
|
||||||
|
inline static constexpr size_t size() noexcept {
|
||||||
|
return sizeof...(Values);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief generate a fennec::integer_sequence \f$\left[\,0\,\ldots\,N\,\right)\f$
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \tparam IntT type of the values, must satisfy ```fennec::is_integral<T>```
|
||||||
|
/// \tparam N size of the sequence to generate
|
||||||
|
template<typename IntT, size_t N> struct make_integer_sequence;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```typename make_integer_sequence<T, N>::type```
|
||||||
|
template<typename IntT, size_t N> using make_integer_sequence_t = typename make_integer_sequence<IntT, N>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::index_sequence ==============================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief metaprogramming integral sequence
|
||||||
|
///
|
||||||
|
/// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices.
|
||||||
|
/// \tparam Indices sequence values
|
||||||
|
template<size_t...Indices> struct const_index_sequence : const_integer_sequence<size_t, Indices...>
|
||||||
|
{
|
||||||
|
/// \brief type of the sequence
|
||||||
|
using value_type = size_t;
|
||||||
|
|
||||||
|
/// \brief self-referential type
|
||||||
|
using type = const_index_sequence;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief returns the number of elements
|
||||||
|
///
|
||||||
|
/// \return number of elements in the array
|
||||||
|
inline static constexpr size_t size() noexcept {
|
||||||
|
return sizeof...(Indices);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief generate a fennec::index_sequence \f$\left[\,0\,\ldots\,N\,\right)\f$
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \tparam T type of the values, must satisfy ```fennec::is_integral<T>```
|
||||||
|
/// \tparam N size of the sequence to generate
|
||||||
|
template<size_t N> struct make_index_sequence;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```typename make_index_sequence<N>::type```
|
||||||
|
template<size_t N> using make_index_sequence_t = typename make_index_sequence<N>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::concat_sequence =============================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief concatenate two sequences
|
||||||
|
///
|
||||||
|
/// \details A tool for concatenating two `fennec::sequence` types.
|
||||||
|
/// \tparam SequenceT0 lhs
|
||||||
|
/// \tparam SequenceT1 rhs
|
||||||
|
template<typename SequenceT0, typename SequenceT1> struct concat_sequence;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```typename concat_sequence<SequenceT0, SequenceT1>::type```
|
||||||
|
template<typename SequenceT0, typename SequenceT1> using concat_sequence_t
|
||||||
|
= typename concat_sequence<SequenceT0, SequenceT1>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Internal ============================================================================================================
|
||||||
|
|
||||||
|
// Implementation for Generating an integer_sequence
|
||||||
|
template<typename T, size_t N> struct make_integer_sequence : concat_sequence_t<make_integer_sequence_t<T, N / 2>, make_integer_sequence_t<T, N - N / 2>>{};
|
||||||
|
|
||||||
|
// Base Case of N=0
|
||||||
|
template<typename T> struct make_integer_sequence<T, 0> : const_integer_sequence<T> {};
|
||||||
|
|
||||||
|
// Base Case of N=1
|
||||||
|
template<typename T> struct make_integer_sequence<T, 1> : const_integer_sequence<T, 0>{};
|
||||||
|
|
||||||
|
|
||||||
|
// Implementation for Generating an index_sequence
|
||||||
|
template<size_t N> struct make_index_sequence : concat_sequence_t<make_index_sequence_t<N / 2>, make_index_sequence_t<N - N / 2>>{};
|
||||||
|
|
||||||
|
// Base Case of N=0
|
||||||
|
template<> struct make_index_sequence<0> : const_index_sequence<> {};
|
||||||
|
|
||||||
|
// Base Case of N=1
|
||||||
|
template<> struct make_index_sequence<1> : const_index_sequence<0>{};
|
||||||
|
|
||||||
|
|
||||||
|
// Specialization for integer sequences
|
||||||
|
template<typename T, T...SequenceV0, T...SequenceV1>
|
||||||
|
struct concat_sequence<const_integer_sequence<T, SequenceV0...>, const_integer_sequence<T, SequenceV1...>>
|
||||||
|
: const_integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||||
|
|
||||||
|
// Specialization for index sequences
|
||||||
|
template<size_t...SequenceV0, size_t...SequenceV1>
|
||||||
|
struct concat_sequence<const_index_sequence<SequenceV0...>, const_index_sequence<SequenceV1...>>
|
||||||
|
: const_index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_SEQUENCES_H
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file constants.h
|
/// \file constants.h
|
||||||
/// \brief metaprogramming constants
|
/// \brief \ref fennec_lang_constants
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -33,48 +33,74 @@
|
|||||||
|
|
||||||
#include <fennec/lang/types.h>
|
#include <fennec/lang/types.h>
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_constants Constants
|
||||||
|
///
|
||||||
|
/// \brief This header is part of the metaprogramming library. It defines structures for constant values,
|
||||||
|
/// used during compile time.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/constants.h> \endcode
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_constants">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::integral_constant "integral_constant<IntT, IntT ValueV>::type"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::integral_constant
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bool_constant "bool_constant<bool ValueV>::type"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bool_constant
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::bool_constant "bool_constant<bool ValueV>::type"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::bool_constant
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief metaprogramming integral constant
|
/// \brief metaprogramming integral constant
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details A metaprogramming integral constant
|
||||||
/// \tparam T type of the constant
|
/// \tparam IntT type of the constant
|
||||||
/// \tparam V value of the constant
|
/// \tparam ValueV value of the constant
|
||||||
template<typename T, T V> struct integral_constant
|
template<typename IntT, IntT ValueV> struct integral_constant
|
||||||
{
|
{
|
||||||
///
|
///
|
||||||
/// \brief value of the constant
|
/// \brief value of the constant
|
||||||
inline static constexpr T value = V;
|
inline static constexpr IntT value = ValueV;
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief cast operator to allow for braced initialization
|
/// \brief cast operator to allow for braced initialization
|
||||||
/// \returns the value of the constant
|
/// \returns the value of the constant
|
||||||
constexpr operator T() const noexcept { return V; }
|
constexpr operator IntT() const noexcept { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief metaprogramming boolean constant
|
/// \brief metaprogramming boolean constant
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
/// \tparam V value of the constant
|
/// \tparam ValueV value of the constant
|
||||||
template<bool_t V>
|
template<bool ValueV>
|
||||||
struct bool_constant
|
struct bool_constant
|
||||||
: integral_constant<bool_t, V> {};
|
: integral_constant<bool_t, ValueV> {};
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief metaprogramming true constant
|
/// \brief metaprogramming true constant
|
||||||
struct true_type
|
struct true_type
|
||||||
: bool_constant<true> {};
|
: bool_constant<true> {};
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief metaprogramming false constant
|
/// \brief metaprogramming false constant
|
||||||
struct false_type
|
struct false_type
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
// =====================================================================================================================
|
|
||||||
// fennec, a free and open source game engine
|
|
||||||
// Copyright © 2025 Medusa Slockbower
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
// =====================================================================================================================
|
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_DETAIL_NUMERIC_TRANSFORMS_H
|
|
||||||
#define FENNEC_LANG_DETAIL_NUMERIC_TRANSFORMS_H
|
|
||||||
|
|
||||||
#include <fennec/lang/types.h>
|
|
||||||
#include <fennec/lang/type_transforms.h>
|
|
||||||
|
|
||||||
namespace fennec
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename> struct __make_unsigned : undefined_t {};
|
|
||||||
|
|
||||||
template<> struct __make_unsigned<char_t> : type_transform<uchar_t> {};
|
|
||||||
template<> struct __make_unsigned<uchar_t> : type_transform<uchar_t> {};
|
|
||||||
template<> struct __make_unsigned<schar_t> : type_transform<uchar_t> {};
|
|
||||||
template<> struct __make_unsigned<short_t> : type_transform<ushort_t> {};
|
|
||||||
template<> struct __make_unsigned<ushort_t> : type_transform<ushort_t> {};
|
|
||||||
template<> struct __make_unsigned<uint_t> : type_transform<uint_t> {};
|
|
||||||
template<> struct __make_unsigned<int_t> : type_transform<uint_t> {};
|
|
||||||
template<> struct __make_unsigned<long_t> : type_transform<ulong_t> {};
|
|
||||||
template<> struct __make_unsigned<ulong_t> : type_transform<ulong_t> {};
|
|
||||||
template<> struct __make_unsigned<llong_t> : type_transform<ullong_t> {};
|
|
||||||
template<> struct __make_unsigned<ullong_t> : type_transform<ullong_t> {};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename> struct __make_signed : undefined_t {};
|
|
||||||
|
|
||||||
template<> struct __make_signed<char_t> : type_transform<schar_t> {};
|
|
||||||
template<> struct __make_signed<uchar_t> : type_transform<schar_t> {};
|
|
||||||
template<> struct __make_signed<schar_t> : type_transform<schar_t> {};
|
|
||||||
template<> struct __make_signed<short_t> : type_transform<short_t> {};
|
|
||||||
template<> struct __make_signed<ushort_t> : type_transform<short_t> {};
|
|
||||||
template<> struct __make_signed<uint_t> : type_transform<int_t> {};
|
|
||||||
template<> struct __make_signed<int_t> : type_transform<int_t> {};
|
|
||||||
template<> struct __make_signed<long_t> : type_transform<long_t> {};
|
|
||||||
template<> struct __make_signed<ulong_t> : type_transform<long_t> {};
|
|
||||||
template<> struct __make_signed<llong_t> : type_transform<llong_t> {};
|
|
||||||
template<> struct __make_signed<ullong_t> : type_transform<llong_t> {};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FENNEC_LANG_DETAIL_NUMERIC_TRANSFORMS_H
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
// =====================================================================================================================
|
|
||||||
// fennec, a free and open source game engine
|
|
||||||
// Copyright © 2025 Medusa Slockbower
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
// =====================================================================================================================
|
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_DETAIL_TYPE_TRAITS_H
|
|
||||||
#define FENNEC_LANG_DETAIL_TYPE_TRAITS_H
|
|
||||||
|
|
||||||
#include <fennec/lang/constants.h>
|
|
||||||
#include <fennec/lang/float.h>
|
|
||||||
|
|
||||||
namespace fennec
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
// Nothing interesting to note here
|
|
||||||
template<typename> struct __is_void : false_type {};
|
|
||||||
template<> struct __is_void<void> : true_type {};
|
|
||||||
|
|
||||||
template<typename> struct __is_bool : false_type {};
|
|
||||||
template<> struct __is_bool<bool_t> : true_type {};
|
|
||||||
|
|
||||||
// Provides definitions for all builtin int types
|
|
||||||
template<typename> struct __is_integral : false_type {};
|
|
||||||
template<> struct __is_integral<bool_t> : true_type {};
|
|
||||||
template<> struct __is_integral<char_t> : true_type {};
|
|
||||||
template<> struct __is_integral<char8_t> : true_type {};
|
|
||||||
template<> struct __is_integral<char16_t> : true_type {};
|
|
||||||
template<> struct __is_integral<char32_t> : true_type {};
|
|
||||||
template<> struct __is_integral<schar_t> : true_type {};
|
|
||||||
template<> struct __is_integral<uchar_t> : true_type {};
|
|
||||||
template<> struct __is_integral<wchar_t> : true_type {};
|
|
||||||
template<> struct __is_integral<short_t> : true_type {};
|
|
||||||
template<> struct __is_integral<ushort_t> : true_type {};
|
|
||||||
template<> struct __is_integral<int_t> : true_type {};
|
|
||||||
template<> struct __is_integral<uint_t> : true_type {};
|
|
||||||
template<> struct __is_integral<long_t> : true_type {};
|
|
||||||
template<> struct __is_integral<ulong_t> : true_type {};
|
|
||||||
template<> struct __is_integral<llong_t> : true_type {};
|
|
||||||
template<> struct __is_integral<ullong_t> : true_type {};
|
|
||||||
|
|
||||||
// Most unsigned types will underflow `-1` to the types maximum value
|
|
||||||
template<typename TypeT> struct __is_signed : bool_constant<TypeT(-1) < TypeT(0)> {};
|
|
||||||
template<typename TypeT> struct __is_unsigned : bool_constant<TypeT(-1) >= TypeT(0)> {};
|
|
||||||
|
|
||||||
template<typename> struct __is_floating_point : false_type {};
|
|
||||||
template<> struct __is_floating_point<float_t> : true_type {};
|
|
||||||
template<> struct __is_floating_point<double_t> : true_type {};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FENNEC_LANG_DETAIL_TYPE_TRAITS_H
|
|
||||||
139
include/fennec/lang/detail/_bits.h
Normal file
139
include/fennec/lang/detail/_bits.h
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_BITS_H
|
||||||
|
#define FENNEC_LANG_DETAIL_BITS_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// helper for bitwise and for 1 byte
|
||||||
|
constexpr size_t _bit_and_8(void* dst, const void* src) {
|
||||||
|
*static_cast<uint8_t*>(dst) = *static_cast<uint8_t*>(dst) & *static_cast<const uint8_t*>(src); return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise and 2 bytes at once
|
||||||
|
constexpr size_t _bit_and_16(void* dst, const void* src) {
|
||||||
|
*static_cast<uint16_t*>(dst) = *static_cast<uint16_t*>(dst) & *static_cast<const uint16_t*>(src); return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise and 4 bytes at once
|
||||||
|
constexpr size_t _bit_and_32(void* dst, const void* src) {
|
||||||
|
*static_cast<uint32_t*>(dst) = *static_cast<uint32_t*>(dst) & *static_cast<const uint32_t*>(src); return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise and 8 bytes at once
|
||||||
|
constexpr size_t _bit_and_64(void* dst, const void* src) {
|
||||||
|
*static_cast<uint64_t*>(dst) = *static_cast<uint64_t*>(dst) & *static_cast<const uint64_t*>(src); return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for selecting size
|
||||||
|
constexpr size_t _bit_and(void* dst, const void* src, size_t n) {
|
||||||
|
switch (n) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return _bit_and_8(dst, src);
|
||||||
|
case 2: case 3:
|
||||||
|
return _bit_and_16(dst, src);
|
||||||
|
case 4: case 5: case 6: case 7:
|
||||||
|
return _bit_and_32(dst, src);
|
||||||
|
default:
|
||||||
|
return _bit_and_64(dst, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// helper for bitwise or for 1 byte
|
||||||
|
constexpr size_t _bit_or_8(void* dst, const void* src) {
|
||||||
|
*static_cast<uint8_t*>(dst) = *static_cast<uint8_t*>(dst) | *static_cast<const uint8_t*>(src); return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise or 2 bytes at once
|
||||||
|
constexpr size_t _bit_or_16(void* dst, const void* src) {
|
||||||
|
*static_cast<uint16_t*>(dst) = *static_cast<uint16_t*>(dst) | *static_cast<const uint16_t*>(src); return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise or 4 bytes at once
|
||||||
|
constexpr size_t _bit_or_32(void* dst, const void* src) {
|
||||||
|
*static_cast<uint32_t*>(dst) = *static_cast<uint32_t*>(dst) | *static_cast<const uint32_t*>(src); return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise or 8 bytes at once
|
||||||
|
constexpr size_t _bit_or_64(void* dst, const void* src) {
|
||||||
|
*static_cast<uint64_t*>(dst) = *static_cast<uint64_t*>(dst) | *static_cast<const uint64_t*>(src); return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for selecting size
|
||||||
|
constexpr size_t _bit_or(void* dst, const void* src, size_t n) {
|
||||||
|
switch (n) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return _bit_or_8(dst, src);
|
||||||
|
case 2: case 3:
|
||||||
|
return _bit_or_16(dst, src);
|
||||||
|
case 4: case 5: case 6: case 7:
|
||||||
|
return _bit_or_32(dst, src);
|
||||||
|
default:
|
||||||
|
return _bit_or_64(dst, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// helper for bitwise and 1 byte
|
||||||
|
constexpr size_t _bit_xor_8(void* dst, const void* src) {
|
||||||
|
*static_cast<uint8_t*>(dst) = *static_cast<uint8_t*>(dst) ^ *static_cast<const uint8_t*>(src); return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise xor 2 bytes at once
|
||||||
|
constexpr size_t _bit_xor_16(void* dst, const void* src) {
|
||||||
|
*static_cast<uint16_t*>(dst) = *static_cast<uint16_t*>(dst) ^ *static_cast<const uint16_t*>(src); return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise xor 4 bytes at once
|
||||||
|
constexpr size_t _bit_xor_32(void* dst, const void* src) {
|
||||||
|
*static_cast<uint32_t*>(dst) = *static_cast<uint32_t*>(dst) ^ *static_cast<const uint32_t*>(src); return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for bitwise xor 8 bytes at once
|
||||||
|
constexpr size_t _bit_xor_64(void* dst, const void* src) {
|
||||||
|
*static_cast<uint64_t*>(dst) = *static_cast<uint64_t*>(dst) ^ *static_cast<const uint64_t*>(src); return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for selecting size
|
||||||
|
constexpr size_t _bit_xor(void* dst, const void* src, size_t n) {
|
||||||
|
switch (n) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return _bit_xor_8(dst, src);
|
||||||
|
case 2: case 3:
|
||||||
|
return _bit_xor_16(dst, src);
|
||||||
|
case 4: case 5: case 6: case 7:
|
||||||
|
return _bit_xor_32(dst, src);
|
||||||
|
default:
|
||||||
|
return _bit_xor_64(dst, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_BITS_H
|
||||||
34
include/fennec/lang/detail/_int.h
Normal file
34
include/fennec/lang/detail/_int.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_INT_H
|
||||||
|
#define FENNEC_LANG_DETAIL_INT_H
|
||||||
|
|
||||||
|
#if FENNEC_COMPILER_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4117)
|
||||||
|
|
||||||
|
#define __PTRDIFF_TYPE__ ptrdiff_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Include math since stdint will define its own versions of isinf and isnan
|
||||||
|
#include <math.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_INT_H
|
||||||
59
include/fennec/lang/detail/_numeric_transforms.h
Normal file
59
include/fennec/lang/detail/_numeric_transforms.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_NUMERIC_TRANSFORMS_H
|
||||||
|
#define FENNEC_LANG_DETAIL_NUMERIC_TRANSFORMS_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/type_transforms.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename> struct _make_unsigned : type_identity<undefined_t> {};
|
||||||
|
|
||||||
|
template<> struct _make_unsigned<char_t> : type_identity<uchar_t> {};
|
||||||
|
template<> struct _make_unsigned<uchar_t> : type_identity<uchar_t> {};
|
||||||
|
template<> struct _make_unsigned<schar_t> : type_identity<uchar_t> {};
|
||||||
|
template<> struct _make_unsigned<short_t> : type_identity<ushort_t> {};
|
||||||
|
template<> struct _make_unsigned<ushort_t> : type_identity<ushort_t> {};
|
||||||
|
template<> struct _make_unsigned<uint_t> : type_identity<uint_t> {};
|
||||||
|
template<> struct _make_unsigned<int_t> : type_identity<uint_t> {};
|
||||||
|
template<> struct _make_unsigned<long_t> : type_identity<ulong_t> {};
|
||||||
|
template<> struct _make_unsigned<ulong_t> : type_identity<ulong_t> {};
|
||||||
|
template<> struct _make_unsigned<llong_t> : type_identity<ullong_t> {};
|
||||||
|
template<> struct _make_unsigned<ullong_t> : type_identity<ullong_t> {};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename> struct _make_signed : type_identity<undefined_t> {};
|
||||||
|
|
||||||
|
template<> struct _make_signed<char_t> : type_identity<schar_t> {};
|
||||||
|
template<> struct _make_signed<uchar_t> : type_identity<schar_t> {};
|
||||||
|
template<> struct _make_signed<schar_t> : type_identity<schar_t> {};
|
||||||
|
template<> struct _make_signed<short_t> : type_identity<short_t> {};
|
||||||
|
template<> struct _make_signed<ushort_t> : type_identity<short_t> {};
|
||||||
|
template<> struct _make_signed<uint_t> : type_identity<int_t> {};
|
||||||
|
template<> struct _make_signed<int_t> : type_identity<int_t> {};
|
||||||
|
template<> struct _make_signed<long_t> : type_identity<long_t> {};
|
||||||
|
template<> struct _make_signed<ulong_t> : type_identity<long_t> {};
|
||||||
|
template<> struct _make_signed<llong_t> : type_identity<llong_t> {};
|
||||||
|
template<> struct _make_signed<ullong_t> : type_identity<llong_t> {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_NUMERIC_TRANSFORMS_H
|
||||||
24
include/fennec/lang/detail/_stdlib.h
Normal file
24
include/fennec/lang/detail/_stdlib.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_STDLIB_H
|
||||||
|
#define FENNEC_LANG_DETAIL_STDLIB_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_STDLIB_H
|
||||||
40
include/fennec/lang/detail/_type_sequences.h
Normal file
40
include/fennec/lang/detail/_type_sequences.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
|
||||||
|
#define FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
|
||||||
|
|
||||||
|
#include <fennec/lang/type_transforms.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename FirstT, typename... RestT> struct _first_element : type_identity<FirstT> {};
|
||||||
|
|
||||||
|
template<size_t n, size_t i, typename...TypesT> struct _nth_element;
|
||||||
|
|
||||||
|
template<size_t n, size_t i> struct _nth_element<n, i> : type_identity<void> {};
|
||||||
|
|
||||||
|
template<size_t n, size_t i, typename HeadT, typename...RestT>
|
||||||
|
struct _nth_element<n, i, HeadT, RestT...> : conditional<
|
||||||
|
n == i, HeadT,
|
||||||
|
typename _nth_element<n, i + 1, RestT...>::type
|
||||||
|
> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
|
||||||
75
include/fennec/lang/detail/_type_traits.h
Normal file
75
include/fennec/lang/detail/_type_traits.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_TYPE_TRAITS_H
|
||||||
|
#define FENNEC_LANG_DETAIL_TYPE_TRAITS_H
|
||||||
|
|
||||||
|
#include <fennec/lang/constants.h>
|
||||||
|
#include <fennec/lang/float.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// Nothing interesting to note here
|
||||||
|
template<typename> struct _is_void : false_type {};
|
||||||
|
template<> struct _is_void<void> : true_type {};
|
||||||
|
|
||||||
|
template<typename> struct _is_bool : false_type {};
|
||||||
|
template<> struct _is_bool<bool_t> : true_type {};
|
||||||
|
|
||||||
|
template<typename> struct _is_null_pointer : false_type {};
|
||||||
|
template<> struct _is_null_pointer<nullptr_t> : true_type {};
|
||||||
|
|
||||||
|
// Provides definitions for all builtin int types
|
||||||
|
template<typename> struct _is_integral : false_type {};
|
||||||
|
template<> struct _is_integral<bool_t> : true_type {};
|
||||||
|
template<> struct _is_integral<char_t> : true_type {};
|
||||||
|
template<> struct _is_integral<char8_t> : true_type {};
|
||||||
|
template<> struct _is_integral<char16_t> : true_type {};
|
||||||
|
template<> struct _is_integral<char32_t> : true_type {};
|
||||||
|
template<> struct _is_integral<schar_t> : true_type {};
|
||||||
|
template<> struct _is_integral<uchar_t> : true_type {};
|
||||||
|
template<> struct _is_integral<wchar_t> : true_type {};
|
||||||
|
template<> struct _is_integral<short_t> : true_type {};
|
||||||
|
template<> struct _is_integral<ushort_t> : true_type {};
|
||||||
|
template<> struct _is_integral<int_t> : true_type {};
|
||||||
|
template<> struct _is_integral<uint_t> : true_type {};
|
||||||
|
template<> struct _is_integral<long_t> : true_type {};
|
||||||
|
template<> struct _is_integral<ulong_t> : true_type {};
|
||||||
|
template<> struct _is_integral<llong_t> : true_type {};
|
||||||
|
template<> struct _is_integral<ullong_t> : true_type {};
|
||||||
|
|
||||||
|
// Most unsigned types will underflow `-1` to the types maximum value
|
||||||
|
template<typename TypeT> struct _is_signed : bool_constant<TypeT(-1) < TypeT(0)> {};
|
||||||
|
template<typename TypeT> struct _is_unsigned : bool_constant<TypeT(-1) >= TypeT(0)> {};
|
||||||
|
|
||||||
|
template<typename> struct _is_floating_point : false_type {};
|
||||||
|
template<> struct _is_floating_point<float_t> : true_type {};
|
||||||
|
template<> struct _is_floating_point<double_t> : true_type {};
|
||||||
|
|
||||||
|
template<typename> struct _is_pointer : false_type {};
|
||||||
|
template<typename T> struct _is_pointer<T*> : true_type {};
|
||||||
|
|
||||||
|
template<typename T, typename U = T&&> U _declval(int);
|
||||||
|
template<typename T> T _declval(long);
|
||||||
|
|
||||||
|
template<typename T> struct _declval_protector : bool_constant<false> {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_TYPE_TRAITS_H
|
||||||
50
include/fennec/lang/detail/_type_transforms.h
Normal file
50
include/fennec/lang/detail/_type_transforms.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H
|
||||||
|
#define FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename _Tp, typename = void>
|
||||||
|
struct _add_lvalue_reference {
|
||||||
|
using type = _Tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _Tp>
|
||||||
|
struct _add_lvalue_reference<_Tp, void_t<_Tp&>> {
|
||||||
|
using type = _Tp&;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename _Tp, typename = void>
|
||||||
|
struct _add_rvalue_reference {
|
||||||
|
using type = _Tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _Tp>
|
||||||
|
struct _add_rvalue_reference<_Tp, void_t<_Tp&&>> {
|
||||||
|
using type = _Tp&&;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H
|
||||||
35
include/fennec/lang/detail/_typeuuid.h
Normal file
35
include/fennec/lang/detail/_typeuuid.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_DETAIL_TYPEUUID_H
|
||||||
|
#define FENNEC_LANG_DETAIL_TYPEUUID_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
|
||||||
|
namespace fennec::detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename RootT>
|
||||||
|
FENNEC_NO_INLINE uint64_t _typeuuid() {
|
||||||
|
static uint64_t i = 0;
|
||||||
|
return ++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_DETAIL_TYPEUUID_H
|
||||||
@@ -30,7 +30,33 @@
|
|||||||
#ifndef FENNEC_LANG_FLOAT_H
|
#ifndef FENNEC_LANG_FLOAT_H
|
||||||
#define FENNEC_LANG_FLOAT_H
|
#define FENNEC_LANG_FLOAT_H
|
||||||
|
|
||||||
#include <fennec/memory/bits.h>
|
#include <fennec/lang/bits.h>
|
||||||
|
|
||||||
|
#undef FLT_HAS_INFINITY
|
||||||
|
#undef FLT_HAS_QUIET_NAN
|
||||||
|
#undef FLT_HAS_SIGNALING_NAN
|
||||||
|
#undef FLT_HAS_DENORM
|
||||||
|
#undef FLT_HAS_DENORM_LOSS
|
||||||
|
#undef FLT_ROUNDS
|
||||||
|
#undef FLT_IS_IEC559
|
||||||
|
#undef FLT_MANT_DIG
|
||||||
|
#undef FLT_DIG
|
||||||
|
#undef FLT_DECIMAL_DIG
|
||||||
|
#undef FLT_RADIX
|
||||||
|
#undef FLT_MIN_EXP
|
||||||
|
#undef FLT_MAX_EXP
|
||||||
|
#undef FLT_MIN_10_EXP
|
||||||
|
#undef FLT_MAX_10_EXP
|
||||||
|
#undef FLT_TRAPS
|
||||||
|
#undef FLT_TINYNESS_BEFORE
|
||||||
|
#undef FLT_MIN
|
||||||
|
#undef FLT_MAX
|
||||||
|
#undef FLT_EPSILON
|
||||||
|
#undef FLT_INF
|
||||||
|
#undef FLT_QUIET_NAN
|
||||||
|
#undef FLT_SIGNALING_NAN
|
||||||
|
#undef FLT_DENORM_MIN
|
||||||
|
#undef FLT_ROUND_ERR
|
||||||
|
|
||||||
#define FLT_HAS_INFINITY 1
|
#define FLT_HAS_INFINITY 1
|
||||||
#define FLT_HAS_QUIET_NAN 1
|
#define FLT_HAS_QUIET_NAN 1
|
||||||
@@ -58,6 +84,32 @@
|
|||||||
#define FLT_DENORM_MIN fennec::bit_cast<float>(0x1)
|
#define FLT_DENORM_MIN fennec::bit_cast<float>(0x1)
|
||||||
#define FLT_ROUND_ERR fennec::bit_cast<float>(0x3f000000)
|
#define FLT_ROUND_ERR fennec::bit_cast<float>(0x3f000000)
|
||||||
|
|
||||||
|
#undef DBL_HAS_INFINITY
|
||||||
|
#undef DBL_HAS_QUIET_NAN
|
||||||
|
#undef DBL_HAS_SIGNALING_NAN
|
||||||
|
#undef DBL_HAS_DENORM
|
||||||
|
#undef DBL_HAS_DENORM_LOSS
|
||||||
|
#undef DBL_ROUNDS
|
||||||
|
#undef DBL_IS_IEC559
|
||||||
|
#undef DBL_MANT_DIG
|
||||||
|
#undef DBL_DIG
|
||||||
|
#undef DBL_DECIMAL_DIG
|
||||||
|
#undef DBL_RADIX
|
||||||
|
#undef DBL_MIN_EXP
|
||||||
|
#undef DBL_MAX_EXP
|
||||||
|
#undef DBL_MIN_10_EXP
|
||||||
|
#undef DBL_MAX_10_EXP
|
||||||
|
#undef DBL_TRAPS
|
||||||
|
#undef DBL_TINYNESS_BEFORE
|
||||||
|
#undef DBL_MIN
|
||||||
|
#undef DBL_MAX
|
||||||
|
#undef DBL_EPSILON
|
||||||
|
#undef DBL_INF
|
||||||
|
#undef DBL_QUIET_NAN
|
||||||
|
#undef DBL_SIGNALING_NAN
|
||||||
|
#undef DBL_DENORM_MIN
|
||||||
|
#undef DBL_ROUND_ERR
|
||||||
|
|
||||||
#define DBL_HAS_INFINITY 1
|
#define DBL_HAS_INFINITY 1
|
||||||
#define DBL_HAS_QUIET_NAN 1
|
#define DBL_HAS_QUIET_NAN 1
|
||||||
#define DBL_HAS_SIGNALING_NAN 1
|
#define DBL_HAS_SIGNALING_NAN 1
|
||||||
@@ -75,13 +127,13 @@
|
|||||||
#define DBL_MAX_10_EXP 308
|
#define DBL_MAX_10_EXP 308
|
||||||
#define DBL_TRAPS 0
|
#define DBL_TRAPS 0
|
||||||
#define DBL_TINYNESS_BEFORE 0
|
#define DBL_TINYNESS_BEFORE 0
|
||||||
#define DBL_MIN fennec::bit_cast<double>(0x10000000000000l)
|
#define DBL_MIN fennec::bit_cast<double>(0x10000000000000ll)
|
||||||
#define DBL_MAX fennec::bit_cast<double>(0x7fefffffffffffffl)
|
#define DBL_MAX fennec::bit_cast<double>(0x7fefffffffffffffll)
|
||||||
#define DBL_EPSILON fennec::bit_cast<double>(0x3cb0000000000000l)
|
#define DBL_EPSILON fennec::bit_cast<double>(0x3cb0000000000000ll)
|
||||||
#define DBL_INF fennec::bit_cast<double>(0x7ff0000000000000l)
|
#define DBL_INF fennec::bit_cast<double>(0x7ff0000000000000ll)
|
||||||
#define DBL_QUIET_NAN fennec::bit_cast<double>(0x7ff8000000000000l)
|
#define DBL_QUIET_NAN fennec::bit_cast<double>(0x7ff8000000000000ll)
|
||||||
#define DBL_SIGNALING_NAN fennec::bit_cast<double>(0x7ff4000000000000l)
|
#define DBL_SIGNALING_NAN fennec::bit_cast<double>(0x7ff4000000000000ll)
|
||||||
#define DBL_DENORM_MIN fennec::bit_cast<double>(0x1l)
|
#define DBL_DENORM_MIN fennec::bit_cast<double>(0x1ll)
|
||||||
#define DBL_ROUND_ERR fennec::bit_cast<double>(0x3fe0000000000000l)
|
#define DBL_ROUND_ERR fennec::bit_cast<double>(0x3fe0000000000000ll)
|
||||||
|
|
||||||
#endif // FENNEC_LANG_FLOAT_H
|
#endif // FENNEC_LANG_FLOAT_H
|
||||||
|
|||||||
91
include/fennec/lang/hashing.h
Normal file
91
include/fennec/lang/hashing.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_HASHING_H
|
||||||
|
#define FENNEC_LANG_HASHING_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/type_traits.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Struct for hashing types, there is no default hashing function
|
||||||
|
/// \tparam Key The type to hash
|
||||||
|
template<typename Key> struct hash;
|
||||||
|
|
||||||
|
// Murmur3 Hash for 64-bit ints
|
||||||
|
template<>
|
||||||
|
struct hash<uint64_t> {
|
||||||
|
using type_t = uint64_t;
|
||||||
|
constexpr size_t operator()(uint64_t x) const {
|
||||||
|
// Murmur3
|
||||||
|
x ^= x >> 33U;
|
||||||
|
x *= 0xff51afd7ed558ccd;
|
||||||
|
x ^= x >> 33U;
|
||||||
|
x *= 0xc4ceb9fe1a85ec53;
|
||||||
|
x ^= x >> 33U;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrapper for casting ints
|
||||||
|
template<typename IntT>
|
||||||
|
requires is_integral_v<IntT>
|
||||||
|
struct hash<IntT> : hash<uint64_t> {
|
||||||
|
using type_t = IntT;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrapper for pointers
|
||||||
|
template<typename PtrT>
|
||||||
|
struct hash<PtrT*> : hash<uintptr_t> {
|
||||||
|
constexpr size_t operator()(PtrT* ptr) const {
|
||||||
|
return hash<uintptr_t>::operator()((uintptr_t)(const void*)ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Float
|
||||||
|
template<>
|
||||||
|
struct hash<float> : hash<uint32_t> {
|
||||||
|
constexpr size_t operator()(float x) const {
|
||||||
|
return hash<uint32_t>::operator()(bit_cast<uint32_t>(x));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<double> : hash<uint64_t> {
|
||||||
|
constexpr size_t operator()(double x) const {
|
||||||
|
return hash<uint64_t>::operator()(bit_cast<uint64_t>(x));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pairs two hashes
|
||||||
|
/// \param x first hash
|
||||||
|
/// \param y second hash
|
||||||
|
/// \returns a pairing of the two hashes
|
||||||
|
constexpr size_t pair_hash(size_t x, size_t y) {
|
||||||
|
// Szudzik Pairing
|
||||||
|
return (x >= y ? (x * x) + x + y : (y * y) + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_HASHING_H
|
||||||
164
include/fennec/lang/integer.h
Normal file
164
include/fennec/lang/integer.h
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file integer.h
|
||||||
|
/// \brief metaprogramming integer type info
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details this file is automatically generated for the current build environment
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_INTEGER_H
|
||||||
|
#define FENNEC_LANG_INTEGER_H
|
||||||
|
|
||||||
|
#undef CHAR_MIN
|
||||||
|
#undef CHAR_MAX
|
||||||
|
#undef WCHAR_MIN
|
||||||
|
#undef WCHAR_MAX
|
||||||
|
#undef SCHAR_MIN
|
||||||
|
#undef SCHAR_MAX
|
||||||
|
#undef UCHAR_MIN
|
||||||
|
#undef UCHAR_MAX
|
||||||
|
#undef INT_MIN
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MIN
|
||||||
|
#undef UINT_MAX
|
||||||
|
#undef LONG_MIN
|
||||||
|
#undef LONG_MAX
|
||||||
|
#undef ULONG_MIN
|
||||||
|
#undef ULONG_MAX
|
||||||
|
#undef LLONG_MIN
|
||||||
|
#undef LLONG_MAX
|
||||||
|
#undef ULLONG_MIN
|
||||||
|
#undef ULLONG_MAX
|
||||||
|
|
||||||
|
#define CHAR_IS_SIGNED true
|
||||||
|
#define CHAR_ROUNDS 0x0
|
||||||
|
#define CHAR_RADIX_DIG 0x7
|
||||||
|
#define CHAR_DIG 0x2
|
||||||
|
#define CHAR_DECIMAL_DIG 0x0
|
||||||
|
#define CHAR_RADIX 0x2
|
||||||
|
#define CHAR_TRAPS 0xtrue
|
||||||
|
#define CHAR_MIN 0x80
|
||||||
|
#define CHAR_MAX 0x7f
|
||||||
|
|
||||||
|
#define WCHAR_IS_SIGNED true
|
||||||
|
#define WCHAR_ROUNDS 0x0
|
||||||
|
#define WCHAR_RADIX_DIG 0x1f
|
||||||
|
#define WCHAR_DIG 0x9
|
||||||
|
#define WCHAR_DECIMAL_DIG 0x0
|
||||||
|
#define WCHAR_RADIX 0x2
|
||||||
|
#define WCHAR_TRAPS 0xtrue
|
||||||
|
#define WCHAR_MIN 0x80000000
|
||||||
|
#define WCHAR_MAX 0x7fffffff
|
||||||
|
|
||||||
|
#define SCHAR_ROUNDS 0x0
|
||||||
|
#define SCHAR_RADIX_DIG 0x7
|
||||||
|
#define SCHAR_DIG 0x2
|
||||||
|
#define SCHAR_DECIMAL_DIG 0x0
|
||||||
|
#define SCHAR_RADIX 0x2
|
||||||
|
#define SCHAR_TRAPS 0xtrue
|
||||||
|
#define SCHAR_MIN 0x80
|
||||||
|
#define SCHAR_MAX 0x7f
|
||||||
|
|
||||||
|
#define UCHAR_ROUNDS 0x0
|
||||||
|
#define UCHAR_RADIX_DIG 0x8
|
||||||
|
#define UCHAR_DIG 0x2
|
||||||
|
#define UCHAR_DECIMAL_DIG 0x0
|
||||||
|
#define UCHAR_RADIX 0x2
|
||||||
|
#define UCHAR_TRAPS 0xtrue
|
||||||
|
#define UCHAR_MIN 0x0
|
||||||
|
#define UCHAR_MAX 0xff
|
||||||
|
|
||||||
|
#define SHORT_ROUNDS 0x0
|
||||||
|
#define SHORT_RADIX_DIG 0xf
|
||||||
|
#define SHORT_DIG 0x4
|
||||||
|
#define SHORT_DECIMAL_DIG 0x0
|
||||||
|
#define SHORT_RADIX 0x2
|
||||||
|
#define SHORT_TRAPS 0xtrue
|
||||||
|
#define SHORT_MIN 0x8000
|
||||||
|
#define SHORT_MAX 0x7fff
|
||||||
|
|
||||||
|
#define USHORT_ROUNDS 0x0
|
||||||
|
#define USHORT_RADIX_DIG 0x10
|
||||||
|
#define USHORT_DIG 0x4
|
||||||
|
#define USHORT_DECIMAL_DIG 0x0
|
||||||
|
#define USHORT_RADIX 0x2
|
||||||
|
#define USHORT_TRAPS 0xtrue
|
||||||
|
#define USHORT_MIN 0x0
|
||||||
|
#define USHORT_MAX 0xffff
|
||||||
|
|
||||||
|
#define INT_ROUNDS 0x0
|
||||||
|
#define INT_RADIX_DIG 0x1f
|
||||||
|
#define INT_DIG 0x9
|
||||||
|
#define INT_DECIMAL_DIG 0x0
|
||||||
|
#define INT_RADIX 0x2
|
||||||
|
#define INT_TRAPS 0xtrue
|
||||||
|
#define INT_MIN 0x80000000
|
||||||
|
#define INT_MAX 0x7fffffff
|
||||||
|
|
||||||
|
#define UINT_ROUNDS 0x0
|
||||||
|
#define UINT_RADIX_DIG 0x20
|
||||||
|
#define UINT_DIG 0x9
|
||||||
|
#define UINT_DECIMAL_DIG 0x0
|
||||||
|
#define UINT_RADIX 0x2
|
||||||
|
#define UINT_TRAPS 0xtrue
|
||||||
|
#define UINT_MIN 0x0
|
||||||
|
#define UINT_MAX 0xffffffff
|
||||||
|
|
||||||
|
#define LONG_ROUNDS 0x0
|
||||||
|
#define LONG_RADIX_DIG 0x3f
|
||||||
|
#define LONG_DIG 0x12
|
||||||
|
#define LONG_DECIMAL_DIG 0x0
|
||||||
|
#define LONG_RADIX 0x2
|
||||||
|
#define LONG_TRAPS 0xtrue
|
||||||
|
#define LONG_MIN 0x8000000000000000
|
||||||
|
#define LONG_MAX 0x7fffffffffffffff
|
||||||
|
|
||||||
|
#define ULONG_ROUNDS 0x0
|
||||||
|
#define ULONG_RADIX_DIG 0x40
|
||||||
|
#define ULONG_DIG 0x13
|
||||||
|
#define ULONG_DECIMAL_DIG 0x0
|
||||||
|
#define ULONG_RADIX 0x2
|
||||||
|
#define ULONG_TRAPS 0xtrue
|
||||||
|
#define ULONG_MIN 0x0
|
||||||
|
#define ULONG_MAX 0xffffffffffffffff
|
||||||
|
|
||||||
|
#define LLONG_ROUNDS 0x0
|
||||||
|
#define LLONG_RADIX_DIG 0x3f
|
||||||
|
#define LLONG_DIG 0x12
|
||||||
|
#define LLONG_DECIMAL_DIG 0x0
|
||||||
|
#define LLONG_RADIX 0x2
|
||||||
|
#define LLONG_TRAPS 0xtrue
|
||||||
|
#define LLONG_MIN 0x8000000000000000
|
||||||
|
#define LLONG_MAX 0x7fffffffffffffff
|
||||||
|
|
||||||
|
#define ULLONG_ROUNDS 0x0
|
||||||
|
#define ULLONG_RADIX_DIG 0x40
|
||||||
|
#define ULLONG_DIG 0x13
|
||||||
|
#define ULLONG_DECIMAL_DIG 0x0
|
||||||
|
#define ULLONG_RADIX 0x2
|
||||||
|
#define ULLONG_TRAPS 0xtrue
|
||||||
|
#define ULLONG_MIN 0x0
|
||||||
|
#define ULLONG_MAX 0xffffffffffffffff
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_INTEGER_H
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,22 +16,92 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file intrinsics.h
|
||||||
|
/// \brief \ref fennec_lang_intrinsics
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_INTRINSICS_H
|
#ifndef FENNEC_LANG_INTRINSICS_H
|
||||||
#define FENNEC_LANG_INTRINSICS_H
|
#define FENNEC_LANG_INTRINSICS_H
|
||||||
|
|
||||||
// Most major compilers support __has_builtin, notably GCC, MINGW, CLANG, and MSVC
|
///
|
||||||
|
/// \page fennec_lang_intrinsics Intrinsics
|
||||||
|
///
|
||||||
|
/// \brief This header contains definitions for compiler intrinsics necessary for implementing functions of the
|
||||||
|
/// C++ stdlib.
|
||||||
|
///
|
||||||
|
/// \code{.cpp}#include <fennec/lang/intrinsics.h>\endcode
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_intrinsics">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_BIT_CAST` <br>
|
||||||
|
/// `Y FENNEC_BUILTIN_BIT_CAST(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// An intrinsic for doing a bitwise cast without using `reinterpret_cast`.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_ADDRESSOF` <br>
|
||||||
|
/// `Y FENNEC_BUILTIN_ADDRESSOF(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Obtains the true address of an object in circumstances where `operator&` is overloaded.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_CONVERTIBLE` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Checks if type `X` can be converted to type `Y`.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_EMPTY` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_EMPTY(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Checks if type `X` stores no data.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_POLYMORPHIC` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_POLYMORPHIC(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Checks if type `X` is polymorphic, this is for classes only thus checks only for subtyping
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_FINAL` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_FINAL(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Checks if type `X` is final, meaning a function or class cannot be derived from.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_ABSTRACT` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_ABSTRACT(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Opposite of `FENNEC_BUILTIN_IS_FINAL`, checks if abstract, meaning `X` has at least one pure virtual function.
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Checks if `X` has a standard layout, here is [full criteria](https://www.cppreference.com/w/cpp/language/classes.html#Standard-layout_class)
|
||||||
|
/// for this trait
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// `FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE` <br>
|
||||||
|
/// `B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)`
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// Checks if type `X` is constructible with args `...`, such that `X::X(...)` exists.
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
|
// Most major compilers support __has_builtin, notably GCC, MINGW, and CLANG
|
||||||
#if defined(__has_builtin)
|
#if defined(__has_builtin)
|
||||||
|
|
||||||
|
|
||||||
// bitcast is slightly more efficient for build times than using memcpy
|
|
||||||
#if __has_builtin(__builtin_bit_cast)
|
|
||||||
# define FENNEC_HAS_BUILTIN_BIT_CAST 1
|
|
||||||
# define FENNEC_BUILTIN_BIT_CAST(type, arg) __builtin_bit_cast(type, arg)
|
|
||||||
#else
|
|
||||||
# define FENNEC_HAS_BUILTIN_BIT_CAST 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// addressof is very difficult to implement without intrinsics.
|
// addressof is very difficult to implement without intrinsics.
|
||||||
#if __has_builtin(__builtin_addressof)
|
#if __has_builtin(__builtin_addressof)
|
||||||
# define FENNEC_HAS_BUILTIN_ADDRESSOF 1
|
# define FENNEC_HAS_BUILTIN_ADDRESSOF 1
|
||||||
@@ -40,39 +110,12 @@
|
|||||||
# define FENNEC_HAS_BUILTIN_ADDRESSOF 0
|
# define FENNEC_HAS_BUILTIN_ADDRESSOF 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// bitcast is slightly more efficient for build times than using memcpy
|
||||||
// Type Traits
|
#if __has_builtin(__builtin_bit_cast)
|
||||||
|
# define FENNEC_HAS_BUILTIN_BIT_CAST 1
|
||||||
// can_convert is also very difficult to implement without intrinsics
|
# define FENNEC_BUILTIN_BIT_CAST(type, arg) __builtin_bit_cast(type, arg)
|
||||||
#if __has_builtin(__is_convertible)
|
|
||||||
# define FENNEC_HAS_BUILTIN_CAN_CONVERT 1
|
|
||||||
# define FENNEC_BUILTIN_CAN_CONVERT(arg0, arg1) __is_convertible(arg0, arg1)
|
|
||||||
#else
|
#else
|
||||||
# define FENNEC_HAS_BUILTIN_CAN_CONVERT 0
|
# define FENNEC_HAS_BUILTIN_BIT_CAST 0
|
||||||
#endif
|
|
||||||
|
|
||||||
// Inconsistent without intrinsics.
|
|
||||||
#if __has_builtin(__is_empty)
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_EMPTY 1
|
|
||||||
# define FENNEC_BUILTIN_IS_EMPTY(arg) __is_empty(arg)
|
|
||||||
#else
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_EMPTY 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Inconsistent without intrinsics
|
|
||||||
#if __has_builtin(__is_polymorphic)
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 1
|
|
||||||
# define FENNEC_BUILTIN_IS_POLYMORPHIC(arg) __is_polymorphic(arg)
|
|
||||||
#else
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Inconsistent without intrinsics
|
|
||||||
#if __has_builtin(__is_final)
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
|
||||||
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
|
||||||
#else
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_FINAL 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Inconsistent without intrinsics
|
// Inconsistent without intrinsics
|
||||||
@@ -83,6 +126,117 @@
|
|||||||
# define FENNEC_HAS_BUILTIN_IS_ABSTRACT 0
|
# define FENNEC_HAS_BUILTIN_IS_ABSTRACT 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_array)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_ARRAY 1
|
||||||
|
# define FENNEC_BUILTIN_IS_ARRAY(arg) __is_array(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_ARRAY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_class)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CLASS 1
|
||||||
|
# define FENNEC_BUILTIN_IS_CLASS(arg) __is_class(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CLASS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CONSTRUCTORS ========================================================================================================
|
||||||
|
|
||||||
|
// Difficult and Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_constructible)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(type, ...) __is_constructible(type __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Difficult and Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_trivially_constructible)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(type) __is_trivially_constructible(type)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Difficult and Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__has_trivial_destructor)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __has_trivial_destructor(type)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ASSIGNMENTS =========================================================================================================
|
||||||
|
|
||||||
|
// Difficult and Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_assignable)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_ASSIGNABLE(a, b) __is_assignable(a, b)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Type Traits
|
||||||
|
// can_convert is also very difficult to implement without intrinsics
|
||||||
|
#if __has_builtin(__is_convertible)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CONVERTIBLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_CONVERTIBLE(arg0, arg1) __is_convertible(arg0, arg1)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CONVERTIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics.
|
||||||
|
#if __has_builtin(__is_empty)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_EMPTY 1
|
||||||
|
# define FENNEC_BUILTIN_IS_EMPTY(arg) __is_empty(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_EMPTY 0
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_final)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
||||||
|
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics.
|
||||||
|
#if __has_builtin(__is_enum)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_ENUM 1
|
||||||
|
# define FENNEC_BUILTIN_IS_ENUM(arg) __is_enum(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_ENUM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_final)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
||||||
|
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent with dynamic intrinsics, requires a massive table for static intrinsics
|
||||||
|
#if __has_builtin(__is_fundamental)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 1
|
||||||
|
# define FENNEC_BUILTIN_IS_FUNDAMENTAL(arg) __is_fundamental(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Inconsistent without intrinsics
|
||||||
|
#if __has_builtin(__is_polymorphic)
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 1
|
||||||
|
# define FENNEC_BUILTIN_IS_POLYMORPHIC(arg) __is_polymorphic(arg)
|
||||||
|
#else
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
// Impossible without instrinsics
|
// Impossible without instrinsics
|
||||||
#if __has_builtin(__is_standard_layout)
|
#if __has_builtin(__is_standard_layout)
|
||||||
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
|
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
|
||||||
@@ -91,20 +245,40 @@
|
|||||||
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 0
|
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Difficult and Inconsistent without intrinsics
|
|
||||||
#if __has_builtin(__is_constructible)
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
|
||||||
# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(type, ...) __is_constructible(type, __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// For compilers without or differently named builtins
|
// For compilers without or differently named builtins
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// TODO: More compiler support
|
// TODO: More compiler support
|
||||||
|
|
||||||
|
#if FENNEC_COMPILER_MSVC
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_ADDRESS_OF 1
|
||||||
|
# define FENNEC_BUILTIN_ADDRESS_OF(arg) __builtin_addressof(arg)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_BIT_CAST 1
|
||||||
|
# define FENNEC_BUILTIN_BIT_CAST(type, arg) __builtin_bit_cast(type, arg)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CONVERTIBLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_CONVERTIBLE(arg0, arg1) __is_convertible_to(arg0, arg1)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
||||||
|
# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_EMPTY 1
|
||||||
|
# define FENNEC_BUILTIN_IS_EMPTY(arg) __is_empty(arg)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
||||||
|
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 1
|
||||||
|
# define FENNEC_BUILTIN_IS_POLYMORPHIC(arg) __is_polymorphic(arg)
|
||||||
|
|
||||||
|
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
|
||||||
|
# define FENNEC_BUILTIN_IS_STANDARD_LAYOUT(arg) __is_standard_layout(arg)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // FENNEC_LANG_INTRINSICS_H
|
#endif // FENNEC_LANG_INTRINSICS_H
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file lang.h
|
/// \file lang.h
|
||||||
/// \brief fennec C++ language library
|
/// \brief \ref fennec_lang
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -31,11 +31,24 @@
|
|||||||
#ifndef FENNEC_LANG_H
|
#ifndef FENNEC_LANG_H
|
||||||
#define FENNEC_LANG_H
|
#define FENNEC_LANG_H
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
#include <fennec/lang/bits.h>
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/utility.h>
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \page page_fennec_lang C++ Language Library
|
/// \page fennec_lang C++ Language Library
|
||||||
///
|
///
|
||||||
/// This library implements the parts of the C++ stdlib that relate to built-in types and metaprogramming.
|
/// This library implements the parts of the C++ stdlib that relate to built-in types and metaprogramming.
|
||||||
///
|
///
|
||||||
|
/// - \subpage fennec_lang_assert
|
||||||
|
/// - \subpage fennec_lang_bit_manipulation
|
||||||
|
/// - \subpage fennec_lang_intrinsics
|
||||||
|
/// - \subpage fennec_lang_limits
|
||||||
|
/// - \subpage fennec_lang_metaprogramming
|
||||||
|
/// - \subpage fennec_lang_types
|
||||||
|
/// - \subpage fennec_lang_utility
|
||||||
|
///
|
||||||
///
|
///
|
||||||
|
|
||||||
#endif // FENNEC_LANG_H
|
#endif // FENNEC_LANG_H
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,14 +16,192 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file limits.h
|
||||||
|
/// \brief \ref fennec_lang_limits
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_LIMITS_H
|
#ifndef FENNEC_LANG_LIMITS_H
|
||||||
#define FENNEC_LANG_LIMITS_H
|
#define FENNEC_LANG_LIMITS_H
|
||||||
|
|
||||||
#include <cmath>
|
///
|
||||||
|
/// \page fennec_lang_limits Limits
|
||||||
|
///
|
||||||
|
/// \brief This header defines fennec::numeric_limits which contains info regarding the limits of numeric types including
|
||||||
|
/// floats and integers. There are overloads for all builtin types, and overloads for other types are included in
|
||||||
|
/// their own header.
|
||||||
|
///
|
||||||
|
/// \code{.cpp}#include <fennec/lang/limits.h>\endcode
|
||||||
|
///
|
||||||
|
/// \section fennec_lang_limits_numeric_limits Numeric Limits
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_limits">
|
||||||
|
/// <tr><th style="vertical-align: top">Member
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><th colspan=2 style="text-align: center;">Traits
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_specialized "is_specialized"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_specialized
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_signed "is_signed"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_signed
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_integer "is_integer"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_integer
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_exact "is_exact"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_exact
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::has_infinity "has_infinity"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::has_infinity
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::has_quiet_nan "has_quiet_nan"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::has_quiet_nan
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::has_signaling_nan "has_signaling_nan"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::has_signaling_nan
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_iec559 "is_iec559"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_iec559
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_bounded "is_bounded"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_bounded
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::is_modulo "is_modulo"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::is_modulo
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::tinyness_before "tinyness_before"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::tinyness_before
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::traps "traps"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::traps
|
||||||
|
///
|
||||||
|
/// <tr><th colspan=2 style="text-align: center;">Binary
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::radix "radix"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::radix
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::digits "digits"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::digits
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::digits10 "digits10"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::digits10
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::max_digits10 "max_digits10"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::max_digits10
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::min_exponent "min_exponent"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::min_exponent
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::min_exponent10 "min_exponent10"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::min_exponent10
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::max_exponent "max_exponent"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::max_exponent
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::max_exponent10 "max_exponent10"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::max_exponent10
|
||||||
|
///
|
||||||
|
/// <tr><th colspan=2 style="text-align: center;">Limits
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::min "min()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::min
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::max "max()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::max
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::lowest "lowest()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::lowest
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::epsilon "epsilon()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::epsilon
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::round_error "round_error()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::round_error
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::infinity "infinity()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::infinity
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::quiet_NaN "quiet_NaN()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::quiet_NaN
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::signaling_NaN "signaling_NaN()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::signaling_NaN
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::numeric_limits::denorm_min "denorm_min()"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::numeric_limits::denorm_min
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#include <fennec/lang/types.h>
|
#include <fennec/lang/types.h>
|
||||||
#include <fennec/lang/type_traits.h>
|
#include <fennec/lang/type_traits.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/integer.h>
|
||||||
|
#include <fennec/lang/float.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -44,43 +222,46 @@ enum float_round_style
|
|||||||
/// \tparam TypeT Numeric types, may be overloaded for custom types
|
/// \tparam TypeT Numeric types, may be overloaded for custom types
|
||||||
template<typename TypeT> struct numeric_limits
|
template<typename TypeT> struct numeric_limits
|
||||||
{
|
{
|
||||||
static constexpr bool is_specialized = false;
|
static constexpr bool is_specialized = false; ///< Check if the template is specialized for TypeT
|
||||||
static constexpr bool is_signed = false;
|
static constexpr bool is_signed = false; ///< Check if TypeT is signed
|
||||||
static constexpr bool is_integer = false;
|
static constexpr bool is_integer = false; ///< Check if TypeT is of an integral type
|
||||||
static constexpr bool is_exact = false;
|
static constexpr bool is_exact = false; ///< Check if TypeT is exact in its precision
|
||||||
static constexpr bool has_infinity = false;
|
static constexpr bool has_infinity = false; ///< Check if TypeT can hold a value representing infinity
|
||||||
static constexpr bool has_quiet_nan = false;
|
static constexpr bool has_quiet_nan = false; ///< Check if TypeT can hold a non-signaling nan
|
||||||
static constexpr bool has_signaling_nan = false;
|
static constexpr bool has_signaling_nan = false; ///< Check if TypeT can hold a signaling nan
|
||||||
static constexpr bool has_denorm = false;
|
static constexpr bool has_denorm = false; ///< Check if TypeT denormalizes
|
||||||
static constexpr bool has_denorm_loss = false;
|
static constexpr bool has_denorm_loss = false; ///< Check if TypeT has precision loss when denormalized
|
||||||
static constexpr bool is_iec559 = false;
|
static constexpr bool is_iec559 = false; ///< Check if a TypeT representing a float is IEC 559 or IEEE 754
|
||||||
static constexpr bool is_bounded = false;
|
static constexpr bool is_bounded = false; ///< Check if TypeT represents a finite set of values
|
||||||
static constexpr bool is_modulo = false;
|
static constexpr bool is_modulo = false; ///< Check if TypeT can handle modulo arithmetic
|
||||||
static constexpr bool tinyness_before = false;
|
static constexpr bool tinyness_before = false; ///< Check if TypeT checks for tinyness before rounding
|
||||||
static constexpr bool traps = false;
|
static constexpr bool traps = false; ///< Check if TypeT can cause operations to trap
|
||||||
|
|
||||||
static constexpr int digits = 0;
|
static constexpr int radix = 0; ///< Get the base representation of the type
|
||||||
static constexpr int digits10 = 0;
|
static constexpr int digits = 0; ///< Get the number of radix digits TypeT represents
|
||||||
static constexpr int max_digits10 = 0;
|
static constexpr int digits10 = 0; ///< Get the number of decimal digits TypeT represents
|
||||||
static constexpr int radix = 0;
|
static constexpr int max_digits10 = 0; ///< Get the maximum number of decimal digits TypeT represents
|
||||||
static constexpr int min_exponent = 0;
|
static constexpr int min_exponent = 0; ///< Get the minimum number of radix digits that represent the exponent of TypeT
|
||||||
static constexpr int min_exponent10 = 0;
|
static constexpr int min_exponent10 = 0; ///< Get the minimum number of decimal digits that represent the exponent of TypeT
|
||||||
static constexpr int max_exponent = 0;
|
static constexpr int max_exponent = 0; ///< Get the maximum number of radix digits that represent the exponent of TypeT
|
||||||
static constexpr int max_exponent10 = 0;
|
static constexpr int max_exponent10 = 0; ///< Get the maximum number of decimal digits that represent the exponent of TypeT
|
||||||
|
|
||||||
static constexpr float_round_style rounding_style = round_indeterminate;
|
static constexpr float_round_style rounding_style = round_indeterminate; ///< The rounding style of TypeT
|
||||||
|
|
||||||
static constexpr TypeT min() { return TypeT(); }
|
// This is very poorly named and defined in the C++ Standard so these functions differ
|
||||||
static constexpr TypeT max() { return TypeT(); }
|
static constexpr TypeT min() { return TypeT(); } ///< Returns the minimum finite value of TypeT
|
||||||
static constexpr TypeT lowest() { return TypeT(); }
|
static constexpr TypeT max() { return TypeT(); } ///< Returns the maximum finite value of TypeT
|
||||||
static constexpr TypeT epsilon() { return TypeT(); }
|
static constexpr TypeT lowest() { return TypeT(); } ///< Returns the smallest positive value of TypeT
|
||||||
static constexpr TypeT round_error() { return TypeT(); }
|
static constexpr TypeT epsilon() { return TypeT(); } ///< Returns the difference between 1.0 and the next representable value
|
||||||
static constexpr TypeT infinity() { return TypeT(); }
|
static constexpr TypeT round_error() { return TypeT(); } ///< Returns the max rounding error of TypeT
|
||||||
static constexpr TypeT quiet_NaN() { return TypeT(); }
|
static constexpr TypeT infinity() { return TypeT(); } ///< Returns a value of TypeT holding a positive infinity
|
||||||
static constexpr TypeT signaling_NaN() { return TypeT(); }
|
static constexpr TypeT quiet_NaN() { return TypeT(); } ///< Returns a value of TypeT holding a quiet NaN
|
||||||
static constexpr TypeT denorm_min() { return TypeT(); }
|
static constexpr TypeT signaling_NaN() { return TypeT(); } ///< Returns a value of TypeT holding a signaling NaN
|
||||||
|
static constexpr TypeT denorm_min() { return TypeT(); } ///< Returns a value of TypeT holding the smallest positive subnormal
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Overload definitions for basic types
|
||||||
|
|
||||||
// Overload for the builtin floating point type
|
// Overload for the builtin floating point type
|
||||||
template<> struct numeric_limits<float>
|
template<> struct numeric_limits<float>
|
||||||
{
|
{
|
||||||
@@ -108,15 +289,15 @@ template<> struct numeric_limits<float>
|
|||||||
static constexpr int max_exponent = FLT_MAX_EXP;
|
static constexpr int max_exponent = FLT_MAX_EXP;
|
||||||
static constexpr int max_exponent10 = FLT_MAX_10_EXP;
|
static constexpr int max_exponent10 = FLT_MAX_10_EXP;
|
||||||
|
|
||||||
static constexpr double min() { return FLT_MIN; }
|
static constexpr float min() { return -FLT_MAX; }
|
||||||
static constexpr double max() { return FLT_MAX; }
|
static constexpr float max() { return FLT_MAX; }
|
||||||
static constexpr double lowest() { return -FLT_MAX; }
|
static constexpr float lowest() { return FLT_MIN; }
|
||||||
static constexpr double epsilon() { return FLT_EPSILON; }
|
static constexpr float epsilon() { return FLT_EPSILON; }
|
||||||
static constexpr double round_error() { return FLT_ROUND_ERR; }
|
static constexpr float round_error() { return FLT_ROUND_ERR; }
|
||||||
static constexpr double infinity() { return FLT_INF; }
|
static constexpr float infinity() { return FLT_INF; }
|
||||||
static constexpr double quiet_NaN() { return FLT_QUIET_NAN; }
|
static constexpr float quiet_NaN() { return FLT_QUIET_NAN; }
|
||||||
static constexpr double signaling_NaN() { return FLT_SIGNALING_NAN; }
|
static constexpr float signaling_NaN() { return FLT_SIGNALING_NAN; }
|
||||||
static constexpr double denorm_min() { return FLT_DENORM_MIN; }
|
static constexpr float denorm_min() { return FLT_DENORM_MIN; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Overload for the bultin double precision floating point type
|
// Overload for the bultin double precision floating point type
|
||||||
@@ -146,9 +327,9 @@ template<> struct numeric_limits<double>
|
|||||||
static constexpr int max_exponent = DBL_MAX_EXP;
|
static constexpr int max_exponent = DBL_MAX_EXP;
|
||||||
static constexpr int max_exponent10 = DBL_MAX_10_EXP;
|
static constexpr int max_exponent10 = DBL_MAX_10_EXP;
|
||||||
|
|
||||||
static constexpr double min() { return DBL_MIN; }
|
static constexpr double min() { return -DBL_MAX; }
|
||||||
static constexpr double max() { return DBL_MAX; }
|
static constexpr double max() { return DBL_MAX; }
|
||||||
static constexpr double lowest() { return -DBL_MAX; }
|
static constexpr double lowest() { return DBL_MIN; }
|
||||||
static constexpr double epsilon() { return DBL_EPSILON; }
|
static constexpr double epsilon() { return DBL_EPSILON; }
|
||||||
static constexpr double round_error() { return DBL_ROUND_ERR; }
|
static constexpr double round_error() { return DBL_ROUND_ERR; }
|
||||||
static constexpr double infinity() { return DBL_INF; }
|
static constexpr double infinity() { return DBL_INF; }
|
||||||
@@ -157,6 +338,424 @@ template<> struct numeric_limits<double>
|
|||||||
static constexpr double denorm_min() { return DBL_DENORM_MIN; }
|
static constexpr double denorm_min() { return DBL_DENORM_MIN; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin char type
|
||||||
|
template<> struct numeric_limits<char>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = CHAR_IS_SIGNED;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = CHAR_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = CHAR_DIG;
|
||||||
|
static constexpr int max_digits10 = CHAR_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = CHAR_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr char min() { return static_cast<char>(CHAR_MIN); }
|
||||||
|
static constexpr char max() { return CHAR_MAX; }
|
||||||
|
static constexpr char lowest() { return 1; }
|
||||||
|
static constexpr char epsilon() { return 1; }
|
||||||
|
static constexpr char round_error() { return 0; }
|
||||||
|
static constexpr char infinity() { return 0; }
|
||||||
|
static constexpr char quiet_NaN() { return 0; }
|
||||||
|
static constexpr char signaling_NaN() { return 0; }
|
||||||
|
static constexpr char denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<signed char>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = true;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = SCHAR_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = SCHAR_DIG;
|
||||||
|
static constexpr int max_digits10 = SCHAR_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = SCHAR_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr signed char min() { return static_cast<signed char>(SCHAR_MIN); }
|
||||||
|
static constexpr signed char max() { return SCHAR_MAX; }
|
||||||
|
static constexpr signed char lowest() { return 1; }
|
||||||
|
static constexpr signed char epsilon() { return 1; }
|
||||||
|
static constexpr signed char round_error() { return 0; }
|
||||||
|
static constexpr signed char infinity() { return 0; }
|
||||||
|
static constexpr signed char quiet_NaN() { return 0; }
|
||||||
|
static constexpr signed char signaling_NaN() { return 0; }
|
||||||
|
static constexpr signed char denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<unsigned char>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = false;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = UCHAR_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = UCHAR_DIG;
|
||||||
|
static constexpr int max_digits10 = UCHAR_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = UCHAR_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr unsigned char min() { return UCHAR_MIN; }
|
||||||
|
static constexpr unsigned char max() { return UCHAR_MAX; }
|
||||||
|
static constexpr unsigned char lowest() { return 1; }
|
||||||
|
static constexpr unsigned char epsilon() { return 1; }
|
||||||
|
static constexpr unsigned char round_error() { return 0; }
|
||||||
|
static constexpr unsigned char infinity() { return 0; }
|
||||||
|
static constexpr unsigned char quiet_NaN() { return 0; }
|
||||||
|
static constexpr unsigned char signaling_NaN() { return 0; }
|
||||||
|
static constexpr unsigned char denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<short>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = true;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = SHORT_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = SHORT_DIG;
|
||||||
|
static constexpr int max_digits10 = SHORT_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = SHORT_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr short min() { return static_cast<short>(SHORT_MIN); }
|
||||||
|
static constexpr short max() { return SHORT_MAX; }
|
||||||
|
static constexpr short lowest() { return 1; }
|
||||||
|
static constexpr short epsilon() { return 1; }
|
||||||
|
static constexpr short round_error() { return 0; }
|
||||||
|
static constexpr short infinity() { return 0; }
|
||||||
|
static constexpr short quiet_NaN() { return 0; }
|
||||||
|
static constexpr short signaling_NaN() { return 0; }
|
||||||
|
static constexpr short denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<unsigned short>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = false;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = USHORT_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = USHORT_DIG;
|
||||||
|
static constexpr int max_digits10 = USHORT_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = USHORT_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr unsigned short min() { return USHORT_MIN; }
|
||||||
|
static constexpr unsigned short max() { return USHORT_MAX; }
|
||||||
|
static constexpr unsigned short lowest() { return 1; }
|
||||||
|
static constexpr unsigned short epsilon() { return 1; }
|
||||||
|
static constexpr unsigned short round_error() { return 0; }
|
||||||
|
static constexpr unsigned short infinity() { return 0; }
|
||||||
|
static constexpr unsigned short quiet_NaN() { return 0; }
|
||||||
|
static constexpr unsigned short signaling_NaN() { return 0; }
|
||||||
|
static constexpr unsigned short denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<int>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = true;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = INT_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = INT_DIG;
|
||||||
|
static constexpr int max_digits10 = INT_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = INT_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr int min() { return INT_MIN; }
|
||||||
|
static constexpr int max() { return INT_MAX; }
|
||||||
|
static constexpr int lowest() { return 1; }
|
||||||
|
static constexpr int epsilon() { return 1; }
|
||||||
|
static constexpr int round_error() { return 0; }
|
||||||
|
static constexpr int infinity() { return 0; }
|
||||||
|
static constexpr int quiet_NaN() { return 0; }
|
||||||
|
static constexpr int signaling_NaN() { return 0; }
|
||||||
|
static constexpr int denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<unsigned int>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = false;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = UINT_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = UINT_DIG;
|
||||||
|
static constexpr int max_digits10 = UINT_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = UINT_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr unsigned int min() { return UINT_MIN; }
|
||||||
|
static constexpr unsigned int max() { return UINT_MAX; }
|
||||||
|
static constexpr unsigned int lowest() { return 1; }
|
||||||
|
static constexpr unsigned int epsilon() { return 1; }
|
||||||
|
static constexpr unsigned int round_error() { return 0; }
|
||||||
|
static constexpr unsigned int infinity() { return 0; }
|
||||||
|
static constexpr unsigned int quiet_NaN() { return 0; }
|
||||||
|
static constexpr unsigned int signaling_NaN() { return 0; }
|
||||||
|
static constexpr unsigned int denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<long int>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = true;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = LONG_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = LONG_DIG;
|
||||||
|
static constexpr int max_digits10 = LONG_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = LONG_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr long int min() { return LONG_MIN; }
|
||||||
|
static constexpr long int max() { return LONG_MAX; }
|
||||||
|
static constexpr long int lowest() { return 1; }
|
||||||
|
static constexpr long int epsilon() { return 1; }
|
||||||
|
static constexpr long int round_error() { return 0; }
|
||||||
|
static constexpr long int infinity() { return 0; }
|
||||||
|
static constexpr long int quiet_NaN() { return 0; }
|
||||||
|
static constexpr long int signaling_NaN() { return 0; }
|
||||||
|
static constexpr long int denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<unsigned long int>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = false;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = ULONG_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = ULONG_DIG;
|
||||||
|
static constexpr int max_digits10 = ULONG_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = ULONG_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr unsigned long min() { return ULONG_MIN; }
|
||||||
|
static constexpr unsigned long max() { return ULONG_MAX; }
|
||||||
|
static constexpr unsigned long lowest() { return 1; }
|
||||||
|
static constexpr unsigned long epsilon() { return 1; }
|
||||||
|
static constexpr unsigned long round_error() { return 0; }
|
||||||
|
static constexpr unsigned long infinity() { return 0; }
|
||||||
|
static constexpr unsigned long quiet_NaN() { return 0; }
|
||||||
|
static constexpr unsigned long signaling_NaN() { return 0; }
|
||||||
|
static constexpr unsigned long denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<long long>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = true;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = LLONG_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = LLONG_DIG;
|
||||||
|
static constexpr int max_digits10 = LLONG_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = LLONG_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr long long min() { return LLONG_MIN; }
|
||||||
|
static constexpr long long max() { return LLONG_MAX; }
|
||||||
|
static constexpr long long lowest() { return 1; }
|
||||||
|
static constexpr long long epsilon() { return 1; }
|
||||||
|
static constexpr long long round_error() { return 0; }
|
||||||
|
static constexpr long long infinity() { return 0; }
|
||||||
|
static constexpr long long quiet_NaN() { return 0; }
|
||||||
|
static constexpr long long signaling_NaN() { return 0; }
|
||||||
|
static constexpr long long denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload for the builtin signed char type
|
||||||
|
template<> struct numeric_limits<unsigned long long>
|
||||||
|
{
|
||||||
|
static constexpr bool is_specialized = true;
|
||||||
|
static constexpr bool is_signed = false;
|
||||||
|
static constexpr bool is_integer = true;
|
||||||
|
static constexpr bool is_exact = true;
|
||||||
|
static constexpr bool has_infinity = false;
|
||||||
|
static constexpr bool has_quiet_nan = false;
|
||||||
|
static constexpr bool has_signaling_nan = false;
|
||||||
|
static constexpr bool has_denorm = false;
|
||||||
|
static constexpr bool has_denorm_loss = false;
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr bool is_bounded = true;
|
||||||
|
static constexpr bool is_modulo = true;
|
||||||
|
static constexpr bool tinyness_before = false;
|
||||||
|
static constexpr bool traps = true;
|
||||||
|
|
||||||
|
static constexpr int digits = ULLONG_RADIX_DIG;
|
||||||
|
static constexpr int digits10 = ULLONG_DIG;
|
||||||
|
static constexpr int max_digits10 = ULLONG_DECIMAL_DIG;
|
||||||
|
static constexpr int radix = ULLONG_RADIX;
|
||||||
|
static constexpr int min_exponent = 0;
|
||||||
|
static constexpr int min_exponent10 = 0;
|
||||||
|
static constexpr int max_exponent = 0;
|
||||||
|
static constexpr int max_exponent10 = 0;
|
||||||
|
|
||||||
|
static constexpr unsigned long long min() { return ULLONG_MIN; }
|
||||||
|
static constexpr unsigned long long max() { return ULLONG_MAX; }
|
||||||
|
static constexpr unsigned long long lowest() { return 1; }
|
||||||
|
static constexpr unsigned long long epsilon() { return 1; }
|
||||||
|
static constexpr unsigned long long round_error() { return 0; }
|
||||||
|
static constexpr unsigned long long infinity() { return 0; }
|
||||||
|
static constexpr unsigned long long quiet_NaN() { return 0; }
|
||||||
|
static constexpr unsigned long long signaling_NaN() { return 0; }
|
||||||
|
static constexpr unsigned long long denorm_min() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_LANG_LIMITS_H
|
#endif // FENNEC_LANG_LIMITS_H
|
||||||
|
|||||||
52
include/fennec/lang/metaprogramming.h
Normal file
52
include/fennec/lang/metaprogramming.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file metaprogramming.h
|
||||||
|
/// \brief \ref fennec_lang
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_METAPROGRAMMING_H
|
||||||
|
#define FENNEC_LANG_METAPROGRAMMING_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_metaprogramming Metaprogramming Library
|
||||||
|
///
|
||||||
|
/// This is a sub-library of the fennec \ref fennec_lang. Metaprogramming is a method of obtaining information about the
|
||||||
|
/// structure of the code and changing its behaviour at compile time. This includes getting traits of types, such as with
|
||||||
|
/// \ref fennec::is_signed. You may even \ref fennec_lang_conditional_types "programmatically enable" functions
|
||||||
|
/// based on the info of the types that the function uses.
|
||||||
|
///
|
||||||
|
/// - \subpage fennec_lang_constants
|
||||||
|
/// - \subpage fennec_lang_conditional_types
|
||||||
|
/// - \subpage fennec_lang_numeric_transforms
|
||||||
|
/// - \subpage fennec_lang_sequences
|
||||||
|
/// - \subpage fennec_lang_type_sequences
|
||||||
|
/// - \subpage fennec_lang_type_traits
|
||||||
|
/// - \subpage fennec_lang_type_transforms
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_METAPROGRAMMING_H
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file numeric_transforms.h
|
/// \file numeric_transforms.h
|
||||||
/// \brief modify numeric types at compile time
|
/// \brief \ref fennec_lang_numeric_transforms
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -30,16 +30,54 @@
|
|||||||
#ifndef FENNEC_LANG_NUMERIC_TRANSFORMS_H
|
#ifndef FENNEC_LANG_NUMERIC_TRANSFORMS_H
|
||||||
#define FENNEC_LANG_NUMERIC_TRANSFORMS_H
|
#define FENNEC_LANG_NUMERIC_TRANSFORMS_H
|
||||||
|
|
||||||
#include <fennec/lang/type_transforms.h>
|
///
|
||||||
#include <fennec/lang/detail/__numeric_transforms.h>
|
/// \page fennec_lang_numeric_transforms Numeric Transforms
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/numeric_transforms.h> \endcode
|
||||||
|
///
|
||||||
|
/// This header contains various compile-time functions for changing the characteristics of a provided type
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_numeric_transforms">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::make_signed "typename make_signed<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::make_signed_t "make_signed_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::make_signed
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::make_unsigned "typename make_unsigned<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::make_unsigned_t "make_unsigned_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::make_unsigned
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
|
||||||
// TODO: Document
|
#include <fennec/lang/type_transforms.h>
|
||||||
|
#include <fennec/lang/detail/_numeric_transforms.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename TypeT> struct make_signed : detail::__make_signed<remove_cv_t<TypeT>> {};
|
///
|
||||||
template<typename TypeT> struct make_unsigned : detail::__make_unsigned<remove_cv_t<TypeT>> {};
|
/// \brief Get the corresponding signed integral type of TypeT
|
||||||
|
/// \tparam TypeT the integral type to transform
|
||||||
|
template<typename TypeT> struct make_signed : detail::_make_signed<remove_cv_t<TypeT>> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `typename make_signed<TypeT>::type`
|
||||||
|
template<typename TypeT> using make_signed_t = typename make_signed<TypeT>::type;
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Get the corresponding unsigned integral type of TypeT
|
||||||
|
/// \tparam TypeT the integral type to transform
|
||||||
|
template<typename TypeT> struct make_unsigned : detail::_make_unsigned<remove_cv_t<TypeT>> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `typename make_unsigned<TypeT>::type`
|
||||||
|
template<typename TypeT> using make_unsigned_t = typename make_unsigned<TypeT>::type;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,225 +0,0 @@
|
|||||||
// =====================================================================================================================
|
|
||||||
// fennec, a free and open source game engine
|
|
||||||
// Copyright © 2025 Medusa Slockbower
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
// =====================================================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \file sequences.h
|
|
||||||
/// \brief metaprogramming sequences
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \author Medusa Slockbower
|
|
||||||
///
|
|
||||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
|
||||||
///
|
|
||||||
///
|
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_SEQUENCES_H
|
|
||||||
#define FENNEC_LANG_SEQUENCES_H
|
|
||||||
|
|
||||||
#include <fennec/lang/type_traits.h>
|
|
||||||
|
|
||||||
namespace fennec
|
|
||||||
{
|
|
||||||
|
|
||||||
// fennec::sequence ====================================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief metaprogramming sequence
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam ValueT type of the values
|
|
||||||
/// \tparam ValuesV sequence values
|
|
||||||
///
|
|
||||||
template<typename ValueT, ValueT...ValuesV> struct sequence
|
|
||||||
{
|
|
||||||
///
|
|
||||||
/// \brief type of the sequence
|
|
||||||
using value_type = ValueT;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief self-referential type
|
|
||||||
using type = sequence;
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief returns the number of elements
|
|
||||||
///
|
|
||||||
/// \return number of elements in the array
|
|
||||||
inline static constexpr size_t size() noexcept { return sizeof...(ValuesV); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fennec::integer_sequence ============================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief metaprogramming integral sequence
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam T type of the values, must satisfy ```fennec::is_integral<T>```
|
|
||||||
/// \tparam Values sequence values
|
|
||||||
///
|
|
||||||
template<typename T, T...Values> requires(is_integral_v<T>)
|
|
||||||
struct integer_sequence : sequence<T, Values...>
|
|
||||||
{
|
|
||||||
///
|
|
||||||
/// \brief type of the sequence
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief self-referential type
|
|
||||||
using type = integer_sequence;
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief returns the number of elements
|
|
||||||
///
|
|
||||||
/// \return number of elements in the array
|
|
||||||
inline static constexpr size_t size() noexcept { return sizeof...(Values); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief generate a fennec::integer_sequence \f$\left[\,0\,\ldots\,N\,\right)\f$
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam T type of the values, must satisfy ```fennec::is_integral<T>```
|
|
||||||
/// \tparam N size of the sequence to generate
|
|
||||||
///
|
|
||||||
template<typename T, size_t N> struct make_integer_sequence;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief shorthand for ```typename make_integer_sequence<T, N>::type```
|
|
||||||
template<typename T, size_t N> using make_integer_sequence_t = typename make_integer_sequence<T, N>::type;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fennec::index_sequence ==============================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief metaprogramming integral sequence
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam Indices sequence values
|
|
||||||
///
|
|
||||||
template<size_t...Indices> struct index_sequence : integer_sequence<size_t, Indices...>
|
|
||||||
{
|
|
||||||
///
|
|
||||||
/// \brief type of the sequence
|
|
||||||
using value_type = size_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief self-referential type
|
|
||||||
using type = index_sequence;
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief returns the number of elements
|
|
||||||
///
|
|
||||||
/// \return number of elements in the array
|
|
||||||
inline static constexpr size_t size() noexcept { return sizeof...(Indices); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief generate a fennec::index_sequence \f$\left[\,0\,\ldots\,N\,\right)\f$
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam T type of the values, must satisfy ```fennec::is_integral<T>```
|
|
||||||
/// \tparam N size of the sequence to generate
|
|
||||||
///
|
|
||||||
template<size_t N> struct make_index_sequence;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief shorthand for ```typename make_index_sequence<N>::type```
|
|
||||||
template<size_t N> using make_index_sequence_t = typename make_index_sequence<N>::type;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fennec::concat_sequence =============================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief concatenate two sequences
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam SequenceT0 lhs
|
|
||||||
/// \tparam SequenceT1 rhs
|
|
||||||
template<typename SequenceT0, typename SequenceT1> struct concat_sequence;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief shorthand for ```typename concat_sequence<SequenceT0, SequenceT1>::type```
|
|
||||||
template<typename SequenceT0, typename SequenceT1> using concat_sequence_t
|
|
||||||
= typename concat_sequence<SequenceT0, SequenceT1>::type;
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief specialization to concatenate two integer sequences
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam T integral type
|
|
||||||
/// \tparam SequenceT0 lhs
|
|
||||||
/// \tparam SequenceT1 rhs
|
|
||||||
template<typename T, T...SequenceV0, T...SequenceV1>
|
|
||||||
struct concat_sequence<integer_sequence<T, SequenceV0...>, integer_sequence<T, SequenceV1...>>
|
|
||||||
: integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \brief specialization to concatenate two index sequences
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam SequenceT0 lhs
|
|
||||||
/// \tparam SequenceT1 rhs
|
|
||||||
template<size_t...SequenceV0, size_t...SequenceV1>
|
|
||||||
struct concat_sequence<index_sequence<SequenceV0...>, index_sequence<SequenceV1...>>
|
|
||||||
: index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Internal ============================================================================================================
|
|
||||||
|
|
||||||
// Implementation for Generating an \ref integer_sequence
|
|
||||||
template<typename T, size_t N> struct make_integer_sequence : concat_sequence_t<make_integer_sequence_t<T, N / 2>, make_integer_sequence_t<T, N - N / 2>>{};
|
|
||||||
|
|
||||||
// Base Case of \f$N=0\f$
|
|
||||||
template<typename T> struct make_integer_sequence<T, 0> : integer_sequence<T> {};
|
|
||||||
|
|
||||||
// Base Case of \f$N=1\f$
|
|
||||||
template<typename T> struct make_integer_sequence<T, 1> : integer_sequence<T, 0>{};
|
|
||||||
|
|
||||||
|
|
||||||
// Implementation for Generating an \ref integer_sequence
|
|
||||||
template<size_t N> struct make_index_sequence : concat_sequence_t<make_index_sequence_t<N / 2>, make_index_sequence_t<N - N / 2>>{};
|
|
||||||
|
|
||||||
// Base Case of \f$N=0\f$
|
|
||||||
template<> struct make_index_sequence<0> : index_sequence<> {};
|
|
||||||
|
|
||||||
// Base Case of \f$N=1\f$
|
|
||||||
template<> struct make_index_sequence<1> : index_sequence<0>{};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FENNEC_LANG_SEQUENCES_H
|
|
||||||
28
include/fennec/lang/startup.h
Normal file
28
include/fennec/lang/startup.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_STARTUP_H
|
||||||
|
#define FENNEC_LANG_STARTUP_H
|
||||||
|
|
||||||
|
// Helper for running a function before main()
|
||||||
|
#define STATIC_CONSTRUCTOR(f) \
|
||||||
|
inline static void f(void); \
|
||||||
|
struct f##_t_ { inline f##_t_(void) { f(); } }; inline static f##_t_ f##_; \
|
||||||
|
inline static void f(void)
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_STARTUP_H
|
||||||
57
include/fennec/lang/type_identity.h
Normal file
57
include/fennec/lang/type_identity.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_TYPE_IDENTITY_H
|
||||||
|
#define FENNEC_LANG_TYPE_IDENTITY_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_type_identity Type Identity
|
||||||
|
///
|
||||||
|
/// \brief Part of the fennec metaprogramming library. This header defines structures for copying types with different traits
|
||||||
|
/// or rather, transform them, at compile time.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/type_identity.h> \endcode
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_identity">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::type_identity "type_identity<TypeT>::type"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::type_identity
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Base Class for Type Transformations
|
||||||
|
///
|
||||||
|
/// \details resembles a transformation from one type to T, the result is stored in the member type_transform::type
|
||||||
|
/// \tparam T Resultant Type
|
||||||
|
template<typename T> struct type_identity {
|
||||||
|
|
||||||
|
/// \brief the type to transform into
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_TYPE_IDENTITY_H
|
||||||
112
include/fennec/lang/type_operators.h
Normal file
112
include/fennec/lang/type_operators.h
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_TYPE_OPERATORS_H
|
||||||
|
#define FENNEC_LANG_TYPE_OPERATORS_H
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/6534041/how-to-check-whether-operator-exists
|
||||||
|
|
||||||
|
// has_equals ==========================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0>
|
||||||
|
struct has_equals {
|
||||||
|
// Use SFINAE to check for the operator
|
||||||
|
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() == declval<V>());
|
||||||
|
template<typename, typename> static auto test(...) -> false_type;
|
||||||
|
|
||||||
|
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> constexpr bool has_equals_v = has_equals<T0, T1>::value;
|
||||||
|
|
||||||
|
// has_nequals =========================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0>
|
||||||
|
struct has_nequals {
|
||||||
|
// Use SFINAE to check for the operator
|
||||||
|
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() != declval<V>());
|
||||||
|
template<typename, typename> static auto test(...) -> false_type;
|
||||||
|
|
||||||
|
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> constexpr bool has_nequals_v = has_nequals<T0, T1>::value;
|
||||||
|
|
||||||
|
|
||||||
|
// has_less ============================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0>
|
||||||
|
struct has_less {
|
||||||
|
// Use SFINAE to check for the operator
|
||||||
|
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() < declval<V>());
|
||||||
|
template<typename, typename> static auto test(...) -> false_type;
|
||||||
|
|
||||||
|
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> constexpr bool has_less_v = has_less<T0, T1>::value;
|
||||||
|
|
||||||
|
|
||||||
|
// has_less_equals =====================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0>
|
||||||
|
struct has_less_equals {
|
||||||
|
// Use SFINAE to check for the operator
|
||||||
|
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() <= declval<V>());
|
||||||
|
template<typename, typename> static auto test(...) -> false_type;
|
||||||
|
|
||||||
|
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> constexpr bool has_less_equals_v = has_less_equals<T0, T1>::value;
|
||||||
|
|
||||||
|
|
||||||
|
// has_greater =========================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0>
|
||||||
|
struct has_greater {
|
||||||
|
// Use SFINAE to check for the operator
|
||||||
|
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() > declval<V>());
|
||||||
|
template<typename, typename> static auto test(...) -> false_type;
|
||||||
|
|
||||||
|
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> constexpr bool has_greater_v = has_greater<T0, T1>::value;
|
||||||
|
|
||||||
|
|
||||||
|
// has_greater_equals ==================================================================================================
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0>
|
||||||
|
struct has_greater_equals {
|
||||||
|
// Use SFINAE to check for the operator
|
||||||
|
template<typename U, typename V> static auto test(U*) -> decltype(declval<U>() >= declval<V>());
|
||||||
|
template<typename, typename> static auto test(...) -> false_type;
|
||||||
|
|
||||||
|
static constexpr bool value = is_same_v<bool, decltype(test<T0, T1>(0))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T0, typename T1 = T0> constexpr bool has_greater_equals_v = has_greater_equals<T0, T1>::value;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_TYPE_OPERATORS_H
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \file variadics.h
|
/// \file type_sequences.h
|
||||||
/// \brief basic types of the c++ language
|
/// \brief \ref fennec_lang_type_sequences
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -28,10 +28,33 @@
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_LANG_VARIADICS_H
|
#ifndef FENNEC_LANG_TYPE_SEQUENCES_H
|
||||||
#define FENNEC_LANG_VARIADICS_H
|
#define FENNEC_LANG_TYPE_SEQUENCES_H
|
||||||
|
|
||||||
#include <fennec/lang/detail/__variadics.h>
|
///
|
||||||
|
/// \page fennec_lang_type_sequences Type Sequences
|
||||||
|
///
|
||||||
|
/// \brief This header is part of the metaprogramming library. It defines structures for sequences of types, used during compile time.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/type_sequences.h> \endcode
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_sequences">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::first_element "typename first_element<ValueT, Values...>::type"<br>
|
||||||
|
/// \ref fennec::first_element_t "first_element_t<ValueT, Values...>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydoc fennec::first_element
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::replace_first_element "typename replace_first_element<ClassT, SubT, OriginT, RestT...>::type"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydoc fennec::replace_first_element
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <fennec/lang/detail/_type_sequences.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -39,15 +62,16 @@ namespace fennec
|
|||||||
///
|
///
|
||||||
/// \brief Get the first element of a template parameter pack
|
/// \brief Get the first element of a template parameter pack
|
||||||
/// \tparam TypesT the Parameter Pack
|
/// \tparam TypesT the Parameter Pack
|
||||||
template<typename...TypesT> struct first_element : detail::__first_element<TypesT...> {};
|
template<typename...TypesT> struct first_element : detail::_first_element<TypesT...> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief alias for first_element<TypesT>::type
|
/// \brief alias for first_element<TypesT>::type
|
||||||
template<typename...TypesT> using first_element_t = typename first_element<TypesT...>::type;
|
template<typename...TypesT> using first_element_t = typename first_element<TypesT...>::type;
|
||||||
|
|
||||||
|
|
||||||
|
template<size_t n, typename...TypesT> struct nth_element : detail::_nth_element<n, 0, TypesT...> {};
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first `ArgT` of `ArgsT...` with `SubT`
|
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first `ArgT` of `ArgsT...` with `SubT`
|
||||||
template<typename ClassT, typename SubT> struct replace_first_element { };
|
template<typename ClassT, typename SubT> struct replace_first_element { };
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file type_traits.h
|
/// \file type_traits.h
|
||||||
/// \brief get info about types at compile-time
|
/// \brief \ref fennec_lang_type_traits
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -31,184 +31,347 @@
|
|||||||
#ifndef FENNEC_LANG_TYPE_TRAITS_H
|
#ifndef FENNEC_LANG_TYPE_TRAITS_H
|
||||||
#define FENNEC_LANG_TYPE_TRAITS_H
|
#define FENNEC_LANG_TYPE_TRAITS_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_type_traits Type Traits
|
||||||
|
///
|
||||||
|
/// \brief Part of the fennec metaprogramming library. This header defines structures for accessing traits of types
|
||||||
|
/// at compile time.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/type_traits.h> \endcode
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_void "is_void<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_void_v "is_void_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_void
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_bool "is_bool<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_bool_v "is_bool_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_bool
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_integral "is_integral<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_integral_v "is_integral_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_integral
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_signed "is_signed<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_signed_v "is_signed_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_signed
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_unsigned "is_unsigned<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_unsigned_v "is_unsigned_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_unsigned
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_floating_point "is_floating_point<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_floating_point_v "is_floating_point_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_floating_point
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_arithmetic "is_arithmetic<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_arithmetic_v "is_arithmetic_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_arithmetic
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_same "is_same<TypeT>::value"<br>
|
||||||
|
/// \ref fennec::is_same_v "is_same_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_same
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_convertible "is_convertible<TypeT0, TypeT1>::value"<br>
|
||||||
|
/// \ref fennec::is_convertible_v "is_convertible_v<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::is_convertible
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::is_constructible "is_constructible<ClassT, ArgsT...>::value"<br>
|
||||||
|
/// \ref fennec::is_constructible_v "is_constructible_v<ClassT, ArgsT...>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydoc fennec::is_constructible
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
#include <fennec/lang/type_transforms.h>
|
#include <fennec/lang/type_transforms.h>
|
||||||
#include <fennec/lang/detail/__type_traits.h>
|
#include <fennec/lang/detail/_type_traits.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// fennec::declval =====================================================================================================
|
||||||
|
|
||||||
|
template<typename T> auto declval() noexcept -> decltype(detail::_declval<T>(0)) {
|
||||||
|
static_assert(detail::_declval_protector<T>{}, "declval must not be used");
|
||||||
|
return detail::_declval<T>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline bool is_constant_evaluated() noexcept {
|
||||||
|
if consteval {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// fennec::is_void =====================================================================================================
|
// fennec::is_void =====================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is of type void
|
/// \brief check if \p T is of type void
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Stores a boolean value in `is_void::value`, representing whether the provided type is of base type void.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_void
|
template<typename T> struct is_void
|
||||||
: detail::__is_void<remove_cvr_t<T>>{};
|
: detail::_is_void<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_void<T>::value```
|
/// \brief shorthand for ```is_void<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_void_v
|
template<typename T> constexpr bool_t is_void_v = is_void<T>::value;
|
||||||
= is_void<T>::value;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fennec::is_bool =====================================================================================================
|
// fennec::is_bool =====================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is of type bool
|
/// \brief check if \p T is of type bool
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Stores a boolean value in `is_bool::value`, representing whether the provided type is of base type bool.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_bool
|
template<typename T> struct is_bool
|
||||||
: detail::__is_bool<remove_cvr_t<T>>{};
|
: detail::_is_bool<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_bool<T>::value```
|
/// \brief shorthand for ```is_bool<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_bool_v
|
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
|
||||||
= is_bool<T>::value;
|
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::is_null_pointer =============================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is of type nullptr_t
|
||||||
|
///
|
||||||
|
/// \details Stores a boolean value in `is_null_pointer::value`, representing whether the provided type is of base type nullptr_t.
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> struct is_null_pointer
|
||||||
|
: detail::_is_null_pointer<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```is_null_pointer<T>::value```
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::value;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::is_array ====================================================================================================
|
||||||
|
|
||||||
|
#if FENNEC_HAS_BUILTIN_IS_ARRAY
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is of an array type
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> struct is_array
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_ARRAY(T)> {};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is of an array type
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> struct is_array
|
||||||
|
: false_type {};
|
||||||
|
|
||||||
|
// overload for a sized array type
|
||||||
|
template<typename T, size_t N> struct is_array<T[N]>
|
||||||
|
: true_type {};
|
||||||
|
|
||||||
|
// overload for a generic array type
|
||||||
|
template<typename T> struct is_array<T[]>
|
||||||
|
: true_type {};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```is_array<T>::value```
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> constexpr bool_t is_array_v = is_array<T>::value;
|
||||||
|
|
||||||
|
// fennec::is_class ====================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is a class
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> struct is_class
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_CLASS(T)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is a class
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> constexpr size_t is_class_v = is_class<T>::value;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Integral Types ======================================================================================================
|
// Integral Types ======================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is of an integral
|
/// \brief check if \p T is of an integral
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Stores a boolean value in `is_integral::value`, representing whether the provided type is of a base integer type.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_integral
|
template<typename T> struct is_integral
|
||||||
: detail::__is_integral<remove_cvr_t<T>> {};
|
: detail::_is_integral<remove_cvr_t<T>> {};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_integral<T>::value```
|
/// \brief shorthand for ```is_integral<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_integral_v
|
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
|
||||||
= is_integral<T>::value;
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is of a signed integral
|
/// \brief check if \p T is of a signed integral
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Checks if type `T` is a signed type i.e. `T(-1) < T(0)` and stores it in `is_same::value`.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_signed
|
template<typename T> struct is_signed
|
||||||
: detail::__is_signed<remove_cvr_t<T>> {};
|
: detail::_is_signed<remove_cvr_t<T>> {};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_signed<T>::value```
|
/// \brief shorthand for ```is_signed<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_signed_v
|
template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value;
|
||||||
= is_signed<T>::value;
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is of an unsigned integral
|
/// \brief check if \p T is of an unsigned integral
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Checks if type `T` is an unsigned type i.e. `T(-1) > T(0)` and stores it in `is_same::value`.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_unsigned
|
template<typename T> struct is_unsigned
|
||||||
: detail::__is_unsigned<remove_cvr_t<T>> {};
|
: detail::_is_unsigned<remove_cvr_t<T>> {};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_unsigned<T>::value```
|
/// \brief shorthand for ```is_unsigned<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_unsigned_v
|
template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
|
||||||
= is_unsigned<T>::value;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Floating Point Types ================================================================================================
|
// Floating Point Types ================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is of a floating point type
|
/// \brief check if \p T is of a floating point type
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_floating_point
|
template<typename T> struct is_floating_point
|
||||||
: detail::__is_floating_point<remove_cvr_t<T>>{};
|
: detail::_is_floating_point<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_floating_point<T>::value```
|
/// \brief shorthand for ```is_floating_point<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_floating_point_v
|
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};
|
||||||
= is_floating_point<T> {};
|
|
||||||
|
|
||||||
|
// Pointer Types =======================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is of a floating point type
|
||||||
|
///
|
||||||
|
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> struct is_pointer
|
||||||
|
: detail::_is_pointer<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```is_floating_point<T>::value```
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Arithmetic Types ====================================================================================================
|
// Arithmetic Types ====================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if \p T is an arithmetic type
|
/// \brief check if \p T is an arithmetic type
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`.
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_arithmetic
|
template<typename T> struct is_arithmetic
|
||||||
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
|
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_arithmetic<T>::value```
|
/// \brief shorthand for ```is_arithmetic<T>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> constexpr bool_t is_arithmetic_v
|
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;
|
||||||
= is_arithmetic<T>::value;
|
|
||||||
|
|
||||||
|
// fennec::is_fundamental ==============================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> struct is_fundamental
|
||||||
|
: bool_constant<is_arithmetic_v<T> || is_void_v<T> || is_null_pointer_v<T>>{};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for ```is_fundamental<T>::value```
|
||||||
|
/// \tparam T type to check
|
||||||
|
template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value;
|
||||||
|
|
||||||
|
|
||||||
// fennec::is_same =====================================================================================================
|
// fennec::is_same =====================================================================================================
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief check if the two types are identical
|
/// \brief check if the two types are identical
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details Checks if `T0` and `T1` are identical and store it in `is_same::value`
|
||||||
/// \tparam T type to check
|
/// \tparam T0 first type to check
|
||||||
template<typename T0, typename T1> struct is_same
|
/// \tparam T1 second type to check
|
||||||
: false_type {};
|
template<typename T0, typename T1> struct is_same : false_type {};
|
||||||
|
|
||||||
// true case
|
// true case
|
||||||
template<typename T> struct is_same<T, T>
|
template<typename T> struct is_same<T, T> : true_type {};
|
||||||
: true_type {};
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_same<T0, T1>::value```
|
/// \brief shorthand for ```is_same<T0, T1>::value```
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T0, typename T1> constexpr bool_t is_same_v
|
template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {};
|
||||||
= is_same<T0, T1> {};
|
|
||||||
|
|
||||||
// fennec::can_convert =================================================================================================
|
// fennec::is_convertible ==============================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief check if type `T0` can be converted `T1`
|
/// \brief check if type `T0` can be converted `T1`
|
||||||
/// \tparam T0 First type
|
///
|
||||||
/// \tparam T1 Second type
|
/// \details Checks if `TypeT0`
|
||||||
template<typename T0, typename T1> struct can_convert
|
/// \tparam FromT First type
|
||||||
: bool_constant<FENNEC_BUILTIN_CAN_CONVERT(T0, T1)> {};
|
/// \tparam ToT Second type
|
||||||
|
template<typename FromT, typename ToT> struct is_convertible
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_CONVERTIBLE(FromT, ToT)> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand
|
/// \brief shorthand for `can_convert<TypeT0, TypeT1>::value`
|
||||||
/// \param T0 First type
|
/// \param FromT First type
|
||||||
/// \param T1 Second type
|
/// \param ToT Second type
|
||||||
template<typename T0, typename T1> using can_convert_v
|
template<typename FromT, typename ToT> constexpr bool_t is_convertible_v = is_convertible<FromT, ToT>{};
|
||||||
= typename can_convert<T0, T1>::type;
|
|
||||||
|
|
||||||
|
|
||||||
// fennec::is_constructible ===============================================================================================
|
// fennec::is_constructible ============================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Check if `ClassT` can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`.
|
/// \brief Check if `ClassT` can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`.
|
||||||
@@ -218,11 +381,111 @@ template<typename T0, typename T1> using can_convert_v
|
|||||||
template<typename ClassT, typename...ArgsT> struct is_constructible
|
template<typename ClassT, typename...ArgsT> struct is_constructible
|
||||||
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, ArgsT...)> {};
|
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, ArgsT...)> {};
|
||||||
|
|
||||||
template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v
|
///
|
||||||
= is_constructible<ClassT, ArgsT...>{};
|
/// \brief Shorthand for `is_constructible<ClassT, ArgsT...>::value`
|
||||||
|
template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v = is_constructible<ClassT, ArgsT...>{};
|
||||||
|
|
||||||
|
|
||||||
// fennec::
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is default constructible
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_default_constructible
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT,)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_default_constructible<ClassT>::value`
|
||||||
|
template<typename ClassT, typename...ArgsT> constexpr bool_t is_default_constructible_v = is_default_constructible<ClassT>{};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is copy constructible
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_copy_constructible
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_copy_constructible<ClassT>::value`
|
||||||
|
template<typename ClassT, typename...ArgsT> constexpr bool_t is_copy_constructible_v = is_copy_constructible<ClassT>{};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is copy constructible
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_move_constructible
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_copy_constructible<ClassT>::value`
|
||||||
|
template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructible_v = is_move_constructible<ClassT>{};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is trivially constructible
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_trivially_constructible
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_trivially_constructible<ClassT, ArgsT...>::value`
|
||||||
|
template<typename ClassT> constexpr bool_t is_trivially_constructible_v = is_trivially_constructible<ClassT>{};
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::is_trivially_destructible ===================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is trivially destructible
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_trivially_destructible
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_trivially_destructible<ClassT, ArgsT...>::value`
|
||||||
|
template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_trivially_destructible<ClassT>{};
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::is_assignable ===============================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`.
|
||||||
|
/// This may be read as "is `ClassT` constructible with `ArgsT`"
|
||||||
|
/// \tparam ClassAT The class type to test
|
||||||
|
/// \tparam ClassBT The arguments for the specific constructor
|
||||||
|
template<typename ClassAT, typename ClassBT> struct is_assignable
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(ClassAT, ClassBT)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_constructible<ClassT, ArgsT...>::value`
|
||||||
|
template<typename ClassT, typename...ArgsT> constexpr bool_t is_assignable_v = is_assignable<ClassT, ArgsT...>{};
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::is_copy_assignable ==========================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is copy assignable
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_copy_assignable
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_copy_assignable<ClassT>::value`
|
||||||
|
template<typename ClassT> constexpr bool_t is_copy_assignable_v = is_copy_assignable<ClassT>{};
|
||||||
|
|
||||||
|
|
||||||
|
// fennec::is_move_assignable ==========================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if `ClassT` is move assignable
|
||||||
|
/// \tparam ClassT The class type to test
|
||||||
|
template<typename ClassT> struct is_move_assignable
|
||||||
|
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Shorthand for `is_move_assignable<ClassT>::value`
|
||||||
|
template<typename ClassT> constexpr bool_t is_move_assignable_v = is_move_assignable<ClassT>{};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file type_transforms.h
|
/// \file type_transforms.h
|
||||||
/// \brief modify types at compile time
|
/// \brief \ref fennec_lang_type_transforms
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -31,57 +31,126 @@
|
|||||||
#ifndef FENNEC_LANG_TYPE_TRANSFORMS_H
|
#ifndef FENNEC_LANG_TYPE_TRANSFORMS_H
|
||||||
#define FENNEC_LANG_TYPE_TRANSFORMS_H
|
#define FENNEC_LANG_TYPE_TRANSFORMS_H
|
||||||
|
|
||||||
|
#include <fennec/lang/type_identity.h>
|
||||||
|
#include <fennec/lang/detail/_type_transforms.h>
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_type_transforms Type Transforms
|
||||||
|
///
|
||||||
|
/// \brief Part of the fennec metaprogramming library. This header defines structures for copying types with different traits
|
||||||
|
/// or rather, transform them, at compile time.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/type_transforms.h> \endcode
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_transforms">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::add_pointer "add_pointer<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::add_pointer_t "add_pointer_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::add_pointer
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::remove_pointer "remove_pointer<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::remove_pointer_t "remove_pointer_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::remove_pointer
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::add_reference "add_reference<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::add_reference_t "add_reference_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::add_reference
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::remove_reference "remove_reference<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::remove_reference_t "remove_reference_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::remove_reference
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::add_const "add_const<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::add_const_t "add_const_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::add_const
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::remove_const "remove_const<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::remove_const_t "remove_const_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::remove_const
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::add_volatile "add_volatile<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::add_volatile_t "add_volatile_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::add_volatile
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::remove_volatile "remove_volatile<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::remove_volatile_t "remove_volatile_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::remove_volatile
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::add_cv "add_cv<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::add_cv_t "add_cv_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::add_cv
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::remove_cv "remove_cv<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::remove_cv_t "remove_cv_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::remove_cv
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::add_cvr "add_cvr<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::add_cvr_t "add_cvr_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::add_cvr
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::remove_cvr "remove_cvr<TypeT>::type"<br>
|
||||||
|
/// \ref fennec::remove_cvr_t "remove_cvr_t<TypeT>"
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::remove_cvr
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
// fennec::type_transform ==============================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \struct fennec::type_transform
|
|
||||||
/// \brief Base Class for Type Transformations
|
|
||||||
///
|
|
||||||
/// \details resembles a transformation from one type to T, the result is stored in the typedef type_transform::type
|
|
||||||
/// \tparam T Resultant Type
|
|
||||||
template<typename T> struct type_transform {
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \typedef type_transform::type
|
|
||||||
/// \brief the type to transform into
|
|
||||||
using type = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Pointer Conversions =================================================================================================
|
// Pointer Conversions =================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::add_pointer
|
|
||||||
/// \brief adds a pointer level to \p T
|
/// \brief adds a pointer level to \p T
|
||||||
///
|
///
|
||||||
/// \details adds a pointer to the provided type such that ```T``` becomes ```T*```
|
/// \details adds a pointer to the provided type such that `T` becomes `T*`
|
||||||
/// \tparam T Resultant Type
|
/// \tparam T Resultant Type
|
||||||
template<typename T> struct add_pointer : type_transform<T*>{};
|
template<typename T> struct add_pointer : type_identity<T*>{};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::add_pointer_t
|
/// \brief shorthand for `typename add_pointer<T>::type`
|
||||||
/// \brief shorthand for ```typename add_pointer<T>::type```
|
|
||||||
template<typename T> using add_pointer_t = typename add_pointer<T>::type;
|
template<typename T> using add_pointer_t = typename add_pointer<T>::type;
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::remove_pointer
|
|
||||||
/// \brief removes a pointer level from \p T
|
/// \brief removes a pointer level from \p T
|
||||||
///
|
///
|
||||||
/// \details removes a pointer from the provided type such that ```T*``` becomes ```T```
|
/// \details removes a pointer from the provided type such that `T*` becomes `T`
|
||||||
/// \tparam T Resultant Type
|
/// \tparam T Resultant Type
|
||||||
template<typename T> struct remove_pointer : type_transform<T> {};
|
template<typename T> struct remove_pointer : type_identity<T> {};
|
||||||
|
|
||||||
// specialization for T*
|
// specialization for T*
|
||||||
template<typename T> struct remove_pointer<T*> : type_transform<T> {};
|
template<typename T> struct remove_pointer<T*> : type_identity<T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::remove_pointer_t
|
/// \brief shorthand for `typename remove_pointer<T>::type`
|
||||||
/// \brief shorthand for ```typename remove_pointer<T>::type```
|
|
||||||
template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;
|
template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;
|
||||||
|
|
||||||
|
|
||||||
@@ -89,186 +158,193 @@ template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;
|
|||||||
// Reference Conversions ===============================================================================================
|
// Reference Conversions ===============================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::add_reference
|
|
||||||
/// \brief add a reference to \p T
|
/// \brief add a reference to \p T
|
||||||
///
|
///
|
||||||
/// \details adds a pointer to the provided type such that ```T``` becomes ```T&```
|
/// \details adds a pointer to the provided type such that `T` becomes `T&`
|
||||||
/// \tparam T Resultant Type
|
/// \tparam T Resultant Type
|
||||||
template<typename T> struct add_reference : type_transform<T&> {};
|
template<typename T> struct add_reference : type_identity<T&> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::add_reference_t
|
/// \brief shorthand for `typename add_reference<T>::type`
|
||||||
/// \brief shorthand for ```typename add_reference<T>::type```
|
|
||||||
template<typename T> using add_reference_t = typename add_reference<T>::type;
|
template<typename T> using add_reference_t = typename add_reference<T>::type;
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::remove_reference
|
|
||||||
/// \brief remove a reference from \p T
|
/// \brief remove a reference from \p T
|
||||||
///
|
///
|
||||||
/// \details removes references from the provided type such that ```T&``` and ```T&&``` become ```T```
|
/// \details removes references from the provided type such that `T&` and `T&&` become `T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct remove_reference : type_transform<T> {};
|
template<typename T> struct remove_reference : type_identity<T> {};
|
||||||
|
|
||||||
// specialization for ```T&```
|
// specialization for `T&`
|
||||||
template<typename T> struct remove_reference<T&> : type_transform<T> {};
|
template<typename T> struct remove_reference<T&> : type_identity<T> {};
|
||||||
|
|
||||||
// specialization for ```T&&```
|
// specialization for `T&&`
|
||||||
template<typename T> struct remove_reference<T&&> : type_transform<T> {};
|
template<typename T> struct remove_reference<T&&> : type_identity<T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::remove_reference_t
|
/// \brief shorthand for `typename remove_reference<T>::type`
|
||||||
/// \brief shorthand for ```typename remove_reference<T>::type```
|
|
||||||
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
|
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief add a lvalue reference to \p T
|
||||||
|
///
|
||||||
|
/// \details adds a lvalue reference to the provided type such that 'T' becomes 'T&'
|
||||||
|
/// \tparam T Reference Type
|
||||||
|
template<typename T> struct add_lvalue_reference : detail::_add_lvalue_reference<T> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for `typename remove_reference<T>::type`
|
||||||
|
template<typename T> using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief add a rvalue reference to \p T
|
||||||
|
///
|
||||||
|
/// \details adds a rvalue reference to the provided type such that 'T' becomes 'T&&'
|
||||||
|
/// \tparam T Reference Type
|
||||||
|
template<typename T> struct add_rvalue_reference : detail::_add_rvalue_reference<T> {};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief shorthand for `typename remove_reference<T>::type`
|
||||||
|
template<typename T> using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Const & Volatile Conversions ========================================================================================
|
// Const & Volatile Conversions ========================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::add_const
|
|
||||||
/// \brief add the const qualifier to the provided type \p T
|
/// \brief add the const qualifier to the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details adds const qualification to the provided type such that ```T``` becomes ```const T```
|
/// \details adds const qualification to the provided type such that `T` becomes `const T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct add_const : type_transform<const T> {};
|
template<typename T> struct add_const : type_identity<const T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::add_const_t
|
/// \brief shorthand for `typename add_const<T>::type`
|
||||||
/// \brief shorthand for ```typename add_const<T>::type```
|
|
||||||
template<typename T> using add_const_t = typename add_const<T>::type;
|
template<typename T> using add_const_t = typename add_const<T>::type;
|
||||||
|
|
||||||
// specialization for const types
|
// specialization for const types
|
||||||
template<typename T> struct add_const<const T> : type_transform<const T> {};
|
template<typename T> struct add_const<const T> : type_identity<const T> {};
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::remove_const
|
|
||||||
/// \brief remove the const qualifier from the provided type \p T
|
/// \brief remove the const qualifier from the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details removes const qualification from the provided type such that ```const T``` becomes ```T```
|
/// \details removes const qualification from the provided type such that `const T` becomes `T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct remove_const : type_transform<T> {};
|
template<typename T> struct remove_const : type_identity<T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::remove_const_t
|
/// \brief shorthand for `typename remove_const<T>::type`
|
||||||
/// \brief shorthand for ```typename remove_const<T>::type```
|
|
||||||
template<typename T> using remove_const_t = typename remove_const<T>::type;
|
template<typename T> using remove_const_t = typename remove_const<T>::type;
|
||||||
|
|
||||||
// specialization for const types
|
// specialization for const types
|
||||||
template<typename T> struct remove_const<const T> : type_transform<T> {};
|
template<typename T> struct remove_const<const T> : type_identity<T> {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::add_volatile
|
|
||||||
/// \brief add the volatile qualifier to the provided type \p T
|
/// \brief add the volatile qualifier to the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details removes references from the provided type such that ```T``` becomes ```volatile T```
|
/// \details removes references from the provided type such that `T` becomes `volatile T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct add_volatile : type_transform<volatile T> {};
|
template<typename T> struct add_volatile : type_identity<volatile T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::add_volatile_t
|
/// \brief shorthand for `typename add_volatile<T>::type`
|
||||||
/// \brief shorthand for ```typename add_volatile<T>::type```
|
|
||||||
template<typename T> using add_volatile_t = typename add_volatile<T>::type;
|
template<typename T> using add_volatile_t = typename add_volatile<T>::type;
|
||||||
|
|
||||||
// specialization for volatile types
|
// specialization for volatile types
|
||||||
template<typename T> struct add_volatile<volatile T> : type_transform<volatile T> {};
|
template<typename T> struct add_volatile<volatile T> : type_identity<volatile T> {};
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::remove_volatile
|
|
||||||
/// \brief remove the volatile qualifier from the provided type \p T
|
/// \brief remove the volatile qualifier from the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details removes references from the provided type such that ```volatile T``` becomes ```T```
|
/// \details removes references from the provided type such that `volatile T` becomes `T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct remove_volatile : type_transform<T> {};
|
template<typename T> struct remove_volatile : type_identity<T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::remove_volatile_t
|
/// \brief shorthand for `typename remove_volatile<T>::type`
|
||||||
/// \brief shorthand for ```typename remove_volatile<T>::type```
|
|
||||||
template<typename T> using remove_volatile_t = typename remove_volatile<T>::type;
|
template<typename T> using remove_volatile_t = typename remove_volatile<T>::type;
|
||||||
|
|
||||||
// specialization for volatile types
|
// specialization for volatile types
|
||||||
template<typename T> struct remove_volatile<volatile T> : type_transform<T> {};
|
template<typename T> struct remove_volatile<volatile T> : type_identity<T> {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \struct fennec::add_cv
|
|
||||||
/// \brief remove the volatile qualifier from the provided type \p T
|
/// \brief remove the volatile qualifier from the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details removes references from the provided type such that ```T```, ```const T```, and ```volatile T``` become
|
/// \details removes references from the provided type such that `T`, `const T`, and `volatile T` become
|
||||||
/// ```const volatile T```
|
/// `const volatile T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct add_cv : type_transform<const volatile T> {};
|
template<typename T> struct add_cv : type_identity<const volatile T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \typedef fennec::add_cv_t
|
/// \brief shorthand for `typename add_cv<T>::type`
|
||||||
/// \brief shorthand for ```typename add_cv<T>::type```
|
|
||||||
template<typename T> using add_cv_t = typename add_cv<T>::type;
|
template<typename T> using add_cv_t = typename add_cv<T>::type;
|
||||||
|
|
||||||
// specialization for const types
|
// specialization for const types
|
||||||
template<typename T> struct add_cv<const T> : type_transform<const volatile T> {};
|
template<typename T> struct add_cv<const T> : type_identity<const volatile T> {};
|
||||||
|
|
||||||
// specialization for volatile types
|
// specialization for volatile types
|
||||||
template<typename T> struct add_cv<volatile T> : type_transform<const volatile T> {};
|
template<typename T> struct add_cv<volatile T> : type_identity<const volatile T> {};
|
||||||
|
|
||||||
// specialization for const volatile types
|
// specialization for const volatile types
|
||||||
template<typename T> struct add_cv<const volatile T> : type_transform<const volatile T> {};
|
template<typename T> struct add_cv<const volatile T> : type_identity<const volatile T> {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief remove the const and volatile qualifiers from the provided type \p T
|
/// \brief remove the const and volatile qualifiers from the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details removes const and volatile from the provided type such that ```const T```, ```volatile T```, and
|
/// \details removes const and volatile from the provided type such that `const T`, `volatile T`, and
|
||||||
/// ```const volatile T``` become ```T```
|
/// `const volatile T` become `T`
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct remove_cv : type_transform<T> {};
|
template<typename T> struct remove_cv : type_identity<T> {};
|
||||||
|
|
||||||
// specialization for const types
|
// specialization for const types
|
||||||
template<typename T> struct remove_cv<const T> : type_transform<T> {};
|
template<typename T> struct remove_cv<const T> : type_identity<T> {};
|
||||||
|
|
||||||
// specialization for volatile types
|
// specialization for volatile types
|
||||||
template<typename T> struct remove_cv<volatile T> : type_transform<T> {};
|
template<typename T> struct remove_cv<volatile T> : type_identity<T> {};
|
||||||
|
|
||||||
// specialization for const volatile types
|
// specialization for const volatile types
|
||||||
template<typename T> struct remove_cv<const volatile T> : type_transform<T> {};
|
template<typename T> struct remove_cv<const volatile T> : type_identity<T> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```typename remove_cv<T>::type```
|
/// \brief shorthand for `typename remove_cv<T>::type`
|
||||||
template<typename T> using remove_cv_t = typename remove_cv<T>::type;
|
template<typename T> using remove_cv_t = typename remove_cv<T>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief add a reference and the const volatile qualifiers from the provided type \p T
|
/// \brief add a reference and the const volatile qualifiers from the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details adds references and const volatile qualifiers to the provided type.
|
/// \details adds references and const volatile qualifiers to the provided type.
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct add_cvr : type_transform<add_reference_t<add_cv_t<T>>> {};
|
template<typename T> struct add_cvr : type_identity<add_reference_t<add_cv_t<T>>> {};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```typename add_cvr<T>::type```
|
/// \brief shorthand for `typename add_cvr<T>::type`
|
||||||
template<typename T> using add_cvr_t = typename add_cvr<T>::type;
|
template<typename T> using add_cvr_t = typename add_cvr<T>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief removes references as well as the const and volatile qualifiers from the provided type \p T
|
/// \brief removes references as well as the const and volatile qualifiers from the provided type \p T
|
||||||
///
|
///
|
||||||
/// \details removes const and volatile from the provided type such that
|
/// \details removes const and volatile from the provided type such that
|
||||||
/// \tparam T Reference Type
|
/// \tparam T Reference Type
|
||||||
template<typename T> struct remove_cvr : type_transform<remove_cv_t<remove_reference_t<T>>> {};
|
template<typename T> struct remove_cvr : type_identity<remove_cv_t<remove_reference_t<T>>> {};
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```typename remove_cvr<T>::type```
|
/// \brief shorthand for `typename remove_cvr<T>::type`
|
||||||
template<typename T> using remove_cvr_t = typename remove_cvr<T>::type;
|
template<typename T> using remove_cvr_t = typename remove_cvr<T>::type;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file types.h
|
/// \file types.h
|
||||||
/// \brief basic types of the c++ language
|
/// \brief \ref fennec_lang_types
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -31,121 +31,248 @@
|
|||||||
#ifndef FENNEC_LANG_TYPES_H
|
#ifndef FENNEC_LANG_TYPES_H
|
||||||
#define FENNEC_LANG_TYPES_H
|
#define FENNEC_LANG_TYPES_H
|
||||||
|
|
||||||
#include <cstdint>
|
///
|
||||||
|
/// \page fennec_lang_types Types
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/types.h> \endcode
|
||||||
|
///
|
||||||
|
/// \brief This header contains definitions for the built-in types of the C++ language.
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_types">
|
||||||
|
/// <tr><th style="vertical-align: top">Type
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><th colspan=2 style="text-align: center;">Basic Types
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::bool_t "bool_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::bool_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::char_t "char_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::char_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::schar_t "schar_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::schar_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uchar_t "uchar_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uchar_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::short_t "short_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::short_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::ushort_t "ushort_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::ushort_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::int_t "int_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::int_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uint_t "uint_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uint_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::long_t "long_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::long_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::ulong_t "ulong_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::ulong_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::llong_t "llong_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::llong_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::ullong_t "ullong_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::ullong_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::float_t "float_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::float_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::double_t "double_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::double_t
|
||||||
|
///
|
||||||
|
/// <tr><th colspan=2 style="text-align: center;">Sized Arithmetic Types
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::int8_t "int8_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::int8_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::int16_t "int16_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::int16_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::int32_t "int32_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::int32_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::int64_t "int64_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::int64_t
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uint8_t "uint8_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uint8_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uint16_t "uint16_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uint16_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uint32_t "uint32_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uint32_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uint64_t "uint64_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::int64_t
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// <tr><th colspan=2 style="text-align: center;">Special Types
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::nullptr_t "nullptr_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::nullptr_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::intptr_t "intptr_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::intptr_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uintptr_t "uintptr_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uintptr_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::intmax_t "intmax_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::intmax_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::uintmax_t "uintmax_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::uintmax_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::size_t "size_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::size_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::ptrdiff_t "ptrdiff_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::ptrdiff_t
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// <tt>\ref fennec::void_t "void_t"</tt>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copybrief fennec::void_t
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <fennec/lang/detail/_int.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/conditional_types.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
// Basic Types =========================================================================================================
|
// Basic Types =========================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \name Basic Types
|
/// \name Basic Types
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
using bool_t = bool; ///< \brief A conditional type
|
||||||
/// \brief A conditional type
|
|
||||||
using bool_t = bool;
|
|
||||||
|
|
||||||
///
|
using char_t = char; ///< \brief A type capable of holding an ascii value
|
||||||
/// \brief A type capable of holding an ascii value
|
using schar_t = signed char; ///< \brief A type with the size of a char, capable of holding a signed 8-bit integer
|
||||||
using char_t = char;
|
using uchar_t = unsigned char; ///< \brief A type with the size of a char, capable of holding an unsigned 8-bit integer
|
||||||
|
|
||||||
///
|
using short_t = signed short; ///< \brief A signed short type, capable of holding signed 16-bit integer
|
||||||
/// \brief A type with the size of a char, capable of holding a signed 8-bit integer
|
using ushort_t = unsigned short; ///< \brief An unsigned short type, capable of holding an unsigned signed 16-bit integer
|
||||||
using schar_t = signed char;
|
|
||||||
|
|
||||||
///
|
using int_t = signed int; ///< \brief A signed integer type, size varies by implementation, but typically 32-bit
|
||||||
/// \brief A type with the size of a char, capable of holding an unsigned 8-bit integer
|
using uint_t = unsigned int; ///< \brief An unsigned integer type, size varies by implementation, but typically 32-bit
|
||||||
using uchar_t = unsigned char;
|
|
||||||
|
|
||||||
///
|
using long_t = signed long; ///< \brief A signed integer type, with a size of at least 32-bits
|
||||||
/// \brief A signed short type, capable of holding signed 16-bit integer
|
using ulong_t = unsigned long; ///< \brief An unsigned integer type, with a size of at least 32-bits
|
||||||
using short_t = signed short;
|
|
||||||
|
|
||||||
///
|
using llong_t = signed long long; ///< \brief A signed integer type, with a size of 64-bits
|
||||||
/// \brief An unsigned short type, capable of holding an unsigned signed 16-bit integer
|
using ullong_t = unsigned long long; ///< \brief An unsigned integer type, with a size of 64-bits
|
||||||
using ushort_t = unsigned short;
|
|
||||||
|
|
||||||
///
|
using float_t = float; ///< \brief A single-precision floating-point type, typically with a size of 32-bits
|
||||||
/// \brief A signed integer type, size varies by implementation, but typically 32-bit
|
using double_t = double; ///< \brief A double-precision floating-point type, typically with a size of 64-bits
|
||||||
using int_t = signed int;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief An unsigned integer type, size varies by implementation, but typically 32-bit
|
|
||||||
using uint_t = unsigned int;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief A signed integer type, with a size of at least 32-bits
|
|
||||||
using long_t = signed long;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief An unsigned integer type, with a size of at least 32-bits
|
|
||||||
using ulong_t = unsigned long;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief A signed integer type, with a size of 64-bits
|
|
||||||
using llong_t = signed long long;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief An unsigned integer type, with a size of 64-bits
|
|
||||||
using ullong_t = unsigned long long;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief A single-precision floating-point type, typically with a size of 32-bits
|
|
||||||
using float_t = float;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief A double-point type, typically with a size of 64-bits
|
|
||||||
using double_t = double;
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \name Special Types
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
using nullptr_t = decltype(nullptr); ///< \brief Null Pointer Type
|
||||||
|
using intptr_t = intptr_t; ///< \brief Signed Integer Capable of Holding a Pointer to void
|
||||||
|
using uintptr_t = uintptr_t; ///< \brief Unsigned Integer Capable of Holding a Pointer to void
|
||||||
|
using intmax_t = intmax_t; ///< \brief Maximum Width Signed Integer Type
|
||||||
|
using uintmax_t = uintmax_t; ///< \brief Maximum Width Unsigned Integer Type
|
||||||
|
using size_t = size_t; ///< \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof`
|
||||||
|
using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers
|
||||||
|
struct empty_t {};
|
||||||
|
|
||||||
|
|
||||||
|
class undefined_t; ///< \brief undefined class for SFINAE
|
||||||
|
template<typename...> using void_t = void; ///< \brief Void type used for SFINAE
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
// Sized Arithmetic Types ==============================================================================================
|
// Sized Arithmetic Types ==============================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \name Sized Integer Types
|
/// \name Sized Integer Types
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
using int8_t = ::int8_t; ///< \brief Signed 8-bit integer
|
||||||
/// \brief Signed 8-bit integer
|
using int16_t = ::int16_t; ///< \brief Signed 16-bit integer
|
||||||
using int8_t = schar_t;
|
using int32_t = ::int32_t; ///< \brief Signed 32-bit integer
|
||||||
|
using int64_t = ::int64_t; ///< \brief Signed 64-bit integer
|
||||||
|
|
||||||
///
|
using uint8_t = ::uint8_t; ///< \brief Unsigned 8-bit integer
|
||||||
/// \brief Signed 16-bit integer
|
using uint16_t = ::uint16_t; ///< \brief Unsigned 16-bit integer
|
||||||
using int16_t = short_t;
|
using uint32_t = ::uint32_t; ///< \brief Unsigned 32-bit integer
|
||||||
|
using uint64_t = ::uint64_t; ///< \brief Unsigned 64-bit integer
|
||||||
///
|
|
||||||
/// \brief Signed 32-bit integer
|
|
||||||
using int32_t = long_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Signed signed 64-bit integer
|
|
||||||
using int64_t = llong_t;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \name Sized Unsigned Integer Types
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Unsigned 8-bit integer
|
|
||||||
using uint8_t = uchar_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Unsigned 16-bit integer
|
|
||||||
using uint16_t = ushort_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Unsigned 32-bit integer
|
|
||||||
using uint32_t = ulong_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Unsigned 64-bit integer
|
|
||||||
using uint64_t = ullong_t;
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
@@ -155,57 +282,9 @@ using uint64_t = ullong_t;
|
|||||||
/// \name Sized Floating-Point Types
|
/// \name Sized Floating-Point Types
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
//using float16_t = _Float16; ///< \brief A half-precision floating-point scalar
|
||||||
/// \brief A single-precision floating-point scalar
|
//using float32_t = _Float32; ///< \brief A single-precision floating-point scalar
|
||||||
using float32_t = float_t;
|
//using float64_t = _Float64; ///< \brief A double-precision floating-point scalar
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief A double-precision floating-point scalar
|
|
||||||
using float64_t = double_t;
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \name Special Types
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Null Pointer Type
|
|
||||||
using nullptr_t = decltype(nullptr);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Signed Integer Capable of Holding a Pointer to void
|
|
||||||
using intptr_t = intptr_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Unsigned Integer Capable of Holding a Pointer to void
|
|
||||||
using uintptr_t = uintptr_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Maximum Width Signed Integer Type
|
|
||||||
using intmax_t = __INTMAX_TYPE__;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Maximum Width Unsigned Integer Type
|
|
||||||
using uintmax_t = __UINTMAX_TYPE__;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof`
|
|
||||||
using size_t = __SIZE_TYPE__;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Signed Integer Type Returned by the Subtraction of two Pointers
|
|
||||||
using ptrdiff_t = __PTRDIFF_TYPE__;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief undefined class for SFINAE
|
|
||||||
class undefined_t;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Void type used for SFINAE
|
|
||||||
template<typename...>
|
|
||||||
using void_t = void;
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|||||||
63
include/fennec/lang/typeuuid.h
Normal file
63
include/fennec/lang/typeuuid.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANG_TYPEUUID_H
|
||||||
|
#define FENNEC_LANG_TYPEUUID_H
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/type_traits.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/detail/_typeuuid.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr uint64_t nullid = 0;
|
||||||
|
|
||||||
|
template<typename TypeT, typename RootT = void>
|
||||||
|
FENNEC_NO_INLINE uint64_t typeuuid() {
|
||||||
|
assertf(not is_constant_evaluated(), "Type UUIDs Cannot Be Obtained at Compile Time");
|
||||||
|
|
||||||
|
static bool init = false;
|
||||||
|
static uint64_t id = nullid;
|
||||||
|
|
||||||
|
if (init) return id;
|
||||||
|
init = true;
|
||||||
|
return id = detail::_typeuuid<RootT>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RootT = void>
|
||||||
|
struct typed {
|
||||||
|
public:
|
||||||
|
const uint64_t type;
|
||||||
|
|
||||||
|
template<typename TypeT>
|
||||||
|
bool is_type() const {
|
||||||
|
return type == typeuuid<TypeT, RootT>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeT>
|
||||||
|
typed(TypeT*)
|
||||||
|
: type(typeuuid<TypeT, RootT>()) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANG_TYPEUUID_H
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file utility.h
|
/// \file utility.h
|
||||||
/// \brief common utility functions related to the c++ language
|
/// \brief \ref fennec_lang_utility
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -31,50 +31,102 @@
|
|||||||
#ifndef FENNEC_LANG_UTILITY_H
|
#ifndef FENNEC_LANG_UTILITY_H
|
||||||
#define FENNEC_LANG_UTILITY_H
|
#define FENNEC_LANG_UTILITY_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_lang_utility Utility
|
||||||
|
///
|
||||||
|
/// \brief This header contains common utility functions related to the C++ language.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/lang/utility.h> \endcode
|
||||||
|
///
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_utility">
|
||||||
|
/// <tr><th style="vertical-align: top">Syntax
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::forward "T&& forward(x)"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::forward
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::move "T&& move(x)"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::move
|
||||||
|
///
|
||||||
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||||
|
/// \ref fennec::copy "const T& copy(x)"<br>
|
||||||
|
/// <td width="50%" style="vertical-align: top">
|
||||||
|
/// \copydetails fennec::copy
|
||||||
|
///
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
|
||||||
#include <fennec/lang/type_transforms.h>
|
#include <fennec/lang/type_transforms.h>
|
||||||
|
#include <fennec/lang/type_traits.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// \details
|
|
||||||
/// \tparam T base type of the object
|
|
||||||
/// \param x reference to the object
|
|
||||||
/// \returns
|
|
||||||
template<typename T> constexpr T&& forward(remove_reference_t<T>& x) noexcept { return x; }
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief forwards reference types to extend their lifetime
|
/// \brief forwards reference types to extend their lifetime
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details forwards reference types to extend their lifetime
|
||||||
/// \tparam T base type of the object
|
/// \tparam T base type of the object
|
||||||
/// \param x reference to the object
|
/// \param x reference to the object
|
||||||
/// \returns
|
/// \returns
|
||||||
template<typename T> constexpr T&& forward(remove_reference_t<T>&& x) noexcept { return x; }
|
template<typename T> constexpr T&& forward(remove_reference_t<T>& x) noexcept {
|
||||||
|
return static_cast<T&&>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// specialization for T&&
|
||||||
|
template<typename T> constexpr T&& forward(remove_reference_t<T>&& x) noexcept {
|
||||||
|
return static_cast<T&&>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief produces an x-value type to indicate \p x may be "moved"
|
/// \brief produces an x-value type to indicate \p x may be "moved"
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details produces an x-value type to indicate \p x may be "moved"
|
||||||
/// \tparam T base type of the object
|
/// \tparam T base type of the object
|
||||||
/// \param x object to be moved
|
/// \param x object to be moved
|
||||||
/// \returns `static_cast<remove_reference_t<T>&&>(x)`
|
/// \returns `static_cast<remove_reference_t<T>&&>(x)`
|
||||||
template<typename T> constexpr remove_reference_t<T>&& move(T&& x) noexcept { return static_cast<remove_reference_t<T>&&>(x); }
|
template<typename T> constexpr remove_reference_t<T>&& move(T&& x) noexcept {
|
||||||
|
return static_cast<remove_reference_t<T>&&>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// \brief produces an r-value type to indicate \p x may be "copied"
|
/// \brief produces an r-value type to indicate \p x may be "copied"
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details produces an r-value type to indicate \p x may be "copied"
|
||||||
/// \tparam T base type of the object
|
/// \tparam T base type of the object
|
||||||
/// \param x object to be copied
|
/// \param x object to be copied
|
||||||
/// \returns const r-value
|
/// \returns const r-value
|
||||||
template<typename T> constexpr const remove_reference_t<T>& copy(T&& x) noexcept { return x; }
|
template<typename T> constexpr const remove_reference_t<T>& copy(T&& x) noexcept {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Swaps x and y
|
||||||
|
/// \tparam T the fundamental type
|
||||||
|
/// \param x first value
|
||||||
|
/// \param y second value
|
||||||
|
template<typename T> requires is_fundamental_v<T>
|
||||||
|
constexpr void swap(T& x, T& y) noexcept {
|
||||||
|
T a = x;
|
||||||
|
x = y;
|
||||||
|
y = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Swaps x and y without invoking destructor
|
||||||
|
/// \tparam T the type
|
||||||
|
/// \param x first value
|
||||||
|
/// \param y second value
|
||||||
|
template<typename T> constexpr void swap(T& x, T& y) noexcept {
|
||||||
|
T a = fennec::move(x);
|
||||||
|
x = fennec::move(y);
|
||||||
|
y = fennec::move(a);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
include/fennec/langproc/filesystem/detail/_stdio.h
Normal file
24
include/fennec/langproc/filesystem/detail/_stdio.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
319
include/fennec/langproc/filesystem/file.h
Normal file
319
include/fennec/langproc/filesystem/file.h
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_IO_FILE_H
|
||||||
|
#define FENNEC_LANGPROC_IO_FILE_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/filesystem/path.h>
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/cstring.h>
|
||||||
|
#include <fennec/langproc/strings/string.h>
|
||||||
|
#include <fennec/langproc/strings/wstring.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Mode flags for opening a file
|
||||||
|
///
|
||||||
|
/// fmode_binary and fmode_wide are independent of the other modes
|
||||||
|
///
|
||||||
|
/// \details Valid Flag Combinations
|
||||||
|
/// <table width="100%" class="fieldtable" id="table_fennec_LANGPROC_io_fmode">
|
||||||
|
/// <tr><th style="vertical-align: top">Flags
|
||||||
|
/// <th style="vertical-align: top">Description
|
||||||
|
///
|
||||||
|
/// <tr><td style="vertical-align: top">`read`
|
||||||
|
/// <td style="vertical-align: top">Opens file as read-only, reading from start
|
||||||
|
///
|
||||||
|
/// <tr><td style="vertical-align: top">`write`
|
||||||
|
/// <td style="vertical-align: top">Opens file as write-only, writing to end
|
||||||
|
///
|
||||||
|
/// <tr><td style="vertical-align: top">`read | write`
|
||||||
|
/// <td style="vertical-align: top">Opens file as read-write, reading from start
|
||||||
|
///
|
||||||
|
/// <tr><td style="vertical-align: top">`write | trunc`
|
||||||
|
/// <td style="vertical-align: top">Opens file as write-only, destroying contents
|
||||||
|
///
|
||||||
|
/// <tr><td style="vertical-align: top">`read | write | trunc`
|
||||||
|
/// <td style="vertical-align: top">Opens file as read-write, destroying contents
|
||||||
|
/// </table>
|
||||||
|
enum fmode_ : uint8_t
|
||||||
|
{
|
||||||
|
fmode_read = 0b00000001 ///< Opens file for reading
|
||||||
|
, fmode_write = 0b00000010 ///< Opens file for writing
|
||||||
|
, fmode_trunc = 0b00000100 ///< Contents of the file will be destroyed, only compatible with write enabled modes
|
||||||
|
, fmode_exclusive = 0b00001000 ///< Generates an error if the opened file is not empty
|
||||||
|
, fmode_binary = 0b00010000 ///< Open in binary mode
|
||||||
|
, fmode_wide = 0b00100000 ///< Opens a file in wide mode
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Structure for handling streams of data
|
||||||
|
///
|
||||||
|
/// \details operations, when errored, will return a corresponding error.
|
||||||
|
/// Use file::get_error() to check if an error is present and return a corresponding string.
|
||||||
|
/// Use file::clear_error() to clear the errored state.
|
||||||
|
/// Some operations, specifically file::rename() and file::copy().
|
||||||
|
class file
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// \brief value of an invalid position
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if the provided mode bitflags are a valid combination
|
||||||
|
/// \param mode the bitfield
|
||||||
|
/// \returns true if the combination of flags is valid, false otherwise
|
||||||
|
static constexpr bool is_valid(uint8_t mode) {
|
||||||
|
const bool t = mode & fmode_trunc;
|
||||||
|
const bool x = mode & fmode_exclusive;
|
||||||
|
const bool w = mode & fmode_write;
|
||||||
|
|
||||||
|
// when x is true, t must be true
|
||||||
|
// when t is true, w must be true
|
||||||
|
return (t && x && w)
|
||||||
|
|| (t && w)
|
||||||
|
|| !(t || x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the c stdout
|
||||||
|
static file& cout();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the c stdin
|
||||||
|
static file& cin();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the c stderr
|
||||||
|
static file& cerr();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief default constructor, initializes an empty stream
|
||||||
|
file();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief default destructor, cleans up an open stream
|
||||||
|
~file();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief move constructor
|
||||||
|
/// \param file the stream to take ownership of
|
||||||
|
file(file&& file) noexcept;
|
||||||
|
|
||||||
|
file& operator=(file&& file) noexcept;
|
||||||
|
|
||||||
|
// don't allow copying streams
|
||||||
|
file(const file&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the path the stream
|
||||||
|
const path& get_path() const {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the mode of the stream
|
||||||
|
uint8_t mode() const {
|
||||||
|
return _mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns true if there is a valid, open stream.
|
||||||
|
bool is_open() const {
|
||||||
|
return _handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// File Access =========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief open a file
|
||||||
|
/// \param path the path to the file
|
||||||
|
/// \param mode the mode flags to open the file with
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
bool open(const cstring& path, uint8_t mode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief open a file
|
||||||
|
/// \param path the path to the file
|
||||||
|
/// \param mode the mode flags to open the file with
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
bool open(const string& path, uint8_t mode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief open a file
|
||||||
|
/// \param path the path to the file
|
||||||
|
/// \param mode the mode flags to open the file with
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
bool open(const path& path, uint8_t mode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief close a stream
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
bool close();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief commit the streams buffer to the file
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
bool commit();
|
||||||
|
|
||||||
|
|
||||||
|
// File Operations =====================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief closes the stream and erases the file
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
bool erase();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief rebinds the stream, copying contents to path, and erasing the old file
|
||||||
|
/// \param path the new path
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
///
|
||||||
|
/// \details attempts to open a write-only stream at path,
|
||||||
|
/// attempts to reopen this file as read-only,
|
||||||
|
/// copies the contents of this file to the new stream,
|
||||||
|
/// reopen the new stream with the flags of this file and binds to it,
|
||||||
|
/// closes the old file.
|
||||||
|
bool rename(const cstring& path);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief rebinds the stream, copying contents to path, and erasing the old file
|
||||||
|
/// \param path the new path
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
///
|
||||||
|
/// \details attempts to open a write-only stream at path,
|
||||||
|
/// attempts to reopen this file as read-only,
|
||||||
|
/// copies the contents of this file to the new stream,
|
||||||
|
/// reopen the new stream with the flags of this file and binds to it,
|
||||||
|
/// closes the old file.
|
||||||
|
bool rename(const string& path);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief rebinds the stream, copying contents to path, and erasing the old file
|
||||||
|
/// \param path the new path
|
||||||
|
/// \returns false on success, true on error
|
||||||
|
///
|
||||||
|
/// \details attempts to open a write-only stream at path,
|
||||||
|
/// attempts to reopen this file as read-only,
|
||||||
|
/// copies the contents of this file to the new stream,
|
||||||
|
/// reopen the new stream with the flags of this file and binds to it,
|
||||||
|
/// closes the old file.
|
||||||
|
bool rename(const path& path);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief copies the contents of this file to path.
|
||||||
|
/// \param path the path to copy to
|
||||||
|
/// \returns a file at the new path with the copied contents
|
||||||
|
file copy(const cstring& path);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief copies the contents of this file to path.
|
||||||
|
/// \param path the path to copy to
|
||||||
|
/// \returns a file at the new path with the copied contents
|
||||||
|
file copy(const string& path);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief copies the contents of this file to path.
|
||||||
|
/// \param path the path to copy to
|
||||||
|
/// \returns a file at the new path with the copied contents
|
||||||
|
file copy(const path& path);
|
||||||
|
|
||||||
|
|
||||||
|
// File Positioning ====================================================================================================
|
||||||
|
|
||||||
|
size_t get_pos() const;
|
||||||
|
bool set_pos(size_t i);
|
||||||
|
bool rewind();
|
||||||
|
bool eof() const;
|
||||||
|
|
||||||
|
|
||||||
|
// Binary Read Operations ==============================================================================================
|
||||||
|
|
||||||
|
char getc();
|
||||||
|
wchar_t getwc();
|
||||||
|
|
||||||
|
size_t read(void* data, size_t size, size_t n);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
size_t read(T* data, size_t n) {
|
||||||
|
return read(static_cast<void*>(data), sizeof(T), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t n>
|
||||||
|
size_t read(T (&data)[n]) {
|
||||||
|
return read(static_cast<void*>(data), sizeof(T), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
string getline();
|
||||||
|
wstring getwline();
|
||||||
|
|
||||||
|
|
||||||
|
// Binary Write Operations =============================================================================================
|
||||||
|
|
||||||
|
bool putc(char c);
|
||||||
|
bool putwc(wchar_t c);
|
||||||
|
|
||||||
|
size_t write(const void* data, size_t size, size_t n);
|
||||||
|
|
||||||
|
template<size_t n>
|
||||||
|
size_t write(const char (&data)[n]) {
|
||||||
|
return write(data, sizeof(char), n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t n>
|
||||||
|
size_t write(const wchar_t (&data)[n]) {
|
||||||
|
return write(data, sizeof(wchar_t), n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
size_t write(const T* data, size_t n) {
|
||||||
|
return write(static_cast<const void*>(data), sizeof(T), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t n>
|
||||||
|
size_t write(const T (&data)[n]) {
|
||||||
|
return write(static_cast<const void*>(data), sizeof(T), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Printing Operations =================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Error Handling ======================================================================================================
|
||||||
|
|
||||||
|
const char* get_error() const { return _error; }
|
||||||
|
void clear_error() { _error = nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE* _handle;
|
||||||
|
path _path;
|
||||||
|
uint8_t _mode;
|
||||||
|
char* _error;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_IO_FILE_H
|
||||||
247
include/fennec/langproc/filesystem/path.h
Normal file
247
include/fennec/langproc/filesystem/path.h
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_IO_PATH_H
|
||||||
|
#define FENNEC_LANGPROC_IO_PATH_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/string.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief struct for handling file paths
|
||||||
|
///
|
||||||
|
/// \details This structure makes no guarantees about the validity of a path.
|
||||||
|
/// Operations do not examine the system's file structure.
|
||||||
|
struct path
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Static Functions ====================================================================================================
|
||||||
|
|
||||||
|
/// \brief Get the current working directory
|
||||||
|
/// \returns a path containing the absolute path to the working directory
|
||||||
|
static path current();
|
||||||
|
|
||||||
|
/// \brief Set the current working directory
|
||||||
|
/// \param path the path to the new working directory
|
||||||
|
/// \returns a path containing the absolute path to the working directory
|
||||||
|
static path current(const path& path);
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, returns the root of the current working directory
|
||||||
|
path() : _str("/") { }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C-String Conversion Constructor
|
||||||
|
/// \param str the cstring to convert
|
||||||
|
path(const cstring& str)
|
||||||
|
: _str(str) {
|
||||||
|
if (str.size() > 2 && str[str.size() - 1] == '/') {
|
||||||
|
_str = _str.substring(0, str.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Conversion Constructor
|
||||||
|
/// \param str the string to convert
|
||||||
|
path(const string& str)
|
||||||
|
: _str(str) {
|
||||||
|
if (str.size() > 2 && str[str.size() - 1] == '/') {
|
||||||
|
_str = _str.substring(0, str.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Path Copy Constructor
|
||||||
|
/// \param p the path to copy
|
||||||
|
path(const path& p)
|
||||||
|
: _str(p._str) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Path Move Constructor
|
||||||
|
/// \param p the path to take ownership of
|
||||||
|
path(path&& p) noexcept : _str(move(p._str)) { }
|
||||||
|
|
||||||
|
|
||||||
|
// Assignment Operators ================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C-String Assignment Operator
|
||||||
|
/// \param str the cstring to assign
|
||||||
|
/// \returns a reference to `this` after assigning `p`
|
||||||
|
template<size_t n>
|
||||||
|
path& operator=(const char (&str)[n]) {
|
||||||
|
_str = str;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C-String Assignment Operator
|
||||||
|
/// \param p the cstring to assign
|
||||||
|
/// \returns a reference to `this` after assigning `p`
|
||||||
|
path& operator=(const cstring& p) {
|
||||||
|
_str = p;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Assignment Operator
|
||||||
|
/// \param p the cstring to assign
|
||||||
|
/// \returns a reference to `this` after assigning `p`
|
||||||
|
path& operator=(const string& p) {
|
||||||
|
_str = p;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Path Copy Assignment Operator
|
||||||
|
/// \param p the path to copy
|
||||||
|
/// \returns a reference to `this` after copying `p`
|
||||||
|
path& operator=(const path& p) {
|
||||||
|
_str = p._str;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Path Move Assignment Operator
|
||||||
|
/// \param p the path to take ownership of
|
||||||
|
/// \returns a reference to `this` after taking ownership of `p`
|
||||||
|
path& operator=(path&& p) noexcept {
|
||||||
|
_str = move(p._str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Append Operators ====================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief
|
||||||
|
/// \param str
|
||||||
|
/// \return
|
||||||
|
path operator/(const cstring& str) const {
|
||||||
|
return path(_str + '/' + str);
|
||||||
|
}
|
||||||
|
|
||||||
|
path operator/(const string& str) const {
|
||||||
|
return path(_str + '/' + str);
|
||||||
|
}
|
||||||
|
|
||||||
|
path operator/(const path& p) const {
|
||||||
|
return path(_str + '/' + p._str);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const path& p) const {
|
||||||
|
return _str == p._str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string& str() const { return _str; }
|
||||||
|
const char* cstr() const { return _str.cstr(); }
|
||||||
|
|
||||||
|
bool empty() {
|
||||||
|
size_t size = _str.size();
|
||||||
|
if (size == 0) return true;
|
||||||
|
#if FENNEC_PLATFORM_WINDOWS
|
||||||
|
return (_str[1] == ':' && size == 3);
|
||||||
|
#else
|
||||||
|
return (_str[0] == '/' && size == 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
path parent() const {
|
||||||
|
#ifdef FENNEC_PLATFORM_WINDOWS
|
||||||
|
size_t start = _str.size() - 1;
|
||||||
|
start = _str[start] == '/' || _str[start] == '\\' ? start - 1 : start;
|
||||||
|
|
||||||
|
size_t r = _str.rfind('/', start);
|
||||||
|
size_t l = _str.rfind('\\', start);
|
||||||
|
if (r == _str.size()) {
|
||||||
|
start = l;
|
||||||
|
}
|
||||||
|
else if (l == _str.size()) {
|
||||||
|
start = r;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
start = max(r, l);
|
||||||
|
}
|
||||||
|
return _str.substring(0, start);
|
||||||
|
#else
|
||||||
|
size_t start = _str.size() - 1;
|
||||||
|
start = _str[start] == '/' ? start - 1 : start;
|
||||||
|
return path(_str.substring(0, _str.rfind('/', start)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
path absolute() const {
|
||||||
|
path parse = *this;
|
||||||
|
path working; working._str.resize(0);
|
||||||
|
|
||||||
|
// Check if this is a rooted path;
|
||||||
|
#ifdef FENNEC_PLATFORM_WINDOWS
|
||||||
|
if (_str[1] != ':') {
|
||||||
|
#else
|
||||||
|
if (_str[0] != '/') {
|
||||||
|
#endif
|
||||||
|
working = current();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (not parse.empty()) {
|
||||||
|
// Handle dots
|
||||||
|
while (not parse.empty() && parse._str[0] == '.') {
|
||||||
|
// Check for ".."
|
||||||
|
if (parse._str[1] == '.') {
|
||||||
|
// ".."
|
||||||
|
if (parse._str.size() == 2) {
|
||||||
|
parse = path();
|
||||||
|
working = working.parent();
|
||||||
|
}
|
||||||
|
// "../"
|
||||||
|
else if (parse._str[2] == '/') {
|
||||||
|
working = working.parent();
|
||||||
|
parse._str = parse._str.substring(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// "./"
|
||||||
|
else if (parse._str[1] == '/') {
|
||||||
|
parse._str = parse._str.substring(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse.empty()) break;
|
||||||
|
|
||||||
|
// Push the path
|
||||||
|
const size_t loc = parse._str.find('/');
|
||||||
|
working._str += '/';
|
||||||
|
working._str += parse._str.substring(0, loc);
|
||||||
|
parse._str = parse._str.substring(loc + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return working;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
string _str;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_IO_PATH_H
|
||||||
351
include/fennec/langproc/strings/cstring.h
Normal file
351
include/fennec/langproc/strings/cstring.h
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
|
#include <fennec/memory/detail/_string.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
#include <fennec/math/common.h>
|
||||||
|
#include <fennec/memory/bytes.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
|
||||||
|
using ::isalnum;
|
||||||
|
using ::isalpha;
|
||||||
|
using ::islower;
|
||||||
|
using ::isupper;
|
||||||
|
using ::isdigit;
|
||||||
|
using ::isxdigit;
|
||||||
|
using ::iscntrl;
|
||||||
|
using ::isgraph;
|
||||||
|
using ::isspace;
|
||||||
|
using ::isblank;
|
||||||
|
using ::isprint;
|
||||||
|
using ::ispunct;
|
||||||
|
|
||||||
|
using ::tolower;
|
||||||
|
using ::toupper;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief This struct wraps c-style strings
|
||||||
|
///
|
||||||
|
/// \details Requires that the string is null-terminated.
|
||||||
|
/// Prevents const qualified memory blocks from being manipulated.
|
||||||
|
/// This struct should be used when fennec::string would make unnecessary dynamic buffers.
|
||||||
|
struct cstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes with nullptr
|
||||||
|
constexpr cstring()
|
||||||
|
: _str(nullptr), _size(0), _const(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes with nullptr
|
||||||
|
constexpr cstring(nullptr_t)
|
||||||
|
: _str(nullptr), _size(0), _const(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \param n the number of characters in the buffer plus the null terminator
|
||||||
|
constexpr cstring(char* str, size_t n)
|
||||||
|
: _str(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(false) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \tparam n the number of characters in the buffer plus the null terminator
|
||||||
|
template<size_t n>
|
||||||
|
constexpr cstring(char(&str)[n])
|
||||||
|
: _str(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(false) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \param n the number of characters in the buffer plus the null terminator
|
||||||
|
constexpr cstring(const char* str, size_t n)
|
||||||
|
: _cstr(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(true) {
|
||||||
|
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \tparam n the number of characters in the buffer plus the null terminator
|
||||||
|
template<size_t n>
|
||||||
|
constexpr cstring(const char(&str)[n])
|
||||||
|
: _cstr(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(true) {
|
||||||
|
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor
|
||||||
|
/// \param str object to move
|
||||||
|
constexpr cstring(cstring&& str) noexcept
|
||||||
|
: _cstr(str._cstr)
|
||||||
|
, _size(str._size)
|
||||||
|
, _const(str._const) {
|
||||||
|
str._cstr = nullptr;
|
||||||
|
str._size = 0;
|
||||||
|
str._const = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
constexpr cstring(const cstring&) = delete;
|
||||||
|
constexpr ~cstring() = default;
|
||||||
|
|
||||||
|
constexpr cstring& operator=(nullptr_t) {
|
||||||
|
_str = nullptr, _size = 0, _const = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
template<size_t n>
|
||||||
|
constexpr cstring& operator=(char(&str)[n]) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
_str = str, _size = n - 1, _const = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
template<size_t n>
|
||||||
|
constexpr cstring& operator=(const char(&str)[n]) {
|
||||||
|
assert(str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
_cstr = str; _size = n - 1; _const = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
constexpr cstring& operator=(cstring&& str) noexcept {
|
||||||
|
_cstr = str._cstr; str._cstr = nullptr;
|
||||||
|
_size = str._size; str._size = 0;
|
||||||
|
_const = str._const; str._const = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||||
|
constexpr size_t size() const { return _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
|
||||||
|
constexpr size_t capacity() const { return _size + 1; }
|
||||||
|
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _cstr == nullptr || _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a reference to the character
|
||||||
|
constexpr char& operator[](size_t i) {
|
||||||
|
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
|
||||||
|
assertd(i < size(), "Array Out of Bounds");
|
||||||
|
return _str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const-Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a copy of the character
|
||||||
|
constexpr char operator[](size_t i) const {
|
||||||
|
assertd(i < size(), "Array Out of Bounds");
|
||||||
|
return _cstr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Access
|
||||||
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
|
constexpr char* data() {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Access
|
||||||
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
|
constexpr const char* data() const {
|
||||||
|
return _cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Implicit Dereference Cast
|
||||||
|
constexpr operator const char*() const {
|
||||||
|
return _cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Examination =========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The length of the string to the first null-terminator
|
||||||
|
constexpr size_t length() const {
|
||||||
|
return find('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Comparison
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \param n the number of characters to compare
|
||||||
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
|
/// current locale, otherwise a positive value.
|
||||||
|
constexpr int compare(const cstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
|
if (i >= _size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = min(n, max(_size, str._size) + 1);
|
||||||
|
return ::strncmp(_cstr + i, str, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Equality
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \returns True if all characters are equal, false otherwise
|
||||||
|
template<size_t n>
|
||||||
|
constexpr bool operator==(const char (&str)[n]) const {
|
||||||
|
return compare(cstring(str)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Equality
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \returns True if all characters are equal, false otherwise
|
||||||
|
constexpr bool operator==(const cstring& str) const {
|
||||||
|
return compare(str) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||||
|
/// \param c the character to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(char c, size_t i = 0) const {
|
||||||
|
if (i >= _size) { // bounds check
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* loc = ::strchr(_cstr + i, c); // get location using strchr
|
||||||
|
return loc ? loc - _cstr : _size; // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(const cstring& str, size_t i = 0) const {
|
||||||
|
if (i + str._size > _size) { // bounds check
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* loc = ::strstr(_cstr + i, str); // get location using strstr
|
||||||
|
return loc ? loc - _cstr : _size; // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||||
|
/// \param c the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(char c, size_t i = npos) const {
|
||||||
|
if (_size == 0) {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = min(i, _size - 1); // clamp i to bounds
|
||||||
|
do {
|
||||||
|
if (_cstr[i] == c) return i; // loop backwards looking for c
|
||||||
|
} while (i--);
|
||||||
|
return _size; // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(const cstring& str, size_t i = npos) const {
|
||||||
|
if (_size == 0) {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char first = str[0];
|
||||||
|
i = min(i, _size - str._size);
|
||||||
|
do {
|
||||||
|
if(_cstr[i] == first) {
|
||||||
|
if (compare(str, i, str._size - 1) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} // loop backwards looking for str
|
||||||
|
} while (i--);
|
||||||
|
return _size; // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union { // hack to allow both const qualified and non-const strings
|
||||||
|
char* _str;
|
||||||
|
const char* _cstr;
|
||||||
|
};
|
||||||
|
size_t _size;
|
||||||
|
bool _const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<cstring> : hash<byte_array> {
|
||||||
|
constexpr size_t operator()(const cstring& str) const {
|
||||||
|
return hash<byte_array>::operator()(byte_array(str, str.size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||||
25
include/fennec/langproc/strings/detail/_ctype.h
Normal file
25
include/fennec/langproc/strings/detail/_ctype.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
24
include/fennec/langproc/strings/detail/_locale.h
Normal file
24
include/fennec/langproc/strings/detail/_locale.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
44
include/fennec/langproc/strings/locale.h
Normal file
44
include/fennec/langproc/strings/locale.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/detail/_locale.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
enum locale : int
|
||||||
|
{
|
||||||
|
lc_all = LC_ALL
|
||||||
|
, lc_collate = LC_COLLATE
|
||||||
|
, lc_ctype = LC_CTYPE
|
||||||
|
, lc_monetary = LC_MONETARY
|
||||||
|
, lc_numeric = LC_NUMERIC
|
||||||
|
, lc_time = LC_TIME
|
||||||
|
};
|
||||||
|
|
||||||
|
using ::lconv;
|
||||||
|
|
||||||
|
using ::setlocale;
|
||||||
|
using ::localeconv;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||||
437
include/fennec/langproc/strings/string.h
Normal file
437
include/fennec/langproc/strings/string.h
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_STRING_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_STRING_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
|
#include <fennec/langproc/strings/cstring.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
#include <fennec/memory/common.h>
|
||||||
|
|
||||||
|
#include <fennec/math/common.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward def
|
||||||
|
template<typename AllocT = allocator<char>> struct _string;
|
||||||
|
|
||||||
|
// Alias for default allocator
|
||||||
|
using string = _string<>;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Struct for wrapping c-style strings
|
||||||
|
///
|
||||||
|
/// \details behaviour guarantees that the underlying string is null-terminated
|
||||||
|
template<typename AllocT>
|
||||||
|
struct _string
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
using alloc_t = allocation<char, AllocT>;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty string
|
||||||
|
constexpr _string()
|
||||||
|
: _str() {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
|
||||||
|
/// \param n the number of characters
|
||||||
|
/// \param c the character to fill with
|
||||||
|
///
|
||||||
|
/// \details adds additional character for null termination.
|
||||||
|
constexpr _string(size_t n, char c = '\0')
|
||||||
|
: _str(n + 1) {
|
||||||
|
fennec::memset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string(const alloc_t& alloc)
|
||||||
|
: _str(alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string(size_t n, char c, const alloc_t& alloc)
|
||||||
|
: _str(n + 1, alloc) {
|
||||||
|
fennec::memset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string(const cstring& cstr)
|
||||||
|
: _str(cstr, cstr.size() + 1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \tparam n the number of characters in the buffer including the null-terminator, if present
|
||||||
|
template<size_t n>
|
||||||
|
explicit constexpr _string(const char (&str)[n])
|
||||||
|
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
||||||
|
fennec::memcpy(_str, str, n);
|
||||||
|
if (str[n - 1] != '\0') {
|
||||||
|
_str[n] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \param n the number of characters in the buffer including the null-terminator, if present
|
||||||
|
constexpr _string(const char* buf, size_t n)
|
||||||
|
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
|
||||||
|
fennec::memcpy(_str, buf, n);
|
||||||
|
if (buf[n - 1] != '\0') {
|
||||||
|
_str[n] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Copy Constructor
|
||||||
|
/// \param str the string to copy
|
||||||
|
constexpr _string(const _string& str) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Move Constructor
|
||||||
|
/// \param str the string to take ownership of
|
||||||
|
constexpr _string(_string&& str) noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, cleans up underlying allocation
|
||||||
|
constexpr ~_string() = default;
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
constexpr _string& operator=(const cstring& cstr) {
|
||||||
|
_str.callocate(cstr.capacity());
|
||||||
|
fennec::memcpy(_str, cstr, cstr.capacity());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string& operator=(const _string& str) = default;
|
||||||
|
constexpr _string& operator=(_string&& str) noexcept = default;
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the string excluding null terminator
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _str.capacity() > 0 ? _str.capacity() - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the string including null terminator
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _str.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a reference to the character
|
||||||
|
constexpr char& operator[](size_t i) {
|
||||||
|
return _str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const-Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a copy of the character
|
||||||
|
constexpr const char& operator[](size_t i) const {
|
||||||
|
return _str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char* data() {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char* data() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char* cstr() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examination =========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The length of the string to the first null-terminator
|
||||||
|
constexpr size_t length() const {
|
||||||
|
return find('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Comparison
|
||||||
|
/// \param ostr the string to compare against
|
||||||
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
|
/// current locale, otherwise a positive value.
|
||||||
|
constexpr int compare(const cstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
||||||
|
|
||||||
|
return ::strncmp(_str + i, str, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Comparison
|
||||||
|
/// \param ostr the string to compare against
|
||||||
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
|
/// current locale, otherwise a positive value.
|
||||||
|
constexpr int compare(const string& str, size_t i = 0, size_t n = npos) const {
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = min(n, max(size(), str.size()) + 1);
|
||||||
|
|
||||||
|
return ::strncmp(_str + i, str.data(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const _string& str) const {
|
||||||
|
return compare(str) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||||
|
/// \param c the character to find
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(char c, size_t i = 0) const {
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* loc = ::strchr(_str + i, c); // get location using strchr
|
||||||
|
return loc ? loc - _str : size(); // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(const string& str, size_t i = 0) const { // bounds check
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* loc = ::strstr(_str, str);
|
||||||
|
return loc ? loc - _str : size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(const cstring& str, size_t i = 0) const {
|
||||||
|
if (i + str.size() > size()) { // bounds check
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* loc = ::strstr(_str + i, str); // get location using strstr
|
||||||
|
return loc ? loc - _str : size(); // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||||
|
/// \param c the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(char c, size_t i = npos) const {
|
||||||
|
if (size() == 0) {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
i = min(i, size() - 1); // clamp i to bounds
|
||||||
|
do {
|
||||||
|
if (_str[i] == c) { // loop backwards looking for c
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} while (i--);
|
||||||
|
return size(); // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(const cstring& str, size_t i = npos) const {
|
||||||
|
if (size() == 0) {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
const char first = str[0];
|
||||||
|
i = min(i, size() - str.size());
|
||||||
|
do {
|
||||||
|
if(_str[i] == first) {
|
||||||
|
if (compare(str, i) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (i--);
|
||||||
|
return size(); // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(const string& str, size_t i = npos) const {
|
||||||
|
if (size() == 0) {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
const char first = str[0];
|
||||||
|
i = min(i, size() - str.size());
|
||||||
|
do {
|
||||||
|
if(_str[i] == first) {
|
||||||
|
if (compare(str, i) == 0) { // loop backwards looking for str
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (i--);
|
||||||
|
return size(); // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Retrieve a substring of a string
|
||||||
|
/// \param i the start index
|
||||||
|
/// \param n the number of characters
|
||||||
|
/// \return
|
||||||
|
constexpr _string substring(size_t i, size_t n = npos) const {
|
||||||
|
if (i >= size()) {
|
||||||
|
return _string("");
|
||||||
|
}
|
||||||
|
n = fennec::min(n, size() - i);
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(n + 1);
|
||||||
|
fennec::memcpy(res.data(), _str + i, n);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
constexpr void resize(size_t n) {
|
||||||
|
_str.creallocate(n + 1);
|
||||||
|
_str[size()] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string operator+(char c) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _string(1, c);
|
||||||
|
}
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(capacity() + 1);
|
||||||
|
fennec::memcpy(res.data(), _str, size());
|
||||||
|
res[size()] = c;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr _string operator+(char c, const _string& str) {
|
||||||
|
_string res(1, c);
|
||||||
|
return res += str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string operator+(const cstring& cstr) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _string(cstr);
|
||||||
|
}
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(size() + cstr.size() + 1);
|
||||||
|
fennec::memcpy(res.data(), _str, size());
|
||||||
|
fennec::memcpy(res.data() + size(), cstr, cstr.size());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string operator+(const _string& str) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _string(str);
|
||||||
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
|
return _string(*this);
|
||||||
|
}
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(size() + str.size() + 1);
|
||||||
|
fennec::memcpy(res.data(), _str, size());
|
||||||
|
fennec::memcpy(res.data() + size(), str.data(), str.size());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string& operator+=(char c) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
_str.callocate(2);
|
||||||
|
_str[0] = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
_str.creallocate(capacity() + 1);
|
||||||
|
_str[size() - 1] = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string& operator+=(const cstring& cstr) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return *this = cstr;
|
||||||
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + cstr.size() + 1);
|
||||||
|
fennec::memcpy(_str + middle, cstr, cstr.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string& operator+=(const _string& str) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return *this = str;
|
||||||
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + str.size() + 1);
|
||||||
|
fennec::memcpy(_str + middle, str.data(), str.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
alloc_t _str;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<string> : hash<byte_array> {
|
||||||
|
constexpr size_t operator()(const string& str) const {
|
||||||
|
return hash<byte_array>::operator()(byte_array(str.data(), str.size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_STRING_H
|
||||||
353
include/fennec/langproc/strings/wcstring.h
Normal file
353
include/fennec/langproc/strings/wcstring.h
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
|
#include <fennec/memory/detail/_string.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
#include <fennec/math/common.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
|
||||||
|
using ::iswalnum;
|
||||||
|
using ::iswalpha;
|
||||||
|
using ::iswlower;
|
||||||
|
using ::iswupper;
|
||||||
|
using ::iswdigit;
|
||||||
|
using ::iswxdigit;
|
||||||
|
using ::iswcntrl;
|
||||||
|
using ::iswgraph;
|
||||||
|
using ::iswspace;
|
||||||
|
using ::iswblank;
|
||||||
|
using ::iswprint;
|
||||||
|
using ::iswpunct;
|
||||||
|
|
||||||
|
using ::towlower;
|
||||||
|
using ::towupper;
|
||||||
|
|
||||||
|
using ::towctrans;
|
||||||
|
using ::wctrans;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief This struct wraps c-style strings
|
||||||
|
///
|
||||||
|
/// \details Requires that the string is null-terminated.
|
||||||
|
/// Prevents const qualified memory blocks from being manipulated.
|
||||||
|
/// This struct should be used when fennec::string would make unnecessary dynamic buffers.
|
||||||
|
struct wcstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes with nullptr
|
||||||
|
constexpr wcstring()
|
||||||
|
: _str(nullptr), _size(0), _const(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes with nullptr
|
||||||
|
constexpr wcstring(nullptr_t)
|
||||||
|
: _str(nullptr), _size(0), _const(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \param n the number of characters in the buffer plus the null terminator
|
||||||
|
constexpr wcstring(wchar_t* str, size_t n)
|
||||||
|
: _str(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(false) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \tparam n the number of characters in the buffer plus the null terminator
|
||||||
|
template<size_t n>
|
||||||
|
constexpr wcstring(wchar_t (&str)[n])
|
||||||
|
: _str(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(false) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \param n the number of characters in the buffer plus the null terminator
|
||||||
|
constexpr wcstring(const wchar_t* str, size_t n)
|
||||||
|
: _cstr(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(true) {
|
||||||
|
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \tparam n the number of characters in the buffer plus the null terminator
|
||||||
|
template<size_t n>
|
||||||
|
constexpr wcstring(const wchar_t (&str)[n])
|
||||||
|
: _cstr(str)
|
||||||
|
, _size(n - 1)
|
||||||
|
, _const(true) {
|
||||||
|
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor
|
||||||
|
/// \param str object to move
|
||||||
|
constexpr wcstring(wcstring&& str) noexcept
|
||||||
|
: _cstr(str._cstr)
|
||||||
|
, _size(str._size)
|
||||||
|
, _const(str._const) {
|
||||||
|
str._cstr = nullptr;
|
||||||
|
str._size = 0;
|
||||||
|
str._const = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
constexpr wcstring(const wcstring&) = delete;
|
||||||
|
constexpr ~wcstring() = default;
|
||||||
|
|
||||||
|
constexpr wcstring& operator=(nullptr_t) {
|
||||||
|
_str = nullptr, _size = 0, _const = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
template<size_t n>
|
||||||
|
constexpr wcstring& operator=(wchar_t(&str)[n]) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
_str = str, _size = n - 1, _const = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
template<size_t n>
|
||||||
|
constexpr wcstring& operator=(const wchar_t(&str)[n]) {
|
||||||
|
assert(str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
_cstr = str; _size = n - 1; _const = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
constexpr wcstring& operator=(wcstring&& str) noexcept {
|
||||||
|
_cstr = str._cstr; str._cstr = nullptr;
|
||||||
|
_size = str._size; str._size = 0;
|
||||||
|
_const = str._const; str._const = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||||
|
constexpr size_t size() const { return _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
|
||||||
|
constexpr size_t capacity() const { return _size + 1; }
|
||||||
|
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _cstr == nullptr || _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a reference to the character
|
||||||
|
constexpr wchar_t& operator[](size_t i) {
|
||||||
|
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
|
||||||
|
assertd(i < size(), "Array Out of Bounds");
|
||||||
|
return _str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const-Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a copy of the character
|
||||||
|
constexpr const wchar_t& operator[](size_t i) const {
|
||||||
|
assertd(i < size(), "Array Out of Bounds");
|
||||||
|
return _cstr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Access
|
||||||
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
|
constexpr wchar_t* data() {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Access
|
||||||
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
|
constexpr const wchar_t* data() const {
|
||||||
|
return _cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Implicit Dereference Cast
|
||||||
|
constexpr operator const wchar_t*() const {
|
||||||
|
return _cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Examination =========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The length of the string to the first null-terminator
|
||||||
|
constexpr size_t length() const {
|
||||||
|
return find('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Comparison
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \param n the number of characters to compare
|
||||||
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
|
/// current locale, otherwise a positive value.
|
||||||
|
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
|
if (i >= _size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = min(n, max(_size, str._size) + 1);
|
||||||
|
return ::wcsncmp(_cstr + i, str, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Equality
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \returns True if all characters are equal, false otherwise
|
||||||
|
template<size_t n>
|
||||||
|
constexpr bool operator==(const wchar_t (&str)[n]) const {
|
||||||
|
return compare(wcstring(str)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Equality
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \returns True if all characters are equal, false otherwise
|
||||||
|
constexpr bool operator==(const wcstring& str) const {
|
||||||
|
return compare(str) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||||
|
/// \param c the character to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(wchar_t c, size_t i = 0) const {
|
||||||
|
if (i >= _size) { // bounds check
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* loc = ::wcschr(_cstr + i, c); // get location using strchr
|
||||||
|
return loc ? loc - _cstr : _size; // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(const wcstring& str, size_t i = 0) const {
|
||||||
|
if (i + str._size > _size) { // bounds check
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* loc = ::wcsstr(_cstr + i, str); // get location using strstr
|
||||||
|
return loc ? loc - _cstr : _size; // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||||
|
/// \param c the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(char c, size_t i = npos) const {
|
||||||
|
if (_size == 0) {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = min(i, _size - 1); // clamp i to bounds
|
||||||
|
do {
|
||||||
|
if (_cstr[i] == c) return i; // loop backwards looking for c
|
||||||
|
} while (i--);
|
||||||
|
return _size; // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
|
||||||
|
if (_size == 0) {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char first = str[0];
|
||||||
|
i = min(i, _size - str._size);
|
||||||
|
do {
|
||||||
|
if(_cstr[i] == first) {
|
||||||
|
if (compare(str, i, str._size - 1) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} // loop backwards looking for str
|
||||||
|
} while (i--);
|
||||||
|
return _size; // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union { // hack to allow both const qualified and non-const strings
|
||||||
|
wchar_t* _str;
|
||||||
|
const wchar_t* _cstr;
|
||||||
|
};
|
||||||
|
size_t _size;
|
||||||
|
bool _const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<wcstring> : hash<byte_array> {
|
||||||
|
constexpr size_t operator()(const wcstring& str) const {
|
||||||
|
return hash<byte_array>::operator()(byte_array(str, str.size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||||
437
include/fennec/langproc/strings/wstring.h
Normal file
437
include/fennec/langproc/strings/wstring.h
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||||
|
#define FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||||
|
|
||||||
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
|
#include <fennec/langproc/strings/wcstring.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
#include <fennec/memory/common.h>
|
||||||
|
|
||||||
|
#include <fennec/math/common.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward def
|
||||||
|
template<typename AllocT = allocator<wchar_t>> struct _wstring;
|
||||||
|
|
||||||
|
// Alias for default allocator
|
||||||
|
using wstring = _wstring<>;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Struct for wrapping c-style strings
|
||||||
|
///
|
||||||
|
/// \details behaviour guarantees that the underlying string is null-terminated
|
||||||
|
template<typename AllocT>
|
||||||
|
struct _wstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
using alloc_t = allocation<wchar_t, AllocT>;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty string
|
||||||
|
constexpr _wstring()
|
||||||
|
: _str() {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
|
||||||
|
/// \param n the number of wchar_tacters
|
||||||
|
/// \param c the wchar_tacter to fill with
|
||||||
|
///
|
||||||
|
/// \details adds additional wchar_tacter for null termination.
|
||||||
|
constexpr _wstring(size_t n, wchar_t c = '\0')
|
||||||
|
: _str(n + 1) {
|
||||||
|
fennec::wmemset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring(const alloc_t& alloc)
|
||||||
|
: _str(alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring(size_t n, wchar_t c, const alloc_t& alloc)
|
||||||
|
: _str(n + 1, alloc) {
|
||||||
|
fennec::wmemset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring(const wcstring& cstr)
|
||||||
|
: _str(cstr, cstr.size() + 1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \tparam n the number of wchar_tacters in the buffer including the null-terminator, if present
|
||||||
|
template<size_t n>
|
||||||
|
explicit constexpr _wstring(const wchar_t (&str)[n])
|
||||||
|
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
||||||
|
fennec::wmemcpy(_str, str, n);
|
||||||
|
if (str[n - 1] != '\0') {
|
||||||
|
_str[n] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
|
/// \param str the buffer to wrap
|
||||||
|
/// \param n the number of wchar_tacters in the buffer including the null-terminator, if present
|
||||||
|
constexpr _wstring(const wchar_t* buf, size_t n)
|
||||||
|
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
|
||||||
|
fennec::wmemcpy(_str, buf, n);
|
||||||
|
if (buf[n - 1] != '\0') {
|
||||||
|
_str[n] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Copy Constructor
|
||||||
|
/// \param str the string to copy
|
||||||
|
constexpr _wstring(const _wstring& str) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Move Constructor
|
||||||
|
/// \param str the string to take ownership of
|
||||||
|
constexpr _wstring(_wstring&& str) noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, cleans up underlying allocation
|
||||||
|
constexpr ~_wstring() = default;
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
constexpr _wstring& operator=(const wcstring& cstr) {
|
||||||
|
_str.callocate(cstr.capacity());
|
||||||
|
fennec::wmemcpy(_str, cstr, cstr.capacity());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring& operator=(const _wstring& str) = default;
|
||||||
|
constexpr _wstring& operator=(_wstring&& str) noexcept = default;
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the string excluding null terminator
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _str.capacity() > 0 ? _str.capacity() - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the string including null terminator
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _str.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a reference to the wchar_tacter
|
||||||
|
constexpr wchar_t& operator[](size_t i) {
|
||||||
|
return _str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const-Array Access Operator
|
||||||
|
/// \param i the index to access
|
||||||
|
/// \returns a copy of the wchar_tacter
|
||||||
|
constexpr const wchar_t& operator[](size_t i) const {
|
||||||
|
return _str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr wchar_t* data() {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const wchar_t* data() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const wchar_t* cstr() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examination =========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The length of the string to the first null-terminator
|
||||||
|
constexpr size_t length() const {
|
||||||
|
return find('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Comparison
|
||||||
|
/// \param ostr the string to compare against
|
||||||
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
|
/// current locale, otherwise a positive value.
|
||||||
|
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
||||||
|
|
||||||
|
return ::wcsncmp(_str + i, str, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Comparison
|
||||||
|
/// \param ostr the string to compare against
|
||||||
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
|
/// current locale, otherwise a positive value.
|
||||||
|
constexpr int compare(const _wstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = min(n, max(size(), str.size()) + 1);
|
||||||
|
|
||||||
|
return ::wcsncmp(_str + i, str.data(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const _wstring& str) const {
|
||||||
|
return compare(str) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||||
|
/// \param c the wchar_tacter to find
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(wchar_t c, size_t i = 0) const {
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* loc = ::wcschr(_str + i, c); // get location using strchr
|
||||||
|
return loc ? loc - _str : size(); // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(const _wstring& str, size_t i = 0) const { // bounds check
|
||||||
|
if (i >= size()) { // bounds check
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* loc = ::wcsstr(_str, str);
|
||||||
|
return loc ? loc - _str : size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t find(const wcstring& str, size_t i = 0) const {
|
||||||
|
if (i + str.size() > size()) { // bounds check
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* loc = ::wcsstr(_str + i, str); // get location using strstr
|
||||||
|
return loc ? loc - _str : size(); // return size if not found
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||||
|
/// \param c the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(wchar_t c, size_t i = npos) const {
|
||||||
|
if (size() == 0) {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
i = min(i, size() - 1); // clamp i to bounds
|
||||||
|
do {
|
||||||
|
if (_str[i] == c) { // loop backwards looking for c
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} while (i--);
|
||||||
|
return size(); // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
|
||||||
|
if (size() == 0) {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
const wchar_t first = str[0];
|
||||||
|
i = min(i, size() - str.size());
|
||||||
|
do {
|
||||||
|
if(_str[i] == first) {
|
||||||
|
if (compare(str, i) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (i--);
|
||||||
|
return size(); // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||||
|
/// \param str the string to find
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
|
constexpr size_t rfind(const string& str, size_t i = npos) const {
|
||||||
|
if (size() == 0) {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
const wchar_t first = str[0];
|
||||||
|
i = min(i, size() - str.size());
|
||||||
|
do {
|
||||||
|
if(_str[i] == first) {
|
||||||
|
if (compare(str, i) == 0) { // loop backwards looking for str
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (i--);
|
||||||
|
return size(); // base case
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Retrieve a substring of a string
|
||||||
|
/// \param i the start index
|
||||||
|
/// \param n the number of wchar_tacters
|
||||||
|
/// \return
|
||||||
|
constexpr _wstring substring(size_t i, size_t n = npos) const {
|
||||||
|
if (i >= size()) {
|
||||||
|
return _wstring("");
|
||||||
|
}
|
||||||
|
n = fennec::min(n, size() - i);
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(n + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str + i, n);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
constexpr void resize(size_t n) {
|
||||||
|
_str.creallocate(n + 1);
|
||||||
|
_str[size()] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring operator+(wchar_t c) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _wstring(1, c);
|
||||||
|
}
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(capacity() + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str, size());
|
||||||
|
res[size()] = c;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr _wstring operator+(wchar_t c, const _wstring& str) {
|
||||||
|
_wstring res(1, c);
|
||||||
|
return res += str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring operator+(const wcstring& cstr) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _wstring(cstr);
|
||||||
|
}
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(size() + cstr.size() + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str, size());
|
||||||
|
fennec::wmemcpy(res.data() + size(), cstr, cstr.size());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring operator+(const _wstring& str) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _wstring(str);
|
||||||
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
|
return _wstring(*this);
|
||||||
|
}
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(size() + str.size() + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str, size());
|
||||||
|
fennec::wmemcpy(res.data() + size(), str.data(), str.size());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring& operator+=(wchar_t c) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
_str.callocate(2);
|
||||||
|
_str[0] = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
_str.creallocate(capacity() + 1);
|
||||||
|
_str[size() - 1] = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring& operator+=(const wcstring& cstr) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return *this = cstr;
|
||||||
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + cstr.size() + 1);
|
||||||
|
fennec::wmemcpy(_str + middle, cstr, cstr.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring& operator+=(const _wstring& str) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return *this = str;
|
||||||
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + str.size() + 1);
|
||||||
|
fennec::wmemcpy(_str + middle, str.data(), str.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
alloc_t _str;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<wstring> : hash<byte_array> {
|
||||||
|
constexpr size_t operator()(const string& str) const {
|
||||||
|
return hash<byte_array>::operator()(byte_array(str.data(), str.size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user