Compare commits

..

35 Commits

Author SHA1 Message Date
520a0e1363 - Setup libdecor, which is used automatically when available.
TODO:
 - xdg decorations
 - threading
 - thread-safe window manager
2025-12-15 23:40:06 -05:00
97f5bbfe00 - Windows now use libdecor when present. 2025-12-15 16:29:00 -05:00
b64ce44d4e - Setup dynamic linking to libdecor 2025-12-15 15:23:45 -05:00
1acf00138a - Setup EGL context for Wayland. Test window now opens as black rectangle. 2025-12-15 13:20:08 -05:00
5dcb58f53c - Setup wayland display and window. Window surface is created and appears in hotbar. Window is not visible. 2025-12-14 15:47:11 -05:00
a1bdc077b1 - fennec::variant & fennec::generic, TODO: Test 2025-12-13 19:00:43 -05:00
9553f9b662 - formatting implemented for floating point types
- fixed some bugs with width and precision specifiers:
    * Evaluation order of nested replacement fields
2025-12-08 12:13:51 -05:00
9645856554 - Refactored fennec::format to use to_chars for ints. floats TODO but will also use to_chars. 2025-12-06 02:19:52 -05:00
a2abb58705 - Fixed header include guards 2025-12-05 10:30:03 -05:00
7f1dd245dc - fennec::format refactor. Strings partially implemented. Integers and bools fully implemented. 2025-12-04 20:39:10 -05:00
6d58105734 - Switched back to custom window management, taking another stab
- Refactored lang yet again, `fennec/lang` is now C++ language. `fennec/string` `fennec/filesystem` and `fennec/format` are now independent.
2025-12-04 01:04:36 -05:00
d928d86014 - Some underlying features for RTTI
- Macro for automatically generating this_t
 - Semantics with static_constructor.h, now FENNEC_PRIVATE_STATIC_CONSTRUCTOR for .cpp files and FENNEC_CLASS_STATIC_CONSTRUCTOR for a class in any source file type.
2025-12-03 01:41:30 -05:00
0b76b06a1b - RTTI properties for types for iterators, indexing, and mapping 2025-11-30 20:58:56 -05:00
6f09c3f7fe - Bug fixing for RTTI
- Fixes for declval + separated into own file
 - is_iterable
 - fixes for doxygen generation
2025-11-29 23:43:18 -05:00
fe8c3a4602 - Basic RTTI type data with inheritance. 2025-11-28 12:58:23 -05:00
b9026ec8da - Adjustments to component system design.
- Added indexed parameters to format strings
2025-10-06 12:47:11 -04:00
7b87828f06 - Adjusted Material/Texture/Lighting outline. 2025-09-29 18:39:14 -04:00
8925b3f2f0 - Refactor on component system to support multiple scenes.
- node2d for 2d scenes
2025-09-25 19:30:08 -04:00
f636feb4f1 - Rough First Pass implementation for format.h
- Started 2D Transform Component and relevant math extensions
 - Switched sequence to use pointers instead of arrays
2025-09-23 18:07:54 -04:00
1a9a80e37f - Some last minute performance improvements I noticed. 2025-09-18 21:56:46 -04:00
18c8171847 - More optimization on fennec::sequence. There are areas that could be improved, but the running time is now within margin. It can be revisited later if this data-structure becomes the focus of a performance critical task. 2025-09-18 21:34:29 -04:00
d546519180 - Fixed rb-tree violations 2025-09-18 08:26:57 -04:00
f208141b5b - Minor performance adjustments 2025-09-17 23:35:48 -04:00
52d6c62f76 Merge branch 'main' of https://git.mslockbo.org/fennec-org/fennec 2025-09-17 17:21:05 -04:00
037e2554a1 - Renamed Doxyfile -> Doxyfile.out 2025-09-17 17:19:52 -04:00
8867576a2e Delete doxy/Doxyfile 2025-09-17 21:17:52 +00:00
788f63d092 - Added generated Doxyfile to .gitignore 2025-09-17 17:16:47 -04:00
a35f2a699d - Fixed some missing and erroneous testing logic for containers
- Lots of bug-fixing for containers
 - Performance optimization for containers
2025-09-17 17:13:52 -04:00
80925965d4 - GCC ARM64 Support, i.e. natively compiled with gcc on arm64 2025-09-15 02:35:34 +00:00
f2a45aa913 - Began outlining tokenizer.h and priority_queue.h
- Began outlining sdl implementation
- Added some helper definitions to various classes
- Added contains to string.h and wstring.h
2025-09-13 20:33:53 -04:00
3565bbbc52 - Fixed some logic errors with assertions for wide vs. byte files.
- Changed getline and getwline to use gets instead of the experimental functions. These, in theory, will be slightly faster.
2025-09-11 16:58:32 -04:00
375492ef7b - "Finished" sequence.h, there's more to do, but the basic functionality is there
- bintree.h is implemented according to the needs of sequence.h at present
2025-08-31 14:38:05 -04:00
dbcb50349d - Binary Tree (Partial)
- Sequence (Partial)
2025-08-30 22:11:41 -04:00
992a02db3e - Changed directory structure significantly, moving gfx api implementations to fennec/renderers
- Began new overarching window interface
 - Began outlining renderer interfaces
 - Began a binary tree implementation in bintree.h, this will act as a generalized binary tree, then red-black tree will be implemented on top of it for sequences (ordered sets)
2025-08-28 00:01:54 -04:00
e1eaf97961 - Switched to SDL for main branch, will revisit custom implementation later. 2025-08-23 20:09:53 -04:00
197 changed files with 11393 additions and 5884 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
/bin/
/lib/
/doxy/README.md
/doxy/Doxyfile.out

View File

@@ -16,21 +16,11 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ======================================================================================================================
cmake_minimum_required(VERSION 3.30)
cmake_minimum_required(VERSION 3.28)
project(fennec)
# External dependencies should be loaded here
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()
@@ -43,6 +33,25 @@ macro(fennec_add_link_libraries)
list(APPEND FENNEC_LINK_LIBRARIES ${ARGN})
endmacro()
macro(fennec_add_shared_libraries)
list(APPEND FENNEC_SHARED_LIBRARIES ${ARGN})
endmacro()
macro(fennec_add_link_options)
list(APPEND FENNEC_PRIVATE_LINK_OPTIONS ${ARGN})
endmacro()
# External dependencies should be loaded here
add_subdirectory(external/cpptrace)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_C_STANDARD 23)
add_custom_target(fennec-dependencies
COMMAND ${CMAKE_COMMAND} -E echo "Running dependencies."
COMMENT "Running dependencies."
)
# include scripts
include("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
@@ -62,7 +71,7 @@ include_directories(${FENNEC_SOURCE_DIR}/include)
# Metaprogramming is a dependency for generating various type info before compilation of the engine.
add_subdirectory(metaprogramming)
# Specify where to send libraries and executables
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})
@@ -75,28 +84,48 @@ add_library(fennec STATIC
# CORE =================================================================================================================
include/fennec/core/engine.h source/core/engine.cpp
include/fennec/core/event.h source/core/event.cpp
include/fennec/core/logger.h source/core/logger.cpp
include/fennec/core/version.h
include/fennec/core/system.h
# SCENE ================================================================================================================
include/fennec/scene/scene.h
include/fennec/scene/scene.h source/scene/scene.cpp
include/fennec/scene/component.h
include/fennec/scene/scene_node.h
include/fennec/scene/node2d.h
include/fennec/scene/forward.h
# RENDERERS ============================================================================================================
include/fennec/renderers/interface/forward.h
include/fennec/renderers/interface/gfxcontext.h
include/fennec/renderers/interface/gfxsubpass.h
include/fennec/renderers/interface/gfxresourcepool.h
# CONTAINERS ===========================================================================================================
include/fennec/containers/containers.h
include/fennec/containers/array.h
include/fennec/containers/bintree.h
include/fennec/containers/bitfield.h
include/fennec/containers/deque.h
include/fennec/containers/dynarray.h
include/fennec/containers/generic.h
include/fennec/containers/graph.h
include/fennec/containers/initializer_list.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/priority_queue.h
include/fennec/containers/rdtree.h
include/fennec/containers/sequence.h
include/fennec/containers/set.h
include/fennec/containers/traversal.h
include/fennec/containers/tuple.h
@@ -106,40 +135,58 @@ add_library(fennec STATIC
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/conditional_types.h
include/fennec/lang/declval.h
include/fennec/lang/hashing.h
include/fennec/lang/intrinsics.h
include/fennec/lang/limits.h
include/fennec/lang/numeric_transforms.h
include/fennec/lang/const_sequences.h
include/fennec/lang/startup.h
include/fennec/lang/metasequences.h
include/fennec/lang/ranges.h
include/fennec/lang/static_constructor.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_transforms.h
include/fennec/lang/typeuuid.h
include/fennec/lang/types.h
include/fennec/lang/utility.h
include/fennec/lang/integer.h
include/fennec/lang/assert.h source/lang/assert.cpp
include/fennec/lang/detail/_bits.h
include/fennec/lang/detail/_declval.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
# RTTI =================================================================================================================
include/fennec/rtti/typeid.h
include/fennec/rtti/type_data.h
include/fennec/rtti/type.h
include/fennec/rtti/enable.h
include/fennec/rtti/forward.h
include/fennec/rtti/typelist.h
include/fennec/rtti/type_registry.h
include/fennec/rtti/singleton.h
include/fennec/rtti/detail/_constants.h
include/fennec/rtti/detail/_this_t.h
include/fennec/rtti/detail/_typeid.h
include/fennec/rtti/detail/_type_name.h
# MEMORY ===============================================================================================================
@@ -184,7 +231,6 @@ add_library(fennec STATIC
include/fennec/math/ext/primes.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
@@ -194,32 +240,56 @@ add_library(fennec STATIC
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
# string ===============================================================================================================
include/fennec/string/locale.h
include/fennec/string/cstring.h
include/fennec/string/string.h
include/fennec/langproc/strings/detail/_ctype.h
include/fennec/string/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
# format ===============================================================================================================
include/fennec/format/format.h
include/fennec/format/format_arg.h
include/fennec/format/formatter.h
include/fennec/format/charconv.h
include/fennec/format/detail/_format.h
source/format/charconv.cpp
# filesystem ===========================================================================================================
include/fennec/filesystem/file.h source/filesystem/file.cpp
include/fennec/filesystem/path.h source/filesystem/path.cpp
# interpret ============================================================================================================
include/fennec/interpret/tokenizer.h
# PLATFORM =============================================================================================================
include/fennec/platform/interface/fwd.h
include/fennec/platform/interface/display_server.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
include/fennec/platform/interface/window.h source/platform/interface/window.cpp
# GRAPHICS =============================================================================================================
include/fennec/gfx3d/mesh_instance.h
# EXTRA SOURCES ========================================================================================================
${FENNEC_EXTRA_SOURCES}
include/fennec/math/ext/rect.h
include/fennec/platform/opengl/egl/error.h
include/fennec/platform/window_manager.h
)
add_dependencies(fennec metaprogramming fennec-dependencies)
@@ -235,10 +305,16 @@ target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not comp
target_link_libraries(fennec PRIVATE
${FENNEC_LINK_LIBRARIES}
${FENNEC_SHARED_LIBRARIES}
cpptrace::cpptrace
)
foreach (_LIB IN ITEMS ${FENNEC_SHARED_LIBRARIES})
add_custom_command(TARGET fennec POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:${_LIB}> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
endforeach ()
# DOXYGEN ==============================================================================================================
@@ -252,7 +328,7 @@ if(DOXYGEN_FOUND)
set(DOXY_EXAMPLES_DIR "${FENNEC_SOURCE_DIR}/examples")
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
set(DOXYGEN_CONFIG_OUT "${FENNEC_SOURCE_DIR}/doxy/Doxyfile.out") # Generated config file from input
configure_file(${DOXYGEN_CONFIG_IN} ${DOXYGEN_CONFIG_OUT} @ONLY) # Execute preprocessing step
message("Doxygen Build Started.")

View File

@@ -49,9 +49,11 @@ Some main areas where the engine strays from the GNU standard includes the follo
* [Section 4.7, Standards for Graphical Interfaces](https://www.gnu.org/prep/standards/html_node/Graphical-Interfaces.html).
fennec provides an implementation for X11, however it does not use the GTK toolkit.
- [Section 6.1, GNU Manuals](https://www.gnu.org/prep/standards/html_node/GNU-Manuals.html)
- [Section 5.1, Formatting Your Source Code](https://www.gnu.org/prep/standards/html_node/index.html).
fennec uses Allman (BSD) for namespaces, otherwise K&R.
* [Section 6.1, GNU Manuals](https://www.gnu.org/prep/standards/html_node/GNU-Manuals.html)
fennec does not use Texinfo and instead uses Doxygen. Otherwise, it follows the other standards of this section.
* [Section 7, The Release Process](https://www.gnu.org/prep/standards/html_node/Managing-Releases.html)
- [Section 7, The Release Process](https://www.gnu.org/prep/standards/html_node/Managing-Releases.html)
fennec follows most of the conventions in this section, however the build system used is CMake and not
Makefile. CMake, although overwhelming at first, is much more friendly to those who are learning build systems for the first time.

View File

@@ -18,6 +18,8 @@
# this script finds the compiler being used
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set(FENNEC_COMPILER "GCC")
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")

View File

@@ -18,8 +18,13 @@
# this script sets flags and variables for gnu and gnu-like compilers
add_compile_options("-mxsave" "-Wall" "-Wextra" "-pedantic" "-Werror")
add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions")
set(FENNEC_PRIVATE_LINK_OPTIONS "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
fennec_add_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]])
fennec_add_definitions(
_GLIBCXX_INCLUDE_NEXT_C_HEADERS=1
FENNEC_COMPILER_GCC=1
FENNEC_NO_INLINE=[[gnu::noinline]]
FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__
)

View File

@@ -16,42 +16,31 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ======================================================================================================================
find_package(OpenGL)
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()
find_package(GLEW REQUIRED)
if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
message(STATUS "Found OpenGL: ${OPENGL_LIBRARIES}")
fennec_add_link_libraries(OpenGL::GL GLEW::GLEW)
fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1)
fennec_add_sources(
include/fennec/renderers/opengl/glcontext.h source/renderers/opengl/glcontext.cpp
)
else()
message(FATAL_ERROR "No Suitable OpenGL implementation found.")
endif()

View File

@@ -21,6 +21,17 @@
# some of this code is based on SDL3's use of wayland-scanner
function(fennec_wayland_get_protocol)
set( _OPTIONS_ARGS )
set( _ONE_VALUE_ARGS )
set( _MULTI_VALUE_ARGS NAMES PATHS )
cmake_parse_arguments(_FINDPROTOCOLS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
find_file(_FINDPROTOCOLS_TEMP NAMES ${_FINDPROTOCOLS_NAMES} PATHS ${_FINDPROTOCOLS_PATHS})
file(COPY ${_FINDPROTOCOLS_TEMP} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
endfunction()
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")
@@ -59,21 +70,18 @@ macro(fennec_check_wayland)
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))
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)
set(WAYLAND_SOURCES_DIR ${FENNEC_SOURCE_DIR}/source/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})
fennec_wayland_get_protocol(NAMES "wayland.xml" PATHS "/usr/share/wayland" "/usr/share/wayland-protocols")
fennec_wayland_get_protocol(NAMES "xdg-shell.xml" PATHS "/usr/share/wayland/stable/xdg-shell" "/usr/share/wayland-protocols/stable/xdg-shell")
# include sub-dependencies
include("${FENNEC_SOURCE_DIR}/cmake/xkb.cmake")
@@ -109,8 +117,13 @@ macro(fennec_check_wayland)
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
include/fennec/platform/linux/wayland/fwd.h
include/fennec/platform/linux/wayland/server.h source/platform/linux/wayland/server.cpp
include/fennec/platform/linux/wayland/window.h source/platform/linux/wayland/window.cpp
# EGL
include/fennec/platform/linux/wayland/egl/context.h source/platform/linux/wayland/egl/context.cpp
include/fennec/platform/linux/wayland/egl/surface.h source/platform/linux/wayland/egl/surface.cpp
)
fennec_add_definitions(
@@ -118,5 +131,38 @@ macro(fennec_check_wayland)
FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"
FENNEC_LIB_WAYLAND_EGL="${WAYLAND_EGL_LIBRARY}"
)
# find libdecor
find_path(
LIBDECOR_INCLUDE_DIR
PATH_SUFFIXES libdecor libdecor-0
NAMES libdecor.h libdecor.h
)
find_library(
LIBDECOR_LIBRARY
PATH_SUFFIXES libdecor libdecor-0
NAMES libdecor.so libdecor-0.so
)
if(LIBDECOR_INCLUDE_DIR AND LIBDECOR_LIBRARY)
message(STATUS "Found libdecor: ${LIBDECOR_LIBRARY}")
fennec_add_definitions(
FENNEC_HAS_LIBDECOR=1
FENNEC_LIB_LIBDECOR="${LIBDECOR_LIBRARY}"
)
include_directories(
${LIBDECOR_INCLUDE_DIR}
)
fennec_add_sources(
include/fennec/platform/linux/wayland/libdecor/sym.h
include/fennec/platform/linux/wayland/libdecor/libdecor.h
include/fennec/platform/linux/wayland/libdecor/loader.h source/platform/linux/wayland/libdecor/loader.cpp
)
endif()
endif()
endmacro()

File diff suppressed because it is too large Load Diff

View File

@@ -1049,7 +1049,8 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
EXCLUDE = "@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/wayland/lib" \
"@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/xkb/lib"
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@@ -2435,8 +2436,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = "FENNEC_SCALAR_TEMPLATE=" \
"FENNEC_VECTOR_TEMPLATE="
PREDEFINED = "FENNEC_DOXYGEN="
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The

67
examples/assert.cpp Normal file
View File

@@ -0,0 +1,67 @@
// =====================================================================================================================
// I release this example code into the public domain
// =====================================================================================================================
// This file contains code that tests the efficiency of the assert macro scheme in
// fennec engine. This is purely looking at the branching aspect and not the private
// assert definition. The code only uses passing values to see any performance overhead
// from the conditional
// This code is based on the example code that cppreference provides at
// https://en.cppreference.com/w/cpp/language/attributes/likely
// To my surprise, the difference between them is negligible.
// Even when n is a crazy number like one billion, there isn't a conclusive difference.
// I checked that it isn't the lambdas, they are optimized out.
// In debug mode, the results are to be expected; release < experimental < control
#include <cassert>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#define assert_c(expression) \
if(not(expression)) { \
std::abort(); \
}
#define assert_e(expression) \
if(not(expression)) [[unlikely]] { \
std::abort(); \
}
#define assert_r(expression) (static_cast<void> (0))
volatile int sink{}; // ensures a side effect
int main() {
auto benchmark = [](auto fun, auto rem) {
srand(0);
const auto start = std::chrono::high_resolution_clock::now();
for (auto size{1ULL}; size != 10'000'000ULL; ++size)
sink = fun(rand());
const std::chrono::duration<double> diff =
std::chrono::high_resolution_clock::now() - start;
std::cout << "Time: " << std::fixed << std::setprecision(6) << diff.count()
<< " sec " << rem << std::endl;
};
benchmark([](int x) {
assert_c(0 <= x && x <= RAND_MAX);
return x;
}, "control");
benchmark([](int x) {
assert_r(0 <= x && x <= RAND_MAX);
return x;
}, "release");
benchmark([](int x) {
assert_e(0 <= x && x <= RAND_MAX);
return x;
}, "experimental");
}

View File

@@ -20,6 +20,7 @@
# GDB CODE =============================================================================================================
import gdb
import gdb.printing
from . import containers
from . import strings

View File

@@ -371,7 +371,7 @@ class RDTreePrinter:
index += ''
index += ''
index += '[{}, {}]'.format(node, i)
index += '[{}]'.format(node)
return index, value
@@ -389,6 +389,200 @@ class RDTreePrinter:
return self.Iterator(self.tree, 0, self.capacity)
# PRIORITY QUEUE =======================================================================================================
class PriorityQueuePrinter:
"""Print a fennec::rdtree"""
class Iterator:
def __init__(self, tree, node, capacity):
self.tree = tree
self.capacity = capacity
self.visit = deque()
self.skip = True
self.visit.append((node, 0, 0, node))
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]
start = self.visit[0][3]
self.visit.popleft()
if node == start and not self.skip:
return self.__next__()
self.skip = False
value = self.tree[node]['_val']['key']
nnext = self.tree[node]['_val']['next']
child = self.tree[node]['_val']['child']
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, start))
if child < self.capacity:
self.visit.appendleft((child, 0, depth + 1, child))
self.skip = True
# ┌ ─ ├ └
if nnext != 18446744073709551615:
index += ''
else:
index += ''
index += ''
index += '[{}]'.format(node)
return index, value
def __init__(self, val):
self.tree = val['_table']['_table']['_alloc']['_data']
self.size = val['_table']['_size']
self.capacity = val['_table']['_table']['_alloc']['_capacity']
self.min = val['_min']
def to_string(self):
if self.size == 0:
return "{ empty }"
return "{ size = " + str(self.size) + " }"
def children(self):
return self.Iterator(self.tree, self.min, self.capacity)
# BINTREE ==============================================================================================================
class BinTreePrinter:
"""Print a fennec::bintree"""
class Iterator:
def __init__(self, tree, node, capacity):
self.tree = tree
self.capacity = capacity
self.visit = deque()
if capacity > 0:
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]
parent = self.tree[node]['parent']
self.visit.popleft()
value = self.tree[node]['value']
left = self.tree[node]['child'][0]
right = self.tree[node]['child'][1]
if right < self.capacity:
self.visit.appendleft((right, 1, depth + 1))
if left < self.capacity:
self.visit.appendleft((left, 0, depth + 1))
index = '' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
if i == 0 and parent != 18446744073709551615 and self.tree[parent]['right'] != 18446744073709551615:
index += ''
else:
index += ''
index += ''
index += '[{}]'.format(node)
return index, value
def __init__(self, val):
self.tree = val['_table']['_data']
self.size = val['_size']
self.root = val['_root']
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, self.root, self.capacity)
# SEQUENCE =============================================================================================================
class SequencePrinter:
"""Print a fennec::sequence"""
class Iterator:
def __init__(self, node):
self.visit = deque()
if node is not None:
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 = node['key']
left = node['child'][0]
right = node['child'][1]
print("it: ", node, " ", left, " ", right);
if right != 0:
self.visit.appendleft((right, 1, depth + 1))
if left != 0:
self.visit.appendleft((left, 0, depth + 1))
index = '' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
if i == 0:
index += ''
else:
index += ''
index += ''
index += '[{}]'.format(node)
return index, value
def __init__(self, val):
self.size = val['_size']
self.root = val['_root']
def to_string(self):
if self.size == 0:
return "{ empty }"
return "{ size = " + str(self.size) + " }"
def children(self):
print("root: ", self.root)
return self.Iterator(self.root)
# Graph ================================================================================================================
class GraphPrinter:
@@ -464,18 +658,21 @@ class GraphPrinter:
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)
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::bintree', '^fennec::bintree<.*>$', BinTreePrinter)
pp.add_printer('fennec::sequence', '^fennec::sequence<.*>$', SequencePrinter)
pp.add_printer('fennec::priority_queue', '^fennec::priority_queue<.*>$', PriorityQueuePrinter)
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
return pp
printer = register_printers()

View File

@@ -24,7 +24,7 @@ from . import utility
class VectorPrinter:
def __init__(self, val):
self.val = val
self.base = val['data']['elements']
self.base = val['data']['data']
self.len = self.base.type.range()[1] + 1
def to_string(self):
@@ -51,7 +51,7 @@ class VectorPrinter:
class QuaternionPrinter:
def __init__(self, val):
self.val = val
self.base = val['data']['elements']
self.base = val['data']['data']
def to_string(self):
res = ("< "
@@ -72,7 +72,7 @@ class QuaternionPrinter:
# VECTOR =================================================================================================================
class MatrixPrinter:
def __init__(self, val):
self.columns = val['data']['elements']
self.columns = val['data']['data']
self.num_columns = self.columns.type.range()[1] + 1
self.num_rows = val.type.template_argument(1)

View File

@@ -34,6 +34,7 @@
#include <fennec/lang/types.h>
#include <fennec/lang/assert.h>
#include <fennec/lang/metasequences.h>
namespace fennec
{
@@ -166,13 +167,13 @@ public:
///
/// \brief Checks if all elements in the arrays are equal
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
return array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
return array::_compare(lhs, rhs, make_index_metasequence<ElemV>{});
}
///
/// \brief Checks if any element in the arrays is not equal
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
return not array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
return not array::_compare(lhs, rhs, make_index_metasequence<ElemV>{});
}
/// @}
@@ -217,7 +218,7 @@ public:
private:
template<size_t...i>
static bool _compare(const array& lhs, const array& rhs, const_index_sequence<i...>) {
static bool _compare(const array& lhs, const array& rhs, index_metasequence<i...>) {
return ((lhs[i] == rhs[i]) && ...);
}
};

View File

