diff --git a/.gitmodules b/.gitmodules index cd4e797..0a15db9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "external/sdl"] - path = external/sdl - url = https://github.com/libsdl-org/SDL.git [submodule "external/cpptrace"] path = external/cpptrace url = https://github.com/jeremy-rifkin/cpptrace.git diff --git a/CMakeLists.txt b/CMakeLists.txt index c8d62c2..44d2ea1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,34 +1,51 @@ +# ====================================================================================================================== +# 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 . +# ====================================================================================================================== + cmake_minimum_required(VERSION 3.30) project(fennec) # External dependencies should be loaded here -# SDL is a dependency of the project, added as a git submodule -add_subdirectory(external/sdl) - # CppTrace is a dependency of the project, added as a git submodule add_subdirectory(external/cpptrace) set(CMAKE_CXX_STANDARD 23) set(CMAKE_C_STANDARD 23) +set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +# include scripts +include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake") +include("${FENNEC_SOURCE_DIR}/cmake/build.cmake") # find dependencies find_package(Doxygen) +fennec_check_platform() # any necessary include directories -include_directories(${PROJECT_SOURCE_DIR}/include) +include_directories(${FENNEC_SOURCE_DIR}/include) # Metaprogramming is a dependency for generating various type info before compilation of the engine. add_subdirectory(metaprogramming) -string(TOLOWER ${CMAKE_BUILD_TYPE} FENNEC_BUILD_NAME) -message(STATUS "OS: ${CMAKE_SYSTEM_NAME}") -message(STATUS "Build: ${FENNEC_BUILD_NAME}") - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}) # add the test suite as a sub-project add_subdirectory(test) @@ -42,6 +59,10 @@ add_library(fennec STATIC # CONTAINERS =========================================================================================================== include/fennec/containers/array.h include/fennec/containers/dynarray.h + include/fennec/containers/map.h + include/fennec/containers/optional.h + include/fennec/containers/pair.h + include/fennec/containers/set.h # LANG ================================================================================================================= @@ -51,15 +72,17 @@ add_library(fennec STATIC include/fennec/lang/bits.h include/fennec/lang/constants.h include/fennec/lang/conditional_types.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/sequences.h + include/fennec/lang/type_identity.h + include/fennec/lang/type_sequences.h include/fennec/lang/type_traits.h include/fennec/lang/type_transforms.h include/fennec/lang/types.h include/fennec/lang/utility.h - include/fennec/lang/type_sequences.h include/fennec/lang/integer.h include/fennec/lang/detail/__bits.h @@ -67,6 +90,7 @@ add_library(fennec STATIC 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/assert.h source/lang/assert.cpp @@ -75,8 +99,9 @@ add_library(fennec STATIC # MEMORY =============================================================================================================== include/fennec/memory/new.h source/memory/new.cpp - include/fennec/memory/common.h include/fennec/memory/allocator.h + include/fennec/memory/bytes.h + include/fennec/memory/common.h include/fennec/memory/memory.h include/fennec/memory/pointers.h include/fennec/memory/ptr_traits.h @@ -110,10 +135,12 @@ add_library(fennec STATIC include/fennec/math/ext/common.h include/fennec/math/ext/constants.h + 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 include/fennec/math/detail/__math.h include/fennec/math/detail/__matrix.h @@ -132,32 +159,34 @@ add_library(fennec STATIC # Filesystem include/fennec/fproc/filesystem/file.h source/fproc/filesystem/file.cpp include/fennec/fproc/filesystem/path.h source/fproc/filesystem/path.cpp + +# PLATFORM ============================================================================================================= + include/fennec/platform/interface/fwd.h + + include/fennec/platform/interface/dialog.h + include/fennec/platform/interface/display.h + include/fennec/platform/interface/window.h source/platform/interface/window.cpp + include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp + + + ${FENNEC_EXTRA_SOURCES} ) -# add metaprogramming templates as a dependency and also force documentation to be generated when fennec is compiled -if(DOXYGEN_FOUND) - add_dependencies(fennec fennecdocs metaprogramming) # SDL3-shared cpptrace::cpptrace) -else() - add_dependencies(fennec metaprogramming) # SDL3-shared cpptrace::cpptrace) -endif() +add_dependencies(fennec metaprogramming) -# Compiler Warning Flags -if(MSVC) - add_compile_options("/W4" "/WX") # All MSVC Warnings throw as Errors -else() - add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror") # All gcc/etc. Warnings throw as errors - - target_compile_definitions(fennec PRIVATE _GLIBCXX_INCLUDE_NEXT_C_HEADERS __USE_FILE_OFFSET64) -endif() - -target_compile_options(fennec PUBLIC "-mavx" "-mavx2" "-mavx512f") # SIMD Instructions, automatic vectorization will occur +target_compile_definitions(fennec PUBLIC + ${FENNEC_COMPILE_DEFINITIONS} +) -target_link_options(fennec PRIVATE "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates") # Do not compile base fennec library with c++ stdlib +target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not compile base fennec library with c++ stdlib # fennec does not use the C++ stdlib because it is bloated, difficult to read, and implementation defined. # This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated -target_link_libraries(fennec PRIVATE SDL3-shared cpptrace::cpptrace) +target_link_libraries(fennec PRIVATE + cpptrace::cpptrace + ${FENNEC_LINK_LIBRARIES} +) @@ -167,10 +196,11 @@ target_link_libraries(fennec PRIVATE SDL3-shared cpptrace::cpptrace) file(COPY logo DESTINATION docs/logo) if(DOXYGEN_FOUND) - set(DOXY_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/docs") - get_filename_component(DOXYGEN_PROJECT_NAME ${PROJECT_SOURCE_DIR} NAME) # Set Doxy Project name to the name of the root dir - set(DOXYGEN_CONFIG_IN "${PROJECT_SOURCE_DIR}/doxy/Doxyfile.in") # Input config file with preprocessor arguments - set(DOXYGEN_CONFIG_OUT "${PROJECT_SOURCE_DIR}/doxy/Doxyfile") # Generated config file from input + add_dependencies(fennec fennecdocs) + set(DOXY_OUTPUT_DIR "${FENNEC_SOURCE_DIR}/docs") + get_filename_component(DOXYGEN_PROJECT_NAME ${FENNEC_SOURCE_DIR} NAME) # Set Doxy Project name to the name of the root dir + set(DOXYGEN_CONFIG_IN "${FENNEC_SOURCE_DIR}/doxy/Doxyfile.in") # Input config file with preprocessor arguments + set(DOXYGEN_CONFIG_OUT "${FENNEC_SOURCE_DIR}/doxy/Doxyfile") # Generated config file from input configure_file(${DOXYGEN_CONFIG_IN} ${DOXYGEN_CONFIG_OUT} @ONLY) # Execute preprocessing step message("Doxygen Build Started.") @@ -179,8 +209,8 @@ if(DOXYGEN_FOUND) # Target for building docs add_custom_target(fennecdocs ALL COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/logo/raster.png + WORKING_DIRECTORY ${FENNEC_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${FENNEC_SOURCE_DIR}/logo/raster.png ${DOXY_OUTPUT_DIR}/logo/raster.png COMMENT "Generating Doxygen Documentation" VERBATIM) @@ -189,7 +219,7 @@ if(DOXYGEN_FOUND) # Target for cleaning docs add_custom_target(fennecdocs-clean ALL - COMMAND ${CMAKE_COMMAND} -E remove -f "${PROJECT_SOURCE_DIR}/docs" + COMMAND ${CMAKE_COMMAND} -E remove -f "${FENNEC_SOURCE_DIR}/docs" COMMENT "Cleaning Doxygen Documentation" VERBATIM) else() diff --git a/PLANNING.md b/PLANNING.md index d5a6ea9..964020a 100644 --- a/PLANNING.md +++ b/PLANNING.md @@ -7,6 +7,7 @@ 1. [Introduction](#introduction) 2. [TODO](#todo) 1. [Security Ramblings](#file-security-ramblings) + 2. [Platform Support](#platform--api-support) 3. [C++ Language](#c-language-library-lang) 4. [Math Library](#math-library-math) 5. [Memory Library](#memory-library-memory) @@ -15,7 +16,7 @@ 8. [Core](#core-core) 1. [Tick](#tick) 2. [Frame](#frame) - 9. [Application Layer](#application-layer-app) + 9. [Platform Support Layer](#platform-support-layer-platform) 10. [Scene](#scene-scene) 11. [2D Graphics](#2d-graphics-gfx2d) 12. [3D Graphics](#3d-graphics-gfx3d) @@ -152,6 +153,38 @@ Directories remain an issue, with `dirent.h` being the only sensible option at t for MSVC. +### Platform & API Support + +I have decided to forgo SDL, this is so the engine can provide specific support for specific platforms. +Also, SDL implements a lot of things that will need to be implemented specifically for the engine, so only the window +management would be used. + +Platform support will be implemented in the following order: + - Linux/BSD + - Wayland + - XKB + - OpenGL (EGL) + - PulseAudio + - Vulkan + - X11 + - OpenGL (EGL) + - ALSA + - Vulkan + - Microsoft Windows + - XInput + - OpenGL + - DirectSound + - Vulkan + - Android + - OpenGL ES + - macOS + - iOS + +Most consoles will never get official platform support due to NDAs which conflict with the principles of this engine. +fennec will avoid using proprietary libraries except when strictly necessary, such as support for Windows and MacOS. +fennec will interact with any drivers required for the listed operating systems above, even if proprietary. + + ## C++ Language Library (`lang`) Implement header files for standard functions relating to the C++ Language. @@ -320,14 +353,12 @@ in their operation order: -## Application Layer (`app`) - -This is the core windowing system of fennec. The implementation will initially be an SDL3 wrapper. -Custom implementation may be further down the roadmap, however this is extremely complicated and there are better -implementations than I could write alone. - +## Platform Support Layer (`platform`) +This is the core part of platform support for fennec. All necessary drivers +and OS specific functionality will be wrapped up nicely into these interfaces. +See implementation order [here](#platform--api-support) ## Scene (`scene`) diff --git a/README.md b/README.md index 889cd29..5f52448 100644 --- a/README.md +++ b/README.md @@ -142,9 +142,9 @@ for more info. build scripts to use another build manager, see the [CMake documentation for available generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html). -  I will at no point provide official cross-compilation toolchains for fennec, if you wish to compile your project for -both Windows and Linux, working on Windows with WSL is likely your best option besides dual-booting. For Android and -iOS, using the GCC and Clang cross-compilation toolchains, respectively, will suffice. +  I will at no point provide official cross-compilation toolchains for fennec. However, I will provide tools for +using specific toolchains for specific platforms that necessitate this. The primary examples would be Android and iOS. +If you wish to build for Windows *and* Linux, your options are WSL or Dual Boot. I recommend Dual Boot over WSL.
@@ -223,14 +223,17 @@ licensing that mesh under another license. Any code that is linked against fennec or uses any part is by definition a covered work must be licensed under GPLv3. +  Later down the line, I plan on implementing scripts in a manner that allows the script itself to remain proprietary. +The scripts will likely be trans-compiled to another language before being compiled to binary, but this is only an +intermediate step and will be erased when no longer needed. +   As long as you use the official editor, it will properly include licenses in project content when provided a license and the name of the license holder. Archive packs will include the license holders non-GPLv3 license in them and any linked code will be covered by GPLv3 under the name of the license holder. Be aware that the parts of your project licensed under GPLv3 must be available upon request.   A release project will consist of an executable, a shared library for your code, an archive pak, and streamable assets. -The executable and shared library are protected under the GPLv3 license, while the archive pak and streamable assets are -protected under your license. +The executable and shared library are under the GPLv3 license, while the archive pak and streamable assets are under your license. It is to my discretion whether I enforce the terms of the license on a party. diff --git a/cmake/build.cmake b/cmake/build.cmake new file mode 100644 index 0000000..020a9eb --- /dev/null +++ b/cmake/build.cmake @@ -0,0 +1,26 @@ +# ====================================================================================================================== +# 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 . +# ====================================================================================================================== + +string(TOLOWER ${CMAKE_BUILD_TYPE} FENNEC_BUILD_NAME) +message(STATUS "Build: ${FENNEC_BUILD_NAME}") + +if(${FENNEC_BUILD_NAME} MATCHES "debug") + list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=false) +else() + list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=true) +endif() \ No newline at end of file diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake new file mode 100644 index 0000000..df4c55a --- /dev/null +++ b/cmake/compiler.cmake @@ -0,0 +1,24 @@ +# ====================================================================================================================== +# fennec, a free and open source game engine +# Copyright © 2025 Medusa Slockbower +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# ====================================================================================================================== + +list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_COMPILER_GCC=0) + +if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") +set(FENNEC_COMPILER "GCC") +include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake") +endif() \ No newline at end of file diff --git a/cmake/gcc.cmake b/cmake/gcc.cmake new file mode 100644 index 0000000..e916f64 --- /dev/null +++ b/cmake/gcc.cmake @@ -0,0 +1,23 @@ +# ====================================================================================================================== +# 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 . +# ====================================================================================================================== + +add_compile_options("-mxsave" "-Wall" "-Wextra" "-pedantic" "-Werror") + +set(FENNEC_PRIVATE_LINK_OPTIONS "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates") + +list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_COMPILER=FENNEC_COMPILER_GCC) \ No newline at end of file diff --git a/cmake/libwayland.cmake b/cmake/libwayland.cmake new file mode 100644 index 0000000..ca69324 --- /dev/null +++ b/cmake/libwayland.cmake @@ -0,0 +1,63 @@ +# ====================================================================================================================== +# fennec, a free and open source game engine +# Copyright © 2025 Medusa Slockbower +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# ====================================================================================================================== + +# https://gist.github.com/mariobadr/acc3c8adf4b4e722705be38c3deac59a + +macro(fennec_check_libwayland) + set(WAYLAND_CLIENT_FOUND 0) + + find_path( + WAYLAND_CLIENT_INCLUDE_DIR + NAMES wayland-client.h + ) + + find_library( + WAYLAND_CLIENT_LIBRARY + NAMES wayland-client libwayland-client + ) + get_filename_component( + WAYLAND_CLIENT_LIBRARY + ${WAYLAND_CLIENT_LIBRARY} + NAME + ) + + if(WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY) + set(WAYLAND_CLIENT_FOUND 1) + add_library(wayland::client UNKNOWN IMPORTED) + + set_target_properties( + wayland::client PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CLIENT_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${WAYLAND_CLIENT_LIBRARY}" + ) + + list(APPEND FENNEC_EXTRA_SOURCES + # Dynamic Library Files + include/fennec/platform/linux/wayland/lib/fwd.h + include/fennec/platform/linux/wayland/lib/sym.h + include/fennec/platform/linux/wayland/lib/sym_def.h + include/fennec/platform/linux/wayland/lib/dyn.h source/platform/linux/wayland/lib/dyn.cpp + + # Fennec Files + include/fennec/platform/linux/wayland/display.h source/platform/linux/wayland/display.cpp + ) + + list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}") + endif() +endmacro() \ No newline at end of file diff --git a/cmake/linux.cmake b/cmake/linux.cmake new file mode 100644 index 0000000..8d5fad0 --- /dev/null +++ b/cmake/linux.cmake @@ -0,0 +1,37 @@ +# ====================================================================================================================== +# 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 . +# ====================================================================================================================== + + +macro(fennec_check_platform) + # compile definitions + list(APPEND FENNEC_COMPILE_DEFINITIONS + FENNEC_PLATFORM_NAME="Linux" + FENNEC_PLATFORM_LINUX=1 + ) + + # extra source files + list(APPEND FENNEC_EXTRA_SOURCES + include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp + ) + + # includes + include("${FENNEC_SOURCE_DIR}/cmake/libwayland.cmake") + + # tests + fennec_check_libwayland() +endmacro() \ No newline at end of file diff --git a/cmake/platform.cmake b/cmake/platform.cmake new file mode 100644 index 0000000..a73f1a3 --- /dev/null +++ b/cmake/platform.cmake @@ -0,0 +1,25 @@ +# ====================================================================================================================== +# fennec, a free and open source game engine +# Copyright © 2025 Medusa Slockbower +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# ====================================================================================================================== + +message(STATUS "OS: ${CMAKE_SYSTEM_NAME}") + +# Check for Linux +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(FENNEC_PLATFORM "Linux") + include("${FENNEC_SOURCE_DIR}/cmake/linux.cmake") +endif () \ No newline at end of file diff --git a/external/sdl b/external/sdl deleted file mode 160000 index d7939ab..0000000 --- a/external/sdl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d7939abf42de34fff409f5e7c4b77ace79dff4de diff --git a/include/fennec/containers/dynarray.h b/include/fennec/containers/dynarray.h index 349e38e..b334a3b 100644 --- a/include/fennec/containers/dynarray.h +++ b/include/fennec/containers/dynarray.h @@ -38,7 +38,7 @@ namespace fennec { -template +template> class dynarray { public: @@ -129,7 +129,9 @@ public: void insert(size_t i, const TypeT& val) { // Grow if the size has reached the capacity of the allocation - if(_size == capacity()) _grow(); + if(_size == capacity()) { + _grow(); + } // Move the data if we are not inserting at the end of the array if((i = min(i, _size)) < _size) { @@ -141,30 +143,36 @@ public: // Insert the element fennec::construct(_alloc.data() + i, val); + ++_size; } void insert(size_t i, TypeT&& val) { // Grow if the size has reached the capacity of the allocation - if(_size == capacity()) _grow(); + if(_size == capacity()) { + _grow(); + } // Move the data if we are not inserting at the end of the array if((i = min(i, _size)) < _size) { fennec::memmove( - _alloc.data() + i - , _alloc.data() + i + 1 + _alloc.data() + i + 1 + , _alloc.data() + i , (_size - i) * sizeof(TypeT)); } // Insert the element fennec::construct(_alloc.data() + i, fennec::forward(val)); + ++_size; } template void emplace(size_t i, ArgsT&&...args) { // Grow if the size has reached the capacity of the allocation - if(_size == capacity()) _grow(); + if(_size == capacity()) { + _grow(); + } // Move the data if we are not inserting at the end of the array if((i = min(i, _size)) < _size) { @@ -176,6 +184,7 @@ public: // Insert the element fennec::construct(_alloc.data() + i, fennec::forward(args)...); + ++_size; } void push_back(const TypeT& val) { @@ -190,8 +199,14 @@ public: dynarray::emplace(_size, fennec::forward(args)...); } + void resize(size_t n) { + _alloc.reallocate(n); + } + private: - void _grow() const { _alloc.reallocate(_alloc.capacity() * 2); } + void _grow() { + _alloc.reallocate(_alloc.capacity() * 2); + } allocation _alloc; size_t _size; diff --git a/include/fennec/containers/map.h b/include/fennec/containers/map.h new file mode 100644 index 0000000..23ff305 --- /dev/null +++ b/include/fennec/containers/map.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_MAP_H +#define FENNEC_CONTAINERS_MAP_H + +#include +#include + +namespace fennec +{ + +// TODO: Document + +template, typename Alloc = allocator>> +struct map { +public: + using key_t = KeyT; + using value_t = ValueT; + using elem_t = pair; + using alloc_t = typename allocator_traits::template rebind; + using hash_t = Hash; + + map() = default; + ~map() = default; + + + +private: + set _set; +}; + +} + +#endif // FENNEC_CONTAINERS_MAP_H diff --git a/include/fennec/containers/optional.h b/include/fennec/containers/optional.h new file mode 100644 index 0000000..a56cde2 --- /dev/null +++ b/include/fennec/containers/optional.h @@ -0,0 +1,247 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_OPTIONAL_H +#define FENNEC_CONTAINERS_OPTIONAL_H + +#include +#include + +#include + +namespace fennec +{ + +struct nullopt_t {}; +constexpr nullopt_t nullopt_v = {}; + +#define nullopt nullopt_v + +/// +/// \brief Structure to hold an optional value. +/// \tparam T +template +struct optional { +public: +// Constructors ======================================================================================================== + + /// + /// \brief Default Constructor + constexpr optional() + : _root(0) + , _set(false) { + } + + /// + /// \brief Default Constructor + constexpr optional(nullopt_t) + : _root(0) + , _set(false) { + } + + /// + /// \brief Fundamental Type Constructor + /// \param val the value to initialize the underlying object with + constexpr optional(T val) requires is_fundamental_v + : _val(val) + , _set(true) { + } + + /// + /// \brief Type Copy Constructor + /// \param val the value to initialize the underlying object with + constexpr optional(const T& val) + : _val(val) + , _set(true) { + } + + /// + /// \brief Copy Constructor + /// \param opt the optional to copy + constexpr optional(const optional& opt) requires is_copy_assignable_v + : optional() { + _set = opt._set; + if (_set) { + _val = opt._val; + } + } + + /// + /// \brief Move Constructor + /// \param opt the optional to move + constexpr optional(optional&& opt) noexcept requires is_move_assignable_v + : optional() { + _set = opt._set; + if (_set) { + _val = fennec::move(opt._val); + } + opt = nullopt; + } + + constexpr ~optional() { + if constexpr(is_fundamental_v) { + return; + } + if (_set) { + _val.~T(); + } + } + + +// Assignment Operators ================================================================================================ + + /// + /// \brief Fundamental Type Assignment + /// \val The value to set with + constexpr optional& operator=(nullopt_t) { + if constexpr(not is_fundamental_v) { + if (_set) { + _val.~T(); + } + } + _root = '\0'; + _set = false; + return *this; + } + + /// + /// \brief Type Copy Assignment + /// \val The value to set with + constexpr optional& operator=(const T& val) requires is_copy_constructible_v and is_copy_assignable_v { + if (_set) { + _val = val; + } else { + fennec::construct(&_val, val); + _set = true; + } + return *this; + } + + /// + /// \brief Type Move Assignment + /// \val The value to set with + constexpr optional& operator=(T&& val) requires is_move_constructible_v and is_move_assignable_v { + if (_set) { + _val = fennec::move(val); + } else { + fennec::construct(&_val, fennec::move(val)); + _set = true; + } + return *this; + } + + /// + /// \brief Copy Assignment + /// \val The optional to copy + constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v and is_copy_assignable_v { + if (_set != opt._set) { + _set = opt._set; + if (_set) { // Construct + fennec::construct(&_val, opt._val); + } else { // Destruct + _val.~T(); + _root = 0; + } + } else if (_set) { // Copy Assignment + _val = opt._val; + } + return *this; + } + + /// + /// \brief Move Assignment + /// \val The optional to move + constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v and is_move_assignable_v { + if (_set != opt._set) { + _set = opt._set; + if (_set) { // Construct + fennec::construct(&_val, fennec::move(opt._val)); + } else { // Destruct + _val.~T(); + _root = 0; + } + } else if (_set) { // Copy Assignment + _val = fennec::move(opt._val); + } + return *this; + } + + template + constexpr T& emplace(ArgsT&&...args) { + if (_set) { + _val = T(fennec::forward(args)...); + } else { + fennec::construct(&_val, fennec::forward(args)...); + _set = true; + } + return _val; + } + + void reset() { + this->operator=(nullopt); + } + + +// Operators =========================================================================================================== + + constexpr operator bool() const { + return _set; + } + + constexpr T* operator->() noexcept { + return _set ? &_val : nullptr; + } + + constexpr const T* operator->() const noexcept { + return _set ? &_val : nullptr; + } + + constexpr T& operator*() & noexcept { + assertd(_set, "Attempted to reference the value of an unset optional"); + return _val; + } + + constexpr const T& operator*() const& noexcept { + assertd(_set, "Attempted to reference the value of an unset optional"); + return _val; + } + + constexpr T&& operator*() && noexcept { + assertd(_set, "Attempted to reference the value of an unset optional"); + return _val; + } + + constexpr const T&& operator*() const&& noexcept { + assertd(_set, "Attempted to reference the value of an unset optional"); + return _val; + } + + + + +private: + union { + char _root; + T _val; + }; + bool _set; +}; + +} + +#endif // FENNEC_CONTAINERS_OPTIONAL_H diff --git a/include/fennec/containers/pair.h b/include/fennec/containers/pair.h new file mode 100644 index 0000000..6a447a7 --- /dev/null +++ b/include/fennec/containers/pair.h @@ -0,0 +1,91 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_PAIR_H +#define FENNEC_CONTAINERS_PAIR_H + +#include +#include + +namespace fennec +{ + +// TODO: Document + +template +struct pair { + constexpr pair() = default; + constexpr ~pair() = default; + + constexpr pair(const T0& x, const T1& y) + : first(x) + , second(y) { + } + + constexpr pair(T0&& x, T1&& y) noexcept + : first(fennec::forward(x)) + , second(fennec::forward(y)) { + } + + constexpr pair(const pair&) = default; + constexpr pair(pair&&) noexcept = default; + + pair& operator=(const pair&) = default; + pair& operator=(pair&&) noexcept = default; + + bool operator==(const pair& p) const { + return first == p.first and second == p.second; + } + + bool operator!=(const pair& p) const { + return first != p.first or second != p.second; + } + + bool operator<(const pair& p) const { + return first < p.first or (first == p.first and second < p.second); + } + + bool operator<=(const pair& p) const { + return first < p.first or (first == p.first and second <= p.second); + } + + bool operator>(const pair& p) const { + return first > p.first or (first == p.first and second > p.second); + } + + bool operator>=(const pair& p) const { + return first > p.first or (first == p.first and second >= p.second); + } + + T0 first; + T1 second; +}; + +template +struct hash> : hash, hash { + constexpr size_t operator()(const pair& p) const { + return fennec::pair_hash( // pair the hashes of both elements + hash::operator()(p.first), + hash::operator()(p.second) + ); + } +}; + +} + +#endif // FENNEC_CONTAINERS_PAIR_H diff --git a/include/fennec/containers/set.h b/include/fennec/containers/set.h new file mode 100644 index 0000000..f1818c4 --- /dev/null +++ b/include/fennec/containers/set.h @@ -0,0 +1,297 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_SET_H +#define FENNEC_CONTAINERS_SET_H + +// https://programming.guide/robin-hood-hashing.html + +#include +#include +#include +#include + +namespace fennec +{ + +// TODO: Document + +template, class Alloc = allocator> +struct set { +public: + using alloc_t = typename allocator_traits::template rebind; + using hash_t = Hash; + using elem_t = T; + + class iterator; + static constexpr size_t npos = -1; + +private: + struct node { + optional value; + int psl; + + constexpr node() = default; + constexpr ~node() = default; + }; + +public: + constexpr set() + : _alloc() + , _hash() + , _size(0) { + }; + + constexpr set(const hash_t& hash) + : _alloc() + , _hash(hash) + , _size(0) { + } + + constexpr set(hash_t&& hash) noexcept + : _alloc() + , _hash(hash) + , _size(0) { + } + + constexpr set(const alloc_t& alloc) + : _alloc(alloc) + , _hash() + , _size(0) { + } + + constexpr set(alloc_t&& alloc) noexcept + : _alloc(alloc) + , _hash() + , _size(0) { + } + + constexpr set(const hash_t& hash, const alloc_t& alloc) + : _alloc(alloc) + , _hash(hash) + , _size(0) { + } + + constexpr set(const hash_t& hash, alloc_t&& alloc) noexcept + : _alloc(alloc) + , _hash(hash) + , _size(0) { + } + + constexpr set(hash_t&& hash, alloc_t&& alloc) noexcept + : _alloc(alloc) + , _hash(hash) + , _size(0) { + } + + constexpr set(hash_t&& hash, const alloc_t& alloc) noexcept + : _alloc(alloc) + , _hash(hash) + , _size(0) {} + + constexpr set(const set& set) + : _alloc(set._alloc) + , _hash(set._hash) + , _size(set._size) { + } + + constexpr set(set&& set) noexcept + : _alloc(fennec::move(set._alloc)) + , _hash(fennec::move(set._hash)) + , _size(fennec::move(set._size)) { + } + + constexpr ~set() = default; + + constexpr size_t size() const { + return _size; + } + + constexpr size_t capacity() const { + return _alloc.capacity(); + } + + constexpr void insert(elem_t&& val) { + if (_size >= capacity()) { // expand when full + _expand(); + } + + elem_t value = fennec::forward(val); + size_t i = _hash(value) % capacity(); // Initial search index + int psl = 0; + while (_alloc[i].value) { // Search for empty cell + if (*_alloc[i].value == val) { // Check to see if this element is already inserted + return; + } + if (psl >= _alloc[i].psl) { // When psl is higher, swap + fennec::swap(*_alloc[i].value, value); + fennec::swap(_alloc[i].psl, psl); + } + i = (i + 1) % capacity(); ++psl; + } + _alloc[i].value = fennec::move(value); + _alloc[i].psl = psl; + ++_size; + } + + constexpr void insert(const elem_t& val) { + elem_t value = val; // Copy Constructor invoked here + this->insert(fennec::move(value)); // Only invokes moves + } + + template + constexpr void emplace(ArgsT&&...args) { + elem_t value = elem_t(fennec::forward(args)...); // Constructor invoked here + this->insert(fennec::move(value)); // Only invokes moves + } + + constexpr iterator find(const elem_t& val) const { + size_t i = _hash(val) % capacity(); // Initial search index + int psl = 0; + + // Loop while there is a value and its psl is greater than our probe + while (_alloc[i].value && _alloc[i].psl > psl) { + if (*_alloc[i].value == val) { + return iterator(this, i); + } + i = (i + 1) % capacity(); ++psl; + } + + return iterator(this, npos); + } + + constexpr bool contains(const elem_t& val) const { + return this->find(val) != end(); + } + + 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; + --_size; + size_t p = i; + while (_alloc[i = (i + 1) % capacity()].value) { + size_t psl = _alloc[i].psl; + if (psl == 0) break; + + fennec::swap(_alloc[i - 1].value, _alloc[i].value); + _alloc[p].psl = psl - 1; + p = i; + } + } + + constexpr void erase(const elem_t& val) { + this->erase(this->find(val)); + } + + +// ITERATOR ============================================================================================================ + + class iterator { + public: + constexpr iterator(const set* set, size_t i) + : _set(set) + , _i(i) { + } + + constexpr ~iterator() { + _set = nullptr; + } + + // prefix operator + constexpr friend iterator& operator++(iterator& rhs) { + while (++rhs._i < capacity()) { + if (rhs._set->_alloc[rhs._i]) { + return rhs; + } + } + rhs._i = npos; + return rhs; + } + + constexpr friend iterator operator++(iterator& lhs, int) { + iterator prev = lhs; + ++lhs; + return prev; + } + + constexpr const elem_t& operator*() const { + return *_set->_alloc[_i].value; + } + + constexpr bool operator==(const iterator& it) { + return _set == it._set and _i == it._i; + } + + constexpr bool operator!=(const iterator& it) { + return _set != it._set or _i != it._i; + } + + private: + const set* _set; + size_t _i; + }; + + constexpr iterator begin() const { + iterator it(this, 0); + if (not _alloc[it._i].value) { + ++it; + } + return it; + } + + constexpr iterator end() const { + return iterator(this, npos); + } + + +// PRIVATE ============================================================================================================= + +private: + constexpr void _expand() { + set cpy; // Create a new set + cpy._alloc.allocate( + fennec::next_prime2(_alloc.capacity()) + ); + fennec::memset(cpy._alloc.data(), 0, cpy._alloc.size()); + + // 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); + } + + allocation _alloc; + hash_t _hash; + size_t _size; +}; + +} + +#endif // FENNEC_CONTAINERS_SET_H diff --git a/include/fennec/fproc/strings/string.h b/include/fennec/fproc/strings/string.h index a13815f..29daa1e 100644 --- a/include/fennec/fproc/strings/string.h +++ b/include/fennec/fproc/strings/string.h @@ -99,7 +99,8 @@ public: /// \details adds additional character for null termination. Ignores whether str is null-terminated. /// This constructor makes the assumption that `n` is the intended number of characters. constexpr _string(const char* str, size_t n) - : _str(str, n + 1) { + : _str(n + 1) { + fennec::memcpy(_str.data(), str, n); _str[n] = '\0'; } @@ -318,7 +319,7 @@ public: constexpr void resize(size_t n) { size_t i = size(); _str.reallocate(n + 1); - if (n > i) fennec::memset(_str.data() + i, '\0', n - i); + if (n > i) fennec::memset(_str.data() + i, '\0', n + 1 - i); } /// @@ -387,6 +388,10 @@ public: return res; } + friend constexpr _string operator+(char c, _string& str) { + return _string(c, 1) + str; + } + constexpr _string operator+(const cstring& str) const { _string res(size() + str.size()); // Make a new string with the size of this + str fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this diff --git a/include/fennec/lang/assert.h b/include/fennec/lang/assert.h index d72eb8a..ee305a7 100644 --- a/include/fennec/lang/assert.h +++ b/include/fennec/lang/assert.h @@ -46,7 +46,12 @@ ///
/// assert(expr, desc) /// -/// Make an assertion with expression `expr` and provide a description `desc`. +/// Make an assertion with expression `expr` and provide a description `desc`. Only halts in debug mode. +/// +///
+/// assertf(expr, desc) +/// +/// Make an assertion with expression `expr` and provide a description `desc`. Always halts. /// ///
/// assertd(expr, desc) @@ -65,15 +70,20 @@ using assert_handler = void (*)(const char *, const char *, int , const char *); -void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc); +void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc, bool halt); // flagged unlikely to optimize branch prediction #define assert(expression, description) \ if(not(expression)) [[unlikely]] { \ - __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description); \ + __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, not FENNEC_RELEASE); \ } -#ifdef NDEBUG +#define assertf(expression, description) \ + if(not(expression)) [[unlikely]] { \ + __assert_impl(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, true); \ + } + +#if FENNEC_RELEASE #define assertd(expression, description) (0) #else #define assertd(expression, description) assert(expression, description) diff --git a/include/fennec/lang/conditional_types.h b/include/fennec/lang/conditional_types.h index 73525f4..e38613a 100644 --- a/include/fennec/lang/conditional_types.h +++ b/include/fennec/lang/conditional_types.h @@ -32,6 +32,8 @@ #ifndef FENNEC_LANG_CONDITIONAL_TYPES_H #define FENNEC_LANG_CONDITIONAL_TYPES_H +#include + /// /// \page fennec_lang_conditional_types Conditional Types /// @@ -64,8 +66,6 @@ /// /// -#include - namespace fennec { @@ -92,12 +92,12 @@ using conditional_t // specialization of fennec::conditional for `true` case template -struct conditional : type_transform{}; +struct conditional : type_identity{}; // specialization of fennec::conditional for `false` case template -struct conditional : type_transform{}; +struct conditional : type_identity{}; // fennec::detect ====================================================================================================== diff --git a/include/fennec/lang/detail/__numeric_transforms.h b/include/fennec/lang/detail/__numeric_transforms.h index 69a840e..9cc134a 100644 --- a/include/fennec/lang/detail/__numeric_transforms.h +++ b/include/fennec/lang/detail/__numeric_transforms.h @@ -28,34 +28,34 @@ namespace fennec namespace detail { -template struct __make_unsigned : type_transform {}; +template struct __make_unsigned : type_identity {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; -template<> struct __make_unsigned : type_transform {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; +template<> struct __make_unsigned : type_identity {}; -template struct __make_signed : type_transform {}; +template struct __make_signed : type_identity {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; -template<> struct __make_signed : type_transform {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; +template<> struct __make_signed : type_identity {}; } diff --git a/include/fennec/lang/detail/__type_sequences.h b/include/fennec/lang/detail/__type_sequences.h index 848521e..fe13156 100644 --- a/include/fennec/lang/detail/__type_sequences.h +++ b/include/fennec/lang/detail/__type_sequences.h @@ -27,7 +27,7 @@ namespace fennec namespace detail { -template struct __first_element : type_transform{}; +template struct __first_element : type_identity{}; } diff --git a/include/fennec/lang/detail/__type_traits.h b/include/fennec/lang/detail/__type_traits.h index 1d731f8..c6bb455 100644 --- a/include/fennec/lang/detail/__type_traits.h +++ b/include/fennec/lang/detail/__type_traits.h @@ -65,6 +65,9 @@ template struct __is_floating_point : false_type {}; template<> struct __is_floating_point : true_type {}; template<> struct __is_floating_point : true_type {}; +template struct __is_pointer : false_type {}; +template struct __is_pointer : true_type {}; + } } diff --git a/include/fennec/lang/detail/__type_transforms.h b/include/fennec/lang/detail/__type_transforms.h new file mode 100644 index 0000000..a518af2 --- /dev/null +++ b/include/fennec/lang/detail/__type_transforms.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H +#define FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H + +#include + +namespace fennec +{ + +namespace detail +{ + +template +struct __add_lvalue_reference { + using type = _Tp; +}; + +template +struct __add_lvalue_reference<_Tp, void_t<_Tp&>> { + using type = _Tp&; +}; + + +template +struct __add_rvalue_reference { + using type = _Tp; +}; + +template +struct __add_rvalue_reference<_Tp, void_t<_Tp&&>> { + using type = _Tp&&; +}; + +} + +} + +#endif // FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H diff --git a/include/fennec/lang/hashing.h b/include/fennec/lang/hashing.h new file mode 100644 index 0000000..75050bf --- /dev/null +++ b/include/fennec/lang/hashing.h @@ -0,0 +1,89 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_LANG_HASHING_H +#define FENNEC_LANG_HASHING_H + +#include +#include + +namespace fennec +{ + +/// +/// \brief Struct for hashing types, there is no default hashing function +/// \tparam Key The type to hash +template struct hash; + +// Murmur3 Hash for 64-bit ints +template<> +struct hash { + using type_t = uint64_t; + constexpr size_t operator()(uint64_t x) const { + // Murmur3 + x ^= x >> 33U; + x *= 0xff51afd7ed558ccd; + x ^= x >> 33U; + x *= 0xc4ceb9fe1a85ec53; + x ^= x >> 33U; + return x; + } +}; + +// Wrapper for casting ints +template + requires is_integral_v +struct hash : hash { + using type_t = IntT; +}; + +// Wrapper for pointers +template + requires is_pointer_v +struct hash : hash { +}; + +// Float +template<> +struct hash : hash { + constexpr size_t operator()(float x) const { + return hash::operator()(bit_cast(x)); + } +}; + +template<> +struct hash : hash { + constexpr size_t operator()(double x) const { + return hash::operator()(bit_cast(x)); + } +}; + + +/// +/// \brief Pairs two hashes +/// \param x first hash +/// \param y second hash +/// \returns a pairing of the two hashes +constexpr size_t pair_hash(size_t x, size_t y) { + // Szudzik Pairing + return (x >= y ? (x * x) + x + y : (y * y) + x); +} + +} + +#endif // FENNEC_LANG_HASHING_H diff --git a/include/fennec/lang/intrinsics.h b/include/fennec/lang/intrinsics.h index 10c04e7..b71bfec 100644 --- a/include/fennec/lang/intrinsics.h +++ b/include/fennec/lang/intrinsics.h @@ -142,14 +142,44 @@ # define FENNEC_HAS_BUILTIN_IS_CLASS #endif +// CONSTRUCTORS ======================================================================================================== + // Difficult and Inconsistent without intrinsics #if __has_builtin(__is_constructible) # define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1 -# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(type, ...) __is_constructible(type, __VA_ARGS__) +# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(type, ...) __is_constructible(type __VA_OPT__(,) __VA_ARGS__) #else # define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 0 #endif +// Difficult and Inconsistent without intrinsics +#if __has_builtin(__is_trivially_constructible) +# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1 +# define FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(type) __is_trivially_constructible(type) +#else +# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 0 +#endif + +// Difficult and Inconsistent without intrinsics +#if __has_builtin(__has_trivial_destructor) +# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1 +# define FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __has_trivial_destructor(type) +#else +# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0 +#endif + + +// ASSIGNMENTS ========================================================================================================= + +// Difficult and Inconsistent without intrinsics +#if __has_builtin(__is_assignable) +# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 1 +# define FENNEC_BUILTIN_IS_ASSIGNABLE(a, b) __is_assignable(a, b) +#else +# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 0 +#endif + + // Type Traits // can_convert is also very difficult to implement without intrinsics #if __has_builtin(__is_convertible) diff --git a/include/fennec/lang/type_identity.h b/include/fennec/lang/type_identity.h new file mode 100644 index 0000000..cf0e419 --- /dev/null +++ b/include/fennec/lang/type_identity.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_LANG_TYPE_IDENTITY_H +#define FENNEC_LANG_TYPE_IDENTITY_H + +/// +/// \page fennec_lang_type_identity Type Identity +/// +/// \brief Part of the fennec metaprogramming library. This header defines structures for copying types with different traits +/// or rather, transform them, at compile time. +/// +/// \code #include \endcode +/// +/// +/// +///
Syntax +/// Description +///