@@ -0,0 +1,831 @@
// =====================================================================================================================
// 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 bintree.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_BINTREE_H
#define FENNEC_CONTAINERS_BINTREE_H
#include <fennec/containers/dynarray.h>
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/containers/traversal.h>
#include <fennec/memory/allocator.h>
namespace fennec
{
///
/// \brief Structure defining a binary tree
/// \tparam TypeT The data type
/// \tparam AllocT An allocator class
template<typename TypeT, class AllocT = allocator<TypeT>>
struct bintree {
// Definitions =========================================================================================================
protected:
struct node;
public:
using value_t = TypeT;
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
static constexpr size_t npos = -1;
friend class iterator;
friend class const_iterator;
protected:
struct node {
value_t value;
size_t parent;
size_t child[2];
constexpr node()
: value()
, parent(npos), child{ npos, npos } {
}
template<typename...ArgsT>
constexpr node(size_t p, size_t l, size_t r, ArgsT&&...args)
: value(fennec::forward<ArgsT>(args)...)
, parent(p), child{ l, r } {
}
constexpr ~node() {
parent = npos;
child[0] = npos;
child[1] = npos;
}
size_t& operator[](bool d) {
return child[d];
}
};
using table_t = allocation<node, alloc_t>;
using freed_t = list<size_t, alloc_t>;
// Constructors & Destructor ===========================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Default Constructor, initializes an empty tree
constexpr bintree()
: _table()
, _freed()
, _root(npos)
, _size(0) {
}
///
/// \brief Move Constructor, takes ownership of a tree
/// \param tree The tree to take ownership of
constexpr bintree(bintree&& tree) noexcept
: _table(fennec::move(tree._table))
, _freed(fennec::move(tree._freed))
, _root(tree._root)
, _size(tree._size) {
}
///
/// \brief Copy Constructor, copies a tree
/// \param tree The tree to copy
constexpr bintree(const bintree& tree)
: _table(tree._table)
, _freed(tree._freed)
, _root(tree._root)
, _size(tree._size) {
}
///
/// \brief Destructor, clears the tree
constexpr ~bintree() {
clear();
}
/// @}
// Properties ==========================================================================================================
public:
///
/// \returns The number of elements in the tree
constexpr size_t size() const {
return _size;
}
///
/// \returns `true` when there are no elements in the tree, `false` otherwise.
constexpr bool empty() const {
return _size == 0;
}
///
/// \returns The capacity of the underlying allocation
constexpr size_t capacity() const {
return _table.capacity();
}
///
/// \returns The next id to be returned by `insert` or `emplace`.
constexpr size_t next_id() const {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
}
return i;
}
///
/// \returns The next id to be returned by `insert` or `emplace`.
constexpr size_t root() const {
return _root;
}
// Navigation ==========================================================================================================
public:
/// \name Navigation
/// @{
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The parent of node `i`
constexpr size_t parent(size_t i) const {
return i == npos ? npos : _table[i].parent;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The grandparent of node `i`
constexpr size_t grandparent(size_t i) const {
return parent(parent(i));
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The left child of node `i`
constexpr size_t left(size_t i) const {
return i == npos ? npos : _table[i].child[false];
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The right child of node `i`
constexpr size_t right(size_t i) const {
return i == npos ? npos : _table[i].child[true];
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \param dir The direction to go `true` for right, `false` for left
/// \returns The child in the direction specified by `dir`
constexpr size_t child(size_t i, bool dir) const {
return i == npos ? npos : _table[i].child[dir];
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns `true` if `i` is the right node of `parent(i)`, `false` otherwise
constexpr bool direction(size_t i) const {
return i == npos ? false : i == right(_parent(i));
}
///
/// \brief \f$O(1)\f$
/// \param i The id of the node
/// \returns The id of the sibling of `i`
constexpr size_t sibling(size_t i) const {
if (i == npos) {
return npos;
}
if (i == _root) {
return npos;
}
size_t p = _parent(i);
bool d = i == _right(p);
return _child(p, !d);
}
///
/// \details \f$O(\log n)\f$
/// \param i The node id
/// \returns The depth of node `i`
constexpr size_t depth(size_t i) const {
size_t d = 0;
while (i != npos) {
i = _parent(i);
++d;
}
return d;
}
///
/// \brief \f$O(\log n)\f$
/// \param i The node id
/// \returns The id of the left-most node of `i`
constexpr size_t left_most(size_t i) const {
if (i >= _table.size()) {
return npos;
}
while (_table[i].child[false] != npos) {
i = _table[i].child[false];
}
return i;
}
///
/// \brief \f$O(\log n)\f$
/// \param i The node id
/// \returns The id of the right-most node of `i`
constexpr size_t right_most(size_t i) const {
if (i >= _table.size()) {
return npos;
}
while (_table[i].right[false] != npos) {
i = _table[i].right[false];
}
return i;
}
/// @}
// Access ==============================================================================================================
public:
/// \name Access
/// @{
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i`
constexpr value_t& operator[](size_t i) {
assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value;
}
///
/// \details Const Access, \f$O(1)\f$
/// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i`
constexpr const value_t& operator[](size_t i) const {
assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value;
}
/// @}
// Modifiers ===========================================================================================================
/// \name Modifiers
/// @{
///
/// \brief Move Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param val The object to move into the new node
/// \returns The id of the new node
constexpr size_t insert_left(size_t p, value_t&& val) {
return this->_insert_left(p, fennec::forward<value_t>(val));
}
///
/// \brief Copy Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the copy assignment operator is used instead
/// \param p The parent node
/// \param val The object to copy to the new node
/// \returns The id of the new node
constexpr size_t insert_left(size_t p, const value_t& val) {
return this->_insert_left(p, val);
}
///
/// \brief Emplace Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
template<typename...ArgsT>
constexpr size_t emplace_left(size_t p, ArgsT&&...args) {
return this->_insert_left(p, fennec::forward<ArgsT>(args)...);
}
///
/// \brief Move Right Insertion, constructs a new node as the right child of `p`
/// \details If the right node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param val The object to move into the new node
/// \returns The id of the new node
constexpr size_t insert_right(size_t p, value_t&& val) {
return this->_insert_right(p, fennec::forward<value_t>(val));
}
///
/// \brief Copy Right Insertion, constructs a new node as the right child of `p`
/// \details If the right node of `p` already exists, the copy assignment operator is used instead
/// \param p The parent node
/// \param val The object to copy to the new node
/// \returns The id of the new node
constexpr size_t insert_right(size_t p, const value_t& val) {
return this->_insert_right(p, val);
}
///
/// \brief Emplace Right Insertion, constructs a new node as the right child of `p`
/// \details If the right node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
template<typename...ArgsT>
constexpr size_t emplace_right(size_t p, ArgsT&&...args) {
return this->_insert_right(p, fennec::forward<ArgsT>(args)...);
}
///
/// \brief Perform a Tree Rotation at `i` in the specified direction
/// \param i The root node for the rotation
/// \param dir The direction to rotate, `true` for right, `false` for left
constexpr size_t rotate(size_t sub, bool dir) {
if (sub == npos) {
return npos;
}
size_t sub_parent = _parent(sub);
size_t new_root = _child(sub, not dir);
size_t new_child = _child(new_root, dir);
_child(sub, not dir) = new_child;
if (new_child != npos) {
_parent(new_child) = sub;
}
_child(new_root, dir) = sub;
_parent(new_root) = sub_parent;
_parent(sub) = new_root;
if (sub_parent != npos) {
_child(sub_parent, sub == _right(sub_parent)) = new_root;
} else {
_root = new_root;
}
return new_root;
}
///
/// \brief Move Insertion, bool d, constructs a new node as the child of `p`
/// \details If the child of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param d The direction to insert
/// \param val The object to move into the new node
/// \returns The id of the new node
constexpr size_t insert(size_t p, bool d, value_t&& val) {
return this->_insert(p, d, fennec::forward<value_t>(val));
}
///
/// \brief Copy Insertion, bool d, constructs a new node as the child of `p`
/// \details If the child of `p` already exists, the copy assignment operator is used instead
/// \param p The parent node
/// \param d The direction to insert
/// \param val The object to copy to the new node
/// \returns The id of the new node
constexpr size_t insert(size_t p, bool d, const value_t& val) {
return this->_insert(p, d, val);
}
///
/// \brief Emplace Insertion, constructs a new node as the child of `p`
/// \details If the child of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param d The direction to insert
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
template<typename...ArgsT>
constexpr size_t emplace(size_t p, bool d, ArgsT&&...args) {
return this->_insert(p, d, fennec::forward<ArgsT>(args)...);
}
///
/// \brief Clears the tree, destroying all elements
constexpr void clear() {
list<size_t> queue;
if (_root != npos) {
queue.push_back(_root);
}
while (not queue.empty()) {
size_t i = queue.front();
queue.pop_front();
if (_right(i) != npos) {
queue.push_front(_right(i));
}
if (_left(i) != npos) {
queue.push_front(_left(i));
}
fennec::destruct(&_table[i]);
}
_size = 0;
_root = npos;
}
/// @}
// 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>
constexpr void traverse(VisitorT&& visit, size_t i) {
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 breadth_first {
list<size_t> visit;
size_t head;
size_t operator()(const bintree&, size_t start) {
return head = start;
}
size_t operator[](const bintree& tree, size_t node, uint8_t mode) {
if (node == npos) {
return npos;
}
size_t lft = tree.left(tree.parent(node));
size_t nxt = lft == node ? tree.right(tree.parent(node)) : npos;
size_t chd = tree.left(node);
if (nxt != npos && node != head) {
visit.push_front(nxt);
}
if (chd != npos && mode != traversal_control_jump_over) {
visit.push_back(chd);
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
struct pre_order {
list<size_t> visit;
size_t head;
constexpr size_t operator()(const bintree&, size_t start) {
head = start;
return start;
}
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t mode) {
if (node == npos) {
return npos;
}
size_t nxt = tree.right(tree.parent(node));
size_t chd = tree.left(node);
nxt = node == nxt ? npos : nxt;
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;
constexpr size_t operator()(const bintree& tree, size_t start) {
head = start;
return tree.left_most(start);
}
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) {
if (node == npos) {
return npos;
}
size_t parent = tree.parent(node);
size_t pright = tree.right(parent);
size_t next = tree.left_most(tree.right(node));
if (node != pright && parent != npos) {
visit.push_front(parent);
}
if (next != npos) {
visit.push_front(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;
constexpr size_t successor(const bintree& tree, size_t n) {
size_t s = tree.left_most(n);
while (n == s) {
size_t r = tree.right(n);
if (r != npos) {
n = r;
s = tree.left_most(n);
} else {
break;
}
}
return s == npos ? n : s;
}
constexpr size_t operator()(const bintree& tree, size_t start) {
head = start;
return this->successor(tree, start);
}
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) {
if (node == npos) {
return npos;
}
size_t parent = tree.parent(node);
size_t pright = tree.right(parent);
if (node == pright) {
if (parent != npos) {
visit.push_front(parent);
}
} else if (pright != npos) {
visit.push_front(this->successor(tree, pright));
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
// Iterator ============================================================================================================
class iterator {
protected:
bintree* _tree;
in_order _order;
size_t _n;
public:
constexpr iterator(bintree* tree, size_t root)
: _tree(tree)
, _order()
, _n(_order(*tree, root)) {
}
constexpr iterator(bintree* tree, size_t root, size_t node)
: _tree(tree)
, _order()
, _n(node) {
_order.head = root;
}
size_t index() const {
return _n;
}
iterator& operator++() {
return _n = _order[*_tree, _n, traversal_control_continue], *this;
}
value_t& operator*() {
return (*_tree)[_n];
}
value_t* operator->() {
return &(*_tree)[_n];
}
const value_t& operator*() const {
return (*_tree)[_n];
}
const value_t* operator->() const {
return &(*_tree)[_n];
}
constexpr bool operator==(const iterator& it) {
return _tree == it._tree and _n == it._n;
}
constexpr bool operator!=(const iterator& it) {
return _tree != it._tree or _n != it._n;
}
};
// Fields ==============================================================================================================
protected:
table_t _table;
freed_t _freed;
size_t _root, _size;
// Helpers =============================================================================================================
constexpr size_t _next_free() {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
_freed.pop_front();
}
if (i >= _table.capacity()) {
_table.creallocate(2 * fennec::max(_table.capacity(), size_t(4)));
}
++_size;
return i;
}
template<typename...ArgsT>
constexpr size_t _insert_left(size_t p, ArgsT&&...args) {
size_t i = p >= capacity() ? npos : p;
i = i == npos ? _root : _left(i);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
} else {
i = _next_free();
if (p != npos) {
_left(p) = i;
}
if (_root == npos) {
_root = i;
}
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
}
return i;
}
template<typename...ArgsT>
constexpr size_t _insert_right(size_t p, ArgsT&&...args) {
size_t i = p == npos ? _root : _right(p);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
} else {
i = _next_free();
if (p != npos) {
_right(p) = i;
}
if (_root == npos) {
_root = i;
}
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
}
return i;
}
template<typename...ArgsT>
constexpr size_t _insert(size_t p, bool d, ArgsT&&...args) {
size_t i = p == npos ? _root : _child(p, d);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
return i;
}
i = _next_free();
if (p != npos) {
_child(p, d) = i;
}
if (_root == npos) {
_root = i;
}
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
return i;
}
constexpr size_t& _parent(size_t i) {
return _table[i].parent;
}
constexpr size_t& _grandparent(size_t i) {
return _parent(_parent(i));
}
constexpr size_t& _left(size_t i) {
return _table[i].child[false];
}
constexpr size_t& _right(size_t i) {
return _table[i].child[true];
}
constexpr size_t& _child(size_t i, bool dir) {
return _table[i].child[dir];
}
constexpr size_t& _sibling(size_t i) {
size_t p = _parent(i);
bool d = i == _right(p);
return _child(p, !d);
}
};
}
#endif // FENNEC_CONTAINERS_BINTREE_H

View File

@@ -0,0 +1,148 @@
// =====================================================================================================================
// 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 bitfield.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_BITFIELD_H
#define FENNEC_CONTAINERS_BITFIELD_H
#include <fennec/containers/array.h>
#include <fennec/lang/types.h>
#include <fennec/lang/utility.h>
namespace fennec
{
///
/// \brief Bitfield Container with basic Bit Ops
/// \tparam N The number of bits in the bitfield
template<size_t N>
struct bitfield {
static constexpr size_t bits = N;
static constexpr size_t bytes = (N + 7) / 8;
public:
constexpr bitfield()
: _bytes() {
}
explicit constexpr bitfield(const bool (&arr)[N])
: _bytes() {
for (size_t i = 0; i < arr; ++i) {
this->store(i, arr[i]);
}
}
template<size_t I>
explicit constexpr bitfield(const size_t (&arr)[I])
: _bytes() {
for (size_t i : arr) {
this->set(i);
}
}
template<typename...ArgsT>
constexpr bitfield(ArgsT&&...args)
: _bytes() {
(this->store(fennec::forward<ArgsT>(args), true), ...);
}
template<typename...ArgsT> requires((is_bool_v<ArgsT> or is_convertible_v<ArgsT, bool>) and ...)
constexpr bitfield(ArgsT&&...args)
: _bytes() {
size_t i = 0;
(this->store(i++, fennec::forward<ArgsT>(args)), ...);
}
bitfield(const bitfield& bf)
: _bytes(bf._bytes) {
}
bitfield(bitfield&& bf) noexcept
: _bytes(bf._bytes) {
}
constexpr ~bitfield() = default;
bitfield& operator=(const bitfield& bf) = default;
bitfield& operator=(bitfield&& bf) noexcept = default;
bool test(size_t i) const {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
return _bytes[b] & (1 << o);
}
void set(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
_bytes[b] |= (1 << o);
}
void clear(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
_bytes[b] &= ~(1 << o);
}
void toggle(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
_bytes[b] ^= (1 << o);
}
void store(size_t i, bool v) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
size_t o = i % 8;
(_bytes[b] &= ~((1 << o))) |= ((v << o));
}
bitfield operator~() const {
bitfield res = *this;
res._inv_helper(make_index_metasequence_t<bytes>{});
return res;
}
private:
array<uint8_t, bytes> _bytes;
template<size_t...I>
void _inv_helper(index_metasequence<I...>) {
((_bytes[I] = ~_bytes[I]), ...);
}
};
}
#endif // FENNEC_CONTAINERS_BITFIELD_H

View File

@@ -18,14 +18,14 @@
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H
#include <fennec/lang/const_sequences.h>
#include <fennec/lang/metasequences.h>
#include <fennec/lang/utility.h>
namespace fennec::detail
{
template <std::size_t I, typename T>
template <size_t I, typename T>
struct _tuple_leaf
{
template <typename ArgT>
@@ -43,7 +43,7 @@ template <typename, typename...>
struct _tuple;
template <size_t...IndicesV, typename...TypesT>
struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
struct _tuple<index_metasequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
{
template <typename...ArgsT>
constexpr _tuple(ArgsT&&... args)

View File

@@ -31,6 +31,7 @@
#ifndef FENNEC_CONTAINERS_DYNARRAY_H
#define FENNEC_CONTAINERS_DYNARRAY_H
#include <fennec/containers/initializer_list.h>
#include <fennec/lang/utility.h>
#include <fennec/memory/allocator.h>
#include <fennec/memory/new.h>
@@ -60,7 +61,7 @@ namespace fennec
///
/// \tparam TypeT value type
template<class TypeT, class Alloc = allocator<TypeT>>
class dynarray {
struct dynarray {
public:
// Definitions =========================================================================================================
@@ -156,7 +157,7 @@ public:
// 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;
constexpr dynarray(size_t n, TypeT&& val) = delete;
///
/// \brief Emplace Constructor
@@ -172,6 +173,60 @@ public:
}
}
///
/// \brief Array Copy Constructor
/// \tparam N The length of the array, automatically deduced
/// \param arr The array to copy
template<size_t N>
constexpr dynarray(const TypeT (&arr)[N])
: _alloc(N)
, _size(N) {
for (size_t i = 0; i < N; ++i) {
_alloc[i] = arr[i];
}
}
///
/// \brief Array Move Constructor
/// \tparam N The length of the array, automatically deduced
/// \param arr The array to move
template<size_t N>
constexpr dynarray(TypeT (&&arr)[N])
: _alloc(N)
, _size(N) {
for (size_t i = 0; i < N; ++i) {
_alloc[i] = fennec::move(arr[i]);
}
}
///
/// \brief Conversion Constructor, copies elements of conv as this `value_t`
/// \tparam OTypeT The other value type
/// \tparam OAlloc The other allocator type
/// \param conv The dynarray to convert
template<typename OTypeT, class OAlloc>
constexpr dynarray(const dynarray<OTypeT, OAlloc>& conv)
: _alloc(conv.size())
, _size(conv.size()) {
size_t i = 0;
for (const auto& it : conv) {
fennec::construct(&_alloc[i++], it);
}
}
///
/// \brief Initializer List Constructor
/// \param l List of elements to initialize with
/// \param alloc An allocator object to copy
constexpr dynarray(initializer_list<value_t> l, const alloc_t& alloc = alloc_t())
: _alloc(l.size(), alloc)
, _size(l.size()) {
size_t i = 0;
for (auto& it : l) {
fennec::construct(&_alloc[i++], fennec::move(it));
}
}
///
/// \brief Copy Constructor, uses the copy constructor to copy each element
/// \param arr the dynarray to copy
@@ -234,6 +289,36 @@ public:
return *this;
}
///
/// \brief Array Copy Assignment Operator
/// \tparam N the length of the array
/// \param arr the array to copy
/// \returns A dynarray after having copied each element of `arr`
template<size_t N>
constexpr dynarray& operator=(const TypeT (&arr)[N]) {
this->clear();
_alloc.creallocate(_size = N);
for (size_t i = 0; i < _size; ++i) {
fennec::construct(&_alloc[i], fennec::copy(arr[i]));
}
return *this;
}
///
/// \brief Array Copy Assignment Operator
/// \tparam N the length of the array
/// \param arr the array to copy
/// \returns A dynarray after having moved each element of `arr`
template<size_t N>
constexpr dynarray& operator=(TypeT (&&arr)[N]) {
this->clear();
_alloc.creallocate(_size = N);
for (size_t i = 0; i < _size; ++i) {
fennec::construct(&_alloc[i], fennec::move(arr[i]));
}
return *this;
}
/// @}
// Properties ==========================================================================================================
@@ -432,6 +517,18 @@ public:
}
}
///
/// \brief Resize the dynarray, invoking the copy constructor for all new elements
/// \param n The new size in elements
/// \param val The value to fill with
constexpr void resize(size_t n, const TypeT& val) {
_alloc.creallocate(n);
while (_size < n) {
emplace_back(val);
}
}
///
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
constexpr void clear() {

View File

@@ -0,0 +1,210 @@
// =====================================================================================================================
// 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 universal.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_GENERIC_H
#define FENNEC_CONTAINERS_GENERIC_H
#include <fennec/memory/allocator.h>
#include <fennec/rtti/type.h>
namespace fennec
{
///
/// \brief A struct capable of holding a single object of any type
struct generic {
// Definitions =========================================================================================================
private:
// based on GCC
enum op_ : uint8_t {
op_clone,
op_destroy,
op_type,
};
using manager_t = void* (*)(uint8_t, void*);
// Constructors ========================================================================================================
public:
///
/// \brief Default Constructor
generic()
: _handle(nullptr)
, _manage(nullptr) {
}
///
/// \brief Copy Constructor
/// \param gen The generic object to copy
generic(const generic& gen)
: _handle(nullptr)
, _manage(gen._manage) {
if (_manage) {
_handle = _manage(op_clone, gen._handle);
}
}
///
/// \brief Move Constructor
/// \param gen The generic object to move
generic(generic&& gen)
: _handle(gen._handle)
, _manage(gen._manage) {
gen._handle = nullptr;
gen._manage = nullptr;
}
///
/// \brief Value Constructor
/// \tparam T The type of the value
/// \param x The value
template<typename T>
generic(T&& x)
: _handle(new T(fennec::forward<T>(x)))
, _manage(_manage_impl<T>) {
}
///
/// \brief Emplace Constructor
/// \tparam T The type to construct
/// \tparam ArgsT The argument types
/// \param args The argument values
template<typename T, typename...ArgsT>
generic(type_identity<T>, ArgsT&&...args)
: _handle(new T(fennec::forward<ArgsT>(args)...))
, _manage(_manage_impl<T>) {
}
///
/// \brief Destructor
~generic() {
reset();
}
// Properties ==========================================================================================================
type type() const {
return *static_cast<fennec::type*>(_manage(op_type, nullptr));
}
bool has_value() const {
return _handle != nullptr;
}
// Assignment ==========================================================================================================
generic& operator=(const generic& gen) {
if (this == &gen) { // self-assignment case
return *this;
}
reset();
_manage = gen._manage;
_handle = _manage(op_clone, gen._handle);
return *this;
}
generic& operator=(generic&& gen) noexcept {
swap(gen);
return *this;
}
// Utility =============================================================================================================
template<typename T>
generic& operator=(T&& x) {
reset();
_handle = new T(fennec::forward<T>(x));
_manage = _manage_impl<T>();
return *this;
}
template<typename T, typename...ArgsT>
void emplace(ArgsT&&...args) {
reset();
_handle = new T(fennec::forward<ArgsT>(args)...);
_manage = _manage_impl<T>;
}
void reset() {
if (_manage) {
_handle = _manage(op_destroy, _handle);
_manage = nullptr;
}
}
void swap(generic& gen) noexcept {
fennec::swap(_handle, gen._handle);
fennec::swap(_manage, gen._manage);
}
template<typename T>
T& cast() {
return *static_cast<T*>(_handle);
}
template<typename T>
const T& cast() const {
return *static_cast<T*>(_handle);
}
private:
void* _handle;
manager_t _manage;
template<typename T>
static void* _manage_impl(uint8_t op, void* hnd) {
static fennec::type t = type::get<T>();
T* ptr = hnd;
switch (op) {
case op_clone:
return new T(*ptr);
case op_destroy:
delete ptr;
return nullptr;
case op_type:
return &t;
default:
return nullptr;
}
}
};
}
#endif // FENNEC_CONTAINERS_GENERIC_H

View 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/>.
// =====================================================================================================================
///
/// \file initializer_list.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_INITIALIZER_LIST_H
#define FENNEC_CONTAINERS_INITIALIZER_LIST_H
// Since initializer lists are completely intertwined with the compiler, and this is part of the c++ standard
// (specifically standard, and not the standard template library) we need to use std::initializer_list.
// We can at least alias it for proper naming conventions.
#include <initializer_list>
namespace fennec
{
using std::initializer_list;
template<typename T>
constexpr const T* begin(initializer_list<T> inls) noexcept {
return inls.begin();
}
template<typename T>
constexpr const T* end(initializer_list<T> inls) noexcept {
return inls.end();
}
}
#endif // FENNEC_CONTAINERS_INITIALIZER_LIST_H

View File

@@ -140,6 +140,7 @@ public:
for (const value_t& it : l) {
this->push_back(it);
}
return *this;
}
///
@@ -152,6 +153,7 @@ public:
_freed = fennec::move(l._freed);
_root = l._root; _last = l._last;
_size = l._size;
return *this;
}
/// @}
@@ -164,15 +166,21 @@ public:
///
/// \returns The size of the list in elements.
constexpr size_t size() const { return _size; }
constexpr size_t size() const {
return _size;
}
///
/// \returns The capacity of the list in elements.
constexpr size_t capacity() const { return _table.capacity(); }
constexpr size_t capacity() const {
return _table.capacity();
}
///
/// \returns `true` when the list is empty, `false` otherwise.
constexpr bool empty() const { return _root == npos; }
constexpr bool empty() const {
return _root == npos;
}
/// @}
@@ -437,10 +445,7 @@ public:
// prefix operator
constexpr friend iterator& operator++(iterator& rhs) {
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
return rhs;
}
rhs._n = npos;
rhs._n = rhs._list->_next(rhs._n);
return rhs;
}

View File

@@ -291,7 +291,9 @@ private:
~U() {
fennec::destruct(&root);
}
} trick = { .root = { KeyT(fennec::forward<ArgsT>(args)...), 0 } };
} trick = {
.root = { KeyT(fennec::forward<ArgsT>(args)...), 0 }
};
return _set.find(trick.val);
}

View File

@@ -1,586 +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 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

View File

@@ -48,8 +48,9 @@ struct object_pool {
// Definitions =========================================================================================================
public:
using value_t = TypeT;
using elem_t = optional<TypeT>;
using elem_t = optional<value_t>;
using table_t = dynarray<elem_t, AllocT>;
using freed_t = list<size_t, AllocT>;
// Constructors & Destructor ===========================================================================================
@@ -119,7 +120,7 @@ public:
/// \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.");
assert(_table[i], "Attempted to access null object.")
return *_table[i];
}
@@ -129,7 +130,7 @@ public:
/// \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.");
assert(_table[i], "Attempted to access null object.")
return *_table[i];
}
@@ -176,12 +177,22 @@ public:
--_size;
}
///
/// \brief Clear the object pool
constexpr void clear() {
for (auto& it : _table) {
it = nullopt;
}
_size = 0;
_freed.clear();
}
/// @}
private:
dynarray<elem_t, AllocT> _table;
list<size_t> _freed;
size_t _size;
table_t _table;
freed_t _freed;
size_t _size;
size_t _next_free() {
size_t next = _size;
@@ -197,7 +208,7 @@ private:
size_t _insert(ArgsT&&...args) {
size_t i = _next_free();
if (i >= _table.size()) {
_table.emplace_back();
_table.resize(fennec::max(_table.size() * 2, size_t(8)));
}
_table[i].emplace(fennec::forward<ArgsT>(args)...);
return i;

View File

@@ -294,9 +294,35 @@ public:
/// \name Modifiers
/// @{
///
/// \brief Emplace Assignment, Move overload
/// \param val The object to take ownership of
constexpr T& emplace(T&& val) {
if (_set) {
_val = fennec::forward<T>(val);
} else {
fennec::construct(&_val, fennec::forward<T>(val));
_set = true;
}
return _val;
}
///
/// \brief Emplace Assignment, Copy overload
/// \param val The object to copy
constexpr T& emplace(const T& val) {
if (_set) {
_val = val;
} else {
fennec::construct(&_val, val);
_set = true;
}
return _val;
}
///
/// \brief Emplace Assignment
/// \val The optional to move
/// \param args The arguments to construct with
template<typename...ArgsT>
constexpr T& emplace(ArgsT&&...args) {
if (_set) {

View File

@@ -95,19 +95,33 @@ struct pair {
///
/// \brief Copy Constructor, copies both elements
constexpr pair(const pair&) = default;
constexpr pair(const pair& pair)
: first(fennec::copy(pair.first))
, second(fennec::copy(pair.second)) {
}
///
/// \brief Move Constructor, moves both elements
constexpr pair(pair&&) noexcept = default;
constexpr pair(pair&& pair) noexcept
: first(fennec::move(pair.first))
, second(fennec::move(pair.second)) {
}
///
/// \brief Copy Assignment, copies both elements
constexpr pair& operator=(const pair&) = default;
constexpr pair& operator=(const pair& pair) {
first = fennec::copy(pair.first);
second = fennec::copy(pair.second);
return *this;
}
///
/// \brief Move Assignment, moves both elements
constexpr pair& operator=(pair&&) noexcept = default;
constexpr pair& operator=(pair&& pair) {
first = fennec::move(pair.first);
second = fennec::move(pair.second);
return *this;
}
/// @}

View File

@@ -0,0 +1,192 @@
// =====================================================================================================================
// 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 priority_queue.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_PRIORITY_QUEUE_H
#define FENNEC_CONTAINERS_PRIORITY_QUEUE_H
#include <fennec/containers/object_pool.h>
#include <fennec/lang/compare.h>
#include <fennec/lang/types.h>
#include <fennec/memory/allocator.h>
// Binary heaps are just kinda busted.
// In-array binary heaps are one of the most efficient data structures for computers
// -> Cache Locality
// -> log(n) runtime
// -> No auxiliary structures or constant runtimes
//
// I tried just about every heap under the sun
// -> strict fibonacci heap, got blown out of the water by std::priority_queue
// -> fibonacci heap, got blown out of the water by std::priority_queue
// -> binomial heap, on-par with std::set, blown out of the water by std::priority_queue
//
// Then I relented and fell back to ye old binary heap
// This implementation roughly matches gcc's std::priority_queue
namespace fennec
{
template<typename ValueT, class CompareT = less<ValueT>, class AllocT = allocator<ValueT>>
struct priority_queue {
// Definitions & Constants =============================================================================================
public:
using value_t = ValueT;
using compare_t = CompareT;
using alloc_t = allocation<value_t, AllocT>;
static constexpr size_t npos = -1;
private:
constexpr size_t left(size_t n) const {
n = n * 2 + 1;
return n >= _size ? npos : n;
}
constexpr size_t right(size_t n) const {
n = n * 2 + 2;
return n >= _size ? npos : n;
}
constexpr size_t parent(size_t n) const {
return n == 0 ? npos : (n - 1) / 2;
}
// Constructors & Destructor ===========================================================================================
public:
constexpr priority_queue()
: _size(0) {
}
constexpr ~priority_queue() {
while (_size > 0) {
--_size;
fennec::destruct(&_table[_size]);
}
}
// Properties ==========================================================================================================
constexpr size_t size() const {
return _size;
}
constexpr size_t capacity() const {
return _table.capacity();
}
constexpr bool empty() const {
return size() == 0;
}
// Access ==============================================================================================================
constexpr const value_t& front() const {
return _table[0];
}
// Modifiers ===========================================================================================================
constexpr void push(const value_t& key) {
this->_insert(key);
}
constexpr void push(value_t&& key) {
this->_insert(fennec::forward<value_t>(key));
}
template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
this->_insert(fennec::forward<ArgsT>(args)...);
}
constexpr void pop() {
fennec::swap(_table[0], _table[--_size]);
fennec::destruct(&_table[_size]);
_fix_erase(0);
}
// Members =============================================================================================================
private:
compare_t _compare;
alloc_t _table;
size_t _size;
// Helpers =============================================================================================================
template<typename...ArgsT>
constexpr void _insert(ArgsT&&...args) {
if (_size == _table.capacity()) {
_expand();
}
fennec::construct(&_table[_size], fennec::forward<ArgsT>(args)...);
_fix_insert(_size++);
}
constexpr void _expand() {
_table.reallocate((_table.capacity() + 1) * 2 - 1);
}
constexpr size_t _min(size_t a, size_t b) {
if (a == npos) { return b; }
if (b == npos) { return a; }
return _compare(_table[a], _table[b]) ? a : b;
}
void _fix_insert(size_t n) {
size_t p = parent(n);
while (p != npos && _compare(_table[n], _table[p])) {
fennec::swap(_table[n], _table[p]);
n = p;
p = parent(n);
}
}
void _fix_erase(size_t n) {
size_t c = _min(left(n), right(n));
while (n != npos && c != npos && _compare(_table[c], _table[n])) {
fennec::swap(_table[c], _table[n]);
n = c;
c = _min(left(n), right(n));
}
}
};
}
#endif // FENNEC_CONTAINERS_PRIORITY_QUEUE_H

View File

@@ -34,6 +34,8 @@
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/containers/traversal.h>
#include <fennec/containers/pair.h>
#include <fennec/memory/allocator.h>
namespace fennec
@@ -58,9 +60,9 @@ public:
protected:
struct node {
optional<TypeT> value;
size_t parent, child, prev, next;
size_t depth, num_children;
value_t value;
size_t parent, child, prev, next;
size_t depth, num_children;
constexpr node()
: value(nullopt)
@@ -194,7 +196,7 @@ public:
/// \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;
if (i >= _table.capacity() && n != npos) return npos;
size_t c = i == npos ? npos : _table[i].child;
if (n != 0)
return next(c, n == npos ? npos : n - 1);
@@ -205,7 +207,7 @@ public:
/// \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 >= _table.capacity() && n != npos) return npos;
if (i == npos) {
return npos;
}
@@ -315,25 +317,15 @@ public:
///
/// \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;
}
constexpr value_t& operator[](size_t i) {
return _table[i].value;
}
///
/// \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;
}
constexpr const value_t& operator[](size_t i) const {
return _table[i].value;
}
@@ -342,7 +334,7 @@ public:
///
/// \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 next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next
/// \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) {
@@ -359,10 +351,33 @@ public:
return this->_insert(parent, next, fennec::forward<value_t>(val));
}
constexpr size_t insert(size_t parent, size_t next, const rdtree& tree) {
list<pair<size_t, size_t>> visit;
visit.push_front({ root, parent });
size_t res = npos;
while (not visit.empty()) {
auto node = visit.front();
visit.pop_front();
size_t p = this->_insert(node.second, node.second == parent ? next : npos, tree[node.first]);
res = (res == npos) ? p : res;
size_t c = tree.child(node.first, npos);
while (c != npos) {
visit.push_front({ c, p });
c = tree._table[c].prev;
}
}
return res;
}
///
/// \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 next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next
/// \param args the args to construct the value to insert
/// \returns the index of the created node
template<typename...ArgsT>
@@ -400,6 +415,8 @@ public:
}
// Traversal ===========================================================================================================
///
@@ -414,13 +431,13 @@ public:
/// \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) {
constexpr 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);
mode = visit(_table[i].value, i);
}
if (mode == traversal_control_break) {
break;
@@ -429,16 +446,52 @@ public:
}
}
struct pre_order {
struct breadth_first {
list<size_t> visit;
size_t head;
size_t head;
size_t operator()(const rdtree&, size_t start) {
constexpr size_t operator()(const rdtree&, size_t start) {
head = start;
return start;
}
size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
constexpr 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.next(node);
if (nxt != npos && node != head) {
visit.push_front(nxt);
}
if (chd != npos && mode != traversal_control_jump_over) {
visit.push_back(chd);
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
struct pre_order {
list<size_t> visit;
size_t head;
constexpr size_t operator()(const rdtree&, size_t start) {
head = start;
return start;
}
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
if (node == npos) {
return npos;
}
@@ -469,12 +522,12 @@ public:
list<size_t> visit;
size_t head;
size_t operator()(const rdtree& tree, size_t start) {
constexpr 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) {
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) {
if (node == npos) {
return npos;
}
@@ -507,12 +560,12 @@ public:
list<size_t> visit;
size_t head;
size_t operator()(const rdtree& tree, size_t start) {
constexpr 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) {
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) {
if (node == npos) {
return npos;
}

View File

@@ -0,0 +1,717 @@
// =====================================================================================================================
// 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 sequence.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_SEQUENCE_H
#define FENNEC_CONTAINERS_SEQUENCE_H
#include <fennec/containers/bintree.h>
#include <fennec/containers/bintree.h>
#include <fennec/containers/pair.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/lang/compare.h>
#include <fennec/memory/allocator.h>
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
// https://www.geeksforgeeks.org/dsa/insertion-in-red-black-tree/
// https://github.com/anandarao/Red-Black-Tree/blob/master/RBTree.cpp
// After rewriting the _fix_insert and _fix_erase functions the performance decreased significantly in the lower end
// but now in the higher end it remains consistent. Something I was doing was disturbing both the rb-tree and bst tree
// properties, now that is fixed. I'll see about optimizing more in the future.
// I realized that the way bintree is setup makes some insert calls O(n + log n) = O(n), so I switched to a pointer based model.
// This increased performance overall maintaining O(log n).
namespace fennec
{
///
///
/// \brief wrapper for ordered sets of elements, called sequences in mathematics
/// \details
/// This data-structure behaves like an ordered-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(\log N)\f$ |
/// | find | \f$O(\log N)\f$ |
/// | insertion | \f$O(\log N)\f$ |
/// | deletion | \f$O(\log N)\f$ |
///
/// \tparam TypeT The type to contain
/// \tparam CompareT Function for comparing two values
/// \tparam AllocT An allocator class
template<typename TypeT, typename CompareT = less<TypeT>, class AllocT = allocator<pair<TypeT, bool>>>
struct sequence {
// Definitions =========================================================================================================
protected:
struct _node;
public:
using value_t = TypeT;
using node_t = pair<TypeT, bool>;
using alloc_t = allocator_traits<AllocT>::template rebind<_node>;
using compare_t = CompareT;
enum color_ : bool {
black = false,
red = true,
};
enum dir_ : bool {
dir_left = false,
dir_right = true,
};
class iterator;
protected:
using node = _node*;
struct _node {
node parent;
node child[2];
value_t key;
bool color;
template<typename...ArgsT>
constexpr _node(ArgsT&&...args)
: parent(nullptr)
, child { nullptr, nullptr }
, key(fennec::forward<ArgsT>(args)...)
, color(red) {
}
template<typename...ArgsT>
constexpr _node(node p, node l, node r, ArgsT&&...args)
: parent(p)
, child { l, r }
, key(fennec::forward<ArgsT>(args)...)
, color(red) {
}
constexpr ~_node() {
parent = nullptr;
child[0] = nullptr;
child[1] = nullptr;
}
};
// Member Access Helpers
constexpr value_t& _key(node n) {
return n->key;
}
constexpr bool& _color(node n) {
return n->color;
}
constexpr node& _parent(node n) {
return n->parent;
}
constexpr node& _child(node n, bool dir) {
return n->child[dir];
}
constexpr node& _left(node n) {
return n->child[dir_left];
}
constexpr node& _right(node n) {
return n->child[dir_right];
}
// Safe Member Access Helpers
constexpr const value_t& key(node n) const {
return n->key;
}
constexpr bool color(node n) {
return n ? n->color : (bool)black;
}
constexpr node parent(node n) {
return n ? n->parent : nullptr;
}
constexpr node child(node n, bool dir) {
return n ? n->child[dir] : nullptr;
}
constexpr node left(node n) {
return n ? n->child[dir_left] : nullptr;
}
constexpr node right(node n) {
return n ? n->child[dir_right] : nullptr;
}
constexpr node leftmost(node n) {
if (n == nullptr) {
return nullptr;
}
while (this->_left(n)) {
n = this->_left(n);
}
return n;
}
constexpr node rightmost(node n) {
if (n == nullptr) {
return nullptr;
}
while (this->_right(n)) {
n = this->_right(n);
}
return n;
}
// Constructors & Destructors ==========================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Default Constructor, initializes an empty sequence
constexpr sequence()
: _root(nullptr), _size(0) {
}
///
/// \brief Move Constructor, takes ownership of a sequence
constexpr sequence(sequence&&) noexcept = default;
///
/// \brief Copy Constructor, copies a sequence
constexpr sequence(const sequence&) = default;
///
/// \brief Default Destructor, destructs elements *in-order*
constexpr ~sequence() {
this->clear();
}
/// @}
// Search ==============================================================================================================
public:
/// \name Search
/// @{
///
/// \brief Value Find Function, finds the iterator position for `val`, otherwise returns `end()`
/// \param val The value to find
/// \returns An iterator at the value
constexpr iterator find(const value_t& val) {
node node = _root;
while (node) {
if (_compare(val, _key(node))) {
node = _left(node);
} else if (_compare(_key(node), val)) {
node = _right(node);
} else {
return sequence::iterator(this, _root, node);
}
}
return sequence::iterator(this, _root, node);
}
///
/// \brief Value Contains Function, checks if the sequence contains a value
/// \param val The value to find
/// \returns `true` if `val` is in the sequence, `false` otherwise
bool contains(const value_t& val) {
return find(val) != end();
}
/// @}
// Properties ==========================================================================================================
public:
/// \name Properties
/// @{
///
/// \returns The number of elements in the sequence
constexpr size_t size() const {
return _size;
}
///
/// \returns `true` when there are no elements in the sequence, `false` otherwise.
constexpr bool empty() const {
return _size == 0;
}
/// @}
// Modifiers ===========================================================================================================
public:
/// \name Modifiers
/// @{
///
/// \brief Move Insertion, moves `val` into the sequence
/// \param val The value to insert
constexpr void insert(value_t&& val) {
node i = _insert_bst(fennec::forward<value_t>(val));
_fix_insert(i);
}
///
/// \brief Copy Insertion, inserts a copy of `val` into the sequence
/// \param val The value to insert
constexpr void insert(const value_t& val) {
node i = _insert_bst(val);
_fix_insert(i);
}
///
/// \brief Emplacement, constructs and adds a value into the sequence
/// \tparam ArgsT The argument types
/// \param args The arguments to construct with
template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
node i = _insert_bst(fennec::forward<ArgsT>(args)...);
_fix_insert(i);
}
constexpr void erase(const value_t& val) {
_erase(find(val)._node);
}
///
/// \brief Destructs all elements, *in-order*, contained in the sequence
constexpr void clear() {
list<node> visit;
for (iterator it = begin(); it != end(); ++it) {
visit.push_back(it._node);
}
for (node n : visit) {
_free_node(n);
}
_root = nullptr;
_size = 0;
}
/// @}
// Iterator ============================================================================================================
///
/// \returns An iterator at the smallest element in the sequence
constexpr iterator begin() {
return sequence::iterator(this, _root);
}
///
/// \returns An iterator after the largest element in the sequence
constexpr iterator end() {
return sequence::iterator(this, _root, nullptr);
}
class iterator {
protected:
sequence* _seq;
node _head;
node _node;
list<node> _visit;
public:
constexpr iterator(sequence* seq, node start)
: _seq(seq)
, _head(start)
, _node(seq->leftmost(start)) {
}
constexpr iterator(sequence* seq, node root, node start)
: _seq(seq)
, _head(root)
, _node(start) {
}
iterator& operator++() {
if (_node == nullptr) {
return *this;
}
node parent = _seq->_parent(_node);
node pright = _seq->right(parent);
node next = _seq->leftmost(_seq->right(_node));
if (_node != pright && parent != nullptr) {
_visit.push_front(parent);
}
if (next != nullptr) {
_visit.push_front(next);
}
if (not _visit.empty()) {
_node = _visit.front();
_visit.pop_front();
} else {
_node = nullptr;
}
return *this;
}
iterator operator++(int) {
iterator prev = *this;
this->operator++();
return prev;
}
const value_t& operator*() const {
return _node->key;
}
const value_t* operator->() const {
return &_node->key;
}
constexpr friend bool operator==(const iterator& lhs, const iterator& rhs) {
return lhs._node == rhs._node;
}
friend struct sequence;
};
// Fields ==============================================================================================================
protected:
alloc_t _alloc;
node _root;
compare_t _compare;
size_t _size;
// Helpers =============================================================================================================
protected:
template<typename...ArgsT>
constexpr node _make_node(ArgsT&&...args) {
node res = _alloc.allocate(1);
fennec::construct(res, fennec::forward<ArgsT>(args)...);
return res;
}
constexpr void _free_node(node n) {
fennec::destruct(n);
_alloc.deallocate(n);
}
constexpr node _rotate(node sub, bool dir) {
if (sub == nullptr) {
return nullptr;
}
node sub_parent = _parent(sub);
node new_root = _child(sub, not dir);
node new_child = _child(new_root, dir);
_child(sub, not dir) = new_child;
if (new_child != nullptr) {
_parent(new_child) = sub;
}
_child(new_root, dir) = sub;
_parent(new_root) = sub_parent;
_parent(sub) = new_root;
if (sub_parent != nullptr) {
_child(sub_parent, sub == _right(sub_parent)) = new_root;
} else {
_root = new_root;
}
return new_root;
}
constexpr void _recolor(node n) {
bool c = color(n) == black;
if (n == _root) { // Only recolor if not the root node
_color(n) = c;
}
_color(_left(n)) = !_color(_left(n)) ;
_color(_right(n)) = !_color(_right(n));
}
// run-of-the-mill bst insert
template<typename...ArgsT>
constexpr node _insert_bst(ArgsT&&...args) {
node res = _make_node(fennec::forward<ArgsT>(args)...);
if (_root == nullptr) {
++_size;
_color(res) = black;
return _root = res;
}
node i = _root;
node p = nullptr;
bool d = dir_left;
while (i != nullptr) {
p = i;
if (_compare(_key(res), _key(i))) {
i = _left(i);
d = dir_left;
} else if (_compare(_key(i), _key(res))) {
i = _right(i);
d = dir_right;
} else {
_free_node(res);
return nullptr;
}
}
++_size;
_child(p, d) = res;
_parent(res) = p;
return res;
}
// This makes some cheats given that the structure is modified only by internal functions
// If such is the case, ONLY LL, LR, RL, and RR will show up
// Then we just need to handle splitting a 4-node
constexpr void _fix_insert(node n) {
if (n == nullptr) {
return;
}
node p = _parent(n);
while (n != _root && color(n) == red && color(p) == red) {
node g = _parent(p);
bool d = n == _right(p);
bool r = p == _right(g);
node u = _child(g, !r);
if (color(u) == red) {
_recolor(g);
n = g;
p = _parent(n);
continue;
}
if (d != r) {
_rotate(p, r);
n = p;
p = _parent(n);
}
_rotate(g, not r);
fennec::swap(_color(p), _color(g));
n = p;
p = _parent(n);
}
_color(_root) = black;
}
constexpr void _swap_val(node a, node b) {
fennec::swap(_key(a), _key(b));
}
constexpr node _red_child(node x) {
node l = _left(x);
node r = _right(x);
if (color(l) == red) {
return l;
}
if (color(r) == red) {
return r;
}
return nullptr;
}
constexpr void _fix_erase(node n) {
if (n == nullptr) {
return;
}
if (n == _root) {
_root = nullptr;
return;
}
node o = n;
node p = _parent(n);
if (p == nullptr) {
_root = nullptr;
return;
}
bool d = n == _right(p);
node c = _red_child(n);
node s = nullptr;
if (_color(n) == red || c != nullptr) {
_child(p, d) = c;
if (c != nullptr) {
_parent(c) = p;
}
_color(c) = black;
return;
}
while (n != _root) {
p = _parent(n);
d = n == _right(p);
s = _child(p, !d);
if (s == nullptr) {
break;
}
if (_color(s) == red) {
_color(s) = black;
_color(p) = red;
_rotate(p, d);
continue;
}
node nc = _child(s, d);
node nf = _child(s, !d);
if (color(nc) == black && color(nf) == black) {
_color(s) = red;
if (_color(p) == red) {
_color(p) = black;
break;
}
n = p;
continue;
}
if (color(nf) == black) {
_color(nc) = black;
_color(s) = red;
_rotate(s, !d);
s = nc;
nf = s;
}
_color(s) = _color(p);
_color(p) = black;
_color(nf) = black;
_rotate(p, d);
break;
}
p = parent(o);
if (p != nullptr) {
if (o == _left(p)) {
_left(p) = nullptr;
} else {
_right(p) = nullptr;
}
_color(_root) = black;
} else {
_root = nullptr;
}
}
constexpr void _erase(node n) {
if (n == nullptr) {
return;
}
node l = _left(n);
node r = _right(n);
// 2 children
if (l != nullptr && r != nullptr) {
node s = leftmost(r);
_swap_val(n, s);
n = s;
l = _left(n);
r = _right(n);
}
node p = _parent(n);
bool d = n == right(p);
node c = l != nullptr ? l : r;
// Single child
if (c != nullptr) {
_parent(c) = p;
}
// Handles root cases
if (p == nullptr) {
_root = c;
if (c == nullptr) {
_free_node(n);
--_size;
return;
} else {
_color(c) = black;
}
}
// Single Child, Red, and Root cases
if (p == nullptr || c != nullptr || _color(n) == red) {
if (p != nullptr) {
_child(p, d) = c;
}
_free_node(n);
--_size;
return;
}
_fix_erase(n);
_free_node(n);
--_size;
}
};
}
#endif // FENNEC_CONTAINERS_SEQUENCE_H

View File

@@ -330,7 +330,7 @@ public:
while (_alloc[i = (i + 1) % capacity()].value) {
if (_alloc[i].psl == 0) break;
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
fennec::swap(_alloc[p].value, _alloc[i].value);
--_alloc[p].psl, --_sumpsl;
p = i;
}

View File

@@ -76,13 +76,15 @@ constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<T
template<typename ...TypesT>
struct tuple : public detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>
struct tuple : public detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>
{
using base_t = detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>;
using base_t = detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>;
template<size_t i>
using elem_t = typename nth_element<i, TypesT...>::type;
static constexpr size_t size = sizeof...(TypesT);
template<typename...ArgsT>
tuple(ArgsT&&...args)
: base_t(fennec::forward<ArgsT>(args)...) {

View File

@@ -31,4 +31,216 @@
#ifndef FENNEC_CONTAINERS_VARIANT_H
#define FENNEC_CONTAINERS_VARIANT_H
#include <fennec/containers/optional.h>
#include <fennec/lang/type_sequences.h>
#include <fennec/math/ext/common.h>
#include <fennec/rtti/type.h>
namespace fennec
{
///
/// \brief A structure that represents a union between `TypesT...`
/// \tparam TypesT The types to hold in the variant
template<typename...TypesT>
struct variant {
// Assertions ==========================================================================================================
static_assert(
is_unique_v<TypesT...> and // No two types in TypesT... may be equivalent
not (is_reference_v<TypesT> or ...) and // No type in TypesT... may be a reference
not (is_array_v<TypesT> or ...) and // No type in TypesT... may be an array
not (is_void_v<TypesT> or ...) // No type in TypesT... may be void
);
// Typedefs & Constants ================================================================================================
static constexpr size_t size = max_element_size_v<TypesT...>;
static constexpr size_t nulltype = sizeof...(TypesT);
// Constructors ========================================================================================================
///
/// \brief Default Constructor, constructs the first type in `TypesT...` that is default constructible
variant()
: _bytes {}
, _type(nulltype) {
using construct_t = search_element_t<is_default_constructible, TypesT...>;
fennec::construct<construct_t>(_handle);
}
///
/// \brief Conversion Constructor, constructs the type in `TypesT...` that is identical to `T`
/// or the first that is constructible with `T`
/// \tparam T The type of the value
/// \param t The value to forward
template<typename T>
variant(T&& t)
: _bytes {}
, _type() {
using same_t = search_element_args<is_same, type_sequence<T>, TypesT...>;
using convert_t = search_element_args<is_constructible, type_sequence<T>, TypesT...>;
using construct_t = conditional_t<is_void_v<same_t>, convert_t, convert_t>;
fennec::construct<construct_t>(_handle, fennec::forward<T>(t));
}
///
/// \brief Emplace Constructor, constructs the first type in `TypesT...` that is constructible with `ArgsT...`
/// \tparam ArgsT The arguments of the constructor
/// \param args The argument values
template<typename T, typename...ArgsT>
variant(type_identity<T>, ArgsT&&...args)
: _bytes{}
, _type(nulltype) {
static_assert(contains_element_v<T, TypesT...>, "T must be in TypesT...");
fennec::construct<T>(_handle, fennec::forward<ArgsT>(args)...);
_type = find_element_v<T>;
}
///
/// \brief Copy Constructor
/// \param v The variant to copy
variant(const variant& v)
: _bytes {}
, _type(nulltype) {
if (v._type == nulltype) {
return;
}
((v._type == find_element_v<TypesT, TypesT...> ?
fennec::construct<TypesT>(_handle, v.get<TypesT>()) :
(0)
), ...);
_type = v._type;
}
///
/// \brief Move Constructor
/// \param v The variant to move
variant(variant&& v) noexcept
: _bytes {}
, _type() {
if (v._type == nulltype) {
return;
}
((v._type == find_element_v<TypesT, TypesT...> ?
fennec::construct<TypesT>(_handle, fennec::move(v.get<TypesT>())) :
(0)
), ...);
_type = v._type;
}
///
/// \brief Destructor, if a type is held, destruct it.
~variant() {
_clear();
}
// Assignment ==========================================================================================================
template<typename T>
variant& operator=(T&& t) {
// First, check if `T` is in `TypesT...`
if constexpr((contains_element_v<T, TypesT> or ...)) {
using type_t = remove_reference_t<T>;
if (_type == find_element_v<type_t, TypesT...>) {
*static_cast<type_t*>(_handle) = fennec::forward<T>(t);
} else {
_clear();
fennec::construct<type_t>(_handle, fennec::forward<T>(t));
_type = find_element_v<type_t, TypesT...>;
}
return *this;
}
// Next, try to assign using the currently held type
bool assigned = false;
if (_type != nulltype) {
((_type == find_element_v<TypesT, TypesT...> ?
(*static_cast<TypesT*>(_handle) = fennec::forward<T>(t), assigned = true) :
(0)
), ...);
}
if (assigned) {
return *this;
}
// Otherwise, destruct, then construct
_clear();
using construct_t = search_element_args<is_constructible, type_sequence<T>, TypesT...>;
fennec::construct<construct_t>(_handle, fennec::forward<T>(t));
return *this;
}
template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>)
void emplace(ArgsT&&...args) {
_clear();
fennec::construct<T>(_handle, fennec::forward<ArgsT>(args)...);
}
template<size_t I, typename...ArgsT>
void emplace(ArgsT&&...args) {
using type_t = nth_element_t<I, TypesT...>;
_clear();
fennec::construct<type_t>(fennec::forward<ArgsT>(args)...);
}
// Access ==============================================================================================================
template<typename T> requires(contains_element_v<T, TypesT...>)
T& get() {
return *static_cast<T*>(_handle);
}
template<typename T> requires(contains_element_v<T, TypesT...>)
const T& get() const {
return *static_cast<T*>(_handle);
}
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
T& get() {
return *static_cast<T*>(_handle);
}
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
const T& get() const {
return *static_cast<T*>(_handle);
}
private:
union {
byte_t _bytes[size];
void* _handle;
};
size_t _type;
void _clear() {
if (_type == nulltype) {
return;
}
((_type == find_element_v<TypesT, TypesT...> ?
fennec::destruct<TypesT>(_handle) :
(0)
), ...);
_type = nulltype;
}
};
}
#endif // FENNEC_CONTAINERS_VARIANT_H

View File

@@ -20,27 +20,32 @@
#define FENNEC_CORE_EVENT_H
#include <fennec/lang/types.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/rtti/enable.h>
#include <fennec/rtti/typeid.h>
namespace fennec
{
struct event;
///
/// \brief Class outlining the interface for an object that listens for events
class event_listener {
public:
virtual ~event_listener() = default;
virtual void handle_event(event* event) = 0;
};
///
/// \brief Main event interface, includes static methods for registering listeners and dispatching events
struct event {
const uint64_t type;
event() = delete;
template<typename EventT>
event() : type(typeuuid<EventT>()) { }
virtual ~event() = default;
///
/// \brief Registers a listener for the event type
/// \tparam EventT
/// \param listener
template<typename EventT>
static void add_listener(event_listener* listener) {
event::add_listener(listener, typeuuid<EventT, event>());
@@ -54,6 +59,10 @@ struct event {
static void add_listener(event_listener* listener, uint64_t type);
static void remove_listener(event_listener* listener);
static void dispatch(event* event);
FENNEC_RTTI_CLASS_ENABLE() {
}
};
}

View File

@@ -0,0 +1,88 @@
// =====================================================================================================================
// 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 logger.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CORE_LOGGER_H
#define FENNEC_CORE_LOGGER_H
#include <fennec/filesystem/file.h>
#include <fennec/rtti/singleton.h>
#include <fennec/containers/tuple.h>
namespace fennec
{
class logger : public singleton<logger> {
public:
logger();
~logger();
static void log(const cstring& str,
uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* const _file = FENNEC_BUILTIN_FILE()
) {
logger& inst = instance();
if (inst._logfile.is_open()) {
inst._logfile.print(cstring(_file, strlen(_file)));
inst._logfile.printf("({}): ", _line);
inst._logfile.println(str);
}
inst._cout->print(cstring(_file, strlen(_file)));
inst._cout->printf("({}): ", _line);
inst._cout->println(str);
}
static void log(const string& str,
uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* const _file = FENNEC_BUILTIN_FILE()
) {
logger& inst = instance();
if (inst._logfile.is_open()) {
inst._logfile.print(cstring(_file, strlen(_file)));
inst._logfile.printf("({}): ", _line);
inst._logfile.println(str);
}
inst._cout->print(cstring(_file, strlen(_file)));
inst._cout->printf("({}): ", _line);
inst._cout->println(str);
}
private:
file _logfile;
file* _cout;
};
}
#endif // FENNEC_CORE_LOGGER_H

View File

@@ -18,7 +18,7 @@
#ifndef FENNEC_CORE_SYSTEM_H
#define FENNEC_CORE_SYSTEM_H
#include <fennec/langproc/strings/string.h>
#include <fennec/string/string.h>
namespace fennec
{

View File

@@ -0,0 +1,48 @@
// =====================================================================================================================
// 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 version.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CORE_VERSION_H
#define FENNEC_CORE_VERSION_H
#include <fennec/lang/types.h>
#include <fennec/string/string.h>
namespace fennec
{
struct version {
uint32_t major, minor, patch;
string str;
};
}
#endif // FENNEC_CORE_VERSION_H

View File

@@ -16,9 +16,9 @@
// 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
#ifndef FENNEC_FILESYSTEM_DETAIL_CTYPE_H
#define FENNEC_FILESYSTEM_DETAIL_CTYPE_H
#include <stdio.h>
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#endif // FENNEC_FILESYSTEM_DETAIL_CTYPE_H

View File

@@ -16,14 +16,15 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_LANGPROC_IO_FILE_H
#define FENNEC_LANGPROC_IO_FILE_H
#ifndef FENNEC_FILESYSTEM_FILE_H
#define FENNEC_FILESYSTEM_FILE_H
#include <fennec/langproc/filesystem/path.h>
#include <fennec/filesystem/path.h>
#include <fennec/format/format.h>
#include <fennec/langproc/strings/cstring.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/langproc/strings/wstring.h>
#include <fennec/string/cstring.h>
#include <fennec/string/string.h>
#include <fennec/string/wstring.h>
namespace fennec
{
@@ -108,6 +109,21 @@ public:
/// \brief default constructor, initializes an empty stream
file();
file(const cstring& path, uint8_t mode)
: file() {
open(path, mode);
}
file(const string& path, uint8_t mode)
: file() {
open(path, mode);
}
file(const path& path, uint8_t mode)
: file() {
open(path, mode);
}
///
/// \brief default destructor, cleans up an open stream
~file();
@@ -250,9 +266,6 @@ public:
// Binary Read Operations ==============================================================================================
char getc();
wchar_t getwc();
size_t read(void* data, size_t size, size_t n);
template<typename T>
@@ -265,9 +278,6 @@ public:
return read(static_cast<void*>(data), sizeof(T), n);
}
string getline();
wstring getwline();
// Binary Write Operations =============================================================================================
@@ -297,8 +307,29 @@ public:
}
// Read Operations =====================================================================================================
char getc();
wchar_t getwc();
string getline();
wstring getwline();
// Printing Operations =================================================================================================
void print(const cstring& str);
void print(const string& str);
void println(const cstring& str);
void println(const string& str);
template<typename...ArgsT>
void printf(const cstring& str, ArgsT&&...args) {
string fmt = fennec::format(str, fennec::forward<ArgsT>(args)...);
this->print(cstring(fmt.cstr(), fmt.length()));
}
@@ -316,4 +347,4 @@ private:
}
#endif // FENNEC_LANGPROC_IO_FILE_H
#endif // FENNEC_FILESYSTEM_FILE_H

View File

@@ -16,10 +16,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_LANGPROC_IO_PATH_H
#define FENNEC_LANGPROC_IO_PATH_H
#ifndef FENNEC_FILESYSTEM_PATH_H
#define FENNEC_FILESYSTEM_PATH_H
#include <fennec/langproc/strings/string.h>
#include <fennec/filesystem/path.h>
#include <fennec/string/string.h>
namespace fennec
{
@@ -32,6 +33,12 @@ namespace fennec
struct path
{
public:
// Definitions =========================================================================================================
class iterator;
friend iterator;
// Static Functions ====================================================================================================
/// \brief Get the current working directory
@@ -154,6 +161,11 @@ public:
return _str == p._str;
}
string filename() const {
size_t i = _str.rfind('/');
return _str.substring(i + 1);
}
const string& str() const { return _str; }
const char* cstr() const { return _str.cstr(); }
@@ -238,10 +250,85 @@ public:
return working;
}
// Iterator ============================================================================================================
iterator begin() const {
return iterator(this, 0);
}
iterator end() const {
return iterator(this, _str.size());
}
class iterator {
public:
constexpr iterator(const path* path, size_t p)
: _str(&path->_str)
, _pos(p) {
// Handle end()
if (p == _str->size()) {
return;
}
// Handle rooted paths
#ifdef FENNEC_PLATFORM_WINDOWS
if ((*_str)[1] == ':') {
_pos = max(_pos, size_t(3));
}
#else
if ((*_str)[0] == '/') {
_pos = max(_pos, size_t(1));
}
#endif
// Ensure we are at the start of a directory/file name
if (_pos != 0 && (*_str)[_pos - 1] != '/') {
_pos = _str->find('/', _pos) + 1;
}
}
constexpr iterator(const iterator&) = default;
constexpr iterator(iterator&&) noexcept = default;
constexpr string operator*() const {
if ((*_str)[_pos] == '/') {
return string("");
}
size_t e = _str->find('/', _pos);
return _str->substring(_pos, e - _pos);
}
constexpr iterator& operator++() {
_pos = min(_str->find('/', _pos) + 1, _str->size());
return *this;
}
constexpr iterator operator++(int) {
iterator it = *this;
this->operator++();
return it;
}
constexpr bool operator==(const iterator& rhs) const {
return _str == rhs._str and _pos == rhs._pos;
}
constexpr bool operator!=(const iterator& rhs) const {
return _str != rhs._str or _pos != rhs._pos;
}
private:
const string* _str;
size_t _pos;
};
private:
string _str;
};
}
#endif // FENNEC_LANGPROC_IO_PATH_H
#endif // FENNEC_FILESYSTEM_PATH_H

View File

@@ -0,0 +1,67 @@
// =====================================================================================================================
// 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 charconv.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_FORMAT_CHARCONV_H
#define FENNEC_FORMAT_CHARCONV_H
namespace fennec
{
char* to_chars(char* first, char* last, char x, int base);
char* to_chars(char* first, char* last, signed char x, int base);
char* to_chars(char* first, char* last, unsigned char x, int base);
char* to_chars(char* first, char* last, signed short x, int base);
char* to_chars(char* first, char* last, unsigned short x, int base);
char* to_chars(char* first, char* last, signed int x, int base);
char* to_chars(char* first, char* last, unsigned int x, int base);
char* to_chars(char* first, char* last, signed long x, int base);
char* to_chars(char* first, char* last, unsigned long x, int base);
char* to_chars(char* first, char* last, signed long long x, int base);
char* to_chars(char* first, char* last, unsigned long long x, int base);
char* to_chars(char* first, char* last, signed long long x, int base);
char* to_chars(char* first, char* last, unsigned long long x, int base);
char* to_chars(char* first, char* last, float x);
char* to_chars(char* first, char* last, float x, char fmt);
char* to_chars(char* first, char* last, float x, char fmt, int precision);
char* to_chars(char* first, char* last, double x);
char* to_chars(char* first, char* last, double x, char fmt);
char* to_chars(char* first, char* last, double x, char fmt, int precision);
}
#endif // FENNEC_FORMAT_CHARCONV_H

View 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 _format.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_FORMAT_DETAIL_FORMAT_H
#define FENNEC_FORMAT_DETAIL_FORMAT_H
#include <fennec/memory/pointers.h>
#include <fennec/format/formatter.h>
#include <fennec/format/format_arg.h>
namespace fennec::detail
{
// Impl interface for templated polymorphism fuckery
struct _format_argimpl {
_format_argimpl() {};
virtual ~_format_argimpl() {};
virtual string format(const format_arg& fmt) = 0;
virtual bool is_integer() = 0;
virtual int64_t int_value() = 0;
};
// Polymorphic template specialization
template<typename T>
struct _format_arg : _format_argimpl {
formatter<T> fmtr;
const T& val;
_format_arg(const T& arg) : val(arg) {
}
virtual ~_format_arg() = default;
string format(const format_arg& fmt) override {
return fennec::forward<string>(fmtr(fmt, val));
}
bool is_integer() override {
return is_integral_v<T> or is_convertible_v<T, int64_t>;
}
virtual int64_t int_value() override {
if constexpr(is_integral_v<T>) {
return val;
} else if constexpr(is_convertible_v<T, int64_t>) {
return val;
} else {
return -1;
}
}
};
// Polymorphic template specialization for x/r/xr value references
template<typename T>
struct _format_arg<T&> : _format_arg<T> {
_format_arg(const T& arg) : _format_arg<T>(arg) {
}
};
// Polymorphic template specialization for x/r/xr value references
template<typename T>
struct _format_arg<const T> : _format_arg<T> {
_format_arg(const T& arg) : _format_arg<T>(arg) {
}
};
// Polymorphic template specialization for x/r/xr value references
template<typename T>
struct _format_arg<const T&> : _format_arg<T> {
_format_arg(const T& arg) : _format_arg<T>(arg) {
}
};
// Containing array for format args
template<size_t N>
struct _format_argarray {
array<unique_ptr<_format_argimpl>, N> args;
template<typename...ArgsT>
_format_argarray(ArgsT&&...args)
: args { unique_ptr<_format_argimpl>(new _format_arg<ArgsT>(fennec::forward<ArgsT>(args)))... } {
}
string format(size_t i, const format_arg& fmt) {
return args[i]->format(fmt);
}
bool is_integer(size_t i) {
return args[i]->is_integer();
}
int64_t int_value(size_t i) {
return args[i]->int_value();
}
};
// checks if character is a valid format type
constexpr bool _isfmt_t(char c) {
switch (c) {
default: return false;
case 's': case '?': // strings
case 'c': // char
case 'd': // decimal
case 'b': case 'B': // binary
case 'o': // octal
case 'x': case 'X': // hex
case 'a': case 'A': // float hex
case 'e': case 'E': // scientific notation
case 'f': case 'F': // fixed precision
case 'g': case 'G': // general precision
return true;
}
}
// checks if character is a valid format int type
constexpr bool _isfmt_i(char c) {
switch (c) {
default: return false;
case 'd': // decimal
case 'b': case 'B': // binary
case 'o': // octal
case 'x': case 'X': // hex
return true;
}
}
// checks if character is a valid format float type
constexpr bool _isfmt_f(char c) {
switch (c) {
default: return false;
case 'a': case 'A': // float hex
case 'e': case 'E': // scientific notation
case 'f': case 'F': // fixed precision
case 'g': case 'G': // general precision
return true;
}
}
}
#endif // FENNEC_FORMAT_DETAIL_FORMAT_H

View File

@@ -0,0 +1,378 @@
// =====================================================================================================================
// 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 format.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_FORMAT_FORMAT_H
#define FENNEC_FORMAT_FORMAT_H
#include <fennec/string/string.h>
#include <fennec/format/detail/_format.h>
#include <fennec/format/formatter.h>
namespace fennec
{
template<typename...ArgsT>
string format(const cstring& str, ArgsT&&...args) {
static constexpr size_t argc = sizeof...(ArgsT);
static constexpr format_arg default_fmt = {
.fill = ' ',
.align = '\0', // default to locale
.sign = '\0', // default to sign only for negative numbers, gets handled later in code
.alt = false, // default no prefix
.upper = false,
.width = 0,
.precision = 6, // default to 6 sigfigs
.base = 10,
.type = '\0',
};
// empty case
if constexpr(argc == 0) {
return str;
}
detail::_format_argarray<argc> argarray = { fennec::forward<ArgsT>(args)... };
string res;
size_t i = 0;
size_t arg_c = -1;
while (i <= str.length()) {
size_t brace = str.find('{', i);
size_t end = str.find('}', i);
format_arg fmt = default_fmt;
// check for '}}'
if (end < brace) {
if (str[end + 1] == '}') {
res += string(str.data() + i, end - i);
i = end + 2;
continue;
}
assertf(false, "fennec::format syntax error, encountered unexpected '{'")
}
// append string
if (brace >= str.length()) { // handle end case
res += string(str.data() + i, str.length() - i);
break;
}
res += string(str.data() + i, brace - i);
// next brace, validate escape
size_t next_brace = str.find('{', brace + 1);
if (brace + 1 == next_brace) {
res += '{';
i = next_brace + 1;
continue;
}
// find contained colon
size_t colon = str.find(':', brace);
// validate colon and brace location
assertf(colon < next_brace or end < next_brace, "fennec::format syntax error, mismatched '{}'");
// parse index if present
size_t id = min(colon, end) - 1;
if (id > brace) {
arg_c = 0;
} else {
++arg_c;
}
for (size_t j = id, k = 1; j > brace; --j, k *= 10) {
size_t u = (str[j] - '0');
assertf(u < 10, "fennec::format syntax error, invalid argument index");
arg_c += k * u;
}
// store argument to allow nested replacement fields
size_t arg = arg_c;
// validate index
assertf(arg < argc, "fennec::format syntax error, invalid argument index");
// early return case for no colon
if (colon > end) {
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
res += argarray.format(arg, fmt);
i = end + 1;
continue;
}
// parse format specifiers
// we're going to parse right-to-left since the valid combinations
// of specifiers change based on the type of the argument
// to compensate for this, the nested replacement fields need to be computed in this loop
// (nested replacement deduced)
size_t nrfd = 0;
size_t nnrf = 0;
// first find the matching '}' brace, e is not necessarily the matching brace
// since some specifiers allow nested replacement fields
size_t parse = colon;
while (str[parse + 1] != '}') {
if (next_brace < end) { // if the next brace is before the next closing brace
++nnrf;
nrfd += str[end - 1] == '{';
parse = end + 1;
end = str.find('}', parse);
next_brace = str.find('{', parse);
} else {
parse = end - 1;
break;
}
}
assertf(nrfd <= 2 and parse < str.length() - 1 and str[parse + 1] == '}',
"fennec::format syntax error, mismatched '{}'");
// check type
switch (str[parse]) {
default: break;
case 's': case '?': // strings
case 'c': // char
fmt.type = str[parse--];
break;
case 'd': // decimal
fmt.base = 10;
fmt.type = str[parse--];
break;
case 'B': // binary
fmt.upper = true; [[fallthrough]];
case 'b':
fmt.base = 2;
fmt.type = str[parse--];
break;
case 'o': // octal
fmt.base = 8;
fmt.type = str[parse--];
break;
case 'X': // hex
fmt.upper = true; [[fallthrough]];
case 'x':
fmt.base = 16;
fmt.type = str[parse--];
break;
case 'A':
fmt.upper = true; [[fallthrough]];
case 'a': // float hex
fmt.base = 16;
fmt.type = str[parse--];
break;
case 'E': // scientific notation
fmt.upper = true; [[fallthrough]];
case 'e':
fmt.base = 16;
fmt.type = str[parse--];
break;
case 'F': // fixed precision
fmt.upper = true; [[fallthrough]];
case 'f':
fmt.base = 10;
fmt.type = str[parse--];
break;
case 'G': // general precision
fmt.upper = true; [[fallthrough]];
case 'g':
fmt.base = 10;
fmt.type = str[parse--];
break;
}
// early return
if (parse == colon) {
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
res += argarray.format(arg, fmt);
i = end + 1;
continue;
}
// search for width and precision
size_t x = 0, j = 1;
bool found_decimal = false;
size_t num_decimals = 0;
bool is_float_t = detail::_isfmt_f(fmt.type);
bool is_str_t = fmt.type == 's';
bool is_integer_t = detail::_isfmt_i(fmt.type);
bool ded_width_f = false;
bool ded_width = false;
size_t ded_temp_i = 0;
// default "precision" for strings should be 0 for no limit
if (is_str_t) {
fmt.precision = 0;
}
// parse width and precision
while (isdigit(str[parse]) or (found_decimal = (str[parse] == '.')) or str[parse] == '{' or str[parse] == '}') {
// handle decimal point for precision
if (found_decimal) {
assertf(is_float_t or is_str_t, "fennec::format syntax error, encountered precision argument on non-floating point format");
assertf(num_decimals == 0, "fennec::format syntax error, multiple decimals detected in floating point format");
++num_decimals;
found_decimal = false;
fmt.precision = x;
x = 0, j = 1;
--parse;
continue;
}
// check for nested replacement field
if (str[parse] == '{') {
assertf(str[parse - 1] == '0' or str[parse - 1] == '.' or not isdigit(str[parse - 1]),
"fennec::format syntax error, unexpected digit preceding nested replacement field");
bool prec = str[parse - 1] == '.';
bool ded = str[parse + 1] == '}';
size_t sub;
if (nrfd == 2) { // if both are deduced, parse normally. Hack with prefix and postfix.
sub = prec ? ++arg_c + 1 : arg_c++;
} else if (nrfd == 1 and nnrf == 2 and prec and ded) { // if only precision is nrf, deduce width first
ded_width_f = true;
ded_temp_i = parse;
continue;
} else { // otherwise deduce normally
sub = ded ? ++arg_c : x;
}
assertf(sub < argc, "fennec::format syntax error, argument index out of range in nested replacement field");
assertf(argarray.is_integer(sub), "fennec::format argument error, nested replacement field argument is not convertible to integral type");
(prec ? fmt.precision : fmt.width) = argarray.int_value(sub);
x = 0;
if (ded_width_f) {
ded_width_f = false;
ded_width = true;
swap(ded_temp_i, parse);
arg_c = sub;
continue;
}
if (ded_width) {
parse = ded_temp_i;
ded_width = false;
}
parse -= 1 + prec;
continue;
}
// ignore closing brace for nested replacement fields
if (str[parse] == '}') {
--parse;
continue;
}
// crude way to only handle 0 case if 0 is the last digit
fmt.fill = str[parse] == '0' ? '0' : ' ';
// parse the number
x += j * (str[parse] - '0');
j *= 10;
--parse;
}
if (x != 0) {
fmt.width = x;
}
// early return
if (parse == colon) {
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
res += argarray.format(arg, fmt);
i = end + 1;
continue;
}
// check for alt form
if (str[parse] == '#') {
assertf(is_float_t or is_integer_t, "fennec::format syntax error, encountered alt spec ('#') with non-decimal type");
fmt.alt = true;
--parse;
}
// check for sign
if (str[parse] == '-' or str[parse] == '+' or str[parse] == ' ') {
fmt.sign = str[parse];
if (str[parse] == ' ') { // handle fill if only space, gets overwritten if encounters fill character
fmt.fill = ' ';
}
--parse;
}
// check for alignment
if (str[parse] == '<' or str[parse] == '>' or str[parse] == '^') {
fmt.align = str[parse];
--parse;
}
// fill character
if (str[parse] != ':') {
fmt.fill = str[parse];
if (str[parse] == ' ') {
fmt.sign = fmt.sign == '\0' ? ' ' : fmt.sign;
}
--parse;
}
// default sign
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
// validate that we handled the entire format arg
assertf(parse == colon, "fennec::format syntax error, malformed format string detected, possible double colon");
// add formatted argument
res += argarray.format(arg, fmt);
i = end + 1;
}
return res;
}
}
#endif // FENNEC_FORMAT_FORMAT_H

View 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/>.
// =====================================================================================================================
///
/// \file format_arg.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_FORMAT_FORMAT_ARG_H
#define FENNEC_FORMAT_FORMAT_ARG_H
#include <fennec/lang/types.h>
namespace fennec
{
struct format_arg {
char fill;
char align, sign;
bool alt, upper;
size_t width, precision;
size_t base;
char type;
};
}
#endif // FENNEC_FORMAT_FORMAT_ARG_H

View File

@@ -0,0 +1,249 @@
// =====================================================================================================================
// 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 formatter.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_FORMAT_FORMATTER_H
#define FENNEC_FORMAT_FORMATTER_H
#include <fennec/format/charconv.h>
#include <fennec/string/string.h>
#include <fennec/format/format_arg.h>
namespace fennec
{
// base template =======================================================================================================
///
/// \brief Formatter struct, used to turn values into formatted strings
/// \tparam T The type to format
template<typename T>
struct formatter {
string operator()(const format_arg&, const T&) {
static_assert(false, "Formatter not implemented for the provided type.");
return string("");
}
};
// strings =============================================================================================================
template<size_t N>
struct formatter<char[N]> {
string operator()(const format_arg&, const char (&str)[N]) {
return string(str);
}
};
template<size_t N>
struct formatter<const char[N]> {
string operator()(const format_arg&, const char (&str)[N]) {
return string(str);
}
};
template<>
struct formatter<cstring> {
string operator()(const format_arg&, const cstring& str) {
return str;
}
};
template<>
struct formatter<string> {
string operator()(const format_arg&, const string& str) {
return str;
}
};
// decimal types =======================================================================================================
template<typename IntT> requires(is_integral_v<IntT> and not is_bool_v<IntT>)
struct formatter<IntT> {
string operator()(const format_arg& fmt, IntT x) {
char digits[128] = {};
auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.base);
assertf(chk != nullptr, "fennec::format error, to_chars error");
size_t len = chk - digits;
// handle uppercase
if (fmt.upper) {
for (auto& digit : digits) {
if (digit == 0) {
break;
}
digit = toupper(digit);
}
}
const bool has_sign = (x < 0 or fmt.sign != '-');
const bool zero = fmt.fill == '0';
const size_t prefix = fmt.alt ? (fmt.type == 'd' ? 0 : 2 - (fmt.type == 'o')) : 0;
const size_t sgnlen = len + (zero ? has_sign + prefix : 0);
const size_t explen = fennec::max(sgnlen, fmt.width) + (zero ? 0 : has_sign + prefix);
const size_t fill = fmt.width > sgnlen ? fmt.width - sgnlen : 0;
size_t sign = 0;
string res = string(explen);
if (fill > 0) {
switch (fmt.align) {
case '<':
memcpy(res.data() + has_sign + prefix, digits, len);
memset(res.data() + has_sign + prefix + len, fmt.fill == '0' ? ' ' : fmt.fill, fill);
break;
case '>': case '\0':
memcpy(res.data() + explen - len, digits, len);
sign = fmt.fill == '0' ? 0 : explen - len - 1 - prefix;
memset(res.data(), fmt.fill, explen - len);
break;
case '^':
size_t bef = fill / 2 + has_sign + prefix;
size_t aft = explen - bef;
memcpy(res.data() + bef, digits, len);
sign = fmt.fill == '0' ? 0 : bef - 1 - prefix;
memset(res.data(), fmt.fill, bef);
memset(res.data() + bef + len, fmt.fill == '0' ? ' ' : fmt.fill, aft);
break;
}
} else {
memcpy(res.data() + has_sign + prefix, digits, len);
}
if (has_sign) {
res[sign] = (x < 0) ? '-' : fmt.sign;
}
if (prefix) {
res[sign + has_sign] = '0';
if (fmt.type != 'o') {
res[sign + has_sign + 1] = fmt.type;
}
}
return res;
}
};
template<typename BoolT> requires(is_bool_v<BoolT>)
struct formatter<BoolT> {
string operator()(const format_arg& fmt, BoolT x) {
if (fmt.type == 's' or fmt.type == '\0') {
return x ? string("true") : string("false");
}
return formatter<uint8_t>{}(fmt, static_cast<uint8_t>(x));
}
};
template<typename FloatT> requires(is_floating_point_v<FloatT>)
struct formatter<FloatT> {
string operator()(const format_arg& fmt, FloatT x) {
// nan & inf cases
if (fennec::isnan(x)) {
return string("nan");
}
if (fennec::isinf(x)) {
return string("inf");
}
char digits[128] = {};
auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.type, fmt.precision);
assertf(chk != nullptr, "fennec::format error, to_chars error");
size_t len = chk - digits;
// handle uppercase
if (fmt.upper) {
for (auto& digit : digits) {
if (digit == 0) {
break;
}
digit = toupper(digit);
}
}
const bool has_sign = (x < 0 or fmt.sign != '-');
const bool zero = fmt.fill == '0';
const size_t prefix = fmt.alt ? 2 : 0;
const size_t sgnlen = len + (zero ? has_sign + prefix : 0);
const size_t explen = fennec::max(sgnlen, fmt.width) + (zero ? 0 : has_sign + prefix);
const size_t fill = fmt.width > sgnlen ? fmt.width - sgnlen : 0;
size_t sign = 0;
string res = string(explen);
if (fill > 0) {
switch (fmt.align) {
case '<':
memcpy(res.data() + has_sign + prefix, digits, len);
memset(res.data() + has_sign + prefix + len, fmt.fill == '0' ? ' ' : fmt.fill, fill);
break;
case '>': case '\0':
memcpy(res.data() + explen - len, digits, len);
sign = fmt.fill == '0' ? 0 : explen - len - 1 - prefix;
memset(res.data(), fmt.fill, explen - len);
break;
case '^':
size_t bef = fill / 2 + has_sign + prefix;
size_t aft = explen - bef;
memcpy(res.data() + bef, digits, len);
sign = fmt.fill == '0' ? 0 : bef - 1 - prefix;
memset(res.data(), fmt.fill, bef);
memset(res.data() + bef + len, fmt.fill == '0' ? ' ' : fmt.fill, aft);
break;
}
} else {
memcpy(res.data() + has_sign + prefix, digits, len);
}
if (has_sign) {
res[sign] = (x < 0) ? '-' : fmt.sign;
}
if (prefix) {
res[sign + has_sign] = '0';
res[sign + has_sign + 1] = fmt.type + ('x' - 'a');
}
return res;
}
};
}
#endif // FENNEC_FORMAT_FORMATTER_H

View 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 mesh_instance.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_GFX3D_MESH_INSTANCE_H
#define FENNEC_GFX3D_MESH_INSTANCE_H
#include <fennec/scene/component.h>
namespace fennec
{
class mesh_instance : component {
public:
private:
};
}
#endif // FENNEC_GFX3D_MESH_INSTANCE_H

View 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/>.
// =====================================================================================================================
///
/// \file tokenizer.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_INTERPRET_TOKENIZER_H
#define FENNEC_INTERPRET_TOKENIZER_H
#include <fennec/containers/list.h>
#include <fennec/containers/map.h>
#include <fennec/containers/priority_queue.h>
#include <fennec/string/string.h>
//
// escape sequences are tricky, sometimes they must be separated by white space,
// other times they don't. Requiring a list of all possible escape sequences is unrealistic.
// We need to allow the user of this struct to specify rules for escape sequences. Here are some basic rules:
//
// An escape sequence is marked by an escape character, e.g. %, \, {{
// Multiple escape characters may be used in a single tokenizer and will have different rules
// Escape characters may also be operators, brackets, or quotes
// Escape sequences may contain operators, brackets, or quotes
//
// Here are a few examples of escape sequences from various formats and languages
// C: \\, \n, \0, \u200b
// PrintF: %s, %2.2f
// Python FMT: {{, }}
// SPSS: ''
//
namespace fennec
{
struct escape_sequence {
virtual size_t operator[](const string& str, size_t i) = 0;
};
struct tokenizer {
using escseq = escape_sequence*;
using escmap = map<char, escape_sequence*>;
string delimiter; // markers that separate tokens
string operators; // operators are treated as individual tokens
string brackets; // characters that mark brackets
string quotes; // characters that mark a string sequence, entire string sequence is treated as one token
escmap escapes; // characters that mark the start of an escape sequence and validate them
bool numbers; // Anything that resembles a number
enum token_ : uint8_t {
token_text = 0,
token_integer,
token_string,
token_newline,
token_escaped,
token_operator,
token_bracket,
token_quoted,
num_token_types
};
using token = pair<string, uint8_t>;
private:
static constexpr uint8_t token_delimiter = num_token_types;
constexpr list<token> operator()(const string& line) {
list<token> res;
priority_queue<pair<size_t, uint8_t>> idx;
for (char c : delimiter) {
size_t i = 0;
while (i != line.size()) {
size_t n = line.find(c, i);
// TODO
}
}
return res;
}
private:
};
}
#endif // FENNEC_INTERPRET_TOKENIZER_H

View File

@@ -0,0 +1,48 @@
// =====================================================================================================================
// 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 declval.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_LANGCPP_DECLVAL_H
#define FENNEC_LANGCPP_DECLVAL_H
#include <fennec/lang/detail/_declval.h>
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);
}
}
#endif // FENNEC_LANGCPP_DECLVAL_H

View File

@@ -0,0 +1,46 @@
// =====================================================================================================================
// 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 _declval.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_LANG_DETAIL_DECLVAL_H
#define FENNEC_LANG_DETAIL_DECLVAL_H
#include <fennec/lang/constants.h>
namespace fennec::detail
{
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_DECLVAL_H

View File

@@ -19,13 +19,19 @@
#ifndef FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
#define FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
#include <fennec/math/common.h>
#include <fennec/lang/type_transforms.h>
namespace fennec::detail
{
template<typename...TypesT> struct _type_sequence {};
template<typename FirstT, typename... RestT> struct _first_element : type_identity<FirstT> {};
// fennec::nth_element =================================================================================================
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> {};
@@ -35,6 +41,56 @@ namespace fennec::detail
n == i, HeadT,
typename _nth_element<n, i + 1, RestT...>::type
> {};
// fennec::max_element_size ============================================================================================
template<size_t, typename...> struct _max_element_size;
template<size_t M, typename HeadT>
struct _max_element_size<M, HeadT>
: integral_constant<size_t, fennec::max(M, sizeof(HeadT))> {
};
template<size_t M, typename HeadT, typename...RestT>
struct _max_element_size<M, HeadT, RestT...>
: _max_element_size<fennec::max(M, sizeof(HeadT)), RestT...> {
};
// fennec::find_element ================================================================================================
template<size_t N, typename, typename...> struct _find_element;
template<size_t N, typename FindT, typename HeadT>
struct _find_element<N, FindT, HeadT> : integral_constant<size_t, is_same_v<FindT, HeadT> ? N : N + 1> {};
template<size_t N, typename FindT, typename HeadT, typename...RestT> requires(is_same_v<FindT, HeadT>)
struct _find_element<N, FindT, HeadT, RestT...>
: conditional_t<is_same_v<FindT, HeadT>, integral_constant<size_t, N>, _find_element<N + 1, FindT, RestT...>> {};
// fennec::search_element ==============================================================================================
template<template<typename> typename, typename...> struct _search_element;
template<template<typename> typename SearchT> struct _search_element<SearchT> : type_identity<void> {};
template<template<typename> typename SearchT, typename HeadT, typename...RestT> requires(SearchT<HeadT>{})
struct _search_element<SearchT, HeadT, RestT...>
: conditional_t<SearchT<HeadT>{}, type_identity<HeadT>, _search_element<SearchT, RestT...>> {
};
template<template<typename, typename...> typename, typename, typename...> struct _search_element_args;
template<template<typename, typename...> typename SearchT, typename...ArgsT>
struct _search_element_args<SearchT, _type_sequence<ArgsT...>> : type_identity<void> {};
template<template<typename, typename...> typename SearchT, typename HeadT, typename...RestT, typename...ArgsT>
struct _search_element_args<SearchT, _type_sequence<ArgsT...>, HeadT, RestT...>
: conditional_t<SearchT<HeadT, ArgsT...>{}, type_identity<HeadT>, _search_element_args<SearchT, _type_sequence<ArgsT...>, RestT...>> {};
}
#endif // FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H

View File

@@ -19,8 +19,9 @@
#ifndef FENNEC_LANG_DETAIL_TYPE_TRAITS_H
#define FENNEC_LANG_DETAIL_TYPE_TRAITS_H
#include <fennec/lang/ranges.h>
#include <fennec/lang/constants.h>
#include <fennec/lang/float.h>
#include <fennec/lang/declval.h>
namespace fennec::detail
{
@@ -62,14 +63,83 @@ namespace fennec::detail
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> 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> struct _is_reference : false_type {};
template<typename T> struct _is_reference<T&> : true_type {};
template<typename T> struct _is_reference<T&&> : true_type {};
template<typename T> struct _declval_protector : bool_constant<false> {};
template<typename> struct _is_lvalue_reference : false_type {};
template<typename T> struct _is_lvalue_reference<T&> : true_type {};
template<typename> struct _is_rvalue_reference : false_type {};
template<typename T> struct _is_rvalue_reference<T&&> : true_type {};
template<typename T> struct _is_complete {
template<typename U>
static auto test(U*) -> bool_constant<sizeof(U) == sizeof(U)>;
static auto test(...) -> false_type;
using type = decltype(_is_complete::test(static_cast<T*>(nullptr)));
};
template<typename T> struct _is_destructible {
template<typename U, typename = decltype(declval<T&>().~T())>
static auto test(int) -> true_type;
template<typename>
static auto test(...) -> false_type;
using type = decltype(test<T>(0));
};
template<typename T> struct _is_nothrow_destructible {
template<typename U, typename = decltype(noexcept(declval<T&>().~T()))>
static auto test(int) -> true_type;
template<typename>
static auto test(...) -> false_type;
using type = decltype(test<T>(0));
};
// https://stackoverflow.com/questions/13830158/how-to-write-a-trait-which-checks-whether-a-type-is-iterable
template<typename T>
auto _is_iterable(int) -> decltype(
fennec::begin(declval<T&>()) != fennec::end(declval<T&>()),
void(),
++declval<decltype(fennec::begin(declval<T&>()))&>(),
void(*fennec::begin(declval<T&>())),
true_type{}
);
template<typename T>
auto _is_iterable(...) -> false_type;
template<typename T>
auto _is_indexable(int) -> decltype(
declval<T&>()[0],
true_type{}
);
template<typename T>
auto _is_indexable(...) -> false_type;
template<typename T>
auto _is_mappable(int) -> decltype(
declval<T&>()[declval<typename T::key_t&>()],
true_type{}
);
template<typename T>
auto _is_mappable(...) -> false_type;
template<typename B> auto _ptr_conv(const volatile B*) -> true_type;
template<typename> auto _ptr_conv(const volatile void*) -> false_type;
template<typename B, typename D> auto _is_base_of(int) -> decltype(detail::_ptr_conv<B>(static_cast<D*>(nullptr)));
template<typename, typename> auto _is_base_of(...) -> false_type;
}
#endif // FENNEC_LANG_DETAIL_TYPE_TRAITS_H

View File

@@ -102,6 +102,9 @@
// Most major compilers support __has_builtin, notably GCC, MINGW, and CLANG
#if defined(__has_builtin)
// UTILITIES ===========================================================================================================
// addressof is very difficult to implement without intrinsics.
#if __has_builtin(__builtin_addressof)
# define FENNEC_HAS_BUILTIN_ADDRESSOF 1
@@ -118,6 +121,37 @@
# define FENNEC_HAS_BUILTIN_BIT_CAST 0
#endif
#if __has_builtin(__builtin_LINE)
# define FENNEC_HAS_BUILTIN_LINE 1
# define FENNEC_BUILTIN_LINE() __builtin_LINE()
#else
# define FENNEC_HAS_BUILTIN_LINE 0
#endif
#if __has_builtin(__builtin_COLUMN)
# define FENNEC_HAS_BUILTIN_COLUMN 1
# define FENNEC_BUILTIN_COLUMN() __builtin_COLUMN()
#else
# define FENNEC_HAS_BUILTIN_COLUMN 0
#endif
#if __has_builtin(__builtin_FILE)
# define FENNEC_HAS_BUILTIN_FILE 1
# define FENNEC_BUILTIN_FILE() __builtin_FILE()
#else
# define FENNEC_HAS_BUILTIN_FILE 0
#endif
#if __has_builtin(__builtin_FUNCTION)
# define FENNEC_HAS_BUILTIN_FUNCTION 1
# define FENNEC_BUILTIN_FUNCTION() __builtin_FUNCTION()
#else
# define FENNEC_HAS_BUILTIN_FUNCTION 0
#endif
// PROPERTIES ==========================================================================================================
// Inconsistent without intrinsics
#if __has_builtin(__is_abstract)
# define FENNEC_HAS_BUILTIN_IS_ABSTRACT 1
@@ -142,6 +176,7 @@
# define FENNEC_HAS_BUILTIN_IS_CLASS
#endif
// CONSTRUCTORS ========================================================================================================
// Difficult and Inconsistent without intrinsics
@@ -213,6 +248,14 @@
# define FENNEC_HAS_BUILTIN_IS_ENUM 0
#endif
// Inconsistent without intrinsics.
#if __has_builtin(__is_union)
# define FENNEC_HAS_BUILTIN_IS_UNION 1
# define FENNEC_BUILTIN_IS_UNION(arg) __is_union(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_UNION 0
#endif
// Inconsistent without intrinsics
#if __has_builtin(__is_final)
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
@@ -221,12 +264,20 @@
# 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)
// Inconsistent without intrinsics
#if __has_builtin(__is_function)
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 1
# define FENNEC_BUILTIN_IS_FUNCTION(arg) __is_function(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 0
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 0
#endif
// Inconsistent without intrinsics
#if __has_builtin(__is_object)
# define FENNEC_HAS_BUILTIN_IS_OBJECT 1
# define FENNEC_BUILTIN_IS_OBJECT(arg) __is_object(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 0
#endif
// Inconsistent without intrinsics

View File

@@ -42,7 +42,8 @@
/// - \subpage fennec_lang_constants
/// - \subpage fennec_lang_conditional_types
/// - \subpage fennec_lang_numeric_transforms
/// - \subpage fennec_lang_sequences
/// - \subpage fennec_lang_metasequences
/// - \subpage fennec_lang_type_identity
/// - \subpage fennec_lang_type_sequences
/// - \subpage fennec_lang_type_traits
/// - \subpage fennec_lang_type_transforms

View File

@@ -17,8 +17,8 @@
// =====================================================================================================================
///
/// \file sequences.h
/// \brief \ref fennec_lang_sequences
/// \file metasequences.h
/// \brief \ref fennec_lang_metasequences
///
///
/// \details
@@ -32,40 +32,40 @@
#define FENNEC_LANG_SEQUENCES_H
///
/// \page fennec_lang_sequences Sequences
/// \page fennec_lang_metasequences Metasequences
///
/// \brief This header is part of the metaprogramming library. It defines structures for sequences of values, used during compile time.
/// \brief This header is part of the metaprogramming library. It defines structures for metasequences of values, used during compile time.
///
/// \code #include <fennec/lang/sequences.h> \endcode
/// \code #include <fennec/lang/metasequences.h> \endcode
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_sequences">
/// <table width="100%" class="fieldtable" id="table_fennec_lang_metasequences">
/// <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>
/// \ref fennec::metasequence "metasequence<ValueT, Values...>"<br>
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::sequence
/// \copydetails fennec::metasequence
///
/// <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>"
/// \ref fennec::integer_metasequence "integer_metasequence<IntT, Values...>"<br>
/// \ref fennec::make_integer_metasequence "typename make_integer_metasequence<IntT, N>::type"<br>
/// \ref fennec::make_integer_metasequence_t "make_integer_metasequence_t<IntT, N>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::integer_sequence
/// \copydetails fennec::integer_metasequence
///
/// <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>"
/// \ref fennec::index_metasequence "index_metasequence<Indices...>"<br>
/// \ref fennec::make_index_metasequence "typename make_index_metasequence<N>::type"<br>
/// \ref fennec::make_index_metasequence_t "make_index_metasequence_t<N>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::index_sequence
/// \copydetails fennec::index_metasequence
///
/// <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>
/// \ref fennec::concat_metasequence "typename concat_metasequence<metasequenceT0, metasequenceT1>::type"<br>
/// \ref fennec::concat_metasequence_t "concat_metasequence_t<metasequenceT0, metasequenceT1>"<br>
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::concat_sequence
/// \copydetails fennec::concat_metasequence
///
/// </table>
///
@@ -75,7 +75,7 @@
namespace fennec
{
// fennec::sequence ====================================================================================================
// fennec::metasequence ====================================================================================================
///
/// \brief metaprogramming sequence
@@ -84,20 +84,20 @@ namespace fennec
/// 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...>)
/// constexpr TypeT summation(metasequence<TypeT, Values...>)
/// {
/// return (Values + ...);
/// }
/// \endcode
/// \tparam ValueT type of the values
/// \tparam Values sequence values
template<typename ValueT, ValueT...Values> struct const_sequence
template<typename ValueT, ValueT...Values> struct metasequence
{
/// \brief type of the sequence
/// \brief type of the metasequence
using value_type = ValueT;
/// \brief self-referential type
using type = const_sequence;
using type = metasequence;
///
/// \brief returns the number of elements
@@ -110,22 +110,22 @@ template<typename ValueT, ValueT...Values> struct const_sequence
// fennec::integer_sequence ============================================================================================
// fennec::integer_metasequence ============================================================================================
///
/// \brief metaprogramming integral sequence
/// \brief metaprogramming integral metasequence
///
/// \details A `fennec::sequence` specialized integer types.
/// \details A `fennec::metasequence` 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...>
struct integer_metasequence : metasequence<IntT, Values...>
{
/// \brief type of the sequence
using value_type = IntT;
/// \brief self-referential type
using type = const_integer_sequence;
using type = integer_metasequence;
///
/// \brief returns the number of elements
@@ -138,33 +138,33 @@ struct const_integer_sequence : const_sequence<IntT, Values...>
///
/// \brief generate a fennec::integer_sequence \f$\left[\,0\,\ldots\,N\,\right)\f$
/// \brief generate a fennec::integer_metasequence \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;
/// \tparam N size of the metasequence to generate
template<typename IntT, size_t N> struct make_integer_metasequence;
///
/// \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;
template<typename IntT, size_t N> using make_integer_metasequence_t = typename make_integer_metasequence<IntT, N>::type;
// fennec::index_sequence ==============================================================================================
// fennec::index_metasequence ==============================================================================================
///
/// \brief metaprogramming integral sequence
/// \brief metaprogramming integral metasequence
///
/// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices.
/// \details A `fennec::integer_metasequence` 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...>
template<size_t...Indices> struct index_metasequence : integer_metasequence<size_t, Indices...>
{
/// \brief type of the sequence
using value_type = size_t;
/// \brief self-referential type
using type = const_index_sequence;
using type = index_metasequence;
///
/// \brief returns the number of elements
@@ -177,67 +177,67 @@ template<size_t...Indices> struct const_index_sequence : const_integer_sequence<
///
/// \brief generate a fennec::index_sequence \f$\left[\,0\,\ldots\,N\,\right)\f$
/// \brief generate a fennec::index_metasequence \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;
template<size_t N> struct make_index_metasequence;
///
/// \brief shorthand for ```typename make_index_sequence<N>::type```
template<size_t N> using make_index_sequence_t = typename make_index_sequence<N>::type;
/// \brief shorthand for ```typename make_index_metasequence<N>::type```
template<size_t N> using make_index_metasequence_t = typename make_index_metasequence<N>::type;
// fennec::concat_sequence =============================================================================================
// fennec::concat_metasequence =============================================================================================
///
/// \brief concatenate two sequences
/// \brief concatenate two metasequences
///
/// \details A tool for concatenating two `fennec::sequence` types.
/// \details A tool for concatenating two `fennec::metasequence` types.
/// \tparam SequenceT0 lhs
/// \tparam SequenceT1 rhs
template<typename SequenceT0, typename SequenceT1> struct concat_sequence;
template<typename SequenceT0, typename SequenceT1> struct concat_metasequence;
///
/// \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 shorthand for ```typename concat_metasequence<SequenceT0, SequenceT1>::type```
template<typename SequenceT0, typename SequenceT1> using concat_metasequence_t
= typename concat_metasequence<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>>{};
template<typename T, size_t N> struct make_integer_metasequence : concat_metasequence_t<make_integer_metasequence_t<T, N / 2>, make_integer_metasequence_t<T, N - N / 2>>{};
// Base Case of N=0
template<typename T> struct make_integer_sequence<T, 0> : const_integer_sequence<T> {};
template<typename T> struct make_integer_metasequence<T, 0> : integer_metasequence<T> {};
// Base Case of N=1
template<typename T> struct make_integer_sequence<T, 1> : const_integer_sequence<T, 0>{};
template<typename T> struct make_integer_metasequence<T, 1> : integer_metasequence<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>>{};
template<size_t N> struct make_index_metasequence : concat_metasequence_t<make_index_metasequence_t<N / 2>, make_index_metasequence_t<N - N / 2>>{};
// Base Case of N=0
template<> struct make_index_sequence<0> : const_index_sequence<> {};
template<> struct make_index_metasequence<0> : index_metasequence<> {};
// Base Case of N=1
template<> struct make_index_sequence<1> : const_index_sequence<0>{};
template<> struct make_index_metasequence<1> : index_metasequence<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)...>{};
struct concat_metasequence<integer_metasequence<T, SequenceV0...>, integer_metasequence<T, SequenceV1...>>
: integer_metasequence<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)...>{};
struct concat_metasequence<index_metasequence<SequenceV0...>, index_metasequence<SequenceV1...>>
: index_metasequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};

View File

@@ -0,0 +1,72 @@
// =====================================================================================================================
// 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 ranges.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_LANGCPP_RANGES_H
#define FENNEC_LANGCPP_RANGES_H
#include <fennec/lang/types.h>
namespace fennec
{
template<typename ContainerT>
inline constexpr auto begin(ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
return c.begin();
}
template<typename ContainerT>
inline constexpr auto begin(const ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
return c.begin();
}
template<typename T, size_t N>
inline constexpr T* begin(T (&arr)[N]) noexcept {
return arr;
}
template<typename ContainerT>
inline constexpr auto end(ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
return c.end();
}
template<typename ContainerT>
inline constexpr auto end(const ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
return c.end();
}
template<typename T, size_t N>
inline constexpr T* end(T (&arr)[N]) noexcept {
return arr + N;
}
}
#endif // FENNEC_LANGCPP_RANGES_H

View File

@@ -20,9 +20,13 @@
#define FENNEC_LANG_STARTUP_H
// Helper for running a function before main()
#define STATIC_CONSTRUCTOR(f) \
#define FENNEC_PRIVATE_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)
#define FENNEC_CLASS_STATIC_CONSTRUCTOR(f) \
struct f##_t_ { inline f##_t_(void) { f(); } }; inline static f##_t_ f##_; \
inline static void f(void)
#endif // FENNEC_LANG_STARTUP_H

View File

@@ -51,6 +51,12 @@
/// \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
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_unique "is_unique<TypesT...>::value"<br>
/// \ref fennec::is_unique_v "is_unique_v<TypesT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydoc fennec::is_unique
/// </table>
///
@@ -59,6 +65,12 @@
namespace fennec
{
template<typename...TypesT> struct type_sequence {};
// fennec::first_element ===============================================================================================
///
/// \brief Get the first element of a template parameter pack
/// \tparam TypesT the Parameter Pack
@@ -69,8 +81,20 @@ template<typename...TypesT> struct first_element : detail::_first_element<TypesT
template<typename...TypesT> using first_element_t = typename first_element<TypesT...>::type;
// fennec::nth_element =================================================================================================
///
/// \brief Gets the type of the nth element of the type sequence `TypesT...`
/// \tparam n The index in the type sequence
/// \tparam TypesT The type sequence
template<size_t n, typename...TypesT> struct nth_element : detail::_nth_element<n, 0, TypesT...> {};
template<size_t n, typename...TypesT> using nth_element_t = nth_element<n, TypesT...>::type;
// fennec::replace_first_element =======================================================================================
///
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first `ArgT` of `ArgsT...` with `SubT`
@@ -84,6 +108,99 @@ template<
struct replace_first_element<ClassT<OriginT, RestT...>, SubT> // Specialization
{ using type = ClassT<SubT, RestT...>; }; // Definition
// fennec::max_element_size ============================================================================================
///
/// \brief Gets the max value of the size of each type in the sequence, i.e. `max(sizeof(Ts)...)`
/// \tparam Ts The type sequence to check
template<typename...Ts> struct max_element_size : detail::_max_element_size<0, Ts...> {};
///
/// \brief Shorthand for `max_element_size<Ts...>::value`
/// \tparam Ts The type sequence to check
template<typename...Ts> constexpr size_t max_element_size_v = max_element_size<Ts...>::value;
// fennec::find_element ================================================================================================
///
/// \brief Finds the index of `T` in `Ts`, if `T` is not found, results in `sizeof...(Ts)`
/// \tparam T The type to find
/// \tparam Ts The type sequence to check
template<typename T, typename...Ts> struct find_element : detail::_find_element<0, T, Ts...> {};
///
/// \brief Shorthand for `find_element<T, Ts...>::value`
/// \tparam T The type to find
/// \tparam Ts The type sequence to check
template<typename T, typename...Ts> constexpr size_t find_element_v = find_element<T, Ts...>::value;
// fennec::search_element ==============================================================================================
///
/// \brief Find the first element in `TypesT...` that satisfies `SearchT<T>`
/// \tparam SearchT A type that satisfies `template<typename>` and contains `static constexpr bool value;` to use for searching
/// \tparam TypesT The type sequence to search
template<template<typename> typename SearchT, typename...TypesT> struct search_element : detail::_search_element<SearchT, TypesT...> {};
///
/// \brief Shorthand for `search_element_t<T, Ts...>::type`
/// \tparam SearchT A type that satisfies `template<typename>` and contains `static constexpr bool value;` to use for searching
/// \tparam TypesT The type sequence to search
template<template<typename> typename SearchT, typename...TypesT> using search_element_t = search_element<SearchT, TypesT...>::type;
template<template<typename, typename...> typename, typename, typename...> struct search_element_args;
template<template<typename, typename...> typename SearchT, typename...TypesT, typename...ArgsT>
struct search_element_args<SearchT, type_sequence<ArgsT...>, TypesT...>
: detail::_search_element_args<SearchT, detail::_type_sequence<ArgsT...>, TypesT...> {
};
// fennec::contains_element ============================================================================================
///
/// \brief Checks if the type sequence `Ts...` contains `T`
/// \tparam T The type to find
/// \tparam Ts The type sequence to check
template<typename T, typename...Ts> struct contains_element : bool_constant<(is_same_v<T, Ts> or ...)> {};
///
/// \brief Shorthand for `contains_element_v<T, Ts...>::value`
/// \tparam T The type to find
/// \tparam Ts The type sequence to check
template<typename T, typename...Ts> constexpr bool contains_element_v = contains_element<T, Ts...>::value;
// fennec::is_unique ===================================================================================================
///
/// \brief Checks if all types in a type sequence are unique
/// \tparam Ts The type sequence to check
template<typename...Ts> struct is_unique : false_type {};
// Single type case
template<typename T> struct is_unique<T> : true_type {};
// Recursion case
template<typename T, typename...Ts> requires(not is_same_v<T, Ts> && ...)
struct is_unique<T, Ts...> : is_unique<Ts...> {};
///
/// \brief Shorthand for `is_unique<Ts...>::value`
/// \tparam Ts The type sequence to check
template<typename...Ts> constexpr bool is_unique_v = is_unique<Ts...>::value;
}

View File

@@ -40,7 +40,10 @@
/// \code #include <fennec/lang/type_traits.h> \endcode
///
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits">
///
/// \section Primary Type Categories
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits_primary_categories">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
@@ -50,6 +53,12 @@
/// \copydetails fennec::is_void
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_null_pointer "is_null_pointer<TypeT>::value"<br>
/// \ref fennec::is_null_pointer_v "is_null_pointer_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_null_pointer
///
/// <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">
@@ -62,6 +71,212 @@
/// \copydetails fennec::is_integral
///
/// <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_array "is_array<TypeT>::value"<br>
/// \ref fennec::is_array_v "is_array_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_array
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_enum "is_enum<TypeT>::value"<br>
/// \ref fennec::is_enum_v "is_enum_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_enum
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_union "is_union<TypeT>::value"<br>
/// \ref fennec::is_union_v "is_union_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_union
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_class "is_class<TypeT>::value"<br>
/// \ref fennec::is_class_v "is_class_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_class
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_function "is_function<TypeT>::value"<br>
/// \ref fennec::is_function_v "is_function_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_function
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_pointer "is_pointer<TypeT>::value"<br>
/// \ref fennec::is_pointer_v "is_pointer_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_pointer
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_lvalue_reference "is_lvalue_reference<TypeT>::value"<br>
/// \ref fennec::is_lvalue_reference_v "is_lvalue_reference_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_lvalue_reference
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_rvalue_reference "is_rvalue_reference<TypeT>::value"<br>
/// \ref fennec::is_rvalue_reference_v "is_rvalue_reference_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_rvalue_reference
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_member_object_pointer "is_member_object_pointer<TypeT>::value"<br>
/// \ref fennec::is_member_object_pointer_v "is_member_object_pointer_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_member_object_pointer
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_member_function_pointer "is_member_function_pointer<TypeT>::value"<br>
/// \ref fennec::is_member_function_pointer_v "is_member_function_pointer_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_member_function_pointer
///
/// </table>
///
///
///
/// \section Composite Type Categories
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits_composite_categories">
/// <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_fundamental "is_fundamental<TypeT>::value"<br>
/// \ref fennec::is_fundamental_v "is_fundamental_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_fundamental
///
/// <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_scalar "is_scalar<TypeT>::value"<br>
/// \ref fennec::is_scalar_v "is_scalar_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_scalar
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_object "is_object<TypeT>::value"<br>
/// \ref fennec::is_object_v "is_object_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_object
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_compound "is_compound<TypeT>::value"<br>
/// \ref fennec::is_compound_v "is_compound_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_compound
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_reference "is_reference<TypeT>::value"<br>
/// \ref fennec::is_reference_v "is_reference_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_reference
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_member_pointer "is_member_pointer<TypeT>::value"<br>
/// \ref fennec::is_member_pointer_v "is_member_pointer_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_member_pointer
///
/// </table>
///
///
///
/// \section Type Properties
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits_type_properties">
/// <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_const "is_const<TypeT>::value"<br>
/// \ref fennec::is_const_v "is_const_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_const
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_volatile "is_volatile<TypeT>::value"<br>
/// \ref fennec::is_volatile_v "is_volatile_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_volatile
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_trivial "is_trivial<TypeT>::value"<br>
/// \ref fennec::is_trivial_v "is_trivial_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_trivial
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_trivially_copyable "is_trivially_copyable<TypeT>::value"<br>
/// \ref fennec::is_trivially_copyable_v "is_trivially_copyable_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_trivially_copyable
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_standard_layout "is_standard_layout<TypeT>::value"<br>
/// \ref fennec::is_standard_layout_v "is_standard_layout_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_standard_layout
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::has_unique_object_representations "has_unique_object_representations<TypeT>::value"<br>
/// \ref fennec::has_unique_object_representations_v "has_unique_object_representations_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::has_unique_object_representations
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_empty "is_empty<TypeT>::value"<br>
/// \ref fennec::is_empty_v "is_empty_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_empty
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_polymorphic "is_polymorphic<TypeT>::value"<br>
/// \ref fennec::is_polymorphic_v "is_polymorphic_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_polymorphic
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_abstract "is_abstract<TypeT>::value"<br>
/// \ref fennec::is_abstract_v "is_abstract_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_abstract
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_complete "is_complete<TypeT>::value"<br>
/// \ref fennec::is_complete_v "is_complete_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_complete
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_final "is_final<TypeT>::value"<br>
/// \ref fennec::is_final_v "is_final_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_final
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_aggregate "is_aggregate<TypeT>::value"<br>
/// \ref fennec::is_aggregate_v "is_aggregate_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_aggregate
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_implicit_lifetime "is_implicit_lifetime<TypeT>::value"<br>
/// \ref fennec::is_implicit_lifetime_v "is_implicit_lifetime_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_implicit_lifetime
///
/// <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">
@@ -74,22 +289,32 @@
/// \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>"
/// \ref fennec::is_bounded_array "is_bounded_array<TypeT>::value"<br>
/// \ref fennec::is_bounded_array_v "is_bounded_array_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_floating_point
/// \copydetails fennec::is_bounded_array
///
/// <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>"
/// \ref fennec::is_unbounded_array "is_unbounded_array<TypeT>::value"<br>
/// \ref fennec::is_unbounded_array_v "is_unbounded_array_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_arithmetic
/// \copydetails fennec::is_unbounded_array
///
/// <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>"
/// \ref fennec::is_scoped_enum "is_scoped_enum<TypeT>::value"<br>
/// \ref fennec::is_scoped_enum_v "is_scoped_enum_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_same
/// \copydetails fennec::is_scoped_enum
///
/// </table>
///
///
///
/// \section Supported Operations
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits_supported_operations">
/// <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_convertible "is_convertible<TypeT0, TypeT1>::value"<br>
@@ -100,25 +325,115 @@
/// <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...>"
/// \ref fennec::is_trivially_constructible "is_trivially_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_constructible_v "is_trivially_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_constructible "is_nothrow_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_constructible_v "is_nothrow_constructible_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydoc fennec::is_constructible
/// \copydetails fennec::is_constructible
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_default_constructible "is_default_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_default_constructible_v "is_default_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_default_constructible "is_trivially_default_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_default_constructible_v "is_trivially_default_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_default_constructible "is_nothrow_default_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_default_constructible_v "is_nothrow_default_constructible_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_default_constructible
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_copy_constructible "is_copy_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_copy_constructible_v "is_copy_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_copy_constructible "is_trivially_copy_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_copy_constructible_v "is_trivially_copy_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_copy_constructible "is_nothrow_copy_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_copy_constructible_v "is_nothrow_copy_constructible_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_copy_constructible
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_move_constructible "is_move_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_move_constructible_v "is_move_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_move_constructible "is_trivially_move_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_move_constructible_v "is_trivially_move_constructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_move_constructible "is_nothrow_move_constructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_move_constructible_v "is_nothrow_move_constructible_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_move_constructible
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_assignable "is_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_assignable_v "is_assignable_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_assignable "is_trivially_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_assignable_v "is_trivially_assignable_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_assignable "is_nothrow_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_assignable_v "is_nothrow_assignable_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_assignable
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_copy_assignable "is_copy_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_copy_assignable_v "is_copy_assignable_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_copy_assignable "is_trivially_copy_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_copy_assignable_v "is_trivially_copy_assignable_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_copy_assignable "is_nothrow_copy_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_copy_assignable_v "is_nothrow_copy_assignable_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_copy_assignable
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_move_assignable "is_move_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_move_assignable_v "is_move_assignable_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_move_assignable "is_trivially_move_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_move_assignable_v "is_trivially_move_assignable_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_move_assignable "is_nothrow_move_assignable<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_move_assignable_v "is_nothrow_move_assignable_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_move_assignable
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_destructible "is_destructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_destructible_v "is_destructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_trivially_destructible "is_trivially_destructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_trivially_destructible_v "is_trivially_destructible_v<ClassT, ArgsT...>"
/// \ref fennec::is_nothrow_destructible "is_nothrow_destructible<ClassT, ArgsT...>::value"<br>
/// \ref fennec::is_nothrow_destructible_v "is_nothrow_destructible_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_destructible
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::has_virtual_destructor "has_virtual_destructor<ClassT, ArgsT...>::value"<br>
/// \ref fennec::has_virtual_destructor_v "has_virtual_destructor_v<ClassT, ArgsT...>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::has_virtual_destructor
///
/// </table>
///
///
///
/// \section Type Relationships
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_traits_type_relationships">
/// <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_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
///
/// </table>
///
#include <fennec/lang/intrinsics.h>
#include <fennec/lang/type_transforms.h>
#include <fennec/lang/detail/_type_traits.h>
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;
@@ -131,7 +446,7 @@ constexpr inline bool is_constant_evaluated() noexcept {
// fennec::is_void =====================================================================================================
///
/// \brief check if \p T is of type void
/// \brief Check if \p T is of type void
///
/// \details Stores a boolean value in `is_void::value`, representing whether the provided type is of base type void.
/// \tparam T type to check
@@ -139,33 +454,16 @@ template<typename T> struct is_void
: 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
template<typename T> constexpr bool_t is_void_v = is_void<T>::value;
// fennec::is_bool =====================================================================================================
///
/// \brief check if \p T is of type bool
///
/// \details Stores a boolean value in `is_bool::value`, representing whether the provided type is of base type bool.
/// \tparam T type to check
template<typename T> struct is_bool
: detail::_is_bool<remove_cvr_t<T>>{};
///
/// \brief shorthand for ```is_bool<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
// fennec::is_null_pointer =============================================================================================
///
/// \brief check if \p T is of type nullptr_t
/// \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
@@ -173,7 +471,7 @@ template<typename T> struct is_null_pointer
: detail::_is_null_pointer<remove_cvr_t<T>>{};
///
/// \brief shorthand for ```is_null_pointer<T>::value```
/// \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;
@@ -181,10 +479,10 @@ template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::va
// fennec::is_array ====================================================================================================
#if FENNEC_HAS_BUILTIN_IS_ARRAY
#ifdef FENNEC_BUILTIN_IS_ARRAY
///
/// \brief check if \p T is of an array type
/// \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)> {};
@@ -192,7 +490,7 @@ template<typename T> struct is_array
#else
///
/// \brief check if \p T is of an array type
/// \brief Check if \p T is of an array type
/// \tparam T type to check
template<typename T> struct is_array
: false_type {};
@@ -208,29 +506,97 @@ template<typename T> struct is_array<T[]>
#endif
///
/// \brief shorthand for ```is_array<T>::value```
/// \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_enum ====================================================================================================
///
/// \brief Check if \p T is an enum
/// \tparam T type to check
template<typename T> struct is_enum
: bool_constant<FENNEC_BUILTIN_IS_ENUM(T)> {};
///
/// \brief Check if \p T is a class
/// \tparam T type to check
template<typename T> constexpr size_t is_enum_v = is_enum<T>::value;
// fennec::is_union ====================================================================================================
///
/// \brief Check if \p T is a union
/// \tparam T type to check
template<typename T> struct is_union
: bool_constant<FENNEC_BUILTIN_IS_UNION(T)> {};
///
/// \brief Check if \p T is a class
/// \tparam T type to check
template<typename T> constexpr size_t is_union_v = is_union<T>::value;
// fennec::is_class ====================================================================================================
///
/// \brief check if \p T is a 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
/// \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 ======================================================================================================
// fennec::is_function ====================================================================================================
///
/// \brief check if \p T is of an integral
/// \brief Check if \p T is a class
/// \tparam T type to check
template<typename T> struct is_function
: bool_constant<FENNEC_BUILTIN_IS_FUNCTION(T)> {};
///
/// \brief Check if \p T is a class
/// \tparam T type to check
template<typename T> constexpr size_t is_function_v = is_function<T>::value;
// Integral Types ======================================================================================================
// fennec::is_bool =====================================================================================================
///
/// \brief Check if \p T is of type bool
///
/// \details Stores a boolean value in `is_bool::value`, representing whether the provided type is of base type bool.
/// \tparam T type to check
template<typename T> struct is_bool
: detail::_is_bool<remove_cvr_t<T>>{};
///
/// \brief Shorthand for ```is_bool<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
// fennec::is_integral =================================================================================================
///
/// \brief Check if \p T is of an integral
///
/// \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
@@ -238,13 +604,17 @@ template<typename T> struct is_integral
: 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
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
// fennec::is_signed =================================================================================================
///
/// \brief check if \p T is of a signed integral
/// \brief Check if \p T is of a signed integral
///
/// \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
@@ -252,13 +622,17 @@ template<typename T> struct is_signed
: 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
template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value;
// fennec::is_unsigned =================================================================================================
///
/// \brief check if \p T is of an unsigned integral
/// \brief Check if \p T is of an unsigned integral
///
/// \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
@@ -266,7 +640,7 @@ template<typename T> struct is_unsigned
: 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
template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
@@ -275,15 +649,15 @@ template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
// 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 Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \details Stores a boolean value in `is_floating_point::value`, representing whether the provided type is of a base floating point type.
/// \tparam T type to check
template<typename T> struct is_floating_point
: 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
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};
@@ -291,24 +665,69 @@ template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T>
// Pointer Types =======================================================================================================
///
/// \brief check if \p T is of a floating point type
/// \brief Check if \p T is of a pointer type
///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \details Stores a boolean value in `is_pointer::value`, representing whether the provided type is of a base pointer type.
/// \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```
/// \brief Shorthand for ```is_pointer<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
// Reference 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_reference
: detail::_is_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
///
/// \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_lvalue_reference
: detail::_is_lvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {};
///
/// \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_rvalue_reference
: detail::_is_rvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {};
// Arithmetic Types ====================================================================================================
///
/// \brief check if \p T is an arithmetic type
/// \brief Check if \p T is an arithmetic type
///
/// \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
@@ -316,21 +735,38 @@ template<typename T> struct is_arithmetic
: 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
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;
// Arithmetic Types ====================================================================================================
///
/// \brief Check if \p T is an arithmetic type
///
/// \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
template<typename T> struct is_scalar
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
///
/// \brief Shorthand for ```is_scalar<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
// fennec::is_fundamental ==============================================================================================
///
/// \brief check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
/// \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```
/// \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;
@@ -338,7 +774,7 @@ template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::valu
// fennec::is_same =====================================================================================================
///
/// \brief check if the two types are identical
/// \brief Check if the two types are identical
///
/// \details Checks if `T0` and `T1` are identical and store it in `is_same::value`
/// \tparam T0 first type to check
@@ -349,14 +785,90 @@ template<typename T0, typename T1> struct is_same : false_type {};
template<typename T> struct is_same<T, T> : true_type {};
///
/// \brief shorthand for ```is_same<T0, T1>::value```
/// \tparam T type to check
/// \brief Shorthand for ```is_same<T0, T1>::value```
/// \tparam T0 first type to check
/// \tparam T1 second type to check
template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {};
// fennec::is_base_of =====================================================================================================
///
/// \brief Check if `Derived` has a base type of `Base`
///
/// \details Checks if `Base` is a base type of `Derived` and stores it in `is_base_of::value`
/// \tparam Base base type to check
/// \tparam Derived derived type to check
template<typename Base, typename Derived> struct is_base_of : bool_constant<
is_class_v<Base> and is_class_v<Derived> and decltype(detail::_is_base_of<Base, Derived>(0))::value
> {};
///
/// \brief Shorthand for ```is_base_of<T0, T1>::value```
/// \tparam Base base type to check
/// \tparam Derived derived type to check
template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_base_of<Base, Derived> {};
// fennec::is_complete ==============================================================================================
///
/// \brief Check if type `T` is complete
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_complete : detail::_is_complete<T>::type {};
///
/// \brief Shorthand for `is_complete<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};
// fennec::is_iterable ==============================================================================================
///
/// \brief Check if type `T` is iterable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};
///
/// \brief Shorthand for `is_iterable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};
// fennec::is_indexable ==============================================================================================
///
/// \brief Check if type `T` is indexable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};
///
/// \brief Shorthand for `is_indexable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};
// fennec::is_mappable ==============================================================================================
///
/// \brief Check if type `T` is mappable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};
///
/// \brief Shorthand for `is_mappable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_mappable_v = is_mappable<T>{};
// fennec::is_convertible ==============================================================================================
///
/// \brief check if type `T0` can be converted `T1`
/// \brief Check if type `T0` can be converted `T1`
///
/// \details Checks if `TypeT0`
/// \tparam FromT First type
@@ -365,7 +877,7 @@ template<typename FromT, typename ToT> struct is_convertible
: bool_constant<FENNEC_BUILTIN_IS_CONVERTIBLE(FromT, ToT)> {};
///
/// \brief shorthand for `can_convert<TypeT0, TypeT1>::value`
/// \brief Shorthand for `can_convert<TypeT0, TypeT1>::value`
/// \param FromT First type
/// \param ToT Second type
template<typename FromT, typename ToT> constexpr bool_t is_convertible_v = is_convertible<FromT, ToT>{};
@@ -387,6 +899,18 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v
///
/// \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>{};
///
/// \brief Check if `ClassT` is default constructible
/// \tparam ClassT The class type to test
@@ -395,7 +919,7 @@ template<typename ClassT> struct is_default_constructible
///
/// \brief Shorthand for `is_default_constructible<ClassT>::value`
template<typename ClassT, typename...ArgsT> constexpr bool_t is_default_constructible_v = is_default_constructible<ClassT>{};
template<typename ClassT> constexpr bool_t is_default_constructible_v = is_default_constructible<ClassT>{};
@@ -422,19 +946,19 @@ template<typename ClassT> struct is_move_constructible
template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructible_v = is_move_constructible<ClassT>{};
// fennec::is_destructible ===================================================================================
///
/// \brief Check if `ClassT` is trivially constructible
/// \brief Check if `ClassT` is destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_constructible
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {};
template<typename ClassT> struct is_destructible
: detail::_is_destructible<ClassT>::type {};
///
/// \brief Shorthand for `is_trivially_constructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_trivially_constructible_v = is_trivially_constructible<ClassT>{};
/// \brief Shorthand for `is_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_destructible_v = is_destructible<ClassT>{};
// fennec::is_trivially_destructible ===================================================================================
///
/// \brief Check if `ClassT` is trivially destructible
@@ -447,6 +971,18 @@ template<typename ClassT> struct is_trivially_destructible
template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_trivially_destructible<ClassT>{};
///
/// \brief Check if `ClassT` is nothrow destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_destructible
: detail::_is_nothrow_destructible<ClassT>::type {};
///
/// \brief Shorthand for `is_nothrow_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_nothrow_destructible_v = is_nothrow_destructible<ClassT>{};
// fennec::is_assignable ===============================================================================================
///
@@ -487,7 +1023,6 @@ template<typename ClassT> struct is_move_assignable
/// \brief Shorthand for `is_move_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_move_assignable_v = is_move_assignable<ClassT>{};
//
}

View File

@@ -31,7 +31,9 @@
#ifndef FENNEC_LANG_TYPE_TRANSFORMS_H
#define FENNEC_LANG_TYPE_TRANSFORMS_H
#include <fennec/lang/conditional_types.h>
#include <fennec/lang/type_identity.h>
#include <fennec/lang/detail/_type_traits.h>
#include <fennec/lang/detail/_type_transforms.h>
///
@@ -154,6 +156,20 @@ template<typename T> struct remove_pointer<T*> : type_identity<T> {};
template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;
///
/// \brief removes all pointer levels from \p T
///
/// \details removes all pointers from the provided type such that `T*`, `T**`, etc. becomes `T`
/// \tparam T Resultant Type
template<typename T> struct strip_pointers : conditional_t<
detail::_is_pointer<T>::value,
strip_pointers<remove_pointer_t<T>>,
type_identity<T>
> {};
template<typename T> using strip_pointers_t = strip_pointers<T>::type;
// Reference Conversions ===============================================================================================
@@ -347,6 +363,20 @@ template<typename T> struct remove_cvr : type_identity<remove_cv_t<remove_refere
/// \brief shorthand for `typename remove_cvr<T>::type`
template<typename T> using remove_cvr_t = typename remove_cvr<T>::type;
///
/// \brief removes references and pointers 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
/// \tparam T Reference Type
template<typename T> struct remove_cvrp : type_identity<remove_cv_t<remove_reference_t<strip_pointers_t<T>>>> {};
///
/// \brief shorthand for `typename remove_cvrp_t<T>::type`
template<typename T> using remove_cvrp_t = typename remove_cvrp<T>::type;
}
#endif // FENNEC_LANG_TYPE_TRANSFORMS_H

View File

@@ -203,8 +203,6 @@
#include <fennec/lang/detail/_int.h>
#include <fennec/lang/conditional_types.h>
namespace fennec
{
// Basic Types =========================================================================================================
@@ -215,6 +213,8 @@ namespace fennec
using bool_t = bool; ///< \brief A conditional type
using byte_t = unsigned char; ///< \brief A type capable of holding a single byte
using char_t = char; ///< \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 uchar_t = unsigned char; ///< \brief A type with the size of a char, capable of holding an unsigned 8-bit integer

View File

@@ -123,9 +123,18 @@ constexpr void swap(T& x, T& y) noexcept {
/// \param x first value
/// \param y second value
template<typename T> constexpr void swap(T& x, T& y) noexcept {
#if FENNEC_COMPILER_GCC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
T a = fennec::move(x);
x = fennec::move(y);
y = fennec::move(a);
#if FENNEC_COMPILER_GCC
#pragma GCC diagnostic pop
#endif
}
}

View File

@@ -44,81 +44,81 @@
///
///
///
/// \section section_sign_functions Sign
/// \section fennec_math_common_section_sign_functions Sign Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_common_sign_functions">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::abs(fennec::genType) "genIType abs(genIType x)" <br>
/// \ref fennec::abs(fennec::genType) "genFType abs(genFType x)" <br>
/// \ref fennec::abs(fennec::genType) "genDType abs(genDType x)"
/// \ref fennec::abs "genIType abs(genIType x)" <br>
/// \ref fennec::abs "genFType abs(genFType x)" <br>
/// \ref fennec::abs "genDType abs(genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::abs(fennec::genType)
/// \copydetails fennec::abs
///
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::sign(fennec::genType) "genIType sign(genIType x)" <br>
/// \ref fennec::sign(fennec::genType) "genFType sign(genFType x)" <br>
/// \ref fennec::sign(fennec::genType) "genDType sign(genDType x)"
/// \ref fennec::sign "genIType sign(genIType x)" <br>
/// \ref fennec::sign "genFType sign(genFType x)" <br>
/// \ref fennec::sign "genDType sign(genDType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::sign(fennec::genType)
/// \copydetails fennec::sign
///
/// </table>
///
///
/// \section section_rounding_functions Rounding
/// \section fennec_math_common_section_rounding_functions Rounding Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_common_rounding_functions">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::floor(fennec::genType) "genFType floor(genFType x)" <br>
/// \ref fennec::floor(fennec::genType) "genDType floor(genDType x)"
/// \ref fennec::floor "genFType floor(genFType x)" <br>
/// \ref fennec::floor "genDType floor(genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::floor(fennec::genType)
/// \copydetails fennec::floor
///
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::ceil(fennec::genType) "genFType ceil(genFType x)" <br>
/// \ref fennec::ceil(fennec::genType) "genDType ceil(genDType x)"
/// \ref fennec::ceil "genFType ceil(genFType x)" <br>
/// \ref fennec::ceil "genDType ceil(genDType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::ceil(fennec::genType)
/// \copydetails fennec::ceil
///
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::round(fennec::genType) "genFType round(genFType x)" <br>
/// \ref fennec::round(fennec::genType) "genDType round(genDType x)"
/// \ref fennec::round "genFType round(genFType x)" <br>
/// \ref fennec::round "genDType round(genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::round(fennec::genType)
/// \copydetails fennec::round
///
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::roundEven(fennec::genType) "genFType roundEven(genFType x)" <br>
/// \ref fennec::roundEven(fennec::genType) "genDType roundEven(genDType x)"
/// \ref fennec::roundEven "genFType roundEven(genFType x)" <br>
/// \ref fennec::roundEven "genDType roundEven(genDType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::roundEven(fennec::genType)
/// \copydetails fennec::roundEven
///
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::trunc(fennec::genType) "genFType trunc(genFType x)" <br>
/// \ref fennec::trunc(fennec::genType) "genDType trunc(genDType x)"
/// \ref fennec::trunc "genFType trunc(genFType x)" <br>
/// \ref fennec::trunc "genDType trunc(genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::trunc(fennec::genType)
/// \copydetails fennec::trunc
///
/// </table>
///
///
/// \section section_decimal_functions Decimal-Point
/// \section fennec_math_common_section_decimal_functions Decimal-Point Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_common_decimal_functions">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::fract(fennec::genType) "genFType fract(genFType x)" <br>
/// \ref fennec::fract(fennec::genType) "genDType fract(genDType x)"
/// \ref fennec::fract "genFType fract(genFType x)" <br>
/// \ref fennec::fract "genDType fract(genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::fract(fennec::genType)
/// \copydetails fennec::fract
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::mod "genFType mod(genFType x, float y)" <br>
@@ -129,59 +129,59 @@
/// \copydetails fennec::mod
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::modf(fennec::genType, fennec::genType&) "genFType modf(genFType x, out genFType i)" <br>
/// \ref fennec::modf(fennec::genType, fennec::genType&) "genDType modf(genDType x, out genDType i)"
/// \ref fennec::modf "genFType modf(genFType x, out genFType i)" <br>
/// \ref fennec::modf "genDType modf(genDType x, out genDType i)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::modf(fennec::genType, fennec::genType&)
/// \copydetails fennec::modf
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::isnan(fennec::genType) "genBType isnan(genFType x)" <br>
/// \ref fennec::isnan(fennec::genType) "genBType isnan(genDType x)"
/// \ref fennec::isnan "genBType isnan(genFType x)" <br>
/// \ref fennec::isnan "genBType isnan(genDType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::isnan(fennec::genType)
/// \copydetails fennec::isnan
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::isinf(fennec::genType) "genBType isinf(genFType x)" <br>
/// \ref fennec::isinf(fennec::genType) "genBType isinf(genDType x)"
/// \ref fennec::isinf "genBType isinf(genFType x)" <br>
/// \ref fennec::isinf "genBType isinf(genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::isinf(fennec::genType)
/// \copydetails fennec::isinf
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::frexp(fennec::genType, fennec::genIType&) "genFType frexp(genFType x, out genIType exp)" <br>
/// \ref fennec::frexp(fennec::genType, fennec::genIType&) "genDType frexp(genDType x, out genIType exp)"
/// \ref fennec::frexp "genFType frexp(genFType x, out genIType exp)" <br>
/// \ref fennec::frexp "genDType frexp(genDType x, out genIType exp)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::frexp(fennec::genType, fennec::genIType&)
/// \copydetails fennec::frexp
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::ldexp(fennec::genType, fennec::genIType) "genFType ldexp(genFType x, genIType exp)" <br>
/// \ref fennec::ldexp(fennec::genType, fennec::genIType) "genDType ldexp(genDType x, genIType exp)"
/// \ref fennec::ldexp "genFType ldexp(genFType x, genIType exp)" <br>
/// \ref fennec::ldexp "genDType ldexp(genDType x, genIType exp)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::ldexp(fennec::genType, fennec::genIType)
/// \copydetails fennec::ldexp
///
/// </table>
///
///
/// \section section_bit_conversion_functions Bit Conversion
/// \section fennec_math_common_section_bit_functions Bit Conversion
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_common_bit_conversions">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::floatBitsToInt(fennec::genType) "genIType floatBitsToInt(genType value)" <br>
/// \ref fennec::floatBitsToUint(fennec::genType) "genUType floatBitsToUint(genType value)"
/// \ref fennec::floatBitsToInt "genIType floatBitsToInt(genType value)" <br>
/// \ref fennec::floatBitsToUint "genUType floatBitsToUint(genType value)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::floatBitsToUint(fennec::genType)
/// \copydetails fennec::floatBitsToUint
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::intBitsToFloat(fennec::genIType) "genFType intBitsToFloat(genIType value)" <br>
/// \ref fennec::uintBitsToFloat(fennec::genUType) "genFType uintBitsToFloat(genUType value)"
/// \ref fennec::intBitsToFloat "genFType intBitsToFloat(genIType value)" <br>
/// \ref fennec::uintBitsToFloat "genFType uintBitsToFloat(genUType value)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::uintBitsToFloat(fennec::genType)
/// \copydetails fennec::uintBitsToFloat
///
/// </table>
///
///
/// \section section_comparison_functions Comparison
/// \section fennec_math_common_section_comparison_functions Comparison Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_common_comparison_functions">
/// <tr><th style="vertical-align: top">Syntax
@@ -226,7 +226,7 @@
/// </table>
///
///
/// \section section_curve_functions Curves
/// \section fennec_math_common_section_curve_functions Curve Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_curve_functions">
/// <tr><th style="vertical-align: top">Syntax
@@ -256,11 +256,11 @@
/// \copydetails fennec::mix
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::mix(fennec::genBType, fennec::genBType, fennec::genBType) "mix(genBType x, genBType y, genBType a)" <br>
/// \ref fennec::mix(fennec::genType, fennec::genType, fennec::genBType) "mix(genIType x, genIType y, genBType a)" <br>
/// \ref fennec::mix(fennec::genType, fennec::genType, fennec::genBType) "mix(genUType x, genUType y, genBType a)" <br>
/// \ref fennec::mix(fennec::genType, fennec::genType, fennec::genBType) "mix(genFType x, genFType y, genBType a)" <br>
/// \ref fennec::mix(fennec::genType, fennec::genType, fennec::genBType) "mix(genDType x, genDType y, genBType a)"
/// \ref fennec::mix "mix(genBType x, genBType y, genBType a)" <br>
/// \ref fennec::mix "mix(genIType x, genIType y, genBType a)" <br>
/// \ref fennec::mix "mix(genUType x, genUType y, genBType a)" <br>
/// \ref fennec::mix "mix(genFType x, genFType y, genBType a)" <br>
/// \ref fennec::mix "mix(genDType x, genDType y, genBType a)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::mix
///
@@ -308,14 +308,6 @@ constexpr genType sign(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> sign(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sign(x[i]) ...);
}
// Absolute Value ======================================================================================================
///
@@ -331,14 +323,6 @@ constexpr genType abs(genType x) {
return x * fennec::sign(x);
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> abs(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::abs(x[i]) ...);
}
/// @}
@@ -366,14 +350,6 @@ constexpr genType floor(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> floor(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::floor(x[i]) ...);
}
// Ceil ================================================================================================================
@@ -391,14 +367,6 @@ constexpr genType ceil(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> ceil(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::ceil(x[i]) ...);
}
// Round ===============================================================================================================
@@ -416,14 +384,6 @@ template<typename genType> constexpr genType round(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> round(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::round(x[i]) ...);
}
// Trunc ===============================================================================================================
@@ -441,14 +401,6 @@ constexpr genType trunc(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> trunc(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::trunc(x[i]) ...);
}
// Round Even ==========================================================================================================
@@ -486,13 +438,6 @@ constexpr genType roundEven(genType x) {
//return i + static_cast<genType>(up);
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> roundEven(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::roundEven(x[i]) ...);
}
/// @}
@@ -519,14 +464,6 @@ constexpr genType fract(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> fract(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::fract(x[i]) ...);
}
// Mod =================================================================================================================
///
@@ -544,19 +481,6 @@ constexpr genType mod(genType x, genType y) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> mod(const vector<genType, i...>& x, genType y) {
return x - y * fennec::floor(x / y);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> mod(const vector<genType, i...>& x, const vector<genType, i...>& y) {
return x - y * fennec::floor(x / y);
}
// ModF ================================================================================================================
///
@@ -574,14 +498,6 @@ constexpr genType modf(genType x, genType& i) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> modf(const vector<genType, i...>& x, vector<genType, i...>& I) {
I = fennec::floor(x); return fennec::fract(x);
}
// Is NaN ==============================================================================================================
///
@@ -603,14 +519,6 @@ constexpr genBType isnan(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
constexpr vector<genBType, i...> isnan(const vector<genType, i...>& x) {
return vector<genBType, i...>(fennec::isnan(x[i]) ...);
}
// Is Inf ==============================================================================================================
///
@@ -627,19 +535,11 @@ constexpr genBType isinf(genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
constexpr vector<genBType, i...> isinf(const vector<genType, i...>& x) {
return vector<genBType, i...>(fennec::isinf(x[i]) ...);
}
// Bit Conversion ======================================================================================================
///
/// \copydetails fennec::floatBitsToUint(fennec::genFType)
/// \copydetails fennec::floatBitsToUint
template<typename genType, typename genIType = int_t> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr genIType floatBitsToInt(genType x) {
return fennec::bit_cast<genIType>(x);
@@ -669,7 +569,7 @@ constexpr genUType floatBitsToUint(genType x) {
///
/// \copydetails fennec::uintBitsToFloat(fennec::genUType)
/// \copydetails fennec::uintBitsToFloat
template<typename genType = float_t, typename genIType = int_t> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr genType intBitsToFloat(genIType x) {
return fennec::bit_cast<genType>(x);
@@ -696,29 +596,6 @@ constexpr genType uintBitsToFloat(genUType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType = float_t, typename genIType = int_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr vector<genIType, i...> floatBitsToInt(const vector<genType, i...>& x) {
return vector<genIType, i...>(fennec::bit_cast<genIType>(x[i])...);
}
template<typename genType = float_t, typename genUType = uint_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr vector<genUType, i...> floatBitsToUint(const vector<genType, i...>& x) {
return vector<genUType, i...>(fennec::bit_cast<genUType>(x[i])...);
}
template<typename genType = float_t, typename genIType = int_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr vector<genType, i...> intBitsToFloat(const vector<genIType, i...>& x) {
return vector<genType, i...>(fennec::bit_cast<genType>(x[i]) ...);
}
template<typename genType = float_t, typename genUType = uint_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr vector<genType, i...> uintBitsToFloat(const vector<genUType, i...>& x) {
return vector<genType, i...>(fennec::bit_cast<genType>(x[i]) ...);
}
// fma =================================================================================================================
@@ -738,14 +615,6 @@ constexpr genType fma(genType a, genType b, genType c) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> fma(const vector<genType, i...>& a, const vector<genType, i...>& b, const vector<genType, i...>& c) {
return vector<genType, i...>(fennec::fma(a[i], b[i], c[i]) ...);
}
// frexp ===============================================================================================================
@@ -769,14 +638,6 @@ constexpr genType frexp(genType x, genIType& exp) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, typename genIType = int_t, size_t...i> requires(is_integral_v<genIType>)
constexpr vector<genType, i...> frexp(const vector<genType, i...>& x, vector<genIType, i...>& exp) {
return vector<genType, i...>(fennec::frexp(x[i], exp[i])...);
}
// ldexp ===============================================================================================================
@@ -802,14 +663,6 @@ constexpr genType ldexp(genType x, genIType exp) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, typename genIType = int_t, size_t...i> requires(is_integral_v<genIType>)
constexpr vector<genType, i...> ldexp(const vector<genType, i...>& x, const vector<genIType, i...>& exp) {
return vector<genType, i...>(fennec::ldexp(x[i], exp[i])...);
}
/// @}
@@ -837,24 +690,6 @@ constexpr genType min(genType x, genType y) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> min(genType x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::min(x, y[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> min(const vector<genType, i...>& x, genType y) {
return vector<genType, i...>(fennec::min(x[i], y) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> min(const vector<genType, i...>& x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::min(x[i], y[i]) ...);
}
// Max =================================================================================================================
///
@@ -872,24 +707,6 @@ constexpr genType max(genType x, genType y) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> max(genType x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::max(x, y[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> max(const vector<genType, i...>& x, genType y) {
return vector<genType, i...>(fennec::max(x[i], y) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> max(const vector<genType, i...>& x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::max(x[i], y[i]) ...);
}
// Clamp ===============================================================================================================
///
@@ -908,19 +725,6 @@ constexpr genType clamp(genType x, genType minVal, genType maxVal) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> clamp(const vector<genType, i...>& x, genType minVal, genType maxVal) {
return vector<genType, i...>(fennec::min(fennec::max(x[i], minVal), maxVal)...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> clamp(const vector<genType, i...>& x, const vector<genType, i...>& minVal, const vector<genType, i...>& maxVal) {
return vector<genType, i...>(fennec::min(fennec::max(x[i], minVal[i]), maxVal[i])...);
}
/// @}
@@ -948,19 +752,6 @@ constexpr genType step(genType edge, genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> step(genType edge, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::step(edge, x[i]) ...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> step(const vector<genType, i...>& edge, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::step(edge[i], x[i]) ...);
}
// Smoothstep ==========================================================================================================
///
@@ -989,19 +780,6 @@ constexpr genType smoothstep(genType edge0, genType edge1, genType x) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> smoothstep(genType edge0, genType edge1, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::smoothstep(edge0, edge1, x[i]) ...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> smoothstep(const vector<genType, i...>& edge0, const vector<genType, i...>& edge1, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::smoothstep(edge0[i], edge1[i], x[i]) ...);
}
// Mix =================================================================================================================
///
@@ -1022,18 +800,6 @@ constexpr genType mix(genType x, genType y, genType a) {
return x * (genType(1.0) - a) + y * a;
}
// Vector Specializations ----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, genType a) {
return x * (genType(1.0) - a) + y * a;
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, const vector<genType, i...>& a) {
return x * (genType(1.0) - a) + y * a;
}
// Mix (Bool) ==========================================================================================================
@@ -1058,7 +824,177 @@ constexpr genType mix(genType x, genType y, genBType a) {
}
// Vector Specializations ----------------------------------------------------------------------------------------------
// Internal ============================================================================================================
template<typename genType, size_t...i>
constexpr vector<genType, i...> sign(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sign(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> abs(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::abs(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> floor(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::floor(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> ceil(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::ceil(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> round(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::round(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> trunc(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::trunc(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> roundEven(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::roundEven(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> fract(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::fract(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> mod(const vector<genType, i...>& x, genType y) {
return x - y * fennec::floor(x / y);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> mod(const vector<genType, i...>& x, const vector<genType, i...>& y) {
return x - y * fennec::floor(x / y);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> modf(const vector<genType, i...>& x, vector<genType, i...>& I) {
I = fennec::floor(x); return fennec::fract(x);
}
template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
constexpr vector<genBType, i...> isnan(const vector<genType, i...>& x) {
return vector<genBType, i...>(fennec::isnan(x[i]) ...);
}
template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
constexpr vector<genBType, i...> isinf(const vector<genType, i...>& x) {
return vector<genBType, i...>(fennec::isinf(x[i]) ...);
}
template<typename genType = float_t, typename genIType = int_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr vector<genIType, i...> floatBitsToInt(const vector<genType, i...>& x) {
return vector<genIType, i...>(fennec::bit_cast<genIType>(x[i])...);
}
template<typename genType = float_t, typename genUType = uint_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr vector<genUType, i...> floatBitsToUint(const vector<genType, i...>& x) {
return vector<genUType, i...>(fennec::bit_cast<genUType>(x[i])...);
}
template<typename genType = float_t, typename genIType = int_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr vector<genType, i...> intBitsToFloat(const vector<genIType, i...>& x) {
return vector<genType, i...>(fennec::bit_cast<genType>(x[i]) ...);
}
template<typename genType = float_t, typename genUType = uint_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr vector<genType, i...> uintBitsToFloat(const vector<genUType, i...>& x) {
return vector<genType, i...>(fennec::bit_cast<genType>(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> fma(const vector<genType, i...>& a, const vector<genType, i...>& b, const vector<genType, i...>& c) {
return vector<genType, i...>(fennec::fma(a[i], b[i], c[i]) ...);
}
template<typename genType, typename genIType = int_t, size_t...i> requires(is_integral_v<genIType>)
constexpr vector<genType, i...> frexp(const vector<genType, i...>& x, vector<genIType, i...>& exp) {
return vector<genType, i...>(fennec::frexp(x[i], exp[i])...);
}
template<typename genType, typename genIType = int_t, size_t...i> requires(is_integral_v<genIType>)
constexpr vector<genType, i...> ldexp(const vector<genType, i...>& x, const vector<genIType, i...>& exp) {
return vector<genType, i...>(fennec::ldexp(x[i], exp[i])...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> min(genType x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::min(x, y[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> min(const vector<genType, i...>& x, genType y) {
return vector<genType, i...>(fennec::min(x[i], y) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> min(const vector<genType, i...>& x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::min(x[i], y[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> max(genType x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::max(x, y[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> max(const vector<genType, i...>& x, genType y) {
return vector<genType, i...>(fennec::max(x[i], y) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> max(const vector<genType, i...>& x, const vector<genType, i...>& y) {
return vector<genType, i...>(fennec::max(x[i], y[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> clamp(const vector<genType, i...>& x, genType minVal, genType maxVal) {
return vector<genType, i...>(fennec::min(fennec::max(x[i], minVal), maxVal)...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> clamp(const vector<genType, i...>& x, const vector<genType, i...>& minVal, const vector<genType, i...>& maxVal) {
return vector<genType, i...>(fennec::min(fennec::max(x[i], minVal[i]), maxVal[i])...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> step(genType edge, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::step(edge, x[i]) ...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> step(const vector<genType, i...>& edge, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::step(edge[i], x[i]) ...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> smoothstep(genType edge0, genType edge1, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::smoothstep(edge0, edge1, x[i]) ...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> smoothstep(const vector<genType, i...>& edge0, const vector<genType, i...>& edge1, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::smoothstep(edge0[i], edge1[i], x[i]) ...);
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, genType a) {
return x * (genType(1.0) - a) + y * a;
}
template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, const vector<genType, i...>& a) {
return x * (genType(1.0) - a) + y * a;
}
template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType> and is_floating_point_v<genType>)
constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, genBType a) {

View File

@@ -24,15 +24,15 @@
namespace fennec
{
template<typename ScalarT, size_t...IndicesV> struct vector; // Forward def for vectors
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV> struct matrix; // Forward def for matrices
template<typename ScalarT, size_t...IndicesV> requires(is_scalar_v<ScalarT>) struct vector; // Forward def for vectors
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV> requires(is_scalar_v<ScalarT>) struct matrix; // Forward def for matrices
// Simplified interface for creating sized vectors or matrices
template<typename ScalarT, size_t SizeV> using vec
= decltype(detail::_gen_vector<vector, ScalarT>(make_index_sequence<SizeV>{})); // Gets the type returned by this function
= decltype(detail::_gen_vector<vector, ScalarT>(make_index_metasequence<SizeV>{})); // Gets the type returned by this function
template<typename ScalarT, size_t ColsV, size_t RowsV> using mat
= decltype(detail::_gen_matrix<matrix, ScalarT, RowsV>(make_index_sequence<ColsV>{})); // Gets the type returned by this function
= decltype(detail::_gen_matrix<matrix, ScalarT, RowsV>(make_index_metasequence<ColsV>{})); // Gets the type returned by this function
}

View File

@@ -19,7 +19,7 @@
#ifndef FENNEC_MATH_DETAIL_TYPES_H
#define FENNEC_MATH_DETAIL_TYPES_H
#include <fennec/lang/const_sequences.h>
#include <fennec/lang/metasequences.h>
namespace fennec
{
@@ -28,11 +28,11 @@ namespace detail
{
template<template<typename, size_t...> typename VectorT, typename ScalarT, size_t...IndicesV>
VectorT<ScalarT, IndicesV...> _gen_vector(const_index_sequence<IndicesV...>); // Helper for substituting a size N with sequence of integers
VectorT<ScalarT, IndicesV...> _gen_vector(index_metasequence<IndicesV...>); // Helper for substituting a size N with sequence of integers
template<template<typename, size_t...> typename MatrixT, typename ScalarT, size_t RowsV, size_t...IndicesV>
MatrixT<ScalarT, RowsV, IndicesV...> _gen_matrix(const_index_sequence<IndicesV...>); // Helper for substituting a size Columns with sequence of integers
MatrixT<ScalarT, RowsV, IndicesV...> _gen_matrix(index_metasequence<IndicesV...>); // Helper for substituting a size Columns with sequence of integers
}

View File

@@ -42,45 +42,45 @@
/// \code #include <fennec/math/exponential.h> \endcode
///
///
/// \section Exponential Functions
/// \section fennec_math_exponential_section_functions Exponential Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_exponential_functions">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::pow(fennec::genType, fennec::genType) "genFType pow(genFType x, genFType y)"
/// \ref fennec::pow "genFType pow(genFType x, genFType y)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::pow(fennec::genType, fennec::genType)
/// \copydetails fennec::pow
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::exp(fennec::genType)"genFType exp(genFType x)"
/// \ref fennec::exp"genFType exp(genFType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::exp(fennec::genType)
/// \copydetails fennec::exp
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::exp2(fennec::genType) "genFType exp2(genFType x)"
/// \ref fennec::exp2 "genFType exp2(genFType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::exp2(fennec::genType)
/// \copydetails fennec::exp2
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::log(fennec::genType) "genFType log(genFType x)"
/// \ref fennec::log "genFType log(genFType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::log(fennec::genType)
/// \copydetails fennec::log
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::log2(fennec::genType) "genFType log2(genFType x)"
/// \ref fennec::log2 "genFType log2(genFType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::log2(fennec::genType)
/// \copydetails fennec::log2
///
/// <tr><td width="50%" style="vertical-align: top" class="odd_c"> <br>
/// \ref fennec::sqrt(fennec::genType) "genFType sqrt(genFType x)"
/// \ref fennec::sqrt "genFType sqrt(genFType x)"
/// <td width="50%" style="vertical-align: top" class="odd_c">
/// \copydetails fennec::sqrt(fennec::genType)
/// \copydetails fennec::sqrt
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::inversesqrt(fennec::genType) "genFType inversesqrt(genFType x)"
/// \ref fennec::inversesqrt "genFType inversesqrt(genFType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::inversesqrt(fennec::genType)
/// \copydetails fennec::inversesqrt
///
/// </table>
///
@@ -110,14 +110,6 @@ constexpr genType pow(genType x, genType y) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
template<typename genType, size_t...i>
constexpr vector<genType, i...> pow(const vector<genType, i...> & x, const vector<genType, i...> & y) {
return vector<genType, i...>(fennec::pow(x[i], y[i]) ...);
}
// exp =================================================================================================================
///
@@ -132,13 +124,6 @@ constexpr genType exp(genType x) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> constexpr vector<genType, i...> exp(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::exp(x[i]) ...);
}
// exp2 ================================================================================================================
///
@@ -152,13 +137,6 @@ template<typename genType> constexpr genType exp2(genType x) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> constexpr vector<genType, i...> exp2(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::exp2(x[i]) ...);
}
// log =================================================================================================================
///
@@ -173,13 +151,6 @@ template<typename genType> constexpr genType log(genType x) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> constexpr genType log(const vector<genType, i...>& x) {
return vector<genType, i...>(log(x[i]) ...);
}
// log2 ================================================================================================================
///
@@ -195,13 +166,6 @@ template<typename genType> constexpr genType log2(genType x) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> constexpr genType log2(const vector<genType, i...>& x) {
return vector<genType, i...>(log2(x[i]) ...);
}
// sqrt ================================================================================================================
///
@@ -216,13 +180,6 @@ template<typename genType> constexpr genType sqrt(genType x) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
template<typename genType, size_t...i> constexpr genType sqrt(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sqrt(x[i]) ...);
}
// inversesqrt =========================================================================================================
///
@@ -237,7 +194,32 @@ template<typename genType> constexpr genType inversesqrt(genType x) {
}
// Vector Specialization -----------------------------------------------------------------------------------------------
// Internal ============================================================================================================
template<typename genType, size_t...i>
constexpr vector<genType, i...> pow(const vector<genType, i...> & x, const vector<genType, i...> & y) {
return vector<genType, i...>(fennec::pow(x[i], y[i]) ...);
}
template<typename genType, size_t...i> constexpr vector<genType, i...> exp(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::exp(x[i]) ...);
}
template<typename genType, size_t...i> constexpr vector<genType, i...> exp2(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::exp2(x[i]) ...);
}
template<typename genType, size_t...i> constexpr genType log(const vector<genType, i...>& x) {
return vector<genType, i...>(log(x[i]) ...);
}
template<typename genType, size_t...i> constexpr genType log2(const vector<genType, i...>& x) {
return vector<genType, i...>(log2(x[i]) ...);
}
template<typename genType, size_t...i> constexpr genType sqrt(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sqrt(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> inversesqrt(const vector<genType, i...>& x) {

View File

@@ -21,7 +21,9 @@
#include <fennec/lang/limits.h>
#include <fennec/math/common.h>
#include <fennec/math/trigonometric.h>
#include <fennec/math/ext/quaternion.h>
namespace fennec

View File

@@ -19,6 +19,7 @@
#ifndef FENNEC_MATH_EXT_QUATERNION_H
#define FENNEC_MATH_EXT_QUATERNION_H
#include <fennec/math/geometric.h>
#include <fennec/math/vector_base.h>
namespace fennec
@@ -31,15 +32,13 @@ template<typename genType> using qua = quaternion<genType>;
using quat = qua<float>;
using dquat = qua<double>;
///
/// \brief Dot Function
/// \param x the first quaternion
/// \param y the second quaternion
/// \returns The sum of component products.
#ifndef FENNEC_DOXYGEN
template<typename genType>
constexpr genType dot(const qua<genType>& x, const qua<genType>& y) {
return x.w*y.w + x.x*y.x + x.y*y.y + x.z*y.z;
}
#endif
///
/// \brief Square Norm Function
@@ -283,7 +282,6 @@ public:
// Quaternion Vector Arithmetic Operators ==============================================================================
/// \brief
constexpr friend vec3_t operator*(const quat_t& q, const vec3_t& v) {
const vec3_t u = q.xyz;
const vec3_t uv = fennec::cross(u, v);
@@ -306,8 +304,8 @@ public:
// Quaternion Quaternion Arithmetic Operators ==========================================================================
constexpr friend quaternion operator+(const quaternion& lhs, const quaternion& rhs) {
return quaternion(
constexpr friend quat_t operator+(const quat_t& lhs, const quat_t& rhs) {
return quat_t(
lhs.w + rhs.w,
lhs.x + rhs.x,
lhs.y + rhs.y,
@@ -315,8 +313,8 @@ public:
);
}
constexpr friend quaternion operator-(const quaternion& lhs, const quaternion& rhs) {
return quaternion(
constexpr friend quat_t operator-(const quat_t& lhs, const quat_t& rhs) {
return quat_t(
lhs.w - rhs.w,
lhs.x - rhs.x,
lhs.y - rhs.y,
@@ -324,8 +322,8 @@ public:
);
}
constexpr friend quaternion operator*(const quaternion& lhs, const quaternion& rhs) {
return quaternion(
constexpr friend quat_t operator*(const quat_t& lhs, const quat_t& rhs) {
return quat_t(
lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z * rhs.z,
lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z * rhs.y,
lhs.w*rhs.y - lhs.x*rhs.z + lhs.y*rhs.w + lhs.z * rhs.x,
@@ -336,7 +334,7 @@ public:
// Quaternion Quaternion Arithmetic Assignment Operators ===============================================================
constexpr friend quaternion& operator+=(quaternion& lhs, const quaternion& rhs) {
constexpr friend quat_t& operator+=(quat_t& lhs, const quat_t& rhs) {
lhs.w += rhs.w;
lhs.x += rhs.x;
lhs.y += rhs.y;
@@ -344,7 +342,7 @@ public:
return lhs;
}
constexpr friend quaternion& operator-=(quaternion& lhs, const quaternion& rhs) {
constexpr friend quat_t& operator-=(quat_t& lhs, const quat_t& rhs) {
lhs.w -= rhs.w;
lhs.x -= rhs.x;
lhs.y -= rhs.y;
@@ -352,7 +350,7 @@ public:
return lhs;
}
constexpr friend quaternion& operator*=(quaternion& lhs, const quaternion& rhs) {
constexpr friend quat_t& operator*=(quat_t& lhs, const quat_t& rhs) {
return lhs = lhs * rhs;
}

View 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 rect.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_MATH_EXT_RECT_H
#define FENNEC_MATH_EXT_RECT_H
#include <fennec/math/vector.h>
namespace fennec
{
template<typename ScalarT>
struct rectangle {
tvec2<ScalarT> position, size;
};
using rect = rectangle<float_t>;
using irect = rectangle<int32_t>;
using urect = rectangle<uint32_t>;
using drect = rectangle<double_t>;
}
#endif // FENNEC_MATH_EXT_RECT_H

View File

@@ -32,7 +32,7 @@ namespace fennec
/// \param x a vector containing the position
/// \returns An identity matrix with the last column set to x
template<typename genType>
constexpr mat<genType, 3, 3> translation(const vec<genType, 2>& x) {
constexpr mat<genType, 3, 3> translation(const vector<genType, 0, 1>& x) {
return mat<genType, 3, 3>(
1, 0, 0,
0, 1, 0,
@@ -45,7 +45,7 @@ constexpr mat<genType, 3, 3> translation(const vec<genType, 2>& x) {
/// \param x a vector containing the position
/// \returns An identity matrix with the last column set to x
template<typename genType>
constexpr mat<genType, 4, 4> translation(const vec<genType, 3>& x) {
constexpr mat<genType, 4, 4> translation(const vector<genType, 0, 1, 2>& x) {
return mat<genType, 4, 4>(
1, 0, 0, 0,
0, 1, 0, 0,
@@ -59,7 +59,7 @@ constexpr mat<genType, 4, 4> translation(const vec<genType, 3>& x) {
/// \param x a vector containing the scale for each axis
/// \returns A diagonal matrix with the terms of x
template<typename genType>
constexpr mat<genType, 3, 3> scaling(const vec<genType, 2>& x) {
constexpr mat<genType, 3, 3> scaling(const vector<genType, 0, 1>& x) {
return mat<genType, 3, 3>(
x.x, 0, 0,
0, x.y, 0,
@@ -72,7 +72,7 @@ constexpr mat<genType, 3, 3> scaling(const vec<genType, 2>& x) {
/// \param x a vector containing the scale for each axis
/// \returns A diagonal matrix with the terms of x
template<typename genType>
constexpr mat<genType, 4, 4> scaling(const vec<genType, 3>& x) {
constexpr mat<genType, 4, 4> scaling(const vector<genType, 0, 1, 2>& x) {
return mat<genType, 4, 4>(
x.x, 0, 0, 0,
0, x.y, 0, 0,
@@ -81,6 +81,15 @@ constexpr mat<genType, 4, 4> scaling(const vec<genType, 3>& x) {
);
}
template<typename genType>
constexpr mat<genType, 3, 3> shear(const vector<genType, 0, 1>& x) {
return mat<genType, 3, 3>(
1, x.x, 0,
x.y, 1, 0,
0, 0, 1
);
}
///
/// \brief Create a 2d rotation matrix
/// \param a the angle of the rotation in radians
@@ -106,7 +115,7 @@ constexpr mat<genType, 3, 3> rotation(const genType a) {
/// \param a The rotation about the axis in radians
/// \returns A rotation matrix about A
template<typename genType>
constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
constexpr mat<genType, 4, 4> rotation(const vector<genType, 0, 1, 2>& A, genType a) {
// https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
// Calculate sin and cos terms
@@ -114,8 +123,8 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
const genType s = fennec::sin(a);
// Calculate axis term
const vec<genType, 3> u = (fennec::one<genType>() - c) * A;
const vec<genType, 3> v = s * A;
const vector<genType, 0, 1, 2> u = (fennec::one<genType>() - c) * A;
const vector<genType, 0, 1, 2> v = s * A;
// Calculate the Matrix
return mat<genType, 4, 4>(
@@ -126,20 +135,20 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
);
}
template<typename genType>
constexpr qua<genType> rotation(const vec<genType, 3>& axis, genType angle) {
vec<genType, 3> a = fennec::normalize(axis);
const genType s = fennec::sin(angle);
return qua<genType>(fennec::cos(angle * genType(0.5)), s * a);
}
// template<typename genType>
// constexpr qua<genType> rotation(const vector<genType, 0, 1, 2>& axis, genType angle) {
// vector<genType, 0, 1, 2> a = fennec::normalize(axis);
// const genType s = fennec::sin(angle);
//
// return qua<genType>(fennec::cos(angle * genType(0.5)), s * a);
// }
/// \brief enum to denote the unit-axis of rotation
enum rot_
enum rotation_
{
rot_x = 0
, rot_y
, rot_z
rotation_x = 0
, rotation_y
, rotation_z
};
///
@@ -147,7 +156,7 @@ enum rot_
/// \tparam axis the unit axis to rotate around
/// \param a the angle, in radians
/// \returns a matrix that rotates vectors around a unit axis
template<typename genType, rot_ axis>
template<typename genType, rotation_ axis>
constexpr mat<genType, 4, 4> rotation(genType a) {
// https://en.wikipedia.org/wiki/Rotation_matrix#Basic_3D_rotations
@@ -156,7 +165,7 @@ constexpr mat<genType, 4, 4> rotation(genType a) {
const genType s = fennec::sin(a);
// Calculate the matrix
if constexpr(axis == rot_x) {
if constexpr(axis == rotation_x) {
return mat<genType, 4, 4>(
1, 0, 0, 0,
0, c, -s, 0,
@@ -164,7 +173,7 @@ constexpr mat<genType, 4, 4> rotation(genType a) {
0, 0, 0, 1
);
}
else if constexpr(axis == rot_y) {
else if constexpr(axis == rotation_y) {
return mat<genType, 4, 4>(
c, 0, s, 0,
0, 0, 0, 0,
@@ -172,7 +181,7 @@ constexpr mat<genType, 4, 4> rotation(genType a) {
0, 0, 0, 1
);
}
else if constexpr(axis == rot_z) {
else if constexpr(axis == rotation_z) {
return mat<genType, 4, 4>(
c, -s, 0, 0,
s, c, 0, 0,
@@ -202,7 +211,7 @@ enum order_
/// \param E the euler angles, taken as tait-bryan (pitch, yaw, roll)
/// \returns a matrix that rotates vectors
template<typename genType, order_ order = order_zxy>
constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& E) {
constexpr mat<genType, 4, 4> rotation(const vector<genType, 0, 1, 2>& E) {
// expanded using a CAS
// Calculate sin and cos terms
@@ -221,40 +230,35 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& E) {
sa*sg - ca*cg*sb, ca*sb*sg + cg*sa, ca*cb, 0,
0, 0, 0, 1
);
}
else if constexpr(order == order_xzy) {
} else if constexpr(order == order_xzy) {
return mat<genType, 4, 4>(
cb*cg, -sg, cg*sb, 0,
ca*cb*sg + sa*sb, ca*cg, cb*sa*sg - ca*sb, 0,
cb*sa*sg - ca*sb, cg*sa, ca*cb + sa*sb*sg, 0,
0, 0, 0, 1
);
}
else if constexpr(order == order_yxz) {
} else if constexpr(order == order_yxz) {
return mat<genType, 4, 4>(
cb*cg + sa*sb*sg, cg*sa*sb - cb*sg, ca*sb, 0,
ca*sg, ca*cg, -sa, 0,
cb*sa*sg - cg*sb, cb*cg*sa + sb*sg, ca*cb, 0,
0, 0, 0, 1
);
}
else if constexpr(order == order_yzx) {
} else if constexpr(order == order_yzx) {
return mat<genType, 4, 4>(
cb*cg, sa*sb - ca*cb*sg, ca*sb + cb*sa*sg, 0,
sg, ca*cg, -cg*sa, 0,
-cg*sb, ca*sb*sg + cb*sa, ca*cb - sa*sb*sg, 0,
0, 0, 0, 1
);
}
else if constexpr(order == order_zxy) {
} else if constexpr(order == order_zxy) {
return mat<genType, 4, 4>(
cb*cg - sa*sb*sg, -ca*sg, cb*sa*sg + cg*sb, 0,
cb*sg + cg*sa*sb, ca*cg, sb*sg - cb*cg*sa, 0,
-ca*sb, sa, ca*cb, 0,
0, 0, 0, 1
);
}
else if constexpr(order == order_zyx) {
} else if constexpr(order == order_zyx) {
return mat<genType, 4, 4>(
cb*cg, cg*sa*sb - ca*sg, ca*cg*sb + sa*sg, 0,
cb*sg, ca*cg + sa*sb*sg, ca*sb*sg - cg*sa, 0,

View File

@@ -19,7 +19,6 @@
#ifndef FENNEC_MATH_EXT_TRIGONOMETRIC_H
#define FENNEC_MATH_EXT_TRIGONOMETRIC_H
#include <fennec/math/trigonometric.h>
#include <fennec/math/ext/quaternion.h>
namespace fennec
@@ -27,6 +26,7 @@ namespace fennec
// Angle Conversions ===================================================================================================
#ifndef FENNEC_DOXYGEN
template<typename genType>
constexpr qua<genType> radians(const qua<genType>& degrees) {
return qua<genType>(degrees * 0.01745329251994329576923690768489);
@@ -37,7 +37,6 @@ constexpr qua<genType> degrees(const qua<genType>& radians) {
return qua<genType>(radians * 57.29577951308232087679815481410517);
}
// Trigonometric Functions =============================================================================================
template<typename genType>
@@ -162,6 +161,7 @@ constexpr qua<genType> atanh(const qua<genType>& x) {
fennec::atanh(x.z)
);
}
#endif
}

View File

@@ -43,13 +43,13 @@
/// \code #include <fennec/math/geometric.h> \endcode
///
///
/// \section Geometric Functions
/// \section fennec_math_geometric_section_functions Geometric Functions
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_geometric_functions">
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::dot "float dot(genFType x, genFType y)" <br>
/// \ref fennec::dot "float dot(genFType x, genFType y)" <br>
/// \ref fennec::dot "double dot(genDType x, genDType x)"
/// <td width="50%" style="vertical-align: top">
/// \copydoc fennec::dot
@@ -118,7 +118,7 @@ namespace fennec
// dot -----------------------------------------------------------------------------------------------------------------
///
/// \brief Returns the dot product of \f$x\f$ and \f$y\f$, i.e., \f$x_0 \cdot y_0 + x_0 \cdot y_0 + \ldots\f$
/// \brief Returns the dot product of \f$x\f$ and \f$y\f$, i.e., \f$x_0 \cdot y_0 + x_1 \cdot y_1 + \ldots\f$
///
/// \returns the dot product of \f$x\f$ and \f$y\f$, i.e., \f$x_0 \cdot y_0 + x_0 \cdot y_0 + \ldots\f$ <br><br>
/// \details we can represent this in linear algebra as the following, <br><br>

View File

@@ -182,7 +182,7 @@ constexpr matrix<scalar, rows, cols...> inverse(const matrix<scalar, rows, cols.
/// \tparam ScalarT
/// \tparam RowsV
/// \tparam ColIndicesV
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV>
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV> requires(is_scalar_v<ScalarT>)
struct matrix
{
// Assertions ==========================================================================================================
@@ -251,7 +251,6 @@ struct matrix
/// \param mat matrix to copy
constexpr matrix(const matrix_t& mat)
: data{ mat.data } {
}
///
@@ -261,7 +260,26 @@ struct matrix
/// \param mat matrix to move
constexpr matrix(matrix_t&& mat) noexcept
: data{ mat.data } {
}
template<typename OScalarT>
constexpr matrix(const matrix<OScalarT, RowsV, ColIndicesV...>& mat)
: matrix() {
for (size_t i = 0; i < columns; ++i) {
for (size_t j = 0; j < rows; ++j) {
data[i][j] = scalar_t(mat[i][j]);
}
}
}
template<typename OScalarT>
constexpr matrix(matrix<OScalarT, RowsV, ColIndicesV...>&& mat) noexcept
: matrix() {
for (size_t i = 0; i < columns; ++i) {
for (size_t j = 0; j < rows; ++j) {
data[i][j] = scalar_t(mat[i][j]);
}
}
}
@@ -629,6 +647,11 @@ struct matrix
);
}
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
return *this = *this * rhs;
}
/// @}

View File

@@ -41,7 +41,7 @@
///
///
#include <fennec/lang/const_sequences.h>
#include <fennec/lang/metasequences.h>
#include <fennec/math/swizzle_storage.h>
@@ -79,7 +79,7 @@ public:
/// \return The Value of the Swizzle as a Vector
constexpr VectorT decay() const {
VectorT res;
return decay_impl(res, make_index_sequence<size>{});
return decay_impl(res, make_index_metasequence<size>{});
}
///
@@ -93,7 +93,7 @@ public:
private:
template<size_t...VecIndicesV>
constexpr VectorT& decay_impl(VectorT& vec, const_index_sequence<VecIndicesV...>) {
constexpr VectorT& decay_impl(VectorT& vec, index_metasequence<VecIndicesV...>) {
return ((vec[VecIndicesV] = this->data[IndicesV]), ..., vec);
}
};

View File

@@ -145,6 +145,8 @@
///
#include <fennec/math/detail/_math.h>
#include <fennec/math/vector.h>
#include <fennec/lang/types.h>
namespace fennec
{
@@ -167,11 +169,6 @@ constexpr genType radians(genType degrees) {
return genType(degrees * 0.01745329251994329576923690768489);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> radians(const vector<genType, i...>& degrees) {
return vector<genType, i...>(degrees * 0.01745329251994329576923690768489);
}
///
/// \brief Converts \f$radians\f$ to \f$degrees\f$, i.e., \f$radians\cdot\frac{\pi}{180}\f$
@@ -186,11 +183,6 @@ constexpr genType degrees(genType radians) {
return genType(radians * 57.29577951308232087679815481410517);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> degrees(const vector<genType, i...>& radians) {
return genType(radians * 57.29577951308232087679815481410517);
}
/// @}
@@ -213,11 +205,6 @@ constexpr genType sin(genType x) {
return ::sin(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> sin(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sin(x[i]) ...);
}
///
/// \brief The Standard Trigonometric Cosine
@@ -232,11 +219,6 @@ constexpr genType cos(genType x) {
return ::cos(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> cos(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::cos(x[i]) ...);
}
///
/// \brief The Standard Trigonometric Tangent
@@ -251,11 +233,6 @@ constexpr genType tan(genType x) {
return ::tan(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> tan(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::tan(x[i]) ...);
}
/// @}
@@ -277,11 +254,6 @@ constexpr genType asin(genType x) {
return ::asin(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> asin(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::asin(x[i]) ...);
}
///
/// \brief Arc Cosine. Returns an angle \f$\theta\f$ whose cosine is /a x.
@@ -297,11 +269,6 @@ constexpr genType acos(genType x) {
return ::acos(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> acos(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::acos(x[i]) ...);
}
///
/// \brief Arc Tangent. Returns an angle \f$\theta\f$ whose tangent is /a y_over_x.
@@ -317,11 +284,6 @@ constexpr genType atan(genType y_over_x) {
return ::atan(y_over_x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> atan(const vector<genType, i...>& y_over_x) {
return vector<genType, i...>(fennec::atan(y_over_x[i]) ...);
}
///
/// \brief Arc Tangent. Returns an angle whose tangent is \f$\frac{y}{x}\f$.
@@ -338,11 +300,6 @@ constexpr genType atan(genType y, genType x) {
return ::atan2(y, x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> atan(const vector<genType, i...>& y, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::atan(y[i], x[i]) ...);
}
/// @}
@@ -364,11 +321,6 @@ constexpr genType sinh(genType x) {
return ::sinh(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> sinh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sinh(x[i]) ...);
}
///
/// \brief Returns the Hyperbolic Cosine Function, \f$\frac{{e}^{x}+{e}^{-x}}{2}\f$
@@ -381,11 +333,6 @@ constexpr genType cosh(genType x) {
return ::cosh(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> cosh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::cosh(x[i]) ...);
}
///
/// \brief Returns the Hyperbolic Tangent Function, \f$\frac{\text{sinh}(x)}{\text{cosh}(x)}\f$
@@ -398,10 +345,6 @@ constexpr genType tanh(genType x) {
return ::tanh(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> tanh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::tanh(x[i]) ...);
}
/// @}
@@ -421,11 +364,6 @@ constexpr genType asinh(genType x) {
return ::asinh(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> asinh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::asinh(x[i]) ...);
}
///
/// \brief The Inverse Hyperbolic Cosine Function
@@ -439,11 +377,6 @@ constexpr genType acosh(genType x) {
return ::acosh(x);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> acosh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::acosh(x[i]) ...);
}
///
/// \brief The Inverse Hyperbolic Tangent Function
@@ -457,12 +390,88 @@ constexpr genType atanh(genType x) {
return ::atanh(x);
}
/// @}
// Internal ============================================================================================================
#ifndef FENNEC_DOXYGEN
template<typename genType, size_t...i>
constexpr vector<genType, i...> radians(const vector<genType, i...>& degrees) {
return vector<genType, i...>(degrees * 0.01745329251994329576923690768489);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> degrees(const vector<genType, i...>& radians) {
return genType(radians * 57.29577951308232087679815481410517);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> sin(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sin(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> cos(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::cos(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> tan(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::tan(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> asin(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::asin(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> acos(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::acos(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> atan(const vector<genType, i...>& y_over_x) {
return vector<genType, i...>(fennec::atan(y_over_x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> atan(const vector<genType, i...>& y, const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::atan(y[i], x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> sinh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::sinh(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> cosh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::cosh(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> tanh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::tanh(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> asinh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::asinh(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> acosh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::acosh(x[i]) ...);
}
template<typename genType, size_t...i>
constexpr vector<genType, i...> atanh(const vector<genType, i...>& x) {
return vector<genType, i...>(fennec::atanh(x[i]) ...);
}
/// @}
#endif

View File

@@ -103,6 +103,7 @@
///
///
#include <fennec/containers/initializer_list.h>
#include <fennec/math/detail/_fwd.h>
#include <fennec/math/vector_base.h>
@@ -120,7 +121,7 @@ namespace fennec
/// \tparam ScalarT The type of the Components
/// \tparam SizeV The number of Components
template<typename ScalarT, size_t SizeV>
using vec = decltype(detail::_gen_vector<vector, ScalarT>(make_index_sequence<SizeV>{}));
using vec = decltype(detail::_gen_vector<vector, ScalarT>(make_index_metasequence<SizeV>{}));
///
@@ -177,7 +178,7 @@ using dvec4 = tvec4<double_t>;
/// \tparam ScalarT base \ref scalar type of each Component
/// \tparam IndicesV index of each Component
/// \nosubgrouping
template<typename ScalarT, size_t... IndicesV>
template<typename ScalarT, size_t... IndicesV> requires(is_scalar_v<ScalarT>)
struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
{
// Assertions ==========================================================================================================
@@ -337,6 +338,21 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
vector::_construct<0>(args...);
}
constexpr vector(initializer_list<ScalarT> init) {
size_t i = 0;
for (ScalarT x : init) {
data[i++] = x;
}
}
template<typename OScalarT>
constexpr vector(initializer_list<OScalarT> init) {
size_t i = 0;
for (OScalarT x : init) {
data[i++] = ScalarT(x);
}
}
/// @}
@@ -1086,22 +1102,22 @@ private:
}
template<size_t OffsetV>
constexpr void _insert(ScalarT& x) {
constexpr void _insert(const ScalarT& x) {
data[OffsetV] = x;
}
template<size_t OffsetV, typename OScalarT>
constexpr void _insert(OScalarT& x) {
constexpr void _insert(const OScalarT& x) {
data[OffsetV] = ScalarT(x);
}
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
constexpr void _insert(vector<OScalarT, OIndicesV...>& vec) {
constexpr void _insert(const vector<OScalarT, OIndicesV...>& vec) {
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
}
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
constexpr void _insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
constexpr void _insert(const swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
size_t i = 0;
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
}

View File

@@ -280,7 +280,7 @@ public:
/// \details This simply acts as a proxy for allocating memory. It does not call any constructors or
/// initialize any values as if they were the provided data type. Any operations present work
/// only on individual bytes.
template<typename T, class AllocT>
template<typename T, class AllocT = allocator<T>>
struct allocation
{
public:
@@ -366,7 +366,8 @@ public:
constexpr allocation(size_t n, const alloc_t& alloc) noexcept
: _alloc(alloc)
, _data(nullptr)
, _capacity(0) {
, _capacity(0)
, _alignment(zero<align_t>()) {
callocate(n);
}
@@ -439,7 +440,10 @@ public:
///
/// \brief Default Destructor, releases the memory block if still present
constexpr ~allocation() noexcept {
if (_data) _alloc.deallocate(_data);
if (_data) {
_alloc.deallocate(_data);
_data = nullptr;
}
}
@@ -450,7 +454,7 @@ public:
/// \param alloc the allocation to copy
/// \returns a reference to `this`
constexpr allocation& operator=(const allocation& alloc) {
allocation::allocate(alloc.capacity());
allocation::allocate(alloc.capacity(), alloc.alignment());
fennec::memmove(_data, alloc, size());
return *this;
}
@@ -465,12 +469,13 @@ public:
fennec::swap(_alloc, alloc._alloc);
fennec::swap(_data, alloc._data);
fennec::swap(_capacity, alloc._capacity);
fennec::swap(_alignment, alloc._alignment);
return *this;
}
// Allocation and Deallocation =====================================================================================
// Allocation and Deallocation =========================================================================================
///
/// \brief Allocate a block of memory for the allocation.
@@ -627,7 +632,11 @@ public:
return _data;
}
private:
constexpr align_t alignment() const {
return _alignment;
}
protected:
alloc_t _alloc; // Allocator object
value_t* _data; // Handle for the memory block
size_t _capacity; // Capacity of the memory block in elements.

View File

@@ -16,8 +16,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_LANG_BYTES_H
#define FENNEC_LANG_BYTES_H
#ifndef FENNEC_MEMORY_BYTES_H
#define FENNEC_MEMORY_BYTES_H
#include <fennec/lang/assert.h>
#include <fennec/lang/types.h>
@@ -186,4 +186,4 @@ struct hash<byte_array> {
}
#endif // FENNEC_LANG_BYTES_H
#endif // FENNEC_MEMORY_BYTES_H

View File

@@ -73,6 +73,8 @@ using ::wmemcmp;
/// \param rhs The second object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of lhs
/// \param n1 The size, in bytes, of rhs
/// \returns \f$0\f$ if the first \f$min(n0, n1)\f$ bytes of \f$lhs\f$ and \f$rhs\f$ are equivalent. Otherwise, returns \f$1\f$
/// for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$
constexpr int memcmp_s(const void* lhs, size_t n0, const void* rhs, size_t n1) {
return memcmp(lhs, rhs, n0 < n1 ? n0 : n1);
}
@@ -98,6 +100,7 @@ using ::wmemcpy;
/// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
/// \returns \f$dst\f$
constexpr void* memcpy_s(void* dst, size_t n0, const void* src, size_t n1) {
return memcpy(dst, src, n0 < n1 ? n0 : n1);
}
@@ -117,6 +120,7 @@ using ::wmemmove;
/// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
/// \returns \f$dst\f$
constexpr void* memmove_s(void* dst, size_t n0, const void* src, size_t n1) {
return memmove(dst, src, n0 < n1 ? n0 : n1);
}

View File

@@ -45,7 +45,7 @@ struct default_delete
/// \param ptr Memory resource to delete
constexpr void operator()(TypeT* ptr) const noexcept {
static_assert(not is_void_v<TypeT>, "cannot delete a pointer to an incomplete type");
static_assert(not sizeof(TypeT) > 0, "cannot delete a pointer to an incomplete type");
static_assert(is_complete_v<TypeT>, "cannot delete a pointer to an incomplete type");
delete ptr;
}
};
@@ -70,7 +70,7 @@ struct default_delete<TypeT[]>
template<class ArrT> requires requires { is_convertible_v<ArrT(*)[], TypeT(*)[]> == true; }
constexpr void operator()(TypeT* ptr) const noexcept {
static_assert(not is_void_v<TypeT>, "cannot delete a pointer to an incomplete type");
static_assert(not sizeof(TypeT) > 0, "cannot delete a pointer to an incomplete type");
static_assert(is_complete_v<TypeT>, "cannot delete a pointer to an incomplete type");
delete[] ptr;
}
};
@@ -91,6 +91,9 @@ public:
/// \brief pointer to element type
using pointer_t = element_t*;
/// \brief pointer to element type
using const_pointer_t = const element_t*;
/// \brief the deleter
using delete_t = DeleteT;
@@ -100,22 +103,13 @@ public:
///
/// \brief Nullptr Constructor, creates a unique_ptr that owns nothing.
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr) {}
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr, delete_t()) {}
///
/// \brief Pointer Constructor, creates a unique_ptr that owns `ptr` with deleter `del`
/// \param ptr The resource to own
/// \param del The deleter
explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del)
: _delete(del)
, _handle(ptr) {
}
///
/// \brief Pointer Constructor, creates a unique_ptr that owns `ptr` with deleter `del`
/// \param ptr The resource to own
/// \param del The deleter
explicit constexpr unique_ptr(pointer_t ptr, delete_t&& del)
explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del = delete_t())
: _delete(del)
, _handle(ptr) {
}
@@ -134,7 +128,7 @@ public:
///
/// \brief Default Constructor, if it owns a resource, it deletes it using `delete_t`
constexpr ~unique_ptr() {
if(_handle) _delete(_handle);
reset();
}
constexpr unique_ptr& operator=(const unique_ptr&) = delete;
@@ -146,18 +140,59 @@ public:
return *this;
}
void reset(pointer_t ptr) {
if(_handle) {
_delete(_handle);
_handle = ptr;
}
}
void reset(nullptr_t = nullptr) {
if(_handle) {
_delete(_handle);
_handle = nullptr;
}
}
pointer_t release() {
pointer_t retval = _handle;
_handle = nullptr;
return retval;
}
pointer_t get() {
return _handle;
}
bool empty() {
return _handle == nullptr;
}
pointer_t operator->() {
return _handle;
}
const_pointer_t operator->() const {
return _handle;
}
private:
delete_t _delete;
pointer_t _handle;
};
///
/// \brief Creates a unique pointer holding an object of type `TypeT`
/// \tparam TypeT The type
/// \tparam ArgsT The constructor arguments, automatically deduced
/// \param args The constructor arguments
/// \returns A unique pointer holding a heap allocated object of type `TypeT` constructed with arguments `args`
template<typename TypeT, typename...ArgsT>
unique_ptr<TypeT> make_unique(ArgsT&&...args) {
return unique_ptr<TypeT>(new TypeT(fennec::forward<ArgsT>(args)...));
}
}
#endif // FENNEC_MEMORY_POINTERS_H

View File

@@ -1,83 +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_PLATFORM_INTERFACE_DISPLAY_H
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_H
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/types.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>
namespace fennec
{
class display : public typed<display>
{
public:
struct pixel_format {
uint8_t depth;
uint8_t r, g, b;
};
struct config {
pixel_format format;
};
virtual bool connected() const = 0;
virtual ~display();
virtual window* create_window(window* parent) = 0;
const pixel_format& get_color_format() const {
return _config.format;
}
virtual void select_context();
virtual void* get_native_handle() = 0;
platform* get_platform() { return _platform; }
gfxcontext* get_context() { return _context; }
const string name;
protected:
platform* _platform;
gfxcontext* _context;
config _config;
template<typename DisplayT>
explicit display(platform* platform, const cstring& name, DisplayT* type)
: typed(type)
, name(name)
, _platform(platform)
, _context(nullptr)
, _config {
.format = {
.depth = 24,
.r = 8,
.g = 8,
.b = 8,
}
} {
}
};
}
#endif // FENNEC_PLATFORM_INTERFACE_DISPLAY_H

View File

@@ -0,0 +1,158 @@
// =====================================================================================================================
// 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 display_server.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_INTERFACE_DISPLAY_SERVER_H
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_SERVER_H
#include <fennec/containers/bitfield.h>
#include <fennec/platform/interface/fwd.h>
#include <fennec/platform/interface/window.h>
#include <fennec/renderers/interface/gfxcontext.h>
#include <fennec/rtti/enable.h>
#include <fennec/rtti/type_registry.h>
namespace fennec
{
class display_server;
///
/// \brief Interface resembling the API for a display server of an operating system, e.g. Linux X11/Wayland
///
/// \details An implementation for a display server should inherit `display_server_base` and note the following:
///
/// For a server type `DisplayT`; any `gfxcontext` implementation that wishes to implement `DisplayT`
/// must provide a constructor that accepts a `DisplayT*`. `DisplayT::ctx_registry::register_type` must then be
/// called for the `gfxcontext` implementation.
class display_server : public type_registry<display_server, platform*> {
// Typedefs/Constants/Enums ============================================================================================
public:
enum feature_ : uint32_t {
feature_subwindows = 0,
feature_icon,
feature_window_drag,
feature_mouse,
feature_cursors,
feature_custom_cursors,
feature_clipboard,
feature_clipboard_primary,
feature_virtual_keyboard,
feature_status_indicators,
feature_dialogues,
feature_input_dialogues,
feature_file_dialogues,
feature_filtered_file_dialogues,
feature_orientation,
feature_hidpi,
feature_hdr,
feature_swap_buffers,
feature_window_transparency,
feature_screen_reader,
feature_text_to_speech,
feature_touchscreen,
feature_system_theme,
feature_count,
};
using featureset_t = bitfield<feature_count>;
using window_id = uint32_t;
using window_pool = object_pool<window*>;
struct config {
};
// Public Members ======================================================================================================
platform* const platform;
explicit display_server(fennec::platform* p)
: platform(p) {
}
virtual ~display_server() {
}
bool has_feature(uint32_t feature) const {
return features.test(feature);
}
virtual window* create_window(const window::config& conf) = 0;
window* get_window(size_t id) {
return id == window::nullid ? nullptr : windows[id];
}
virtual void connect() = 0;
virtual void disconnect() = 0;
virtual bool connected() const = 0;
virtual void dispatch() = 0;
virtual void* get_native_handle() = 0;
gfxcontext* get_gfx_context() {
return gfx_context.get();
}
protected:
featureset_t features;
window_pool windows;
unique_ptr<gfxcontext> gfx_context;
FENNEC_RTTI_CLASS_ENABLE() {
}
};
template<typename DisplayT, typename WindowT>
class display_server_base : public display_server, public type_registry<gfxcontext, DisplayT*> {
public:
display_server_base(fennec::platform* p)
: display_server(p) {
}
using ctx_registry = type_registry<gfxcontext, DisplayT*>;
using window_t = WindowT;
};
}
#endif // FENNEC_PLATFORM_INTERFACE_DISPLAY_SERVER_H

View File

@@ -22,12 +22,12 @@
namespace fennec
{
class platform; // Handles OS level functionality
class display; // Handles display protocols
class window; // Handles window surfaces of the display protocol
class inputdevice; // Handles input devices
class gfxcontext; // Handle Driver Contexts, i.e. EGL, WGL, VkWayland, etc.
class gfxsurface; // Handle surface targets for windows
class platform;
class display_server; // The display server used by the OS, e.g. WDM, Wayland, X11, etc.
class gfxcontext; // Handles the GFX API context of a display server, e.g. OpenGL, Vulkan, etc.
class window; // Handles window surfaces of the display protocol
class gfxsurface; // Handles the GFX surface of a window for a specific gfxcontext
}

View File

@@ -19,11 +19,12 @@
#ifndef FENNEC_PLATFORM_INTERFACE_PLATFORM_H
#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H
#include <fennec/containers/list.h>
#include <fennec/langproc/strings/cstring.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>
#include <fennec/platform/interface/display_server.h>
#include <fennec/string/cstring.h>
#include <fennec/rtti/enable.h>
#include <fennec/rtti/singleton.h>
#include <fennec/rtti/detail/_this_t.h>
/*
* This class should resemble the target platform as a whole. By itself, it will represent the OS, i.e. Linux, Windows,
@@ -59,14 +60,16 @@
namespace fennec
{
class platform : public typed<platform> {
///
/// \brief Main platform class
class platform : public singleton<platform*> {
public:
using shared_object = struct shared_object;
using symbol = void*;
const string name;
platform();
virtual ~platform() = default;
platform(const platform&) = delete;
// Dynamically linked objects
virtual shared_object* load_object(const cstring& file) = 0;
@@ -74,65 +77,14 @@ public:
virtual symbol find_symbol(shared_object* obj, const cstring& name) = 0;
virtual void initialize(); // Initialize Drivers and Contexts
virtual void shutdown(); // Close Drivers and Contexts
virtual void shutdown(); // Close Drivers and Contexts
display* get_display() { return _display; }
display_server* get_display_server() { return display.get(); }
protected:
template<typename PlatformT>
explicit platform(const cstring& name, PlatformT* type)
: typed(type)
, name(name) {
auto& globals = _get_globals();
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions.");
globals.singleton = this;
}
unique_ptr<display_server> display;
virtual void load_display();
display* _display;
private:
platform(const platform&) = delete;
// Static Stuff ========================================================================================================
public:
using display_ctor = display* (*)(platform*);
using input_ctor = inputdevice* (*)(display*);
using gfxctx_ctor = gfxcontext* (*)(display*);
template<typename ctor>
struct driver {
int priority;
ctor constructor;
};
struct global_context {
platform* singleton;
list<driver<display_ctor>> displays;
list<driver<input_ctor>> inputs;
list<driver<gfxctx_ctor>> graphics;
global_context()
: singleton(nullptr) {
}
};
static void add_driver(display_ctor ctor, int priority);
static void add_driver(input_ctor ctor, int priority);
static void add_driver(gfxctx_ctor ctor, int priority);
private:
static global_context& _get_globals();
public:
static const global_context& get_globals() {
return _get_globals();
}
static platform* instance() {
return _get_globals().singleton;
FENNEC_RTTI_CLASS_ENABLE() {
}
};

View File

@@ -16,152 +16,179 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file window.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H
#include <fennec/containers/optional.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/platform/interface/fwd.h>
#include <fennec/platform/linux/wayland/display.h>
#include <fennec/math/ext/rect.h>
#include <fennec/string/string.h>
#include <fennec/containers/bitfield.h>
#include <fennec/containers/optional.h>
namespace fennec
{
///
/// \brief interface for handling windows
/// \details the interface makes no guarantees about the bit-depth and is completely dependent on the implementation.
class window : public typed<window> {
class window {
// Structures & Typedefs ===============================================================================================
public:
enum class fullscreen_mode {
windowed = 0,
borderless,
fullscreen
static constexpr size_t nullid = -1;
enum mode_ : uint8_t {
mode_windowed = 0,
mode_minimized,
mode_maximized,
mode_fullscreen,
mode_exclusive_fullscreen,
};
enum flags_ : uint32_t {
flags_none = 0,
flags_child = 0x1 << 0,
flags_modal = 0x1 << 1,
flags_grab_mouse = 0x1 << 2,
flags_grab_keyboard = 0x1 << 3,
flags_block_screensaver = 0x1 << 4,
enum vsync_ : uint8_t {
vsync_disabled = 0,
vsync_enabled,
vsync_adaptive
};
enum flag_ : uint8_t {
flag_always_on_top = 0, // Window always appears on top level
flag_borderless, // Window has no border decorations
flag_modal, // Window always appears above parent and blocks input going to parent
flag_pass_mouse, // Mouse interaction passes to next underlying window in the application
flag_popup, // Window does not show in taskbar and closes when loses focus
flag_resizable, // Window can be resized through functions defined by Desktop Environment
flag_transparent, // Window has an alpha value
flag_no_focus, // Window can be focused
flag_count
};
enum state_ : uint8_t {
state_running = 0, // Window is running
state_child, // Window is a child
state_suspended, // Window is suspended
state_visible, // Window is visible
state_count
};
using flags_t = bitfield<flag_count>;
using state_t = bitfield<state_count>;
struct accessibility {
string name, description;
};
struct config {
string title;
uint32_t flags;
size_t width, height;
fullscreen_mode fullscreen;
string title;
flags_t flags;
uint8_t mode;
size_t parent;
irect rect;
double_t fractional_scaling;
accessibility accessibility;
};
struct state {
uint8_t mode;
irect rect;
state_t flags;
int_t buffer_scale;
double_t fractional_scaling;
};
window(display_server* server, size_t id, const config& conf)
: server(server), id(id)
, cfg(conf), state(), root(nullptr) {
state.mode = conf.mode;
}
virtual ~window() = default;
virtual bool running() = 0;
virtual void configure(const config& config) = 0;
virtual bool initialize(bool modal) = 0;
virtual bool shutdown() = 0;
size_t get_id() const { return id; }
size_t get_parent_id() const { return cfg.parent; }
virtual bool set_title(const cstring& title) = 0;
virtual bool set_title(const string& title) = 0;
const config& get_config() const { return cfg; }
virtual bool set_width(size_t w) = 0;
virtual bool set_height(size_t h) = 0;
virtual bool resize(size_t w, size_t h) = 0;
window* get_parent() const;
virtual bool set_fullscreen_mode(fullscreen_mode mode) = 0;
const ivec2& get_size() const { return state.rect.size; }
const ivec2& get_position() const { return state.rect.position; }
virtual bool set_resizable(bool e) = 0;
virtual bool grab_keyboard(bool e) = 0;
virtual bool grab_mouse(bool e) = 0;
virtual bool block_screensaver(bool e) = 0;
virtual struct wl_surface* get_native_handle() = 0;
bool is_child() const {
if (not _config) return false;
return _config->flags & flags_child;
}
bool is_modal() const {
if (not _config) return false;
return _config->flags & flags_modal;
}
display* get_display() {
return _display;
}
const display* get_display() const {
return _display;
}
const config& get_config() const {
return *_config;
}
int get_width() const { return state.rect.size.x; }
int get_height() const { return state.rect.size.y; }
int get_pos_x() const { return state.rect.position.x; }
int get_pos_y() const { return state.rect.position.y; }
const string& get_title() const {
static const string _null{"null"};
if (not _config) return _null;
return _config->title;
}
bool is_visible() const { return state.flags.test(state_visible); }
bool is_child() const { return state.flags.test(state_child); }
bool is_running() const { return state.flags.test(state_running); }
bool is_suspended() const { return state.flags.test(state_suspended); }
bool get_flag(uint8_t flag) const { return cfg.flags.test(flag); }
bool is_always_on_top() const { return get_flag(flag_always_on_top); }
bool is_borderless() const { return get_flag(flag_borderless); }
bool is_modal() const { return get_flag(flag_modal); }
bool is_passing_mouse() const { return get_flag(flag_pass_mouse); }
bool is_popup() const { return get_flag(flag_popup); }
bool is_resizable() const { return get_flag(flag_resizable); }
bool is_transparent() const { return get_flag(flag_transparent); }
bool is_no_focus() const { return get_flag(flag_no_focus); }
size_t get_width() const {
if (not _config) return false;
return _config->width;
}
virtual bool set_flag(uint8_t flag, bool val) = 0;
size_t get_height() const {
if (not _config) return false;
return _config->height;
}
bool set_always_on_top(bool val) { return set_flag(flag_always_on_top, val); }
bool set_borderless(bool val) { return set_flag(flag_borderless, val); }
bool set_modal(bool val) { return set_flag(flag_modal, val); }
bool set_passing_mouse(bool val) { return set_flag(flag_pass_mouse, val); }
bool set_popup(bool val) { return set_flag(flag_popup, val); }
bool set_resizable(bool val) { return set_flag(flag_resizable, val); }
bool set_transparent(bool val) { return set_flag(flag_transparent, val); }
bool set_no_focus(bool val) { return set_flag(flag_no_focus, val); }
virtual void initialize() = 0;
virtual void shutdown() = 0;
fullscreen_mode get_fullscreen_mode() const {
if (not _config) return fullscreen_mode::windowed;
return _config->fullscreen;
}
virtual void begin_frame();
virtual void end_frame();
bool is_keyboard_grabbed() const {
if (not _config) return false;
return _config->flags & flags_grab_keyboard;
}
bool is_mouse_grabbed() const {
if (not _config) return false;
return _config->flags & flags_grab_mouse;
}
bool is_screensaver_blocked() const {
if (not _config) return false;
return _config->flags & flags_block_screensaver;
}
template<class DisplayT>
DisplayT* get_display() {
return static_cast<DisplayT*>(_display);
}
virtual void* get_native_handle() = 0;
protected:
template<typename TypeT>
window(display* display, window* parent, TypeT* type)
: typed(type)
, _display(display)
, _parent(parent)
, _surface(nullptr) {
display_server* const server;
const size_t id;
config cfg;
state state;
window* root;
gfxsurface* gfx_surface;
};
template<typename DisplayT>
class window_base : public window {
public:
window_base(display_server* display, size_t id, const config& conf)
: window(display, id, conf) {
}
display* _display;
window* _parent;
optional<config> _config;
gfxsurface* _surface;
private:
private:
using display_t = DisplayT;
};
}

View File

@@ -26,12 +26,15 @@ namespace fennec
class linux_platform : public unix_platform {
public:
linux_platform()
: unix_platform("linux", this) {
: unix_platform() {
}
void initialize() override;
void shutdown() override;
FENNEC_RTTI_CLASS_ENABLE(unix_platform) {
}
};
}

View File

@@ -1,71 +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_PLATFORM_LINUX_WAYLAND_DISPLAY_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H
#include <fennec/platform/interface/display.h>
#include <fennec/platform/linux/wayland/lib/wayland.h>
namespace fennec
{
class wayland_display : public display {
public:
explicit wayland_display(platform* platform);
~wayland_display() override;
bool connected() const override;
void* get_native_handle() override { return _handle; }
window* create_window(window* parent) override;
wl_registry* get_registry() { return _registry; }
const wl_registry* get_registry() const { return _registry; }
wl_compositor* get_compositor() { return _compositor; }
const wl_compositor* get_compositor() const { return _compositor; }
// xdg_wm_base* get_shell() { return _shell; }
//const xdg_wm_base* get_shell() const { return _shell; }
wl_seat* get_seat() { return _seat; }
const wl_seat* get_seat() const { return _seat; }
wl_shm* get_shm() { return _shm; }
const wl_shm* get_shm() const { return _shm; }
private:
wl_display* _handle;
wl_registry* _registry;
wl_compositor* _compositor;
//xdg_wm_base* _shell;
wl_seat* _seat;
wl_shm* _shm;
bool _fifo;
void cleanup();
static void listen_global(void*, wl_registry*, uint32_t, const char*, uint32_t);
static void listen_global_remove(void*, wl_registry*, uint32_t);
static void listen_seat(void*, wl_seat*, uint32_t);
};
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H

View File

@@ -0,0 +1,55 @@
// =====================================================================================================================
// 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 context.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_EGL_CONTEXT_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_EGL_CONTEXT_H
#include <fennec/platform/opengl/egl/context.h>
namespace fennec
{
class wayland_eglcontext : public eglcontext {
public:
explicit wayland_eglcontext(display_server* display);
~wayland_eglcontext();
gfxsurface* create_surface(window* window) override;
private:
FENNEC_RTTI_CLASS_ENABLE(eglcontext) {
wayland_server::ctx_registry::register_type<wayland_eglcontext>();
}
};
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_EGL_CONTEXT_H

View File

@@ -0,0 +1,53 @@
// =====================================================================================================================
// 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 surface.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef LATFORM_LINUX_WAYLAND_EGL_SURFACE_H
#define LATFORM_LINUX_WAYLAND_EGL_SURFACE_H
#include <fennec/platform/opengl/egl/surface.h>
#include <fennec/platform/linux/wayland/fwd.h>
namespace fennec
{
class wayland_eglsurface : public eglsurface {
public:
wayland_eglsurface(wayland_window* win, eglcontext* ctx);
~wayland_eglsurface();
void resize(const ivec2& size) override;
private:
};
}
#endif // LATFORM_LINUX_WAYLAND_EGL_SURFACE_H

View 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/>.
// =====================================================================================================================
///
/// \file fwd.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_FWD_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_FWD_H
namespace fennec
{
class wayland_server;
class wayland_window;
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_FWD_H

View File

@@ -1,4 +1,4 @@
/* Generated by wayland-scanner 1.23.1 */
/* Generated by wayland-scanner 1.24.0 */
#ifndef WAYLAND_CLIENT_PROTOCOL_H
#define WAYLAND_CLIENT_PROTOCOL_H
@@ -36,6 +36,7 @@ extern "C" {
* - @subpage page_iface_wl_region - region interface
* - @subpage page_iface_wl_subcompositor - sub-surface compositing
* - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface
* - @subpage page_iface_wl_fixes - wayland protocol fixes
* @section page_copyright_wayland Copyright
* <pre>
*
@@ -73,6 +74,7 @@ struct wl_data_device_manager;
struct wl_data_offer;
struct wl_data_source;
struct wl_display;
struct wl_fixes;
struct wl_keyboard;
struct wl_output;
struct wl_pointer;
@@ -940,6 +942,25 @@ extern const struct wl_interface wl_subcompositor_interface;
*/
extern const struct wl_interface wl_subsurface_interface;
#endif
#ifndef WL_FIXES_INTERFACE
#define WL_FIXES_INTERFACE
/**
* @page page_iface_wl_fixes wl_fixes
* @section page_iface_wl_fixes_desc Description
*
* This global fixes problems with other core-protocol interfaces that
* cannot be fixed in these interfaces themselves.
* @section page_iface_wl_fixes_api API
* See @ref iface_wl_fixes.
*/
/**
* @defgroup iface_wl_fixes The wl_fixes interface
*
* This global fixes problems with other core-protocol interfaces that
* cannot be fixed in these interfaces themselves.
*/
extern const struct wl_interface wl_fixes_interface;
#endif
#ifndef WL_DISPLAY_ERROR_ENUM
#define WL_DISPLAY_ERROR_ENUM
@@ -2076,8 +2097,10 @@ struct wl_buffer_listener {
* compositor releases buffer
*
* Sent when this wl_buffer is no longer used by the compositor.
* The client is now free to reuse or destroy this buffer and its
* backing storage.
*
* For more information on when release events may or may not be
* sent, and what consequences it has, please see the description
* of wl_surface.attach.
*
* If a client receives a release event before the frame callback
* requested in the same wl_surface.commit that attaches this
@@ -3915,7 +3938,8 @@ wl_surface_destroy(struct wl_surface *wl_surface)
* the delivery of wl_buffer.release events becomes undefined. A well
* behaved client should not rely on wl_buffer.release events in this
* case. Alternatively, a client could create multiple wl_buffer objects
* from the same backing storage or use wp_linux_buffer_release.
* from the same backing storage or use a protocol extension providing
* per-commit release notifications.
*
* Destroying the wl_buffer after wl_buffer.release does not change
* the surface contents. Destroying the wl_buffer before wl_buffer.release
@@ -4247,6 +4271,9 @@ wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, in
* x and y, combined with the new surface size define in which
* directions the surface's size changes.
*
* The exact semantics of wl_surface.offset are role-specific. Refer to
* the documentation of specific roles for more information.
*
* Surface location offset is double-buffered state, see
* wl_surface.commit.
*
@@ -4310,9 +4337,10 @@ struct wl_seat_listener {
/**
* seat capabilities changed
*
* This is emitted whenever a seat gains or loses the pointer,
* keyboard or touch capabilities. The argument is a capability
* enum containing the complete set of capabilities this seat has.
* This is sent on binding to the seat global or whenever a seat
* gains or loses the pointer, keyboard or touch capabilities. The
* argument is a capability enum containing the complete set of
* capabilities this seat has.
*
* When the pointer capability is added, a client may create a
* wl_pointer object using the wl_seat.get_pointer request. This
@@ -4356,9 +4384,10 @@ struct wl_seat_listener {
* be shared across processes to refer to a specific wl_seat
* global.
*
* The name event is sent after binding to the seat global. This
* event is only sent once per seat object, and the name does not
* change over the lifetime of the wl_seat global.
* The name event is sent after binding to the seat global, and
* should be sent before announcing capabilities. This event only
* sent once per seat object, and the name does not change over the
* lifetime of the wl_seat global.
*
* Compositors may re-use the same seat name if the wl_seat global
* is destroyed and re-created later.
@@ -5157,6 +5186,14 @@ enum wl_keyboard_keymap_format {
* physical key state
*
* Describes the physical state of a key that produced the key event.
*
* Since version 10, the key can be in a "repeated" pseudo-state which
* means the same as "pressed", but is used to signal repetition in the
* key event.
*
* The key may only enter the repeated state after entering the pressed
* state and before entering the released state. This event may be
* generated multiple times while the key is down.
*/
enum wl_keyboard_key_state {
/**
@@ -5167,7 +5204,16 @@ enum wl_keyboard_key_state {
* key is pressed
*/
WL_KEYBOARD_KEY_STATE_PRESSED = 1,
/**
* key was repeated
* @since 10
*/
WL_KEYBOARD_KEY_STATE_REPEATED = 2,
};
/**
* @ingroup iface_wl_keyboard
*/
#define WL_KEYBOARD_KEY_STATE_REPEATED_SINCE_VERSION 10
#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
/**
@@ -5207,6 +5253,9 @@ struct wl_keyboard_listener {
* down to the keys in the keys argument. The compositor must not
* send this event if the wl_keyboard already had an active surface
* immediately before this event.
*
* Clients should not use the list of pressed keys to emulate
* key-press events. The order of keys in the list is unspecified.
* @param serial serial number of the enter event
* @param surface surface gaining keyboard focus
* @param keys the keys currently logically down
@@ -5257,6 +5306,11 @@ struct wl_keyboard_listener {
* event if state is pressed (resp. released) and the key was
* already logically down (resp. was not logically down)
* immediately before this event.
*
* Since version 10, compositors may send key events with the
* "repeated" key state when a wl_keyboard.repeat_info event with a
* rate argument of 0 has been received. This allows the compositor
* to take over the responsibility of key repetition.
* @param serial serial number of the key event
* @param time timestamp with millisecond granularity
* @param key key that produced the event
@@ -6403,6 +6457,69 @@ wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)
WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
}
#define WL_FIXES_DESTROY 0
#define WL_FIXES_DESTROY_REGISTRY 1
/**
* @ingroup iface_wl_fixes
*/
#define WL_FIXES_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wl_fixes
*/
#define WL_FIXES_DESTROY_REGISTRY_SINCE_VERSION 1
/** @ingroup iface_wl_fixes */
static inline void
wl_fixes_set_user_data(struct wl_fixes *wl_fixes, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_fixes, user_data);
}
/** @ingroup iface_wl_fixes */
static inline void *
wl_fixes_get_user_data(struct wl_fixes *wl_fixes)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_fixes);
}
static inline uint32_t
wl_fixes_get_version(struct wl_fixes *wl_fixes)
{
return wl_proxy_get_version((struct wl_proxy *) wl_fixes);
}
/**
* @ingroup iface_wl_fixes
*/
static inline void
wl_fixes_destroy(struct wl_fixes *wl_fixes)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_fixes,
WL_FIXES_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_fixes), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_wl_fixes
*
* This request destroys a wl_registry object.
*
* The client should no longer use the wl_registry after making this
* request.
*
* The compositor will emit a wl_display.delete_id event with the object ID
* of the registry and will no longer emit any events on the registry. The
* client should re-use the object ID once it receives the
* wl_display.delete_id event.
*/
static inline void
wl_fixes_destroy_registry(struct wl_fixes *wl_fixes, struct wl_registry *registry)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_fixes,
WL_FIXES_DESTROY_REGISTRY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_fixes), 0, registry);
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,4 +1,4 @@
/* Generated by wayland-scanner 1.23.1 */
/* Generated by wayland-scanner 1.24.0 */
#ifndef XDG_SHELL_CLIENT_PROTOCOL_H
#define XDG_SHELL_CLIENT_PROTOCOL_H
@@ -1390,6 +1390,46 @@ enum xdg_toplevel_state {
* @since 6
*/
XDG_TOPLEVEL_STATE_SUSPENDED = 9,
/**
* the surfaces left edge is constrained
*
* The left edge of the window is currently constrained, meaning
* it shouldn't attempt to resize from that edge. It can for
* example mean it's tiled next to a monitor edge on the
* constrained side of the window.
* @since 7
*/
XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT = 10,
/**
* the surfaces right edge is constrained
*
* The right edge of the window is currently constrained, meaning
* it shouldn't attempt to resize from that edge. It can for
* example mean it's tiled next to a monitor edge on the
* constrained side of the window.
* @since 7
*/
XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT = 11,
/**
* the surfaces top edge is constrained
*
* The top edge of the window is currently constrained, meaning
* it shouldn't attempt to resize from that edge. It can for
* example mean it's tiled next to a monitor edge on the
* constrained side of the window.
* @since 7
*/
XDG_TOPLEVEL_STATE_CONSTRAINED_TOP = 12,
/**
* the surfaces bottom edge is tiled
*
* The bottom edge of the window is currently constrained,
* meaning it shouldn't attempt to resize from that edge. It can
* for example mean it's tiled next to a monitor edge on the
* constrained side of the window.
* @since 7
*/
XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM = 13,
};
/**
* @ingroup iface_xdg_toplevel
@@ -1411,6 +1451,22 @@ enum xdg_toplevel_state {
* @ingroup iface_xdg_toplevel
*/
#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6
/**
* @ingroup iface_xdg_toplevel
*/
#define XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION 7
/**
* @ingroup iface_xdg_toplevel
*/
#define XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT_SINCE_VERSION 7
/**
* @ingroup iface_xdg_toplevel
*/
#define XDG_TOPLEVEL_STATE_CONSTRAINED_TOP_SINCE_VERSION 7
/**
* @ingroup iface_xdg_toplevel
*/
#define XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM_SINCE_VERSION 7
#endif /* XDG_TOPLEVEL_STATE_ENUM */
#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM

View File

@@ -501,8 +501,10 @@
<event name="release">
<description summary="compositor releases buffer">
Sent when this wl_buffer is no longer used by the compositor.
The client is now free to reuse or destroy this buffer and its
backing storage.
For more information on when release events may or may not be sent,
and what consequences it has, please see the description of
wl_surface.attach.
If a client receives a release event before the frame callback
requested in the same wl_surface.commit that attaches this
@@ -1504,7 +1506,8 @@
the delivery of wl_buffer.release events becomes undefined. A well
behaved client should not rely on wl_buffer.release events in this
case. Alternatively, a client could create multiple wl_buffer objects
from the same backing storage or use wp_linux_buffer_release.
from the same backing storage or use a protocol extension providing
per-commit release notifications.
Destroying the wl_buffer after wl_buffer.release does not change
the surface contents. Destroying the wl_buffer before wl_buffer.release
@@ -1832,6 +1835,9 @@
x and y, combined with the new surface size define in which
directions the surface's size changes.
The exact semantics of wl_surface.offset are role-specific. Refer to
the documentation of specific roles for more information.
Surface location offset is double-buffered state, see
wl_surface.commit.
@@ -1880,7 +1886,7 @@
</event>
</interface>
<interface name="wl_seat" version="9">
<interface name="wl_seat" version="10">
<description summary="group of input devices">
A seat is a group of keyboards, pointer and touch devices. This
object is published as a global during start up, or when such a
@@ -1908,9 +1914,10 @@
<event name="capabilities">
<description summary="seat capabilities changed">
This is emitted whenever a seat gains or loses the pointer,
keyboard or touch capabilities. The argument is a capability
enum containing the complete set of capabilities this seat has.
This is sent on binding to the seat global or whenever a seat gains
or loses the pointer, keyboard or touch capabilities.
The argument is a capability enum containing the complete set of
capabilities this seat has.
When the pointer capability is added, a client may create a
wl_pointer object using the wl_seat.get_pointer request. This object
@@ -1992,9 +1999,9 @@
The same seat names are used for all clients. Thus, the name can be
shared across processes to refer to a specific wl_seat global.
The name event is sent after binding to the seat global. This event is
only sent once per seat object, and the name does not change over the
lifetime of the wl_seat global.
The name event is sent after binding to the seat global, and should be sent
before announcing capabilities. This event only sent once per seat object,
and the name does not change over the lifetime of the wl_seat global.
Compositors may re-use the same seat name if the wl_seat global is
destroyed and re-created later.
@@ -2013,7 +2020,7 @@
</interface>
<interface name="wl_pointer" version="9">
<interface name="wl_pointer" version="10">
<description summary="pointer input device">
The wl_pointer interface represents one or more input devices,
such as mice, which control the pointer location and pointer_focus
@@ -2426,7 +2433,7 @@
</event>
</interface>
<interface name="wl_keyboard" version="9">
<interface name="wl_keyboard" version="10">
<description summary="keyboard input device">
The wl_keyboard interface represents one or more keyboards
associated with a seat.
@@ -2479,6 +2486,9 @@
the surface argument and the keys currently logically down to the keys
in the keys argument. The compositor must not send this event if the
wl_keyboard already had an active surface immediately before this event.
Clients should not use the list of pressed keys to emulate key-press
events. The order of keys in the list is unspecified.
</description>
<arg name="serial" type="uint" summary="serial number of the enter event"/>
<arg name="surface" type="object" interface="wl_surface" summary="surface gaining keyboard focus"/>
@@ -2505,9 +2515,18 @@
<enum name="key_state">
<description summary="physical key state">
Describes the physical state of a key that produced the key event.
Since version 10, the key can be in a "repeated" pseudo-state which
means the same as "pressed", but is used to signal repetition in the
key event.
The key may only enter the repeated state after entering the pressed
state and before entering the released state. This event may be
generated multiple times while the key is down.
</description>
<entry name="released" value="0" summary="key is not pressed"/>
<entry name="pressed" value="1" summary="key is pressed"/>
<entry name="repeated" value="2" summary="key was repeated" since="10"/>
</enum>
<event name="key">
@@ -2530,6 +2549,11 @@
compositor must not send this event if state is pressed (resp. released)
and the key was already logically down (resp. was not logically down)
immediately before this event.
Since version 10, compositors may send key events with the "repeated"
key state when a wl_keyboard.repeat_info event with a rate argument of
0 has been received. This allows the compositor to take over the
responsibility of key repetition.
</description>
<arg name="serial" type="uint" summary="serial number of the key event"/>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
@@ -2590,7 +2614,7 @@
</event>
</interface>
<interface name="wl_touch" version="9">
<interface name="wl_touch" version="10">
<description summary="touchscreen input device">
The wl_touch interface represents a touchscreen
associated with a seat.
@@ -3245,4 +3269,31 @@
</request>
</interface>
<interface name="wl_fixes" version="1">
<description summary="wayland protocol fixes">
This global fixes problems with other core-protocol interfaces that
cannot be fixed in these interfaces themselves.
</description>
<request name="destroy" type="destructor">
<description summary="destroys this object"/>
</request>
<request name="destroy_registry">
<description summary="destroy a wl_registry">
This request destroys a wl_registry object.
The client should no longer use the wl_registry after making this
request.
The compositor will emit a wl_display.delete_id event with the object ID
of the registry and will no longer emit any events on the registry. The
client should re-use the object ID once it receives the
wl_display.delete_id event.
</description>
<arg name="registry" type="object" interface="wl_registry"
summary="the registry to destroy"/>
</request>
</interface>
</protocol>

View File

@@ -29,7 +29,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
<interface name="xdg_wm_base" version="6">
<interface name="xdg_wm_base" version="7">
<description summary="create desktop-style surfaces">
The xdg_wm_base interface is exposed as a global object enabling clients
to turn their wl_surfaces into windows in a desktop environment. It
@@ -122,7 +122,7 @@
</event>
</interface>
<interface name="xdg_positioner" version="6">
<interface name="xdg_positioner" version="7">
<description summary="child surface positioner">
The xdg_positioner provides a collection of rules for the placement of a
child surface relative to a parent surface. Rules can be defined to ensure
@@ -407,7 +407,7 @@
</request>
</interface>
<interface name="xdg_surface" version="6">
<interface name="xdg_surface" version="7">
<description summary="desktop user interface surface base interface">
An interface that may be implemented by a wl_surface, for
implementations that provide a desktop-style user interface.
@@ -617,7 +617,7 @@
</interface>
<interface name="xdg_toplevel" version="6">
<interface name="xdg_toplevel" version="7">
<description summary="toplevel surface">
This interface defines an xdg_surface role which allows a surface to,
among other things, set window-like properties such as maximize,
@@ -911,6 +911,38 @@
outputs are switched off due to screen locking.
</description>
</entry>
<entry name="constrained_left" value="10" since="7">
<description summary="the surfaces left edge is constrained">
The left edge of the window is currently constrained, meaning it
shouldn't attempt to resize from that edge. It can for example mean
it's tiled next to a monitor edge on the constrained side of the
window.
</description>
</entry>
<entry name="constrained_right" value="11" since="7">
<description summary="the surfaces right edge is constrained">
The right edge of the window is currently constrained, meaning it
shouldn't attempt to resize from that edge. It can for example mean
it's tiled next to a monitor edge on the constrained side of the
window.
</description>
</entry>
<entry name="constrained_top" value="12" since="7">
<description summary="the surfaces top edge is constrained">
The top edge of the window is currently constrained, meaning it
shouldn't attempt to resize from that edge. It can for example mean
it's tiled next to a monitor edge on the constrained side of the
window.
</description>
</entry>
<entry name="constrained_bottom" value="13" since="7">
<description summary="the surfaces bottom edge is tiled">
The bottom edge of the window is currently constrained, meaning it
shouldn't attempt to resize from that edge. It can for example mean
it's tiled next to a monitor edge on the constrained side of the
window.
</description>
</entry>
</enum>
<request name="set_max_size">
@@ -1207,7 +1239,7 @@
</event>
</interface>
<interface name="xdg_popup" version="6">
<interface name="xdg_popup" version="7">
<description summary="short-lived, popup surfaces for menus">
A popup surface is a short-lived, temporary surface. It can be used to
implement for example menus, popovers, tooltips and other similar user

View File

@@ -0,0 +1,80 @@
// =====================================================================================================================
// 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 libdecor.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_H
#include <fennec/platform/linux/wayland/lib/wayland.h>
#include <libdecor.h>
#define FENNEC_LIB(name) extern "C" bool FENNEC_HAS_LIB_##name;
#define FENNEC_SYMBOL(ret, fn, ...) using LIBDECOR_sym_##fn = ret(*)(__VA_ARGS__); \
extern "C" LIBDECOR_sym_##fn LIBDECOR_##fn;
#define FENNEC_GLOBAL(type, name) extern "C" type* LIBDECOR_##name;
#include <fennec/platform/linux/wayland/libdecor/sym.h>
#define libdecor_unref LIBDECOR_libdecor_unref
#define libdecor_new LIBDECOR_libdecor_new
#define libdecor_decorate LIBDECOR_libdecor_decorate
#define libdecor_frame_unref LIBDECOR_libdecor_frame_unref
#define libdecor_frame_set_title LIBDECOR_libdecor_frame_set_title
#define libdecor_frame_set_app_id LIBDECOR_libdecor_frame_set_app_id
#define libdecor_frame_set_max_content_size LIBDECOR_libdecor_frame_set_max_content_size
#define libdecor_frame_get_max_content_size LIBDECOR_libdecor_frame_get_max_content_size
#define libdecor_frame_set_min_content_size LIBDECOR_libdecor_frame_set_min_content_size
#define libdecor_frame_get_min_content_size LIBDECOR_libdecor_frame_get_min_content_size
#define libdecor_frame_resize LIBDECOR_libdecor_frame_resize
#define libdecor_frame_move LIBDECOR_libdecor_frame_move
#define libdecor_frame_commit LIBDECOR_libdecor_frame_commit
#define libdecor_frame_set_minimized LIBDECOR_libdecor_frame_set_minimized
#define libdecor_frame_set_maximized LIBDECOR_libdecor_frame_set_maximized
#define libdecor_frame_unset_maximized LIBDECOR_libdecor_frame_unset_maximized
#define libdecor_frame_set_fullscreen LIBDECOR_libdecor_frame_set_fullscreen
#define libdecor_frame_unset_fullscreen LIBDECOR_libdecor_frame_unset_fullscreen
#define libdecor_frame_set_capabilities LIBDECOR_libdecor_frame_set_capabilities
#define libdecor_frame_unset_capabilities LIBDECOR_libdecor_frame_unset_capabilities
#define libdecor_frame_has_capability LIBDECOR_libdecor_frame_has_capability
#define libdecor_frame_set_visibility LIBDECOR_libdecor_frame_set_visibility
#define libdecor_frame_is_visible LIBDECOR_libdecor_frame_is_visible
#define libdecor_frame_is_floating LIBDECOR_libdecor_frame_is_floating
#define libdecor_frame_set_parent LIBDECOR_libdecor_frame_set_parent
#define libdecor_frame_show_window_menu LIBDECOR_libdecor_frame_show_window_menu
#define libdecor_frame_get_xdg_surface LIBDECOR_libdecor_frame_get_xdg_surface
#define libdecor_frame_get_xdg_toplevel LIBDECOR_libdecor_frame_get_xdg_toplevel
#define libdecor_frame_translate_coordinate LIBDECOR_libdecor_frame_translate_coordinate
#define libdecor_frame_map LIBDECOR_libdecor_frame_map
#define libdecor_state_new LIBDECOR_libdecor_state_new
#define libdecor_state_free LIBDECOR_libdecor_state_free
#define libdecor_configuration_get_content_size LIBDECOR_libdecor_configuration_get_content_size
#define libdecor_configuration_get_window_state LIBDECOR_libdecor_configuration_get_window_state
#define libdecor_dispatch LIBDECOR_libdecor_dispatch
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_H

View File

@@ -16,23 +16,35 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_TEST_LANG_SEQUENCES_H
#define FENNEC_TEST_LANG_SEQUENCES_H
///
/// \file loader.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#include <fennec/lang/const_sequences.h>
namespace fennec::test
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_LOADER_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_LOADER_H
#include <fennec/platform/interface/platform.h>
namespace fennec
{
inline void test_sequences()
{
static_assert(fennec::is_same_v<make_index_sequence_t<2>, const_index_sequence<0, 1>>);
static_assert(fennec::is_same_v<make_index_sequence_t<3>, const_index_sequence<0, 1, 2>>);
static_assert(fennec::is_same_v<make_index_sequence_t<4>, const_index_sequence<0, 1, 2, 3>>);
namespace libdecor
{
// TODO
}
bool load_symbols(platform* platform);
void unload_symbols(platform* platform);
}
#endif // FENNEC_TEST_LANG_SEQUENCES_H
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_LOADER_H

View File

@@ -0,0 +1,88 @@
// =====================================================================================================================
// 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/>.
// =====================================================================================================================
#include <fennec/lang/types.h>
#ifndef FENNEC_LIB
#define FENNEC_LIB(...)
#endif
#ifndef FENNEC_SYMBOL
#define FENNEC_SYMBOL(...)
#endif
#ifndef FENNEC_GLOBAL
#define FENNEC_GLOBAL(...)
#endif
FENNEC_LIB(LIBDECOR)
FENNEC_SYMBOL(void, libdecor_unref, struct libdecor*)
FENNEC_SYMBOL(int, libdecor_dispatch, struct libdecor*, int)
FENNEC_SYMBOL(struct libdecor*, libdecor_new, struct wl_display*, \
struct libdecor_interface*)
FENNEC_SYMBOL(struct libdecor_frame*, libdecor_decorate, struct libdecor*, \
struct wl_surface*, \
struct libdecor_frame_interface*, void*)
FENNEC_SYMBOL(void, libdecor_frame_unref, struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_set_title, struct libdecor_frame*, const char*)
FENNEC_SYMBOL(void, libdecor_frame_set_app_id, struct libdecor_frame*, const char*)
FENNEC_SYMBOL(void, libdecor_frame_set_max_content_size, struct libdecor_frame*, int, int)
FENNEC_SYMBOL(void, libdecor_frame_set_min_content_size, struct libdecor_frame*, int, int)
FENNEC_SYMBOL(void, libdecor_frame_get_min_content_size, const struct libdecor_frame*, int*, int*)
FENNEC_SYMBOL(void, libdecor_frame_get_max_content_size, const struct libdecor_frame*, int*, int*)
FENNEC_SYMBOL(void, libdecor_frame_resize, struct libdecor_frame*, struct wl_seat*, uint32_t, \
enum libdecor_resize_edge)
FENNEC_SYMBOL(void, libdecor_frame_move, struct libdecor_frame*, struct wl_seat*, uint32_t)
FENNEC_SYMBOL(void, libdecor_frame_commit, struct libdecor_frame*, struct libdecor_state*,\
struct libdecor_configuration*)
FENNEC_SYMBOL(void, libdecor_frame_set_minimized, struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_set_maximized, struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_unset_maximized, struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_set_fullscreen, struct libdecor_frame*, struct wl_output*)
FENNEC_SYMBOL(void, libdecor_frame_unset_fullscreen, struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_set_capabilities, struct libdecor_frame*, enum libdecor_capabilities)
FENNEC_SYMBOL(void, libdecor_frame_unset_capabilities, struct libdecor_frame*, enum libdecor_capabilities)
FENNEC_SYMBOL(bool, libdecor_frame_has_capability, struct libdecor_frame*, enum libdecor_capabilities)
FENNEC_SYMBOL(void, libdecor_frame_set_visibility, struct libdecor_frame*, bool)
FENNEC_SYMBOL(bool, libdecor_frame_is_visible, struct libdecor_frame*)
FENNEC_SYMBOL(bool, libdecor_frame_is_floating, struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_set_parent, struct libdecor_frame*,\
struct libdecor_frame*)
FENNEC_SYMBOL(void, libdecor_frame_show_window_menu, struct libdecor_frame*, struct wl_seat*, uint32_t, int, int)
FENNEC_SYMBOL(void, libdecor_frame_translate_coordinate, struct libdecor_frame*, int, int, int*, int*)
FENNEC_SYMBOL(void, libdecor_frame_map, struct libdecor_frame*)
FENNEC_SYMBOL(struct xdg_surface*, libdecor_frame_get_xdg_surface, struct libdecor_frame*)
FENNEC_SYMBOL(struct xdg_toplevel*, libdecor_frame_get_xdg_toplevel, struct libdecor_frame*)
FENNEC_SYMBOL(struct libdecor_state*, libdecor_state_new, int, int)
FENNEC_SYMBOL(void, libdecor_state_free, struct libdecor_state*)
FENNEC_SYMBOL(bool, libdecor_configuration_get_content_size, struct libdecor_configuration*,\
struct libdecor_frame*,\
int*,\
int*)
FENNEC_SYMBOL(bool, libdecor_configuration_get_window_state, struct libdecor_configuration*,\
enum libdecor_window_state*)
#undef FENNEC_LIB
#undef FENNEC_SYMBOL
#undef FENNEC_GLOBAL

View File

@@ -0,0 +1,110 @@
// =====================================================================================================================
// 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 wayland_server.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_SERVER_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_SERVER_H
#include <fennec/platform/linux/wayland/fwd.h>
#include <fennec/platform/interface/display_server.h>
#if FENNEC_HAS_LIBDECOR
#include <fennec/platform/linux/wayland/libdecor/libdecor.h>
#endif
// forward defs to avoid flooding global namespace
struct wl_display;
struct wl_shm;
struct wl_compositor;
struct wl_registry;
struct wl_seat;
struct wp_viewporter;
struct xdg_wm_base;
namespace fennec
{
///
/// \brief Class for handling the Wayland Display Server
class wayland_server : public display_server_base<wayland_server, wayland_window> {
public:
explicit wayland_server(fennec::platform* p);
~wayland_server() override;
void connect() override;
void disconnect() override;
bool connected() const override;
void dispatch() override;
window* create_window(const window::config& conf) override;
void* get_native_handle() override { return display; }
// Fields ==============================================================================================================
private:
wl_display* display;
wl_registry* registry;
wl_compositor* compositor;
xdg_wm_base* xdg;
wl_seat* seat;
bool fifo, has_libdecor;
#if FENNEC_HAS_LIBDECOR
libdecor* libdecor;
#endif
// Listeners ===========================================================================================================
static void _wl_registry_listen_global(void*, wl_registry*, uint32_t, const char*, uint32_t);
static void _wl_registry_on_global_remove(void*, wl_registry*, uint32_t);
static void _wl_seat_listen_capabilities(void*, wl_seat*, uint32_t);
static void _wl_seat_listen_name(void*, wl_seat*, const char*);
static void _xdg_listen_ping(void*, xdg_wm_base*, uint32_t);
#if FENNEC_HAS_LIBDECOR
static void _libdecor_on_error(struct libdecor*, libdecor_error error, const char* message);
#endif
FENNEC_RTTI_CLASS_ENABLE(display_server) {
display_server::register_type<wayland_server>(1);
}
friend class wayland_window;
};
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_SERVER_H

View File

@@ -17,7 +17,7 @@
// =====================================================================================================================
///
/// \file window.h
/// \file wayland_window.h
/// \brief
///
///
@@ -31,51 +31,76 @@
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
#include <fennec/platform/linux/wayland/fwd.h>
#include <fennec/platform/interface/window.h>
#include <fennec/platform/linux/wayland/display.h>
struct wl_array;
struct wl_callback;
struct wl_output;
struct wl_surface;
struct xdg_surface;
struct xdg_toplevel;
struct libdecor_frame;
struct libdecor_configuration;
namespace fennec
{
class wayland_window : public window {
class wayland_window : public window_base<wayland_server> {
public:
bool running() override;
wayland_window(display_server* server, uint32_t id, const config& cfg);
~wayland_window();
void configure(const config& config) override;
void initialize() override;
void shutdown() override;
bool initialize(bool modal) override;
void* get_native_handle() override;
bool shutdown() override;
bool set_flag(uint8_t flag, bool val) override;
bool set_title(const cstring& title) override;
bool set_title(const string& title) override;
bool set_width(size_t w) override;
bool set_height(size_t h) override;
bool resize(size_t w, size_t h) override;
bool set_resizable(bool e) override;
bool set_fullscreen_mode(fullscreen_mode mode) override;
bool grab_keyboard(bool e) override;
bool grab_mouse(bool e) override;
bool block_screensaver(bool e) override;
wayland_window(wayland_display* display, wayland_window* parent);
~wayland_window() override;
struct wl_surface* get_native_handle() override {
return _handle;
}
// Fields ==============================================================================================================
private:
wl_surface* _handle;
wl_shell_surface* _shell;
size_t _nfs_width, _nfs_height;
wl_surface* surface;
xdg_surface* xdgsurface;
xdg_toplevel* xdgtoplevel;
wl_callback* frame_callback;
static void listen_ping(void*, wl_shell_surface*, uint32_t);
static void listen_configure(void*, wl_shell_surface*, uint32_t, int32_t, int32_t);
static void listen_popup_done(void*, wl_shell_surface*);
#if FENNEC_HAS_LIBDECOR
libdecor_frame* libdecorframe;
libdecor_configuration* libdecorcfg;
#endif
// Helpers =============================================================================================================
void _update_size(const ivec2& size);
// Listeners ===========================================================================================================
static void _wl_surface_listen_enter(void*, wl_surface*, wl_output*);
static void _wl_surface_listen_leave(void*, wl_surface*, wl_output*);
static void _wl_surface_listen_preferred_buffer_scale(void*, wl_surface*, int32_t);
static void _wl_surface_listen_preferred_buffer_transform(void*, wl_surface*, uint32_t);
static void _wl_frame_listen_done(void*, wl_callback*, uint32_t);
static void _xdg_surface_listen_configure(void*, xdg_surface*, uint32_t);
static void _xdg_toplevel_listen_configure(void*, xdg_toplevel*, int32_t, int32_t, wl_array*);
static void _xdg_toplevel_listen_configure_bounds(void*, xdg_toplevel*, int32_t, int32_t);
static void _xdg_toplevel_listen_close(void*, xdg_toplevel*);
static void _xdg_toplevel_listen_wm_capabilities(void*, xdg_toplevel*, wl_array*);
#if FENNEC_HAS_LIBDECOR
static void _libdecor_frame_listen_configure(libdecor_frame*, libdecor_configuration*, void*);
static void _libdecor_frame_listen_close(libdecor_frame*, void*);
static void _libdecor_frame_listen_commit(libdecor_frame*, void*);
static void _libdecor_frame_listen_dismiss_popup(libdecor_frame*, const char*, void*);
#endif
};
}

View File

@@ -16,34 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
/*
* Copyright © 2009-2012 Daniel Stone
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#include <stdio.h>
#include <fennec/lang/types.h>
#ifndef FENNEC_LIB
#define FENNEC_LIB(...)

View File

@@ -16,44 +16,37 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_PLATFORM_OPENGL_EGL_CONTEXT_H
#define FENNEC_PLATFORM_OPENGL_EGL_CONTEXT_H
///
/// \file context.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_OPENGL_EGLCONTEXT_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_OPENGL_EGLCONTEXT_H
#include <EGL/egl.h>
#include <fennec/platform/interface/gfxcontext.h>
#include <fennec/platform/opengl/egl/fwd.h>
#include <fennec/platform/opengl/egl/error.h>
#include <fennec/platform/linux/wayland/server.h>
#include <fennec/renderers/opengl/glcontext.h>
namespace fennec
{
class eglcontext : public gfxcontext {
class eglcontext : public glcontext {
public:
eglcontext(display* display);
eglcontext(display_server* display);
~eglcontext();
~eglcontext() override;
bool connected() override;
int32_t get_version_major() override { return _eglvmajor; }
int32_t get_version_minor() override { return _eglvminor; }
int32_t get_version() override { return _eglctype; }
const cstring& get_name() override;
bool check_extension(const cstring& ext) override;
gfxsurface* create_surface(window* window) override;
void make_current(gfxsurface* surface) override;
EGLDisplay get_egl_display() {
return _egldisplay;
}
EGLDisplay get_egl_context() {
return _eglcontext;
}
EGLDisplay get_egl_config() {
return _eglconfig;
}
bool is_valid() override;
private:
EGLDisplay _egldisplay;
@@ -62,9 +55,12 @@ private:
EGLint _eglvmajor, _eglvminor, _eglctype;
cstring _extensions;
void cleanup();
FENNEC_RTTI_CLASS_ENABLE(glcontext) {
}
friend class eglsurface;
};
}
#endif // FENNEC_PLATFORM_OPENGL_EGL_CONTEXT_H
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_OPENGL_EGLCONTEXT_H

View 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/>.
// =====================================================================================================================
///
/// \file error.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_OPENGL_EGL_ERROR_H
#define FENNEC_PLATFORM_OPENGL_EGL_ERROR_H
#include <EGL/egl.h>
#include <fennec/string/cstring.h>
inline fennec::cstring eglErrorString(EGLint err) {
switch (err) {
case EGL_SUCCESS: return "None";
case EGL_NOT_INITIALIZED: return "Not Initialized";
case EGL_BAD_ACCESS: return "Bad Access";
case EGL_BAD_ALLOC: return "Bad Alloc";
case EGL_BAD_ATTRIBUTE: return "Bad Attribute";
case EGL_BAD_CONTEXT: return "Bad Context";
case EGL_BAD_CONFIG: return "Bad Config";
case EGL_BAD_CURRENT_SURFACE: return "Bad Current Surface";
case EGL_BAD_DISPLAY: return "Bad Display";
case EGL_BAD_SURFACE: return "Bad Surface";
case EGL_BAD_MATCH: return "Bad Match";
case EGL_BAD_PARAMETER: return "Bad Parameter";
case EGL_BAD_NATIVE_PIXMAP: return "Bad Native Pixmap";
case EGL_BAD_NATIVE_WINDOW: return "Bad Native Window";
case EGL_CONTEXT_LOST: return "Context Lost";
default: return "Unknown Error";
}
}
#endif // FENNEC_PLATFORM_OPENGL_EGL_ERROR_H

Some files were not shown because too many files have changed in this diff Show More