+/// \ref fennec::type_identity "type_identity::type"
+///
+/// \copydetails fennec::type_identity +///
+/// + +namespace fennec +{ + +/// +/// \brief Base Class for Type Transformations +/// +/// \details resembles a transformation from one type to T, the result is stored in the member type_transform::type +/// \tparam T Resultant Type +template struct type_identity { + + /// \brief the type to transform into + using type = T; +}; + +} + +#endif // FENNEC_LANG_TYPE_IDENTITY_H diff --git a/include/fennec/lang/type_traits.h b/include/fennec/lang/type_traits.h index b6450e8..2c63dfd 100644 --- a/include/fennec/lang/type_traits.h +++ b/include/fennec/lang/type_traits.h @@ -272,6 +272,22 @@ template struct is_floating_point template constexpr bool_t is_floating_point_v = is_floating_point {}; +// Pointer Types ======================================================================================================= + +/// +/// \brief check if \p T is of a floating point type +/// +/// \details Checks if type `T` is a floating point type and store it in `is_same::value`. +/// \tparam T type to check +template struct is_pointer + : detail::__is_pointer>{}; + +/// +/// \brief shorthand for ```is_floating_point::value``` +/// \tparam T type to check +template constexpr bool_t is_pointer_v = is_pointer {}; + + // Arithmetic Types ==================================================================================================== @@ -339,7 +355,7 @@ template struct is_convertible template constexpr bool_t is_convertible_v = is_convertible{}; -// fennec::is_constructible =============================================================================================== +// fennec::is_constructible ============================================================================================ /// /// \brief Check if `ClassT` can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`. @@ -354,7 +370,106 @@ template struct is_constructible template constexpr bool_t is_constructible_v = is_constructible{}; -// fennec:: + +/// +/// \brief Check if `ClassT` is default constructible +/// \tparam ClassT The class type to test +template struct is_default_constructible + : bool_constant {}; + +/// +/// \brief Shorthand for `is_default_constructible::value` +template constexpr bool_t is_default_constructible_v = is_default_constructible{}; + + + +/// +/// \brief Check if `ClassT` is copy constructible +/// \tparam ClassT The class type to test +template struct is_copy_constructible + : bool_constant)> {}; + +/// +/// \brief Shorthand for `is_copy_constructible::value` +template constexpr bool_t is_copy_constructible_v = is_copy_constructible{}; + + + +/// +/// \brief Check if `ClassT` is copy constructible +/// \tparam ClassT The class type to test +template struct is_move_constructible + : bool_constant)> {}; + +/// +/// \brief Shorthand for `is_copy_constructible::value` +template constexpr bool_t is_move_constructible_v = is_move_constructible{}; + + + +/// +/// \brief Check if `ClassT` is trivially constructible +/// \tparam ClassT The class type to test +template struct is_trivially_constructible + : bool_constant {}; + +/// +/// \brief Shorthand for `is_trivially_constructible::value` +template constexpr bool_t is_trivially_constructible_v = is_trivially_constructible{}; + + +// fennec::is_trivially_destructible =================================================================================== + +/// +/// \brief Check if `ClassT` is trivially destructible +/// \tparam ClassT The class type to test +template struct is_trivially_destructible + : bool_constant {}; + +/// +/// \brief Shorthand for `is_trivially_destructible::value` +template constexpr bool_t is_trivially_destructible_v = is_trivially_destructible{}; + + +// fennec::is_assignable =============================================================================================== + +/// +/// \brief Check if `ClassT` can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`. +/// This may be read as "is `ClassT` constructible with `ArgsT`" +/// \tparam ClassAT The class type to test +/// \tparam ClassBT The arguments for the specific constructor +template struct is_assignable + : bool_constant {}; + +/// +/// \brief Shorthand for `is_constructible::value` +template constexpr bool_t is_assignable_v = is_assignable{}; + + +// fennec::is_copy_assignable ========================================================================================== + +/// +/// \brief Check if `ClassT` is copy assignable +/// \tparam ClassT The class type to test +template struct is_copy_assignable + : bool_constant, add_lvalue_reference_t)> {}; + +/// +/// \brief Shorthand for `is_copy_assignable::value` +template constexpr bool_t is_copy_assignable_v = is_copy_assignable{}; + + +// fennec::is_move_assignable ========================================================================================== + +/// +/// \brief Check if `ClassT` is move assignable +/// \tparam ClassT The class type to test +template struct is_move_assignable + : bool_constant, add_rvalue_reference_t)> {}; + +/// +/// \brief Shorthand for `is_move_assignable::value` +template constexpr bool_t is_move_assignable_v = is_move_assignable{}; // diff --git a/include/fennec/lang/type_transforms.h b/include/fennec/lang/type_transforms.h index c071b46..46268dc 100644 --- a/include/fennec/lang/type_transforms.h +++ b/include/fennec/lang/type_transforms.h @@ -31,6 +31,9 @@ #ifndef FENNEC_LANG_TYPE_TRANSFORMS_H #define FENNEC_LANG_TYPE_TRANSFORMS_H +#include +#include + /// /// \page fennec_lang_type_transforms Type Transforms /// @@ -44,11 +47,6 @@ /// Syntax /// Description ///
-/// \ref fennec::type_transform "type_transform::type"
-/// -/// \copydetails fennec::type_transform -/// -///
/// \ref fennec::add_pointer "add_pointer::type"
/// \ref fennec::add_pointer_t "add_pointer_t" /// @@ -127,22 +125,6 @@ namespace fennec { -// fennec::type_transform ============================================================================================== - -/// -/// \brief Base Class for Type Transformations -/// -/// \details resembles a transformation from one type to T, the result is stored in the member type_transform::type -/// \tparam T Resultant Type -template struct type_transform { - - /// - /// \brief the type to transform into - using type = T; -}; - - - // Pointer Conversions ================================================================================================= /// @@ -150,7 +132,7 @@ template struct type_transform { /// /// \details adds a pointer to the provided type such that `T` becomes `T*` /// \tparam T Resultant Type -template struct add_pointer : type_transform{}; +template struct add_pointer : type_identity{}; /// /// \brief shorthand for `typename add_pointer::type` @@ -162,10 +144,10 @@ template using add_pointer_t = typename add_pointer::type; /// /// \details removes a pointer from the provided type such that `T*` becomes `T` /// \tparam T Resultant Type -template struct remove_pointer : type_transform {}; +template struct remove_pointer : type_identity {}; // specialization for T* -template struct remove_pointer : type_transform {}; +template struct remove_pointer : type_identity {}; /// /// \brief shorthand for `typename remove_pointer::type` @@ -180,7 +162,7 @@ template using remove_pointer_t = typename remove_pointer::type; /// /// \details adds a pointer to the provided type such that `T` becomes `T&` /// \tparam T Resultant Type -template struct add_reference : type_transform {}; +template struct add_reference : type_identity {}; /// /// \brief shorthand for `typename add_reference::type` @@ -192,19 +174,43 @@ template using add_reference_t = typename add_reference::type; /// /// \details removes references from the provided type such that `T&` and `T&&` become `T` /// \tparam T Reference Type -template struct remove_reference : type_transform {}; +template struct remove_reference : type_identity {}; // specialization for `T&` -template struct remove_reference : type_transform {}; +template struct remove_reference : type_identity {}; // specialization for `T&&` -template struct remove_reference : type_transform {}; +template struct remove_reference : type_identity {}; /// /// \brief shorthand for `typename remove_reference::type` template using remove_reference_t = typename remove_reference::type; +/// +/// \brief add a lvalue reference to \p T +/// +/// \details adds a lvalue reference to the provided type such that 'T' becomes 'T&' +/// \tparam T Reference Type +template struct add_lvalue_reference : detail::__add_lvalue_reference {}; + +/// +/// \brief shorthand for `typename remove_reference::type` +template using add_lvalue_reference_t = typename add_lvalue_reference::type; + + +/// +/// \brief add a rvalue reference to \p T +/// +/// \details adds a rvalue reference to the provided type such that 'T' becomes 'T&&' +/// \tparam T Reference Type +template struct add_rvalue_reference : detail::__add_rvalue_reference {}; + +/// +/// \brief shorthand for `typename remove_reference::type` +template using add_rvalue_reference_t = typename add_rvalue_reference::type; + + // Const & Volatile Conversions ======================================================================================== @@ -213,14 +219,14 @@ template using remove_reference_t = typename remove_reference::t /// /// \details adds const qualification to the provided type such that `T` becomes `const T` /// \tparam T Reference Type -template struct add_const : type_transform {}; +template struct add_const : type_identity {}; /// /// \brief shorthand for `typename add_const::type` template using add_const_t = typename add_const::type; // specialization for const types -template struct add_const : type_transform {}; +template struct add_const : type_identity {}; /// @@ -228,14 +234,14 @@ template struct add_const : type_transform {}; /// /// \details removes const qualification from the provided type such that `const T` becomes `T` /// \tparam T Reference Type -template struct remove_const : type_transform {}; +template struct remove_const : type_identity {}; /// /// \brief shorthand for `typename remove_const::type` template using remove_const_t = typename remove_const::type; // specialization for const types -template struct remove_const : type_transform {}; +template struct remove_const : type_identity {}; @@ -244,14 +250,14 @@ template struct remove_const : type_transform {}; /// /// \details removes references from the provided type such that `T` becomes `volatile T` /// \tparam T Reference Type -template struct add_volatile : type_transform {}; +template struct add_volatile : type_identity {}; /// /// \brief shorthand for `typename add_volatile::type` template using add_volatile_t = typename add_volatile::type; // specialization for volatile types -template struct add_volatile : type_transform {}; +template struct add_volatile : type_identity {}; /// @@ -259,14 +265,14 @@ template struct add_volatile : type_transform struct remove_volatile : type_transform {}; +template struct remove_volatile : type_identity {}; /// /// \brief shorthand for `typename remove_volatile::type` template using remove_volatile_t = typename remove_volatile::type; // specialization for volatile types -template struct remove_volatile : type_transform {}; +template struct remove_volatile : type_identity {}; @@ -276,20 +282,20 @@ template struct remove_volatile : type_transform {}; /// \details removes references from the provided type such that `T`, `const T`, and `volatile T` become /// `const volatile T` /// \tparam T Reference Type -template struct add_cv : type_transform {}; +template struct add_cv : type_identity {}; /// /// \brief shorthand for `typename add_cv::type` template using add_cv_t = typename add_cv::type; // specialization for const types -template struct add_cv : type_transform {}; +template struct add_cv : type_identity {}; // specialization for volatile types -template struct add_cv : type_transform {}; +template struct add_cv : type_identity {}; // specialization for const volatile types -template struct add_cv : type_transform {}; +template struct add_cv : type_identity {}; @@ -299,16 +305,16 @@ template struct add_cv : type_transform struct remove_cv : type_transform {}; +template struct remove_cv : type_identity {}; // specialization for const types -template struct remove_cv : type_transform {}; +template struct remove_cv : type_identity {}; // specialization for volatile types -template struct remove_cv : type_transform {}; +template struct remove_cv : type_identity {}; // specialization for const volatile types -template struct remove_cv : type_transform {}; +template struct remove_cv : type_identity {}; /// /// \brief shorthand for `typename remove_cv::type` @@ -321,7 +327,7 @@ template using remove_cv_t = typename remove_cv::type; /// /// \details adds references and const volatile qualifiers to the provided type. /// \tparam T Reference Type -template struct add_cvr : type_transform>> {}; +template struct add_cvr : type_identity>> {}; /// /// \brief shorthand for `typename add_cvr::type` @@ -334,7 +340,7 @@ template using add_cvr_t = typename add_cvr::type; /// /// \details removes const and volatile from the provided type such that /// \tparam T Reference Type -template struct remove_cvr : type_transform>> {}; +template struct remove_cvr : type_identity>> {}; /// diff --git a/include/fennec/lang/types.h b/include/fennec/lang/types.h index 5d9d019..734f635 100644 --- a/include/fennec/lang/types.h +++ b/include/fennec/lang/types.h @@ -242,7 +242,6 @@ namespace fennec /// \name Special Types /// @{ - using nullptr_t = decltype(nullptr); ///< \brief Null Pointer Type using intptr_t = intptr_t; ///< \brief Signed Integer Capable of Holding a Pointer to void using uintptr_t = uintptr_t; ///< \brief Unsigned Integer Capable of Holding a Pointer to void @@ -251,6 +250,7 @@ namespace fennec using size_t = size_t; ///< \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof` using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers + class undefined_t; ///< \brief undefined class for SFINAE template using void_t = void; ///< \brief Void type used for SFINAE @@ -263,15 +263,15 @@ namespace fennec /// \name Sized Integer Types /// @{ - using int8_t = schar_t; ///< \brief Signed 8-bit integer - using int16_t = short_t; ///< \brief Signed 16-bit integer - using int32_t = conditional_t; ///< \brief Signed 32-bit integer - using int64_t = llong_t; ///< \brief Signed 64-bit integer + using int8_t = schar_t; ///< \brief Signed 8-bit integer + using int16_t = short_t; ///< \brief Signed 16-bit integer + using int32_t = conditional_t; ///< \brief Signed 32-bit integer + using int64_t = conditional_t; ///< \brief Signed 64-bit integer - using uint8_t = uchar_t; ///< \brief Unsigned 8-bit integer - using uint16_t = ushort_t; ///< \brief Unsigned 16-bit integer - using uint32_t = conditional_t; ///< \brief Unsigned 32-bit integer - using uint64_t = ullong_t; ///< \brief Unsigned 64-bit integer + using uint8_t = uchar_t; ///< \brief Unsigned 8-bit integer + using uint16_t = ushort_t; ///< \brief Unsigned 16-bit integer + using uint32_t = conditional_t; ///< \brief Unsigned 32-bit integer + using uint64_t = conditional_t; ///< \brief Unsigned 64-bit integer /// @} diff --git a/include/fennec/lang/utility.h b/include/fennec/lang/utility.h index 5050f88..33b41f7 100644 --- a/include/fennec/lang/utility.h +++ b/include/fennec/lang/utility.h @@ -60,6 +60,7 @@ /// #include +#include namespace fennec { @@ -104,6 +105,29 @@ template constexpr const remove_reference_t& copy(T&& x) noexcept return x; } +/// +/// \brief Swaps x and y +/// \tparam T the fundamental type +/// \param x first value +/// \param y second value +template requires is_fundamental_v +constexpr void swap(T& x, T& y) noexcept { + T a = x; + x = y; + y = a; +} + +/// +/// \brief Swaps x and y without invoking destructor +/// \tparam T the type +/// \param x first value +/// \param y second value +template constexpr void swap(T& x, T& y) noexcept { + T a = fennec::move(x); + x = fennec::move(y); + y = fennec::move(a); +} + } #endif // FENNEC_LANG_UTILITY_H diff --git a/include/fennec/math/exponential.h b/include/fennec/math/exponential.h index d7fe981..c61add5 100644 --- a/include/fennec/math/exponential.h +++ b/include/fennec/math/exponential.h @@ -88,6 +88,7 @@ /// #include +#include namespace fennec { diff --git a/include/fennec/math/ext/primes.h b/include/fennec/math/ext/primes.h new file mode 100644 index 0000000..766b654 --- /dev/null +++ b/include/fennec/math/ext/primes.h @@ -0,0 +1,107 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_MATH_EXT_PRIMES_H +#define FENNEC_MATH_EXT_PRIMES_H + +#include + +namespace fennec +{ + +template +constexpr bool is_prime(genType x) { + // Base Cases Covers + if (x <= 1) return false; // Eliminates 0 and 1 + if (x <= 3) return true; // Eliminates 2 and 3 + if (x % 2 == 0 or x % 3 == 0) return false; // Eliminates even numbers and numbers divisible by 3 + // 4, 6, 8, 9, 10, 12, 14, 15 + if (x < 15) return true; // Covers 5, 7, 11, 13 + + // Due to the property of 15 being divisible by 5 and the nature of primes + // All prime numbers must end in 1, 3, 7, 9 + // when x/15 is even, x%15 must be odd + // and when x/15 is odd, x%15 must be even + // To explain, when x/15 is even, 15*x/15 ends in 0, and when odd, ends in 5 + // Thus when x/15 is even, 15*x/15 ends in 0, and the results are 1, 3, 7, 11, 13 + // And when x/15 is even, 15*x/15 ends in 5, and the results are 2, 4, 8, 14 + genType mod15 = x % 15; + genType mod15e = mod15 % 2; + genType div15e = (x / 15) % 2; + if (mod15e == div15e) return false; + + // Iterate + genType limit = sqrt(x); + for (genType i = 5; i <= limit; i += 6) { + if (x % i == 0 || x % (i + 2) == 0) { + return false; + } + } + + return true; +} + +template +constexpr genType next_prime(genType x) { + genType n = (x + 1) / 6 + 1; + + while (true) { + x = (n++ * 6) - 1; + if (fennec::is_prime(x)) return x; + if (fennec::is_prime(x += 2)) return x; + } +} + +template +constexpr genType next_prime2(genType x) { + genType n = (x + 1) / 6; + n *= 2; + + while (true) { + x = (n++ * 6) - 1; + if (fennec::is_prime(x)) return x; + if (fennec::is_prime(x += 2)) return x; + } +} + +template +constexpr genType prev_prime(genType x) { + genType n = (x + 1) / 6 - 1; + + while (true) { + x = (n-- * 6) - 1; + if (fennec::is_prime(x)) return x; + if (fennec::is_prime(x += 2)) return x; + } +} + +template +constexpr genType prev_prime2(genType x) { + genType n = (x + 1) / 6; + n /= 2; + + while (true) { + x = (n-- * 6) - 1; + if (fennec::is_prime(x)) return x; + if (fennec::is_prime(x += 2)) return x; + } +} + +} + +#endif // FENNEC_MATH_EXT_PRIMES_H diff --git a/include/fennec/math/ext/quaternion.h b/include/fennec/math/ext/quaternion.h index b85e9c9..1042c51 100644 --- a/include/fennec/math/ext/quaternion.h +++ b/include/fennec/math/ext/quaternion.h @@ -105,7 +105,7 @@ public: /// /// \brief Component Constructor - /// \param w The real component + /// \param w The scalar component /// \param x The coefficient of the `i` component /// \param y The coefficient of the `j` component /// \param z The coefficient of the `k` component @@ -113,10 +113,18 @@ public: data = { x, y, z, w }; } + /// + /// \brief Component Constructor + /// \param s The scalar component + /// \param v The vector component + constexpr quaternion(scalar_t s, vec3_t v) { + data = { v.x, v.y, v.z, s }; + } + /// /// \brief Vector Constructor /// \param v A 4d vector - constexpr quaternion(const vec& v) { + constexpr quaternion(const vec4_t& v) { data = v.data; } diff --git a/include/fennec/math/ext/transform.h b/include/fennec/math/ext/transform.h index 6121a97..bdd59c7 100644 --- a/include/fennec/math/ext/transform.h +++ b/include/fennec/math/ext/transform.h @@ -131,7 +131,7 @@ constexpr qua rotation(const vec& axis, genType angle) { vec a = fennec::normalize(axis); const genType s = fennec::sin(angle); - return qua(fennec::cos(angle * genType(0.5)), s * a.x, s * a.y, s * a.z); + return qua(fennec::cos(angle * genType(0.5)), s * a); } /// \brief enum to denote the unit-axis of rotation diff --git a/include/fennec/memory/allocator.h b/include/fennec/memory/allocator.h index 965aa22..e60b5d4 100644 --- a/include/fennec/memory/allocator.h +++ b/include/fennec/memory/allocator.h @@ -457,14 +457,11 @@ public: /// \param alloc the allocation to copy /// \returns a reference to `this` constexpr allocation& operator=(allocation&& alloc) noexcept { - // Copy contents - _alloc = alloc._alloc; - _data = alloc._data; - _capacity = alloc._capacity; - // Cleanup alloc - alloc._data = nullptr; - alloc._capacity = 0; + // Copy contents + fennec::swap(_alloc, alloc._alloc); + fennec::swap(_data, alloc._data); + fennec::swap(_capacity, alloc._capacity); return *this; } @@ -525,6 +522,11 @@ public: return _data[i]; } + constexpr value_t operator[](size_t i) const requires is_fundamental_v { + assertd(i < size(), "Array Out of Bounds"); + return _data[i]; + } + constexpr const value_t& operator[](size_t i) const { assertd(i < size(), "Array Out of Bounds"); return _data[i]; diff --git a/include/fennec/memory/bytes.h b/include/fennec/memory/bytes.h new file mode 100644 index 0000000..64a51d5 --- /dev/null +++ b/include/fennec/memory/bytes.h @@ -0,0 +1,188 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_LANG_BYTES_H +#define FENNEC_LANG_BYTES_H + +#include +#include +#include + +namespace fennec +{ + +/// \brief byte type +using byte_t = uint8_t; + +/// +/// \brief container for handling byte arrays +struct byte_array { +public: + + /// + /// \brief Default Constructor + constexpr byte_array() + : _carr(nullptr) + , _size(0) + , _const(true) { + } + + /// + /// \brief Buffer Constructor + /// \param arr the buffer to wrap + /// \param n the size of the buffer in bytes + constexpr byte_array(void* arr, size_t n) + : _arr(static_cast(arr)) + , _size(n) + , _const(false) { + } + + /// + /// \brief Const Buffer Constructor + /// \param arr the buffer to wrap + /// \param n the size of the buffer in bytes + constexpr byte_array(const void* arr, size_t n) + : _carr(static_cast(arr)) + , _size(n) + , _const(true) { + } + + /// + /// \brief Buffer Constructor + /// \param arr the buffer to wrap + /// \tparam n the size of the buffer in elements + template + constexpr byte_array(T arr[n]) + : byte_array(arr, n * sizeof(T)) { + } + + /// + /// \brief Const Buffer Constructor + /// \param arr the buffer to wrap + /// \tparam n the size of the buffer in elements + template + constexpr byte_array(const T arr[n]) + : byte_array(arr, n * sizeof(T)) { + } + + /// + /// \returns The size of the array in bytes + constexpr size_t size() const { + return _size; + } + + /// + /// \brief Array Access Operator + /// \param i the index to access + /// \returns a reference to the byte at `i` + constexpr byte_t& operator[](int i) { + assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); + assertd(i < _size, "Array Out of Bounds"); + return _arr[i]; + } + + /// + /// \brief Const Array Access Operator + /// \param i the index to access + /// \returns a copy of the byte at `i` + constexpr byte_t operator[](int i) const { + assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); + assertd(i < _size, "Array Out of Bounds"); + return _carr[i]; + } + + /// + /// \brief Cast Function + /// \tparam T type to cast to + /// \returns a pointer to the underlying buffer interpreted as an array of `T` + template + constexpr T* cast() { + void* temp = _arr; + return static_cast(temp); + } + + /// + /// \brief Const Cast Function + /// \tparam T type to cast to + /// \returns a pointer to the underlying buffer interpreted as an array of `T` + template + constexpr const T* cast() const { + const void* temp = _carr; + return static_cast(temp); + } + +private: + union { // hack to allow both const qualified and non-const strings + byte_t* _arr; + const byte_t* _carr; + }; + size_t _size; + bool _const; +}; + +/// +/// \brief Byte Array Hash Function +template<> +struct hash { + size_t operator()(const byte_array& bytes) { + + // Murmur2 + static constexpr uint64_t m = 0xc6a4a7935bd1e995; + static constexpr uint64_t s = 0xff51afd7ed558ccd; + static constexpr uint64_t r = 47; + const uint64_t n = bytes.size(); + + uint64_t h = s ^ (n * m); + const uint64_t* x = bytes.cast<>(); + const uint64_t* y = x + (n / sizeof(uint64_t)); + + while (x != y) { + uint64_t k = *x++; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + const uint8_t* b = (const uint8_t*)x; + switch (n & 7) { + case 7: h ^= uint64_t(b[6]) << 48; + case 6: h ^= uint64_t(b[5]) << 40; + case 5: h ^= uint64_t(b[4]) << 32; + case 4: h ^= uint64_t(b[3]) << 24; + case 3: h ^= uint64_t(b[2]) << 16; + case 2: h ^= uint64_t(b[1]) << 8; + case 1: h ^= uint64_t(b[0]); + h *= m; + default: + } + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; + } +}; + +} + +#endif // FENNEC_LANG_BYTES_H diff --git a/include/fennec/memory/detail/__ptr_traits.h b/include/fennec/memory/detail/__ptr_traits.h index a56388b..05a9ec2 100644 --- a/include/fennec/memory/detail/__ptr_traits.h +++ b/include/fennec/memory/detail/__ptr_traits.h @@ -71,7 +71,7 @@ private: using __diff_t = typename TypeT::diff_t; // Helper to prevent substitution issues with detecting the difference type template // Helper to prevent substitution issues with detecting a defined rebind - using __rebind_helper = type_transform>; + using __rebind_helper = type_identity>; public: using pointer_t = ClassT; diff --git a/include/fennec/memory/new.h b/include/fennec/memory/new.h index 8b67bd9..df5f762 100644 --- a/include/fennec/memory/new.h +++ b/include/fennec/memory/new.h @@ -54,19 +54,19 @@ struct nothrow_t size_t pagesize(); template void construct(TypeT* ptr) { - ptr->TypeT(); + new(ptr) TypeT(); } template void construct(TypeT* ptr, const TypeT& val) { - ptr->TypeT(val); + new(ptr) TypeT(val); } template void construct(TypeT* ptr, TypeT&& val) { - ptr->TypeT(fennec::forward(val)); + new(ptr) TypeT(fennec::forward(val)); } -template void construct(TypeT* ptr, ArgsT...args) { - ptr->TypeT(fennec::forward(args)...); +template void construct(TypeT* ptr, ArgsT&&...args) { + new(ptr) TypeT(fennec::forward(args)...); } template void destruct(TypeT* ptr) { diff --git a/include/fennec/platform/interface/dialog.h b/include/fennec/platform/interface/dialog.h new file mode 100644 index 0000000..3530d1a --- /dev/null +++ b/include/fennec/platform/interface/dialog.h @@ -0,0 +1,22 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_INTERFACE_DIALOG_H +#define FENNEC_PLATFORM_INTERFACE_DIALOG_H + +#endif // FENNEC_PLATFORM_INTERFACE_DIALOG_H diff --git a/include/fennec/platform/interface/display.h b/include/fennec/platform/interface/display.h new file mode 100644 index 0000000..588ac10 --- /dev/null +++ b/include/fennec/platform/interface/display.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_INTERFACE_DISPLAY_H +#define FENNEC_PLATFORM_INTERFACE_DISPLAY_H + +#include + +namespace fennec +{ + +/// +/// \brief Interface for display management +class display +{ +public: + struct config { + + }; + + virtual bool connected() const = 0; + +protected: + virtual ~display() = default; + +private: + config _config; +}; + +} + +#endif // FENNEC_PLATFORM_INTERFACE_DISPLAY_H diff --git a/include/fennec/platform/interface/fwd.h b/include/fennec/platform/interface/fwd.h new file mode 100644 index 0000000..3e6b3a6 --- /dev/null +++ b/include/fennec/platform/interface/fwd.h @@ -0,0 +1,30 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_INTERFACE_FORWARD_H +#define FENNEC_PLATFORM_INTERFACE_FORWARD_H + +namespace fennec +{ + +class window; +class display; + +} + +#endif // FENNEC_PLATFORM_INTERFACE_FORWARD_H diff --git a/include/fennec/platform/interface/platform.h b/include/fennec/platform/interface/platform.h new file mode 100644 index 0000000..084fcac --- /dev/null +++ b/include/fennec/platform/interface/platform.h @@ -0,0 +1,74 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_INTERFACE_PLATFORM_H +#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H + +#include +#include + +namespace fennec +{ + +class platform { +public: + using shared_object = struct shared_object; + using function_pointer = void (*)(void); + + struct shared_lib { + shared_object* _lib; + const cstring _name; + }; + + enum class user { + client, + server + }; + + struct config { + user type; + }; + + // Functions with default implementations + + virtual string get_environment_variable(const cstring& var); + + + + // Pure Virtual Functions + + virtual display* get_display() = 0; + + virtual shared_object* load_object(const cstring& file) = 0; + virtual void unload_object(shared_object* obj) = 0; + + virtual function_pointer find_symbol(shared_object* hndl, const cstring& name) = 0; + + + +protected: + platform(user t); + virtual ~platform() = default; + +private: + config _config; +}; + +} + +#endif // FENNEC_PLATFORM_INTERFACE_PLATFORM_H diff --git a/include/fennec/platform/interface/window.h b/include/fennec/platform/interface/window.h new file mode 100644 index 0000000..2f09bbe --- /dev/null +++ b/include/fennec/platform/interface/window.h @@ -0,0 +1,137 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H +#define FENNEC_PLATFORM_INTERFACE_WINDOW_H + +#include +#include + +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: + enum class fullscreen_mode { + windowed = 0, + borderless, + 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, + }; + + union bits { + uint32_t depth; + uint8_t r, g, b, a; + }; + + struct config { + string title; + uint32_t flags; + size_t width, height; + fullscreen_mode fullscreen; + bits bit_depth; + }; + + virtual bool set_title(const cstring& title) = 0; + virtual bool set_title(const string& title) = 0; + + virtual bool set_width(size_t w) = 0; + virtual bool set_height(size_t h) = 0; + virtual bool set_size(size_t w, size_t h) = 0; + + virtual bool set_fullscreen_mode(fullscreen_mode mode) = 0; + + 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; + + bool is_child() const { + return _config.flags & flags_child; + } + + bool is_modal() const { + return _config.flags & flags_modal; + } + + display* get_display() { + return _display; + } + + const display* get_display() const { + return _display; + } + + + const string& get_title() const { + return _config.title; + } + + + size_t get_width() const { + return _config.width; + } + + size_t get_height() const { + return _config.height; + } + + + fullscreen_mode get_fullscreen_mode() const { + return _config.fullscreen; + } + + + bool is_keyboard_grabbed() const { + return _config.flags & flags_grab_keyboard; + } + + bool is_mouse_grabbed() const { + return _config.flags & flags_grab_mouse; + } + + bool is_screensaver_blocked() const { + return _config.flags & flags_block_screensaver; + } + +protected: + virtual ~window() = default; + window(display* display, window* parent, bool modal); + + display* _display; + window* _parent; + config _config; + +private: +}; + +} + +#endif // FENNEC_PLATFORM_INTERFACE_WINDOW_H diff --git a/include/fennec/platform/linux/platform.h b/include/fennec/platform/linux/platform.h new file mode 100644 index 0000000..7813e5a --- /dev/null +++ b/include/fennec/platform/linux/platform.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_LINUX_PLATFORM_H +#define FENNEC_PLATFORM_LINUX_PLATFORM_H + +#include +#include +#include + +namespace fennec +{ + +class linux_platform : public platform { +public: + enum display_ : int_t { + display_none = -1, + display_x11 = 0, + display_wayland, + }; + + linux_platform(user type); + ~linux_platform() override; + + shared_object* load_object(const cstring& file) override; + void unload_object(shared_object* obj) override; + function_pointer find_symbol(shared_object* hndl, const cstring& name) override; + + display* get_display() override; + + +private: + display* _display; + int_t _display_driver; + + void _runtime_client_checks(); + void _find_display_driver(); + + void _runtime_server_checks(); +}; + +} + +#endif // FENNEC_PLATFORM_LINUX_PLATFORM_H diff --git a/include/fennec/platform/linux/wayland/display.h b/include/fennec/platform/linux/wayland/display.h new file mode 100644 index 0000000..5919174 --- /dev/null +++ b/include/fennec/platform/linux/wayland/display.h @@ -0,0 +1,51 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H +#define FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H + +#include +#include + +#include +#include + +namespace fennec +{ + +namespace wayland +{ + +class wayland_display : public display { +public: + wayland_display(linux_platform* platform); + wayland_display(linux_platform* platform, const cstring& drv); + ~wayland_display() override; + + bool connected() const override; + +private: + struct wl_display* _handle; + linux_platform* _platform; +}; + +} + +} + +#endif // FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H diff --git a/include/fennec/platform/linux/wayland/lib/dyn.h b/include/fennec/platform/linux/wayland/lib/dyn.h new file mode 100644 index 0000000..dac2bea --- /dev/null +++ b/include/fennec/platform/linux/wayland/lib/dyn.h @@ -0,0 +1,37 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_DYN_H +#define FENNEC_PLATFORM_LINUX_WAYLAND_DYN_H + +#include + +namespace fennec +{ + +namespace wayland +{ + +bool load_symbols(linux_platform* platform); +void unload_symbols(linux_platform* platform); + +} + +} + +#endif // FENNEC_PLATFORM_LINUX_WAYLAND_DYN_H diff --git a/include/fennec/platform/linux/wayland/lib/fwd.h b/include/fennec/platform/linux/wayland/lib/fwd.h new file mode 100644 index 0000000..59e9e97 --- /dev/null +++ b/include/fennec/platform/linux/wayland/lib/fwd.h @@ -0,0 +1,24 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_FWD_H +#define FENNEC_PLATFORM_LINUX_WAYLAND_FWD_H + +struct wl_display; + +#endif // FENNEC_PLATFORM_LINUX_WAYLAND_FWD_H diff --git a/include/fennec/platform/linux/wayland/lib/sym.h b/include/fennec/platform/linux/wayland/lib/sym.h new file mode 100644 index 0000000..a851bca --- /dev/null +++ b/include/fennec/platform/linux/wayland/lib/sym.h @@ -0,0 +1,37 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#include + +#ifndef FENNEC_LIB +#define FENNEC_LIB(...) +#endif + +#ifndef FENNEC_SYMBOL +#define FENNEC_SYMBOL(...) +#endif + +FENNEC_LIB(WAYLAND); + +FENNEC_SYMBOL(struct wl_display*, wl_display_connect, const char* name); +FENNEC_SYMBOL(void, wl_display_disconnect, wl_display* name); + +#undef FENNEC_LIB +#undef FENNEC_SYMBOL + + diff --git a/include/fennec/platform/linux/wayland/lib/sym_def.h b/include/fennec/platform/linux/wayland/lib/sym_def.h new file mode 100644 index 0000000..74e03fe --- /dev/null +++ b/include/fennec/platform/linux/wayland/lib/sym_def.h @@ -0,0 +1,27 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_SYM_DEF_H +#define FENNEC_PLATFORM_LINUX_WAYLAND_SYM_DEF_H + +#define FENNEC_LIB(name) inline bool FENNEC_HAS_LIB_##name = false; +#define FENNEC_SYMBOL(ret, fn, ...) using sym_##fn = ret(*)(__VA_ARGS__); \ + inline sym_##fn fn = nullptr; +#include + +#endif // FENNEC_PLATFORM_LINUX_WAYLAND_SYM_DEF_H diff --git a/source/debug/assert_impl.cpp b/source/debug/assert_impl.cpp index 2d14aed..933a5d4 100644 --- a/source/debug/assert_impl.cpp +++ b/source/debug/assert_impl.cpp @@ -17,7 +17,7 @@ // ===================================================================================================================== #include -//#include +#include void __assert_callback(const char* expression, const char* file, int line, const char* function, const char* description) { @@ -28,5 +28,5 @@ void __assert_callback(const char* expression, const char* file, int line, const "At %s:%d in %s \n" "Description: %s \n", expression, file, line, function, description); -// cpptrace::generate_trace(2).print(); + cpptrace::generate_trace(2).print(); } \ No newline at end of file diff --git a/source/lang/assert.cpp b/source/lang/assert.cpp index 31756f5..d4ace7f 100644 --- a/source/lang/assert.cpp +++ b/source/lang/assert.cpp @@ -22,12 +22,11 @@ using assert_handler = void (*)(const char *, const char *, int , const char *); void __assert_callback(const char* expression, const char* file, int line, const char* function, const char* description); -void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* description) +void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* description, bool halt) { __assert_callback(expression, file, line, function, description); -#ifndef NDEBUG - - ::abort(); -#endif + if (halt) { + ::abort(); + } } \ No newline at end of file diff --git a/source/platform/interface/platform.cpp b/source/platform/interface/platform.cpp new file mode 100644 index 0000000..368569a --- /dev/null +++ b/source/platform/interface/platform.cpp @@ -0,0 +1,34 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#include +#include + +namespace fennec +{ + +string platform::get_environment_variable(const cstring& var) { + const char* val = getenv(var); + return string(val, strlen(val)); +} + +platform::platform(user t) { + _config.type = t; +} + +} diff --git a/source/platform/interface/window.cpp b/source/platform/interface/window.cpp new file mode 100644 index 0000000..3f42aca --- /dev/null +++ b/source/platform/interface/window.cpp @@ -0,0 +1,36 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#include + +namespace fennec +{ + +window::window(display* display, window* parent, bool modal) + : _display(display) + , _parent(parent) + , _config() { + + bool child = parent != nullptr; + assert(!modal || child, "Attempted to create non-child modal window."); + _config.flags |= child ? flags_child : flags_none; + _config.flags |= modal ? flags_modal : flags_none; +} + +} + diff --git a/source/platform/linux/platform.cpp b/source/platform/linux/platform.cpp new file mode 100644 index 0000000..8390dc3 --- /dev/null +++ b/source/platform/linux/platform.cpp @@ -0,0 +1,98 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#include + +#include + +#ifdef FENNEC_LIB_WAYLAND +#include +#include +#endif + +namespace fennec +{ + +using namespace wayland; + +linux_platform::linux_platform(user _type) + : platform(_type) + , _display_driver(display_none) { + switch (_type) { + case user::client: { + _runtime_client_checks(); + return; + } + case user::server: { + _runtime_server_checks(); + } + } +} + +linux_platform::~linux_platform() { + +} + +shared_object* linux_platform::load_object(const cstring& file) { + void* handle = dlopen(file, RTLD_NOW | RTLD_LOCAL); + const char* load_error = dlerror(); + assert(handle != nullptr, load_error); + return static_cast(handle); +} + +void linux_platform::unload_object(shared_object* obj) { + if (obj) { + dlclose(obj); + } +} + +platform::function_pointer linux_platform::find_symbol(shared_object* hndl, const cstring& name) { + string _name = name; + void* symbol = dlsym(hndl, _name); + if (symbol == nullptr) { + _name = '_' + _name; + symbol = dlsym(hndl, _name); + } + return (function_pointer)symbol; +} + +display* linux_platform::get_display() { + return _display; +} + +void linux_platform::_runtime_client_checks() { +#ifdef FENNEC_LIB_WAYLAND + if (wayland::load_symbols(this)) { + _display_driver = display_wayland; + _display = new wayland_display(this); + wayland::unload_symbols(this); // Doesn't actually unload symbols, just resets ref counter to only consider + // the created display + } +#endif + assertf(_display != nullptr, "failed to find suitable display driver"); +} + +void linux_platform::_find_display_driver() { + +} + +void linux_platform::_runtime_server_checks() { + +} + +} diff --git a/source/platform/linux/wayland/display.cpp b/source/platform/linux/wayland/display.cpp new file mode 100644 index 0000000..c8ff5c3 --- /dev/null +++ b/source/platform/linux/wayland/display.cpp @@ -0,0 +1,58 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#include +#include +#include + +namespace fennec +{ + +namespace wayland +{ + +wayland_display::wayland_display(linux_platform* platform) + : display() + , _handle() + , _platform(platform) { + load_symbols(_platform); + _handle = wl_display_connect(nullptr); +} + +wayland_display::wayland_display(linux_platform* platform, const cstring& drv) + : display() + , _handle() + , _platform(platform) { + load_symbols(_platform); + _handle = wl_display_connect(nullptr); +} + +wayland_display::~wayland_display() { + wl_display_disconnect(_handle); + unload_symbols(_platform); + _handle = nullptr; + _platform = nullptr; +} + +bool wayland_display::connected() const { + return _handle != nullptr; +} + +} + +} \ No newline at end of file diff --git a/source/platform/linux/wayland/lib/dyn.cpp b/source/platform/linux/wayland/lib/dyn.cpp new file mode 100644 index 0000000..b3d18bb --- /dev/null +++ b/source/platform/linux/wayland/lib/dyn.cpp @@ -0,0 +1,69 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#include +#include + +namespace fennec +{ + +namespace wayland +{ + +using shared_lib = platform::shared_lib; + +static int _load_count = 0; + +// Create private variables +#define FENNEC_LIB(lib) static shared_lib _FENNEC_LIB_##lib = { nullptr, FENNEC_LIB_##lib }; +#define FENNEC_SYMBOL(...) +#include + +bool load_symbols(linux_platform* platform) { + if (_load_count++ != 0) { + return true; + } + +#define FENNEC_LIB(lib) _FENNEC_LIB_##lib._lib = platform->load_object(_FENNEC_LIB_##lib._name); \ + FENNEC_HAS_LIB_##lib = _FENNEC_LIB_##lib._lib != nullptr; \ + if(not FENNEC_HAS_LIB_##lib) { \ + unload_symbols(platform); \ + return false; \ + } \ + shared_lib& current_lib = _FENNEC_LIB_##lib; +#define FENNEC_SYMBOL(ret, fn, ...) fn = (sym_##fn)(platform->find_symbol(current_lib._lib, #fn)); +#include + + return true; +} + +void unload_symbols(linux_platform* platform) { + if (--_load_count != 0) { + return; + } + +#define FENNEC_LIB(lib) platform->unload_object(_FENNEC_LIB_##lib._lib); \ + _FENNEC_LIB_##lib._lib = nullptr; +#define FENNEC_SYMBOL(ret, fn, ...) fn = nullptr; +#include +} + + +} + +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9483079..6a53127 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -27,6 +27,12 @@ add_executable(fennec-test main.cpp printing.h tests/math/test_ext.h tests/math/ext/test_quaternion.h + tests/platform/linux/test_wayland.h + tests/platform/test_linux.h + tests/test_platform.h + tests/lang/test_hashing.h + tests/containers/test_array.h + tests/containers/test_set.h ) target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}" diff --git a/test/main.cpp b/test/main.cpp index 16f4308..e661d7f 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -23,7 +23,9 @@ #include "tests/test_memory.h" #include "test.h" +#include "tests/test_containers.h" #include "tests/test_fproc.h" +#include "tests/test_platform.h" int main(int, char **) @@ -37,6 +39,11 @@ int main(int, char **) fennec::test::fennec_test_lang(); fennec_test_spacer(3); + fennec_test_header("containers library"); + fennec_test_spacer(2); + fennec::test::fennec_test_containers(); + fennec_test_spacer(3); + fennec_test_header("math library"); fennec_test_spacer(2); fennec::test::fennec_test_math(); @@ -47,5 +54,10 @@ int main(int, char **) fennec::test::fennec_test_fproc(); fennec_test_spacer(3); + fennec_test_header("platform library"); + fennec_test_spacer(2); + fennec::test::fennec_test_platform(); + fennec_test_spacer(3); + return 0; } diff --git a/test/test.h b/test/test.h index 063b6a4..441f166 100644 --- a/test/test.h +++ b/test/test.h @@ -73,7 +73,7 @@ inline void __fennec_test_run(const std::string& expression, const ResultT& resu std::cout << std::endl; // Assert to halt and get some debug info - assert(passed, "Test Failed"); + assertf(passed, "Test Failed"); } } diff --git a/test/tests/containers/test_array.h b/test/tests/containers/test_array.h new file mode 100644 index 0000000..89c3ba9 --- /dev/null +++ b/test/tests/containers/test_array.h @@ -0,0 +1,49 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_CONTAINERS_ARRAY_H +#define FENNEC_TEST_CONTAINERS_ARRAY_H + +#include "../../test.h" + +#include + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_containers_array() { + + const char string[] = "Hello World!"; + array arr1; + array arr2; + strcpy(&arr1[0], string); + strcpy(&arr2[0], string); + + fennec_test_run(strcmp(&arr1[0], string), 0); + fennec_test_run(strcmp(&arr2[0], string), 0); + fennec_test_run(arr1 == arr2, true); +} + +} + +} + +#endif // FENNEC_TEST_CONTAINERS_ARRAY_H diff --git a/test/tests/containers/test_dynarray.h b/test/tests/containers/test_dynarray.h new file mode 100644 index 0000000..b82e0f8 --- /dev/null +++ b/test/tests/containers/test_dynarray.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_CONTAINERS_DYNARRAY_H +#define FENNEC_TEST_CONTAINERS_DYNARRAY_H + +#include "../../test.h" + +#include + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_containers_dynarray() { + + dynarray test1; + dynarray test2; + + int n = 10000; + test1.resize(n); test2.resize(n); + for (int i = 0; i < n; ++i) { + test1.push_back(i); + test2.push_back(n - i - 1); + } + + for (int i = 0; i < n; ++i) { + assertf(test1[i] == test2[n - i - 1], "Failed dynarray::push_back"); + } + + std::cout << "passed" << std::endl; +} + +} + +} + +#endif // FENNEC_TEST_CONTAINERS_DYNARRAY_H diff --git a/test/tests/containers/test_optional.h b/test/tests/containers/test_optional.h new file mode 100644 index 0000000..a5fe1f0 --- /dev/null +++ b/test/tests/containers/test_optional.h @@ -0,0 +1,124 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_CONTAINERS_OPTIONAL_H +#define FENNEC_TEST_CONTAINERS_OPTIONAL_H + +#include "../../test.h" + +#include + +namespace fennec +{ + +namespace test +{ + +enum opt_test_ : uint8_t { + opt_test_none = 0x1 << 0, + opt_test_default_constructor = 0x1 << 1, + opt_test_destructor = 0x1 << 2, + opt_test_copy_constructor = 0x1 << 3, + opt_test_move_constructor = 0x1 << 4, + opt_test_copy_assignment = 0x1 << 5, + opt_test_move_assignment = 0x1 << 6, +}; + +struct optional_helper { + + inline static uint8_t test = opt_test_none; + + optional_helper() : i(0) { + fennec_test_run(bool(test & opt_test_default_constructor), true); + } + + ~optional_helper() { + fennec_test_run(bool(test & opt_test_destructor), true); + } + + optional_helper(const optional_helper&) : i(0) { + fennec_test_run(bool(test & opt_test_copy_constructor), true); + } + + optional_helper(optional_helper&&) noexcept : i(0) { + fennec_test_run(bool(test & opt_test_move_constructor), true); + } + + optional_helper& operator=(const optional_helper&) { + fennec_test_run(bool(test & opt_test_copy_assignment), true); + return *this; + } + + optional_helper& operator=(optional_helper&&) noexcept { + fennec_test_run(bool(test & opt_test_move_assignment), true); + return *this; + } + + int i; +}; + +inline void fennec_test_containers_optional() { + static_assert( + is_default_constructible_v + and is_copy_constructible_v + and is_move_constructible_v + and is_copy_assignable_v + and is_move_assignable_v + ); + + optional opt = optional(); + + optional_helper::test = opt_test_default_constructor; + opt.emplace(); + + optional_helper::test = opt_test_destructor; + opt.reset(); + + optional_helper::test = opt_test_default_constructor | opt_test_copy_constructor | opt_test_destructor; + opt = copy(optional_helper()); + + optional_helper::test = opt_test_destructor; + opt.reset(); + + optional_helper::test = opt_test_default_constructor | opt_test_move_constructor | opt_test_destructor; + opt = optional_helper(); + + optional_helper::test = opt_test_destructor; + opt.reset(); + + optional_helper::test = opt_test_default_constructor; + opt.emplace(); + + optional_helper::test = opt_test_default_constructor | opt_test_copy_assignment | opt_test_destructor; + opt = copy(optional_helper()); + + optional_helper::test = opt_test_default_constructor | opt_test_move_assignment | opt_test_destructor; + opt = optional_helper(); + + optional_helper::test = opt_test_destructor; + opt.reset(); + + std::cout << opt << std::endl; + std::cout << "passed" << std::endl; +} + +} + +} + +#endif // FENNEC_TEST_CONTAINERS_OPTIONAL_H diff --git a/test/tests/containers/test_set.h b/test/tests/containers/test_set.h new file mode 100644 index 0000000..8747404 --- /dev/null +++ b/test/tests/containers/test_set.h @@ -0,0 +1,58 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_CONTAINERS_SET_H +#define FENNEC_TEST_CONTAINERS_SET_H + +#include "../../test.h" + +#include +#include +#include + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_containers_set() { + + using type_t = decltype(rand()); + std::unordered_set ref; + set test; + + srand(0); + for (int i = 0; i < 10000; ++i) { + type_t v = rand(); + ref.insert(v); + test.insert(v); + } + + for (int i = 0; i < 10000; ++i) { + assertf(ref.contains(i) == test.contains(i), "set test failed"); + } + + std::cout << "passed" << std::endl; +} + +} + +} + +#endif // FENNEC_TEST_CONTAINERS_SET_H diff --git a/test/tests/fproc/strings/test_cstring.h b/test/tests/fproc/strings/test_cstring.h index 0eb8055..ad5f91f 100644 --- a/test/tests/fproc/strings/test_cstring.h +++ b/test/tests/fproc/strings/test_cstring.h @@ -47,8 +47,6 @@ inline void fennec_test_fproc_strings_cstring() fennec_test_run(str.rfind('o'), static_cast(7)); fennec_test_run(str.rfind("World"), static_cast(6)); - fennec_test_spacer(2); - } } diff --git a/test/tests/fproc/test_io.h b/test/tests/fproc/test_io.h index cedd5dd..8842b43 100644 --- a/test/tests/fproc/test_io.h +++ b/test/tests/fproc/test_io.h @@ -88,8 +88,6 @@ inline void fennec_test_fproc_io() { fennec_test_run(file::cout().write("Hello World!"), sizeof("Hello World!")); fennec_test_run(file::cerr().write("Hello World!"), sizeof("Hello World!")); - fennec_test_spacer(2); - } } diff --git a/test/tests/fproc/test_strings.h b/test/tests/fproc/test_strings.h index 925871b..61786e2 100644 --- a/test/tests/fproc/test_strings.h +++ b/test/tests/fproc/test_strings.h @@ -35,6 +35,7 @@ inline void fennec_test_fproc_strings() fennec_test_fproc_strings_cstring(); fennec_test_spacer(3); + // TODO } } diff --git a/test/tests/lang/test_bits.h b/test/tests/lang/test_bits.h index 0fa61ab..0216256 100644 --- a/test/tests/lang/test_bits.h +++ b/test/tests/lang/test_bits.h @@ -30,7 +30,7 @@ namespace fennec namespace test { -void fennec_test_lang_bits() +inline void fennec_test_lang_bits() { int a = 0x48ef13ad; int b = 0x23e5ab9c; diff --git a/test/tests/lang/test_hashing.h b/test/tests/lang/test_hashing.h new file mode 100644 index 0000000..04b5ed3 --- /dev/null +++ b/test/tests/lang/test_hashing.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_LANG_HASHING_H +#define FENNEC_TEST_LANG_HASHING_H + +#include +#include "../../test.h" + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_lang_hashing() { + + size_t num = 61; + float_t numf = bit_cast((uint32_t)num); + double_t numd = bit_cast(num); + size_t exp = hash()(num); + + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + fennec_test_run(hash()(num), exp); + + fennec_test_spacer(1); + + fennec_test_run(hash()(numf), exp); + fennec_test_run(hash()(numd), exp); +} + +} + +} + +#endif // FENNEC_TEST_LANG_HASHING_H diff --git a/test/tests/lang/test_sequences.h b/test/tests/lang/test_sequences.h index 4055058..4e97a9d 100644 --- a/test/tests/lang/test_sequences.h +++ b/test/tests/lang/test_sequences.h @@ -32,6 +32,8 @@ inline void test_sequences() static_assert(fennec::is_same_v, index_sequence<0, 1>>); static_assert(fennec::is_same_v, index_sequence<0, 1, 2>>); static_assert(fennec::is_same_v, index_sequence<0, 1, 2, 3>>); + + // TODO } } diff --git a/test/tests/math/ext/test_quaternion.h b/test/tests/math/ext/test_quaternion.h index 6be1706..558e16b 100644 --- a/test/tests/math/ext/test_quaternion.h +++ b/test/tests/math/ext/test_quaternion.h @@ -38,6 +38,8 @@ inline void fennec_test_math_quaternion() { fennec_test_run(quat(), quat(1, 0, 0, 0)); fennec_test_spacer(2); + + // TODO } } diff --git a/test/tests/math/test_common.h b/test/tests/math/test_common.h index 61ce8b3..8c50cb9 100644 --- a/test/tests/math/test_common.h +++ b/test/tests/math/test_common.h @@ -208,9 +208,6 @@ inline void fennec_test_math_common() fennec_test_run(mix(0.0f, 1.0f, false), 0.0f); fennec_test_run(mix(0.0f, 1.0f, true), 1.0f); - - fennec_test_spacer(2); - } } diff --git a/test/tests/math/test_exponential.h b/test/tests/math/test_exponential.h index 646de5b..6b7c455 100644 --- a/test/tests/math/test_exponential.h +++ b/test/tests/math/test_exponential.h @@ -75,9 +75,6 @@ inline void fennec_test_math_exponential() fennec_test_run(fennec::inversesqrt(1.0f), 1.0f / 1.0f); fennec_test_run(fennec::inversesqrt(4.0f), 1.0f / 2.0f); fennec_test_run(fennec::inversesqrt(9.0f), 1.0f / 3.0f); - - fennec_test_spacer(2); - } } diff --git a/test/tests/math/test_ext.h b/test/tests/math/test_ext.h index 14c5cb6..c48d8cb 100644 --- a/test/tests/math/test_ext.h +++ b/test/tests/math/test_ext.h @@ -36,6 +36,7 @@ inline void fennec_test_math_ext() { fennec_test_math_quaternion(); fennec_test_spacer(3); + // TODO } } diff --git a/test/tests/math/test_geometric.h b/test/tests/math/test_geometric.h index 94e3c23..9aa6b1f 100644 --- a/test/tests/math/test_geometric.h +++ b/test/tests/math/test_geometric.h @@ -77,9 +77,6 @@ inline void fennec_test_math_geometric() fennec_test_run(fennec::reflect(vec2(1, -1), vec2(0, 1)), vec2(1, 1)); fennec_test_run(fennec::refract(vec2(1, -1), vec2(0, 1), 1/1.33f), vec2(0.7518797, -1)); - - fennec_test_spacer(2); - } } diff --git a/test/tests/math/test_matrix.h b/test/tests/math/test_matrix.h index 04fd859..0ca803e 100644 --- a/test/tests/math/test_matrix.h +++ b/test/tests/math/test_matrix.h @@ -320,8 +320,6 @@ inline void fennec_test_math_matrix() fennec_test_run(fennec::inverse(mat2(1, 2, 3, 4)), mat2(-2, 1, 1.5, -0.5)); fennec_test_run(fennec::inverse(mat3(1, 2, 3, 0, 1, 4, 5, 6, 0)), mat3(-24, 18, 5, 20, -15, -4, -5, 4, 1)); fennec_test_run(fennec::inverse(mat4(2, 1, -3, 4, -1, 0, 2, 5, 3, 2, 1, 0, 4, -2, 3, 1)), (1.0f / 414.0f) * mat4(36, -39, 33, 51, -18, 31, 133, -83, -72, 55, 49, 13, 36, 53, -13, 5)); - - fennec_test_spacer(2); } } diff --git a/test/tests/math/test_relational.h b/test/tests/math/test_relational.h index 5a18d4a..4935d79 100644 --- a/test/tests/math/test_relational.h +++ b/test/tests/math/test_relational.h @@ -45,8 +45,6 @@ inline void fennec_test_math_relational() fennec_test_run(not(bvec3(true, false, true)), bvec3(false, true, false)); fennec_test_run(fennec::all(bvec3(true, true, true)), true); - - fennec_test_spacer(2); } } diff --git a/test/tests/math/test_trigonometric.h b/test/tests/math/test_trigonometric.h index d2da391..433cd59 100644 --- a/test/tests/math/test_trigonometric.h +++ b/test/tests/math/test_trigonometric.h @@ -112,11 +112,6 @@ inline void fennec_test_math_trigonometric() fennec_test_run(fennec::asinh((fennec::e() - fennec::one_over_e()) / 2.0f), 1.0f); fennec_test_run(fennec::acosh((fennec::e() + fennec::one_over_e()) / 2.0f), 1.0f); fennec_test_run(fennec::atanh(((fennec::e_raised_two() - 1) / (fennec::e_raised_two() + 1))), 1.0f); - - - fennec_test_spacer(2); - - } } diff --git a/test/tests/math/test_vector.h b/test/tests/math/test_vector.h index e876fdf..e11fc1e 100644 --- a/test/tests/math/test_vector.h +++ b/test/tests/math/test_vector.h @@ -594,8 +594,6 @@ inline void fennec_test_math_vector() fennec_test_run(([]() -> ivec2 { ivec2 v(0x2A1E, 0x7BF3); return v >>= ivec2(4, 8); }()), ivec2(0x2A1, 0x7B)); fennec_test_run(([]() -> ivec3 { ivec3 v(0x2A1E, 0x7BF3, 0x3927); return v >>= ivec3(4, 8, 12); }()), ivec3(0x2A1, 0x7B, 0x3)); fennec_test_run(([]() -> ivec4 { ivec4 v(0x2A1E, 0x7BF3, 0x3927, 0x237C); return v >>= ivec4(4, 8, 12, 16); }()), ivec4(0x2A1, 0x7B, 0x3, 0x0)); - - } } diff --git a/test/tests/platform/linux/test_wayland.h b/test/tests/platform/linux/test_wayland.h new file mode 100644 index 0000000..f6820c0 --- /dev/null +++ b/test/tests/platform/linux/test_wayland.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_PLATFORM_LINUX_WAYLAND_H +#define FENNEC_TEST_PLATFORM_LINUX_WAYLAND_H + +#include "../../../test.h" +#include + +namespace fennec +{ + +namespace test +{ + +using namespace wayland; + +inline void fennec_test_platform_linux_wayland(linux_platform& platform) { + + wayland_display* display = static_cast(platform.get_display()); + fennec_test_run(display != nullptr, true); +} + +} + +} + +#endif // FENNEC_TEST_PLATFORM_LINUX_WAYLAND_H diff --git a/test/tests/platform/test_linux.h b/test/tests/platform/test_linux.h new file mode 100644 index 0000000..1ade79e --- /dev/null +++ b/test/tests/platform/test_linux.h @@ -0,0 +1,51 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_PLATFORM_LINUX_H +#define FENNEC_TEST_PLATFORM_LINUX_H +#include "../../test.h" + +#ifdef FENNEC_LIB_WAYLAND +#include "linux/test_wayland.h" +#endif + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_platform_linux() { + + linux_platform platform(platform::user::client); + +#ifdef FENNEC_LIB_WAYLAND + fennec_test_section("wayland tests"); + fennec_test_spacer(2); + fennec_test_platform_linux_wayland(platform); + fennec_test_spacer(3); +#endif + + // TODO +} + +} + +} + +#endif // FENNEC_TEST_PLATFORM_LINUX_H diff --git a/test/tests/test_containers.h b/test/tests/test_containers.h new file mode 100644 index 0000000..758700b --- /dev/null +++ b/test/tests/test_containers.h @@ -0,0 +1,61 @@ +// ===================================================================================================================== +// fennec-test, a program to execute unit tests for fennec +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_CONTAINERS_H +#define FENNEC_TEST_CONTAINERS_H + +#include "containers/test_array.h" +#include "containers/test_dynarray.h" +#include "containers/test_optional.h" +#include "containers/test_set.h" + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_containers() +{ + fennec_test_subheader("optional tests"); + fennec_test_spacer(2); + fennec_test_containers_optional(); + fennec_test_spacer(3); + + fennec_test_subheader("array tests"); + fennec_test_spacer(2); + fennec_test_containers_array(); + fennec_test_spacer(3); + + fennec_test_subheader("dynarray tests"); + fennec_test_spacer(2); + fennec_test_containers_dynarray(); + fennec_test_spacer(3); + + fennec_test_subheader("set tests"); + fennec_test_spacer(2); + fennec_test_containers_set(); + + // TODO +} + +} + +} + +#endif // FENNEC_TEST_CONTAINERS_H diff --git a/test/tests/test_fproc.h b/test/tests/test_fproc.h index 1dd1c2e..eb32f42 100644 --- a/test/tests/test_fproc.h +++ b/test/tests/test_fproc.h @@ -40,6 +40,8 @@ inline void fennec_test_fproc() { fennec_test_spacer(2); fennec_test_fproc_io(); fennec_test_spacer(3); + + // TODO } } diff --git a/test/tests/test_lang.h b/test/tests/test_lang.h index b125832..aca0428 100644 --- a/test/tests/test_lang.h +++ b/test/tests/test_lang.h @@ -21,6 +21,7 @@ #include "lang/test_bits.h" #include "lang/test_conditional_types.h" +#include "lang/test_hashing.h" namespace fennec { @@ -34,6 +35,12 @@ inline void fennec_test_lang() fennec_test_spacer(2); fennec_test_lang_bits(); fennec_test_spacer(3); + + fennec_test_subheader("hashing tests"); + fennec_test_spacer(2); + fennec_test_lang_hashing(); + + // TODO } } diff --git a/test/tests/test_math.h b/test/tests/test_math.h index 273bd98..5b3419f 100644 --- a/test/tests/test_math.h +++ b/test/tests/test_math.h @@ -83,6 +83,8 @@ inline void fennec_test_math() fennec_test_spacer(2); fennec_test_math_ext(); fennec_test_spacer(3); + + // TODO } } diff --git a/test/tests/test_memory.h b/test/tests/test_memory.h index 45a1eb6..218bd20 100644 --- a/test/tests/test_memory.h +++ b/test/tests/test_memory.h @@ -19,4 +19,6 @@ #ifndef FENNEC_TEST_MEMORY_H #define FENNEC_TEST_MEMORY_H +// TODO + #endif // FENNEC_TEST_MEMORY_H diff --git a/test/tests/test_platform.h b/test/tests/test_platform.h new file mode 100644 index 0000000..e651fef --- /dev/null +++ b/test/tests/test_platform.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_TEST_PLATFORM_H +#define FENNEC_TEST_PLATFORM_H +#include "../test.h" + +#if FENNEC_PLATFORM_LINUX +#include "./platform/test_linux.h" +#endif + +namespace fennec +{ + +namespace test +{ + +inline void fennec_test_platform() { +#if FENNEC_PLATFORM_LINUX + fennec_test_subheader("linux"); + fennec_test_spacer(2); + fennec_test_platform_linux(); + fennec_test_spacer(3); +#endif +} + +} + +} + +#endif // FENNEC_TEST_PLATFORM_H