- More Documentation

- Vulkan Configuration Implementations
 - Fixed build errors on GCC and Clang
This commit is contained in:
2026-07-18 23:48:00 -04:00
parent ed381c4178
commit cf909624df
164 changed files with 19857 additions and 5872 deletions

View File

@@ -88,7 +88,6 @@ fennec_add_sources(
include/fennec/core/logger.h source/core/logger.cpp include/fennec/core/logger.h source/core/logger.cpp
include/fennec/core/version.h include/fennec/core/version.h
include/fennec/core/system.h
@@ -150,12 +149,14 @@ fennec_add_sources(
include/fennec/lang/declval.h include/fennec/lang/declval.h
include/fennec/lang/function.h include/fennec/lang/function.h
include/fennec/lang/hashing.h include/fennec/lang/hashing.h
include/fennec/lang/integer.h
include/fennec/lang/intrinsics.h include/fennec/lang/intrinsics.h
include/fennec/lang/limits.h include/fennec/lang/limits.h
include/fennec/lang/numeric_transforms.h include/fennec/lang/numeric_transforms.h
include/fennec/lang/metasequences.h include/fennec/lang/metasequences.h
include/fennec/lang/ranges.h include/fennec/lang/ranges.h
include/fennec/lang/static_constructor.h include/fennec/lang/static_constructor.h
include/fennec/lang/system.h
include/fennec/lang/type_identity.h include/fennec/lang/type_identity.h
include/fennec/lang/type_operators.h include/fennec/lang/type_operators.h
include/fennec/lang/type_sequences.h include/fennec/lang/type_sequences.h
@@ -163,7 +164,6 @@ fennec_add_sources(
include/fennec/lang/type_transforms.h include/fennec/lang/type_transforms.h
include/fennec/lang/types.h include/fennec/lang/types.h
include/fennec/lang/utility.h include/fennec/lang/utility.h
include/fennec/lang/integer.h
include/fennec/lang/assert.h source/lang/assert.cpp include/fennec/lang/assert.h source/lang/assert.cpp
@@ -179,14 +179,15 @@ fennec_add_sources(
# RTTI ================================================================================================================= # RTTI =================================================================================================================
include/fennec/rtti/typeid.h
include/fennec/rtti/type_data.h
include/fennec/rtti/type.h
include/fennec/rtti/enable.h
include/fennec/rtti/forward.h include/fennec/rtti/forward.h
include/fennec/rtti/typelist.h include/fennec/rtti/enable.h
include/fennec/rtti/type_registry.h
include/fennec/rtti/singleton.h include/fennec/rtti/singleton.h
include/fennec/rtti/this_t.h
include/fennec/rtti/type.h
include/fennec/rtti/type_data.h
include/fennec/rtti/type_registry.h
include/fennec/rtti/typeid.h
include/fennec/rtti/typelist.h
include/fennec/rtti/detail/_constants.h include/fennec/rtti/detail/_constants.h
@@ -268,6 +269,7 @@ fennec_add_sources(
include/fennec/string/locale.h include/fennec/string/locale.h
include/fennec/string/cstring.h include/fennec/string/cstring.h
include/fennec/string/string.h include/fennec/string/string.h
include/fennec/string/string_view.h
include/fennec/string/detail/_ctype.h include/fennec/string/detail/_ctype.h
@@ -314,7 +316,9 @@ add_subdirectory(test)
add_library(fennec STATIC add_library(fennec STATIC
${FENNEC_SOURCES} ${FENNEC_SOURCES}
include/fennec/rtti/this_t.h include/fennec/renderers/vulkan/lib/logical_device.h
include/fennec/renderers/vulkan/lib/physical_device_properties.h
include/fennec/renderers/vulkan/lib/physical_device_features.h
) )
add_dependencies(fennec metaprogramming fennec-dependencies) add_dependencies(fennec metaprogramming fennec-dependencies)

View File

@@ -155,7 +155,6 @@ is also a viable IDE but involves some extra setup.
|------------------------------|----------------------------------------------------------------------------------------------------------| |------------------------------|----------------------------------------------------------------------------------------------------------|
| C/C++ Compiler | GCC/G++ is the compiler that fennec is designed around, however, Clang, MSVC, and MinGW may also be used | | C/C++ Compiler | GCC/G++ is the compiler that fennec is designed around, however, Clang, MSVC, and MinGW may also be used |
| CMake | The build manager used by the engine | | CMake | The build manager used by the engine |
| Volk<sup>[*](#opt)</sup> | The Vulkan loader Volk, includes necessary headers for Vulkan. |
| A build system | Any build system will work, however, `build.sh` uses Ninja by default. | | A build system | Any build system will work, however, `build.sh` uses Ninja by default. |
| A memory debugger | Any memory debugger will work, however, `test.sh` uses Valgrind by default. | | A memory debugger | Any memory debugger will work, however, `test.sh` uses Valgrind by default. |
| Doxygen<sup>[*](#opt)</sup> | Doxygen is required for building the documentation for fennec. | | Doxygen<sup>[*](#opt)</sup> | Doxygen is required for building the documentation for fennec. |

View File

@@ -18,11 +18,22 @@
# this script handles functionality related to the build process and its info # this script handles functionality related to the build process and its info
# Acquire the build name
string(TOLOWER ${CMAKE_BUILD_TYPE} FENNEC_BUILD_NAME) string(TOLOWER ${CMAKE_BUILD_TYPE} FENNEC_BUILD_NAME)
message(STATUS "Build: ${FENNEC_BUILD_NAME}") message(STATUS "Build: ${FENNEC_BUILD_NAME}")
# Add build name to the compile definitions
fennec_add_definitions(FENNEC_BUILD_NAME="${FENNEC_BUILD_NAME}")
# Check if building for debug
if(${FENNEC_BUILD_NAME} MATCHES "debug") if(${FENNEC_BUILD_NAME} MATCHES "debug")
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=false) fennec_add_definitions(FENNEC_RELEASE=false FENNEC_DEBUG=true)
# Release with debug info
elseif(${FENNEC_BUILD_NAME} MATCHES "relwithdebinfo")
fennec_add_definitions(FENNEC_RELEASE=true FENNEC_DEBUG=true)
# Any others are considered release without debugging
else() else()
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=true) fennec_add_definitions(FENNEC_RELEASE=true FENNEC_DEBUG=false)
endif() endif()

38
cmake/clang.cmake Normal file
View File

@@ -0,0 +1,38 @@
# ======================================================================================================================
# fennec, a free and open source game engine
# Copyright © 2025 - 2026 Medusa Slockbower
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ======================================================================================================================
# this script sets flags and variables for llvm compilers
# Receive all warnings and treat as errors
add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions")
# Use relative directories to hide the user's directory
fennec_add_compile_options("-ffile-prefix-map=${FENNEC_SOURCE_DIR}=.")
# Disable STDLIB, Exceptions, and RTTI, we implement our own. Also include diagnostics and pthread.
fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates" "-pthread")
# Base definitions for Clang
fennec_add_definitions(
_GLIBCXX_INCLUDE_NEXT_C_HEADERS=1
FENNEC_COMPILER_CLANG=1
FENNEC_GLIBC=1
FENNEC_NO_INLINE=[[clang::noinline]]
FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__
)

View File

@@ -18,13 +18,27 @@
# this script finds the compiler being used # this script finds the compiler being used
# Send a message letting us know the compiler and its version
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
# Add definitions for the compiler
fennec_add_definitions( fennec_add_definitions(
FENNEC_LONG_COMPILER_NAME="${CMAKE_CXX_COMPILER_ID} ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR}" FENNEC_LONG_COMPILER_NAME="${CMAKE_CXX_COMPILER_ID} ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR}"
) )
# GCC
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set(FENNEC_COMPILER "GCC") set(FENNEC_COMPILER "GCC")
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake") include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")
endif() endif()
# Clang
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(FENNEC_COMPILER "Clang")
include("${FENNEC_SOURCE_DIR}/cmake/clang.cmake")
endif()
# TODO: MSVC & MinGW

View File

@@ -18,15 +18,20 @@
# this script sets flags and variables for gnu and gnu-like compilers # this script sets flags and variables for gnu and gnu-like compilers
# Receive all warnings and treat as errors
add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions") add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions")
# Use relative directories to hide the user's directory
fennec_add_compile_options("-ffile-prefix-map=${FENNEC_SOURCE_DIR}=.") fennec_add_compile_options("-ffile-prefix-map=${FENNEC_SOURCE_DIR}=.")
# Disable STDLIB, Exceptions, and RTTI, we implement our own. Also include diagnostics and pthread.
fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates" "-pthread") fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates" "-pthread")
# Base definitions for GCC
fennec_add_definitions( fennec_add_definitions(
_GLIBCXX_INCLUDE_NEXT_C_HEADERS=1 _GLIBCXX_INCLUDE_NEXT_C_HEADERS=1
FENNEC_COMPILER_GCC=1 FENNEC_COMPILER_GCC=1
FENNEC_GLIBC=1
FENNEC_NO_INLINE=[[gnu::noinline]] FENNEC_NO_INLINE=[[gnu::noinline]]
FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__ FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__
) )

View File

@@ -33,9 +33,11 @@ macro(fennec_check_platform)
include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp
) )
# Add display and graphics for client builds.
if(FENNEC_USER_CLIENT) if(FENNEC_USER_CLIENT)
include("${FENNEC_SOURCE_DIR}/cmake/wayland.cmake") include("${FENNEC_SOURCE_DIR}/cmake/wayland.cmake")
fennec_init_graphics()
fennec_check_wayland() fennec_check_wayland()
fennec_init_graphics() fennec_init_graphics()
endif() endif()

View File

@@ -18,9 +18,10 @@
find_package(OpenGL) find_package(OpenGL)
# Check if EGL is desired
if(FENNEC_GRAPHICS_WANT_EGL) if(FENNEC_GRAPHICS_WANT_EGL)
fennec_add_sources( fennec_add_sources(
include/fennec/platform/opengl/egl/fwd.h include/fennec/platform/opengl/egl/forward.h
include/fennec/platform/opengl/egl/error.h include/fennec/platform/opengl/egl/error.h
include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp
include/fennec/platform/opengl/egl/surface.h source/platform/opengl/egl/surface.cpp include/fennec/platform/opengl/egl/surface.h source/platform/opengl/egl/surface.cpp
@@ -29,15 +30,24 @@ if(FENNEC_GRAPHICS_WANT_EGL)
) )
endif() endif()
# Check that we found OpenGL
if(TARGET OpenGL::GL) if(TARGET OpenGL::GL)
# Link & add definitions for OpenGL
fennec_add_link_libraries(OpenGL::GL) fennec_add_link_libraries(OpenGL::GL)
fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1) fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1)
# Cmake Definition for OpenGL detection
set(FENNEC_FOUND_OPENGL TRUE)
# Add OpenGL sources
fennec_add_sources( fennec_add_sources(
include/fennec/platform/opengl/glad/gl.h source/platform/opengl/glad/gl.c include/fennec/platform/opengl/glad/gl.h source/platform/opengl/glad/gl.c
include/fennec/renderers/opengl/glcontext.h source/renderers/opengl/glcontext.cpp include/fennec/renderers/opengl/glcontext.h source/renderers/opengl/glcontext.cpp
) )
else() else()
# OpenGL is required if included.
message(FATAL_ERROR "No Suitable OpenGL implementation found.") message(FATAL_ERROR "No Suitable OpenGL implementation found.")
endif() endif()

View File

@@ -28,7 +28,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
include("${FENNEC_SOURCE_DIR}/cmake/linux.cmake") include("${FENNEC_SOURCE_DIR}/cmake/linux.cmake")
endif () endif ()
# Graphics APIs # Include graphics APIs Second time for any platform specific requirements
macro(fennec_init_graphics) macro(fennec_init_graphics)
include("${FENNEC_SOURCE_DIR}/cmake/opengl.cmake") include("${FENNEC_SOURCE_DIR}/cmake/opengl.cmake")
include("${FENNEC_SOURCE_DIR}/cmake/vulkan.cmake") include("${FENNEC_SOURCE_DIR}/cmake/vulkan.cmake")

View File

@@ -18,12 +18,15 @@
# this script contains the main version # this script contains the main version
# Fennec Version Definition
# These should only get updated whenever a new release occurs
set(FENNEC_VERSION_MAJOR 0) set(FENNEC_VERSION_MAJOR 0)
set(FENNEC_VERSION_MINOR 1) set(FENNEC_VERSION_MINOR 1)
set(FENNEC_VERSION_PATCH 0) set(FENNEC_VERSION_PATCH 0)
set(FENNEC_VERSION_STRING "${FENNEC_VERSION_MAJOR}.${FENNEC_VERSION_MINOR}.${FENNEC_VERSION_PATCH}") set(FENNEC_VERSION_STRING "${FENNEC_VERSION_MAJOR}.${FENNEC_VERSION_MINOR}.${FENNEC_VERSION_PATCH}")
math(EXPR FENNEC_VERSION_NUM "(${FENNEC_VERSION_MAJOR} << 16) | (${FENNEC_VERSION_MINOR} << 8) | ${FENNEC_VERSION_PATCH}") math(EXPR FENNEC_VERSION_NUM "(${FENNEC_VERSION_MAJOR} << 16) | (${FENNEC_VERSION_MINOR} << 8) | ${FENNEC_VERSION_PATCH}")
# Define the versions for compilation
list(APPEND FENNEC_COMPILE_DEFINITIONS list(APPEND FENNEC_COMPILE_DEFINITIONS
FENNEC_VERSION_MAJOR=${FENNEC_VERSION_MAJOR} FENNEC_VERSION_MAJOR=${FENNEC_VERSION_MAJOR}
FENNEC_VERSION_MINOR=${FENNEC_VERSION_MINOR} FENNEC_VERSION_MINOR=${FENNEC_VERSION_MINOR}

View File

@@ -16,24 +16,41 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# ====================================================================================================================== # ======================================================================================================================
find_package(Vulkan COMPONENTS glslang volk) find_package(Vulkan COMPONENTS glslang)
# MoltenVK for Apple Products
if(FENNEC_GRAPHICS_WANT_MOLTENVK) if(FENNEC_GRAPHICS_WANT_MOLTENVK)
find_package(Vulkan COMPONENTS MoltenVK) find_package(Vulkan COMPONENTS MoltenVK)
endif() endif()
if( TARGET Vulkan::Headers AND TARGET Vulkan::volk # Base Headers and Meta-Loader
# Headers and Loaders
if( TARGET Vulkan::Headers # Base Headers and Meta-Loader
AND TARGET Vulkan::glslang # GLSL Compilation AND TARGET Vulkan::glslang # GLSL Compilation
AND (NOT FENNEC_GRAPHICS_WANT_MOLTENVK OR TARGET Vulkan::MoltenVK) AND (NOT FENNEC_GRAPHICS_WANT_MOLTENVK OR TARGET Vulkan::MoltenVK)
) )
fennec_add_link_libraries(Vulkan::volk Vulkan::glslang) # Link & Define Vulkan Libraries
fennec_add_link_libraries(Vulkan::glslang)
fennec_add_definitions(FENNEC_GRAPHICS_VULKAN=1) fennec_add_definitions(FENNEC_GRAPHICS_VULKAN=1)
fennec_add_sources( # Cmake Definition for Vulkan detection
include/fennec/renderers/vulkan/lib/app_info.h set(FENNEC_FOUND_VULKAN TRUE)
include/fennec/renderers/vulkan/lib/instance.h
include/fennec/renderers/vulkan/vkcontext.h include/fennec/renderers/vulkan/vkcontext.cpp # Add Vulkan Sources
fennec_add_sources(
include/fennec/renderers/vulkan/lib/forward.h
include/fennec/renderers/vulkan/lib/app_info.h
include/fennec/renderers/vulkan/lib/debug.h
include/fennec/renderers/vulkan/lib/enum.h
include/fennec/renderers/vulkan/lib/instance.h
include/fennec/renderers/vulkan/lib/physical_device.h
include/fennec/renderers/vulkan/lib/surface.h
include/fennec/platform/vulkan/volk/volk.h source/platform/vulkan/volk/volk.c
include/fennec/renderers/vulkan/vkcontext.h source/renderers/vulkan/vkcontext.cpp
include/fennec/renderers/vulkan/vksurface.h source/renderers/vulkan/vksurface.cpp
) )
else() else()
message(WARNING "No Suitable Vulkan implementation found.") message(WARNING "No Suitable Vulkan implementation found.")

View File

@@ -70,11 +70,12 @@ macro(fennec_check_wayland)
NAMES wayland-egl libwayland-egl NAMES wayland-egl libwayland-egl
) )
# Check that we have found everything needed for Wayland
if( (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY AND WAYLAND_SCANNER) if( (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY AND WAYLAND_SCANNER)
AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARY)) AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARY))
message(STATUS "Found Wayland: ${WAYLAND_CLIENT_LIBRARY}") message(STATUS "Found Wayland: ${WAYLAND_CLIENT_LIBRARY}")
# Wayland Directories
set(WAYLAND_PROTOCOLS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/protocols) set(WAYLAND_PROTOCOLS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/protocols)
set(WAYLAND_HEADERS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/headers) set(WAYLAND_HEADERS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/headers)
set(WAYLAND_SOURCES_DIR ${FENNEC_SOURCE_DIR}/source/platform/linux/wayland/lib/sources) set(WAYLAND_SOURCES_DIR ${FENNEC_SOURCE_DIR}/source/platform/linux/wayland/lib/sources)
@@ -117,7 +118,7 @@ macro(fennec_check_wayland)
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
# Fennec Files # Fennec Files
include/fennec/platform/linux/wayland/fwd.h include/fennec/platform/linux/wayland/forward.h
include/fennec/platform/linux/wayland/server.h source/platform/linux/wayland/server.cpp include/fennec/platform/linux/wayland/server.h source/platform/linux/wayland/server.cpp
include/fennec/platform/linux/wayland/window.h source/platform/linux/wayland/window.cpp include/fennec/platform/linux/wayland/window.h source/platform/linux/wayland/window.cpp
@@ -126,6 +127,12 @@ macro(fennec_check_wayland)
include/fennec/platform/linux/wayland/egl/surface.h source/platform/linux/wayland/egl/surface.cpp include/fennec/platform/linux/wayland/egl/surface.h source/platform/linux/wayland/egl/surface.cpp
) )
if(FENNEC_FOUND_VULKAN)
fennec_add_sources(
include/fennec/platform/linux/wayland/vulkan/context.h source/platform/linux/wayland/vulkan/context.cpp
)
endif ()
fennec_add_definitions( fennec_add_definitions(
FENNEC_HAS_WAYLAND=1 FENNEC_HAS_WAYLAND=1
FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}" FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"

View File

@@ -283,7 +283,8 @@ TAB_SIZE = 4
# with the commands \{ and \} for these it is advised to use the version @{ and # with the commands \{ and \} for these it is advised to use the version @{ and
# @} or use a double escape (\\{ and \\}) # @} or use a double escape (\\{ and \\})
ALIASES = ALIASES = emph{1}="\f$\textbf{\1}\f$" \
math{1}="\f$\1\f$"
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For # only. Doxygen will then generate output that is more tailored for C. For

View File

@@ -44,20 +44,19 @@ namespace fennec
/// \brief Data Structure that defines a compile-time allocated array /// \brief Data Structure that defines a compile-time allocated array
/// ///
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | ⛔ | /// | insertion | ⛔ |
/// | deletion | ⛔ | /// | deletion | ⛔ |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam ValueT value type /// \tparam ValueT value type
/// \tparam N number of elements /// \tparam N number of elements
@@ -70,7 +69,7 @@ public:
/// \name Definitions /// \name Definitions
/// @{ /// @{
using value_t = ValueT; //!< Alias for \f$ValueT\f$ using value_t = ValueT; //!< Alias for \emph{ValueT}
/// @} /// @}
@@ -96,21 +95,21 @@ public:
/// ///
/// \brief Returns the number of elements in the array. /// \brief Returns the number of elements in the array.
/// \returns \f$N\f$ /// \returns \emph{N}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
[[nodiscard]] constexpr size_t size() const { return N; } constexpr size_t size() const { return N; }
/// ///
/// \brief Returns \f$true\f$ when the array is empty /// \brief Returns \emph{true} when the array is empty
/// \returns \f$ElemV == 0\f$ /// \returns \math{\textbf{ElemV} == 0}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
[[nodiscard]] constexpr bool_t is_empty() const { return N == 0; } constexpr bool_t is_empty() const { return N == 0; }
/// @} /// @}
@@ -128,7 +127,7 @@ public:
/// \return reference to the requested element /// \return reference to the requested element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assertd(i < N, "Array Out of Bounds"); assertd(i < N, "Array Out of Bounds");
@@ -142,7 +141,7 @@ public:
/// \return reference to the requested element /// \return reference to the requested element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assertd(i < N, "Array Out of Bounds"); assertd(i < N, "Array Out of Bounds");
@@ -150,10 +149,10 @@ public:
} }
/// ///
/// \returns A reference to \f$data[0]\f$ /// \returns A reference to \math{\textbf{data}[0]}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& front() { constexpr value_t& front() {
return data[0]; return data[0];
@@ -161,20 +160,20 @@ public:
/// ///
/// \brief Access the first element /// \brief Access the first element
/// \returns A const-qualified reference to \f$data[0]\f$ /// \returns A const-qualified reference to \math{\textbf{data}[0]}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& front() const { constexpr const value_t& front() const {
return data[0]; return data[0];
} }
/// ///
/// \returns A reference to \f$data[N - 1]\f$ /// \returns A reference to \math{\textbf{data}[\textbf{N} - 1]}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& back() { constexpr value_t& back() {
return data[N - 1]; return data[N - 1];
@@ -182,10 +181,10 @@ public:
/// ///
/// \brief Access the last element /// \brief Access the last element
/// \returns A const-qualified reference to \f$data[N - 1]\f$ /// \returns A const-qualified reference to \math{\textbf{data}[\textbf{N} - 1]}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& back() const { constexpr const value_t& back() const {
return data[N - 1]; return data[N - 1];
@@ -205,7 +204,7 @@ public:
/// \brief Checks if all elements in the arrays are equal /// \brief Checks if all elements in the arrays are equal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
friend constexpr bool_t operator==(const array& lhs, const array& rhs) { friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
return array::_compare(lhs, rhs, make_index_metasequence<N>{}); return array::_compare(lhs, rhs, make_index_metasequence<N>{});
@@ -215,7 +214,7 @@ public:
/// \brief Checks if any element in the arrays is not equal /// \brief Checks if any element in the arrays is not equal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) { friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
return not array::_compare(lhs, rhs, make_index_metasequence<N>{}); return not array::_compare(lhs, rhs, make_index_metasequence<N>{});
@@ -234,18 +233,18 @@ public:
/// \returns A pointer to the first element of the array /// \returns A pointer to the first element of the array
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t* begin() { constexpr value_t* begin() {
return data; return data;
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns A const-qualified pointer to the first element of the array /// \returns A const-qualified pointer to the first element of the array
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t* begin() const { constexpr const value_t* begin() const {
return data; return data;
@@ -255,18 +254,18 @@ public:
/// \returns A pointer to one after the end of the array /// \returns A pointer to one after the end of the array
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t* end() { constexpr value_t* end() {
return data + N; return data + N;
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \returns A const-qualified pointer to one after the end of the array /// \returns A const-qualified pointer to one after the end of the array
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t* end() const { constexpr const value_t* end() const {
return data + N; return data + N;

View File

@@ -31,34 +31,34 @@
#ifndef FENNEC_CONTAINERS_BINTREE_H #ifndef FENNEC_CONTAINERS_BINTREE_H
#define FENNEC_CONTAINERS_BINTREE_H #define FENNEC_CONTAINERS_BINTREE_H
#include <fennec/memory/allocator.h>
#include <fennec/containers/deque.h> #include <fennec/containers/deque.h>
#include <fennec/containers/list.h> #include <fennec/containers/list.h>
#include <fennec/containers/optional.h> #include <fennec/containers/optional.h>
#include <fennec/containers/pair.h> #include <fennec/containers/pair.h>
#include <fennec/containers/traversal.h> #include <fennec/containers/traversal.h>
#include <fennec/memory/allocator.h>
namespace fennec namespace fennec
{ {
/// ///
/// \brief Structure defining a binary tree /// \brief Structure defining an in-array binary tree
/// ///
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypeT The data type /// \tparam TypeT The data type
/// \tparam AllocT An allocator class /// \tparam AllocT An allocator class
@@ -107,7 +107,7 @@ public:
/// \details The underlying allocation is not initialized. /// \details The underlying allocation is not initialized.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bintree() constexpr bintree()
: _table() : _table()
@@ -120,10 +120,10 @@ public:
/// \brief Move Constructor, takes ownership of a tree /// \brief Move Constructor, takes ownership of a tree
/// \param tree The tree to take ownership of /// \param tree The tree to take ownership of
/// ///
/// \details Takes ownership of the underlying allocation of \f$tree\f$ /// \details Takes ownership of the underlying allocation of \emph{tree}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bintree(bintree&& tree) noexcept constexpr bintree(bintree&& tree) noexcept
: _table(fennec::move(tree._table)) : _table(fennec::move(tree._table))
@@ -136,10 +136,10 @@ public:
/// \brief Copy Constructor, copies a tree /// \brief Copy Constructor, copies a tree
/// \param tree The tree to copy /// \param tree The tree to copy
/// ///
/// \details Copies the contents of \f$tree\f$ into a new tree. Invokes copy constructor. /// \details Copies the contents of \emph{tree} into a new tree. Invokes copy constructor.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr bintree(const bintree& tree) constexpr bintree(const bintree& tree)
: _table(tree._table.capacity()) : _table(tree._table.capacity())
@@ -173,10 +173,10 @@ public:
/// ///
/// \brief Destructor, clears the tree /// \brief Destructor, clears the tree
/// ///
/// \details Clears the contents of \f$tree\f$. Invokes destructor. /// \details Clears the contents of \emph{tree}. Invokes destructor.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~bintree() { constexpr ~bintree() {
clear(); clear();
@@ -195,17 +195,17 @@ public:
/// \returns The number of elements in the tree /// \returns The number of elements in the tree
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
} }
/// ///
/// \returns \f$true\f$ when there are no elements in the tree, \f$false\f$ otherwise. /// \returns \emph{true} when there are no elements in the tree, \emph{false} otherwise.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _size == 0; return _size == 0;
@@ -215,17 +215,17 @@ public:
/// \returns The capacity of the underlying allocation /// \returns The capacity of the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.capacity(); return _table.capacity();
} }
/// ///
/// \returns The next id to be returned by \f$insert\f$ or \f$emplace\f$. /// \returns The next id to be returned by `bintree::insert` or `bintree::emplace`.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t next_id() const { constexpr size_t next_id() const {
size_t i = _size; size_t i = _size;
@@ -236,10 +236,10 @@ public:
} }
/// ///
/// \returns The next id to be returned by \f$insert\f$ or \f$emplace\f$. /// \returns The next id to be returned by `bintree::insert` or `bintree::emplace`.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t root() const { constexpr size_t root() const {
return _root; return _root;
@@ -257,10 +257,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns The parent of node \f$i\f$ /// \returns The parent of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t parent(size_t i) const { constexpr size_t parent(size_t i) const {
return i == npos ? npos : _table[i].parent; return i == npos ? npos : _table[i].parent;
@@ -268,10 +268,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns The grandparent of node \f$i\f$ /// \returns The grandparent of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t grandparent(size_t i) const { constexpr size_t grandparent(size_t i) const {
return parent(parent(i)); return parent(parent(i));
@@ -279,10 +279,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns The left child of node \f$i\f$ /// \returns The left child of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t left(size_t i) const { constexpr size_t left(size_t i) const {
return i == npos ? npos : _table[i].child[false]; return i == npos ? npos : _table[i].child[false];
@@ -290,10 +290,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns The right child of node \f$i\f$ /// \returns The right child of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t right(size_t i) const { constexpr size_t right(size_t i) const {
return i == npos ? npos : _table[i].child[true]; return i == npos ? npos : _table[i].child[true];
@@ -301,11 +301,11 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \param dir The direction to go \f$true\f$ for right, \f$false\f$ for left /// \param dir The direction to go \emph{true} for right, \emph{false} for left
/// \returns The child in the direction specified by \f$dir\f$ /// \returns The child in the direction specified by \emph{dir}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t child(size_t i, bool dir) const { constexpr size_t child(size_t i, bool dir) const {
return i == npos ? npos : _table[i].child[dir]; return i == npos ? npos : _table[i].child[dir];
@@ -313,10 +313,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns \f$true\f$ if \f$i\f$ is the right node of \f$parent(i)\f$, \f$false\f$ otherwise /// \returns \emph{true} if \emph{i} is the right node of \emph{parent(i)}, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool side(size_t i) const { constexpr bool side(size_t i) const {
return i == npos ? false : i == right(_parent(i)); return i == npos ? false : i == right(_parent(i));
@@ -324,10 +324,10 @@ public:
/// ///
/// \param i The id of the node /// \param i The id of the node
/// \returns The id of the sibling of \f$i\f$ /// \returns The id of the sibling of \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t sibling(size_t i) const { constexpr size_t sibling(size_t i) const {
if (i == npos) { if (i == npos) {
@@ -337,16 +337,16 @@ public:
return npos; return npos;
} }
size_t p = _parent(i); size_t p = _parent(i);
bool d = i == _right(p); const bool d = i == _right(p);
return _child(p, !d); return _child(p, !d);
} }
/// ///
/// \param i The node id /// \param i The node id
/// \returns The depth of node \f$i\f$ /// \returns The depth of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log n)\f$ /// \emph{O(\log n)}
/// ///
constexpr size_t depth(size_t i) const { constexpr size_t depth(size_t i) const {
size_t d = 0; size_t d = 0;
@@ -359,10 +359,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns The id of the left-most node of \f$i\f$ /// \returns The id of the left-most node of \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log n)\f$ /// \emph{O(\log n)}
/// ///
constexpr size_t left_most(size_t i) const { constexpr size_t left_most(size_t i) const {
if (i >= _table.size()) { if (i >= _table.size()) {
@@ -376,10 +376,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns The id of the right-most node of \f$i\f$ /// \returns The id of the right-most node of \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log n)\f$ /// \emph{O(\log n)}
/// ///
constexpr size_t right_most(size_t i) const { constexpr size_t right_most(size_t i) const {
if (i >= _table.size()) { if (i >= _table.size()) {
@@ -402,10 +402,10 @@ public:
/// ///
/// \param i The node id /// \param i The node id
/// \returns a reference to the value of node \f$i\f$ /// \returns a reference to the value of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assertd(i < _table.size(), "Index out of bounds."); assertd(i < _table.size(), "Index out of bounds.");
@@ -415,10 +415,10 @@ public:
/// ///
/// \details Node access /// \details Node access
/// \param i The node id /// \param i The node id
/// \returns a reference to the value of node \f$i\f$ /// \returns a reference to the value of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assertd(i < _table.size(), "Index out of bounds."); assertd(i < _table.size(), "Index out of bounds.");
@@ -435,40 +435,40 @@ public:
/// @{ /// @{
/// ///
/// \details If the left node of \f$p\f$ already exists, the move assignment operator is used instead /// \details If the left node of \emph{p} already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to move into the new node /// \param val The object to move into the new node
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert_left(size_t p, value_t&& val) { constexpr size_t insert_left(size_t p, value_t&& val) {
return this->_insert_left(p, fennec::forward<value_t>(val)); return this->_insert_left(p, fennec::forward<value_t>(val));
} }
/// ///
/// \details If the left node of \f$p\f$ already exists, the copy assignment operator is used instead /// \details If the left node of \emph{p} already exists, the copy assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to copy to the new node /// \param val The object to copy to the new node
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert_left(size_t p, const value_t& val) { constexpr size_t insert_left(size_t p, const value_t& val) {
return this->_insert_left(p, val); return this->_insert_left(p, val);
} }
/// ///
/// \brief Left Insertion, constructs a new node as the left child of \f$p\f$ /// \brief Left Insertion, constructs a new node as the left child of \emph{p}
/// \details If the left node of \f$p\f$ already exists, the move assignment operator is used instead /// \details If the left node of \emph{p} already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param args The arguments to construct the new node with /// \param args The arguments to construct the new node with
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace_left(size_t p, ArgsT&&...args) { constexpr size_t emplace_left(size_t p, ArgsT&&...args) {
@@ -476,40 +476,40 @@ public:
} }
/// ///
/// \details If the right node of \f$p\f$ already exists, the move assignment operator is used instead /// \details If the right node of \emph{p} already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to move into the new node /// \param val The object to move into the new node
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert_right(size_t p, value_t&& val) { constexpr size_t insert_right(size_t p, value_t&& val) {
return this->_insert_right(p, fennec::forward<value_t>(val)); return this->_insert_right(p, fennec::forward<value_t>(val));
} }
/// ///
/// \details If the right node of \f$p\f$ already exists, the copy assignment operator is used instead /// \details If the right node of \emph{p} already exists, the copy assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to copy to the new node /// \param val The object to copy to the new node
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert_right(size_t p, const value_t& val) { constexpr size_t insert_right(size_t p, const value_t& val) {
return this->_insert_right(p, val); return this->_insert_right(p, val);
} }
/// ///
/// \brief Right Insertion, constructs a new node as the right child of \f$p\f$ /// \brief Right Insertion, constructs a new node as the right child of \emph{p}
/// \details If the right node of \f$p\f$ already exists, the move assignment operator is used instead /// \details If the right node of \emph{p} already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param args The arguments to construct the new node with /// \param args The arguments to construct the new node with
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace_right(size_t p, ArgsT&&...args) { constexpr size_t emplace_right(size_t p, ArgsT&&...args) {
@@ -519,21 +519,21 @@ public:
/// ///
/// \brief Perform a Tree Rotation at \f$i\f$ in the specified direction /// \brief Perform a Tree Rotation at \emph{i} in the specified direction
/// \param sub The root node for the rotation /// \param sub The root node for the rotation
/// \param dir The direction to rotate, \f$true\f$ for right, \f$false\f$ for left /// \param dir The direction to rotate, \emph{true} for right, \emph{false} for left
/// \returns the new root node /// \returns the new root node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t rotate(size_t sub, bool dir) { constexpr size_t rotate(size_t sub, bool dir) {
if (sub == npos) { if (sub == npos) {
return npos; return npos;
} }
size_t sub_parent = _parent(sub); const size_t sub_parent = _parent(sub);
size_t new_root = _child(sub, not dir); const size_t new_root = _child(sub, not dir);
size_t new_child = _child(new_root, dir); const size_t new_child = _child(new_root, dir);
_child(sub, not dir) = new_child; _child(sub, not dir) = new_child;
if (new_child != npos) { if (new_child != npos) {
@@ -552,43 +552,43 @@ public:
} }
/// ///
/// \details If the child of \f$p\f$ already exists, the move assignment operator is used instead /// \details If the child of \emph{p} already exists, the move assignment operator is used instead
/// \param parent The parent node /// \param parent The parent node
/// \param side The side to insert on /// \param side The side to insert on
/// \param val The object to move into the new node /// \param val The object to move into the new node
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(size_t parent, bool side, value_t&& val) { constexpr size_t insert(size_t parent, bool side, value_t&& val) {
return this->_insert(parent, side, fennec::forward<value_t>(val)); return this->_insert(parent, side, fennec::forward<value_t>(val));
} }
/// ///
/// \details If the child of \f$p\f$ already exists, the copy assignment operator is used instead /// \details If the child of \emph{p} already exists, the copy assignment operator is used instead
/// \param parent The parent node /// \param parent The parent node
/// \param side The side to insert on /// \param side The side to insert on
/// \param val The object to copy to the new node /// \param val The object to copy to the new node
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(size_t parent, bool side, const value_t& val) { constexpr size_t insert(size_t parent, bool side, const value_t& val) {
return this->_insert(parent, side, val); return this->_insert(parent, side, val);
} }
/// ///
/// \brief Insertion, constructs a new node as the child of \f$p\f$ /// \brief Insertion, constructs a new node as the child of \emph{p}
/// \details If the child of \f$p\f$ already exists, the move assignment operator is used instead /// \details If the child of \emph{p} already exists, the move assignment operator is used instead
/// \param parent The parent node /// \param parent The parent node
/// \param side The side to insert on /// \param side The side to insert on
/// \param args The arguments to construct the new node with /// \param args The arguments to construct the new node with
/// \returns The id of the new node /// \returns The id of the new node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace(size_t parent, bool side, ArgsT&&...args) { constexpr size_t emplace(size_t parent, bool side, ArgsT&&...args) {
@@ -599,7 +599,7 @@ public:
/// \brief Clears the tree, destroying all elements /// \brief Clears the tree, destroying all elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void clear() { constexpr void clear() {
list<size_t> queue; list<size_t> queue;
@@ -636,16 +636,16 @@ public:
/// ///
/// \details /// \details
/// The visitor should accept a reference to a value of type \f$TypeT\f$ and a \f$size_t\f$ which contains the node's id. /// The visitor should accept a reference to a value of type \emph{TypeT} and a \emph{size_t} which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum /// The visitor should return one of the following values in the `fennec::traversal_control_` enum
/// ///
/// \tparam OrderT The order with which to traverse the tree. /// \tparam OrderT The order with which to traverse the tree.
/// \tparam VisitorT The visitor, should fulfill the signature \f$uint8_t visit(TypeT&, size_t)\f$ /// \tparam VisitorT The visitor, should fulfill the signature \emph{uint8_t visit(TypeT&, size_t)}
/// \param visit The visiting object /// \param visit The visiting object
/// \param i The node to start at /// \param i The node to start at
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename OrderT, typename VisitorT> template<typename OrderT, typename VisitorT>
constexpr void traverse(VisitorT&& visit, size_t i) { constexpr void traverse(VisitorT&& visit, size_t i) {
@@ -667,16 +667,16 @@ public:
/// \brief Traverse the tree using a specified order and visiting functor /// \brief Traverse the tree using a specified order and visiting functor
/// ///
/// \details /// \details
/// The visitor should accept a reference to a value of type \f$TypeT\f$ and a \f$size_t\f$ which contains the node's id. /// The visitor should accept a reference to a value of type \emph{TypeT} and a \emph{size_t} which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum /// The visitor should return one of the following values in the `fennec::traversal_control_` enum
/// ///
/// \tparam OrderT The order with which to traverse the tree. /// \tparam OrderT The order with which to traverse the tree.
/// \tparam VisitorT The visitor, should fulfill the signature \f$uint8_t visit(TypeT&, size_t)\f$ /// \tparam VisitorT The visitor, should fulfill the signature \emph{uint8_t visit(TypeT&, size_t)}
/// \param visit The visiting object /// \param visit The visiting object
/// \param i The node to start at /// \param i The node to start at
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename OrderT, typename VisitorT> template<typename OrderT, typename VisitorT>
constexpr void traverse(VisitorT&& visit, size_t i) const { constexpr void traverse(VisitorT&& visit, size_t i) const {
@@ -717,9 +717,9 @@ public:
return npos; return npos;
} }
size_t lft = tree.left(tree.parent(node)); const size_t lft = tree.left(tree.parent(node));
size_t nxt = lft == node ? tree.right(tree.parent(node)) : npos; const size_t nxt = lft == node ? tree.right(tree.parent(node)) : npos;
size_t chd = tree.left(node); const size_t chd = tree.left(node);
if (nxt != npos && node != head) { if (nxt != npos && node != head) {
visit.push_front(nxt); visit.push_front(nxt);
@@ -769,7 +769,7 @@ public:
} }
size_t nxt = tree.right(tree.parent(node)); size_t nxt = tree.right(tree.parent(node));
size_t chd = tree.left(node); const size_t chd = tree.left(node);
nxt = node == nxt ? npos : nxt; nxt = node == nxt ? npos : nxt;
if (nxt != npos && node != head) { if (nxt != npos && node != head) {
@@ -792,7 +792,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = { 0 };
}; };
/// ///
@@ -819,9 +819,9 @@ public:
return npos; return npos;
} }
size_t parent = tree.parent(node); const size_t parent = tree.parent(node);
size_t pright = tree.right(parent); const size_t pright = tree.right(parent);
size_t next = tree.left_most(tree.right(node)); const size_t next = tree.left_most(tree.right(node));
if (node != pright && parent != npos) { if (node != pright && parent != npos) {
visit.push_front(parent); visit.push_front(parent);
@@ -843,7 +843,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = { 0 };
}; };
/// ///
@@ -870,15 +870,15 @@ public:
return npos; return npos;
} }
size_t parent = tree.parent(node); const size_t parent = tree.parent(node);
size_t pright = tree.right(parent); const size_t right = tree.right(parent);
if (node == pright) { if (node == right) {
if (parent != npos) { if (parent != npos) {
visit.push_front(parent); visit.push_front(parent);
} }
} else if (pright != npos) { } else if (right != npos) {
visit.push_front(this->_successor(tree, pright)); visit.push_front(this->_successor(tree, right));
} }
if (not visit.is_empty()) { if (not visit.is_empty()) {
@@ -894,7 +894,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = { 0 };
constexpr size_t _successor(const bintree& tree, size_t n) { constexpr size_t _successor(const bintree& tree, size_t n) {
size_t s = tree.left_most(n); size_t s = tree.left_most(n);
@@ -919,7 +919,7 @@ public:
/// @{ /// @{
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
/// \details Performs pre-order traversal /// \details Performs pre-order traversal
class iterator { class iterator {
@@ -954,7 +954,7 @@ public:
/// ///
/// \brief iterator pre-increment operator /// \brief iterator pre-increment operator
/// \returns A reference to self after having stepped to the next node /// \returns A reference to \emph{this} after having stepped to the next node
iterator& operator++() { iterator& operator++() {
return _n = _order[*_tree, _n, traversal_control_continue], *this; return _n = _order[*_tree, _n, traversal_control_continue], *this;
} }
@@ -988,7 +988,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if iterators are identical, \emph{false} otherwise
constexpr bool operator==(const iterator& it) { constexpr bool operator==(const iterator& it) {
return _tree == it._tree and _n == it._n; return _tree == it._tree and _n == it._n;
} }
@@ -996,7 +996,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if iterators are different, \emph{false} otherwise
constexpr bool operator!=(const iterator& it) { constexpr bool operator!=(const iterator& it) {
return _tree != it._tree or _n != it._n; return _tree != it._tree or _n != it._n;
} }
@@ -1009,7 +1009,7 @@ public:
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
/// \details Performs pre-order traversal /// \details Performs pre-order traversal
class const_iterator { class const_iterator {
@@ -1044,7 +1044,7 @@ public:
/// ///
/// \brief iterator pre-increment operator /// \brief iterator pre-increment operator
/// \returns A reference to self after having stepped to the next node /// \returns A reference to \emph{this} after having stepped to the next node
const_iterator& operator++() { const_iterator& operator++() {
return _n = _order[*_tree, _n, traversal_control_continue], *this; return _n = _order[*_tree, _n, traversal_control_continue], *this;
} }
@@ -1064,7 +1064,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if iterators are identical, \emph{false} otherwise
constexpr bool operator==(const iterator& it) { constexpr bool operator==(const iterator& it) {
return _tree == it._tree and _n == it._n; return _tree == it._tree and _n == it._n;
} }
@@ -1072,7 +1072,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if iterators are different, \emph{false} otherwise
constexpr bool operator!=(const iterator& it) { constexpr bool operator!=(const iterator& it) {
return _tree != it._tree or _n != it._n; return _tree != it._tree or _n != it._n;
} }
@@ -1087,18 +1087,18 @@ public:
/// \returns an iterator at the first element in pre-order traversal /// \returns an iterator at the first element in pre-order traversal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
iterator begin() { iterator begin() {
return iterator(this, _root); return iterator(this, _root);
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns an iterator at the first element in pre-order traversal /// \returns an iterator at the first element in pre-order traversal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
const_iterator begin() const { const_iterator begin() const {
return iterator(this, _root); return iterator(this, _root);
@@ -1108,18 +1108,18 @@ public:
/// \returns an iterator at the first element in pre-order traversal /// \returns an iterator at the first element in pre-order traversal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
iterator end() { iterator end() {
return iterator(this, _root, nullid); return iterator(this, _root, nullid);
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \returns an iterator at the first element in pre-order traversal /// \returns an iterator at the first element in pre-order traversal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
const_iterator end() const { const_iterator end() const {
return iterator(this, _root, nullid); return iterator(this, _root, nullid);
@@ -1228,8 +1228,8 @@ private:
} }
constexpr size_t& _sibling(size_t i) { constexpr size_t& _sibling(size_t i) {
size_t p = _parent(i); const size_t p = _parent(i);
bool d = i == _right(p); const bool d = i == _right(p);
return _child(p, !d); return _child(p, !d);
} }

View File

@@ -31,10 +31,11 @@
#ifndef FENNEC_CONTAINERS_BITFIELD_H #ifndef FENNEC_CONTAINERS_BITFIELD_H
#define FENNEC_CONTAINERS_BITFIELD_H #define FENNEC_CONTAINERS_BITFIELD_H
#include <fennec/containers/array.h>
#include <fennec/lang/types.h> #include <fennec/lang/types.h>
#include <fennec/lang/utility.h> #include <fennec/lang/utility.h>
#include <fennec/containers/array.h>
namespace fennec namespace fennec
{ {
@@ -42,20 +43,19 @@ namespace fennec
/// \brief Bitfield Container with basic Bit Ops /// \brief Bitfield Container with basic Bit Ops
/// ///
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | ⛔ | /// | insertion | ⛔ |
/// | deletion | ⛔ | /// | deletion | ⛔ |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam N The number of bits in the bitfield /// \tparam N The number of bits in the bitfield
template<size_t N> template<size_t N>
@@ -81,10 +81,10 @@ public:
/// ///
/// \brief Default constructor. /// \brief Default constructor.
/// \details Initializes all bits with \f$0\f$. /// \details Initializes all bits with \emph{0}.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr bitfield() constexpr bitfield()
: _bytes() { : _bytes() {
@@ -93,10 +93,10 @@ public:
/// ///
/// \brief Boolean array constructor. /// \brief Boolean array constructor.
/// \param arr An array of boolean values resembling each bit. /// \param arr An array of boolean values resembling each bit.
/// \details Initializes each bit with the respective boolean value in \f$arr\f$ /// \details Initializes each bit with the respective boolean value in \emph{arr}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
explicit constexpr bitfield(const bool (&arr)[N]) explicit constexpr bitfield(const bool (&arr)[N])
: _bytes() { : _bytes() {
@@ -108,10 +108,10 @@ public:
/// ///
/// \brief Index array constructor. /// \brief Index array constructor.
/// \param arr An array of indices. /// \param arr An array of indices.
/// \details Sets the bits of each index provided in \f$arr\f$. /// \details Sets the bits of each index provided in \emph{arr}.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<size_t I> template<size_t I>
explicit constexpr bitfield(const size_t (&arr)[I]) explicit constexpr bitfield(const size_t (&arr)[I])
@@ -123,11 +123,11 @@ public:
/// ///
/// \param args A set of indices. /// \param args A set of indices.
/// \details This substitution assumes \f$ArgsT\ldots\f$ can be taken as an array of indices. <br> /// \details This substitution assumes \emph{ArgsT...} can be taken as an array of indices. <br>
/// Sets the bits of each index provided in \f$args\ldots\f$. /// Sets the bits of each index provided in \emph{args...}.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr bitfield(ArgsT&&...args) constexpr bitfield(ArgsT&&...args)
@@ -138,12 +138,12 @@ public:
/// ///
/// \brief Variadic array constructor /// \brief Variadic array constructor
/// \param args A set of boolean values. /// \param args A set of boolean values.
/// \details This substitution assumes \f$ArgsT\ldots\f$ can be taken as an array of booleans. <br> /// \details This substitution assumes \emph{ArgsT...} can be taken as an array of booleans. <br>
/// Initializes each bit with the respective boolean in \f$args\ldots\f$. <br> /// Initializes each bit with the respective boolean in \emph{args...}. <br>
/// Does not necessitate the number of arguments be equal to the number of bits. /// Does not necessitate the number of arguments be equal to the number of bits.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename...ArgsT> requires((is_bool_v<ArgsT> or is_convertible_v<ArgsT, bool>) and ...) template<typename...ArgsT> requires((is_bool_v<ArgsT> or is_convertible_v<ArgsT, bool>) and ...)
constexpr bitfield(ArgsT&&...args) constexpr bitfield(ArgsT&&...args)
@@ -157,7 +157,7 @@ public:
/// \param bf bitfield to copy /// \param bf bitfield to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
bitfield(const bitfield& bf) bitfield(const bitfield& bf)
: _bytes(bf._bytes) { : _bytes(bf._bytes) {
@@ -168,7 +168,7 @@ public:
/// \param bf bitfield to move /// \param bf bitfield to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
bitfield(bitfield&& bf) noexcept bitfield(bitfield&& bf) noexcept
: _bytes(bf._bytes) { : _bytes(bf._bytes) {
@@ -190,20 +190,20 @@ public:
/// ///
/// \brief copy assignment /// \brief copy assignment
/// \param bf bitfield to copy /// \param bf bitfield to copy
/// \returns a reference to self /// \returns a reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
bitfield& operator=(const bitfield& bf) = default; bitfield& operator=(const bitfield& bf) = default;
/// ///
/// \brief move assignment /// \brief move assignment
/// \param bf bitfield to move /// \param bf bitfield to move
/// \returns a reference to self /// \returns a reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
bitfield& operator=(bitfield&& bf) noexcept = default; bitfield& operator=(bitfield&& bf) noexcept = default;
@@ -222,12 +222,12 @@ public:
/// \returns the value stored in the bit as a boolean /// \returns the value stored in the bit as a boolean
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
bool test(size_t i) const { bool test(size_t i) const {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
size_t o = i % 8; const size_t o = i % 8;
return _bytes[b] & (1 << o); return _bytes[b] & (1 << o);
} }
@@ -236,12 +236,12 @@ public:
/// \param i the index of the bit /// \param i the index of the bit
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void set(size_t i) { void set(size_t i) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
size_t o = i % 8; const size_t o = i % 8;
_bytes[b] |= (1 << o); _bytes[b] |= (1 << o);
} }
@@ -250,12 +250,12 @@ public:
/// \param i the index of the bit /// \param i the index of the bit
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void clear(size_t i) { void clear(size_t i) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
size_t o = i % 8; const size_t o = i % 8;
_bytes[b] &= ~(1 << o); _bytes[b] &= ~(1 << o);
} }
@@ -264,27 +264,27 @@ public:
/// \param i the index of the bit /// \param i the index of the bit
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void toggle(size_t i) { void toggle(size_t i) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
size_t o = i % 8; const size_t o = i % 8;
_bytes[b] ^= (1 << o); _bytes[b] ^= (1 << o);
} }
/// ///
/// \brief store \f$v\f$ in bit \f$i\f$ /// \brief store \emph{v} in bit \emph{i}
/// \param i the index of the bit /// \param i the index of the bit
/// \param v the value to store /// \param v the value to store
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void store(size_t i, bool v) { void store(size_t i, bool v) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
size_t o = i % 8; const size_t o = i % 8;
(_bytes[b] &= ~((1 << o))) |= ((v << o)); (_bytes[b] &= ~((1 << o))) |= ((v << o));
} }
@@ -293,7 +293,7 @@ public:
/// \returns a bitfield containing the bit-wise inverse /// \returns a bitfield containing the bit-wise inverse
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
bitfield operator~() const { bitfield operator~() const {
bitfield res = *this; bitfield res = *this;

View File

@@ -42,20 +42,19 @@
/// ///
/// \section fennec_containers_container_section_properties Container Properties /// \section fennec_containers_container_section_properties Container Properties
/// ///
/// | Property | Meaning | /// | Property | Meaning |
/// |:----------------|:-----------------------------------------------------------------------------------------------| /// |:----------------|:-------------------------------------------------------------------------------------------------------------------|
/// | **stable** | Any pointer reference to an element remains constant for the lifetime of the container. | /// | **stable** | Any pointer reference to an element remains constant for the lifetime of the container. |
/// | **dynamic** | Memory for this container is allocated on the heap. | /// | **dynamic** | Memory for this container is allocated on the heap. |
/// | **homogeneous** | The types of all elements are either identical, or inherit the same base type. | /// | **homogeneous** | The types of all elements are either identical, or inherit the same base type. |
/// | **distinct** | Elements are guaranteed to be unique in their value. | /// | **distinct** | Elements are guaranteed to be unique in their value. |
/// | **ordered** | Elements are guaranteed to be in order, such that for any index \f$i\f$, \f$E_i < E_{i + 1}\f$ | /// | **ordered** | Elements are guaranteed to be in order, such that for any index \math{i}, \math{\textbf{E}_i < \textbf{E}_{i + 1}} |
/// | **space** | The amount of memory allocated with respect to the number of elements, in big-O notation. | /// | **space** | The amount of memory allocated with respect to the number of elements, in big-O notation. |
/// | **linear** | Each element is sequential in terms of access. | /// | **linear** | Each element is sequential in terms of access. |
/// | **access** | The runtime of the access operators and functions, in big-O notation. | /// | **access** | The runtime of the access operators and functions, in big-O notation. |
/// | **find** | The runtime of finding an element in the container, in big-O notation. | /// | **find** | The runtime of finding an element in the container, in big-O notation. |
/// | **insertion** | The runtime of inserting an element in the container, in big-O notation. | /// | **insertion** | The runtime of inserting an element in the container, in big-O notation. |
/// | **deletion** | The runtime of erasing an element in the container, in big-O notation. | /// | **deletion** | The runtime of erasing an element in the container, in big-O notation. |
/// | **space** | The space complexity of the container. |
/// ///
/// ///
/// \section fennec_containers_section_cppstdlib C++ Standard Template Library /// \section fennec_containers_section_cppstdlib C++ Standard Template Library

View File

@@ -33,8 +33,6 @@
#include <fennec/memory/allocator.h> #include <fennec/memory/allocator.h>
// TODO: Document
namespace fennec namespace fennec
{ {
@@ -46,20 +44,19 @@ namespace fennec
/// This behaves the similar to fennec::list, however it does not allow arbitrary access, insertion, or deletion. /// This behaves the similar to fennec::list, however it does not allow arbitrary access, insertion, or deletion.
/// It is one of the few data structures in this library that is stable, i.e. pointers to elements do not change. /// It is one of the few data structures in this library that is stable, i.e. pointers to elements do not change.
/// ///
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypeT value type /// \tparam TypeT value type
template<typename TypeT, typename AllocT = allocator<TypeT>> template<typename TypeT, typename AllocT = allocator<TypeT>>
@@ -93,7 +90,7 @@ public:
/// \brief Default Constructor, initializes an empty deque /// \brief Default Constructor, initializes an empty deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
deque() deque()
: _alloc() : _alloc()
@@ -107,7 +104,7 @@ public:
/// \param alloc the allocator to copy /// \param alloc the allocator to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
deque(const alloc_t& alloc) deque(const alloc_t& alloc)
: _alloc(alloc) : _alloc(alloc)
@@ -121,7 +118,7 @@ public:
/// \param deque the deque to copy /// \param deque the deque to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
deque(const deque& deque) deque(const deque& deque)
: _alloc(deque._alloc) : _alloc(deque._alloc)
@@ -140,7 +137,7 @@ public:
/// \param deque the deque to move /// \param deque the deque to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
deque(deque&& deque) noexcept deque(deque&& deque) noexcept
: _alloc(deque._alloc) : _alloc(deque._alloc)
@@ -155,7 +152,7 @@ public:
/// \brief Destructor, calls deque::clear /// \brief Destructor, calls deque::clear
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
~deque() { ~deque() {
clear(); clear();
@@ -169,10 +166,10 @@ public:
/// @{ /// @{
/// ///
/// \returns \f$true\f$ when the deque is empty, \f$false\f$ otherwise /// \returns \emph{true} when the deque is empty, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _size == 0; return _size == 0;
@@ -182,7 +179,7 @@ public:
/// \returns the number of elements in the deque /// \returns the number of elements in the deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
@@ -200,7 +197,7 @@ public:
/// \returns a reference to the first element in the deque /// \returns a reference to the first element in the deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
value_t& front() { value_t& front() {
assert(not is_empty(), "Attempted to access an empty deque."); assert(not is_empty(), "Attempted to access an empty deque.");
@@ -211,7 +208,7 @@ public:
/// \returns a const-qualified reference to the first element in the deque /// \returns a const-qualified reference to the first element in the deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
const value_t& front() const { const value_t& front() const {
assert(not is_empty(), "Attempted to access an empty deque."); assert(not is_empty(), "Attempted to access an empty deque.");
@@ -222,7 +219,7 @@ public:
/// \returns a reference to the last element in the deque /// \returns a reference to the last element in the deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
value_t& back() { value_t& back() {
assert(not is_empty(), "Attempted to access an empty deque."); assert(not is_empty(), "Attempted to access an empty deque.");
@@ -233,7 +230,7 @@ public:
/// \returns a const-qualified reference to the last element in the deque /// \returns a const-qualified reference to the last element in the deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
const value_t& back() const { const value_t& back() const {
assert(not is_empty(), "Attempted to access an empty deque."); assert(not is_empty(), "Attempted to access an empty deque.");
@@ -253,7 +250,7 @@ public:
/// \param elem the value to move /// \param elem the value to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void push_front(value_t&& elem) { void push_front(value_t&& elem) {
this->_push_front(elem); this->_push_front(elem);
@@ -264,7 +261,7 @@ public:
/// \param elem the value to copy /// \param elem the value to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void push_front(const value_t& elem) { void push_front(const value_t& elem) {
this->_push_front(elem); this->_push_front(elem);
@@ -276,7 +273,7 @@ public:
/// \param args Arguments used to construct the value /// \param args Arguments used to construct the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
void emplace_front(ArgsT&&...args) { void emplace_front(ArgsT&&...args) {
@@ -289,7 +286,7 @@ public:
/// \param elem the value to move /// \param elem the value to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void push_back(value_t&& elem) { void push_back(value_t&& elem) {
this->_push_back(elem); this->_push_back(elem);
@@ -300,7 +297,7 @@ public:
/// \param elem the value to copy /// \param elem the value to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void push_back(const value_t& elem) { void push_back(const value_t& elem) {
this->_push_back(elem); this->_push_back(elem);
@@ -312,7 +309,7 @@ public:
/// \param args Arguments used to construct the value /// \param args Arguments used to construct the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
void emplace_back(ArgsT&&...args) { void emplace_back(ArgsT&&...args) {
@@ -323,7 +320,7 @@ public:
/// \brief Clears the contents of the deque /// \brief Clears the contents of the deque
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
void clear() { void clear() {
elem_t it = _first; elem_t it = _first;
@@ -342,7 +339,7 @@ public:
/// \brief Erase the First Element /// \brief Erase the First Element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void pop_front() { void pop_front() {
if (_first == nullptr) { if (_first == nullptr) {
@@ -360,7 +357,7 @@ public:
/// \brief Erase the Last Element /// \brief Erase the Last Element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void pop_back() { void pop_back() {
if (_last == nullptr) { if (_last == nullptr) {

View File

@@ -18,6 +18,7 @@
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H #ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H #define FENNEC_CONTAINERS_DETAIL_TUPLE_H
#include <fennec/lang/metasequences.h> #include <fennec/lang/metasequences.h>
#include <fennec/lang/utility.h> #include <fennec/lang/utility.h>
@@ -28,8 +29,11 @@ namespace fennec::detail
template <size_t I, typename T> template <size_t I, typename T>
struct _tuple_leaf struct _tuple_leaf
{ {
template <typename ArgT> constexpr _tuple_leaf(_tuple_leaf&&) noexcept = default;
constexpr _tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {} constexpr _tuple_leaf(const _tuple_leaf&) = default;
template <typename ArgT> requires(not is_same_v<remove_cvref_t<ArgT>, _tuple_leaf>)
constexpr explicit _tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {}
constexpr ~_tuple_leaf() = default; constexpr ~_tuple_leaf() = default;
@@ -45,8 +49,11 @@ struct _tuple;
template <size_t...IndicesV, typename...TypesT> template <size_t...IndicesV, typename...TypesT>
struct _tuple<index_metasequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>... struct _tuple<index_metasequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
{ {
constexpr _tuple(_tuple&&) noexcept = default;
constexpr _tuple(const _tuple&) = default;
template <typename...ArgsT> template <typename...ArgsT>
constexpr _tuple(ArgsT&&... args) constexpr explicit _tuple(ArgsT&&... args)
: _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... { : _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {
} }

View File

@@ -31,10 +31,13 @@
#ifndef FENNEC_CONTAINERS_DYNARRAY_H #ifndef FENNEC_CONTAINERS_DYNARRAY_H
#define FENNEC_CONTAINERS_DYNARRAY_H #define FENNEC_CONTAINERS_DYNARRAY_H
#include <fennec/containers/initializer_list.h>
#include <fennec/lang/utility.h> #include <fennec/lang/utility.h>
#include <fennec/memory/allocator.h> #include <fennec/memory/allocator.h>
#include <fennec/memory/new.h>
#include <fennec/containers/initializer_list.h>
#include <fennec/format/formatter.h>
namespace fennec namespace fennec
{ {
@@ -43,20 +46,19 @@ namespace fennec
/// ///
/// \brief Wrapper for dynamically sized and allocated arrays /// \brief Wrapper for dynamically sized and allocated arrays
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | \f$O(N)\f$ | /// | insertion | \emph{O(N)} |
/// | deletion | \f$O(N)\f$ | /// | deletion | \emph{O(N)} |
/// | space | \f$O(N)\f$ |
/// ///
/// This structure prefers shallow moves and deep copies. /// This structure prefers shallow moves and deep copies.
/// ///
@@ -86,7 +88,7 @@ public:
/// \brief Default Constructor, initializes an empty allocation. /// \brief Default Constructor, initializes an empty allocation.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr dynarray() constexpr dynarray()
: _alloc(8) : _alloc(8)
@@ -99,7 +101,7 @@ public:
/// data. /// data.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
explicit constexpr dynarray(const alloc_t& alloc) explicit constexpr dynarray(const alloc_t& alloc)
: _alloc(8, alloc) : _alloc(8, alloc)
@@ -107,11 +109,11 @@ public:
} }
/// ///
/// \brief Sized Allocation, initializes a dynarray with \f$n\f$ elements using the default constructor. /// \brief Sized Allocation, initializes a dynarray with \emph{n} elements using the default constructor.
/// \param n The number of elements. /// \param n The number of elements.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
explicit constexpr dynarray(size_t n) explicit constexpr dynarray(size_t n)
: _alloc(n) : _alloc(n)
@@ -124,13 +126,13 @@ public:
} }
/// ///
/// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator \f$alloc\f$ and \f$n\f$ elements /// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator \emph{alloc} and \emph{n} elements
/// using the default constructor. /// using the default constructor.
/// \param n The number of elements /// \param n The number of elements
/// \param alloc The allocator object to copy /// \param alloc The allocator object to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr dynarray(size_t n, const alloc_t& alloc) constexpr dynarray(size_t n, const alloc_t& alloc)
: _alloc(n, alloc) : _alloc(n, alloc)
@@ -142,13 +144,13 @@ public:
} }
/// ///
/// \brief Sized Allocation Copy Constructor, Create an allocation of size \f$n\f$ elements, with each element /// \brief Sized Allocation Copy Constructor, Create an allocation of size \emph{n} elements, with each element
/// constructed using the copy constructor /// constructed using the copy constructor
/// \param n the number of elements /// \param n the number of elements
/// \param val the value to copy /// \param val the value to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr dynarray(size_t n, const TypeT& val) constexpr dynarray(size_t n, const TypeT& val)
: _alloc(n) : _alloc(n)
@@ -166,7 +168,7 @@ public:
/// \param args The arguments to create each object with /// \param args The arguments to create each object with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr explicit dynarray(size_t n, ArgsT&&...args) constexpr explicit dynarray(size_t n, ArgsT&&...args)
@@ -183,7 +185,7 @@ public:
/// \param arr The array to copy /// \param arr The array to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<size_t N> template<size_t N>
constexpr dynarray(const TypeT (&arr)[N]) constexpr dynarray(const TypeT (&arr)[N])
@@ -200,7 +202,7 @@ public:
/// \param arr The array to move /// \param arr The array to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<size_t N> template<size_t N>
constexpr dynarray(TypeT (&&arr)[N]) constexpr dynarray(TypeT (&&arr)[N])
@@ -212,13 +214,13 @@ public:
} }
/// ///
/// \brief Conversion Constructor, copies elements of conv as this \f$value_t\f$ /// \brief Conversion Constructor, copies elements of conv as this \emph{value_t}
/// \tparam OTypeT The other value type /// \tparam OTypeT The other value type
/// \tparam OAlloc The other allocator type /// \tparam OAlloc The other allocator type
/// \param conv The dynarray to convert /// \param conv The dynarray to convert
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename OTypeT, class OAlloc> template<typename OTypeT, class OAlloc>
constexpr dynarray(const dynarray<OTypeT, OAlloc>& conv) constexpr dynarray(const dynarray<OTypeT, OAlloc>& conv)
@@ -236,7 +238,7 @@ public:
/// \param alloc An allocator object to copy /// \param alloc An allocator object to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr dynarray(initializer_list<value_t> l, const alloc_t& alloc = alloc_t()) constexpr dynarray(initializer_list<value_t> l, const alloc_t& alloc = alloc_t())
: _alloc(l.size(), alloc) : _alloc(l.size(), alloc)
@@ -252,7 +254,7 @@ public:
/// \param arr the dynarray to copy /// \param arr the dynarray to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr dynarray(const dynarray& arr) constexpr dynarray(const dynarray& arr)
: _alloc(arr._size) : _alloc(arr._size)
@@ -267,7 +269,7 @@ public:
/// \param arr the dynarray to move /// \param arr the dynarray to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr dynarray(dynarray&& arr) noexcept constexpr dynarray(dynarray&& arr) noexcept
: _alloc(fennec::move(arr._alloc)) : _alloc(fennec::move(arr._alloc))
@@ -279,7 +281,7 @@ public:
/// \brief Default Destructor, destructs all elements and frees the underlying allocation /// \brief Default Destructor, destructs all elements and frees the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~dynarray() { constexpr ~dynarray() {
value_t* addr = _alloc.data(); value_t* addr = _alloc.data();
@@ -292,10 +294,6 @@ public:
/// @} /// @}
private:
// This constructor should not be invokable since moving is a single object operation and will cause undefined
// behaviour when moving to multiple elements
constexpr dynarray(size_t n, TypeT&& val) = delete;
// Assignment ========================================================================================================== // Assignment ==========================================================================================================
@@ -307,10 +305,10 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param arr the array to copy /// \param arr the array to copy
/// \returns A dynarray after having copied each element of \f$arr\f$ /// \returns A dynarray after having copied each element of \emph{arr}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr dynarray& operator=(const dynarray& arr) { constexpr dynarray& operator=(const dynarray& arr) {
this->clear(); this->clear();
@@ -324,10 +322,10 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param arr the array to move /// \param arr the array to move
/// \returns A dynarray after having taken ownership of the contents of \f$arr\f$ /// \returns A dynarray after having taken ownership of the contents of \emph{arr}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr dynarray& operator=(dynarray&& arr) noexcept { constexpr dynarray& operator=(dynarray&& arr) noexcept {
this->clear(); this->clear();
@@ -341,10 +339,10 @@ public:
/// \brief Array Copy Assignment Operator /// \brief Array Copy Assignment Operator
/// \tparam N the length of the array /// \tparam N the length of the array
/// \param arr the array to copy /// \param arr the array to copy
/// \returns A dynarray after having copied each element of \f$arr\f$ /// \returns A dynarray after having copied each element of \emph{arr}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<size_t N> template<size_t N>
constexpr dynarray& operator=(const TypeT (&arr)[N]) { constexpr dynarray& operator=(const TypeT (&arr)[N]) {
@@ -360,10 +358,10 @@ public:
/// \brief Array Copy Assignment Operator /// \brief Array Copy Assignment Operator
/// \tparam N the length of the array /// \tparam N the length of the array
/// \param arr the array to copy /// \param arr the array to copy
/// \returns A dynarray after having moved each element of \f$arr\f$ /// \returns A dynarray after having moved each element of \emph{arr}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<size_t N> template<size_t N>
constexpr dynarray& operator=(TypeT (&&arr)[N]) { constexpr dynarray& operator=(TypeT (&&arr)[N]) {
@@ -387,7 +385,7 @@ public:
/// \returns The size of the dynarray in elements /// \returns The size of the dynarray in elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
@@ -397,7 +395,7 @@ public:
/// \returns The current capacity, in elements, of the underlying allocation /// \returns The current capacity, in elements, of the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _alloc.capacity(); return _alloc.capacity();
@@ -407,7 +405,7 @@ public:
/// \returns True when there are no elements active, otherwise false /// \returns True when there are no elements active, otherwise false
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _size == 0; return _size == 0;
@@ -425,10 +423,10 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i The index to access /// \param i The index to access
/// \returns A reference to the element at index \f$i\f$ /// \returns A reference to the element at index \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr TypeT& operator[](size_t i) { constexpr TypeT& operator[](size_t i) {
assertd(i < _size, "Array Out of Bounds"); assertd(i < _size, "Array Out of Bounds");
@@ -438,10 +436,10 @@ public:
/// ///
/// \brief Array Access Operator (const) /// \brief Array Access Operator (const)
/// \param i The index to access /// \param i The index to access
/// \returns A const qualified reference to the element at index \f$i\f$ /// \returns A const qualified reference to the element at index \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const TypeT& operator[](size_t i) const { constexpr const TypeT& operator[](size_t i) const {
assertd(i < _size, "Array Out of Bounds"); assertd(i < _size, "Array Out of Bounds");
@@ -452,7 +450,7 @@ public:
/// \returns Reference to the first element in the dynarray /// \returns Reference to the first element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr TypeT& front() { constexpr TypeT& front() {
return this->operator[](0); return this->operator[](0);
@@ -462,7 +460,7 @@ public:
/// \returns A const-qualified reference to the first element in the dynarray /// \returns A const-qualified reference to the first element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const TypeT& front() const { constexpr const TypeT& front() const {
return this->operator[](0); return this->operator[](0);
@@ -472,7 +470,7 @@ public:
/// \returns A reference to the last element in the dynarray /// \returns A reference to the last element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr TypeT& back() { constexpr TypeT& back() {
return this->operator[](size() - 1); return this->operator[](size() - 1);
@@ -482,7 +480,7 @@ public:
/// \returns A const-qualified reference to the last element in the dynarray /// \returns A const-qualified reference to the last element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const TypeT& back() const { constexpr const TypeT& back() const {
return this->operator[](size() - 1); return this->operator[](size() - 1);
@@ -492,7 +490,7 @@ public:
/// \returns A pointer to the underlying allocation /// \returns A pointer to the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr TypeT* data() { constexpr TypeT* data() {
return _alloc.data(); return _alloc.data();
@@ -502,7 +500,7 @@ public:
/// \returns A pointer to the underlying allocation /// \returns A pointer to the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const TypeT* data() const { constexpr const TypeT* data() const {
return _alloc.data(); return _alloc.data();
@@ -523,7 +521,7 @@ public:
/// \param val the value to initialize with /// \param val the value to initialize with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void insert(size_t i, TypeT&& val) { constexpr void insert(size_t i, TypeT&& val) {
@@ -535,8 +533,8 @@ public:
// Move the data if we are not inserting at the end of the array // Move the data if we are not inserting at the end of the array
if((i = min(i, _size)) < _size) { if((i = min(i, _size)) < _size) {
fennec::memmove( fennec::memmove(
(void*)(_alloc.data() + i + 1) static_cast<void*>(_alloc.data() + i + 1)
, (void*)(_alloc.data() + i) , static_cast<void*>(_alloc.data() + i)
, (_size - i) * sizeof(TypeT)); , (_size - i) * sizeof(TypeT));
} }
@@ -551,7 +549,7 @@ public:
/// \param val the value to initialize with /// \param val the value to initialize with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void insert(size_t i, const TypeT& val) { constexpr void insert(size_t i, const TypeT& val) {
@@ -563,8 +561,8 @@ public:
// Move the data if we are not inserting at the end of the array // Move the data if we are not inserting at the end of the array
if((i = min(i, _size)) < _size) { if((i = min(i, _size)) < _size) {
fennec::memmove( fennec::memmove(
(void*)(_alloc.data() + i), static_cast<void*>(_alloc.data() + i),
(void*)(_alloc.data() + i + 1), static_cast<void*>(_alloc.data() + i + 1),
(_size - i) * sizeof(TypeT) (_size - i) * sizeof(TypeT)
); );
} }
@@ -581,7 +579,7 @@ public:
/// \tparam ArgsT Argument types /// \tparam ArgsT Argument types
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace(size_t i, ArgsT&&...args) { constexpr void emplace(size_t i, ArgsT&&...args) {
@@ -594,8 +592,8 @@ public:
// Move the data if we are not inserting at the end of the array // Move the data if we are not inserting at the end of the array
if((i = min(i, _size)) < _size) { if((i = min(i, _size)) < _size) {
fennec::memmove( fennec::memmove(
(void*)(_alloc.data() + i) static_cast<void*>(_alloc.data() + i)
, (void*)(_alloc.data() + i + 1) , static_cast<void*>(_alloc.data() + i + 1)
, (_size - i) * sizeof(TypeT)); , (_size - i) * sizeof(TypeT));
} }
@@ -609,7 +607,7 @@ public:
/// \param val Value to initialize with /// \param val Value to initialize with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void push_back(const TypeT& val) { constexpr void push_back(const TypeT& val) {
dynarray::insert(_size, val); dynarray::insert(_size, val);
@@ -620,7 +618,7 @@ public:
/// \param val Value to initialize with /// \param val Value to initialize with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void push_back(TypeT&& val) { constexpr void push_back(TypeT&& val) {
dynarray::insert(_size, fennec::forward<TypeT>(val)); dynarray::insert(_size, fennec::forward<TypeT>(val));
@@ -632,7 +630,7 @@ public:
/// \param args Arguments to construct with /// \param args Arguments to construct with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace_back(ArgsT...args) { constexpr void emplace_back(ArgsT...args) {
@@ -643,7 +641,7 @@ public:
/// \brief Erase last element /// \brief Erase last element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void pop_back() { constexpr void pop_back() {
fennec::destruct(&_alloc[--_size]); fennec::destruct(&_alloc[--_size]);
@@ -653,10 +651,10 @@ public:
/// \brief Resize the dynarray, invoking the default constructor for all new elements /// \brief Resize the dynarray, invoking the default constructor for all new elements
/// \param n The new size in elements /// \param n The new size in elements
/// ///
/// \details if \f$n\f$ is less than the current size, any elements that would be removed are destructed /// \details if \emph{n} is less than the current size, any elements that would be removed are destructed
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void resize(size_t n) { constexpr void resize(size_t n) {
_reduce(n); _reduce(n);
@@ -674,10 +672,10 @@ public:
/// \param n The new size in elements /// \param n The new size in elements
/// \param val The value to fill with /// \param val The value to fill with
/// ///
/// \details if \f$n\f$ is less than the current size, any elements that would be removed are destructed /// \details if \emph{n} is less than the current size, any elements that would be removed are destructed
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void resize(size_t n, const TypeT& val) { constexpr void resize(size_t n, const TypeT& val) {
_reduce(n); _reduce(n);
@@ -694,10 +692,10 @@ public:
/// \brief Reserve the array, allocating new space without initialization /// \brief Reserve the array, allocating new space without initialization
/// \param n The new capacity in elements /// \param n The new capacity in elements
/// ///
/// \details if \f$n\f$ is less than the current size, any elements that would be removed are destructed /// \details if \emph{n} is less than the current size, any elements that would be removed are destructed
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void reserve(size_t n) { constexpr void reserve(size_t n) {
_reduce(n); _reduce(n);
@@ -708,7 +706,7 @@ public:
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation. /// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void clear() { constexpr void clear() {
_reduce(0); _reduce(0);
@@ -728,16 +726,16 @@ public:
/// \returns A pointer to the first element in the dynarray /// \returns A pointer to the first element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr TypeT* begin() { return _alloc; } constexpr TypeT* begin() { return _alloc; }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns A const qualified pointer to the first element in the dynarray /// \returns A const qualified pointer to the first element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const TypeT* begin() const { return _alloc; } constexpr const TypeT* begin() const { return _alloc; }
@@ -746,16 +744,16 @@ public:
/// \return A pointer to the address after the last element in the dynarray /// \return A pointer to the address after the last element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr TypeT* end() { return begin() + _size; } constexpr TypeT* end() { return begin() + _size; }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \return A const qualified pointer to the address after the last element in the dynarray /// \return A const qualified pointer to the address after the last element in the dynarray
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const TypeT* end() const { return begin() + _size; } constexpr const TypeT* end() const { return begin() + _size; }
@@ -783,6 +781,27 @@ private:
} }
}; };
///
/// \brief Formatter for `fennec::dynarray`
/// \tparam T The element type.
template<typename T>
struct formatter<dynarray<T>> {
///
/// \brief format function
/// \param str the string argument
/// \returns the formatted version of \emph{str}
string operator()(const format_arg& fmt, const dynarray<T>& arr) const {
string res = string("[ ");
for (auto& it : arr) {
res += ' ';
res += base(fmt, it);
}
return res;
}
static constexpr formatter<T> base = {};
};
} }
#endif // FENNEC_CONTAINERS_DYNARRAY_H #endif // FENNEC_CONTAINERS_DYNARRAY_H

View File

@@ -32,6 +32,7 @@
#define FENNEC_CONTAINERS_GENERIC_H #define FENNEC_CONTAINERS_GENERIC_H
#include <fennec/memory/allocator.h> #include <fennec/memory/allocator.h>
#include <fennec/rtti/type.h> #include <fennec/rtti/type.h>
namespace fennec namespace fennec
@@ -40,20 +41,19 @@ namespace fennec
/// ///
/// \brief A struct capable of holding a single object of any type /// \brief A struct capable of holding a single object of any type
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogeneous | ⛔ | /// | homogeneous | ⛔ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(1)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(1)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | ⛔ | /// | find | ⛔ |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(1)\f$ |
struct generic { struct generic {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
@@ -79,7 +79,7 @@ public:
/// \brief Default Constructor /// \brief Default Constructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
generic() generic()
: _handle(nullptr) : _handle(nullptr)
@@ -91,7 +91,7 @@ public:
/// \param gen The generic object to copy /// \param gen The generic object to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
generic(const generic& gen) generic(const generic& gen)
: _handle(nullptr) : _handle(nullptr)
@@ -106,7 +106,7 @@ public:
/// \param gen The generic object to move /// \param gen The generic object to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
generic(generic&& gen) generic(generic&& gen)
: _handle(gen._handle) : _handle(gen._handle)
@@ -121,7 +121,7 @@ public:
/// \param x The value /// \param x The value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T> template<typename T>
generic(T&& x) generic(T&& x)
@@ -136,7 +136,7 @@ public:
/// \param args The argument values /// \param args The argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T, typename...ArgsT> template<typename T, typename...ArgsT>
generic(type_identity<T>, ArgsT&&...args) generic(type_identity<T>, ArgsT&&...args)
@@ -164,17 +164,17 @@ public:
/// \returns a runtime type struct referencing the held type /// \returns a runtime type struct referencing the held type
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
type type() const { type type() const {
return *static_cast<fennec::type*>(_manage(op_type, nullptr)); return *static_cast<fennec::type*>(_manage(op_type, nullptr));
} }
/// ///
/// \returns \f$true\f$ if there is a held value, \f$false\f$ otherwise /// \returns \emph{true} if there is a held value, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
bool has_value() const { bool has_value() const {
return _handle != nullptr; return _handle != nullptr;
@@ -192,10 +192,10 @@ public:
/// ///
/// \brief copy assignment /// \brief copy assignment
/// \param gen the generic to copy /// \param gen the generic to copy
/// \returns a reference to self after copying the contents of \f$gen\f$ /// \returns a reference to \emph{this} after copying the contents of \emph{gen}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
generic& operator=(const generic& gen) { generic& operator=(const generic& gen) {
if (this == &gen) { // self-assignment case if (this == &gen) { // self-assignment case
@@ -211,10 +211,10 @@ public:
/// ///
/// \brief move assignment /// \brief move assignment
/// \param gen the generic to move /// \param gen the generic to move
/// \returns a reference to self after swapping contents with \f$gen\f$ /// \returns a reference to \emph{this} after swapping contents with \emph{gen}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
generic& operator=(generic&& gen) noexcept { generic& operator=(generic&& gen) noexcept {
swap(gen); swap(gen);
@@ -225,10 +225,10 @@ public:
/// \brief value assignment /// \brief value assignment
/// \tparam T the type of the value /// \tparam T the type of the value
/// \param x the value to assign /// \param x the value to assign
/// \returns a reference to self after having assigned \f$x\f$ /// \returns a reference to \emph{this} after having assigned \emph{x}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T> template<typename T>
generic& operator=(T&& x) { generic& operator=(T&& x) {
@@ -250,13 +250,13 @@ public:
/// ///
/// \brief emplace value /// \brief emplace value
/// ///
/// \details constructs a new value of type \f$T\f$ using \f$args\ldots\f$ /// \details constructs a new value of type \emph{T} using \emph{args\ldots}
/// \tparam T the type to construct /// \tparam T the type to construct
/// \tparam ArgsT the argument types /// \tparam ArgsT the argument types
/// \param args the argument values /// \param args the argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T, typename...ArgsT> template<typename T, typename...ArgsT>
void emplace(ArgsT&&...args) { void emplace(ArgsT&&...args) {
@@ -270,7 +270,7 @@ public:
/// \details clears the held value using the appropriate destructor /// \details clears the held value using the appropriate destructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void reset() { void reset() {
if (_manage) { if (_manage) {
@@ -284,7 +284,7 @@ public:
/// \param gen the generic to swap with /// \param gen the generic to swap with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void swap(generic& gen) noexcept { void swap(generic& gen) noexcept {
fennec::swap(_handle, gen._handle); fennec::swap(_handle, gen._handle);
@@ -303,12 +303,12 @@ public:
/// ///
/// \brief cast value /// \brief cast value
/// ///
/// \details equivalent to \f$reinterpret_cast\f$ /// \details equivalent to \emph{reinterpret_cast}
/// \tparam T The type to cast to /// \tparam T The type to cast to
/// \returns The contents of generic after having cast to \f$T\f$ /// \returns The contents of generic after having cast to \emph{T}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T, typename U = remove_cvref_t<T>> template<typename T, typename U = remove_cvref_t<T>>
T cast() { T cast() {
@@ -316,12 +316,12 @@ public:
} }
/// ///
/// \details equivalent to \f$reinterpret_cast\f$ /// \details equivalent to \emph{reinterpret_cast}
/// \tparam T The type to cast to /// \tparam T The type to cast to
/// \returns The contents of generic after having cast to \f$T\f$ /// \returns The contents of generic after having cast to \emph{T}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T, typename U = remove_cvref_t<T>> template<typename T, typename U = remove_cvref_t<T>>
T cast() const { T cast() const {

View File

@@ -35,7 +35,6 @@
#include <fennec/containers/list.h> #include <fennec/containers/list.h>
#include <fennec/containers/map.h> #include <fennec/containers/map.h>
#include <fennec/containers/object_pool.h> #include <fennec/containers/object_pool.h>
#include <fennec/containers/set.h>
/* /*
* With the directed tree we were able to cheat a little, the structure has more rules to it which allows * With the directed tree we were able to cheat a little, the structure has more rules to it which allows
@@ -55,20 +54,19 @@ namespace fennec
/// \brief Graph Data Structure, describes sets of arbitrarily connected vertices /// \brief Graph Data Structure, describes sets of arbitrarily connected vertices
/// ///
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:--------------:| /// |:-----------:|:---------------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N + M)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(1)\f$ | /// | find | \emph{O(1)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(M)\f$ | /// | deletion | \emph{O(M)} |
/// | space | \f$O(N + M)\f$ |
/// ///
/// Graphs contain vertices and edges. Graphs are either directed /// Graphs contain vertices and edges. Graphs are either directed
/// or undirected. This structure allows the creation of both directed and undirected edges. As /// or undirected. This structure allows the creation of both directed and undirected edges. As
@@ -80,11 +78,11 @@ namespace fennec
/// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would /// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would
/// produce a connected graph. We will call this "disjointed" /// produce a connected graph. We will call this "disjointed"
/// ///
/// A directed graph is semi-connected if there is a directed path p for \f$u\f$ &rarr; \f$v\f$ *or* \f$v\f$ &rarr; \f$u\f$ for every /// A directed graph is semi-connected if there is a directed path p for \emph{u} &rarr; \emph{v} *or* \emph{v} &rarr; \emph{u} for every
/// pair of vertices \f$[u, v]\f$. We will call this "unilateral" /// pair of vertices \emph{[u, v]}. We will call this "unilateral"
/// ///
/// A directed graph is strongly-connected if there is a directed path p for \f$u\f$ &rarr; \f$v\f$ *and* \f$v\f$ &rarr; \f$u\f$ for every pair /// A directed graph is strongly-connected if there is a directed path p for \emph{u} &rarr; \emph{v} *and* \emph{v} &rarr; \emph{u} for every pair
/// of vertices \f$[u, v]\f$. We will call this "connected" /// of vertices \emph{[u, v]}. We will call this "connected"
/// ///
/// \tparam VertexT The type associated with each vertex /// \tparam VertexT The type associated with each vertex
/// \tparam EdgeT The type associated with each edge /// \tparam EdgeT The type associated with each edge
@@ -122,7 +120,7 @@ public:
/// \brief Default Constructor, initializes empty graph /// \brief Default Constructor, initializes empty graph
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr graph() = default; constexpr graph() = default;
@@ -130,7 +128,7 @@ public:
/// \brief Destructor /// \brief Destructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N + M)\f$ /// \math{\textbf{O(N} + \textbf{M)}}
/// ///
constexpr ~graph() = default; constexpr ~graph() = default;
@@ -146,7 +144,7 @@ public:
/// \returns A reference to this after assigning g /// \returns A reference to this after assigning g
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N + M)\f$ /// \math{\textbf{O(N} + \textbf{M)}}
/// ///
constexpr graph& operator=(const graph& g) = default; constexpr graph& operator=(const graph& g) = default;
@@ -156,7 +154,7 @@ public:
/// \returns A reference to this after assigning g /// \returns A reference to this after assigning g
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr graph& operator=(graph&& g) = default; constexpr graph& operator=(graph&& g) = default;
@@ -172,7 +170,7 @@ public:
/// \returns The number of vertices in the graph /// \returns The number of vertices in the graph
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t num_vertices() const { constexpr size_t num_vertices() const {
return _vertex_pool.size(); return _vertex_pool.size();
@@ -182,7 +180,7 @@ public:
/// \returns The number of edges in the graph /// \returns The number of edges in the graph
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t num_edges() const { constexpr size_t num_edges() const {
return _edge_pool.size(); return _edge_pool.size();
@@ -192,57 +190,57 @@ public:
/// \returns The capacity of the vertex pool /// \returns The capacity of the vertex pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _vertex_pool.capacity(); return _vertex_pool.capacity();
} }
/// ///
/// \returns \f$true\f$ when there are no vertices in the graph, \f$false\f$ otherwise /// \returns \emph{true} when there are no vertices in the graph, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return num_vertices() == 0; return num_vertices() == 0;
} }
/// ///
/// \brief Checks if there exists an edge \f$e\f$ that starts from \f$a\f$ and ends at \f$b\f$ /// \brief Checks if there exists an edge \math{e} that starts from \emph{a} and ends at \emph{b}
/// \param a The first vertex /// \param a The first vertex
/// \param b The second vertex /// \param b The second vertex
/// \returns \f$true\f$ if the edge exists, \f$false\f$ otherwise /// \returns \emph{true} if the edge exists, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool exists(size_t a, size_t b) const { constexpr bool exists(size_t a, size_t b) const {
return _edge_map[a][b] != nullptr; return _edge_map[a][b] != nullptr;
} }
/// ///
/// \brief Checks if there exists an edge \f$e0\f$ that starts from \f$a\f$ and ends at \f$b\f$ and \f$e1\f$ that starts from \f$b\f$ /// \brief Checks if there exists an edge \math{e_0} that starts from \emph{a} and ends at \emph{b} and \math{e_1} that starts from \emph{b}
/// and ends at \f$a\f$ /// and ends at \emph{a}
/// \param a The first vertex /// \param a The first vertex
/// \param b The second vertex /// \param b The second vertex
/// \returns \f$true\f$ if both edges exist, \f$false\f$ otherwise /// \returns \emph{true} if both edges exist, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_symmetric(size_t a, size_t b) const { constexpr bool is_symmetric(size_t a, size_t b) const {
return exists(a, b) and exists(b, a); return exists(a, b) and exists(b, a);
} }
/// ///
/// \brief Checks if there exists an edge \f$e\f$ between \f$a\f$ and \f$b\f$ /// \brief Checks if there exists an edge \math{e} between \emph{a} and \emph{b}
/// \param a The first vertex /// \param a The first vertex
/// \param b The second vertex /// \param b The second vertex
/// \returns \f$true\f$ if both edges exist, \f$false\f$ otherwise /// \returns \emph{true} if both edges exist, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_undirected(size_t a, size_t b) const { constexpr bool is_undirected(size_t a, size_t b) const {
const auto* e0 = _edge_map[a][b]; const auto* e0 = _edge_map[a][b];
@@ -269,7 +267,7 @@ public:
/// \returns A reference to the value stored in the vertex /// \returns A reference to the value stored in the vertex
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr vertex_t& operator[](size_t vertex) { constexpr vertex_t& operator[](size_t vertex) {
return _vertex_pool[vertex]; return _vertex_pool[vertex];
@@ -281,7 +279,7 @@ public:
/// \returns A reference to the value stored in the vertex /// \returns A reference to the value stored in the vertex
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const vertex_t& operator[](size_t vertex) const { constexpr const vertex_t& operator[](size_t vertex) const {
return _vertex_pool[vertex]; return _vertex_pool[vertex];
@@ -291,10 +289,10 @@ public:
/// \brief edge Access Operator /// \brief edge Access Operator
/// \param a The id of the first vertex /// \param a The id of the first vertex
/// \param b The id of the second vertex /// \param b The id of the second vertex
/// \returns A pointer to the value stored in the edge, \f$nullptr\f$ if not found /// \returns A pointer to the value stored in the edge, \emph{nullptr} if not found
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr edge_t* operator[](size_t a, size_t b) { constexpr edge_t* operator[](size_t a, size_t b) {
if (is_empty()) { if (is_empty()) {
@@ -311,10 +309,10 @@ public:
/// \brief edge Const Access Operator /// \brief edge Const Access Operator
/// \param a The id of the first vertex /// \param a The id of the first vertex
/// \param b The id of the second vertex /// \param b The id of the second vertex
/// \returns A const-qualified pointer to the value stored in the edge, \f$nullptr\f$ if not found /// \returns A const-qualified pointer to the value stored in the edge, \emph{nullptr} if not found
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const edge_t* operator[](size_t a, size_t b) const { constexpr const edge_t* operator[](size_t a, size_t b) const {
if (is_empty()) { if (is_empty()) {
@@ -328,12 +326,12 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge to \f$x\ldots\f$ /// \brief Getter for a list of vertices \emph{X} that \emph{vertex} has an edge to \emph{X...}
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices \f$x\f$ with edges from \f$vertex\f$ to \f$x\ldots\f$ /// \returns A list containing all vertices \emph{X} with edges from \emph{vertex} to \emph{X...}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
list<size_t> outgoing(size_t vertex) { list<size_t> outgoing(size_t vertex) {
list<size_t> res; list<size_t> res;
@@ -347,12 +345,12 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge from \f$x\ldots\f$ /// \brief Getter for a list of vertices \emph{X} that \emph{vertex} has an edge from \emph{X...}
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices \f$x\f$ with edges from \f$x\ldots\f$ to \f$vertex\f$ /// \returns A list containing all vertices \emph{X} with edges from \emph{X...} to \emph{vertex}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
list<size_t> incoming(size_t vertex) { list<size_t> incoming(size_t vertex) {
list<size_t> res; list<size_t> res;
@@ -368,12 +366,12 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge to and from \f$x\ldots\f$ /// \brief Getter for a list of vertices \emph{X} that \emph{vertex} has an edge to and from \emph{X...}
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices \f$x\f$ that have symmetric edges with \f$vertex\f$ /// \returns A list containing all vertices \emph{X} that have symmetric edges with \emph{vertex}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
list<size_t> symmetric(size_t vertex) { list<size_t> symmetric(size_t vertex) {
list<size_t> res; list<size_t> res;
@@ -389,16 +387,16 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge to and from \f$x\ldots\f$ and share the same value /// \brief Getter for a list of vertices \emph{X} that \emph{vertex} has an edge to and from \emph{X...} and share the same value
/// \details /// \details
/// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be /// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be
/// turned into a directed edge by changing the weight object associated with the edge, or by /// turned into a directed edge by changing the weight object associated with the edge, or by
/// removing one of the sub-edges. /// removing one of the sub-edges.
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices \f$x\f$ that have symmetric edges with \f$vertex\f$ /// \returns A list containing all vertices \emph{X} that have symmetric edges with \emph{vertex}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
list<size_t> undirected(size_t vertex) { list<size_t> undirected(size_t vertex) {
list<size_t> res; list<size_t> res;
@@ -421,7 +419,7 @@ public:
/// \returns A pointer to a map containing edges mapped from this vertex /// \returns A pointer to a map containing edges mapped from this vertex
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
const auto* edges(size_t vertex) { const auto* edges(size_t vertex) {
if (is_empty() || vertex >= _edge_map.size()) { if (is_empty() || vertex >= _edge_map.size()) {
@@ -444,7 +442,7 @@ public:
/// \returns The id of the new vertex /// \returns The id of the new vertex
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(vertex_t&& vertex) { constexpr size_t insert(vertex_t&& vertex) {
return this->_insert(fennec::forward<vertex_t>(vertex)); return this->_insert(fennec::forward<vertex_t>(vertex));
@@ -456,7 +454,7 @@ public:
/// \returns The id of the new vertex /// \returns The id of the new vertex
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(const vertex_t& vertex) { constexpr size_t insert(const vertex_t& vertex) {
return this->_insert(vertex); return this->_insert(vertex);
@@ -469,7 +467,7 @@ public:
/// \returns The id of the new vertex /// \returns The id of the new vertex
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace(ArgsT&&...args) { constexpr size_t emplace(ArgsT&&...args) {
@@ -481,7 +479,7 @@ public:
/// \param vertex The id of the vertex to erase /// \param vertex The id of the vertex to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
constexpr void erase(size_t vertex) { constexpr void erase(size_t vertex) {
cut(vertex); cut(vertex);
@@ -489,14 +487,14 @@ public:
} }
/// ///
/// \brief Form an edge from vertex \f$a\f$ to vertex \f$b\f$ /// \brief Form an edge from vertex \emph{a} to vertex \emph{b}
/// \tparam ArgsT The argument types /// \tparam ArgsT The argument types
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
/// \param args The arguments to construct the edge with /// \param args The arguments to construct the edge with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void make_edge(size_t a, size_t b, ArgsT&&...args) { constexpr void make_edge(size_t a, size_t b, ArgsT&&...args) {
@@ -508,7 +506,7 @@ public:
_edge_map.resize(_vertex_pool.capacity()); _edge_map.resize(_vertex_pool.capacity());
} }
auto it = _edge_map[a][b]; const auto it = _edge_map[a][b];
size_t conn; size_t conn;
if (it != nullptr) { if (it != nullptr) {
conn = *it; conn = *it;
@@ -520,14 +518,14 @@ public:
} }
/// ///
/// \brief Form an undirected edge between vertex \f$a\f$ and vertex \f$b\f$ /// \brief Form an undirected edge between vertex \emph{a} and vertex \emph{b}
/// \tparam ArgsT The argument types /// \tparam ArgsT The argument types
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
/// \param args The arguments to construct the edge with /// \param args The arguments to construct the edge with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void make_edge2(size_t a, size_t b, ArgsT&&...args) { constexpr void make_edge2(size_t a, size_t b, ArgsT&&...args) {
@@ -539,7 +537,7 @@ public:
_edge_map.resize(_vertex_pool.capacity()); _edge_map.resize(_vertex_pool.capacity());
} }
auto it = _edge_map[a][b]; const auto it = _edge_map[a][b];
size_t conn; size_t conn;
if (it != nullptr) { if (it != nullptr) {
conn = *it; conn = *it;
@@ -553,12 +551,12 @@ public:
} }
/// ///
/// \brief Disconnect an edge from vertex \f$a\f$ to vertex \f$b\f$ /// \brief Disconnect an edge from vertex \emph{a} to vertex \emph{b}
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void cut_edge(size_t a, size_t b) { constexpr void cut_edge(size_t a, size_t b) {
@@ -580,12 +578,12 @@ public:
} }
/// ///
/// \brief Disconnect both directed edges between vertices \f$a\f$ and \f$b\f$ /// \brief Disconnect both directed edges between vertices \emph{a} and \emph{b}
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void cut_edge2(size_t a, size_t b) { constexpr void cut_edge2(size_t a, size_t b) {
const auto* ita = _edge_map[a][b]; const auto* ita = _edge_map[a][b];
@@ -600,11 +598,11 @@ public:
} }
/// ///
/// \brief Break *all* edges connected to \f$n\f$ /// \brief Break *all* edges connected to \emph{n}
/// \param n The vertex id /// \param n The vertex id
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(M)\f$ /// \emph{O(M)}
/// ///
void cut(size_t n) { void cut(size_t n) {
for (const auto it : outgoing(n)) { for (const auto it : outgoing(n)) {
@@ -619,7 +617,7 @@ public:
/// \brief Clear the graph, destructing all vertices and edges. /// \brief Clear the graph, destructing all vertices and edges.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N + M)\f$ /// \emph{O(N + M)}
/// ///
void clear() { void clear() {
_vertex_pool.clear(); _vertex_pool.clear();

View File

@@ -44,7 +44,7 @@ using std::initializer_list;
/// ///
/// \param inls the initializer list /// \param inls the initializer list
/// \returns A const qualified pointer to the first element in \f$inls\f$ /// \returns A const qualified pointer to the first element in \emph{inls}
template<typename T> template<typename T>
constexpr const T* begin(initializer_list<T> inls) noexcept { constexpr const T* begin(initializer_list<T> inls) noexcept {
return inls.begin(); return inls.begin();
@@ -52,7 +52,7 @@ constexpr const T* begin(initializer_list<T> inls) noexcept {
/// ///
/// \param inls the initializer list /// \param inls the initializer list
/// \returns A const qualified pointer to one past the last element in \f$inls\f$ /// \returns A const qualified pointer to one past the last element in \emph{inls}
template<typename T> template<typename T>
constexpr const T* end(initializer_list<T> inls) noexcept { constexpr const T* end(initializer_list<T> inls) noexcept {
return inls.end(); return inls.end();

View File

@@ -48,23 +48,22 @@ namespace fennec
/// This data-structure behaves like a linked list, but does not use pointers. Instead, it is in-array. This creates the /// This data-structure behaves like a linked list, but does not use pointers. Instead, it is in-array. This creates the
/// following properties: /// following properties:
/// ///
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(N)\f$ | /// | access | \emph{O(N)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | \f$O(N)\f$ | /// | insertion | \emph{O(N)} |
/// | deletion | \f$O(N)\f$ | /// | deletion | \emph{O(N)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \note Access, Insertion, and Deletion are \f$O(N)\f$ using the index pattern, /// \note Access, Insertion, and Deletion are \emph{O(N)} using the index pattern,
/// using the iterator pattern yields \f$O(1)\f$ runtime. /// using the iterator pattern yields \emph{O(1)} runtime.
/// ///
/// \tparam TypeT value type /// \tparam TypeT value type
template<class TypeT, class Alloc = allocator<TypeT>> template<class TypeT, class Alloc = allocator<TypeT>>
@@ -106,18 +105,18 @@ public:
/// \brief Default Constructor, initializes an empty list. /// \brief Default Constructor, initializes an empty list.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr list() constexpr list()
: _table(), _freed(), _root(npos), _last(npos), _size(0) { : _table(), _freed(), _root(npos), _last(npos), _size(0) {
} }
/// ///
/// \brief Copy Constructor, copies all elements in \f$l\f$ with optimized layout /// \brief Copy Constructor, copies all elements in \emph{l} with optimized layout
/// \param l The list to copy /// \param l The list to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr list(const list& l) constexpr list(const list& l)
: list() { : list() {
@@ -132,7 +131,7 @@ public:
/// \param l The list to move /// \param l The list to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr list(list&& l) noexcept constexpr list(list&& l) noexcept
: _table(fennec::move(l._table)) : _table(fennec::move(l._table))
@@ -146,7 +145,7 @@ public:
/// \brief Destructor, destructs all elements then releases the allocation. /// \brief Destructor, destructs all elements then releases the allocation.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~list() { constexpr ~list() {
clear(); clear();
@@ -163,10 +162,10 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param l the list to copy /// \param l the list to copy
/// \returns \f$this\f$ after having copied all elements of \f$l\f$ /// \returns \emph{this} after having copied all elements of \emph{l}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr list& operator=(const list& l) { constexpr list& operator=(const list& l) {
this->clear(); this->clear();
@@ -179,10 +178,10 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param l the list to copy /// \param l the list to copy
/// \returns \f$this\f$ after having taken ownership over the contents of \f$l\f$ /// \returns \emph{this} after having taken ownership over the contents of \emph{l}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr list& operator=(list&& l) noexcept { constexpr list& operator=(list&& l) noexcept {
this->clear(); this->clear();
@@ -206,7 +205,7 @@ public:
/// \returns The size of the list in elements. /// \returns The size of the list in elements.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
@@ -216,17 +215,17 @@ public:
/// \returns The capacity of the list in elements. /// \returns The capacity of the list in elements.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.size(); return _table.size();
} }
/// ///
/// \returns \f$true\f$ when the list is empty, \f$false\f$ otherwise. /// \returns \emph{true} when the list is empty, \emph{false} otherwise.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _root == npos; return _root == npos;
@@ -244,10 +243,10 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i Index to access /// \param i Index to access
/// \returns A reference to the element at \f$i\f$ /// \returns A reference to the element at \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr value_t& operator[](int i) { constexpr value_t& operator[](int i) {
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds"); assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
@@ -259,10 +258,10 @@ public:
/// ///
/// \brief Const Array Access Operator /// \brief Const Array Access Operator
/// \param i Index to access /// \param i Index to access
/// \returns A const-qualified reference to the element at \f$i\f$ /// \returns A const-qualified reference to the element at \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr const value_t& operator[](int i) const { constexpr const value_t& operator[](int i) const {
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds"); assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
@@ -276,7 +275,7 @@ public:
/// \returns A reference to the first element in the list /// \returns A reference to the first element in the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& front() { constexpr value_t& front() {
return *_table[_root].value; return *_table[_root].value;
@@ -287,7 +286,7 @@ public:
/// \returns A const-qualified reference to the first element in the list /// \returns A const-qualified reference to the first element in the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& front() const { constexpr const value_t& front() const {
return *_table[_root].value; return *_table[_root].value;
@@ -298,7 +297,7 @@ public:
/// \returns A reference to the last element in the list /// \returns A reference to the last element in the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& back() { constexpr value_t& back() {
return *_table[_last].value; return *_table[_last].value;
@@ -309,7 +308,7 @@ public:
/// \returns A const-qualified reference to the last element in the list /// \returns A const-qualified reference to the last element in the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& back() const { constexpr const value_t& back() const {
return *_table[_last].value; return *_table[_last].value;
@@ -331,7 +330,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator insert(const iterator& it, const value_t& x) { constexpr iterator insert(const iterator& it, const value_t& x) {
return this->_insert(it._n, x); return this->_insert(it._n, x);
@@ -344,7 +343,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator insert(const iterator& it, value_t&& x) { constexpr iterator insert(const iterator& it, value_t&& x) {
return this->_insert(it._n, fennec::forward<value_t>(x)); return this->_insert(it._n, fennec::forward<value_t>(x));
@@ -357,7 +356,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr iterator insert(size_t i, const value_t& x) { constexpr iterator insert(size_t i, const value_t& x) {
assert(i <= size(), "Index out of Bounds"); assert(i <= size(), "Index out of Bounds");
@@ -373,7 +372,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr iterator insert(size_t i, value_t&& x) { constexpr iterator insert(size_t i, value_t&& x) {
assert(i <= size(), "Index out of Bounds"); assert(i <= size(), "Index out of Bounds");
@@ -390,7 +389,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr iterator emplace(size_t i, ArgsT&&...args) { constexpr iterator emplace(size_t i, ArgsT&&...args) {
@@ -408,7 +407,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr iterator emplace(const iterator& it, ArgsT&&...args) { constexpr iterator emplace(const iterator& it, ArgsT&&...args) {
@@ -421,7 +420,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator push_front(const value_t& x) { constexpr iterator push_front(const value_t& x) {
return this->_insert(_root, x); return this->_insert(_root, x);
@@ -433,7 +432,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator push_front(value_t&& x) { constexpr iterator push_front(value_t&& x) {
return this->_insert(_root, fennec::forward<value_t>(x)); return this->_insert(_root, fennec::forward<value_t>(x));
@@ -446,7 +445,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr iterator emplace_front(ArgsT&&...args) { constexpr iterator emplace_front(ArgsT&&...args) {
@@ -459,7 +458,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator push_back(const value_t& x) { constexpr iterator push_back(const value_t& x) {
return this->_insert(npos, x); return this->_insert(npos, x);
@@ -471,7 +470,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator push_back(value_t&& x) { constexpr iterator push_back(value_t&& x) {
return this->_insert(npos, fennec::forward<value_t>(x)); return this->_insert(npos, fennec::forward<value_t>(x));
@@ -484,7 +483,7 @@ public:
/// \returns The id of the inserted node /// \returns The id of the inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr iterator emplace_back(ArgsT&&...args) { constexpr iterator emplace_back(ArgsT&&...args) {
@@ -496,11 +495,11 @@ public:
/// \param i Index to erase /// \param i Index to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void erase(size_t i) { constexpr void erase(size_t i) {
assert(i < size(), "Index out of Bounds!"); assert(i < size(), "Index out of Bounds!");
size_t n = _walk(i); const size_t n = _walk(i);
_erase(n); _erase(n);
} }
@@ -509,7 +508,7 @@ public:
/// \param it Location to Erase /// \param it Location to Erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void erase(const iterator& it) { constexpr void erase(const iterator& it) {
this->_erase(it._n); this->_erase(it._n);
@@ -519,7 +518,7 @@ public:
/// \brief Pop Front, erases first element /// \brief Pop Front, erases first element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void pop_front() { constexpr void pop_front() {
_erase(_root); _erase(_root);
@@ -529,7 +528,7 @@ public:
/// \brief Pop Back, erases first element /// \brief Pop Back, erases first element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void pop_back() { constexpr void pop_back() {
_erase(_last); _erase(_last);
@@ -539,7 +538,7 @@ public:
/// \brief Clears the list, destructing all elements in order /// \brief Clears the list, destructing all elements in order
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void clear() { constexpr void clear() {
size_t i = _root; size_t i = _root;
@@ -564,18 +563,18 @@ public:
/// \returns An iterator for the first element in the list /// \returns An iterator for the first element in the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator begin() { constexpr iterator begin() {
return iterator(this, _root); return iterator(this, _root);
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns A const iterator for the first element in the list /// \returns A const iterator for the first element in the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const_iterator begin() const { constexpr const_iterator begin() const {
return const_iterator(this, _root); return const_iterator(this, _root);
@@ -585,25 +584,25 @@ public:
/// \returns An iterator for the end of the list /// \returns An iterator for the end of the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator end() { constexpr iterator end() {
return iterator(this, npos); return iterator(this, npos);
} }
/// ///
/// \brief Const C++ Iterator Specification \f$end()\f$ /// \brief Const C++ Iterator Specification \emph{end()}
/// \returns A const iterator for the end of the list /// \returns A const iterator for the end of the list
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const_iterator end() const { constexpr const_iterator end() const {
return const_iterator(this, npos); return const_iterator(this, npos);
} }
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
class iterator { class iterator {
public: public:
/// ///
@@ -615,7 +614,7 @@ public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \param rhs the iterator to increment /// \param rhs the iterator to increment
/// \returns \f$rhs\f$ after having moved to the next element in the list /// \returns \emph{rhs} after having moved to the next element in the list
constexpr friend iterator& operator++(iterator& rhs) { constexpr friend iterator& operator++(iterator& rhs) {
rhs._n = rhs._list->_next(rhs._n); rhs._n = rhs._list->_next(rhs._n);
return rhs; return rhs;
@@ -624,7 +623,7 @@ public:
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \param lhs the iterator to increment /// \param lhs the iterator to increment
/// \returns \f$lhs\f$ before having moved to the next element in the list /// \returns \emph{lhs} before having moved to the next element in the list
constexpr friend iterator operator++(iterator& lhs, int) { constexpr friend iterator operator++(iterator& lhs, int) {
iterator prev = lhs; iterator prev = lhs;
++lhs; ++lhs;
@@ -648,7 +647,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
constexpr bool operator==(const iterator& it) { constexpr bool operator==(const iterator& it) {
return _list == it._list and _n == it._n; return _list == it._list and _n == it._n;
} }
@@ -656,7 +655,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
constexpr bool operator!=(const iterator& it) { constexpr bool operator!=(const iterator& it) {
return _list != it._list or _n != it._n; return _list != it._list or _n != it._n;
} }
@@ -685,7 +684,7 @@ public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \param rhs the iterator to increment /// \param rhs the iterator to increment
/// \returns \f$rhs\f$ after having moved to the next element in the list /// \returns \emph{rhs} after having moved to the next element in the list
constexpr friend const_iterator& operator++(const_iterator& rhs) { constexpr friend const_iterator& operator++(const_iterator& rhs) {
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) { if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
return rhs; return rhs;
@@ -697,7 +696,7 @@ public:
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \param lhs the iterator to increment /// \param lhs the iterator to increment
/// \returns \f$lhs\f$ before having moved to the next element in the list /// \returns \emph{lhs} before having moved to the next element in the list
constexpr friend const_iterator operator++(const_iterator& lhs, int) { constexpr friend const_iterator operator++(const_iterator& lhs, int) {
const_iterator prev = lhs; const_iterator prev = lhs;
++lhs; ++lhs;
@@ -721,7 +720,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
constexpr bool operator==(const const_iterator& it) { constexpr bool operator==(const const_iterator& it) {
return _list == it._list and _n == it._n; return _list == it._list and _n == it._n;
} }
@@ -729,7 +728,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
constexpr bool operator!=(const const_iterator& it) { constexpr bool operator!=(const const_iterator& it) {
return _list != it._list or _n != it._n; return _list != it._list or _n != it._n;
} }
@@ -800,7 +799,7 @@ private:
constexpr size_t _next_free() { constexpr size_t _next_free() {
if (not _freed.is_empty()) { if (not _freed.is_empty()) {
size_t n = _freed.back(); const size_t n = _freed.back();
_freed.pop_back(); _freed.pop_back();
return n; return n;
} }

View File

@@ -56,24 +56,23 @@ namespace fennec
*/ */
/// ///
/// \brief Data Structure defining a mapping of \f$key\f$ \f$KeyT\f$ to \f$value\f$ \f$ValueT\f$ /// \brief Data Structure defining a mapping of \emph{key} \emph{KeyT} to \emph{value} \emph{ValueT}
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ✅ | /// | distinct | ✅ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(1)\f$ | /// | find | \emph{O(1)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \note These runtimes are amortized, in theory the worst case is \f$O(N)\f$, but that is highly improbable. /// \note These runtimes are amortized, in theory the worst case is \emph{O(N)}, but that is highly improbable.
/// ///
/// \tparam KeyT The Key Type /// \tparam KeyT The Key Type
/// \tparam ValueT The Value Type /// \tparam ValueT The Value Type
@@ -102,7 +101,7 @@ public:
/// \brief key hash helper /// \brief key hash helper
struct key_hash : hash_t { struct key_hash : hash_t {
/// ///
/// \brief C++ 11 Hash Specification \f$operator()\f$ /// \brief C++ 11 Hash Specification \emph{operator()}
/// \param p the pair to hash /// \param p the pair to hash
/// \returns the hash of the key /// \returns the hash of the key
constexpr size_t operator()(const elem_t& p) const { constexpr size_t operator()(const elem_t& p) const {
@@ -114,10 +113,10 @@ public:
/// \brief key comparison helper /// \brief key comparison helper
struct key_equals : equality<KeyT> { struct key_equals : equality<KeyT> {
/// ///
/// \brief C++ 11 Compare Specification \f$operator()\f$ /// \brief C++ 11 Compare Specification \emph{operator()}
/// \param a the first pair /// \param a the first pair
/// \param b the second pair /// \param b the second pair
/// \returns \f$true\f$ if the keys are equal, \f$false\f$ otherwise /// \returns \emph{true} if the keys are equal, \emph{false} otherwise
constexpr bool operator()(const elem_t& a, const elem_t& b) const { constexpr bool operator()(const elem_t& a, const elem_t& b) const {
return equality<KeyT>::operator()(a.first, b.first); return equality<KeyT>::operator()(a.first, b.first);
} }
@@ -156,7 +155,7 @@ public:
} }
/// ///
/// \returns \f$true\f$ when there are no elements in the set, \f$false\f$ otherwise /// \returns \emph{true} when there are no elements in the set, \emph{false} otherwise
constexpr size_t is_empty() const { constexpr size_t is_empty() const {
return _set.size(); return _set.size();
} }
@@ -179,10 +178,10 @@ public:
/// ///
/// \brief Key Access Operator /// \brief Key Access Operator
/// \param key Key value to access /// \param key Key value to access
/// \returns A pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present. /// \returns A pointer to the value associated with \emph{key}, \emph{nullptr} if \emph{key} is not present.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t* operator[](const KeyT& key) { constexpr value_t* operator[](const KeyT& key) {
auto it = _set.at(this->_find(key)); auto it = _set.at(this->_find(key));
@@ -192,10 +191,10 @@ public:
/// ///
/// \brief Key Const Access Operator /// \brief Key Const Access Operator
/// \param key Key value to access /// \param key Key value to access
/// \returns A const-qualified pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present. /// \returns A const-qualified pointer to the value associated with \emph{key}, \emph{nullptr} if \emph{key} is not present.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t* operator[](const KeyT& key) const { constexpr const value_t* operator[](const KeyT& key) const {
auto it = _set.at(this->_find(key)); auto it = _set.at(this->_find(key));
@@ -206,10 +205,10 @@ public:
/// \brief Argument Key Access Operator /// \brief Argument Key Access Operator
/// \tparam ArgsT Argument Types /// \tparam ArgsT Argument Types
/// \param args Arguments to construct the key with /// \param args Arguments to construct the key with
/// \returns A pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present. /// \returns A pointer to the value associated with \emph{key}, \emph{nullptr} if \emph{key} is not present.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr value_t* operator[](ArgsT&&...args) { constexpr value_t* operator[](ArgsT&&...args) {
@@ -221,10 +220,10 @@ public:
/// \brief Argument Key Const Access Operator /// \brief Argument Key Const Access Operator
/// \tparam ArgsT Argument Type /// \tparam ArgsT Argument Type
/// \param args Argument to construct the key with /// \param args Argument to construct the key with
/// \returns A const-qualified pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present. /// \returns A const-qualified pointer to the value associated with \emph{key}, \emph{nullptr} if \emph{key} is not present.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr const value_t* operator[](ArgsT&&...args) const { constexpr const value_t* operator[](ArgsT&&...args) const {
@@ -246,7 +245,7 @@ public:
/// \param pair a pair containing the key and its value /// \param pair a pair containing the key and its value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void insert(elem_t&& pair) { constexpr void insert(elem_t&& pair) {
this->_insert(fennec::forward<elem_t>(pair)); this->_insert(fennec::forward<elem_t>(pair));
@@ -258,7 +257,7 @@ public:
/// \param args Arguments for constructing the key-value pair /// \param args Arguments for constructing the key-value pair
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace(const KeyT& key, ArgsT&&...args) { constexpr void emplace(const KeyT& key, ArgsT&&...args) {
@@ -270,7 +269,7 @@ public:
/// \param args Arguments for constructing the key-value pair /// \param args Arguments for constructing the key-value pair
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) { constexpr void emplace(ArgsT&&...args) {
@@ -282,7 +281,7 @@ public:
/// \param key key to erase /// \param key key to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void erase(KeyT&& key) { constexpr void erase(KeyT&& key) {
_set.erase(this->_find(fennec::forward<KeyT>(key))); _set.erase(this->_find(fennec::forward<KeyT>(key)));
@@ -293,7 +292,7 @@ public:
/// \param key key to erase /// \param key key to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void erase(const KeyT& key) { constexpr void erase(const KeyT& key) {
_set.erase(this->_find(key)); _set.erase(this->_find(key));
@@ -305,7 +304,7 @@ public:
/// \param args Arguments to construct a key to erase /// \param args Arguments to construct a key to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void erase(ArgsT&&...args) { constexpr void erase(ArgsT&&...args) {
@@ -316,7 +315,7 @@ public:
/// \brief Clears the map destructing all elements /// \brief Clears the map destructing all elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void clear() { void clear() {
_set.clear(); _set.clear();
@@ -332,11 +331,11 @@ public:
/// @{ /// @{
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns an iterator at the start of the map /// \returns an iterator at the start of the map
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator begin() { constexpr iterator begin() {
return _set.begin(); return _set.begin();
@@ -344,11 +343,11 @@ public:
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \returns an iterator at the end of the map /// \returns an iterator at the end of the map
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator end() { constexpr iterator end() {
return _set.end(); return _set.end();

View File

@@ -41,20 +41,19 @@ namespace fennec
/// ///
/// \brief Struct which holds a pool of objects associated with ids /// \brief Struct which holds a pool of objects associated with ids
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypeT The value type /// \tparam TypeT The value type
/// \tparam AllocT The allocator type /// \tparam AllocT The allocator type
@@ -88,7 +87,7 @@ public:
/// \brief Default Constructor, initializes an empty object pool /// \brief Default Constructor, initializes an empty object pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr object_pool() constexpr object_pool()
: _size(0) { : _size(0) {
@@ -98,7 +97,7 @@ public:
/// \brief Default Destructor, destructs objects then releases the allocation. /// \brief Default Destructor, destructs objects then releases the allocation.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~object_pool() = default; constexpr ~object_pool() = default;
@@ -114,7 +113,7 @@ public:
/// \returns The number of active objects in the pool /// \returns The number of active objects in the pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
@@ -124,30 +123,30 @@ public:
/// \returns The capacity of the underlying allocation /// \returns The capacity of the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.capacity(); return _table.capacity();
} }
/// ///
/// \returns \f$true\f$ when there are no objects in the pool, \f$false\f$ otherwise /// \returns \emph{true} when there are no objects in the pool, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return size() == 0; return size() == 0;
} }
/// ///
/// \brief Retrieve the next id \f$i\f$ that would be assigned to an object \f$o\f$ were it added to the object pool /// \brief Retrieve the next id \emph{i} that would be assigned to an object \math{o} were it added to the object pool
/// ///
/// \details This can be useful if there are constant members that need to be assigned at construction. /// \details This can be useful if there are constant members that need to be assigned at construction.
/// \returns The id of the next inserted node /// \returns The id of the next inserted node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t next_id() const { constexpr size_t next_id() const {
size_t next = _size; size_t next = _size;
@@ -167,10 +166,10 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i id of the object /// \param i id of the object
/// \returns a reference to the object with id \f$i\f$ /// \returns a reference to the object with id \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
@@ -181,10 +180,10 @@ public:
/// ///
/// \brief Array Const Access Operator /// \brief Array Const Access Operator
/// \param i id of the object /// \param i id of the object
/// \returns a const-qualified reference to the object with id \f$i\f$ /// \returns a const-qualified reference to the object with id \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
@@ -206,24 +205,24 @@ public:
/// @{ /// @{
/// ///
/// \brief Move Insertion, inserts \f$x\f$ into the pool /// \brief Move Insertion, inserts \emph{x} into the pool
/// \param x the object to move /// \param x the object to move
/// \returns An integer corresponding to the id of the node /// \returns An integer corresponding to the id of the node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(value_t&& x) { constexpr size_t insert(value_t&& x) {
return this->_insert(fennec::forward<value_t>(x)); return this->_insert(fennec::forward<value_t>(x));
} }
/// ///
/// \brief Move Insertion, inserts a copy of \f$x\f$ into the pool /// \brief Move Insertion, inserts a copy of \emph{x} into the pool
/// \param x the object to copy /// \param x the object to copy
/// \returns An integer corresponding to the id of the node /// \returns An integer corresponding to the id of the node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(const value_t& x) { constexpr size_t insert(const value_t& x) {
return this->_insert(x); return this->_insert(x);
@@ -231,12 +230,12 @@ public:
/// ///
/// \brief Emplacement, constructs a new object using \f$args\ldots\f$ /// \brief Emplacement, constructs a new object using \emph{args...}
/// \param args The arguments to construct the new object with /// \param args The arguments to construct the new object with
/// \returns An integer corresponding to the id of the node /// \returns An integer corresponding to the id of the node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace(ArgsT&&...args) { constexpr size_t emplace(ArgsT&&...args) {
@@ -248,7 +247,7 @@ public:
/// \param i The id of the object /// \param i The id of the object
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void erase(size_t i) { constexpr void erase(size_t i) {
_table[i] = nullopt; _table[i] = nullopt;
@@ -260,7 +259,7 @@ public:
/// \brief Clear the object pool /// \brief Clear the object pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void clear() { constexpr void clear() {
_table.clear(); _table.clear();
@@ -277,18 +276,18 @@ public:
/// \returns an iterator at the start of the object pool /// \returns an iterator at the start of the object pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
iterator begin() { iterator begin() {
return iterator(this, 0); return iterator(this, 0);
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns an iterator at the start of the object pool /// \returns an iterator at the start of the object pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
const_iterator begin() const { const_iterator begin() const {
return const_iterator(this, 0); return const_iterator(this, 0);
@@ -298,25 +297,25 @@ public:
/// \returns an iterator at the start of the end of the object pool /// \returns an iterator at the start of the end of the object pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
iterator end() { iterator end() {
return iterator(this, _size); return iterator(this, _size);
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \returns an iterator at the start of the end of the object pool /// \returns an iterator at the start of the end of the object pool
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
const_iterator end() const { const_iterator end() const {
return const_iterator(this, _size); return const_iterator(this, _size);
} }
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
class iterator { class iterator {
public: public:
/// ///
@@ -337,18 +336,18 @@ public:
/// ///
/// \brief copy assignment /// \brief copy assignment
/// \param it the iterator to copy /// \param it the iterator to copy
/// \returns a reference to self after having copied \f$it\f$ /// \returns a reference to \emph{this} after having copied \emph{it}
iterator& operator=(const iterator& it) = default; iterator& operator=(const iterator& it) = default;
/// ///
/// \brief move assignment /// \brief move assignment
/// \param it the iterator to move /// \param it the iterator to move
/// \returns a reference to self after having moved \f$it\f$ /// \returns a reference to \emph{this} after having moved \emph{it}
iterator& operator=(iterator&& it) noexcept = default; iterator& operator=(iterator&& it) noexcept = default;
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \returns \f$it\f$ before having been incremented /// \returns \emph{it} before having been incremented
friend iterator operator++(iterator& it, int) { friend iterator operator++(iterator& it, int) {
iterator ret = it; iterator ret = it;
++it.curr; ++it.curr;
@@ -358,7 +357,7 @@ public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \returns \f$it\f$ after having moved to the next element /// \returns \emph{it} after having moved to the next element
friend iterator& operator++(iterator& it) { friend iterator& operator++(iterator& it) {
++it.curr; ++it.curr;
it._fix(); it._fix();
@@ -382,7 +381,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
bool operator==(const iterator& it) { bool operator==(const iterator& it) {
return pool == it.pool and curr == it.curr; return pool == it.pool and curr == it.curr;
} }
@@ -390,7 +389,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
bool operator!=(const iterator& it) { bool operator!=(const iterator& it) {
return pool != it.pool or curr != it.curr; return pool != it.pool or curr != it.curr;
} }
@@ -414,7 +413,7 @@ public:
}; };
/// ///
/// \brief C++ Iterator Specification \f$const_iterator\f$ /// \brief C++ Iterator Specification \emph{const_iterator}
class const_iterator { class const_iterator {
public: public:
/// ///
@@ -435,18 +434,18 @@ public:
/// ///
/// \brief copy assignment /// \brief copy assignment
/// \param it the iterator to copy /// \param it the iterator to copy
/// \returns a reference to self after having copied \f$it\f$ /// \returns a reference to \emph{this} after having copied \emph{it}
const_iterator& operator=(const const_iterator& it) = default; const_iterator& operator=(const const_iterator& it) = default;
/// ///
/// \brief move assignment /// \brief move assignment
/// \param it the iterator to move /// \param it the iterator to move
/// \returns a reference to self after having moved \f$it\f$ /// \returns a reference to \emph{this} after having moved \emph{it}
const_iterator& operator=(const_iterator&& it) noexcept = default; const_iterator& operator=(const_iterator&& it) noexcept = default;
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \returns \f$it\f$ before having been incremented /// \returns \emph{it} before having been incremented
friend const_iterator operator++(const_iterator& it, int) { friend const_iterator operator++(const_iterator& it, int) {
const_iterator ret = it; const_iterator ret = it;
++it.curr; ++it.curr;
@@ -456,7 +455,7 @@ public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \returns \f$it\f$ after having moved to the next element /// \returns \emph{it} after having moved to the next element
friend const_iterator& operator++(const_iterator& it) { friend const_iterator& operator++(const_iterator& it) {
++it.curr; ++it.curr;
it._fix(); it._fix();
@@ -480,7 +479,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
bool operator==(const const_iterator& it) { bool operator==(const const_iterator& it) {
return pool == it.pool and curr == it.curr; return pool == it.pool and curr == it.curr;
} }
@@ -488,7 +487,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
bool operator!=(const const_iterator& it) { bool operator!=(const const_iterator& it) {
return pool != it.pool or curr != it.curr; return pool != it.pool or curr != it.curr;
} }

View File

@@ -39,34 +39,33 @@
namespace fennec namespace fennec
{ {
/// ///
/// \brief struct to represent a \f$null\f$ `fennec::optional` /// \brief struct to represent a \emph{null} `fennec::optional`
struct nullopt_t {}; struct nullopt_t {};
/// ///
/// \brief value representing a \f$null\f$ `fennec::optional` /// \brief value representing a \emph{null} `fennec::optional`
constexpr nullopt_t nullopt_v = {}; constexpr nullopt_t nullopt_v = {};
/// ///
/// \brief alias for representing a \f$null\f$ `fennec::optional` /// \brief alias for representing a \emph{null} `fennec::optional`
#define nullopt nullopt_v #define nullopt nullopt_v
/// ///
/// \brief Structure to hold an optional value. /// \brief Structure to hold an optional value.
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(1)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | ⛔ | /// | find | ⛔ |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(1)\f$ |
/// ///
/// \tparam T /// \tparam T
template<typename T> template<typename T>
@@ -95,7 +94,7 @@ public:
/// \brief Default Constructor /// \brief Default Constructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional() constexpr optional()
: _root(0) : _root(0)
@@ -106,7 +105,7 @@ public:
/// \brief Default Constructor /// \brief Default Constructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional(nullopt_t) constexpr optional(nullopt_t)
: _root(0) : _root(0)
@@ -118,7 +117,7 @@ public:
/// \param val the value to initialize the underlying object with /// \param val the value to initialize the underlying object with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional(const T& val) constexpr optional(const T& val)
: _val(val) : _val(val)
@@ -130,7 +129,7 @@ public:
/// \param val the value to initialize the underlying object with /// \param val the value to initialize the underlying object with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional(T&& val) constexpr optional(T&& val)
: _val(fennec::forward<T>(val)) : _val(fennec::forward<T>(val))
@@ -142,7 +141,7 @@ public:
/// \param opt the optional to copy /// \param opt the optional to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional(const optional& opt) requires is_copy_assignable_v<T> constexpr optional(const optional& opt) requires is_copy_assignable_v<T>
: optional() { : optional() {
@@ -157,7 +156,7 @@ public:
/// \param opt the optional to move /// \param opt the optional to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional(optional&& opt) noexcept requires is_move_assignable_v<T> constexpr optional(optional&& opt) noexcept requires is_move_assignable_v<T>
: optional() { : optional() {
@@ -174,7 +173,7 @@ public:
/// \param args The argument values /// \param args The argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr optional(ArgsT&&...args) constexpr optional(ArgsT&&...args)
@@ -186,7 +185,7 @@ public:
/// \brief destructor /// \brief destructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr ~optional() { constexpr ~optional() {
if constexpr(is_fundamental_v<T>) { if constexpr(is_fundamental_v<T>) {
@@ -207,20 +206,20 @@ public:
/// ///
/// \brief Implicit Boolean Check /// \brief Implicit Boolean Check
/// \returns \f$true\f$ when there is a value contained /// \returns \emph{true} when there is a value contained
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr operator bool() const { constexpr operator bool() const {
return _set; return _set;
} }
/// ///
/// \returns \f$true\f$ when there is no held value, \f$false\f$ otherwise. /// \returns \emph{true} when there is no held value, \emph{false} otherwise.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return not _set; return not _set;
@@ -236,10 +235,10 @@ public:
/// ///
/// \brief Null Assignment /// \brief Null Assignment
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional& operator=(nullopt_t) { constexpr optional& operator=(nullopt_t) {
if constexpr(not is_fundamental_v<T>) { if constexpr(not is_fundamental_v<T>) {
@@ -255,10 +254,10 @@ public:
/// ///
/// \brief Type Copy Assignment /// \brief Type Copy Assignment
/// \param val The value to set with /// \param val The value to set with
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional& operator=(const T& val) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> { constexpr optional& operator=(const T& val) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
if (_set) { if (_set) {
@@ -273,10 +272,10 @@ public:
/// ///
/// \brief Type Move Assignment /// \brief Type Move Assignment
/// \param val The value to set with /// \param val The value to set with
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional& operator=(T&& val) requires is_move_constructible_v<T> and is_move_assignable_v<T> { constexpr optional& operator=(T&& val) requires is_move_constructible_v<T> and is_move_assignable_v<T> {
if (_set) { if (_set) {
@@ -291,10 +290,10 @@ public:
/// ///
/// \brief Copy Assignment /// \brief Copy Assignment
/// \param opt The optional to copy /// \param opt The optional to copy
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> { constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
if (_set != opt._set) { if (_set != opt._set) {
@@ -314,10 +313,10 @@ public:
/// ///
/// \brief Move Assignment /// \brief Move Assignment
/// \param opt The optional to move /// \param opt The optional to move
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v<T> and is_move_assignable_v<T> { constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v<T> and is_move_assignable_v<T> {
if (_set != opt._set) { if (_set != opt._set) {
@@ -343,20 +342,20 @@ public:
/// @{ /// @{
/// ///
/// \returns A pointer to the value, \f$nullptr\f$ if there is no value /// \returns A pointer to the value, \emph{nullptr} if there is no value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pointer_t operator->() noexcept { constexpr pointer_t operator->() noexcept {
return _set ? &_val : nullptr; return _set ? &_val : nullptr;
} }
/// ///
/// \returns A const-qualified pointer to the value, \f$nullptr\f$ if there is no value /// \returns A const-qualified pointer to the value, \emph{nullptr} if there is no value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const_pointer_t operator->() const noexcept { constexpr const_pointer_t operator->() const noexcept {
return _set ? &_val : nullptr; return _set ? &_val : nullptr;
@@ -367,7 +366,7 @@ public:
/// \returns A reference to the value /// \returns A reference to the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr T& operator*() & noexcept { constexpr T& operator*() & noexcept {
assertd(_set, "Attempted to reference the value of an unset optional"); assertd(_set, "Attempted to reference the value of an unset optional");
@@ -379,7 +378,7 @@ public:
/// \returns A const-qualified reference to the value /// \returns A const-qualified reference to the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const T& operator*() const& noexcept { constexpr const T& operator*() const& noexcept {
assertd(_set, "Attempted to reference the value of an unset optional"); assertd(_set, "Attempted to reference the value of an unset optional");
@@ -391,7 +390,7 @@ public:
/// \returns A reference to the value /// \returns A reference to the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr T&& operator*() && noexcept { constexpr T&& operator*() && noexcept {
assertd(_set, "Attempted to reference the value of an unset optional"); assertd(_set, "Attempted to reference the value of an unset optional");
@@ -403,7 +402,7 @@ public:
/// \returns A const-qualified reference to the value /// \returns A const-qualified reference to the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const T&& operator*() const&& noexcept { constexpr const T&& operator*() const&& noexcept {
assertd(_set, "Attempted to reference the value of an unset optional"); assertd(_set, "Attempted to reference the value of an unset optional");
@@ -423,7 +422,7 @@ public:
/// \returns A reference to the held value /// \returns A reference to the held value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr T& emplace(T&& val) { constexpr T& emplace(T&& val) {
if (_set) { if (_set) {
@@ -441,7 +440,7 @@ public:
/// \returns A reference to the held value /// \returns A reference to the held value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr T& emplace(const T& val) { constexpr T& emplace(const T& val) {
if (_set) { if (_set) {
@@ -459,7 +458,7 @@ public:
/// \returns A reference to the held value /// \returns A reference to the held value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr T& emplace(ArgsT&&...args) { constexpr T& emplace(ArgsT&&...args) {
@@ -476,7 +475,7 @@ public:
/// \brief Reset the Optional /// \brief Reset the Optional
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
void reset() { void reset() {
this->operator=(nullopt); this->operator=(nullopt);

View File

@@ -43,20 +43,19 @@ namespace fennec
/// ///
/// \brief Struct for holding a pair of values /// \brief Struct for holding a pair of values
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogeneous | ⛔ | /// | homogeneous | ⛔ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(1)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | ⛔ | /// | find | ⛔ |
/// | insertion | ⛔ | /// | insertion | ⛔ |
/// | deletion | ⛔ | /// | deletion | ⛔ |
/// | space | \f$O(1)\f$ |
/// ///
/// \tparam TypeT0 The type of the first value /// \tparam TypeT0 The type of the first value
/// \tparam TypeT1 The type of the second value /// \tparam TypeT1 The type of the second value
@@ -85,7 +84,7 @@ public:
/// \brief Default Constructor, invokes default constructor for both elements /// \brief Default Constructor, invokes default constructor for both elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair() = default; constexpr pair() = default;
@@ -93,7 +92,7 @@ public:
/// \brief Destructor, invokes destructor for both elements /// \brief Destructor, invokes destructor for both elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr ~pair() = default; constexpr ~pair() = default;
@@ -103,7 +102,7 @@ public:
/// \param y Value to copy for the first element /// \param y Value to copy for the first element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair(const TypeT0& x, const TypeT1& y) constexpr pair(const TypeT0& x, const TypeT1& y)
: first(x) : first(x)
@@ -116,7 +115,7 @@ public:
/// \param y Value to move for the first element /// \param y Value to move for the first element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair(TypeT0&& x, TypeT1&& y) noexcept constexpr pair(TypeT0&& x, TypeT1&& y) noexcept
: first(fennec::forward<TypeT0>(x)) : first(fennec::forward<TypeT0>(x))
@@ -129,7 +128,7 @@ public:
/// \param arg2 Value to initialize the first element /// \param arg2 Value to initialize the first element
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename Arg1T, typename Arg2T> template<typename Arg1T, typename Arg2T>
constexpr pair(Arg1T&& arg1, Arg2T&& arg2) constexpr pair(Arg1T&& arg1, Arg2T&& arg2)
@@ -142,7 +141,7 @@ public:
/// \param pair The pair to copy /// \param pair The pair to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair(const pair& pair) constexpr pair(const pair& pair)
: first(fennec::copy(pair.first)) : first(fennec::copy(pair.first))
@@ -154,7 +153,7 @@ public:
/// \param pair The pair to move /// \param pair The pair to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair(pair&& pair) noexcept constexpr pair(pair&& pair) noexcept
: first(fennec::move(pair.first)) : first(fennec::move(pair.first))
@@ -164,10 +163,10 @@ public:
/// ///
/// \brief Copy Assignment, copies both elements /// \brief Copy Assignment, copies both elements
/// \param pair The pair to copy /// \param pair The pair to copy
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair& operator=(const pair& pair) { constexpr pair& operator=(const pair& pair) {
first = fennec::copy(pair.first); first = fennec::copy(pair.first);
@@ -178,10 +177,10 @@ public:
/// ///
/// \brief Move Assignment, moves both elements /// \brief Move Assignment, moves both elements
/// \param pair The pair to move /// \param pair The pair to move
/// \returns A reference to self /// \returns A reference to \emph{this}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr pair& operator=(pair&& pair) { constexpr pair& operator=(pair&& pair) {
first = fennec::move(pair.first); first = fennec::move(pair.first);
@@ -201,10 +200,10 @@ public:
/// ///
/// \brief Equality Operator /// \brief Equality Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns \f$true\f$ when both elements of each pair are equal /// \returns \emph{true} when both elements of each pair are equal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool operator==(const pair& p) const { constexpr bool operator==(const pair& p) const {
return first == p.first and second == p.second; return first == p.first and second == p.second;
@@ -213,10 +212,10 @@ public:
/// ///
/// \brief Inequality Operator /// \brief Inequality Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns \f$true\f$ when either element of each pair are equal /// \returns \emph{true} when either element of each pair are equal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool operator!=(const pair& p) const { constexpr bool operator!=(const pair& p) const {
return first != p.first or second != p.second; return first != p.first or second != p.second;
@@ -225,11 +224,11 @@ public:
/// ///
/// \brief Less Than Operator /// \brief Less Than Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is less, or they are /// \returns lexical comparison of both elements, i.e. returns \emph{true} when the first element is less, or they are
/// equal and the second element is less /// equal and the second element is less
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool operator<(const pair& p) const { constexpr bool operator<(const pair& p) const {
return first < p.first or (first == p.first and second < p.second); return first < p.first or (first == p.first and second < p.second);
@@ -238,11 +237,11 @@ public:
/// ///
/// \brief Less Equal Operator /// \brief Less Equal Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is less, or they are /// \returns lexical comparison of both elements, i.e. returns \emph{true} when the first element is less, or they are
/// equal and the second element is less or equal /// equal and the second element is less or equal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool operator<=(const pair& p) const { constexpr bool operator<=(const pair& p) const {
return first < p.first or (first == p.first and second <= p.second); return first < p.first or (first == p.first and second <= p.second);
@@ -251,11 +250,11 @@ public:
/// ///
/// \brief Greater Than Operator /// \brief Greater Than Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is greater, or they are /// \returns lexical comparison of both elements, i.e. returns \emph{true} when the first element is greater, or they are
/// equal and the second element is greater /// equal and the second element is greater
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool operator>(const pair& p) const { constexpr bool operator>(const pair& p) const {
return first > p.first or (first == p.first and second > p.second); return first > p.first or (first == p.first and second > p.second);
@@ -264,11 +263,11 @@ public:
/// ///
/// \brief Greater Equal Operator /// \brief Greater Equal Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is greater, or they are /// \returns lexical comparison of both elements, i.e. returns \emph{true} when the first element is greater, or they are
/// equal and the second element is greater or equal /// equal and the second element is greater or equal
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool operator>=(const pair& p) const { constexpr bool operator>=(const pair& p) const {
return first > p.first or (first == p.first and second >= p.second); return first > p.first or (first == p.first and second >= p.second);
@@ -284,9 +283,9 @@ public:
template<typename TypeT0, typename TypeT1> template<typename TypeT0, typename TypeT1>
struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> { struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> {
/// ///
/// \brief C++ 11 Hash Specification \f$operator()\f$ /// \brief C++ 11 Hash Specification \emph{operator()}
/// \param p The pair to hash /// \param p The pair to hash
/// \returns a pairing of the hashes of both elements of \f$p\f$ using `fennec::pair_hash` /// \returns a pairing of the hashes of both elements of \emph{p} using `fennec::pair_hash`
constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const { constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const {
return fennec::pair_hash( // pair the hashes of both elements return fennec::pair_hash( // pair the hashes of both elements
hash<TypeT0>::operator()(p.first), hash<TypeT0>::operator()(p.first),

View File

@@ -56,20 +56,20 @@ namespace fennec
/// ///
/// \brief a priority queue data structure implemented using a binary heap /// \brief a priority queue data structure implemented using a binary heap
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ✅ | /// | ordered | ✅ |
/// | space | \f$O(N)\f$ | /// | space | \emph{O(N)} |
/// | linear | ✅ | /// | linear | ✅ |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | ⛔ | /// | find | ⛔ |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ | /// | space | \emph{O(N)} |
/// ///
/// \tparam ValueT The value type /// \tparam ValueT The value type
/// \tparam CompareT The compare type, defaults to `fennec::less` /// \tparam CompareT The compare type, defaults to `fennec::less`
@@ -115,7 +115,7 @@ public:
/// \details initializes an empty queue /// \details initializes an empty queue
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr priority_queue() constexpr priority_queue()
: _size(0) { : _size(0) {
@@ -125,7 +125,7 @@ public:
/// \brief destructor /// \brief destructor
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~priority_queue() { constexpr ~priority_queue() {
while (_size > 0) { while (_size > 0) {
@@ -142,7 +142,7 @@ public:
/// \returns the size of the queue /// \returns the size of the queue
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
@@ -152,17 +152,17 @@ public:
/// \returns the capacity of the underlying allocation /// \returns the capacity of the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.capacity(); return _table.capacity();
} }
/// ///
/// \returns \f$true\f$ if the queue holds no elements /// \returns \emph{true} if the queue holds no elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return size() == 0; return size() == 0;
@@ -176,7 +176,7 @@ public:
/// \returns the value at the front of the queue /// \returns the value at the front of the queue
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& front() const { constexpr const value_t& front() const {
return _table[0]; return _table[0];
@@ -191,7 +191,7 @@ public:
/// \param key the key to insert /// \param key the key to insert
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr void push(const value_t& key) { constexpr void push(const value_t& key) {
this->_insert(key); this->_insert(key);
@@ -201,7 +201,7 @@ public:
/// \param key the key to insert /// \param key the key to insert
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr void push(value_t&& key) { constexpr void push(value_t&& key) {
this->_insert(fennec::forward<value_t>(key)); this->_insert(fennec::forward<value_t>(key));
@@ -213,7 +213,7 @@ public:
/// \param args the argument values /// \param args the argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) { constexpr void emplace(ArgsT&&...args) {
@@ -224,7 +224,7 @@ public:
/// \brief pop the element at the front of the queue /// \brief pop the element at the front of the queue
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr void pop() { constexpr void pop() {
fennec::swap(_table[0], _table[--_size]); fennec::swap(_table[0], _table[--_size]);

View File

@@ -32,7 +32,7 @@
#define FENNEC_CONTAINERS_RDTREE_H #define FENNEC_CONTAINERS_RDTREE_H
#include <fennec/containers/list.h> #include <fennec/containers/list.h>
#include <fennec/containers/optional.h> #include <fennec/containers/deque.h>
#include <fennec/containers/traversal.h> #include <fennec/containers/traversal.h>
#include <fennec/containers/pair.h> #include <fennec/containers/pair.h>
@@ -44,20 +44,19 @@ namespace fennec
/// ///
/// \brief Rooted-Directed Tree /// \brief Rooted-Directed Tree
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(N)\f$ | /// | find | \emph{O(N)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypeT Data type /// \tparam TypeT Data type
/// \tparam AllocT Allocator Type /// \tparam AllocT Allocator Type
@@ -133,7 +132,7 @@ public:
/// \param args The arguments to construct the root with /// \param args The arguments to construct the root with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
explicit constexpr rdtree(ArgsT&&...args) explicit constexpr rdtree(ArgsT&&...args)
@@ -143,23 +142,62 @@ public:
} }
/// ///
/// \brief Copy Constructor, copies the contents of \f$tree\f$ /// \brief Copy Constructor, copies the contents of \emph{tree}
/// \param tree the rdtree to copy /// \param tree the rdtree to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr rdtree(const rdtree& tree) constexpr rdtree(const rdtree& tree) {
: _table(tree._table), _freed(tree._freed), _size(tree._size) { _table.reallocate(tree.size());
// TODO: properly invoke copy constructor for all elements
// Stack used for depth-first traversal
deque<size_t> visit;
deque<size_t> stack;
// Push the root to the visit queue if the tree isn't empty
if (not tree.is_empty()) {
stack.push_back(npos);
visit.push_back(root);
}
// Iterate
while (not visit.is_empty()) {
// Pop the next node
const size_t node = visit.front();
visit.pop_front();
// Get the next node and the child
const size_t next = tree.next(node);
const size_t child = tree.child(node);
// Fix stack
while (tree.depth(node) < stack.size()) {
stack.pop_back();
}
// Add this node
stack.push_back(insert(stack.back(), npos, tree[node]));
// Push the next node
if (next != npos) {
visit.push_front(next);
}
// Push the child
if (child != npos) {
visit.push_front(child);
}
}
} }
/// ///
/// \brief Move Constructor, takes ownership over the contents of \f$tree\f$ /// \brief Move Constructor, takes ownership over the contents of \emph{tree}
/// \param tree the rdtree to move /// \param tree the rdtree to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr rdtree(rdtree&& tree) noexcept constexpr rdtree(rdtree&& tree) noexcept
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) { : _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
@@ -176,10 +214,10 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param rhs the rdtree to copy /// \param rhs the rdtree to copy
/// \returns \f$this\f$ after copying the contents of \f$rhs\f$ /// \returns \emph{this} after copying the contents of \emph{rhs}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr rdtree& operator=(const rdtree& rhs) { constexpr rdtree& operator=(const rdtree& rhs) {
// TODO: properly invoke copy constructor for all elements // TODO: properly invoke copy constructor for all elements
@@ -195,10 +233,10 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param rhs the rdtree to move /// \param rhs the rdtree to move
/// \returns \f$this\f$ after taking ownership over the contents of \f$rhs\f$ /// \returns \emph{this} after taking ownership over the contents of \emph{rhs}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr rdtree& operator=(rdtree&& rhs) noexcept { constexpr rdtree& operator=(rdtree&& rhs) noexcept {
for (value_t* it : _table) { for (value_t* it : _table) {
@@ -221,7 +259,7 @@ public:
/// \returns The number of nodes in the tree /// \returns The number of nodes in the tree
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
@@ -231,17 +269,17 @@ public:
/// \returns The capacity of the underlying allocation /// \returns The capacity of the underlying allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.capacity(); return _table.capacity();
} }
/// ///
/// \returns \f$true\f$ when there are no nodes in the tree, \f$false\f$ otherwise /// \returns \emph{true} when there are no nodes in the tree, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _size == 0; return _size == 0;
@@ -260,7 +298,7 @@ public:
/// \returns The id of the parent node /// \returns The id of the parent node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t parent(size_t i) const { constexpr size_t parent(size_t i) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
@@ -273,11 +311,11 @@ public:
/// \returns The id of the child node /// \returns The id of the child node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t child(size_t i, size_t n = 0) const { constexpr size_t child(size_t i, size_t n = 0) const {
if (i >= _table.capacity() && n != npos) return npos; if (i >= _table.capacity() && n != npos) return npos;
size_t c = i == npos ? npos : _table[i].child; const size_t c = i == npos ? npos : _table[i].child;
if (n != 0) if (n != 0)
return next(c, n == npos ? npos : n - 1); return next(c, n == npos ? npos : n - 1);
return c; return c;
@@ -289,7 +327,7 @@ public:
/// \returns The id of the next node /// \returns The id of the next node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t next(size_t i, size_t n = 0) const { constexpr size_t next(size_t i, size_t n = 0) const {
if (i >= _table.capacity() && n != npos) return npos; if (i >= _table.capacity() && n != npos) return npos;
@@ -297,7 +335,7 @@ public:
return npos; return npos;
} }
size_t org = i; const size_t org = i;
size_t nxt = _table[i].next; size_t nxt = _table[i].next;
while (nxt != npos) { while (nxt != npos) {
i = nxt; i = nxt;
@@ -318,7 +356,7 @@ public:
/// \returns The id of the previous node /// \returns The id of the previous node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t prev(size_t i, size_t n = 0) const { constexpr size_t prev(size_t i, size_t n = 0) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
@@ -326,7 +364,7 @@ public:
return npos; return npos;
} }
size_t org = i; const size_t org = i;
size_t prv = _table[i].prev; size_t prv = _table[i].prev;
while (prv != npos) { while (prv != npos) {
i = prv; i = prv;
@@ -343,10 +381,10 @@ public:
/// ///
/// \param i the node to start at /// \param i the node to start at
/// \returns the left-most child of node \f$i\f$ /// \returns the left-most child of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr size_t left_most(size_t i) const { constexpr size_t left_most(size_t i) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
@@ -355,7 +393,7 @@ public:
return i; return i;
} }
while (true) { while (true) {
size_t p = n; const size_t p = n;
if ((n = child(n)) == npos) { if ((n = child(n)) == npos) {
return p; return p;
} }
@@ -364,10 +402,10 @@ public:
/// ///
/// \param i the node to start at /// \param i the node to start at
/// \returns the right-most child of node \f$i\f$ /// \returns the right-most child of node \emph{i}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr size_t right_most(size_t i) const { constexpr size_t right_most(size_t i) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
@@ -391,7 +429,7 @@ public:
/// \returns The depth of the node /// \returns The depth of the node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t depth(size_t i) const { constexpr size_t depth(size_t i) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
@@ -403,7 +441,7 @@ public:
/// \returns The number of children the node has /// \returns The number of children the node has
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t num_children(size_t i) const { constexpr size_t num_children(size_t i) const {
if (i >= _table.capacity()) return 0; if (i >= _table.capacity()) return 0;
@@ -411,10 +449,10 @@ public:
} }
/// ///
/// \returns The next node id were \f$insert\f$ or \f$emplace\f$ to be called /// \returns The next node id were \emph{insert} or \emph{emplace} to be called
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t next_id() const { constexpr size_t next_id() const {
size_t i = _size; size_t i = _size;
@@ -429,7 +467,7 @@ public:
/// \returns A reference to the value of the node wrapped in an optional /// \returns A reference to the value of the node wrapped in an optional
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
return _table[i].value; return _table[i].value;
@@ -440,7 +478,7 @@ public:
/// \returns A const-qualified reference to the value of the node wrapped in an optional /// \returns A const-qualified reference to the value of the node wrapped in an optional
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
return _table[i].value; return _table[i].value;
@@ -455,28 +493,28 @@ public:
/// @{ /// @{
/// ///
/// \brief Insertion, creates a node in the tree with parent \f$parent\f$ /// \brief Insertion, creates a node in the tree with parent \emph{parent}
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node /// \param parent the parent node, if \emph{npos} sets the value of the root node
/// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next /// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next
/// \param val the value to insert /// \param val the value to insert
/// \returns the index of the created node /// \returns the index of the created node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(size_t parent, size_t next, const value_t& val) { constexpr size_t insert(size_t parent, size_t next, const value_t& val) {
return this->_insert(parent, next, val); return this->_insert(parent, next, val);
} }
/// ///
/// \brief Insertion, creates a node in the tree with parent \f$parent\f$ /// \brief Insertion, creates a node in the tree with parent \emph{parent}
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node /// \param parent the parent node, if \emph{npos} sets the value of the root node
/// \param next the next node, as an index relative to the parent /// \param next the next node, as an index relative to the parent
/// \param val the value to insert /// \param val the value to insert
/// \returns the index of the created node /// \returns the index of the created node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(size_t parent, size_t next, value_t&& val) { constexpr size_t insert(size_t parent, size_t next, value_t&& val) {
return this->_insert(parent, next, fennec::forward<value_t>(val)); return this->_insert(parent, next, fennec::forward<value_t>(val));
@@ -484,13 +522,13 @@ public:
/// ///
/// \brief tree insertion, copies the contents of tree into self with the root at the specified node location /// \brief tree insertion, copies the contents of tree into self with the root at the specified node location
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node /// \param parent the parent node, if \emph{npos} sets the value of the root node
/// \param next the next node, as an index relative to the parent /// \param next the next node, as an index relative to the parent
/// \param tree the tree to insert /// \param tree the tree to insert
/// \returns the index of the inserted root /// \returns the index of the inserted root
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t insert(size_t parent, size_t next, const rdtree& tree) { constexpr size_t insert(size_t parent, size_t next, const rdtree& tree) {
list<pair<size_t, size_t>> visit; list<pair<size_t, size_t>> visit;
@@ -516,14 +554,14 @@ public:
} }
/// ///
/// \brief Insertion, creates a node in the tree with parent \f$parent\f$ /// \brief Insertion, creates a node in the tree with parent \emph{parent}
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node /// \param parent the parent node, if \emph{npos} sets the value of the root node
/// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next /// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next
/// \param args the args to construct the value to insert /// \param args the args to construct the value to insert
/// \returns the index of the created node /// \returns the index of the created node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace(size_t parent, size_t next, ArgsT&&...args) { constexpr size_t emplace(size_t parent, size_t next, ArgsT&&...args) {
@@ -536,7 +574,7 @@ public:
/// \param i1 The id of the second node /// \param i1 The id of the second node
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void swap(size_t i0, size_t i1) { constexpr void swap(size_t i0, size_t i1) {
assertf(i0 != root and i1 != root, "Cannot Swap With Root"); assertf(i0 != root and i1 != root, "Cannot Swap With Root");
@@ -575,16 +613,16 @@ public:
/// \brief Traverse the tree using a specified order and visiting functor /// \brief Traverse the tree using a specified order and visiting functor
/// ///
/// \details /// \details
/// The visitor should accept a reference to a value of type \f$TypeT\f$ and a \f$size_t\f$ which contains the node's id. /// The visitor should accept a reference to a value of type \emph{TypeT} and a \emph{size_t} which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum /// The visitor should return one of the following values in the `fennec::traversal_control_` enum
/// ///
/// \tparam OrderT The order with which to traverse the tree. /// \tparam OrderT The order with which to traverse the tree.
/// \tparam VisitorT The visitor, should fulfill the signature \f$uint8_t visit(TypeT&, size_t)\f$ /// \tparam VisitorT The visitor, should fulfill the signature \emph{uint8_t visit(TypeT&, size_t)}
/// \param visit The visiting object /// \param visit The visiting object
/// \param i The node to start at /// \param i The node to start at
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename OrderT, typename VisitorT> template<typename OrderT, typename VisitorT>
constexpr void traverse(VisitorT&& visit, size_t i = root) { constexpr void traverse(VisitorT&& visit, size_t i = root) {
@@ -606,16 +644,16 @@ public:
/// \brief Traverse the tree using a specified order and visiting functor /// \brief Traverse the tree using a specified order and visiting functor
/// ///
/// \details /// \details
/// The visitor should accept a reference to a value of type \f$TypeT\f$ and a \f$size_t\f$ which contains the node's id. /// The visitor should accept a reference to a value of type \emph{TypeT} and a \emph{size_t} which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum /// The visitor should return one of the following values in the `fennec::traversal_control_` enum
/// ///
/// \tparam OrderT The order with which to traverse the tree. /// \tparam OrderT The order with which to traverse the tree.
/// \tparam VisitorT The visitor, should fulfill the signature \f$uint8_t visit(TypeT&, size_t)\f$ /// \tparam VisitorT The visitor, should fulfill the signature \emph{uint8_t visit(TypeT&, size_t)}
/// \param visit The visiting object /// \param visit The visiting object
/// \param i The node to start at /// \param i The node to start at
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename OrderT, typename VisitorT> template<typename OrderT, typename VisitorT>
constexpr void traverse(VisitorT&& visit, size_t i = root) const { constexpr void traverse(VisitorT&& visit, size_t i = root) const {
@@ -657,8 +695,8 @@ public:
return npos; return npos;
} }
size_t nxt = tree.next(node); const size_t nxt = tree.next(node);
size_t chd = tree.next(node); const size_t chd = tree.next(node);
if (nxt != npos && node != head) { if (nxt != npos && node != head) {
visit.push_front(nxt); visit.push_front(nxt);
@@ -680,7 +718,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = npos;
}; };
/// ///
@@ -707,8 +745,8 @@ public:
return npos; return npos;
} }
size_t nxt = tree.next(node); const size_t nxt = tree.next(node);
size_t chd = tree.child(node); const size_t chd = tree.child(node);
if (nxt != npos && node != head) { if (nxt != npos && node != head) {
visit.push_front(nxt); visit.push_front(nxt);
@@ -730,7 +768,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = npos;
}; };
/// ///
@@ -757,8 +795,8 @@ public:
return npos; return npos;
} }
size_t prnt = tree.parent(node); const size_t prnt = tree.parent(node);
size_t next = tree.next(node); const size_t next = tree.next(node);
if (node != head) { if (node != head) {
if (tree.child(prnt) == node) { if (tree.child(prnt) == node) {
visit.push_back(prnt); visit.push_back(prnt);
@@ -782,7 +820,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = npos;
}; };
/// ///
@@ -809,8 +847,8 @@ public:
return npos; return npos;
} }
size_t prnt = tree.parent(node); const size_t prnt = tree.parent(node);
size_t next = tree.next(node); const size_t next = tree.next(node);
if (node != head) { if (node != head) {
if (next != npos) { if (next != npos) {
@@ -832,7 +870,7 @@ public:
private: private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head = npos;
}; };
/// @} /// @}

View File

@@ -56,20 +56,19 @@ namespace fennec
/// \details /// \details
/// This data-structure behaves like an ordered-set, but does not use pointers, instead storing the table in-array /// This data-structure behaves like an ordered-set, but does not use pointers, instead storing the table in-array
/// ///
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:---------------:| /// |:-----------:|:----------------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ✅ | /// | distinct | ✅ |
/// | ordered | ✅ | /// | ordered | ✅ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(\log N)\f$ | /// | access | \emph{O(\log N)} |
/// | find | \f$O(\log N)\f$ | /// | find | \emph{O(\log N)} |
/// | insertion | \f$O(\log N)\f$ | /// | insertion | \emph{O(\log N)} |
/// | deletion | \f$O(\log N)\f$ | /// | deletion | \emph{O(\log N)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypeT The type to contain /// \tparam TypeT The type to contain
/// \tparam CompareT Function for comparing two values /// \tparam CompareT Function for comparing two values
@@ -141,27 +140,27 @@ private:
// Member Access Helpers // Member Access Helpers
constexpr value_t& _key(node n) { static constexpr value_t& _key(node n) {
return n->key; return n->key;
} }
constexpr bool& _color(node n) { static constexpr bool& _color(node n) {
return n->color; return n->color;
} }
constexpr node& _parent(node n) { static constexpr node& _parent(node n) {
return n->parent; return n->parent;
} }
constexpr node& _child(node n, bool dir) { static constexpr node& _child(node n, bool dir) {
return n->child[dir]; return n->child[dir];
} }
constexpr node& _left(node n) { static constexpr node& _left(node n) {
return n->child[dir_left]; return n->child[dir_left];
} }
constexpr node& _right(node n) { static constexpr node& _right(node n) {
return n->child[dir_right]; return n->child[dir_right];
} }
@@ -174,7 +173,7 @@ private:
} }
constexpr bool color(node n) { constexpr bool color(node n) {
return n ? n->color : (bool)black; return n ? n->color : bool(black);
} }
constexpr node parent(node n) { constexpr node parent(node n) {
@@ -224,7 +223,7 @@ public:
/// \brief Default Constructor, initializes an empty sequence /// \brief Default Constructor, initializes an empty sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr sequence() constexpr sequence()
: _root(nullptr), _size(0) { : _root(nullptr), _size(0) {
@@ -234,7 +233,7 @@ public:
/// \brief Move Constructor, takes ownership of a sequence /// \brief Move Constructor, takes ownership of a sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr sequence(sequence&&) noexcept = default; constexpr sequence(sequence&&) noexcept = default;
@@ -247,7 +246,7 @@ public:
/// \brief Default Destructor, destructs elements *in-order* /// \brief Default Destructor, destructs elements *in-order*
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~sequence() { constexpr ~sequence() {
this->clear(); this->clear();
@@ -261,12 +260,12 @@ public:
/// @{ /// @{
/// ///
/// \brief Value Find Function, finds the iterator position for \f$val\f$, otherwise returns \f$end()\f$ /// \brief Value Find Function, finds the iterator position for \emph{val}, otherwise returns \emph{end()}
/// \param val The value to find /// \param val The value to find
/// \returns An iterator at the value /// \returns An iterator at the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr iterator find(const value_t& val) { constexpr iterator find(const value_t& val) {
node node = _root; node node = _root;
@@ -285,7 +284,7 @@ public:
/// ///
/// \brief Value Contains Function, checks if the sequence contains a value /// \brief Value Contains Function, checks if the sequence contains a value
/// \param val The value to find /// \param val The value to find
/// \returns \f$true\f$ if \f$val\f$ is in the sequence, \f$false\f$ otherwise /// \returns \emph{true} if \emph{val} is in the sequence, \emph{false} otherwise
bool contains(const value_t& val) { bool contains(const value_t& val) {
return find(val) != end(); return find(val) != end();
} }
@@ -302,17 +301,17 @@ public:
/// \returns The number of elements in the sequence /// \returns The number of elements in the sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
} }
/// ///
/// \returns \f$true\f$ when there are no elements in the sequence, \f$false\f$ otherwise. /// \returns \emph{true} when there are no elements in the sequence, \emph{false} otherwise.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _size == 0; return _size == 0;
@@ -326,11 +325,11 @@ public:
/// @{ /// @{
/// ///
/// \brief Move Insertion, moves \f$val\f$ into the sequence /// \brief Move Insertion, moves \emph{val} into the sequence
/// \param val The value to insert /// \param val The value to insert
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr void insert(value_t&& val) { constexpr void insert(value_t&& val) {
node i = _insert_bst(fennec::forward<value_t>(val)); node i = _insert_bst(fennec::forward<value_t>(val));
@@ -338,11 +337,11 @@ public:
} }
/// ///
/// \brief Copy Insertion, inserts a copy of \f$val\f$ into the sequence /// \brief Copy Insertion, inserts a copy of \emph{val} into the sequence
/// \param val The value to insert /// \param val The value to insert
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr void insert(const value_t& val) { constexpr void insert(const value_t& val) {
node i = _insert_bst(val); node i = _insert_bst(val);
@@ -355,7 +354,7 @@ public:
/// \param args The arguments to construct with /// \param args The arguments to construct with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) { constexpr void emplace(ArgsT&&...args) {
@@ -368,7 +367,7 @@ public:
/// \param val the value to erase /// \param val the value to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr void erase(const value_t& val) { constexpr void erase(const value_t& val) {
_erase(find(val)._node); _erase(find(val)._node);
@@ -378,7 +377,7 @@ public:
/// \brief Destructs all elements, *in-order*, contained in the sequence /// \brief Destructs all elements, *in-order*, contained in the sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void clear() { constexpr void clear() {
list<node> visit; list<node> visit;
@@ -400,18 +399,18 @@ public:
/// \returns An iterator at the smallest element in the sequence /// \returns An iterator at the smallest element in the sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr iterator begin() { constexpr iterator begin() {
return sequence::iterator(this, _root); return sequence::iterator(this, _root);
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns An iterator at the smallest element in the sequence /// \returns An iterator at the smallest element in the sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(\log N)\f$ /// \emph{O(\log N)}
/// ///
constexpr const_iterator begin() const { constexpr const_iterator begin() const {
return sequence::const_iterator(this, _root); return sequence::const_iterator(this, _root);
@@ -421,32 +420,32 @@ public:
/// \returns An iterator after the largest element in the sequence /// \returns An iterator after the largest element in the sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator end() { constexpr iterator end() {
return sequence::iterator(this, _root, nullptr); return sequence::iterator(this, _root, nullptr);
} }
/// ///
/// \brief Const C++ Iterator Specification \f$end()\f$ /// \brief Const C++ Iterator Specification \emph{end()}
/// \returns An iterator after the largest element in the sequence /// \returns An iterator after the largest element in the sequence
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const_iterator end() const { constexpr const_iterator end() const {
return sequence::const_iterator(this, _root, nullptr); return sequence::const_iterator(this, _root, nullptr);
} }
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
class iterator { class iterator {
public: public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \param it the iterator to increment /// \param it the iterator to increment
/// \returns \f$it\f$ after having moved to the next element in the list /// \returns \emph{it} after having moved to the next element in the list
friend iterator& operator++(iterator& it) { friend iterator& operator++(iterator& it) {
if (it._node == nullptr) { if (it._node == nullptr) {
return it; return it;
@@ -477,7 +476,7 @@ public:
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \param it the iterator to increment /// \param it the iterator to increment
/// \returns \f$it\f$ before having moved to the next element in the list /// \returns \emph{it} before having moved to the next element in the list
friend iterator operator++(iterator& it, int) { friend iterator operator++(iterator& it, int) {
iterator prev = it; iterator prev = it;
++it; ++it;
@@ -502,7 +501,7 @@ public:
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param lhs the iterator /// \param lhs the iterator
/// \param rhs the iterator to compare with /// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
constexpr friend bool operator==(const iterator& lhs, const iterator& rhs) { constexpr friend bool operator==(const iterator& lhs, const iterator& rhs) {
return lhs._seq == rhs._seq and lhs._node == rhs._node; return lhs._seq == rhs._seq and lhs._node == rhs._node;
} }
@@ -511,7 +510,7 @@ public:
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param lhs the iterator /// \param lhs the iterator
/// \param rhs the iterator to compare with /// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
constexpr friend bool operator!=(const iterator& lhs, const iterator& rhs) { constexpr friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return lhs._seq != rhs._seq or lhs._node != rhs._node; return lhs._seq != rhs._seq or lhs._node != rhs._node;
} }
@@ -538,14 +537,14 @@ public:
}; };
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
class const_iterator { class const_iterator {
public: public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \param it the iterator to increment /// \param it the iterator to increment
/// \returns \f$it\f$ after having moved to the next element in the list /// \returns \emph{it} after having moved to the next element in the list
friend const_iterator& operator++(const_iterator& it) { friend const_iterator& operator++(const_iterator& it) {
if (it._node == nullptr) { if (it._node == nullptr) {
return it; return it;
@@ -576,7 +575,7 @@ public:
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \param it the iterator to increment /// \param it the iterator to increment
/// \returns \f$it\f$ before having moved to the next element in the list /// \returns \emph{it} before having moved to the next element in the list
friend const_iterator operator++(const_iterator& it, int) { friend const_iterator operator++(const_iterator& it, int) {
const_iterator prev = it; const_iterator prev = it;
++it; ++it;
@@ -601,7 +600,7 @@ public:
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param lhs the iterator /// \param lhs the iterator
/// \param rhs the iterator to compare with /// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
constexpr friend bool operator==(const const_iterator& lhs, const const_iterator& rhs) { constexpr friend bool operator==(const const_iterator& lhs, const const_iterator& rhs) {
return lhs._seq == rhs._seq and lhs._node == rhs._node; return lhs._seq == rhs._seq and lhs._node == rhs._node;
} }
@@ -610,7 +609,7 @@ public:
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param lhs the iterator /// \param lhs the iterator
/// \param rhs the iterator to compare with /// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
constexpr friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs) { constexpr friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs) {
return lhs._seq != rhs._seq or lhs._node != rhs._node; return lhs._seq != rhs._seq or lhs._node != rhs._node;
} }

View File

@@ -49,20 +49,19 @@ namespace fennec
/// \details /// \details
/// This data-structure behaves like a set, but does not use pointers, instead storing the table in-array /// This data-structure behaves like a set, but does not use pointers, instead storing the table in-array
/// ///
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ✅ | /// | homogeneous | ✅ |
/// | distinct | ✅ | /// | distinct | ✅ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(1)\f$ | /// | find | \emph{O(1)} |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypeT The type to contain /// \tparam TypeT The type to contain
template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>> template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
@@ -112,7 +111,7 @@ public:
/// \brief Default Constructor, initializes empty set /// \brief Default Constructor, initializes empty set
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr set() constexpr set()
: _table() : _table()
@@ -127,7 +126,7 @@ public:
/// \param hash the hash object /// \param hash the hash object
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr set(const hash_t& hash) constexpr set(const hash_t& hash)
: _table() : _table()
@@ -142,7 +141,7 @@ public:
/// \param alloc the allocator object /// \param alloc the allocator object
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr set(const alloc_t& alloc) constexpr set(const alloc_t& alloc)
: _table(alloc) : _table(alloc)
@@ -158,7 +157,7 @@ public:
/// \param alloc the allocator object /// \param alloc the allocator object
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr set(const hash_t& hash, const alloc_t& alloc) constexpr set(const hash_t& hash, const alloc_t& alloc)
: _table(alloc) : _table(alloc)
@@ -173,7 +172,7 @@ public:
/// \param set Set to copy /// \param set Set to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr set(const set& set) constexpr set(const set& set)
: _table(set._table) : _table(set._table)
@@ -188,7 +187,7 @@ public:
/// \param set Set to move /// \param set Set to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr set(set&& set) noexcept constexpr set(set&& set) noexcept
: _table(fennec::move(set._table)) : _table(fennec::move(set._table))
@@ -202,7 +201,7 @@ public:
/// \brief Destructor, destructs all elements and releases the allocation /// \brief Destructor, destructs all elements and releases the allocation
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr ~set() { constexpr ~set() {
for (size_t i = 0; i < capacity(); ++i) { for (size_t i = 0; i < capacity(); ++i) {
@@ -222,17 +221,17 @@ public:
/// \returns Size of the set in elements /// \returns Size of the set in elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
} }
/// ///
/// \returns \f$true\f$ when the set is empty, \f$false\f$ otherwise /// \returns \emph{true} when the set is empty, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool is_empty() const { constexpr bool is_empty() const {
return _size == 0; return _size == 0;
@@ -242,7 +241,7 @@ public:
/// \returns Capacity of the set in elements /// \returns Capacity of the set in elements
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.size(); return _table.size();
@@ -262,7 +261,7 @@ public:
/// \returns An iterator at the location of the value /// \returns An iterator at the location of the value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator find(const elem_t& val) const { constexpr iterator find(const elem_t& val) const {
if (capacity() == 0) { if (capacity() == 0) {
@@ -311,10 +310,10 @@ public:
/// ///
/// \brief Check if a set contains a value /// \brief Check if a set contains a value
/// \param val Value to check /// \param val Value to check
/// \returns \f$true\f$ if \f$val\f$ can be found, \f$false\f$ otherwise /// \returns \emph{true} if \emph{val} can be found, \emph{false} otherwise
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr bool contains(const elem_t& val) const { constexpr bool contains(const elem_t& val) const {
return this->find(val) != end(); return this->find(val) != end();
@@ -323,11 +322,11 @@ public:
/// ///
/// \brief Iterator Access /// \brief Iterator Access
/// \param it Location to access /// \param it Location to access
/// \returns A pointer to the element, \f$nullptr\f$ if not found. /// \returns A pointer to the element, \emph{nullptr} if not found.
/// The value should not be changed in a manner that will change the hash of the element. /// The value should not be changed in a manner that will change the hash of the element.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr elem_t* at(const iterator& it) { constexpr elem_t* at(const iterator& it) {
if (it == end()) { if (it == end()) {
@@ -342,10 +341,10 @@ public:
/// ///
/// \brief Iterator Const Access /// \brief Iterator Const Access
/// \param it Location to access /// \param it Location to access
/// \returns A const-qualified pointer to the element, \f$nullptr\f$ if not found. /// \returns A const-qualified pointer to the element, \emph{nullptr} if not found.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr const elem_t* at(const iterator& it) const { constexpr const elem_t* at(const iterator& it) const {
if (not _table[it._i].value) return nullptr; if (not _table[it._i].value) return nullptr;
@@ -365,7 +364,7 @@ public:
/// \returns An iterator at the held value /// \returns An iterator at the held value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator insert(elem_t&& val) { constexpr iterator insert(elem_t&& val) {
return this->_insert(fennec::forward<elem_t>(val)); return this->_insert(fennec::forward<elem_t>(val));
@@ -377,7 +376,7 @@ public:
/// \returns An iterator at the held value /// \returns An iterator at the held value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator insert(const elem_t& val) { constexpr iterator insert(const elem_t& val) {
return this->_insert(val); return this->_insert(val);
@@ -390,7 +389,7 @@ public:
/// \returns An iterator at the held value /// \returns An iterator at the held value
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
constexpr iterator emplace(ArgsT&&...args) { constexpr iterator emplace(ArgsT&&...args) {
@@ -402,7 +401,7 @@ public:
/// \param it Location to erase /// \param it Location to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void erase(iterator it) { constexpr void erase(iterator it) {
size_t i = it._i; size_t i = it._i;
@@ -431,7 +430,7 @@ public:
/// \param val Value to erase /// \param val Value to erase
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr void erase(const elem_t& val) { constexpr void erase(const elem_t& val) {
this->erase(this->find(val)); this->erase(this->find(val));
@@ -441,7 +440,7 @@ public:
/// \brief Clear all elements from the set, destructing them /// \brief Clear all elements from the set, destructing them
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
constexpr void clear() { constexpr void clear() {
_table.clear(); _table.clear();
@@ -456,11 +455,11 @@ public:
/// @{ /// @{
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns An iterator for all elements of the set in no particular order /// \returns An iterator for all elements of the set in no particular order
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator begin() const { constexpr iterator begin() const {
iterator it(this, 0); iterator it(this, 0);
@@ -471,11 +470,11 @@ public:
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \returns An iterator representing the end of the set /// \returns An iterator representing the end of the set
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
constexpr iterator end() const { constexpr iterator end() const {
return iterator(this, npos); return iterator(this, npos);
@@ -484,10 +483,10 @@ public:
/// @} /// @}
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
class iterator { class iterator {
public: public:
@@ -500,7 +499,7 @@ public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \param it the iterator to increment /// \param it the iterator to increment
/// \returns \f$it\f$ after having moved to the next element in the list /// \returns \emph{it} after having moved to the next element in the list
constexpr friend iterator& operator++(iterator& it) { constexpr friend iterator& operator++(iterator& it) {
while (++it._i < it._set->capacity()) { while (++it._i < it._set->capacity()) {
if (it._set->_table[it._i].value) { if (it._set->_table[it._i].value) {
@@ -514,7 +513,7 @@ public:
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \param it the iterator to increment /// \param it the iterator to increment
/// \returns \f$it\f$ before having moved to the next element in the list /// \returns \emph{it} before having moved to the next element in the list
constexpr friend iterator operator++(iterator& it, int) { constexpr friend iterator operator++(iterator& it, int) {
iterator prev = it; iterator prev = it;
++it; ++it;
@@ -539,7 +538,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
constexpr bool operator==(const iterator& it) const { constexpr bool operator==(const iterator& it) const {
return _set == it._set and _i == it._i; return _set == it._set and _i == it._i;
} }
@@ -547,7 +546,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param it the iterator to compare with /// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
constexpr bool operator!=(const iterator& it) const { constexpr bool operator!=(const iterator& it) const {
return _set != it._set or _i != it._i; return _set != it._set or _i != it._i;
} }

View File

@@ -42,20 +42,19 @@ namespace fennec
/// ///
/// \brief Tuple, holds a collection of values of different types /// \brief Tuple, holds a collection of values of different types
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogeneous | ⛔ | /// | homogeneous | ⛔ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(N)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | \f$O(1)\f$ | /// | find | \emph{O(1)} |
/// | insertion | ⛔ | /// | insertion | ⛔ |
/// | deletion | ⛔ | /// | deletion | ⛔ |
/// | space | \f$O(N)\f$ |
/// ///
/// \tparam TypesT The types to store /// \tparam TypesT The types to store
template<typename...TypesT> struct tuple; template<typename...TypesT> struct tuple;
@@ -65,7 +64,7 @@ template<typename...TypesT> struct tuple;
/// \tparam i the index /// \tparam i the index
/// \tparam TypesT the types held in the tuple /// \tparam TypesT the types held in the tuple
/// \param x the tuple /// \param x the tuple
/// \returns the \f$i\f$th element of the tuple /// \returns the \emph{i}th element of the tuple
template<size_t i, typename...TypesT> template<size_t i, typename...TypesT>
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) { constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
using elem_t = typename tuple<TypesT...>::template elem_t<i>; using elem_t = typename tuple<TypesT...>::template elem_t<i>;
@@ -77,7 +76,7 @@ constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x
/// \tparam i the index /// \tparam i the index
/// \tparam TypesT the types held in the tuple /// \tparam TypesT the types held in the tuple
/// \param x the tuple /// \param x the tuple
/// \returns the \f$i\f$th element of the tuple /// \returns the \emph{i}th element of the tuple
template<size_t i, typename...TypesT> template<size_t i, typename...TypesT>
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) { constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) {
using elem_t = typename tuple<TypesT...>::template elem_t<i>; using elem_t = typename tuple<TypesT...>::template elem_t<i>;
@@ -98,7 +97,7 @@ public:
using base_t = detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>; //!< the base type using base_t = detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>; //!< the base type
template<size_t i> template<size_t i>
using elem_t = typename nth_element<i, TypesT...>::type; //!< helper for getting the \f$i\f$th element using elem_t = typename nth_element<i, TypesT...>::type; //!< helper for getting the \emph{i}th element
static constexpr size_t size = sizeof...(TypesT); //!< the number of elements held by the tuple static constexpr size_t size = sizeof...(TypesT); //!< the number of elements held by the tuple
@@ -114,7 +113,7 @@ public:
/// \param args The arguments to initialize the tuple with /// \param args The arguments to initialize the tuple with
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
template<typename...ArgsT> template<typename...ArgsT>
tuple(ArgsT&&...args) tuple(ArgsT&&...args)
@@ -126,7 +125,7 @@ public:
/// \param cpy the tuple to copy /// \param cpy the tuple to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
tuple(const tuple& cpy) tuple(const tuple& cpy)
: base_t(cpy) { : base_t(cpy) {
@@ -137,7 +136,7 @@ public:
/// \param mov the tuple to move /// \param mov the tuple to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(N)\f$ /// \emph{O(N)}
/// ///
tuple(tuple&& mov) tuple(tuple&& mov)
: base_t(fennec::forward<tuple>(mov)) { : base_t(fennec::forward<tuple>(mov)) {

View File

@@ -40,22 +40,21 @@ namespace fennec
{ {
/// ///
/// \brief A structure that represents a union between \f$TypesT\ldots\f$ /// \brief A structure that represents a union between \emph{TypesT\ldots}
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:-----------:|:----------:| /// |:-----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogeneous | ⛔ | /// | homogeneous | ⛔ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | linear | |
/// | linear | | /// | space | \emph{O(1)} |
/// | access | \f$O(1)\f$ | /// | access | \emph{O(1)} |
/// | find | ⛔ | /// | find | ⛔ |
/// | insertion | \f$O(1)\f$ | /// | insertion | \emph{O(1)} |
/// | deletion | \f$O(1)\f$ | /// | deletion | \emph{O(1)} |
/// | space | \f$O(1)\f$ |
/// ///
/// \tparam TypesT The types to hold in the variant /// \tparam TypesT The types to hold in the variant
template<typename...TypesT> template<typename...TypesT>
@@ -90,10 +89,10 @@ public:
/// @{ /// @{
/// ///
/// \brief Default Constructor, constructs the first type in \f$TypesT\ldots\f$ that is default constructible /// \brief Default Constructor, constructs the first type in \emph{TypesT...} that is default constructible
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
variant() variant()
: _bytes {} : _bytes {}
@@ -104,13 +103,13 @@ public:
} }
/// ///
/// \brief Conversion Constructor, constructs the type in \f$TypesT\ldots\f$ that is identical to \f$T\f$ /// \brief Conversion Constructor, constructs the type in \emph{TypesT...} that is identical to \emph{T}
/// or the first that is constructible with \f$T\f$ /// or the first that is constructible with \emph{T}
/// \tparam T The type of the value /// \tparam T The type of the value
/// \param t The value to forward /// \param t The value to forward
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T> template<typename T>
variant(T&& t) variant(T&& t)
@@ -124,12 +123,12 @@ public:
} }
/// ///
/// \brief Emplace Constructor, constructs a type \f$T\f$ that is in \f$TypesT\ldots\f$ that is constructible with \f$ArgsT\ldots\f$ /// \brief Emplace Constructor, constructs a type \emph{T} that is in \emph{TypesT...} that is constructible with \emph{ArgsT...}
/// \tparam ArgsT The arguments of the constructor /// \tparam ArgsT The arguments of the constructor
/// \param args The argument values /// \param args The argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T, typename...ArgsT> template<typename T, typename...ArgsT>
variant(type_identity<T>, ArgsT&&...args) variant(type_identity<T>, ArgsT&&...args)
@@ -146,7 +145,7 @@ public:
/// \param v The variant to copy /// \param v The variant to copy
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
variant(const variant& v) variant(const variant& v)
: _bytes {} : _bytes {}
@@ -169,7 +168,7 @@ public:
/// \param v The variant to move /// \param v The variant to move
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
variant(variant&& v) noexcept variant(variant&& v) noexcept
: _bytes {} : _bytes {}
@@ -191,7 +190,7 @@ public:
/// \brief Destructor, if a type is held, destruct it. /// \brief Destructor, if a type is held, destruct it.
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
~variant() { ~variant() {
_clear(); _clear();
@@ -211,10 +210,10 @@ public:
/// \brief value assignment operator /// \brief value assignment operator
/// \tparam T The type to assign /// \tparam T The type to assign
/// \param t the value to assign /// \param t the value to assign
/// \returns a reference to \f$self\f$ after assigning \f$t\f$ /// \returns a reference to \emph{self} after assigning \emph{t}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T> template<typename T>
variant& operator=(T&& t) { variant& operator=(T&& t) {
@@ -259,7 +258,7 @@ public:
/// \param args the argument values /// \param args the argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>) template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>)
void emplace(ArgsT&&...args) { void emplace(ArgsT&&...args) {
@@ -273,7 +272,7 @@ public:
/// \param args the argument values /// \param args the argument values
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<size_t I, typename...ArgsT> template<size_t I, typename...ArgsT>
void emplace(ArgsT&&...args) { void emplace(ArgsT&&...args) {
@@ -291,12 +290,12 @@ public:
/// @{ /// @{
/// ///
/// \brief get the value of the variant interpreted as \f$T\f$ /// \brief get the value of the variant interpreted as \emph{T}
/// \tparam T the type to interpret as /// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$ /// \returns The value interpreted as \emph{T}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T> requires(contains_element_v<T, TypesT...>) template<typename T> requires(contains_element_v<T, TypesT...>)
T& get() { T& get() {
@@ -305,10 +304,10 @@ public:
/// ///
/// \tparam T the type to interpret as /// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$ /// \returns The value interpreted as \emph{T}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<typename T> requires(contains_element_v<T, TypesT...>) template<typename T> requires(contains_element_v<T, TypesT...>)
const T& get() const { const T& get() const {
@@ -317,10 +316,10 @@ public:
/// ///
/// \tparam T the type to interpret as /// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$ /// \returns The value interpreted as \emph{T}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>) template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
T& get() { T& get() {
@@ -329,10 +328,10 @@ public:
/// ///
/// \tparam T the type to interpret as /// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$ /// \returns The value interpreted as \emph{T}
/// ///
/// \par Complexity /// \par Complexity
/// \f$O(1)\f$ /// \emph{O(1)}
/// ///
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>) template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
const T& get() const { const T& get() const {

View File

@@ -32,9 +32,11 @@
#ifndef FENNEC_CORE_LOGGER_H #ifndef FENNEC_CORE_LOGGER_H
#define FENNEC_CORE_LOGGER_H #define FENNEC_CORE_LOGGER_H
#include <fennec/containers/pair.h>
#include <fennec/filesystem/file.h> #include <fennec/filesystem/file.h>
#include <fennec/rtti/singleton.h> #include <fennec/rtti/singleton.h>
#include <fennec/containers/tuple.h> #include <fennec/containers/tuple.h>
#include <fennec/lang/system.h>
namespace fennec namespace fennec
{ {
@@ -43,6 +45,31 @@ namespace fennec
/// \brief logger class /// \brief logger class
class logger : public singleton<logger> { class logger : public singleton<logger> {
// Definitions =========================================================================================================
public:
///
/// \brief Log Severities
enum severity : uint32_t {
info = 0,
alert,
warning,
error,
fatal,
};
static const pair<cstring, cstring>& severity_color(uint32_t severity) {
static constexpr pair<cstring, cstring> colors[] = {
{ "\033[0m", "\033[0m" }, // severity_info
{ "\033[36m", "\033[0m" }, // severity_alert
{ "\033[33m", "\033[0m" }, // severity_warning
{ "\033[31m", "\033[0m" }, // severity_error
{ "\033[1;31m", "\033[0m" }, // severity_fatal
};
return colors[severity];
}
// Logger System Interface ============================================================================================= // Logger System Interface =============================================================================================
public: public:
@@ -54,7 +81,8 @@ public:
/// \param str the string to log /// \param str the string to log
/// \param _line the line of the log call /// \param _line the line of the log call
/// \param _file the file log was called in /// \param _file the file log was called in
static void log(const cstring& str, static void log(uint32_t severity,
const cstring& str,
uint32_t _line = FENNEC_BUILTIN_LINE(), uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* _file = FENNEC_BUILTIN_FILE() const char* _file = FENNEC_BUILTIN_FILE()
) { ) {
@@ -66,9 +94,12 @@ public:
inst._logfile.println(str); inst._logfile.println(str);
} }
const auto& color = severity_color(severity);
inst._cout->print(color.first);
inst._cout->print(cstring(_file, strlen(_file))); inst._cout->print(cstring(_file, strlen(_file)));
inst._cout->printf("({}): ", _line); inst._cout->printf("({}): ", _line);
inst._cout->println(str); inst._cout->print(str);
inst._cout->println(color.second);
} }
/// ///
@@ -76,7 +107,8 @@ public:
/// \param str the string to log /// \param str the string to log
/// \param _line the line of the log call /// \param _line the line of the log call
/// \param _file the file log was called in /// \param _file the file log was called in
static void log(const string& str, static void log(uint32_t severity,
const string& str,
uint32_t _line = FENNEC_BUILTIN_LINE(), uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* _file = FENNEC_BUILTIN_FILE() const char* _file = FENNEC_BUILTIN_FILE()
) { ) {
@@ -88,9 +120,13 @@ public:
inst._logfile.println(str); inst._logfile.println(str);
} }
const auto& color = severity_color(severity);
inst._cout->print(color.first);
inst._cout->print(cstring(_file, strlen(_file))); inst._cout->print(cstring(_file, strlen(_file)));
inst._cout->printf("({}): ", _line); inst._cout->printf("({}): ", _line);
inst._cout->println(str); inst._cout->print(str);
inst._cout->println(color.second);
} }
/// @} /// @}

View File

@@ -37,6 +37,12 @@
#pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wpedantic"
#endif #endif
#if FENNEC_COMPILER_CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#endif
#if FENNEC_COMPILER_MSVC #if FENNEC_COMPILER_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4201) #pragma warning(disable:4201)
@@ -59,13 +65,13 @@ public:
/// @{ /// @{
union { union {
uint64_t num; //!< long version number
struct { struct {
uint16_t major = { 1 }; //!< the major version uint16_t major = { 1 }; //!< the major version
uint16_t minor = { 0 }; //!< the minor version uint16_t minor = { 0 }; //!< the minor version
uint16_t patch = { 0 }; //!< the patch version uint16_t patch = { 0 }; //!< the patch version
uint16_t meta = { 0 }; //!< the meta version, e.g. "rc.1" uint16_t meta = { 0 }; //!< the meta version, e.g. "rc.1"
}; };
uint64_t num; //!< long version number
}; };
/// @} /// @}
@@ -114,6 +120,10 @@ public:
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#ifdef FENNEC_COMPILER_CLANG
#pragma clang diagnostic pop
#endif
#if FENNEC_COMPILER_MSVC #if FENNEC_COMPILER_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif

View File

@@ -39,19 +39,19 @@ namespace fennec
/// <tr><th style="vertical-align: top">Flags /// <tr><th style="vertical-align: top">Flags
/// <th style="vertical-align: top">Description /// <th style="vertical-align: top">Description
/// ///
/// <tr><td style="vertical-align: top">\f$read\f$ /// <tr><td style="vertical-align: top">\emph{read}
/// <td style="vertical-align: top">Opens file as read-only, reading from start /// <td style="vertical-align: top">Opens file as read-only, reading from start
/// ///
/// <tr><td style="vertical-align: top">\f$write\f$ /// <tr><td style="vertical-align: top">\emph{write}
/// <td style="vertical-align: top">Opens file as write-only, writing to end /// <td style="vertical-align: top">Opens file as write-only, writing to end
/// ///
/// <tr><td style="vertical-align: top">\f$read | write\f$ /// <tr><td style="vertical-align: top">\emph{read | write}
/// <td style="vertical-align: top">Opens file as read-write, reading from start /// <td style="vertical-align: top">Opens file as read-write, reading from start
/// ///
/// <tr><td style="vertical-align: top">\f$write | trunc\f$ /// <tr><td style="vertical-align: top">\emph{write | trunc}
/// <td style="vertical-align: top">Opens file as write-only, destroying contents /// <td style="vertical-align: top">Opens file as write-only, destroying contents
/// ///
/// <tr><td style="vertical-align: top">\f$read | write | trunc\f$ /// <tr><td style="vertical-align: top">\emph{read | write | trunc}
/// <td style="vertical-align: top">Opens file as read-write, destroying contents /// <td style="vertical-align: top">Opens file as read-write, destroying contents
/// </table> /// </table>
enum fmode_ : uint8_t enum fmode_ : uint8_t
@@ -147,7 +147,7 @@ public:
file(); file();
/// ///
/// \details Initializes a stream pointing to \f$path\f$ opened with \f$mode\f$ /// \details Initializes a stream pointing to \emph{path} opened with \emph{mode}
/// \param path the path of the file /// \param path the path of the file
/// \param mode the mode to open with /// \param mode the mode to open with
file(const cstring& path, uint8_t mode) file(const cstring& path, uint8_t mode)
@@ -156,7 +156,7 @@ public:
} }
/// ///
/// \details Initializes a stream pointing to \f$path\f$ opened with \f$mode\f$ /// \details Initializes a stream pointing to \emph{path} opened with \emph{mode}
/// \param path the path of the file /// \param path the path of the file
/// \param mode the mode to open with /// \param mode the mode to open with
file(const string& path, uint8_t mode) file(const string& path, uint8_t mode)
@@ -166,7 +166,7 @@ public:
/// ///
/// \brief Path constructor /// \brief Path constructor
/// \details Initializes a stream pointing to \f$path\f$ opened with \f$mode\f$ /// \details Initializes a stream pointing to \emph{path} opened with \emph{mode}
/// \param path the path of the file /// \param path the path of the file
/// \param mode the mode to open with /// \param mode the mode to open with
file(const path& path, uint8_t mode) file(const path& path, uint8_t mode)
@@ -179,23 +179,39 @@ public:
/// \param file the stream to take ownership of /// \param file the stream to take ownership of
file(file&& file) noexcept; file(file&& file) noexcept;
///
/// \brief Copy Constructor
/// \details Deleted, no semantics for copying a stream. Holding multiple copies of a stream will cause conflicts.
file(const file&) = delete;
/// ///
/// \brief Destructor /// \brief Destructor
/// \details Flushes and closes an open stream /// \details Flushes and closes an open stream
~file(); ~file();
///@}
// Assignment ==========================================================================================================
public:
/// \name Assignment
/// @{
/// ///
/// \brief Move assignment /// \brief Move assignment
/// \param file the stream to take ownership of /// \param file the stream to take ownership of
file& operator=(file&& file) noexcept; file& operator=(file&& file) noexcept;
///@} ///
/// \brief Copy Assignment
private: /// \details Deleted, no semantics for copying a stream. Holding multiple copies of a stream will cause conflicts.
// don't allow copying streams /// \returns Deleted
file(const file&) = delete;
file& operator=(const file&) = delete; file& operator=(const file&) = delete;
/// @}
// Properties ========================================================================================================== // Properties ==========================================================================================================
public: public:
@@ -216,7 +232,7 @@ public:
} }
/// ///
/// \returns \f$true\f$ if there is a valid, open stream. /// \returns \emph{true} if there is a valid, open stream.
bool is_open() const { bool is_open() const {
return _handle != nullptr; return _handle != nullptr;
} }
@@ -233,30 +249,30 @@ public:
/// ///
/// \param path the path to the file /// \param path the path to the file
/// \param mode the mode flags to open the file with /// \param mode the mode flags to open the file with
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
bool open(const cstring& path, uint8_t mode); bool open(const cstring& path, uint8_t mode);
/// ///
/// \param path the path to the file /// \param path the path to the file
/// \param mode the mode flags to open the file with /// \param mode the mode flags to open the file with
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
bool open(const string& path, uint8_t mode); bool open(const string& path, uint8_t mode);
/// ///
/// \brief Open a file /// \brief Open a file
/// \param path the path to the file /// \param path the path to the file
/// \param mode the mode flags to open the file with /// \param mode the mode flags to open the file with
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
bool open(const path& path, uint8_t mode); bool open(const path& path, uint8_t mode);
/// ///
/// \brief Close a stream /// \brief Close a stream
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
bool close(); bool close();
/// ///
/// \brief Commit the streams buffer to the file /// \brief Commit the streams buffer to the file
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
bool commit(); bool commit();
/// @} /// @}
@@ -270,12 +286,12 @@ public:
/// ///
/// \brief closes the stream and erases the file /// \brief closes the stream and erases the file
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
bool erase(); bool erase();
/// ///
/// \param path the new path /// \param path the new path
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
/// ///
/// \details /// \details
/// Copies contents to the new path, and erases the old file. /// Copies contents to the new path, and erases the old file.
@@ -288,7 +304,7 @@ public:
/// ///
/// \param path the new path /// \param path the new path
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
/// ///
/// \details /// \details
/// Copies contents to the new path, and erases the old file. /// Copies contents to the new path, and erases the old file.
@@ -302,7 +318,7 @@ public:
/// ///
/// \brief Rebind the stream. /// \brief Rebind the stream.
/// \param path the new path /// \param path the new path
/// \returns \f$false\f$ on success, \f$true\f$ on error /// \returns \emph{false} on success, \emph{true} on error
/// ///
/// \details /// \details
/// Copies contents to the new path, and erases the old file. /// Copies contents to the new path, and erases the old file.
@@ -366,16 +382,16 @@ public:
/// ///
/// \param i the new index to move to /// \param i the new index to move to
/// \returns \f$false\f$ on success, \f$true\f$ otherwise /// \returns \emph{false} on success, \emph{true} otherwise
bool set_pos(size_t i); bool set_pos(size_t i);
/// ///
/// \brief return to the start of the stream /// \brief return to the start of the stream
/// \returns \f$false\f$ on success, \f$true\f$ otherwise /// \returns \emph{false} on success, \emph{true} otherwise
bool rewind(); bool rewind();
/// ///
/// \returns \f$true\f$ if the stream has reached the end of the file, \f$false\f$ otherwise /// \returns \emph{true} if the stream has reached the end of the file, \emph{false} otherwise
bool eof() const; bool eof() const;
/// @} /// @}
@@ -429,13 +445,13 @@ public:
/// ///
/// \brief put a character at the current position in the stream /// \brief put a character at the current position in the stream
/// \param c the character to put /// \param c the character to put
/// \returns \f$false\f$ on success, \f$true\f$ otherwise /// \returns \emph{false} on success, \emph{true} otherwise
bool putc(char c); bool putc(char c);
/// ///
/// \brief put a wide character at the current position in the stream /// \brief put a wide character at the current position in the stream
/// \param c the character to put /// \param c the character to put
/// \returns \f$false\f$ on success, \f$true\f$ otherwise /// \returns \emph{false} on success, \emph{true} otherwise
bool putwc(wchar_t c); bool putwc(wchar_t c);
/// ///
@@ -551,7 +567,7 @@ public:
/// \param args the argument values /// \param args the argument values
template<typename...ArgsT> template<typename...ArgsT>
void printf(const cstring& str, ArgsT&&...args) { void printf(const cstring& str, ArgsT&&...args) {
string fmt = fennec::format(str, fennec::forward<ArgsT>(args)...); const string fmt = fennec::format(str, fennec::forward<ArgsT>(args)...);
this->print(cstring(fmt.cstr(), fmt.length())); this->print(cstring(fmt.cstr(), fmt.length()));
} }

View File

@@ -115,7 +115,7 @@ public:
/// ///
/// \brief C-String Assignment Operator /// \brief C-String Assignment Operator
/// \param str the cstring to assign /// \param str the cstring to assign
/// \returns a reference to \f$this\f$ after assigning \f$p\f$ /// \returns a reference to \emph{this} after assigning \emph{p}
template<size_t n> template<size_t n>
path& operator=(const char (&str)[n]) { path& operator=(const char (&str)[n]) {
_str = str; _str = str;
@@ -125,7 +125,7 @@ public:
/// ///
/// \brief C-String Assignment Operator /// \brief C-String Assignment Operator
/// \param p the cstring to assign /// \param p the cstring to assign
/// \returns a reference to \f$this\f$ after assigning \f$p\f$ /// \returns a reference to \emph{this} after assigning \emph{p}
path& operator=(const cstring& p) { path& operator=(const cstring& p) {
_str = p; _str = p;
return *this; return *this;
@@ -134,7 +134,7 @@ public:
/// ///
/// \brief String Assignment Operator /// \brief String Assignment Operator
/// \param p the cstring to assign /// \param p the cstring to assign
/// \returns a reference to \f$this\f$ after assigning \f$p\f$ /// \returns a reference to \emph{this} after assigning \emph{p}
path& operator=(const string& p) { path& operator=(const string& p) {
_str = p; _str = p;
return *this; return *this;
@@ -143,7 +143,7 @@ public:
/// ///
/// \brief Path Copy Assignment Operator /// \brief Path Copy Assignment Operator
/// \param p the path to copy /// \param p the path to copy
/// \returns a reference to \f$this\f$ after copying \f$p\f$ /// \returns a reference to \emph{this} after copying \emph{p}
path& operator=(const path& p) { path& operator=(const path& p) {
_str = p._str; _str = p._str;
return *this; return *this;
@@ -152,7 +152,7 @@ public:
/// ///
/// \brief Path Move Assignment Operator /// \brief Path Move Assignment Operator
/// \param p the path to take ownership of /// \param p the path to take ownership of
/// \returns a reference to \f$this\f$ after taking ownership of \f$p\f$ /// \returns a reference to \emph{this} after taking ownership of \emph{p}
path& operator=(path&& p) noexcept { path& operator=(path&& p) noexcept {
_str = move(p._str); _str = move(p._str);
return *this; return *this;
@@ -170,7 +170,7 @@ public:
/// ///
/// \brief path equality operator /// \brief path equality operator
/// \param p the path to compare against /// \param p the path to compare against
/// \returns \f$true\f$ if the paths are identical, \f$false\f$ otherwise. relative paths are not resolved /// \returns \emph{true} if the paths are identical, \emph{false} otherwise. relative paths are not resolved
bool operator==(const path& p) const { bool operator==(const path& p) const {
return _str == p._str; return _str == p._str;
} }
@@ -187,7 +187,7 @@ public:
/// ///
/// \brief path append operator /// \brief path append operator
/// \param str the filename to append /// \param str the filename to append
/// \returns a path containing the current path followed by \f$str\f$ /// \returns a path containing the current path followed by \emph{str}
path operator/(const cstring& str) const { path operator/(const cstring& str) const {
return path(_str + '/' + str); return path(_str + '/' + str);
} }
@@ -195,7 +195,7 @@ public:
/// ///
/// \brief path append operator /// \brief path append operator
/// \param str the filename to append /// \param str the filename to append
/// \returns a path containing the current path followed by \f$str\f$ /// \returns a path containing the current path followed by \emph{str}
path operator/(const string& str) const { path operator/(const string& str) const {
return path(_str + '/' + str); return path(_str + '/' + str);
} }
@@ -203,7 +203,7 @@ public:
/// ///
/// \brief path append operator /// \brief path append operator
/// \param p the path to append /// \param p the path to append
/// \returns a path containing the current path followed by \f$p\f$ /// \returns a path containing the current path followed by \emph{p}
path operator/(const path& p) const { path operator/(const path& p) const {
return path(_str + '/' + p._str); return path(_str + '/' + p._str);
} }
@@ -214,7 +214,7 @@ public:
/// \brief the filename of the current path /// \brief the filename of the current path
/// \returns a string containing a copy of the filename /// \returns a string containing a copy of the filename
string filename() const { string filename() const {
size_t i = _str.rfind('/'); const size_t i = _str.rfind('/');
return _str.substring(i + 1); return _str.substring(i + 1);
} }
@@ -227,9 +227,9 @@ public:
const char* cstr() const { return _str.cstr(); } const char* cstr() const { return _str.cstr(); }
/// ///
/// \returns \f$true\f$ if the path is empty or points to root /// \returns \emph{true} if the path is empty or points to root
bool is_empty() { bool is_empty() {
size_t size = _str.size(); const size_t size = _str.size();
if (size == 0) return true; if (size == 0) return true;
#if FENNEC_PLATFORM_WINDOWS #if FENNEC_PLATFORM_WINDOWS
return (_str[1] == ':' && size == 3); return (_str[1] == ':' && size == 3);
@@ -322,21 +322,21 @@ public:
/// @{ /// @{
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \returns an iterator at the first filename in the path /// \returns an iterator at the first filename in the path
iterator begin() const { iterator begin() const {
return iterator(this, 0); return iterator(this, 0);
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \returns an iterator to the end of the path /// \returns an iterator to the end of the path
iterator end() const { iterator end() const {
return iterator(this, _str.size()); return iterator(this, _str.size());
} }
/// ///
/// \brief C++ Iterator Specification \f$iterator\f$ /// \brief C++ Iterator Specification \emph{iterator}
class iterator { class iterator {
public: public:
/// ///
@@ -363,7 +363,7 @@ public:
/// ///
/// \brief prefix increment operator /// \brief prefix increment operator
/// \returns \f$self\f$ after having moved to the next element in the list /// \returns \emph{self} after having moved to the next element in the list
constexpr iterator& operator++() { constexpr iterator& operator++() {
_pos = min(_str->find('/', _pos) + 1, _str->size()); _pos = min(_str->find('/', _pos) + 1, _str->size());
return *this; return *this;
@@ -371,9 +371,9 @@ public:
/// ///
/// \brief postfix increment operator /// \brief postfix increment operator
/// \returns \f$self\f$ before having moved to the next element in the list /// \returns \emph{self} before having moved to the next element in the list
constexpr iterator operator++(int) { constexpr iterator operator++(int) {
iterator it = *this; const iterator it = *this;
this->operator++(); this->operator++();
return it; return it;
} }
@@ -381,7 +381,7 @@ public:
/// ///
/// \brief iterator equality operator /// \brief iterator equality operator
/// \param rhs the iterator to compare with /// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are identical, \emph{false} otherwise
constexpr bool operator==(const iterator& rhs) const { constexpr bool operator==(const iterator& rhs) const {
return _str == rhs._str and _pos == rhs._pos; return _str == rhs._str and _pos == rhs._pos;
} }
@@ -389,7 +389,7 @@ public:
/// ///
/// \brief iterator inequality operator /// \brief iterator inequality operator
/// \param rhs the iterator to compare with /// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise /// \returns \emph{true} if the iterators are different, \emph{false} otherwise
constexpr bool operator!=(const iterator& rhs) const { constexpr bool operator!=(const iterator& rhs) const {
return _str != rhs._str or _pos != rhs._pos; return _str != rhs._str or _pos != rhs._pos;
} }

View File

@@ -60,6 +60,8 @@ string format(const cstring& str, ArgsT&&...args) {
.type = '\0', .type = '\0',
}; };
static_assert(argc > 0, "fennec::format may not accept 0 arguments");
// empty case // empty case
if constexpr(argc == 0) { if constexpr(argc == 0) {
return str; return str;

View File

@@ -48,9 +48,9 @@ struct formatter {
/// ///
/// \brief default format function /// \brief default format function
/// ///
/// \details throws a static assertion /// \details Fails an assertion, the formatter is not implemented for the provided type
/// \returns empty string /// \returns empty string
string operator()(const format_arg&, const T&) { string operator()(const format_arg&, const T&) const {
static_assert(false, "Formatter not implemented for the provided type."); static_assert(false, "Formatter not implemented for the provided type.");
return string(""); return string("");
} }
@@ -59,6 +59,8 @@ struct formatter {
// strings ============================================================================================================= // strings =============================================================================================================
// TODO: String formatting
/// ///
/// \brief formatter of a character array /// \brief formatter of a character array
/// \tparam N the number of characters /// \tparam N the number of characters
@@ -67,8 +69,8 @@ struct formatter<char[N]> {
/// ///
/// \brief format function /// \brief format function
/// \param str the string argument /// \param str the string argument
/// \returns the formatted version of \f$str\f$ /// \returns the formatted version of \emph{str}
string operator()(const format_arg&, const char (&str)[N]) { string operator()(const format_arg&, const char (&str)[N]) const {
return string(str); return string(str);
} }
}; };
@@ -81,8 +83,8 @@ struct formatter<const char[N]> {
/// ///
/// \brief format function /// \brief format function
/// \param str the string argument /// \param str the string argument
/// \returns the formatted version of \f$str\f$ /// \returns the formatted version of \emph{str}
string operator()(const format_arg&, const char (&str)[N]) { string operator()(const format_arg&, const char (&str)[N]) const {
return string(str); return string(str);
} }
}; };
@@ -94,8 +96,8 @@ struct formatter<cstring> {
/// ///
/// \brief format function /// \brief format function
/// \param str the string argument /// \param str the string argument
/// \returns the formatted version of \f$str\f$ /// \returns the formatted version of \emph{str}
string operator()(const format_arg&, const cstring& str) { string operator()(const format_arg&, const cstring& str) const {
return str; return str;
} }
}; };
@@ -107,8 +109,8 @@ struct formatter<string> {
/// ///
/// \brief format function /// \brief format function
/// \param str the string argument /// \param str the string argument
/// \returns the formatted version of \f$str\f$ /// \returns the formatted version of \emph{str}
string operator()(const format_arg&, const string& str) { string operator()(const format_arg&, const string& str) const {
return str; return str;
} }
}; };
@@ -124,12 +126,12 @@ struct formatter<IntT> {
/// \brief format function /// \brief format function
/// \param fmt the format specification /// \param fmt the format specification
/// \param x the integral argument /// \param x the integral argument
/// \returns the formatted version of \f$x\f$ /// \returns the formatted version of \emph{x}
string operator()(const format_arg& fmt, IntT x) { string operator()(const format_arg& fmt, IntT x) const {
char digits[128] = {}; char digits[128] = {};
auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.base); auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.base);
assertf(chk != nullptr, "fennec::format error, to_chars error"); assertf(chk != nullptr, "fennec::format error, to_chars error");
size_t len = chk - digits; const size_t len = chk - digits;
// handle uppercase // handle uppercase
if (fmt.upper) { if (fmt.upper) {
@@ -163,8 +165,8 @@ struct formatter<IntT> {
memset(res.data(), fmt.fill, explen - len); memset(res.data(), fmt.fill, explen - len);
break; break;
case '^': case '^':
size_t bef = fill / 2 + has_sign + prefix; const size_t bef = fill / 2 + has_sign + prefix;
size_t aft = explen - bef; const size_t aft = explen - bef;
memcpy(res.data() + bef, digits, len); memcpy(res.data() + bef, digits, len);
sign = fmt.fill == '0' ? 0 : bef - 1 - prefix; sign = fmt.fill == '0' ? 0 : bef - 1 - prefix;
memset(res.data(), fmt.fill, bef); memset(res.data(), fmt.fill, bef);
@@ -200,8 +202,8 @@ struct formatter<BoolT> {
/// \brief format function /// \brief format function
/// \param fmt the format specification /// \param fmt the format specification
/// \param x the boolean argument /// \param x the boolean argument
/// \returns the formatted version of \f$x\f$ /// \returns the formatted version of \emph{x}
string operator()(const format_arg& fmt, BoolT x) { string operator()(const format_arg& fmt, BoolT x) const {
if (fmt.type == 's' or fmt.type == '\0') { if (fmt.type == 's' or fmt.type == '\0') {
return x ? string("true") : string("false"); return x ? string("true") : string("false");
} }
@@ -218,8 +220,8 @@ struct formatter<FloatT> {
/// \brief format function /// \brief format function
/// \param fmt the format specification /// \param fmt the format specification
/// \param x the float argument /// \param x the float argument
/// \returns the formatted version of \f$x\f$ /// \returns the formatted version of \emph{x}
string operator()(const format_arg& fmt, FloatT x) { string operator()(const format_arg& fmt, FloatT x) const {
// nan & inf cases // nan & inf cases
if (fennec::isnan(x)) { if (fennec::isnan(x)) {
@@ -267,8 +269,8 @@ struct formatter<FloatT> {
memset(res.data(), fmt.fill, explen - len); memset(res.data(), fmt.fill, explen - len);
break; break;
case '^': case '^':
size_t bef = fill / 2 + has_sign + prefix; const size_t bef = fill / 2 + has_sign + prefix;
size_t aft = explen - bef; const size_t aft = explen - bef;
memcpy(res.data() + bef, digits, len); memcpy(res.data() + bef, digits, len);
sign = fmt.fill == '0' ? 0 : bef - 1 - prefix; sign = fmt.fill == '0' ? 0 : bef - 1 - prefix;
memset(res.data(), fmt.fill, bef); memset(res.data(), fmt.fill, bef);

View File

@@ -94,8 +94,8 @@ private:
list<token> res; list<token> res;
priority_queue<pair<size_t, uint8_t>> idx; priority_queue<pair<size_t, uint8_t>> idx;
for (char c : delimiter) { for (const char c : delimiter) {
size_t i = 0; const size_t i = 0;
while (i != line.size()) { while (i != line.size()) {
size_t n = line.find(c, i); size_t n = line.find(c, i);
// TODO // TODO

View File

@@ -48,18 +48,18 @@
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// assert(expr, desc) /// assert(expr, desc)
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Make an assertion with expression \f$expr\f$ and provide a description \f$desc\f$. Only halts in debug mode. /// Make an assertion with expression \emph{expr} and provide a description \emph{desc}. Only halts in debug mode.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// assertf(expr, desc) /// assertf(expr, desc)
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Make an assertion with expression \f$expr\f$ and provide a description \f$desc\f$. Always halts. /// Make an assertion with expression \emph{expr} and provide a description \emph{desc}. Always halts.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// assertd(expr, desc) /// assertd(expr, desc)
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Make an assertion, ***only in debug mode***, with expression \f$expr\f$ and provide a description \f$desc\f$. /// Make an assertion, ***only in debug mode***, with expression \emph{expr} and provide a description \emph{desc}.
/// This should be used when the branching caused by \f$assert\f$ would hinder performance in release mode. /// This should be used when the branching caused by \emph{assert} would hinder performance in release mode.
/// ///
/// </table> /// </table>
/// ///
@@ -92,7 +92,7 @@ void _assert(const char (&expr)[ExprL],
/// \param description the description of the assertion /// \param description the description of the assertion
#define assert(expression, description) \ #define assert(expression, description) \
if(not(expression)) [[unlikely]] { \ if(not(expression)) [[unlikely]] { \
_assert(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, not FENNEC_RELEASE); \ _assert(#expression, __FILE__, __LINE__, __PRETTY_FUNCTION__, description, FENNEC_DEBUG); \
} }
/// ///

View File

@@ -116,7 +116,7 @@ constexpr ToT bit_cast(const FromT& from) {
/// \param arr the array of bytes to modify /// \param arr the array of bytes to modify
/// \param mask the mask to and against arr /// \param mask the mask to and against arr
/// \param n the number of bytes /// \param n the number of bytes
/// \returns the pointer \f$arr\f$ /// \returns the pointer \emph{arr}
constexpr void* bit_and(void* arr, const void* mask, size_t n) { constexpr void* bit_and(void* arr, const void* mask, size_t n) {
if (arr == mask) { if (arr == mask) {
return arr; return arr;

View File

@@ -33,23 +33,23 @@ namespace fennec
template<typename T0, typename T1 = T0> struct equality; template<typename T0, typename T1 = T0> struct equality;
/// ///
/// \brief Implementations for two types that have a common equality operator \f$==\f$ /// \brief Implementations for two types that have a common equality operator \math{=}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1> template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct equality<T0, T1> { struct equality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise /// \returns \emph{true} if equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return x == y; return x == y;
} }
}; };
/// ///
/// \brief Implementations for two types that have a common less operator \f$<\f$ /// \brief Implementations for two types that have a common less operator \math{<}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires(not has_equals_v<T0, T1> template<typename T0, typename T1> requires(not has_equals_v<T0, T1>
@@ -57,16 +57,16 @@ template<typename T0, typename T1> requires(not has_equals_v<T0, T1>
struct equality<T0, T1> { struct equality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise /// \returns \emph{true} if equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return not(x < y) and not(y < x); return not(x < y) and not(y < x);
} }
}; };
/// ///
/// \brief Implementations for two types that have a common greater operator \f$>\f$ /// \brief Implementations for two types that have a common greater operator \math{>}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires(not(has_equals_v<T0, T1>) template<typename T0, typename T1> requires(not(has_equals_v<T0, T1>)
@@ -75,9 +75,9 @@ template<typename T0, typename T1> requires(not(has_equals_v<T0, T1>)
struct equality<T0, T1> { struct equality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise /// \returns \emph{true} if equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return not(x > y) and not(y > x); return not(x > y) and not(y > x);
} }
@@ -93,16 +93,16 @@ struct equality<T0, T1> {
template<typename T0, typename T1 = T0> struct inequality; template<typename T0, typename T1 = T0> struct inequality;
/// ///
/// \brief Implementations for two types that have a common inequality operator \f$\neq\f$ /// \brief Implementations for two types that have a common inequality operator \math{\neq}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires has_nequals_v<T0, T1> template<typename T0, typename T1> requires has_nequals_v<T0, T1>
struct inequality<T0, T1> { struct inequality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise /// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return x != y; return x != y;
} }
@@ -110,48 +110,48 @@ struct inequality<T0, T1> {
/// ///
/// \brief Implementations for two types that have a common equality operator \f$==\f$ /// \brief Implementations for two types that have a common equality operator \math{=}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1> template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct inequality<T0, T1> { struct inequality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise /// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return not (x == y); return not (x == y);
} }
}; };
/// ///
/// \brief Implementations for two types that have a common less operator \f$<\f$ /// \brief Implementations for two types that have a common less operator \math{<}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0> template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0>
struct inequality<T0, T1> { struct inequality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise /// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return (x < y) or (y < x); return (x < y) or (y < x);
} }
}; };
/// ///
/// \brief Implementations for two types that have a common greater operator \f$>\f$ /// \brief Implementations for two types that have a common greater operator \math{>}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0> template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0>
struct inequality<T0, T1> { struct inequality<T0, T1> {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise /// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return (x > y) or (y > x); return (x > y) or (y > x);
} }
@@ -161,16 +161,16 @@ struct inequality<T0, T1> {
// less ================================================================================================================ // less ================================================================================================================
/// ///
/// \brief Struct to test if a value of type \f$T0\f$ is less than a value of type \f$T1\f$ /// \brief Struct to test if a value of type \emph{T0} is less than a value of type \emph{T1}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_less_v<T0, T1> template<typename T0, typename T1 = T0> requires has_less_v<T0, T1>
struct less { struct less {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if less, \f$false\f$ otherwise /// \returns \emph{true} if less, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return x < y; return x < y;
} }
@@ -180,16 +180,16 @@ struct less {
// less_equal ========================================================================================================== // less_equal ==========================================================================================================
/// ///
/// \brief Struct to test if a value of type \f$T0\f$ is less than or equal to a value of type \f$T1\f$ /// \brief Struct to test if a value of type \emph{T0} is less than or equal to a value of type \emph{T1}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1> template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1>
struct less_equals { struct less_equals {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if less than or equal, \f$false\f$ otherwise /// \returns \emph{true} if less than or equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return x <= y; return x <= y;
} }
@@ -199,16 +199,16 @@ struct less_equals {
// greater ============================================================================================================= // greater =============================================================================================================
/// ///
/// \brief Struct to test if a value of type \f$T0\f$ is greater than a value of type \f$T1\f$ /// \brief Struct to test if a value of type \emph{T0} is greater than a value of type \emph{T1}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1> template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1>
struct greater { struct greater {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if greater, \f$false\f$ otherwise /// \returns \emph{true} if greater, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return x > y; return x > y;
} }
@@ -218,16 +218,16 @@ struct greater {
// less_equal ========================================================================================================== // less_equal ==========================================================================================================
/// ///
/// \brief Struct to test if a value of type \f$T0\f$ is greater than or equal to a value of type \f$T1\f$ /// \brief Struct to test if a value of type \emph{T0} is greater than or equal to a value of type \emph{T1}
/// \tparam T0 The first type /// \tparam T0 The first type
/// \tparam T1 The second type /// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1> template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1>
struct greater_equals { struct greater_equals {
/// ///
/// \brief operator to test the two values /// \brief operator to test the two values
/// \param x the value of type \f$T0\f$ /// \param x the value of type \emph{T0}
/// \param y the value of type \f$T1\f$ /// \param y the value of type \emph{T1}
/// \returns \f$true\f$ if greater than or equal, \f$false\f$ otherwise /// \returns \emph{true} if greater than or equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const { constexpr bool operator()(const T0& x, const T1& y) const {
return x >= y; return x >= y;
} }

View File

@@ -77,8 +77,8 @@ namespace fennec
/// \details Selects between \p TrueT and \p FalseT based on the boolean value \p b. /// \details Selects between \p TrueT and \p FalseT based on the boolean value \p b.
/// The chosen type is stored in `fennec::conditional::type`. /// The chosen type is stored in `fennec::conditional::type`.
/// \tparam B the value of the condition /// \tparam B the value of the condition
/// \tparam TrueT type to use when \f$B == true\f$ /// \tparam TrueT type to use when \math{\textbf{B} = \textbf{true}}
/// \tparam FalseT type to use when \f$B == false\f$ /// \tparam FalseT type to use when \math{\textbf{B} = \textbf{false}}
template<bool B, typename TrueT, typename FalseT> template<bool B, typename TrueT, typename FalseT>
struct conditional; struct conditional;
@@ -90,12 +90,12 @@ using conditional_t
= typename conditional<B, TrueT, FalseT>::type; = typename conditional<B, TrueT, FalseT>::type;
#ifndef FENNEC_DOXYGEN #ifndef FENNEC_DOXYGEN
// specialization of fennec::conditional for \f$true\f$ case // specialization of fennec::conditional for \emph{true} case
template<typename T, typename F> template<typename T, typename F>
struct conditional<true, T, F> : type_identity<T>{}; struct conditional<true, T, F> : type_identity<T>{};
// specialization of fennec::conditional for \f$false\f$ case // specialization of fennec::conditional for \emph{false} case
template<typename T, typename F> template<typename T, typename F>
struct conditional<false, T, F> : type_identity<F>{}; struct conditional<false, T, F> : type_identity<F>{};
#endif #endif
@@ -103,13 +103,13 @@ struct conditional<false, T, F> : type_identity<F>{};
// fennec::detect ====================================================================================================== // fennec::detect ======================================================================================================
/// ///
/// \brief Detect whether \f$DetectT<ArgsT...>\f$ is a valid type /// \brief Detect whether \emph{DetectT<ArgsT...>} is a valid type
/// ///
/// \details Selects \f$DetectT<ArgsT...>\f$ if it exists, otherwise selects \f$DefaultT\f$ The chosen type is stored in `fennec::detect::type` and /// \details Selects \emph{DetectT<ArgsT...>} if it exists, otherwise selects \emph{DefaultT} The chosen type is stored in `fennec::detect::type` and
/// a boolean value is stored in `fennec::detect::is_detected` representing whether \f$DetectT<ArgsT...>\f$ is found. /// a boolean value is stored in `fennec::detect::is_detected` representing whether \emph{DetectT<ArgsT...>} is found.
/// \tparam DefaultT Default type /// \tparam DefaultT Default type
/// \tparam DetectT Type to detect /// \tparam DetectT Type to detect
/// \tparam ArgsT Any template arguments for \f$DetectT<ArgsT>\f$ /// \tparam ArgsT Any template arguments for \emph{DetectT<ArgsT>}
template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT> template<typename DefaultT, template<typename...> typename DetectT, typename...ArgsT>
struct detect struct detect
{ {
@@ -140,7 +140,7 @@ struct detect<DefaultT, DetectT, ArgsT...>
/// ///
/// \brief Leverage SFINAE to conditionally enable a function or class at compile-time /// \brief Leverage SFINAE to conditionally enable a function or class at compile-time
/// ///
/// \details If \f$B\f$ is \f$true\f$, define a public member type \f$type\f$. Otherwise, there is no member. <br> /// \details If \emph{B} is \emph{true}, define a public member type \emph{type}. Otherwise, there is no member. <br>
/// **Example Usage** /// **Example Usage**
/// \code{.cpp} /// \code{.cpp}
/// template<typename TypeT, /// template<typename TypeT,

View File

@@ -41,7 +41,7 @@ namespace fennec
/// ///
/// \brief Metaprogramming helper for testing values of type T /// \brief Metaprogramming helper for testing values of type T
/// \tparam T the type /// \tparam T the type
/// \returns a metavalue of type \f$T\f$ /// \returns a metavalue of type \emph{T}
template<typename T> auto declval() noexcept -> decltype(detail::_declval<T>(0)) { template<typename T> auto declval() noexcept -> decltype(detail::_declval<T>(0)) {
static_assert(detail::_declval_protector<T>{}, "declval must not be used"); static_assert(detail::_declval_protector<T>{}, "declval must not be used");
return detail::_declval<T>(0); return detail::_declval<T>(0);

View File

@@ -19,7 +19,6 @@
#ifndef FENNEC_LANG_DETAIL_TYPE_TRAITS_H #ifndef FENNEC_LANG_DETAIL_TYPE_TRAITS_H
#define FENNEC_LANG_DETAIL_TYPE_TRAITS_H #define FENNEC_LANG_DETAIL_TYPE_TRAITS_H
#include <fennec/lang/ranges.h>
#include <fennec/lang/constants.h> #include <fennec/lang/constants.h>
#include <fennec/lang/declval.h> #include <fennec/lang/declval.h>
@@ -82,6 +81,12 @@ namespace fennec::detail
template<typename> struct _is_rvalue_reference : false_type {}; template<typename> struct _is_rvalue_reference : false_type {};
template<typename T> struct _is_rvalue_reference<T&&> : true_type {}; template<typename T> struct _is_rvalue_reference<T&&> : true_type {};
template<typename> struct _is_bounded_array : false_type {};
template<typename T, size_t N> struct _is_bounded_array<T[N]> : true_type {};
template<typename> struct _is_unbounded_array : false_type {};
template<typename T> struct _is_unbounded_array<T[]> : true_type {};
template<typename T> struct _is_complete { template<typename T> struct _is_complete {
template<typename U> template<typename U>
static auto test(U*) -> bool_constant<sizeof(U) == sizeof(U)>; static auto test(U*) -> bool_constant<sizeof(U) == sizeof(U)>;
@@ -105,13 +110,37 @@ namespace fennec::detail
using type = decltype(test<T>(0)); using type = decltype(test<T>(0));
}; };
template<typename ContainerT>
auto _begin(ContainerT& c) noexcept(noexcept(c.begin())) -> decltype(c.begin()) {
return c.begin();
}
template<typename T, size_t N>
auto _begin(T (&arr)[N]) -> T* {
return arr[0];
}
void _begin(...);
template<typename ContainerT>
auto _end(ContainerT& c) noexcept(noexcept(c.end())) -> decltype(c.end()) {
return c.end();
}
template<typename T, size_t N>
auto _end(T (&arr)[N]) -> T* {
return arr[N - 1];
}
void _end(...);
// https://stackoverflow.com/questions/13830158/how-to-write-a-trait-which-checks-whether-a-type-is-iterable // https://stackoverflow.com/questions/13830158/how-to-write-a-trait-which-checks-whether-a-type-is-iterable
template<typename T> template<typename T>
auto _is_iterable(int) -> decltype( auto _is_iterable(int) -> decltype(
fennec::begin(declval<T&>()) != fennec::end(declval<T&>()), detail::_begin(declval<T&>()) != detail::_end(declval<T&>()),
void(), void(),
++declval<decltype(fennec::begin(declval<T&>()))&>(), ++declval<decltype(detail::_begin(declval<T&>()))&>(),
void(*fennec::begin(declval<T&>())), void(*detail::_begin(declval<T&>())),
true_type{} true_type{}
); );
@@ -130,6 +159,20 @@ namespace fennec::detail
auto _is_indexable(...) -> false_type; auto _is_indexable(...) -> false_type;
// https://stackoverflow.com/a/31409532
template<typename T>
auto _is_iterator(...) -> decltype(
declval<T>() != declval<T>(),
void(),
++declval<T>(),
*declval<T>(),
true_type{}
);
template<typename T>
auto _is_iterator(...) -> false_type;
template<typename T> template<typename T>
auto _is_mappable(int) -> decltype( auto _is_mappable(int) -> decltype(

View File

@@ -23,7 +23,7 @@
/// ///
/// \details This file is automatically generated for the current build environment. /// \details This file is automatically generated for the current build environment.
/// ///
/// Environment for this build: GNU Linux x86_64 /// Environment for this build: Clang Linux x86_64
/// ///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) /// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
/// ///
@@ -60,55 +60,55 @@
#undef FLT_DENORM_MIN #undef FLT_DENORM_MIN
#undef FLT_ROUND_ERR #undef FLT_ROUND_ERR
/// \brief Does \f$float\f$ have an infinity? /// \brief Does \emph{float} have an infinity?
#define FLT_HAS_INFINITY 1 #define FLT_HAS_INFINITY 1
/// \brief Does \f$float\f$ have a quiet NaN? /// \brief Does \emph{float} have a quiet NaN?
#define FLT_HAS_QUIET_NAN 1 #define FLT_HAS_QUIET_NAN 1
/// \brief Does \f$float\f$ have a signaling NaN? /// \brief Does \emph{float} have a signaling NaN?
#define FLT_HAS_SIGNALING_NAN 1 #define FLT_HAS_SIGNALING_NAN 1
/// \brief Does \f$float\f$ use denormalization? /// \brief Does \emph{float} use denormalization?
#define FLT_HAS_DENORM 1 #define FLT_HAS_DENORM 1
/// \brief Does \f$float\f$ have loss with denormalization? /// \brief Does \emph{float} have loss with denormalization?
#define FLT_HAS_DENORM_LOSS 0 #define FLT_HAS_DENORM_LOSS 0
/// \brief What rounding style does \f$float\f$ use? /// \brief What rounding style does \emph{float} use?
#define FLT_ROUNDS 1 #define FLT_ROUNDS 1
/// \brief Does \f$float\f$ use the IEEE floating point specification? /// \brief Does \emph{float} use the IEEE floating point specification?
#define FLT_IS_IEC559 1 #define FLT_IS_IEC559 1
/// \brief The number of mantissa bits in \f$float\f$. /// \brief The number of mantissa bits in \emph{float}.
#define FLT_MANT_DIG 24 #define FLT_MANT_DIG 24
/// \brief The number of decimal digits guaranteed to be preserved in a \f$float\f$ &rarr; \f$text\f$ &rarr; \f$float\f$. /// \brief The number of decimal digits guaranteed to be preserved in a \emph{float} &rarr; \emph{text} &rarr; \emph{float}.
#define FLT_DIG 6 #define FLT_DIG 6
/// \brief The decimal precision required to serialize and deserialize a \f$float\f$. /// \brief The decimal precision required to serialize and deserialize a \emph{float}.
#define FLT_DECIMAL_DIG 9 #define FLT_DECIMAL_DIG 9
/// \brief The radix, or integer base, used to represent a \f$float\f$. /// \brief The radix, or integer base, used to represent a \emph{float}.
#define FLT_RADIX 2 #define FLT_RADIX 2
/// \brief The minimum negative integer such that \f${FLT_RADIX}^{FLT_MIN_EXP}\f$ results in a normalized \f$float\f$. /// \brief The minimum negative integer such that \math{\textbf{FLT_RADIX}^\textbf{FLT_MIN_EXP}} results in a normalized \emph{float}.
#define FLT_MIN_EXP -125 #define FLT_MIN_EXP -125
/// \brief The maximum positive integer such that \f${FLT_RADIX}^{FLT_MAX_EXP}\f$ results in a non-infinite \f$float\f$. /// \brief The maximum positive integer such that \math{\textbf{FLT_RADIX}^\textbf{FLT_MAX_EXP}} results in a non-infinite \emph{float}.
#define FLT_MAX_EXP 128 #define FLT_MAX_EXP 128
/// \brief The minimum negative integer such that \f${10}^{FLT_MIN_EXP}\f$ results in a normalized \f$float\f$. /// \brief The minimum negative integer such that \math{{10}^\textbf{FLT_MIN_EXP}} results in a normalized \emph{float}.
#define FLT_MIN_10_EXP -37 #define FLT_MIN_10_EXP -37
/// \brief The maximum positive integer such that \f${10}^{FLT_MAX_EXP}\f$ results in a non-infinite \f$float\f$. /// \brief The maximum positive integer such that \math{{10}^\textbf{FLT_MAX_EXP}} results in a non-infinite \emph{float}.
#define FLT_MAX_10_EXP 38 #define FLT_MAX_10_EXP 38
/// \brief Do arithmetics operations with \f$float\f$ trap? /// \brief Do arithmetics operations with \emph{float} trap?
#define FLT_TRAPS 0 #define FLT_TRAPS 0
/// \brief Do arithmetics operations with \f$float\f$ check for underflow? /// \brief Do arithmetics operations with \emph{float} check for underflow?
#define FLT_TINYNESS_BEFORE 0 #define FLT_TINYNESS_BEFORE 0
/// \brief Smallest positive, finite, normal value of \f$float\f$. /// \brief Smallest positive, finite, normal value of \emph{float}.
#define FLT_MIN fennec::bit_cast<float>(0x800000) #define FLT_MIN fennec::bit_cast<float>(0x800000)
/// \brief Largest positive, finite value of \f$float\f$. /// \brief Largest positive, finite value of \emph{float}.
#define FLT_MAX fennec::bit_cast<float>(0x7f7fffff) #define FLT_MAX fennec::bit_cast<float>(0x7f7fffff)
/// \brief The difference between \f$1.0\f$ and the next representable value of \f$float\f$. /// \brief The difference between \emph{1.0} and the next representable value of \emph{float}.
#define FLT_EPSILON fennec::bit_cast<float>(0x34000000) #define FLT_EPSILON fennec::bit_cast<float>(0x34000000)
/// \brief A value representing \f$\inf\f$ of type \f$float\f$. /// \brief A value representing \emph{\inf} of type \emph{float}.
#define FLT_INF fennec::bit_cast<float>(0x7f800000) #define FLT_INF fennec::bit_cast<float>(0x7f800000)
/// \brief A value representing \f$NaN\f$ of type \f$float\f$ that does not trap. /// \brief A value representing \emph{NaN} of type \emph{float} that does not trap.
#define FLT_QUIET_NAN fennec::bit_cast<float>(0x7fc00000) #define FLT_QUIET_NAN fennec::bit_cast<float>(0x7fc00000)
/// \brief A value representing \f$NaN\f$ of type \f$float\f$ that traps. /// \brief A value representing \emph{NaN} of type \emph{float} that traps.
#define FLT_SIGNALING_NAN fennec::bit_cast<float>(0x7fa00000) #define FLT_SIGNALING_NAN fennec::bit_cast<float>(0x7fa00000)
/// \brief Smallest positive, finite, subnormal value of \f$float\f$. /// \brief Smallest positive, finite, subnormal value of \emph{float}.
#define FLT_DENORM_MIN fennec::bit_cast<float>(0x1) #define FLT_DENORM_MIN fennec::bit_cast<float>(0x1)
/// \brief Maximum rounding error of type \f$float\f$. /// \brief Maximum rounding error of type \emph{float}.
#define FLT_ROUND_ERR fennec::bit_cast<float>(0x3f000000) #define FLT_ROUND_ERR fennec::bit_cast<float>(0x3f000000)
#undef DBL_HAS_INFINITY #undef DBL_HAS_INFINITY
@@ -137,55 +137,55 @@
#undef DBL_DENORM_MIN #undef DBL_DENORM_MIN
#undef DBL_ROUND_ERR #undef DBL_ROUND_ERR
/// \brief Does \f$double\f$ have an infinity? /// \brief Does \emph{double} have an infinity?
#define DBL_HAS_INFINITY 1 #define DBL_HAS_INFINITY 1
/// \brief Does \f$double\f$ have a quiet NaN? /// \brief Does \emph{double} have a quiet NaN?
#define DBL_HAS_QUIET_NAN 1 #define DBL_HAS_QUIET_NAN 1
/// \brief Does \f$double\f$ have a signaling NaN? /// \brief Does \emph{double} have a signaling NaN?
#define DBL_HAS_SIGNALING_NAN 1 #define DBL_HAS_SIGNALING_NAN 1
/// \brief Does \f$double\f$ use denormalization? /// \brief Does \emph{double} use denormalization?
#define DBL_HAS_DENORM 1 #define DBL_HAS_DENORM 1
/// \brief Does \f$double\f$ have loss with denormalization? /// \brief Does \emph{double} have loss with denormalization?
#define DBL_HAS_DENORM_LOSS 0 #define DBL_HAS_DENORM_LOSS 0
/// \brief What rounding style does \f$double\f$ use? /// \brief What rounding style does \emph{double} use?
#define DBL_ROUNDS 1 #define DBL_ROUNDS 1
/// \brief Does \f$double\f$ use the IEEE doubleing point specification? /// \brief Does \emph{double} use the IEEE doubleing point specification?
#define DBL_IS_IEC559 1 #define DBL_IS_IEC559 1
/// \brief The number of mantissa bits in \f$double\f$. /// \brief The number of mantissa bits in \emph{double}.
#define DBL_MANT_DIG 53 #define DBL_MANT_DIG 53
/// \brief The number of decimal digits guaranteed to be preserved in a \f$double\f$ &rarr; \f$text\f$ &rarr; \f$double\f$. /// \brief The number of decimal digits guaranteed to be preserved in a \emph{double} &rarr; \emph{text} &rarr; \emph{double}.
#define DBL_DIG 15 #define DBL_DIG 15
/// \brief The decimal precision required to serialize and deserialize a \f$double\f$. /// \brief The decimal precision required to serialize and deserialize a \emph{double}.
#define DBL_DECIMAL_DIG 17 #define DBL_DECIMAL_DIG 17
/// \brief The radix, or integer base, used to represent a \f$double\f$. /// \brief The radix, or integer base, used to represent a \emph{double}.
#define DBL_RADIX 2 #define DBL_RADIX 2
/// \brief The minimum negative integer such that \f${DBL_RADIX}^{DBL_MIN_EXP}\f$ results in a normalized \f$double\f$. /// \brief The minimum negative integer such that \math{\textbf{DBL_RADIX}^\textbf{DBL_MIN_EXP}} results in a normalized \emph{double}.
#define DBL_MIN_EXP -1021 #define DBL_MIN_EXP -1021
/// \brief The maximum positive integer such that \f${DBL_RADIX}^{DBL_MAX_EXP}\f$ results in a non-infinite \f$double\f$. /// \brief The maximum positive integer such that \math{\textbf{DBL_RADIX}^\textbf{DBL_MAX_EXP}} results in a non-infinite \emph{double}.
#define DBL_MAX_EXP 1024 #define DBL_MAX_EXP 1024
/// \brief The minimum negative integer such that \f${10}^{DBL_MIN_EXP}\f$ results in a normalized \f$double\f$. /// \brief The minimum negative integer such that \math{{10}^\textbf{DBL_MIN_EXP}} results in a normalized \emph{double}.
#define DBL_MIN_10_EXP -307 #define DBL_MIN_10_EXP -307
/// \brief The maximum positive integer such that \f${10}^{DBL_MAX_EXP}\f$ results in a non-infinite \f$double\f$. /// \brief The maximum positive integer such that \math{{10}^\textbf{DBL_MAX_EXP}} results in a non-infinite \emph{double}.
#define DBL_MAX_10_EXP 308 #define DBL_MAX_10_EXP 308
/// \brief Do arithmetics operations with \f$double\f$ trap? /// \brief Do arithmetics operations with \emph{double} trap?
#define DBL_TRAPS 0 #define DBL_TRAPS 0
/// \brief Do arithmetics operations with \f$double\f$ check for underflow? /// \brief Do arithmetics operations with \emph{double} check for underflow?
#define DBL_TINYNESS_BEFORE 0 #define DBL_TINYNESS_BEFORE 0
/// \brief Smallest positive, finite, normal value of \f$double\f$. /// \brief Smallest positive, finite, normal value of \emph{double}.
#define DBL_MIN fennec::bit_cast<double>(0x10000000000000ll) #define DBL_MIN fennec::bit_cast<double>(0x10000000000000ll)
/// \brief Largest positive, finite value of \f$double\f$. /// \brief Largest positive, finite value of \emph{double}.
#define DBL_MAX fennec::bit_cast<double>(0x7fefffffffffffffll) #define DBL_MAX fennec::bit_cast<double>(0x7fefffffffffffffll)
/// \brief The difference between \f$1.0\f$ and the next representable value of \f$double\f$. /// \brief The difference between \emph{1.0} and the next representable value of \emph{double}.
#define DBL_EPSILON fennec::bit_cast<double>(0x3cb0000000000000ll) #define DBL_EPSILON fennec::bit_cast<double>(0x3cb0000000000000ll)
/// \brief A value representing \f$\inf\f$ of type \f$double\f$. /// \brief A value representing \emph{\inf} of type \emph{double}.
#define DBL_INF fennec::bit_cast<double>(0x7ff0000000000000ll) #define DBL_INF fennec::bit_cast<double>(0x7ff0000000000000ll)
/// \brief A value representing \f$NaN\f$ of type \f$double\f$ that does not trap. /// \brief A value representing \emph{NaN} of type \emph{double} that does not trap.
#define DBL_QUIET_NAN fennec::bit_cast<double>(0x7ff8000000000000ll) #define DBL_QUIET_NAN fennec::bit_cast<double>(0x7ff8000000000000ll)
/// \brief A value representing \f$NaN\f$ of type \f$double\f$ that traps. /// \brief A value representing \emph{NaN} of type \emph{double} that traps.
#define DBL_SIGNALING_NAN fennec::bit_cast<double>(0x7ff4000000000000ll) #define DBL_SIGNALING_NAN fennec::bit_cast<double>(0x7ff4000000000000ll)
/// \brief Smallest positive, finite, subnormal value of \f$double\f$. /// \brief Smallest positive, finite, subnormal value of \emph{double}.
#define DBL_DENORM_MIN fennec::bit_cast<double>(0x1ll) #define DBL_DENORM_MIN fennec::bit_cast<double>(0x1ll)
/// \brief Maximum rounding error of type \f$double\f$. /// \brief Maximum rounding error of type \emph{double}.
#define DBL_ROUND_ERR fennec::bit_cast<double>(0x3fe0000000000000ll) #define DBL_ROUND_ERR fennec::bit_cast<double>(0x3fe0000000000000ll)
#endif // FENNEC_LANG_FLOAT_H #endif // FENNEC_LANG_FLOAT_H

View File

@@ -85,18 +85,18 @@ public:
/// ///
/// \brief copy assignment /// \brief copy assignment
/// \param func the function to copy /// \param func the function to copy
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr function& operator=(const function& func) = default; constexpr function& operator=(const function& func) = default;
/// ///
/// \brief move assignment /// \brief move assignment
/// \param func the function to capture /// \param func the function to capture
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr function& operator=(function&& func) = default; constexpr function& operator=(function&& func) = default;
/// ///
/// \brief null assignment /// \brief null assignment
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr function& operator=(nullptr_t) { constexpr function& operator=(nullptr_t) {
call = nullptr; call = nullptr;
return *this; return *this;
@@ -105,7 +105,7 @@ public:
/// ///
/// \brief function assignment /// \brief function assignment
/// \param func the function to capture /// \param func the function to capture
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr function& operator=(ReturnT (*func)(ArgsT...)) { constexpr function& operator=(ReturnT (*func)(ArgsT...)) {
call = func; call = func;
return *this; return *this;
@@ -113,7 +113,7 @@ public:
/// ///
/// \brief implicit bool check /// \brief implicit bool check
/// \returns \f$true\f$ if a function is captured, \f$false\f$ otherwise /// \returns \emph{true} if a function is captured, \emph{false} otherwise
constexpr operator bool() const noexcept { constexpr operator bool() const noexcept {
return call != nullptr; return call != nullptr;
} }

View File

@@ -66,11 +66,11 @@ struct hash<PtrT*> : hash<uintptr_t> {
/// \param ptr the pointer to hash /// \param ptr the pointer to hash
/// \returns an integer hash for the value /// \returns an integer hash for the value
constexpr size_t operator()(PtrT* ptr) const { constexpr size_t operator()(PtrT* ptr) const {
return hash<uintptr_t>::operator()((uintptr_t)(const void*)ptr); return hash<uintptr_t>::operator()(fennec::bit_cast<uintptr_t>(ptr));
} }
}; };
// Float /// \brief Hashing for `float`
template<> template<>
struct hash<float> : hash<uint32_t> { struct hash<float> : hash<uint32_t> {
using type_t = float; //!< the type of the hash using type_t = float; //!< the type of the hash
@@ -82,6 +82,7 @@ struct hash<float> : hash<uint32_t> {
} }
}; };
/// \brief Hashing for `double`
template<> template<>
struct hash<double> : hash<uint64_t> { struct hash<double> : hash<uint64_t> {
using type_t = double; //!< the type of the hash using type_t = double; //!< the type of the hash

View File

@@ -23,7 +23,7 @@
/// ///
/// \details This file is automatically generated for the current build environment. /// \details This file is automatically generated for the current build environment.
/// ///
/// Environment for this build: GNU Linux x86_64 /// Environment for this build: Clang Linux x86_64
/// ///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) /// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
/// ///
@@ -53,212 +53,212 @@
#undef ULLONG_MIN #undef ULLONG_MIN
#undef ULLONG_MAX #undef ULLONG_MAX
/// \brief Is \f$char\f$ signed? /// \brief Is \emph{char} signed?
#define CHAR_IS_SIGNED true #define CHAR_IS_SIGNED true
/// \brief Rounding style of type \f$char\f$. /// \brief Rounding style of type \emph{char}.
#define CHAR_ROUNDS 0x0 #define CHAR_ROUNDS 0
/// \brief Number of radix digits represented by \f$char\f$. /// \brief Number of radix digits represented by \emph{char}.
#define CHAR_RADIX_DIG 0x7 #define CHAR_RADIX_DIG 0x7
/// \brief Number of decimal digits represented by \f$char\f$. /// \brief Number of decimal digits represented by \emph{char}.
#define CHAR_DIG 0x2 #define CHAR_DIG 0x2
/// \brief Number of decimal digits necessary to differentiate all values of type \f$char\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{char}.
#define CHAR_DECIMAL_DIG 0x0 #define CHAR_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \f$char\f$. /// \brief The radix, or integer base, used to represent a \emph{char}.
#define CHAR_RADIX 0x2 #define CHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$char\f$ trap? /// \brief Do arithmetics operations with \emph{char} trap?
#define CHAR_TRAPS 0xtrue #define CHAR_TRAPS true
/// \brief Smallest finite value of \f$char\f$. /// \brief Smallest finite value of \emph{char}.
#define CHAR_MIN 0x80 #define CHAR_MIN -0x80
/// \brief Largest finite value of \f$char\f$. /// \brief Largest finite value of \emph{char}.
#define CHAR_MAX 0x7f #define CHAR_MAX 0x7f
/// \brief Is \f$wchar_t\f$ signed? /// \brief Is \emph{wchar_t} signed?
#define WCHAR_IS_SIGNED true #define WCHAR_IS_SIGNED true
/// \brief Rounding style of type \f$wchar_t\f$. /// \brief Rounding style of type \emph{wchar_t}.
#define WCHAR_ROUNDS 0x0 #define WCHAR_ROUNDS 0
/// \brief Number of radix digits represented by \f$wchar_t\f$. /// \brief Number of radix digits represented by \emph{wchar_t}.
#define WCHAR_RADIX_DIG 0x1f #define WCHAR_RADIX_DIG 0x1f
/// \brief Number of decimal digits represented by \f$wchar_t\f$. /// \brief Number of decimal digits represented by \emph{wchar_t}.
#define WCHAR_DIG 0x9 #define WCHAR_DIG 0x9
/// \brief Number of decimal digits necessary to differentiate all values of type \f$wchar_t\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{wchar_t}.
#define WCHAR_DECIMAL_DIG 0x0 #define WCHAR_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \f$wchar_t\f$. /// \brief The radix, or integer base, used to represent a \emph{wchar_t}.
#define WCHAR_RADIX 0x2 #define WCHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$wchar_t\f$ trap? /// \brief Do arithmetics operations with \emph{wchar_t} trap?
#define WCHAR_TRAPS 0xtrue #define WCHAR_TRAPS true
/// \brief Smallest finite value of \f$wchar_t\f$. /// \brief Smallest finite value of \emph{wchar_t}.
#define WCHAR_MIN 0x80000000 #define WCHAR_MIN - 0x0
/// \brief Largest finite value of \f$wchar_t\f$. /// \brief Largest finite value of \emph{wchar_t}.
#define WCHAR_MAX 0x7fffffff #define WCHAR_MAX 0xffff
/// \brief Is \f$signed char\f$ signed? /// \brief Rounding style of type \emph{signed char}.
#define SCHAR_ROUNDS 0x0 #define SCHAR_ROUNDS 0
/// \brief Rounding style of type \f$signed char\f$. /// \brief Number of radix digits represented by \emph{signed char}.
#define SCHAR_RADIX_DIG 0x7 #define SCHAR_RADIX_DIG 0x7
/// \brief Number of radix digits represented by \f$signed char\f$. /// \brief Number of decimal digits represented by \emph{signed char}.
#define SCHAR_DIG 0x2 #define SCHAR_DIG 0x2
/// \brief Number of decimal digits represented by \f$signed char\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{signed char}.
#define SCHAR_DECIMAL_DIG 0x0 #define SCHAR_DECIMAL_DIG 0
/// \brief Number of decimal digits necessary to differentiate all values of type \f$signed char\f$. /// \brief The radix, or integer base, used to represent a \emph{signed char}.
#define SCHAR_RADIX 0x2 #define SCHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$signed char\f$ trap? /// \brief Do arithmetics operations with \emph{signed char} trap?
#define SCHAR_TRAPS 0xtrue #define SCHAR_TRAPS true
/// \brief Smallest finite value of \f$signed char\f$. /// \brief Smallest finite value of \emph{signed char}.
#define SCHAR_MIN 0x80 #define SCHAR_MIN -0x80
/// \brief Largest finite value of \f$signed char\f$. /// \brief Largest finite value of \emph{signed char}.
#define SCHAR_MAX 0x7f #define SCHAR_MAX 0x7f
/// \brief Is \f$unsigned char\f$ unsigned? /// \brief Rounding style of type \emph{unsigned char}.
#define UCHAR_ROUNDS 0x0 #define UCHAR_ROUNDS 0
/// \brief Rounding style of type \f$unsigned char\f$. /// \brief Number of radix digits represented by \emph{unsigned char}.
#define UCHAR_RADIX_DIG 0x8 #define UCHAR_RADIX_DIG 0x8
/// \brief Number of radix digits represented by \f$unsigned char\f$. /// \brief Number of decimal digits represented by \emph{unsigned char}.
#define UCHAR_DIG 0x2 #define UCHAR_DIG 0x2
/// \brief Number of decimal digits represented by \f$unsigned char\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned char}.
#define UCHAR_DECIMAL_DIG 0x0 #define UCHAR_DECIMAL_DIG 0
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned char\f$. /// \brief The radix, or integer base, used to represent an \emph{unsigned char}.
#define UCHAR_RADIX 0x2 #define UCHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned char\f$ trap? /// \brief Do arithmetics operations with \emph{unsigned char} trap?
#define UCHAR_TRAPS 0xtrue #define UCHAR_TRAPS true
/// \brief Smallest finite value of \f$unsigned char\f$. /// \brief Smallest finite value of \emph{unsigned char}.
#define UCHAR_MIN 0x0 #define UCHAR_MIN 0x0
/// \brief Largest finite value of \f$unsigned char\f$. /// \brief Largest finite value of \emph{unsigned char}.
#define UCHAR_MAX 0xff #define UCHAR_MAX 0xff
/// \brief Rounding style of type \f$short\f$. /// \brief Rounding style of type \emph{short}.
#define SHORT_ROUNDS 0x0 #define SHORT_ROUNDS 0
/// \brief Number of radix digits represented by \f$short\f$. /// \brief Number of radix digits represented by \emph{short}.
#define SHORT_RADIX_DIG 0xf #define SHORT_RADIX_DIG 0xf
/// \brief Number of decimal digits represented by \f$short\f$. /// \brief Number of decimal digits represented by \emph{short}.
#define SHORT_DIG 0x4 #define SHORT_DIG 0x4
/// \brief Number of decimal digits necessary to differentiate all values of type \f$short\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{short}.
#define SHORT_DECIMAL_DIG 0x0 #define SHORT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \f$short\f$. /// \brief The radix, or integer base, used to represent a \emph{short}.
#define SHORT_RADIX 0x2 #define SHORT_RADIX 0x2
/// \brief Do arithmetics operations with \f$short\f$ trap? /// \brief Do arithmetics operations with \emph{short} trap?
#define SHORT_TRAPS 0xtrue #define SHORT_TRAPS true
/// \brief Smallest finite value of \f$short\f$. /// \brief Smallest finite value of \emph{short}.
#define SHORT_MIN 0xffff8000 #define SHORT_MIN 0x8000
/// \brief Largest finite value of \f$short\f$. /// \brief Largest finite value of \emph{short}.
#define SHORT_MAX 0x7fff #define SHORT_MAX 0x7fff
/// \brief Rounding style of type \f$unsigned short\f$. /// \brief Rounding style of type \emph{unsigned short}.
#define USHORT_ROUNDS 0x0 #define USHORT_ROUNDS 0
/// \brief Number of radix digits represented by \f$unsigned short\f$. /// \brief Number of radix digits represented by \emph{unsigned short}.
#define USHORT_RADIX_DIG 0x10 #define USHORT_RADIX_DIG 0x10
/// \brief Number of decimal digits represented by \f$unsigned short\f$. /// \brief Number of decimal digits represented by \emph{unsigned short}.
#define USHORT_DIG 0x4 #define USHORT_DIG 0x4
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned short\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned short}.
#define USHORT_DECIMAL_DIG 0x0 #define USHORT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \f$unsigned short\f$. /// \brief The radix, or integer base, used to represent an \emph{unsigned short}.
#define USHORT_RADIX 0x2 #define USHORT_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned short\f$ trap? /// \brief Do arithmetics operations with \emph{unsigned short} trap?
#define USHORT_TRAPS 0xtrue #define USHORT_TRAPS true
/// \brief Smallest finite value of \f$unsigned short\f$. /// \brief Smallest finite value of \emph{unsigned short}.
#define USHORT_MIN 0x0 #define USHORT_MIN 0
/// \brief Largest finite value of \f$unsigned short\f$. /// \brief Largest finite value of \emph{unsigned short}.
#define USHORT_MAX 0xffff #define USHORT_MAX 0xffff
/// \brief Rounding style of type \f$int\f$. /// \brief Rounding style of type \emph{int}.
#define INT_ROUNDS 0x0 #define INT_ROUNDS 0
/// \brief Number of radix digits represented by \f$int\f$. /// \brief Number of radix digits represented by \emph{int}.
#define INT_RADIX_DIG 0x1f #define INT_RADIX_DIG 0x1f
/// \brief Number of decimal digits represented by \f$int\f$. /// \brief Number of decimal digits represented by \emph{int}.
#define INT_DIG 0x9 #define INT_DIG 0x9
/// \brief Number of decimal digits necessary to differentiate all values of type \f$int\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{int}.
#define INT_DECIMAL_DIG 0x0 #define INT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \f$int\f$. /// \brief The radix, or integer base, used to represent an \emph{int}.
#define INT_RADIX 0x2 #define INT_RADIX 0x2
/// \brief Do arithmetics operations with \f$int\f$ trap? /// \brief Do arithmetics operations with \emph{int} trap?
#define INT_TRAPS 0xtrue #define INT_TRAPS true
/// \brief Smallest finite value of \f$int\f$. /// \brief Smallest finite value of \emph{int}.
#define INT_MIN 0x80000000 #define INT_MIN 0x80000000
/// \brief Largest finite value of \f$int\f$. /// \brief Largest finite value of \emph{int}.
#define INT_MAX 0x7fffffff #define INT_MAX 0x7fffffff
/// \brief Rounding style of type \f$unsigned int\f$. /// \brief Rounding style of type \emph{unsigned int}.
#define UINT_ROUNDS 0x0 #define UINT_ROUNDS 0
/// \brief Number of radix digits represented by \f$unsigned int\f$. /// \brief Number of radix digits represented by \emph{unsigned int}.
#define UINT_RADIX_DIG 0x20 #define UINT_RADIX_DIG 0x20
/// \brief Number of decimal digits represented by \f$unsigned int\f$. /// \brief Number of decimal digits represented by \emph{unsigned int}.
#define UINT_DIG 0x9 #define UINT_DIG 0x9
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned int\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned int}.
#define UINT_DECIMAL_DIG 0x0 #define UINT_DECIMAL_DIG 0
/// \brief The radix, or unsigned integer base, used to represent a \f$unsigned int\f$. /// \brief The radix, or integer base, used to represent an \emph{unsigned int}.
#define UINT_RADIX 0x2 #define UINT_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned int\f$ trap? /// \brief Do arithmetics operations with \emph{unsigned int} trap?
#define UINT_TRAPS 0xtrue #define UINT_TRAPS true
/// \brief Smallest finite value of \f$unsigned int\f$. /// \brief Smallest finite value of \emph{unsigned int}.
#define UINT_MIN 0x0 #define UINT_MIN 0
/// \brief Largest finite value of \f$unsigned int\f$. /// \brief Largest finite value of \emph{unsigned int}.
#define UINT_MAX 0xffffffff #define UINT_MAX 0xffffffff
/// \brief Rounding style of type \f$long int\f$. /// \brief Rounding style of type \emph{long int}.
#define LONG_ROUNDS 0x0 #define LONG_ROUNDS 0
/// \brief Number of radix digits represented by \f$long int\f$. /// \brief Number of radix digits represented by \emph{long int}.
#define LONG_RADIX_DIG 0x3f #define LONG_RADIX_DIG 0x3f
/// \brief Number of decimal digits represented by \f$long int\f$. /// \brief Number of decimal digits represented by \emph{long int}.
#define LONG_DIG 0x12 #define LONG_DIG 0x12
/// \brief Number of decimal digits necessary to differentiate all values of type \f$long int\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{long int}.
#define LONG_DECIMAL_DIG 0x0 #define LONG_DECIMAL_DIG 0
/// \brief The radix, or long integer base, used to represent a \f$long int\f$. /// \brief The radix, or integer base, used to represent a \emph{long int}.
#define LONG_RADIX 0x2 #define LONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$long int\f$ trap? /// \brief Do arithmetics operations with \emph{long int} trap?
#define LONG_TRAPS 0xtrue #define LONG_TRAPS true
/// \brief Smallest finite value of \f$long int\f$. /// \brief Smallest finite value of \emph{long int}.
#define LONG_MIN 0x8000000000000000 #define LONG_MIN 0x8000000000000000
/// \brief Largest finite value of \f$long int\f$. /// \brief Largest finite value of \emph{long int}.
#define LONG_MAX 0x7fffffffffffffff #define LONG_MAX 0x7fffffffffffffff
/// \brief Rounding style of type \f$unsigned long int\f$. /// \brief Rounding style of type \emph{unsigned long int}.
#define ULONG_ROUNDS 0x0 #define ULONG_ROUNDS 0
/// \brief Number of radix digits represented by \f$unsigned long int\f$. /// \brief Number of radix digits represented by \emph{unsigned long int}.
#define ULONG_RADIX_DIG 0x40 #define ULONG_RADIX_DIG 0x40
/// \brief Number of decimal digits represented by \f$unsigned long int\f$. /// \brief Number of decimal digits represented by \emph{unsigned long int}.
#define ULONG_DIG 0x13 #define ULONG_DIG 0x13
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned long int\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned long int}.
#define ULONG_DECIMAL_DIG 0x0 #define ULONG_DECIMAL_DIG 0
/// \brief The radix, or unsigned long integer base, used to represent a \f$unsigned long int\f$. /// \brief The radix, or integer base, used to represent an \emph{unsigned long int}.
#define ULONG_RADIX 0x2 #define ULONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned long int\f$ trap? /// \brief Do arithmetics operations with \emph{unsigned long int} trap?
#define ULONG_TRAPS 0xtrue #define ULONG_TRAPS true
/// \brief Smallest finite value of \f$unsigned long int\f$. /// \brief Smallest finite value of \emph{unsigned long int}.
#define ULONG_MIN 0x0 #define ULONG_MIN 0
/// \brief Largest finite value of \f$unsigned long int\f$. /// \brief Largest finite value of \emph{unsigned long int}.
#define ULONG_MAX 0xffffffffffffffff #define ULONG_MAX 0xffffffffffffffff
/// \brief Rounding style of type \f$long long\f$. /// \brief Rounding style of type \emph{long long}.
#define LLONG_ROUNDS 0x0 #define LLONG_ROUNDS 0
/// \brief Number of radix digits represented by \f$long long\f$. /// \brief Number of radix digits represented by \emph{long long}.
#define LLONG_RADIX_DIG 0x3f #define LLONG_RADIX_DIG 0x3f
/// \brief Number of decimal digits represented by \f$long long\f$. /// \brief Number of decimal digits represented by \emph{long long}.
#define LLONG_DIG 0x12 #define LLONG_DIG 0x12
/// \brief Number of decimal digits necessary to differentiate all values of type \f$long long\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{long long}.
#define LLONG_DECIMAL_DIG 0x0 #define LLONG_DECIMAL_DIG 0
/// \brief The radix, or long longeger base, used to represent a \f$long long\f$. /// \brief The radix, or integer base, used to represent a \emph{long long}.
#define LLONG_RADIX 0x2 #define LLONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$long long\f$ trap? /// \brief Do arithmetics operations with \emph{long long} trap?
#define LLONG_TRAPS 0xtrue #define LLONG_TRAPS true
/// \brief Smallest finite value of \f$long long\f$. /// \brief Smallest finite value of \emph{long long}.
#define LLONG_MIN 0x8000000000000000 #define LLONG_MIN 0x8000000000000000
/// \brief Largest finite value of \f$long long\f$. /// \brief Largest finite value of \emph{long long}.
#define LLONG_MAX 0x7fffffffffffffff #define LLONG_MAX 0x7fffffffffffffff
/// \brief Rounding style of type \f$unsigned long long\f$. /// \brief Rounding style of type \emph{unsigned long long}.
#define ULLONG_ROUNDS 0x0 #define ULLONG_ROUNDS 0
/// \brief Number of radix digits represented by \f$unsigned long long\f$. /// \brief Number of radix digits represented by \emph{unsigned long long}.
#define ULLONG_RADIX_DIG 0x40 #define ULLONG_RADIX_DIG 0x40
/// \brief Number of decimal digits represented by \f$unsigned long long\f$. /// \brief Number of decimal digits represented by \emph{unsigned long long}.
#define ULLONG_DIG 0x13 #define ULLONG_DIG 0x13
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned long long\f$. /// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned long long}.
#define ULLONG_DECIMAL_DIG 0x0 #define ULLONG_DECIMAL_DIG 0
/// \brief The radix, or unsigned long longeger base, used to represent a \f$unsigned long long\f$. /// \brief The radix, or integer base, used to represent an \emph{unsigned long long}.
#define ULLONG_RADIX 0x2 #define ULLONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned long long\f$ trap? /// \brief Do arithmetics operations with \emph{unsigned long long} trap?
#define ULLONG_TRAPS 0xtrue #define ULLONG_TRAPS true
/// \brief Smallest finite value of \f$unsigned long long\f$. /// \brief Smallest finite value of \emph{unsigned long long}.
#define ULLONG_MIN 0x0 #define ULLONG_MIN 0
/// \brief Largest finite value of \f$unsigned long long\f$. /// \brief Largest finite value of \emph{unsigned long long}.
#define ULLONG_MAX 0xffffffffffffffff #define ULLONG_MAX 0xffffffffffffffff
#endif // FENNEC_LANG_INTEGER_H #endif // FENNEC_LANG_INTEGER_H

View File

@@ -40,59 +40,59 @@
/// <tr><th style="vertical-align: top">Syntax /// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description /// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_BIT_CAST\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_BIT_CAST} <br>
/// \f$Y FENNEC_BUILTIN_BIT_CAST(X)\f$ /// \emph{Y FENNEC_BUILTIN_BIT_CAST(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// An intrinsic for doing a bitwise cast without using \f$reinterpret_cast\f$. /// An intrinsic for doing a bitwise cast without using \emph{reinterpret_cast}.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_ADDRESSOF\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_ADDRESSOF} <br>
/// \f$Y FENNEC_BUILTIN_ADDRESSOF(X)\f$ /// \emph{Y FENNEC_BUILTIN_ADDRESSOF(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Obtains the true address of an object in circumstances where \f$operator&\f$ is overloaded. /// Obtains the true address of an object in circumstances where \emph{operator&} is overloaded.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_CONVERTIBLE\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_CONVERTIBLE} <br>
/// \f$B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)\f$ /// \emph{B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type \f$X\f$ can be converted to type \f$Y\f$. /// Checks if type \emph{X} can be converted to type \emph{Y}.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_EMPTY\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_EMPTY} <br>
/// \f$B FENNEC_BUILTIN_IS_EMPTY(X)\f$ /// \emph{B FENNEC_BUILTIN_IS_EMPTY(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type \f$X\f$ stores no data. /// Checks if type \emph{X} stores no data.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_POLYMORPHIC\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_POLYMORPHIC} <br>
/// \f$B FENNEC_BUILTIN_IS_POLYMORPHIC(X)\f$ /// \emph{B FENNEC_BUILTIN_IS_POLYMORPHIC(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type \f$X\f$ is polymorphic, this is for classes only thus checks only for subtyping /// Checks if type \emph{X} is polymorphic, this is for classes only thus checks only for subtyping
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_FINAL\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_FINAL} <br>
/// \f$B FENNEC_BUILTIN_IS_FINAL(X)\f$ /// \emph{B FENNEC_BUILTIN_IS_FINAL(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type \f$X\f$ is final, meaning a function or class cannot be derived from. /// Checks if type \emph{X} is final, meaning a function or class cannot be derived from.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_ABSTRACT\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_ABSTRACT} <br>
/// \f$B FENNEC_BUILTIN_IS_ABSTRACT(X)\f$ /// \emph{B FENNEC_BUILTIN_IS_ABSTRACT(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Opposite of \f$FENNEC_BUILTIN_IS_FINAL\f$, checks if abstract, meaning \f$X\f$ has at least one pure virtual function. /// Opposite of \emph{FENNEC_BUILTIN_IS_FINAL}, checks if abstract, meaning \emph{X} has at least one pure virtual function.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT} <br>
/// \f$B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)\f$ /// \emph{B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if \f$X\f$ has a standard layout, here is [full criteria](https://www.cppreference.com/w/cpp/language/classes.html#Standard-layout_class) /// Checks if \emph{X} has a standard layout, here is [full criteria](https://www.cppreference.com/w/cpp/language/classes.html#Standard-layout_class)
/// for this trait /// for this trait
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE\f$ <br> /// \emph{FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE} <br>
/// \f$B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)\f$ /// \emph{B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)}
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type \f$X\f$ is constructible with args \f$\ldots\f$, such that \f$X::X(...)\f$ exists. /// Checks if type \emph{X} is constructible with args \emph{\ldots}, such that \emph{X::X(...)} exists.
/// ///
/// </table> /// </table>
/// ///
@@ -242,8 +242,16 @@
// Difficult and Inconsistent without intrinsics // Difficult and Inconsistent without intrinsics
#if __has_builtin(__has_trivial_destructor) #if __has_builtin(__has_trivial_destructor)
# define FENNEC_HAS_BUILTIN_HAS_TRIVIAL_DESTRUCTOR 1
# define FENNEC_BUILTIN_HAS_TRIVIAL_DESTRUCTOR(type) __has_trivial_destructor(type)
#else
# define FENNEC_HAS_BUILTIN_HAS_TRIVIAL_DESTRUCTOR 0
#endif
// Difficult and Inconsistent without intrinsics
#if __has_builtin(__is_trivially_destructible)
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1 # define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1
# define FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __has_trivial_destructor(type) # define FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __is_trivially_destructible(type)
#else #else
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0 # define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0
#endif #endif

View File

@@ -231,7 +231,7 @@ template<typename TypeT> struct numeric_limits
static constexpr bool has_signaling_nan = false; //!< Check if TypeT can hold a signaling nan static constexpr bool has_signaling_nan = false; //!< Check if TypeT can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if TypeT denormalizes static constexpr bool has_denorm = false; //!< Check if TypeT denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if TypeT has precision loss when denormalized static constexpr bool has_denorm_loss = false; //!< Check if TypeT has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if a TypeT representing a float is IEC 559 or IEEE 754 static constexpr bool is_iec559 = false; //!< Check if TypeT represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = false; //!< Check if TypeT represents a finite set of values static constexpr bool is_bounded = false; //!< Check if TypeT represents a finite set of values
static constexpr bool is_modulo = false; //!< Check if TypeT can handle modulo arithmetic static constexpr bool is_modulo = false; //!< Check if TypeT can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if TypeT checks for tinyness before rounding static constexpr bool tinyness_before = false; //!< Check if TypeT checks for tinyness before rounding
@@ -260,500 +260,515 @@ template<typename TypeT> struct numeric_limits
static constexpr TypeT denorm_min() { return TypeT(); } //!< \returns a value of TypeT holding the smallest positive subnormal static constexpr TypeT denorm_min() { return TypeT(); } //!< \returns a value of TypeT holding the smallest positive subnormal
}; };
// Overload definitions for basic types
// Overload for the builtin floating point type // Overloads ===========================================================================================================
///
/// \brief Definition for type \emph{float}.
template<> struct numeric_limits<float> template<> struct numeric_limits<float>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for float
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if float is signed
static constexpr bool is_integer = false; static constexpr bool is_integer = false; //!< Check if float is of an integral type
static constexpr bool is_exact = false; static constexpr bool is_exact = false; //!< Check if float is exact in its precision
static constexpr bool has_infinity = FLT_HAS_INFINITY; static constexpr bool has_infinity = FLT_HAS_INFINITY; //!< Check if float can hold a value representing infinity
static constexpr bool has_quiet_nan = FLT_HAS_QUIET_NAN; static constexpr bool has_quiet_nan = FLT_HAS_QUIET_NAN; //!< Check if float can hold a non-signaling nan
static constexpr bool has_signaling_nan = FLT_HAS_SIGNALING_NAN; static constexpr bool has_signaling_nan = FLT_HAS_SIGNALING_NAN; //!< Check if float can hold a signaling nan
static constexpr bool has_denorm = FLT_HAS_DENORM; static constexpr bool has_denorm = FLT_HAS_DENORM; //!< Check if float denormalizes
static constexpr bool has_denorm_loss = FLT_HAS_DENORM_LOSS; static constexpr bool has_denorm_loss = FLT_HAS_DENORM_LOSS; //!< Check if float has precision loss when denormalized
static constexpr bool is_iec559 = FLT_IS_IEC559; static constexpr bool is_iec559 = FLT_IS_IEC559; //!< Check if float represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if float represents a finite set of values
static constexpr bool is_modulo = false; static constexpr bool is_modulo = false; //!< Check if float can handle modulo arithmetic
static constexpr bool tinyness_before = FLT_TINYNESS_BEFORE; static constexpr bool tinyness_before = FLT_TINYNESS_BEFORE; //!< Check if float checks for tinyness before rounding
static constexpr bool traps = FLT_TRAPS; static constexpr bool traps = FLT_TRAPS; //!< Check if float can cause operations to trap
static constexpr int digits = FLT_MANT_DIG; static constexpr int digits = FLT_MANT_DIG; //!< Get the base representation of the type
static constexpr int digits10 = FLT_DIG; static constexpr int digits10 = FLT_DIG; //!< Get the number of radix digits float represents
static constexpr int max_digits10 = FLT_DECIMAL_DIG; static constexpr int max_digits10 = FLT_DECIMAL_DIG; //!< Get the number of decimal digits float represents
static constexpr int radix = FLT_RADIX; static constexpr int radix = FLT_RADIX; //!< Get the maximum number of decimal digits float represents
static constexpr int min_exponent = FLT_MIN_EXP; static constexpr int min_exponent = FLT_MIN_EXP; //!< Get the minimum number of radix digits that represent the exponent of float
static constexpr int min_exponent10 = FLT_MIN_10_EXP; static constexpr int min_exponent10 = FLT_MIN_10_EXP; //!< Get the minimum number of decimal digits that represent the exponent of float
static constexpr int max_exponent = FLT_MAX_EXP; static constexpr int max_exponent = FLT_MAX_EXP; //!< Get the maximum number of radix digits that represent the exponent of float
static constexpr int max_exponent10 = FLT_MAX_10_EXP; static constexpr int max_exponent10 = FLT_MAX_10_EXP; //!< Get the maximum number of decimal digits that represent the exponent of float
static constexpr float min() { return -FLT_MAX; } static constexpr float min() { return -FLT_MAX; } //!< \returns the minimum finite value of float
static constexpr float max() { return FLT_MAX; } static constexpr float max() { return FLT_MAX; } //!< \returns the maximum finite value of float
static constexpr float lowest() { return FLT_MIN; } static constexpr float lowest() { return FLT_MIN; } //!< \returns the smallest positive value of float
static constexpr float epsilon() { return FLT_EPSILON; } static constexpr float epsilon() { return FLT_EPSILON; } //!< \returns the difference between 1.0 and the next representable value
static constexpr float round_error() { return FLT_ROUND_ERR; } static constexpr float round_error() { return FLT_ROUND_ERR; } //!< \returns the max rounding error of float
static constexpr float infinity() { return FLT_INF; } static constexpr float infinity() { return FLT_INF; } //!< \returns a value of float holding a positive infinity
static constexpr float quiet_NaN() { return FLT_QUIET_NAN; } static constexpr float quiet_NaN() { return FLT_QUIET_NAN; } //!< \returns a value of float holding a quiet NaN
static constexpr float signaling_NaN() { return FLT_SIGNALING_NAN; } static constexpr float signaling_NaN() { return FLT_SIGNALING_NAN; } //!< \returns a value of float holding a signaling NaN
static constexpr float denorm_min() { return FLT_DENORM_MIN; } static constexpr float denorm_min() { return FLT_DENORM_MIN; } //!< \returns a value of float holding the smallest positive subnormal
}; };
// Overload for the bultin double precision floating point type
///
/// \brief Definition for type \emph{double}.
template<> struct numeric_limits<double> template<> struct numeric_limits<double>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for double
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if double is signed
static constexpr bool is_integer = false; static constexpr bool is_integer = false; //!< Check if double is of an integral type
static constexpr bool is_exact = false; static constexpr bool is_exact = false; //!< Check if double is exact in its precision
static constexpr bool has_infinity = DBL_HAS_INFINITY; static constexpr bool has_infinity = DBL_HAS_INFINITY; //!< Check if double can hold a value representing infinity
static constexpr bool has_quiet_nan = DBL_HAS_QUIET_NAN; static constexpr bool has_quiet_nan = DBL_HAS_QUIET_NAN; //!< Check if double can hold a non-signaling nan
static constexpr bool has_signaling_nan = DBL_HAS_SIGNALING_NAN; static constexpr bool has_signaling_nan = DBL_HAS_SIGNALING_NAN; //!< Check if double can hold a signaling nan
static constexpr bool has_denorm = DBL_HAS_DENORM; static constexpr bool has_denorm = DBL_HAS_DENORM; //!< Check if double denormalizes
static constexpr bool has_denorm_loss = DBL_HAS_DENORM_LOSS; static constexpr bool has_denorm_loss = DBL_HAS_DENORM_LOSS; //!< Check if double has precision loss when denormalized
static constexpr bool is_iec559 = DBL_IS_IEC559; static constexpr bool is_iec559 = DBL_IS_IEC559; //!< Check if double represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if double represents a finite set of values
static constexpr bool is_modulo = false; static constexpr bool is_modulo = false; //!< Check if double can handle modulo arithmetic
static constexpr bool tinyness_before = DBL_TINYNESS_BEFORE; static constexpr bool tinyness_before = DBL_TINYNESS_BEFORE; //!< Check if double checks for tinyness before rounding
static constexpr bool traps = DBL_TRAPS; static constexpr bool traps = DBL_TRAPS; //!< Check if double can cause operations to trap
static constexpr int digits = DBL_MANT_DIG; static constexpr int digits = DBL_MANT_DIG; //!< Get the base representation of the type
static constexpr int digits10 = DBL_DIG; static constexpr int digits10 = DBL_DIG; //!< Get the number of radix digits double represents
static constexpr int max_digits10 = DBL_DECIMAL_DIG; static constexpr int max_digits10 = DBL_DECIMAL_DIG; //!< Get the number of decimal digits double represents
static constexpr int radix = DBL_RADIX; static constexpr int radix = DBL_RADIX; //!< Get the maximum number of decimal digits double represents
static constexpr int min_exponent = DBL_MIN_EXP; static constexpr int min_exponent = DBL_MIN_EXP; //!< Get the minimum number of radix digits that represent the exponent of double
static constexpr int min_exponent10 = DBL_MIN_10_EXP; static constexpr int min_exponent10 = DBL_MIN_10_EXP; //!< Get the minimum number of decimal digits that represent the exponent of double
static constexpr int max_exponent = DBL_MAX_EXP; static constexpr int max_exponent = DBL_MAX_EXP; //!< Get the maximum number of radix digits that represent the exponent of double
static constexpr int max_exponent10 = DBL_MAX_10_EXP; static constexpr int max_exponent10 = DBL_MAX_10_EXP; //!< Get the maximum number of decimal digits that represent the exponent of double
static constexpr double min() { return -DBL_MAX; } static constexpr double min() { return -DBL_MAX; } //!< \returns the minimum finite value of double
static constexpr double max() { return DBL_MAX; } static constexpr double max() { return DBL_MAX; } //!< \returns the maximum finite value of double
static constexpr double lowest() { return DBL_MIN; } static constexpr double lowest() { return DBL_MIN; } //!< \returns the smallest positive value of double
static constexpr double epsilon() { return DBL_EPSILON; } static constexpr double epsilon() { return DBL_EPSILON; } //!< \returns the difference between 1.0 and the next representable value
static constexpr double round_error() { return DBL_ROUND_ERR; } static constexpr double round_error() { return DBL_ROUND_ERR; } //!< \returns the max rounding error of double
static constexpr double infinity() { return DBL_INF; } static constexpr double infinity() { return DBL_INF; } //!< \returns a value of double holding a positive infinity
static constexpr double quiet_NaN() { return DBL_QUIET_NAN; } static constexpr double quiet_NaN() { return DBL_QUIET_NAN; } //!< \returns a value of double holding a quiet NaN
static constexpr double signaling_NaN() { return DBL_SIGNALING_NAN; } static constexpr double signaling_NaN() { return DBL_SIGNALING_NAN; } //!< \returns a value of double holding a signaling NaN
static constexpr double denorm_min() { return DBL_DENORM_MIN; } static constexpr double denorm_min() { return DBL_DENORM_MIN; } //!< \returns a value of double holding the smallest positive subnormal
}; };
// Overload for the builtin char type ///
/// \brief Definition for type \emph{char}.
template<> struct numeric_limits<char> template<> struct numeric_limits<char>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for char
static constexpr bool is_signed = CHAR_IS_SIGNED; static constexpr bool is_signed = CHAR_IS_SIGNED; //!< Check if char is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if char is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if char is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if char can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if char can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if char can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if char denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if char has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if char represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if char represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if char can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if char checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if char can cause operations to trap
static constexpr int digits = CHAR_RADIX_DIG; static constexpr int digits = CHAR_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = CHAR_DIG; static constexpr int digits10 = CHAR_DIG; //!< Get the number of radix digits char represents
static constexpr int max_digits10 = CHAR_DECIMAL_DIG; static constexpr int max_digits10 = CHAR_DECIMAL_DIG; //!< Get the number of decimal digits char represents
static constexpr int radix = CHAR_RADIX; static constexpr int radix = CHAR_RADIX; //!< Get the maximum number of decimal digits char represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of char
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of char
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of char
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of char
static constexpr char min() { return static_cast<char>(CHAR_MIN); } static constexpr char min() { return CHAR_MIN; } //!< \returns the minimum finite value of char
static constexpr char max() { return CHAR_MAX; } static constexpr char max() { return CHAR_MAX; } //!< \returns the maximum finite value of char
static constexpr char lowest() { return 1; } static constexpr char lowest() { return 1; } //!< \returns the smallest positive value of char
static constexpr char epsilon() { return 1; } static constexpr char epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr char round_error() { return 0; } static constexpr char round_error() { return 0; } //!< \returns the max rounding error of char
static constexpr char infinity() { return 0; } static constexpr char infinity() { return 0; } //!< \returns a value of char holding a positive infinity
static constexpr char quiet_NaN() { return 0; } static constexpr char quiet_NaN() { return 0; } //!< \returns a value of char holding a quiet NaN
static constexpr char signaling_NaN() { return 0; } static constexpr char signaling_NaN() { return 0; } //!< \returns a value of char holding a signaling NaN
static constexpr char denorm_min() { return 0; } static constexpr char denorm_min() { return 0; } //!< \returns a value of char holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{signed char}.
template<> struct numeric_limits<signed char> template<> struct numeric_limits<signed char>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for signed char
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if signed char is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if signed char is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if signed char is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if signed char can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if signed char can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if signed char can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if signed char denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if signed char has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if signed char represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if signed char represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if signed char can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if signed char checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if signed char can cause operations to trap
static constexpr int digits = SCHAR_RADIX_DIG; static constexpr int digits = SCHAR_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = SCHAR_DIG; static constexpr int digits10 = SCHAR_DIG; //!< Get the number of radix digits signed char represents
static constexpr int max_digits10 = SCHAR_DECIMAL_DIG; static constexpr int max_digits10 = SCHAR_DECIMAL_DIG; //!< Get the number of decimal digits signed char represents
static constexpr int radix = SCHAR_RADIX; static constexpr int radix = SCHAR_RADIX; //!< Get the maximum number of decimal digits signed char represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of signed char
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of signed char
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of signed char
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of signed char
static constexpr signed char min() { return static_cast<signed char>(SCHAR_MIN); } static constexpr signed char min() { return SCHAR_MIN; } //!< \returns the minimum finite value of signed char
static constexpr signed char max() { return SCHAR_MAX; } static constexpr signed char max() { return SCHAR_MAX; } //!< \returns the maximum finite value of signed char
static constexpr signed char lowest() { return 1; } static constexpr signed char lowest() { return 1; } //!< \returns the smallest positive value of signed char
static constexpr signed char epsilon() { return 1; } static constexpr signed char epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr signed char round_error() { return 0; } static constexpr signed char round_error() { return 0; } //!< \returns the max rounding error of signed char
static constexpr signed char infinity() { return 0; } static constexpr signed char infinity() { return 0; } //!< \returns a value of signed char holding a positive infinity
static constexpr signed char quiet_NaN() { return 0; } static constexpr signed char quiet_NaN() { return 0; } //!< \returns a value of signed char holding a quiet NaN
static constexpr signed char signaling_NaN() { return 0; } static constexpr signed char signaling_NaN() { return 0; } //!< \returns a value of signed char holding a signaling NaN
static constexpr signed char denorm_min() { return 0; } static constexpr signed char denorm_min() { return 0; } //!< \returns a value of signed char holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{unsigned char}.
template<> struct numeric_limits<unsigned char> template<> struct numeric_limits<unsigned char>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned char
static constexpr bool is_signed = false; static constexpr bool is_signed = false; //!< Check if unsigned char is unsigned
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if unsigned char is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if unsigned char is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if unsigned char can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if unsigned char can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if unsigned char can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if unsigned char denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if unsigned char has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if unsigned char represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if unsigned char represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if unsigned char can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if unsigned char checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if unsigned char can cause operations to trap
static constexpr int digits = UCHAR_RADIX_DIG; static constexpr int digits = UCHAR_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = UCHAR_DIG; static constexpr int digits10 = UCHAR_DIG; //!< Get the number of radix digits unsigned char represents
static constexpr int max_digits10 = UCHAR_DECIMAL_DIG; static constexpr int max_digits10 = UCHAR_DECIMAL_DIG; //!< Get the number of decimal digits unsigned char represents
static constexpr int radix = UCHAR_RADIX; static constexpr int radix = UCHAR_RADIX; //!< Get the maximum number of decimal digits unsigned char represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of unsigned char
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of unsigned char
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of unsigned char
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of unsigned char
static constexpr unsigned char min() { return UCHAR_MIN; } static constexpr unsigned char min() { return UCHAR_MIN; } //!< \returns the minimum finite value of unsigned char
static constexpr unsigned char max() { return UCHAR_MAX; } static constexpr unsigned char max() { return UCHAR_MAX; } //!< \returns the maximum finite value of unsigned char
static constexpr unsigned char lowest() { return 1; } static constexpr unsigned char lowest() { return 1; } //!< \returns the smallest positive value of unsigned char
static constexpr unsigned char epsilon() { return 1; } static constexpr unsigned char epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr unsigned char round_error() { return 0; } static constexpr unsigned char round_error() { return 0; } //!< \returns the max rounding error of unsigned char
static constexpr unsigned char infinity() { return 0; } static constexpr unsigned char infinity() { return 0; } //!< \returns a value of unsigned char holding a positive infinity
static constexpr unsigned char quiet_NaN() { return 0; } static constexpr unsigned char quiet_NaN() { return 0; } //!< \returns a value of unsigned char holding a quiet NaN
static constexpr unsigned char signaling_NaN() { return 0; } static constexpr unsigned char signaling_NaN() { return 0; } //!< \returns a value of unsigned char holding a signaling NaN
static constexpr unsigned char denorm_min() { return 0; } static constexpr unsigned char denorm_min() { return 0; } //!< \returns a value of unsigned char holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{short}.
template<> struct numeric_limits<short> template<> struct numeric_limits<short>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for short
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if short is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if short is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if short is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if short can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if short can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if short can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if short denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if short has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if short represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if short represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if short can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if short checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if short can cause operations to trap
static constexpr int digits = SHORT_RADIX_DIG; static constexpr int digits = SHORT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = SHORT_DIG; static constexpr int digits10 = SHORT_DIG; //!< Get the number of radix digits short represents
static constexpr int max_digits10 = SHORT_DECIMAL_DIG; static constexpr int max_digits10 = SHORT_DECIMAL_DIG; //!< Get the number of decimal digits short represents
static constexpr int radix = SHORT_RADIX; static constexpr int radix = SHORT_RADIX; //!< Get the maximum number of decimal digits short represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of short
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of short
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of short
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of short
static constexpr short min() { return static_cast<short>(SHORT_MIN); } static constexpr short min() { return static_cast<short>(SHORT_MIN); } //!< \returns the minimum finite value of short
static constexpr short max() { return SHORT_MAX; } static constexpr short max() { return SHORT_MAX; } //!< \returns the maximum finite value of short
static constexpr short lowest() { return 1; } static constexpr short lowest() { return 1; } //!< \returns the smallest positive value of short
static constexpr short epsilon() { return 1; } static constexpr short epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr short round_error() { return 0; } static constexpr short round_error() { return 0; } //!< \returns the max rounding error of short
static constexpr short infinity() { return 0; } static constexpr short infinity() { return 0; } //!< \returns a value of short holding a positive infinity
static constexpr short quiet_NaN() { return 0; } static constexpr short quiet_NaN() { return 0; } //!< \returns a value of short holding a quiet NaN
static constexpr short signaling_NaN() { return 0; } static constexpr short signaling_NaN() { return 0; } //!< \returns a value of short holding a signaling NaN
static constexpr short denorm_min() { return 0; } static constexpr short denorm_min() { return 0; } //!< \returns a value of short holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{unsigned short}.
template<> struct numeric_limits<unsigned short> template<> struct numeric_limits<unsigned short>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for signed short
static constexpr bool is_signed = false; static constexpr bool is_signed = false; //!< Check if unsigned short is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if unsigned short is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if unsigned short is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if unsigned short can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if unsigned short can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if unsigned short can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if unsigned short denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if unsigned short has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if unsigned short represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if unsigned short represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if unsigned short can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if unsigned short checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if unsigned short can cause operations to trap
static constexpr int digits = USHORT_RADIX_DIG; static constexpr int digits = USHORT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = USHORT_DIG; static constexpr int digits10 = USHORT_DIG; //!< Get the number of radix digits unsigned short represents
static constexpr int max_digits10 = USHORT_DECIMAL_DIG; static constexpr int max_digits10 = USHORT_DECIMAL_DIG; //!< Get the number of decimal digits unsigned short represents
static constexpr int radix = USHORT_RADIX; static constexpr int radix = USHORT_RADIX; //!< Get the maximum number of decimal digits unsigned short represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of unsigned short
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of unsigned short
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of unsigned short
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of unsigned short
static constexpr unsigned short min() { return USHORT_MIN; } static constexpr unsigned short min() { return USHORT_MIN; } //!< \returns the minimum finite value of unsigned short
static constexpr unsigned short max() { return USHORT_MAX; } static constexpr unsigned short max() { return USHORT_MAX; } //!< \returns the maximum finite value of unsigned short
static constexpr unsigned short lowest() { return 1; } static constexpr unsigned short lowest() { return 1; } //!< \returns the smallest positive value of unsigned short
static constexpr unsigned short epsilon() { return 1; } static constexpr unsigned short epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr unsigned short round_error() { return 0; } static constexpr unsigned short round_error() { return 0; } //!< \returns the max rounding error of unsigned short
static constexpr unsigned short infinity() { return 0; } static constexpr unsigned short infinity() { return 0; } //!< \returns a value of unsigned short holding a positive infinity
static constexpr unsigned short quiet_NaN() { return 0; } static constexpr unsigned short quiet_NaN() { return 0; } //!< \returns a value of unsigned short holding a quiet NaN
static constexpr unsigned short signaling_NaN() { return 0; } static constexpr unsigned short signaling_NaN() { return 0; } //!< \returns a value of unsigned short holding a signaling NaN
static constexpr unsigned short denorm_min() { return 0; } static constexpr unsigned short denorm_min() { return 0; } //!< \returns a value of unsigned short holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{int}.
template<> struct numeric_limits<int> template<> struct numeric_limits<int>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for int
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if int is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if int is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if int is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if int can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if int denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if int has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if int represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if int can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if int checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if int can cause operations to trap
static constexpr int digits = INT_RADIX_DIG; static constexpr int digits = INT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = INT_DIG; static constexpr int digits10 = INT_DIG; //!< Get the number of radix digits int represents
static constexpr int max_digits10 = INT_DECIMAL_DIG; static constexpr int max_digits10 = INT_DECIMAL_DIG; //!< Get the number of decimal digits int represents
static constexpr int radix = INT_RADIX; static constexpr int radix = INT_RADIX; //!< Get the maximum number of decimal digits int represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of int
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of int
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of int
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of int
static constexpr int min() { return INT_MIN; } static constexpr int min() { return INT_MIN; } //!< \returns the minimum finite value of int
static constexpr int max() { return INT_MAX; } static constexpr int max() { return INT_MAX; } //!< \returns the maximum finite value of int
static constexpr int lowest() { return 1; } static constexpr int lowest() { return 1; } //!< \returns the smallest positive value of int
static constexpr int epsilon() { return 1; } static constexpr int epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr int round_error() { return 0; } static constexpr int round_error() { return 0; } //!< \returns the max rounding error of int
static constexpr int infinity() { return 0; } static constexpr int infinity() { return 0; } //!< \returns a value of int holding a positive infinity
static constexpr int quiet_NaN() { return 0; } static constexpr int quiet_NaN() { return 0; } //!< \returns a value of int holding a quiet NaN
static constexpr int signaling_NaN() { return 0; } static constexpr int signaling_NaN() { return 0; } //!< \returns a value of int holding a signaling NaN
static constexpr int denorm_min() { return 0; } static constexpr int denorm_min() { return 0; } //!< \returns a value of int holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{unsigned int}.
template<> struct numeric_limits<unsigned int> template<> struct numeric_limits<unsigned int>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned int
static constexpr bool is_signed = false; static constexpr bool is_signed = false; //!< Check if unsigned int is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if unsigned int is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if unsigned int is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if unsigned int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if unsigned int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if unsigned int can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if unsigned int denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if unsigned int has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if unsigned int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if unsigned int represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if unsigned int can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if unsigned int checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if unsigned int can cause operations to trap
static constexpr int digits = UINT_RADIX_DIG; static constexpr int digits = UINT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = UINT_DIG; static constexpr int digits10 = UINT_DIG; //!< Get the number of radix digits unsigned int represents
static constexpr int max_digits10 = UINT_DECIMAL_DIG; static constexpr int max_digits10 = UINT_DECIMAL_DIG; //!< Get the number of decimal digits unsigned int represents
static constexpr int radix = UINT_RADIX; static constexpr int radix = UINT_RADIX; //!< Get the maximum number of decimal digits unsigned int represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of unsigned int
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of unsigned int
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of unsigned int
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of unsigned int
static constexpr unsigned int min() { return UINT_MIN; } static constexpr unsigned int min() { return UINT_MIN; } //!< \returns the minimum finite value of unsigned int
static constexpr unsigned int max() { return UINT_MAX; } static constexpr unsigned int max() { return UINT_MAX; } //!< \returns the maximum finite value of unsigned int
static constexpr unsigned int lowest() { return 1; } static constexpr unsigned int lowest() { return 1; } //!< \returns the smallest positive value of unsigned int
static constexpr unsigned int epsilon() { return 1; } static constexpr unsigned int epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr unsigned int round_error() { return 0; } static constexpr unsigned int round_error() { return 0; } //!< \returns the max rounding error of unsigned int
static constexpr unsigned int infinity() { return 0; } static constexpr unsigned int infinity() { return 0; } //!< \returns a value of unsigned int holding a positive infinity
static constexpr unsigned int quiet_NaN() { return 0; } static constexpr unsigned int quiet_NaN() { return 0; } //!< \returns a value of unsigned int holding a quiet NaN
static constexpr unsigned int signaling_NaN() { return 0; } static constexpr unsigned int signaling_NaN() { return 0; } //!< \returns a value of unsigned int holding a signaling NaN
static constexpr unsigned int denorm_min() { return 0; } static constexpr unsigned int denorm_min() { return 0; } //!< \returns a value of unsigned int holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{long int}.
template<> struct numeric_limits<long int> template<> struct numeric_limits<long int>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for long int
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if long int is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if long int is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if long int is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if long int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if long int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if long int can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if long int denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if long int has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if long int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if long int represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if long int can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if long int checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if long int can cause operations to trap
static constexpr int digits = LONG_RADIX_DIG; static constexpr int digits = LONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = LONG_DIG; static constexpr int digits10 = LONG_DIG; //!< Get the number of radix digits long int represents
static constexpr int max_digits10 = LONG_DECIMAL_DIG; static constexpr int max_digits10 = LONG_DECIMAL_DIG; //!< Get the number of decimal digits long int represents
static constexpr int radix = LONG_RADIX; static constexpr int radix = LONG_RADIX; //!< Get the maximum number of decimal digits long int represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of long int
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of long int
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of long int
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of long int
static constexpr long int min() { return LONG_MIN; } static constexpr long int min() { return LONG_MIN; } //!< \returns the minimum finite value of long int
static constexpr long int max() { return LONG_MAX; } static constexpr long int max() { return LONG_MAX; } //!< \returns the maximum finite value of long int
static constexpr long int lowest() { return 1; } static constexpr long int lowest() { return 1; } //!< \returns the smallest positive value of long int
static constexpr long int epsilon() { return 1; } static constexpr long int epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr long int round_error() { return 0; } static constexpr long int round_error() { return 0; } //!< \returns the max rounding error of long int
static constexpr long int infinity() { return 0; } static constexpr long int infinity() { return 0; } //!< \returns a value of long int holding a positive infinity
static constexpr long int quiet_NaN() { return 0; } static constexpr long int quiet_NaN() { return 0; } //!< \returns a value of long int holding a quiet NaN
static constexpr long int signaling_NaN() { return 0; } static constexpr long int signaling_NaN() { return 0; } //!< \returns a value of long int holding a signaling NaN
static constexpr long int denorm_min() { return 0; } static constexpr long int denorm_min() { return 0; } //!< \returns a value of long int holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{unsigned long int}.
template<> struct numeric_limits<unsigned long int> template<> struct numeric_limits<unsigned long int>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned long int
static constexpr bool is_signed = false; static constexpr bool is_signed = false; //!< Check if unsigned long int is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if unsigned long int is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if unsigned long int is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if unsigned long int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if unsigned long int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if unsigned long int can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if unsigned long int denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if unsigned long int has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if unsigned long int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if unsigned long int represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if unsigned long int can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if unsigned long int checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if unsigned long int can cause operations to trap
static constexpr int digits = ULONG_RADIX_DIG; static constexpr int digits = ULONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = ULONG_DIG; static constexpr int digits10 = ULONG_DIG; //!< Get the number of radix digits unsigned long int represents
static constexpr int max_digits10 = ULONG_DECIMAL_DIG; static constexpr int max_digits10 = ULONG_DECIMAL_DIG; //!< Get the number of decimal digits unsigned long int represents
static constexpr int radix = ULONG_RADIX; static constexpr int radix = ULONG_RADIX; //!< Get the maximum number of decimal digits unsigned long int represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of unsigned long int
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of unsigned long int
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of unsigned long int
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of unsigned long int
static constexpr unsigned long min() { return ULONG_MIN; } static constexpr unsigned long min() { return ULONG_MIN; } //!< \returns the minimum finite value of unsigned long int
static constexpr unsigned long max() { return ULONG_MAX; } static constexpr unsigned long max() { return ULONG_MAX; } //!< \returns the maximum finite value of unsigned long int
static constexpr unsigned long lowest() { return 1; } static constexpr unsigned long lowest() { return 1; } //!< \returns the smallest positive value of unsigned long int
static constexpr unsigned long epsilon() { return 1; } static constexpr unsigned long epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr unsigned long round_error() { return 0; } static constexpr unsigned long round_error() { return 0; } //!< \returns the max rounding error of unsigned long int
static constexpr unsigned long infinity() { return 0; } static constexpr unsigned long infinity() { return 0; } //!< \returns a value of unsigned long int holding a positive infinity
static constexpr unsigned long quiet_NaN() { return 0; } static constexpr unsigned long quiet_NaN() { return 0; } //!< \returns a value of unsigned long int holding a quiet NaN
static constexpr unsigned long signaling_NaN() { return 0; } static constexpr unsigned long signaling_NaN() { return 0; } //!< \returns a value of unsigned long int holding a signaling NaN
static constexpr unsigned long denorm_min() { return 0; } static constexpr unsigned long denorm_min() { return 0; } //!< \returns a value of unsigned long int holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{long long}.
template<> struct numeric_limits<long long> template<> struct numeric_limits<long long>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for long long
static constexpr bool is_signed = true; static constexpr bool is_signed = true; //!< Check if long long is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if long long is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if long long is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if long long can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if long long can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if long long can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if long long denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if long long has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if long long represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if long long represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if long long can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if long long checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if long long can cause operations to trap
static constexpr int digits = LLONG_RADIX_DIG; static constexpr int digits = LLONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = LLONG_DIG; static constexpr int digits10 = LLONG_DIG; //!< Get the number of radix digits long long represents
static constexpr int max_digits10 = LLONG_DECIMAL_DIG; static constexpr int max_digits10 = LLONG_DECIMAL_DIG; //!< Get the number of decimal digits long long represents
static constexpr int radix = LLONG_RADIX; static constexpr int radix = LLONG_RADIX; //!< Get the maximum number of decimal digits long long represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of long long
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of long long
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of long long
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of long long
static constexpr long long min() { return LLONG_MIN; } static constexpr long long min() { return LLONG_MIN; } //!< \returns the minimum finite value of long long
static constexpr long long max() { return LLONG_MAX; } static constexpr long long max() { return LLONG_MAX; } //!< \returns the maximum finite value of long long
static constexpr long long lowest() { return 1; } static constexpr long long lowest() { return 1; } //!< \returns the smallest positive value of long long
static constexpr long long epsilon() { return 1; } static constexpr long long epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr long long round_error() { return 0; } static constexpr long long round_error() { return 0; } //!< \returns the max rounding error of long long
static constexpr long long infinity() { return 0; } static constexpr long long infinity() { return 0; } //!< \returns a value of long long holding a positive infinity
static constexpr long long quiet_NaN() { return 0; } static constexpr long long quiet_NaN() { return 0; } //!< \returns a value of long long holding a quiet NaN
static constexpr long long signaling_NaN() { return 0; } static constexpr long long signaling_NaN() { return 0; } //!< \returns a value of long long holding a signaling NaN
static constexpr long long denorm_min() { return 0; } static constexpr long long denorm_min() { return 0; } //!< \returns a value of long long holding the smallest positive subnormal
}; };
// Overload for the builtin signed char type ///
/// \brief Definition for type \emph{unsigned long long}.
template<> struct numeric_limits<unsigned long long> template<> struct numeric_limits<unsigned long long>
{ {
static constexpr bool is_specialized = true; static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned long long
static constexpr bool is_signed = false; static constexpr bool is_signed = false; //!< Check if unsigned long long is signed
static constexpr bool is_integer = true; static constexpr bool is_integer = true; //!< Check if unsigned long long is of an integral type
static constexpr bool is_exact = true; static constexpr bool is_exact = true; //!< Check if unsigned long long is exact in its precision
static constexpr bool has_infinity = false; static constexpr bool has_infinity = false; //!< Check if unsigned long long can hold a value representing infinity
static constexpr bool has_quiet_nan = false; static constexpr bool has_quiet_nan = false; //!< Check if unsigned long long can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; static constexpr bool has_signaling_nan = false; //!< Check if unsigned long long can hold a signaling nan
static constexpr bool has_denorm = false; static constexpr bool has_denorm = false; //!< Check if unsigned long long denormalizes
static constexpr bool has_denorm_loss = false; static constexpr bool has_denorm_loss = false; //!< Check if unsigned long long has precision loss when denormalized
static constexpr bool is_iec559 = false; static constexpr bool is_iec559 = false; //!< Check if unsigned long long represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; static constexpr bool is_bounded = true; //!< Check if unsigned long long represents a finite set of values
static constexpr bool is_modulo = true; static constexpr bool is_modulo = true; //!< Check if unsigned long long can handle modulo arithmetic
static constexpr bool tinyness_before = false; static constexpr bool tinyness_before = false; //!< Check if unsigned long long checks for tinyness before rounding
static constexpr bool traps = true; static constexpr bool traps = true; //!< Check if unsigned long long can cause operations to trap
static constexpr int digits = ULLONG_RADIX_DIG; static constexpr int digits = ULLONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = ULLONG_DIG; static constexpr int digits10 = ULLONG_DIG; //!< Get the number of radix digits unsigned long long represents
static constexpr int max_digits10 = ULLONG_DECIMAL_DIG; static constexpr int max_digits10 = ULLONG_DECIMAL_DIG; //!< Get the number of decimal digits unsigned long long represents
static constexpr int radix = ULLONG_RADIX; static constexpr int radix = ULLONG_RADIX; //!< Get the maximum number of decimal digits unsigned long long represents
static constexpr int min_exponent = 0; static constexpr int min_exponent = 0; //!< Get the minimum number of radix digits that represent the exponent of unsigned long long
static constexpr int min_exponent10 = 0; static constexpr int min_exponent10 = 0; //!< Get the minimum number of decimal digits that represent the exponent of unsigned long long
static constexpr int max_exponent = 0; static constexpr int max_exponent = 0; //!< Get the maximum number of radix digits that represent the exponent of unsigned long long
static constexpr int max_exponent10 = 0; static constexpr int max_exponent10 = 0; //!< Get the maximum number of decimal digits that represent the exponent of unsigned long long
static constexpr unsigned long long min() { return ULLONG_MIN; } static constexpr unsigned long long min() { return ULLONG_MIN; } //!< \returns the minimum finite value of unsigned long long
static constexpr unsigned long long max() { return ULLONG_MAX; } static constexpr unsigned long long max() { return ULLONG_MAX; } //!< \returns the maximum finite value of unsigned long long
static constexpr unsigned long long lowest() { return 1; } static constexpr unsigned long long lowest() { return 1; } //!< \returns the smallest positive value of unsigned long long
static constexpr unsigned long long epsilon() { return 1; } static constexpr unsigned long long epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr unsigned long long round_error() { return 0; } static constexpr unsigned long long round_error() { return 0; } //!< \returns the max rounding error of unsigned long long
static constexpr unsigned long long infinity() { return 0; } static constexpr unsigned long long infinity() { return 0; } //!< \returns a value of unsigned long long holding a positive infinity
static constexpr unsigned long long quiet_NaN() { return 0; } static constexpr unsigned long long quiet_NaN() { return 0; } //!< \returns a value of unsigned long long holding a quiet NaN
static constexpr unsigned long long signaling_NaN() { return 0; } static constexpr unsigned long long signaling_NaN() { return 0; } //!< \returns a value of unsigned long long holding a signaling NaN
static constexpr unsigned long long denorm_min() { return 0; } static constexpr unsigned long long denorm_min() { return 0; } //!< \returns a value of unsigned long long holding the smallest positive subnormal
}; };
} }

View File

@@ -80,7 +80,7 @@ namespace fennec
/// ///
/// \brief metaprogramming sequence /// \brief metaprogramming sequence
/// ///
/// \details Stores a sequence of values of type \f$ValueT\f$ as a template pack. /// \details Stores a sequence of values of type \emph{ValueT} as a template pack.
/// You can access the parameter pack in another template function, i.e. /// You can access the parameter pack in another template function, i.e.
/// \code{cpp} /// \code{cpp}
/// template<typename TypeT, TypeT...Values> /// template<typename TypeT, TypeT...Values>
@@ -138,7 +138,7 @@ struct integer_metasequence : metasequence<IntT, Values...>
/// ///
/// \brief generate a fennec::integer_metasequence \f$\left[\,0\,\ldots\,N\,\right)\f$ /// \brief generate a fennec::integer_metasequence \math{\left[\,0\,\ldots\,N\,\right)}
/// ///
/// \details /// \details
/// \tparam IntT type of the values, must satisfy `fennec::is_integral<T>` /// \tparam IntT type of the values, must satisfy `fennec::is_integral<T>`
@@ -177,7 +177,7 @@ template<size_t...Indices> struct index_metasequence : integer_metasequence<size
/// ///
/// \brief generate a fennec::index_metasequence \f$\left[\,0\,\ldots\,N\,\right)\f$ /// \brief generate a fennec::index_metasequence \math{\left[\,0\,\ldots\,N\,\right)}
/// ///
/// \details /// \details
/// \tparam T type of the values, must satisfy `fennec::is_integral<T>` /// \tparam T type of the values, must satisfy `fennec::is_integral<T>`

View File

@@ -32,12 +32,13 @@
#define FENNEC_LANG_RANGES_H #define FENNEC_LANG_RANGES_H
#include <fennec/lang/types.h> #include <fennec/lang/types.h>
#include <fennec/lang/type_traits.h>
namespace fennec namespace fennec
{ {
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \tparam ContainerT the container type /// \tparam ContainerT the container type
/// \param c the container to iterate on /// \param c the container to iterate on
/// \returns an iterator at the start of the container /// \returns an iterator at the start of the container
@@ -47,7 +48,7 @@ inline constexpr auto begin(ContainerT& c) noexcept(noexcept(c.begin())) -> decl
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \tparam ContainerT the container type /// \tparam ContainerT the container type
/// \param c the container to iterate on /// \param c the container to iterate on
/// \returns an iterator at the start of the container /// \returns an iterator at the start of the container
@@ -57,7 +58,7 @@ inline constexpr auto begin(const ContainerT& c) noexcept(noexcept(c.begin())) -
} }
/// ///
/// \brief C++ Iterator Specification \f$begin()\f$ /// \brief C++ Iterator Specification \emph{begin()}
/// \tparam T the element type /// \tparam T the element type
/// \tparam N the bounds of the array /// \tparam N the bounds of the array
/// \param arr a bounded array to iterate on /// \param arr a bounded array to iterate on
@@ -69,7 +70,7 @@ inline constexpr T* begin(T (&arr)[N]) noexcept {
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \tparam ContainerT the container type /// \tparam ContainerT the container type
/// \param c the container to iterate on /// \param c the container to iterate on
/// \returns an iterator at the end of the container /// \returns an iterator at the end of the container
@@ -79,7 +80,7 @@ inline constexpr auto end(ContainerT& c) noexcept(noexcept(c.end())) -> decltype
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \tparam ContainerT the container type /// \tparam ContainerT the container type
/// \param c the container to iterate on /// \param c the container to iterate on
/// \returns an iterator at the end of the container /// \returns an iterator at the end of the container
@@ -89,7 +90,7 @@ inline constexpr auto end(const ContainerT& c) noexcept(noexcept(c.end())) -> de
} }
/// ///
/// \brief C++ Iterator Specification \f$end()\f$ /// \brief C++ Iterator Specification \emph{end()}
/// \tparam T the element type /// \tparam T the element type
/// \tparam N the bounds of the array /// \tparam N the bounds of the array
/// \param arr a bounded array to iterate on /// \param arr a bounded array to iterate on
@@ -99,6 +100,129 @@ inline constexpr T* end(T (&arr)[N]) noexcept {
return arr + N; return arr + N;
} }
///
/// \brief Range for array types.
/// \tparam TypeT The base type.
///
/// \note Operates on the range \emph{[first, last)}.
template<typename TypeT>
struct range {
TypeT* first; //!< The first element
TypeT* last; //!< The last element
///
/// \brief C++ Iterator Specification \emph{begin()}
/// \returns A pointer to the start of the array
TypeT* begin() const {
return first;
}
///
/// \brief C++ Iterator Specification \emph{end()}
/// \returns A pointer to the start of the array
TypeT* end() const {
return last;
}
};
///
/// \brief Range for iterators.
/// \tparam IteratorT The iterator type.
///
/// \note Operates on the range \emph{[first, last)}.
template<typename IteratorT> requires(is_iterable_v<IteratorT>)
struct range<IteratorT> {
IteratorT first; //!< The first element
IteratorT last; //!< The last element
///
/// \brief C++ Iterator Specification \emph{begin()}
/// \returns A pointer to the start of the array
IteratorT& begin() const {
return first;
}
///
/// \brief C++ Iterator Specification \emph{end()}
/// \returns A pointer to the start of the array
IteratorT& end() const {
return last;
}
};
///
/// \brief Proxy Struct for fulfilling the C++ 11 Iterator Specification
template<typename ScalarT>
struct counter {
ScalarT val; //!< The held value
///
/// \brief Pre-Increment
/// \returns A reference to \emph{this} after incrementing \emph{val}.
counter& operator++() {
++val;
return *this;
}
///
/// \brief Post-Increment
/// \returns A counter with the previously held value.
counter operator++(int) {
++val;
return { val - 1 };
}
///
/// \brief Equality Operator
/// \param ctr The counter to compare with
/// \returns \math{{val}_{this} = {val}_{ctr}}
bool operator==(const counter& ctr) const {
return val == ctr.val;
}
///
/// \brief Equality Operator
/// \param ctr The counter to compare with
/// \returns \math{{val}_{this} \neq {val}_{ctr}}
bool operator!=(const counter& ctr) const {
return val != ctr.val;
}
///
/// \brief Dereference Operator
/// \returns \emph{val}
ScalarT operator*() const {
return val;
}
};
///
/// \brief Range for scalar types.
/// \tparam ScalarT The scalar type.
///
/// \note Operates on the range \emph{[first, last)}.
template<typename ScalarT> requires(is_scalar_v<ScalarT>)
struct range<ScalarT> {
ScalarT first; //!< The starting value
ScalarT last; //!< The last value
///
/// \brief C++ Iterator Specification \emph{begin()}
/// \returns A `fennec::counter` containing \emph{first}
counter<ScalarT> begin() const {
return { first };
}
///
/// \brief C++ Iterator Specification \emph{begin()}
/// \returns A `fennec::counter` containing \emph{last}
counter<ScalarT> end() const {
return { last };
}
};
} }
#endif // FENNEC_LANG_RANGES_H #endif // FENNEC_LANG_RANGES_H

View File

@@ -1,6 +1,6 @@
// ===================================================================================================================== // =====================================================================================================================
// fennec, a free and open source game engine // fennec, a free and open source game engine
// Copyright © 2025 - 2026 Medusa Slockbower // Copyright © 2025 Medusa Slockbower
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@@ -16,32 +16,29 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
#ifndef FENNEC_CORE_SYSTEM_H ///
#define FENNEC_CORE_SYSTEM_H /// \file system.h
#include <fennec/string/string.h> /// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_LANG_SYSTEM_H
#define FENNEC_LANG_SYSTEM_H
#include <fennec/lang/detail/_stdlib.h>
namespace fennec namespace fennec
{ {
class system { using ::system;
public:
using tick_f = void (*)(system*, double);
using frame_f = void (*)(system*, size_t);
const string name;
const tick_f tick;
const frame_f frame;
system(const cstring& name, tick_f tick, frame_f frame)
: name(name), tick(tick), frame(frame) {
}
virtual ~system() = default;
virtual void init() = 0;
virtual void shutdown() = 0;
};
} }
#endif // FENNEC_CORE_SYSTEM_H #endif // FENNEC_LANG_SYSTEM_H

View File

@@ -102,7 +102,7 @@ template<size_t n, typename...TypesT> using nth_element_t = nth_element<n, Types
// fennec::replace_first_element ======================================================================================= // fennec::replace_first_element =======================================================================================
/// ///
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first \f$ArgT\f$ of `ArgsT...` with \f$SubT\f$ /// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first \emph{ArgT} of \emph{ArgsT...} with \emph{SubT}
template<typename ClassT, typename SubT> struct replace_first_element { }; template<typename ClassT, typename SubT> struct replace_first_element { };
#ifndef FENNEC_DOXYGEN #ifndef FENNEC_DOXYGEN
@@ -134,7 +134,7 @@ template<typename...Ts> constexpr size_t max_element_size_v = max_element_size<T
// fennec::find_element ================================================================================================ // fennec::find_element ================================================================================================
/// ///
/// \brief Finds the index of \f$T\f$ in \f$Ts\f$, if \f$T\f$ is not found, results in `sizeof...(Ts)` /// \brief Finds the index of \emph{T} in \emph{Ts}, if \emph{T} is not found, results in `sizeof...(Ts)`
/// \tparam T The type to find /// \tparam T The type to find
/// \tparam Ts The type sequence to check /// \tparam Ts The type sequence to check
template<typename T, typename...Ts> struct find_element : detail::_find_element<0, T, Ts...> {}; template<typename T, typename...Ts> struct find_element : detail::_find_element<0, T, Ts...> {};
@@ -180,7 +180,7 @@ struct search_element_args<SearchT, type_sequence<ArgsT...>, TypesT...>
// fennec::contains_element ============================================================================================ // fennec::contains_element ============================================================================================
/// ///
/// \brief Checks if the type sequence `Ts...` contains \f$T\f$ /// \brief Checks if the type sequence \emph{Ts...} contains \emph{T}
/// \tparam T The type to find /// \tparam T The type to find
/// \tparam Ts The type sequence to check /// \tparam Ts The type sequence to check
template<typename T, typename...Ts> struct contains_element : bool_constant<(is_same_v<T, Ts> or ...)> {}; template<typename T, typename...Ts> struct contains_element : bool_constant<(is_same_v<T, Ts> or ...)> {};

View File

@@ -436,7 +436,7 @@ namespace fennec
/// ///
/// \brief metaprogramming helper for determining if a function is consteval /// \brief metaprogramming helper for determining if a function is consteval
/// \returns \f$true\f$ if under `consteval`, \f$false\f$ otherwise /// \returns \emph{true} if under `consteval`, \emph{false} otherwise
constexpr inline bool is_constant_evaluated() noexcept { constexpr inline bool is_constant_evaluated() noexcept {
if consteval { if consteval {
return true; return true;
@@ -461,7 +461,7 @@ template<typename T> struct is_void
: detail::_is_void<remove_cvref_t<T>>{}; : detail::_is_void<remove_cvref_t<T>>{};
/// ///
/// \brief Shorthand for ```is_void<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_void_v = is_void<T>::value; template<typename T> constexpr bool_t is_void_v = is_void<T>::value;
@@ -478,7 +478,7 @@ template<typename T> struct is_null_pointer
: detail::_is_null_pointer<remove_cvref_t<T>>{}; : detail::_is_null_pointer<remove_cvref_t<T>>{};
/// ///
/// \brief Shorthand for ```is_null_pointer<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::value; template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::value;
@@ -495,7 +495,7 @@ template<typename T> struct is_bool
: detail::_is_bool<remove_cvref_t<T>>{}; : detail::_is_bool<remove_cvref_t<T>>{};
/// ///
/// \brief Shorthand for ```is_bool<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value; template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
@@ -512,7 +512,7 @@ template<typename T> struct is_integral
: detail::_is_integral<remove_cvref_t<T>> {}; : detail::_is_integral<remove_cvref_t<T>> {};
/// ///
/// \brief Shorthand for ```is_integral<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value; template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
@@ -529,7 +529,7 @@ template<typename T> struct is_floating_point
: detail::_is_floating_point<remove_cvref_t<T>>{}; : detail::_is_floating_point<remove_cvref_t<T>>{};
/// ///
/// \brief Shorthand for ```is_floating_point<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {}; template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};
@@ -564,7 +564,7 @@ template<typename T> struct is_array<T[]>
#endif #endif
/// ///
/// \brief Shorthand for ```is_array<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_array_v = is_array<T>::value; template<typename T> constexpr bool_t is_array_v = is_array<T>::value;
@@ -641,7 +641,7 @@ template<typename T> struct is_pointer
: detail::_is_pointer<remove_cvref_t<T>>{}; : detail::_is_pointer<remove_cvref_t<T>>{};
/// ///
/// \brief Shorthand for ```is_pointer<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {}; template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
@@ -652,13 +652,13 @@ template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
/// ///
/// \brief Check if \p T is of a floating point type /// \brief Check if \p T is of a floating point type
/// ///
/// \details Checks if type \f$T\f$ is a floating point type and store it in `is_same::value`. /// \details Checks if type \emph{T} is a floating point type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_lvalue_reference template<typename T> struct is_lvalue_reference
: detail::_is_lvalue_reference<T>{}; : detail::_is_lvalue_reference<T>{};
/// ///
/// \brief Shorthand for ```is_floating_point<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {}; template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {};
@@ -669,13 +669,13 @@ template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_referenc
/// ///
/// \brief Check if \p T is of a floating point type /// \brief Check if \p T is of a floating point type
/// ///
/// \details Checks if type \f$T\f$ is a floating point type and store it in `is_same::value`. /// \details Checks if type \emph{T} is a floating point type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_rvalue_reference template<typename T> struct is_rvalue_reference
: detail::_is_rvalue_reference<T>{}; : detail::_is_rvalue_reference<T>{};
/// ///
/// \brief Shorthand for ```is_floating_point<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {}; template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {};
@@ -686,13 +686,13 @@ template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_referenc
/// ///
/// \brief Check if \p T is a pointer to a member function /// \brief Check if \p T is a pointer to a member function
/// ///
/// \details Checks if type \f$T\f$ is pointer to a member function and store it in `is_member_function_pointer::value`. /// \details Checks if type \emph{T} is pointer to a member function and store it in `is_member_function_pointer::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_member_function_pointer template<typename T> struct is_member_function_pointer
: bool_constant<FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(T)> {}; : bool_constant<FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(T)> {};
/// ///
/// \brief Shorthand for ```is_member_function_pointer<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_member_function_pointer_v = is_member_function_pointer<T> {}; template<typename T> constexpr bool_t is_member_function_pointer_v = is_member_function_pointer<T> {};
@@ -703,13 +703,13 @@ template<typename T> constexpr bool_t is_member_function_pointer_v = is_member_f
/// ///
/// \brief Check if \p T is a pointer to a member object /// \brief Check if \p T is a pointer to a member object
/// ///
/// \details Checks if type \f$T\f$ is pointer to a member object and store it in `is_member_object_pointer::value`. /// \details Checks if type \emph{T} is pointer to a member object and store it in `is_member_object_pointer::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_member_object_pointer template<typename T> struct is_member_object_pointer
: bool_constant<FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(T)> {}; : bool_constant<FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(T)> {};
/// ///
/// \brief Shorthand for ```is_member_object_pointer<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_member_object_pointer_v = is_member_object_pointer<T> {}; template<typename T> constexpr bool_t is_member_object_pointer_v = is_member_object_pointer<T> {};
@@ -725,13 +725,13 @@ template<typename T> constexpr bool_t is_member_object_pointer_v = is_member_obj
/// ///
/// \brief Check if \p T is an arithmetic type /// \brief Check if \p T is an arithmetic type
/// ///
/// \details Checks if type \f$T\f$ is a built-in type with arithmetic operators and store it in `is_same::value`. /// \details Checks if type \emph{T} is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_arithmetic template<typename T> struct is_arithmetic
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{}; : bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
/// ///
/// \brief Shorthand for ```is_arithmetic<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value; template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;
@@ -745,7 +745,7 @@ template<typename T> struct is_fundamental
: bool_constant<is_arithmetic_v<T> or is_void_v<T> or is_null_pointer_v<T>>{}; : bool_constant<is_arithmetic_v<T> or is_void_v<T> or is_null_pointer_v<T>>{};
/// ///
/// \brief Shorthand for ```is_fundamental<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value; template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value;
@@ -756,13 +756,13 @@ template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::valu
/// ///
/// \brief Check if \p T is an arithmetic type /// \brief Check if \p T is an arithmetic type
/// ///
/// \details Checks if type \f$T\f$ is a built-in type with arithmetic operators and store it in `is_scalar::value`. /// \details Checks if type \emph{T} is a built-in type with arithmetic operators and store it in `is_scalar::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_scalar template<typename T> struct is_scalar
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{}; : bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
/// ///
/// \brief Shorthand for ```is_scalar<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value; template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
@@ -773,12 +773,12 @@ template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
/// ///
/// \brief Check if \p T is an object /// \brief Check if \p T is an object
/// ///
/// \details Checks if type \f$T\f$ is an object and store it in `is_object::value`. /// \details Checks if type \emph{T} is an object and store it in `is_object::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_object : bool_constant<FENNEC_BUILTIN_IS_OBJECT(T)> {}; template<typename T> struct is_object : bool_constant<FENNEC_BUILTIN_IS_OBJECT(T)> {};
/// ///
/// \brief Shorthand for ```is_object<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_object_v = is_object<T>::value; template<typename T> constexpr bool_t is_object_v = is_object<T>::value;
@@ -789,12 +789,12 @@ template<typename T> constexpr bool_t is_object_v = is_object<T>::value;
/// ///
/// \brief Check if \p T is a object compound type /// \brief Check if \p T is a object compound type
/// ///
/// \details Checks if type \f$T\f$ is an object and store it in `is_compound::value`. /// \details Checks if type \emph{T} is an object and store it in `is_compound::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_compound : bool_constant<not is_fundamental_v<T>> {}; template<typename T> struct is_compound : bool_constant<not is_fundamental_v<T>> {};
/// ///
/// \brief Shorthand for ```is_compound<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_compound_v = is_compound<T>::value; template<typename T> constexpr bool_t is_compound_v = is_compound<T>::value;
@@ -805,13 +805,13 @@ template<typename T> constexpr bool_t is_compound_v = is_compound<T>::value;
/// ///
/// \brief Check if \p T is of a reference type /// \brief Check if \p T is of a reference type
/// ///
/// \details Checks if type \f$T\f$ is a reference type and store it in `is_reference::value`. /// \details Checks if type \emph{T} is a reference type and store it in `is_reference::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_reference template<typename T> struct is_reference
: detail::_is_reference<T>{}; : detail::_is_reference<T>{};
/// ///
/// \brief Shorthand for ```is_reference<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_reference_v = is_reference<T> {}; template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
@@ -822,13 +822,13 @@ template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
/// ///
/// \brief Check if \p T is a pointer to a member /// \brief Check if \p T is a pointer to a member
/// ///
/// \details Checks if type \f$T\f$ is pointer to a member and store it in `is_member_function_pointer::value`. /// \details Checks if type \emph{T} is pointer to a member and store it in `is_member_function_pointer::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_member_pointer template<typename T> struct is_member_pointer
: bool_constant<FENNEC_BUILTIN_IS_MEMBER_POINTER(T)> {}; : bool_constant<FENNEC_BUILTIN_IS_MEMBER_POINTER(T)> {};
/// ///
/// \brief Shorthand for ```is_member_function_pointer<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_member_pointer_v = is_member_pointer<T> {}; template<typename T> constexpr bool_t is_member_pointer_v = is_member_pointer<T> {};
@@ -844,13 +844,13 @@ template<typename T> constexpr bool_t is_member_pointer_v = is_member_pointer<T>
/// ///
/// \brief Check if \p T is of a const type /// \brief Check if \p T is of a const type
/// ///
/// \details Checks if type \f$T\f$ is a const type and store it in `is_same::value`. /// \details Checks if type \emph{T} is a const type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_const template<typename T> struct is_const
: detail::_is_const<T>{}; : detail::_is_const<T>{};
/// ///
/// \brief Shorthand for ```is_const<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_const_v = is_const<T> {}; template<typename T> constexpr bool_t is_const_v = is_const<T> {};
@@ -861,13 +861,13 @@ template<typename T> constexpr bool_t is_const_v = is_const<T> {};
/// ///
/// \brief Check if \p T is of a volatile type /// \brief Check if \p T is of a volatile type
/// ///
/// \details Checks if type \f$T\f$ is a volatile type and store it in `is_same::value`. /// \details Checks if type \emph{T} is a volatile type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_volatile template<typename T> struct is_volatile
: detail::_is_volatile<T>{}; : detail::_is_volatile<T>{};
/// ///
/// \brief Shorthand for ```is_volatile<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_volatile_v = is_volatile<T> {}; template<typename T> constexpr bool_t is_volatile_v = is_volatile<T> {};
@@ -876,9 +876,9 @@ template<typename T> constexpr bool_t is_volatile_v = is_volatile<T> {};
// fennec::is_trivial -------------------------------------------------------------------------------------------------- // fennec::is_trivial --------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is trivial /// \brief Check if type \emph{T} is trivial
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_trivial : bool_constant<FENNEC_BUILTIN_IS_TRIVIAL(T)> {}; template<typename T> struct is_trivial : bool_constant<FENNEC_BUILTIN_IS_TRIVIAL(T)> {};
@@ -892,9 +892,9 @@ template<typename T> constexpr bool_t is_trivial_v = is_trivial<T>{};
// fennec::is_trivially_copyable --------------------------------------------------------------------------------------- // fennec::is_trivially_copyable ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is trivially_copyable /// \brief Check if type \emph{T} is trivially_copyable
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_trivially_copyable : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(T)> {}; template<typename T> struct is_trivially_copyable : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(T)> {};
@@ -908,9 +908,9 @@ template<typename T> constexpr bool_t is_trivially_copyable_v = is_trivially_cop
// fennec::is_standard_layout ------------------------------------------------------------------------------------------ // fennec::is_standard_layout ------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is standard_layout /// \brief Check if type \emph{T} is standard_layout
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_standard_layout : bool_constant<FENNEC_BUILTIN_IS_STANDARD_LAYOUT(T)> {}; template<typename T> struct is_standard_layout : bool_constant<FENNEC_BUILTIN_IS_STANDARD_LAYOUT(T)> {};
@@ -924,9 +924,9 @@ template<typename T> constexpr bool_t is_standard_layout_v = is_standard_layout<
// fennec::has_unique_object_representations --------------------------------------------------------------------------- // fennec::has_unique_object_representations ---------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ has unique object representations /// \brief Check if type \emph{T} has unique object representations
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct has_unique_object_representations template<typename T> struct has_unique_object_representations
: bool_constant<FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(remove_cv_t<T>)> {}; : bool_constant<FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(remove_cv_t<T>)> {};
@@ -941,9 +941,9 @@ template<typename T> constexpr bool_t has_unique_object_representations_v = has_
// fennec::is_empty ---------------------------------------------------------------------------------------------------- // fennec::is_empty ----------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is empty /// \brief Check if type \emph{T} is empty
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_empty : bool_constant<FENNEC_BUILTIN_IS_EMPTY(T)> {}; template<typename T> struct is_empty : bool_constant<FENNEC_BUILTIN_IS_EMPTY(T)> {};
@@ -957,9 +957,9 @@ template<typename T> constexpr bool_t is_empty_v = is_empty<T>{};
// fennec::is_polymorphic ---------------------------------------------------------------------------------------------- // fennec::is_polymorphic ----------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is polymorphic /// \brief Check if type \emph{T} is polymorphic
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_polymorphic : bool_constant<FENNEC_BUILTIN_IS_POLYMORPHIC(T)> {}; template<typename T> struct is_polymorphic : bool_constant<FENNEC_BUILTIN_IS_POLYMORPHIC(T)> {};
@@ -973,9 +973,9 @@ template<typename T> constexpr bool_t is_polymorphic_v = is_polymorphic<T>{};
// fennec::is_abstract ------------------------------------------------------------------------------------------------- // fennec::is_abstract -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is abstract /// \brief Check if type \emph{T} is abstract
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_abstract : bool_constant<FENNEC_BUILTIN_IS_ABSTRACT(T)> {}; template<typename T> struct is_abstract : bool_constant<FENNEC_BUILTIN_IS_ABSTRACT(T)> {};
@@ -989,9 +989,9 @@ template<typename T> constexpr bool_t is_abstract_v = is_abstract<T>{};
// fennec::is_complete ------------------------------------------------------------------------------------------------- // fennec::is_complete -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is complete /// \brief Check if type \emph{T} is complete
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_complete : detail::_is_complete<T>::type {}; template<typename T> struct is_complete : detail::_is_complete<T>::type {};
@@ -1005,9 +1005,9 @@ template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};
// fennec::is_final ------------------------------------------------------------------------------------------------- // fennec::is_final -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is final /// \brief Check if type \emph{T} is final
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_final : bool_constant<FENNEC_BUILTIN_IS_FINAL(T)> {}; template<typename T> struct is_final : bool_constant<FENNEC_BUILTIN_IS_FINAL(T)> {};
@@ -1021,9 +1021,9 @@ template<typename T> constexpr bool_t is_final_v = is_final<T>{};
// fennec::is_aggregate ------------------------------------------------------------------------------------------------- // fennec::is_aggregate -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is aggregate /// \brief Check if type \emph{T} is aggregate
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_aggregate : bool_constant<FENNEC_BUILTIN_IS_AGGREGATE(T)> {}; template<typename T> struct is_aggregate : bool_constant<FENNEC_BUILTIN_IS_AGGREGATE(T)> {};
@@ -1040,13 +1040,13 @@ template<typename T> constexpr bool_t is_aggregate_v = is_aggregate<T>{};
/// ///
/// \brief Check if \p T is of a signed integral /// \brief Check if \p T is of a signed integral
/// ///
/// \details Checks if type \f$T\f$ is a signed type i.e. `T(-1) < T(0)` and stores it in `is_same::value`. /// \details Checks if type \emph{T} is a signed type i.e. \math{\textbf{T(-1)} < \textbf{T(0)}} and stores it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_signed template<typename T> struct is_signed
: detail::_is_signed<remove_cvref_t<T>> {}; : detail::_is_signed<remove_cvref_t<T>> {};
/// ///
/// \brief Shorthand for ```is_signed<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value; template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value;
@@ -1058,13 +1058,13 @@ template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value;
/// ///
/// \brief Check if \p T is of an unsigned integral /// \brief Check if \p T is of an unsigned integral
/// ///
/// \details Checks if type \f$T\f$ is an unsigned type i.e. `T(-1) > T(0)` and stores it in `is_same::value`. /// \details Checks if type \emph{T} is an unsigned type i.e. \math{\textbf{T(-1)} > \textbf{T(0)}} and stores it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_unsigned template<typename T> struct is_unsigned
: detail::_is_unsigned<remove_cvref_t<T>> {}; : detail::_is_unsigned<remove_cvref_t<T>> {};
/// ///
/// \brief Shorthand for ```is_unsigned<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value; template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
@@ -1072,16 +1072,6 @@ template<typename T> struct is_unsigned
// fennec::is_bounded_array -------------------------------------------------------------------------------------------- // fennec::is_bounded_array --------------------------------------------------------------------------------------------
#if FENNEC_HAS_BUILTIN_BOUNDED_ARRAY
///
/// \brief Check if \p T is of a bounded array type
/// \tparam T type to check
template<typename T> struct is_bounded_array
: bool_constant<FENNEC_BUILTIN_IS_BOUNDED_ARRAY(T)> {};
#else
/// ///
/// \brief Check if \p T is of an bounded type /// \brief Check if \p T is of an bounded type
/// \tparam T type to check /// \tparam T type to check
@@ -1092,10 +1082,8 @@ template<typename T> struct is_bounded_array
template<typename T, size_t N> struct is_bounded_array<T[N]> template<typename T, size_t N> struct is_bounded_array<T[N]>
: true_type {}; : true_type {};
#endif
/// ///
/// \brief Shorthand for ```is_bounded_array<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_bounded_array_v = is_bounded_array<T>::value; template<typename T> constexpr bool_t is_bounded_array_v = is_bounded_array<T>::value;
@@ -1103,16 +1091,6 @@ template<typename T> constexpr bool_t is_bounded_array_v = is_bounded_array<T>::
// fennec::is_unbounded_array ------------------------------------------------------------------------------------------ // fennec::is_unbounded_array ------------------------------------------------------------------------------------------
#if FENNEC_HAS_BUILTIN_UNBOUNDED_ARRAY
///
/// \brief Check if \p T is of a unbounded array type
/// \tparam T type to check
template<typename T> struct is_unbounded_array
: bool_constant<FENNEC_BUILTIN_IS_UNBOUNDED_ARRAY(T)> {};
#else
/// ///
/// \brief Check if \p T is of an unbounded type /// \brief Check if \p T is of an unbounded type
/// \tparam T type to check /// \tparam T type to check
@@ -1123,10 +1101,8 @@ template<typename T> struct is_unbounded_array
template<typename T> struct is_unbounded_array<T[]> template<typename T> struct is_unbounded_array<T[]>
: true_type {}; : true_type {};
#endif
/// ///
/// \brief Shorthand for ```is_unbounded_array<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_unbounded_array_v = is_unbounded_array<T>::value; template<typename T> constexpr bool_t is_unbounded_array_v = is_unbounded_array<T>::value;
@@ -1163,7 +1139,7 @@ struct is_scoped_enum<T>
#endif #endif
/// ///
/// \brief Shorthand for ```is_scoped_enum<T>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool_t is_scoped_enum_v = is_scoped_enum<T>::value; template<typename T> constexpr bool_t is_scoped_enum_v = is_scoped_enum<T>::value;
@@ -1177,9 +1153,9 @@ template<typename T> constexpr bool_t is_scoped_enum_v = is_scoped_enum<T>::valu
// fennec::is_convertible ---------------------------------------------------------------------------------------------- // fennec::is_convertible ----------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T0\f$ can be converted \f$T1\f$ /// \brief Check if type \emph{T0} can be converted \emph{T1}
/// ///
/// \details Checks if \f$TypeT0\f$ /// \details Checks if \emph{TypeT0}
/// \tparam FromT First type /// \tparam FromT First type
/// \tparam ToT Second type /// \tparam ToT Second type
template<typename FromT, typename ToT> struct is_convertible template<typename FromT, typename ToT> struct is_convertible
@@ -1196,8 +1172,8 @@ template<typename FromT, typename ToT> constexpr bool_t is_convertible_v = is_co
// fennec::is_constructible -------------------------------------------------------------------------------------------- // fennec::is_constructible --------------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`. /// \brief Check if \emph{ClassT} can be constructed with \emph{ArgsT...}, i.e. `ClassT(ArgsT...)`.
/// This may be read as "is \f$ClassT\f$ constructible with \f$ArgsT\f$" /// This may be read as "is \emph{ClassT} constructible with \emph{ArgsT}"
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor /// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_constructible template<typename ClassT, typename...ArgsT> struct is_constructible
@@ -1212,7 +1188,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v
// fennec::is_trivially_constructible ---------------------------------------------------------------------------------- // fennec::is_trivially_constructible ----------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially constructible /// \brief Check if \emph{ClassT} is trivially constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor /// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_trivially_constructible template<typename ClassT, typename...ArgsT> struct is_trivially_constructible
@@ -1227,7 +1203,7 @@ template<typename ClassT> constexpr bool_t is_trivially_constructible_v = is_tri
// fennec::is_nothrow_constructible ------------------------------------------------------------------------------------ // fennec::is_nothrow_constructible ------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow constructible /// \brief Check if \emph{ClassT} is nothrow constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor /// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_nothrow_constructible template<typename ClassT, typename...ArgsT> struct is_nothrow_constructible
@@ -1242,7 +1218,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_constructible_v = is_nothr
// fennec::is_default_constructible ------------------------------------------------------------------------------------ // fennec::is_default_constructible ------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is default constructible /// \brief Check if \emph{ClassT} is default constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_default_constructible template<typename ClassT> struct is_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT)> {};
@@ -1256,7 +1232,7 @@ template<typename ClassT> constexpr bool_t is_default_constructible_v = is_defau
// fennec::is_trivially_default_constructible -------------------------------------------------------------------------- // fennec::is_trivially_default_constructible --------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially default constructible /// \brief Check if \emph{ClassT} is trivially default constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_default_constructible template<typename ClassT> struct is_trivially_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {};
@@ -1270,7 +1246,7 @@ template<typename ClassT> constexpr bool_t is_trivially_default_constructible_v
// fennec::is_nothrow_default_constructible -------------------------------------------------------------------------- // fennec::is_nothrow_default_constructible --------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow default constructible /// \brief Check if \emph{ClassT} is nothrow default constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_default_constructible template<typename ClassT> struct is_nothrow_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE(ClassT)> {};
@@ -1284,7 +1260,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_default_constructible_v =
// fennec::is_copy_constructible --------------------------------------------------------------------------------------- // fennec::is_copy_constructible ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is copy constructible /// \brief Check if \emph{ClassT} is copy constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_constructible template<typename ClassT> struct is_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1298,7 +1274,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_copy_constructib
// fennec::is_trivially_copy_constructible ----------------------------------------------------------------------------- // fennec::is_trivially_copy_constructible -----------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially copy constructible /// \brief Check if \emph{ClassT} is trivially copy constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_copy_constructible template<typename ClassT> struct is_trivially_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1312,7 +1288,7 @@ template<typename ClassT> struct is_trivially_copy_constructible
// fennec::is_nothrow_copy_constructible ------------------------------------------------------------------------------- // fennec::is_nothrow_copy_constructible -------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow copy constructible /// \brief Check if \emph{ClassT} is nothrow copy constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_copy_constructible template<typename ClassT> struct is_nothrow_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1326,7 +1302,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_nothrow_copy_con
// fennec::is_move_constructible --------------------------------------------------------------------------------------- // fennec::is_move_constructible ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is move constructible /// \brief Check if \emph{ClassT} is move constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_constructible template<typename ClassT> struct is_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {};
@@ -1340,7 +1316,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructib
// fennec::is_trivially_move_constructible ----------------------------------------------------------------------------- // fennec::is_trivially_move_constructible -----------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially move constructible /// \brief Check if \emph{ClassT} is trivially move constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_move_constructible template<typename ClassT> struct is_trivially_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1354,7 +1330,7 @@ template<typename ClassT> struct is_trivially_move_constructible
// fennec::is_nothrow_move_constructible ------------------------------------------------------------------------------- // fennec::is_nothrow_move_constructible -------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow move constructible /// \brief Check if \emph{ClassT} is nothrow move constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_move_constructible template<typename ClassT> struct is_nothrow_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1368,7 +1344,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_nothrow_move_con
// fennec::is_assignable ----------------------------------------------------------------------------------------------- // fennec::is_assignable -----------------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is assignable /// \brief Check if \emph{ClassT} is assignable
/// \tparam ClassAT The class type to test /// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor /// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_assignable template<typename ClassAT, typename ClassBT> struct is_assignable
@@ -1383,7 +1359,7 @@ template<typename ClassAT, typename ClassBT> constexpr bool_t is_assignable_v =
// fennec::is_trivially_assignable ------------------------------------------------------------------------------------- // fennec::is_trivially_assignable -------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially assignable /// \brief Check if \emph{ClassT} is trivially assignable
/// \tparam ClassAT The class type to test /// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor /// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_trivially_assignable template<typename ClassAT, typename ClassBT> struct is_trivially_assignable
@@ -1399,7 +1375,7 @@ template<typename ClassAT, typename ClassBT> constexpr bool_t is_trivially_assig
// fennec::is_nothrow_assignable --------------------------------------------------------------------------------------- // fennec::is_nothrow_assignable ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow assignable /// \brief Check if \emph{ClassT} is nothrow assignable
/// \tparam ClassAT The class type to test /// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor /// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_nothrow_assignable template<typename ClassAT, typename ClassBT> struct is_nothrow_assignable
@@ -1414,7 +1390,7 @@ template<typename ClassAT, typename ClassBT> constexpr bool_t is_nothrow_assigna
// fennec::is_copy_assignable ------------------------------------------------------------------------------------------ // fennec::is_copy_assignable ------------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is copy assignable /// \brief Check if \emph{ClassT} is copy assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_assignable template<typename ClassT> struct is_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1428,7 +1404,7 @@ template<typename ClassT> constexpr bool_t is_copy_assignable_v = is_copy_assign
// fennec::is_trivially_copy_assignable -------------------------------------------------------------------------------- // fennec::is_trivially_copy_assignable --------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially_copy assignable /// \brief Check if \emph{ClassT} is trivially_copy assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_copy_assignable template<typename ClassT> struct is_trivially_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1442,7 +1418,7 @@ template<typename ClassT> constexpr bool_t is_trivially_copy_assignable_v = is_t
// fennec::is_nothrow_copy_assignable ---------------------------------------------------------------------------------- // fennec::is_nothrow_copy_assignable ----------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow_copy assignable /// \brief Check if \emph{ClassT} is nothrow_copy assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_copy_assignable template<typename ClassT> struct is_nothrow_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1456,7 +1432,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_copy_assignable_v = is_not
// fennec::is_move_assignable ------------------------------------------------------------------------------------------ // fennec::is_move_assignable ------------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is move assignable /// \brief Check if \emph{ClassT} is move assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_assignable template<typename ClassT> struct is_move_assignable
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
@@ -1470,7 +1446,7 @@ template<typename ClassT> constexpr bool_t is_move_assignable_v = is_move_assign
// fennec::is_trivially_move_assignable -------------------------------------------------------------------------------- // fennec::is_trivially_move_assignable --------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially_move assignable /// \brief Check if \emph{ClassT} is trivially_move assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_move_assignable template<typename ClassT> struct is_trivially_move_assignable
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
@@ -1484,7 +1460,7 @@ template<typename ClassT> constexpr bool_t is_trivially_move_assignable_v = is_t
// fennec::is_nothrow_move_assignable -------------------------------------------------------------------------------- // fennec::is_nothrow_move_assignable --------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow_move assignable /// \brief Check if \emph{ClassT} is nothrow_move assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_move_assignable template<typename ClassT> struct is_nothrow_move_assignable
: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
@@ -1498,7 +1474,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_move_assignable_v = is_not
// fennec::is_destructible --------------------------------------------------------------------------------------------- // fennec::is_destructible ---------------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is destructible /// \brief Check if \emph{ClassT} is destructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_destructible template<typename ClassT> struct is_destructible
: detail::_is_destructible<ClassT>::type {}; : detail::_is_destructible<ClassT>::type {};
@@ -1512,10 +1488,14 @@ template<typename ClassT> constexpr bool_t is_destructible_v = is_destructible<C
// fennec::is_trivially_destructible ----------------------------------------------------------------------------------- // fennec::is_trivially_destructible -----------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is trivially destructible /// \brief Check if \emph{ClassT} is trivially destructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_destructible template<typename ClassT> struct is_trivially_destructible
#if FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {};
#else
: bool_constant<FENNEC_BUILTIN_HAS_TRIVIAL_DESTRUCTOR(ClassT)> {};
#endif
/// ///
/// \brief Shorthand for `is_trivially_destructible<ClassT, ArgsT...>::value` /// \brief Shorthand for `is_trivially_destructible<ClassT, ArgsT...>::value`
@@ -1526,7 +1506,7 @@ template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_triv
// fennec::is_nothrow_destructible ------------------------------------------------------------------------------------- // fennec::is_nothrow_destructible -------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$ClassT\f$ is nothrow destructible /// \brief Check if \emph{ClassT} is nothrow destructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_destructible template<typename ClassT> struct is_nothrow_destructible
: detail::_is_nothrow_destructible<ClassT>::type {}; : detail::_is_nothrow_destructible<ClassT>::type {};
@@ -1547,7 +1527,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_destructible_v = is_nothro
/// ///
/// \brief Check if the two types are identical /// \brief Check if the two types are identical
/// ///
/// \details Checks if \f$T0\f$ and \f$T1\f$ are identical and store it in `is_same::value` /// \details Checks if \emph{T0} and \emph{T1} are identical and store it in `is_same::value`
/// \tparam T0 first type to check /// \tparam T0 first type to check
/// \tparam T1 second type to check /// \tparam T1 second type to check
template<typename T0, typename T1> struct is_same : false_type {}; template<typename T0, typename T1> struct is_same : false_type {};
@@ -1556,7 +1536,7 @@ template<typename T0, typename T1> struct is_same : false_type {};
template<typename T> struct is_same<T, T> : true_type {}; template<typename T> struct is_same<T, T> : true_type {};
/// ///
/// \brief Shorthand for ```is_same<T0, T1>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam T0 first type to check /// \tparam T0 first type to check
/// \tparam T1 second type to check /// \tparam T1 second type to check
template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {}; template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {};
@@ -1566,9 +1546,9 @@ template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1>
// fennec::is_base_of -------------------------------------------------------------------------------------------------- // fennec::is_base_of --------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if \f$Derived\f$ has a base type of \f$Base\f$ /// \brief Check if \emph{Derived} has a base type of \emph{Base}
/// ///
/// \details Checks if \f$Base\f$ is a base type of \f$Derived\f$ and stores it in `is_base_of::value` /// \details Checks if \emph{Base} is a base type of \emph{Derived} and stores it in `is_base_of::value`
/// \tparam Base base type to check /// \tparam Base base type to check
/// \tparam Derived derived type to check /// \tparam Derived derived type to check
template<typename Base, typename Derived> struct is_base_of : bool_constant< template<typename Base, typename Derived> struct is_base_of : bool_constant<
@@ -1576,7 +1556,7 @@ template<typename Base, typename Derived> struct is_base_of : bool_constant<
> {}; > {};
/// ///
/// \brief Shorthand for ```is_base_of<T0, T1>::value``` /// \brief Shorthand for `(.*?)`
/// \tparam Base base type to check /// \tparam Base base type to check
/// \tparam Derived derived type to check /// \tparam Derived derived type to check
template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_base_of<Base, Derived> {}; template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_base_of<Base, Derived> {};
@@ -1586,9 +1566,9 @@ template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_bas
// fennec::is_iterable ------------------------------------------------------------------------------------------------- // fennec::is_iterable -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is iterable /// \brief Check if type \emph{T} is iterable
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{Base} is iterable and stores it in `is_base_of::value`
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {}; template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};
@@ -1599,12 +1579,28 @@ template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};
// fennec::is_iterator -------------------------------------------------------------------------------------------------
///
/// \brief Check if type \emph{T} is an iterator
///
/// \details Checks if \emph{T} is an iterator and stores it in `is_base_of::value`
/// \tparam T type to check
template<typename T> struct is_iterator : decltype(detail::_is_iterator<T>(0)) {};
///
/// \brief Shorthand for `is_iterator<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_iterator_v = is_iterator<T>{};
// fennec::is_indexable ------------------------------------------------------------------------------------------------ // fennec::is_indexable ------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is indexable /// \brief Check if type \emph{T} is indexable
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {}; template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};
@@ -1618,9 +1614,9 @@ template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};
// fennec::is_mappable ------------------------------------------------------------------------------------------------- // fennec::is_mappable -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type \f$T\f$ is mappable /// \brief Check if type \emph{T} is mappable
/// ///
/// \details Checks if \f$T\f$ /// \details Checks if \emph{T}
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {}; template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};

View File

@@ -194,9 +194,9 @@ template<typename T> using decay_t = typename decay<T>::type;
// Pointer Conversions ================================================================================================= // Pointer Conversions =================================================================================================
/// ///
/// \brief adds a pointer level to \f$T\f$ /// \brief adds a pointer level to \emph{T}
/// ///
/// \details adds a pointer to the provided type such that \f$T\f$ becomes \f$T*\f$ /// \details adds a pointer to the provided type such that \emph{T} becomes \emph{T*}
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct add_pointer : detail::_add_pointer<T>{}; template<typename T> struct add_pointer : detail::_add_pointer<T>{};
@@ -206,9 +206,9 @@ template<typename T> using add_pointer_t = typename add_pointer<T>::type;
/// ///
/// \brief removes a pointer level from \f$T\f$ /// \brief removes a pointer level from \emph{T}
/// ///
/// \details removes a pointer from the provided type such that \f$T*\f$ becomes \f$T\f$ /// \details removes a pointer from the provided type such that \emph{T*} becomes \emph{T}
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct remove_pointer : detail::_remove_pointer<T> {}; template<typename T> struct remove_pointer : detail::_remove_pointer<T> {};
@@ -218,9 +218,9 @@ template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;
/// ///
/// \brief removes all pointer levels from \f$T\f$ /// \brief removes all pointer levels from \emph{T}
/// ///
/// \details removes all pointers from the provided type such that \f$T*\f$, \f$T**\f$, etc. becomes \f$T\f$ /// \details removes all pointers from the provided type such that \emph{T*}, \emph{T**}, etc. becomes \emph{T}
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct strip_pointers : conditional_t< template<typename T> struct strip_pointers : conditional_t<
detail::_is_pointer<T>::value, detail::_is_pointer<T>::value,
@@ -237,9 +237,9 @@ template<typename T> using strip_pointers_t = strip_pointers<T>::type;
// Reference Conversions =============================================================================================== // Reference Conversions ===============================================================================================
/// ///
/// \brief add a reference to \f$T\f$ /// \brief add a reference to \emph{T}
/// ///
/// \details adds a pointer to the provided type such that \f$T\f$ becomes \f$T\&\f$ /// \details adds a pointer to the provided type such that \emph{T} becomes \emph{T\&}
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct add_reference : type_identity<T&> {}; template<typename T> struct add_reference : type_identity<T&> {};
@@ -249,9 +249,9 @@ template<typename T> using add_reference_t = typename add_reference<T>::type;
/// ///
/// \brief add a lvalue reference to \f$T\f$ /// \brief add a lvalue reference to \emph{T}
/// ///
/// \details adds a lvalue reference to the provided type such that \f$T\f$ becomes \f$T\&\f$ /// \details adds a lvalue reference to the provided type such that \emph{T} becomes \emph{T\&}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_lvalue_reference : detail::_add_lvalue_reference<T> {}; template<typename T> struct add_lvalue_reference : detail::_add_lvalue_reference<T> {};
@@ -261,9 +261,9 @@ template<typename T> using add_lvalue_reference_t = typename add_lvalue_referen
/// ///
/// \brief add a rvalue reference to \f$T\f$ /// \brief add a rvalue reference to \emph{T}
/// ///
/// \details adds a rvalue reference to the provided type such that \f$T\f$ becomes \f$T\&\&\f$ /// \details adds a rvalue reference to the provided type such that \emph{T} becomes \emph{T\&\&}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_rvalue_reference : detail::_add_rvalue_reference<T> {}; template<typename T> struct add_rvalue_reference : detail::_add_rvalue_reference<T> {};
@@ -273,9 +273,9 @@ template<typename T> using add_rvalue_reference_t = typename add_rvalue_referen
/// ///
/// \brief remove a reference from \f$T\f$ /// \brief remove a reference from \emph{T}
/// ///
/// \details removes references from the provided type such that \f$T\&\f$ and \f$T\&\&\f$ become \f$T\f$ /// \details removes references from the provided type such that \emph{T\&} and \emph{T\&\&} become \emph{T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_reference : type_identity<T> {}; template<typename T> struct remove_reference : type_identity<T> {};
@@ -294,9 +294,9 @@ template<typename T> using remove_reference_t = typename remove_reference<T>::t
// Const & Volatile Conversions ======================================================================================== // Const & Volatile Conversions ========================================================================================
/// ///
/// \brief add the const qualifier to the provided type \f$T\f$ /// \brief add the const qualifier to the provided type \emph{T}
/// ///
/// \details adds const qualification to the provided type such that \f$T\f$ becomes \f$const\quad T\f$ /// \details adds const qualification to the provided type such that \emph{T} becomes \emph{const\quad T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_const : detail::_add_const<T> {}; template<typename T> struct add_const : detail::_add_const<T> {};
@@ -306,9 +306,9 @@ template<typename T> using add_const_t = typename add_const<T>::type;
/// ///
/// \brief remove the const qualifier from the provided type \f$T\f$ /// \brief remove the const qualifier from the provided type \emph{T}
/// ///
/// \details removes const qualification from the provided type such that \f$const\quad T\f$ becomes \f$T\f$ /// \details removes const qualification from the provided type such that \emph{const\quad T} becomes \emph{T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_const : detail::_remove_const<T> {}; template<typename T> struct remove_const : detail::_remove_const<T> {};
@@ -319,9 +319,9 @@ template<typename T> using remove_const_t = typename remove_const<T>::type;
/// ///
/// \brief add the volatile qualifier to the provided type \f$T\f$ /// \brief add the volatile qualifier to the provided type \emph{T}
/// ///
/// \details removes references from the provided type such that \f$T\f$ becomes \f$volatile\quad T\f$ /// \details removes references from the provided type such that \emph{T} becomes \emph{volatile\quad T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_volatile : detail::_add_volatile<T> {}; template<typename T> struct add_volatile : detail::_add_volatile<T> {};
@@ -331,9 +331,9 @@ template<typename T> using add_volatile_t = typename add_volatile<T>::type;
/// ///
/// \brief remove the volatile qualifier from the provided type \f$T\f$ /// \brief remove the volatile qualifier from the provided type \emph{T}
/// ///
/// \details removes references from the provided type such that \f$volatile\quad T\f$ becomes \f$T\f$ /// \details removes references from the provided type such that \emph{volatile\quad T} becomes \emph{T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_volatile : detail::_remove_volatile<T> {}; template<typename T> struct remove_volatile : detail::_remove_volatile<T> {};
@@ -344,10 +344,10 @@ template<typename T> using remove_volatile_t = typename remove_volatile<T>::type
/// ///
/// \brief remove the volatile qualifier from the provided type \f$T\f$ /// \brief remove the volatile qualifier from the provided type \emph{T}
/// ///
/// \details removes references from the provided type such that \f$T\f$, \f$const\quad T\f$, and \f$volatile\quad T\f$ /// \details removes references from the provided type such that \emph{T}, \emph{const\quad T}, and \emph{volatile\quad T}
/// become \f$const volatile T\f$ /// become \emph{const volatile T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_cv : detail::_add_cv<T> {}; template<typename T> struct add_cv : detail::_add_cv<T> {};
@@ -358,10 +358,10 @@ template<typename T> using add_cv_t = typename add_cv<T>::type;
/// ///
/// \brief remove the const and volatile qualifiers from the provided type \f$T\f$ /// \brief remove the const and volatile qualifiers from the provided type \emph{T}
/// ///
/// \details removes const and volatile from the provided type such that \f$const\quad T\f$, \f$volatile\quad T\f$, and /// \details removes const and volatile from the provided type such that \emph{const\quad T}, \emph{volatile\quad T}, and
/// \f$const\quad volatile\quad T\f$ become \f$T\f$ /// \emph{const\quad volatile\quad T} become \emph{T}
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_cv : detail::_remove_cv<T> {}; template<typename T> struct remove_cv : detail::_remove_cv<T> {};
@@ -372,7 +372,7 @@ template<typename T> using remove_cv_t = typename remove_cv<T>::type;
/// ///
/// \brief add a reference and the const volatile qualifiers from the provided type \f$T\f$ /// \brief add a reference and the const volatile qualifiers from the provided type \emph{T}
/// ///
/// \details adds references and const volatile qualifiers to the provided type. /// \details adds references and const volatile qualifiers to the provided type.
/// \tparam T Reference Type /// \tparam T Reference Type
@@ -385,7 +385,7 @@ template<typename T> using add_cvref_t = typename add_cvref<T>::type;
/// ///
/// \brief removes references as well as the const and volatile qualifiers from the provided type \f$T\f$ /// \brief removes references as well as the const and volatile qualifiers from the provided type \emph{T}
/// ///
/// \details removes const and volatile from the provided type such that /// \details removes const and volatile from the provided type such that
/// \tparam T Reference Type /// \tparam T Reference Type
@@ -399,7 +399,7 @@ template<typename T> using remove_cvref_t = typename remove_cvref<T>::type;
/// ///
/// \brief removes references and pointers as well as the const and volatile qualifiers from the provided type \f$T\f$ /// \brief removes references and pointers as well as the const and volatile qualifiers from the provided type \emph{T}
/// ///
/// \details removes const and volatile from the provided type such that /// \details removes const and volatile from the provided type such that
/// \tparam T Reference Type /// \tparam T Reference Type

View File

@@ -84,10 +84,10 @@ template<typename T> constexpr T&& forward(remove_reference_t<T>&& x) noexcept {
#endif #endif
/// \brief Copies \f$v\f$ to a new object of `decay_t<T>` /// \brief Copies \emph{v} to a new object of `decay_t<T>`
/// \tparam T The type /// \tparam T The type
/// \param v The object /// \param v The object
/// \returns A stack allocated copy of \f$v\f$ in `decay_t<T>` /// \returns A stack allocated copy of \emph{v} in `decay_t<T>`
template<typename T> constexpr decay_t<T> decay_copy(T&& v) { template<typename T> constexpr decay_t<T> decay_copy(T&& v) {
return fennec::forward<T>(v); return fennec::forward<T>(v);
} }

View File

@@ -295,11 +295,11 @@ namespace fennec
// Sign ================================================================================================================ // Sign ================================================================================================================
/// ///
/// \brief Returns \f$1\f$ if \f$x > 0\f$, \f$0\f$ if \f$x = 0\f$, or \f$-1\f$ if \f$x<0\f$ /// \brief Returns \math{1} if \math{x > 0}, \math{0} if \math{x = 0}, or \math{-1} if \math{x<0}
/// ///
/// \returns \f$1\f$ if \f$x > 0\f$, \f$0\f$ if \f$x = 0\f$, or \f$-1\f$ if \f$x<0\f$ <br><br> /// \returns \math{1} if \math{x > 0}, \math{0} if \math{x = 0}, or \math{-1} if \math{x<0} <br><br>
/// \details We can express this as, <br><br> /// \details We can express this as, <br><br>
/// \f$\text{sign}(x) = \text{sgn}(x) = \left\{\begin{array}{lr} -1 & x < 0, \\ 0 & x = 0, \\ 1 & x > 0.\end{array}\right.\f$ <br><br> /// \math{\text{sign}(x) = \text{sgn}(x) = \left\{\begin{array}{lr} -1 & x < 0, \\ 0 & x = 0, \\ 1 & x > 0.\end{array}\right.} <br><br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -311,11 +311,11 @@ constexpr genType sign(genType x) {
// Absolute Value ====================================================================================================== // Absolute Value ======================================================================================================
/// ///
/// \brief Returns \f$x\f$ if \f$x \ge 0\f$, otherwise it returns \f$-x\f$ /// \brief Returns \math{x} if \math{x \ge 0}, otherwise returns \math{-x}
/// ///
/// \returns \f$x\f$ if \f$x \ge 0\f$, otherwise it returns \f$-x\f$. <br> <br> /// \returns \math{x} if \math{x \ge 0}, otherwise it returns \math{-x}. <br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{abs}(x)=\left|x\right|\f$.<br> <br> /// \math{\text{abs}(x)=\left|x\right|}.<br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -337,11 +337,11 @@ constexpr genType abs(genType x) {
// Floor =============================================================================================================== // Floor ===============================================================================================================
/// ///
/// \brief Returns a value equal to the nearest integer that is less than or equal to \f$x\f$ /// \brief Returns a value equal to the nearest integer that is less than or equal to \math{x}
/// ///
/// \returns a value equal to the nearest integer that is less than or equal to \f$x\f$ <br> <br> /// \returns a value equal to the nearest integer that is less than or equal to \math{x} <br> <br>
/// \details We can express this as,<br> <br> /// \details We can express this as,<br> <br>
/// \f$\text{floor}(x)=\lfloor x\rfloor\f$<br> <br> /// \math{\text{floor}(x)=\lfloor x\rfloor}<br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -354,11 +354,11 @@ constexpr genType floor(genType x) {
// Ceil ================================================================================================================ // Ceil ================================================================================================================
/// ///
/// \brief Returns a value equal to the nearest integer that is greater than or equal to \f$x\f$ /// \brief Returns a value equal to the nearest integer that is greater than or equal to \math{x}
/// ///
/// \returns a value equal to the nearest integer that is greater than or equal to \f$x\f$ <br> <br> /// \returns a value equal to the nearest integer that is greater than or equal to \math{x} <br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{ceil}(x)=\lceil{x}\rceil\f$ <br> <br> /// \math{\text{ceil}(x)=\lceil{x}\rceil} <br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -371,12 +371,12 @@ constexpr genType ceil(genType x) {
// Round =============================================================================================================== // Round ===============================================================================================================
/// ///
/// \brief Returns a value equal to the nearest integer. In C++, a fractional part of \f$0.5\f$ will always round up. /// \brief Returns a value equal to the nearest integer. In C++, a fractional part of \math{0.5} will always round up.
/// ///
/// \returns a value equal to the nearest integer.<br> <br> /// \returns a value equal to the nearest integer.<br> <br>
/// \details In C++, a fractional part of \f$0.5\f$ will always round up.<br> <br> /// \details In C++, a fractional part of \math{0.5} will always round up.<br> <br>
/// We can express this as, <br> <br> /// We can express this as, <br> <br>
/// \f$\text{round}(x) = \text{sgn}(x) \cdot \lfloor \left| x \right| + 0.5 \rfloor\f$<br> <br> /// \math{\text{round}(x) = \text{sgn}(x) \cdot \lfloor \left| x \right| + 0.5 \rfloor}<br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> constexpr genType round(genType x) { template<typename genType> constexpr genType round(genType x) {
@@ -388,11 +388,11 @@ template<typename genType> constexpr genType round(genType x) {
// Trunc =============================================================================================================== // Trunc ===============================================================================================================
/// ///
/// \brief Returns a value equal to the nearest integer that is less than or equal to \f$x\f$ /// \brief Returns a value equal to the nearest integer that is less than or equal to \math{x}
/// ///
/// \returns a value equal to the nearest integer that is less than or equal to \f$x\f$ <br> <br> /// \returns a value equal to the nearest integer that is less than or equal to \math{x} <br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{trunc}(x) = \text{sgn}(x) \cdot \lceil \left| x \right| - 0.5 \rceil\f$<br> <br> /// \math{\text{trunc}(x) = \text{sgn}(x) \cdot \lceil \left| x \right| - 0.5 \rceil}<br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -405,13 +405,13 @@ constexpr genType trunc(genType x) {
// Round Even ========================================================================================================== // Round Even ==========================================================================================================
/// ///
/// \brief Returns a value equal to the nearest integer. In C++, a fractional part of \f$0.5\f$ will always /// \brief Returns a value equal to the nearest integer. In C++, a fractional part of \math{0.5} will always
/// round to the nearest even integer. /// round to the nearest even integer.
/// ///
/// \returns a value equal to the nearest integer.<br> <br> /// \returns a value equal to the nearest integer.<br> <br>
/// \details In C++, a fractional part of \f$0.5\f$ will always round to the nearest even integer.<br> <br> /// \details In C++, a fractional part of \math{0.5} will always round to the nearest even integer.<br> <br>
/// We can express this as,<br> <br> /// We can express this as,<br> <br>
/// \f$\text{roundEven}() = \begin{cases}\lfloor{x}\rfloor + \text{mod}(\lfloor{x}\rfloor, 2.0) & \text{fract}(x) = 0.5, \\ \text{round}(x) \end{cases}\f$<br> <br> /// \math{\text{roundEven}() = \begin{cases}\lfloor{x}\rfloor + \text{mod}(\lfloor{x}\rfloor, 2.0) & \text{fract}(x) = 0.5, \\ \text{round}(x) \end{cases}}<br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -451,11 +451,11 @@ constexpr genType roundEven(genType x) {
// Fract =============================================================================================================== // Fract ===============================================================================================================
/// ///
/// \brief Returns \f$x - floor(x)\f$ /// \brief Returns \math{x - floor(x)}
/// ///
/// \returns \f$x - \text{floor}(x)\f$ <br> <br> /// \returns \math{x - \text{floor}(x)} <br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{fract}(x)=x-\text{floor}\f$<br> <br> /// \math{\text{fract}(x)=x-\text{floor}}<br> <br>
/// ///
/// \param x input value /// \param x input value
template<typename genType> template<typename genType>
@@ -467,11 +467,11 @@ constexpr genType fract(genType x) {
// Mod ================================================================================================================= // Mod =================================================================================================================
/// ///
/// \brief Modulus. Returns \f$x-y\cdot floor (x/y)\f$ /// \brief Modulus. Returns \math{x-y\cdot floor (x/y)}
/// ///
/// \returns \f$x-y\cdot\text{floor}(x/y)\f$ <br> <br> /// \returns \math{x-y\cdot\text{floor}(x/y)} <br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{fract}(x)=x-\text{floor}(\frac{x}{y})\f$<br> <br> /// \math{\text{fract}(x)=x-\text{floor}(\frac{x}{y})}<br> <br>
/// ///
/// \param x dividend /// \param x dividend
/// \param y divisor /// \param y divisor
@@ -484,11 +484,11 @@ constexpr genType mod(genType x, genType y) {
// ModF ================================================================================================================ // ModF ================================================================================================================
/// ///
/// \brief Returns the fractional part of \f$x\f$ and stores the integral part in \f$i\f$. /// \brief Returns the fractional part of \math{x} and stores the integral part in \math{i}.
/// ///
/// \returns the fractional part of \f$x\f$ and stores the integral part in \f$i\f$. <br> <br> /// \returns the fractional part of \math{x} and stores the integral part in \math{i}. <br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{modf}(x) = \text{trunc}(x),\, i := \text{fract}(x)\f$ <br> <br> /// \math{\text{modf}(x) = \text{trunc}(x),\, i := \text{fract}(x)} <br> <br>
/// ///
/// \param x input value /// \param x input value
/// \param i integral out /// \param i integral out
@@ -501,14 +501,14 @@ constexpr genType modf(genType x, genType& i) {
// Is NaN ============================================================================================================== // Is NaN ==============================================================================================================
/// ///
/// \brief Returns **true** if \f$x\f$ holds a NaN. Returns **false** otherwise. /// \brief Returns **true** if \math{x} holds a NaN. Returns **false** otherwise.
/// ///
/// \returns **true** if \f$x\f$ holds a NaN. Returns **false** otherwise. <br> <br> /// \returns **true** if \math{x} holds a NaN. Returns **false** otherwise. <br> <br>
/// \details \f$NaN\f$ is a concept unique to computing. It strictly means, and more specifically, /// \details \math{NaN} is a concept unique to computing. It strictly means, and more specifically,
/// floating point values can only represent *real* numbers. This is why some functions, /// floating point values can only represent *real* numbers. This is why some functions,
/// like \ref fennec::sqrt "sqrt()", return \f$NaN\f$ when an expression would return /// like \ref fennec::sqrt "sqrt()", return \math{NaN} when an expression would return
/// a value in a different coordinate space. There are other cases, such as \f$\frac{1}{x}\f$, /// a value in a different coordinate space. There are other cases, such as \math{\frac{1}{x}},
/// where \f$x=0\f$ is undefined, and respectively the return value is also \f$NaN\f$. <br> <br> /// where \math{x=0} is undefined, and respectively the return value is also \math{NaN}. <br> <br>
/// ///
/// To learn more, see [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) <br> <br> /// To learn more, see [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) <br> <br>
/// ///
@@ -522,10 +522,10 @@ constexpr genBType isnan(genType x) {
// Is Inf ============================================================================================================== // Is Inf ==============================================================================================================
/// ///
/// \brief Returns **true** if \f$x\f$ holds a positive or negative infinity. Returns **false** otherwise. <br> <br> /// \brief Returns **true** if \math{x} holds a positive or negative infinity. Returns **false** otherwise. <br> <br>
/// ///
/// \returns **true** if \f$x\f$ holds a positive or negative infinity. Returns **false** otherwise. /// \returns **true** if \math{x} holds a positive or negative infinity. Returns **false** otherwise.
/// \details \f$\inf\f$, or \f$\infty\f$, is used to express any function that is boundless, endless, or larger /// \details \math{\inf}, or \math{\infty}, is used to express any function that is boundless, endless, or larger
/// than any natural number. This function has applications in Set Theory and Mathematical Analysis. <br> <br> /// than any natural number. This function has applications in Set Theory and Mathematical Analysis. <br> <br>
/// ///
/// \param x input value /// \param x input value
@@ -553,13 +553,13 @@ constexpr genIType floatBitsToInt(genType x) {
/// \returns a signed or unsigned integer value representing the encoding of a floating-point value. /// \returns a signed or unsigned integer value representing the encoding of a floating-point value.
/// The float value's bit-level representation is preserved. <br> <br> /// The float value's bit-level representation is preserved. <br> <br>
/// \details we can express this in set theory, i.e. <br> <br> /// \details we can express this in set theory, i.e. <br> <br>
/// let \f$B\f$ be a set, such that, \f$B=\left\lbrace{b_{0},...b_{32}}\right\rbrace\f$ and \f$b_{i} \in S\f$ where \f$S=\left\lbrace{0, 1}\right\rbrace\f$<br> /// let \math{B} be a set, such that, \math{B=\left\lbrace{b_{0},...b_{32}}\right\rbrace} and \math{b_{i} \in S} where \math{S=\left\lbrace{0, 1}\right\rbrace}<br>
/// let \f$m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}\f$<br> /// let \math{m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}}<br>
/// let \f$p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127\f$<br> /// let \math{p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127}<br>
/// let \f$s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\f$<br> <br> /// let \math{s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}}<br> <br>
/// then, \f$x_B=s_B m_B 2^{p_B}\f$<br> /// then, \math{x_B=s_B m_B 2^{p_B}}<br>
/// and, \f$i_B=-b_{31} 2^{31}+\sum_{i=0}^{30}{a_i 2^i}\f$<br> /// and, \math{i_B=-b_{31} 2^{31}+\sum_{i=0}^{30}{a_i 2^i}}<br>
/// and, \f$u_B=\sum_{i=0}^{31}{a_i 2^i}\f$<br> <br> /// and, \math{u_B=\sum_{i=0}^{31}{a_i 2^i}}<br> <br>
/// ///
/// \param x value to convert /// \param x value to convert
template<typename genType, typename genUType = uint_t> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType)) template<typename genType, typename genUType = uint_t> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
@@ -581,13 +581,13 @@ constexpr genType intBitsToFloat(genIType x) {
/// ///
/// \returns a floating-point value corresponding to a signed or unsigned integer encoding of a floating-point value. <br> <br> /// \returns a floating-point value corresponding to a signed or unsigned integer encoding of a floating-point value. <br> <br>
/// \details we can express this in set theory, i.e. <br> <br> /// \details we can express this in set theory, i.e. <br> <br>
/// let \f$B\f$ be a set, such that, \f$B=\left\lbrace{b_{0},...b_{32}}\right\rbrace\f$ and \f$b_{i} \in S\f$ where \f$S=\left\lbrace{0, 1}\right\rbrace\f$<br> /// let \math{B} be a set, such that, \math{B=\left\lbrace{b_{0},...b_{32}}\right\rbrace} and \math{b_{i} \in S} where \math{S=\left\lbrace{0, 1}\right\rbrace}<br>
/// let \f$m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}\f$<br> /// let \math{m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}}<br>
/// let \f$p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127\f$<br> /// let \math{p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127}<br>
/// let \f$s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\f$<br> <br> /// let \math{s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}}<br> <br>
/// then, \f$x_B=s_B m_B 2^{p_B}\f$<br> /// then, \math{x_B=s_B m_B 2^{p_B}}<br>
/// and, \f$i_B=-b_{31} 2^31+\sum_{i=0}^{30}{a_i 2^i}\f$<br> /// and, \math{i_B=-b_{31} 2^31+\sum_{i=0}^{30}{a_i 2^i}}<br>
/// and, \f$u_B=\sum_{i=0}^{31}{a_i 2^i}\f$<br> <br> /// and, \math{u_B=\sum_{i=0}^{31}{a_i 2^i}}<br> <br>
/// ///
/// \param x value to convert /// \param x value to convert
template<typename genType = float_t, typename genUType = uint_t> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType)) template<typename genType = float_t, typename genUType = uint_t> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
@@ -600,9 +600,9 @@ constexpr genType uintBitsToFloat(genUType x) {
// fma ================================================================================================================= // fma =================================================================================================================
/// ///
/// \brief Computes and returns \f$a \cdot b + c\f$. <br> <br> /// \brief Computes and returns \math{a \cdot b + c}. <br> <br>
/// ///
/// \returns \f$a \cdot b + c\f$. /// \returns \math{a \cdot b + c}.
/// \details In C++, this function will use the [fused multiply-add](https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation), /// \details In C++, this function will use the [fused multiply-add](https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation),
/// when the instruction is present on the target architecture. <br> <br> /// when the instruction is present on the target architecture. <br> <br>
/// ///
@@ -619,16 +619,16 @@ constexpr genType fma(genType a, genType b, genType c) {
// frexp =============================================================================================================== // frexp ===============================================================================================================
/// ///
/// \brief Splits \f$x\f$ into a floating-point significand in the range \f$[0.5,1.0]\f$, and an integral exponent of two, /// \brief Splits \math{x} into a floating-point significand in the range \math{[0.5,1.0]}, and an integral exponent of two,
/// such that \f$x=sig \cdot 2^{exp}\f$. /// such that \math{x=sig \cdot 2^{exp}}.
/// ///
/// \returns The significand of the expression.<br> <br> /// \returns The significand of the expression.<br> <br>
/// \details The significand is returned by the function and the exponent is returned in the parameter \f$exp\f$. /// \details The significand is returned by the function and the exponent is returned in the parameter \math{exp}.
/// For a floating-point value of zero, the significand and exponent are both zero. If an implementation /// For a floating-point value of zero, the significand and exponent are both zero. If an implementation
/// supports signed zero, an input value of minus zero should return a significand of minus zero. For a /// supports signed zero, an input value of minus zero should return a significand of minus zero. For a
/// floating-point value that is an infinity or is not a number, the results are undefined. If the input /// floating-point value that is an infinity or is not a number, the results are undefined. If the input
/// \f$x\f$ is a vector, this operation is performed in a component-wise manner; the value returned by the /// \math{x} is a vector, this operation is performed in a component-wise manner; the value returned by the
/// function and the value written to \f$exp\f$ are vectors with the same number of components as \f$x\f$. <br> <br> /// function and the value written to \math{exp} are vectors with the same number of components as \math{x}. <br> <br>
/// ///
/// \param x The floating-point value to split /// \param x The floating-point value to split
/// \param exp The variable to store the exponent in /// \param exp The variable to store the exponent in
@@ -642,11 +642,11 @@ constexpr genType frexp(genType x, genIType& exp) {
// ldexp =============================================================================================================== // ldexp ===============================================================================================================
/// ///
/// \brief Builds a floating-point number from \f$x\f$ and the corresponding integral exponent of two in \f$exp\f$ /// \brief Builds a floating-point number from \math{x} and the corresponding integral exponent of two in \math{exp}
/// ///
/// \returns \f${x}\cdot{2^{exp}}\f$ /// \returns \math{{x}\cdot{2^{exp}}}
/// \details Builds a floating-point number from x and the corresponding integral exponent of two in exp, /// \details Builds a floating-point number from x and the corresponding integral exponent of two in exp,
/// returning: \f${x}\cdot{2^{exp}}\f$. If this product is too large to be represented in the floating-point /// returning: \math{{x}\cdot{2^{exp}}}. If this product is too large to be represented in the floating-point
/// type, the result is undefined. If exp is greater than +128 (single-precision) or +1024 (double-precision), /// type, the result is undefined. If exp is greater than +128 (single-precision) or +1024 (double-precision),
/// the value returned is undefined. If exp is less than -126 (single-precision) or -1022 (double-precision), /// the value returned is undefined. If exp is less than -126 (single-precision) or -1022 (double-precision),
/// the value returned may be flushed to zero. Additionally, splitting the value into a significand and /// the value returned may be flushed to zero. Additionally, splitting the value into a significand and
@@ -676,14 +676,14 @@ constexpr genType ldexp(genType x, genIType exp) {
// Min ================================================================================================================= // Min =================================================================================================================
/// ///
/// \brief Returns \f$y\f$ if \f$x<y;\f$ otherwise it returns \f$x\f$ /// \brief Returns \math{y} if \math{x<y;} otherwise it returns \math{x}
/// ///
/// \returns \f$y\f$ if \f$x<y\f$, otherwise it returns \f$x\f$<br> <br> /// \returns \math{y} if \math{x<y}, otherwise it returns \math{x}<br> <br>
/// \details We can express this as,<br> <br> /// \details We can express this as,<br> <br>
/// \f$\text{min}(x, y)=\begin{cases}y, & y < x \\ x\end{cases}\f$<br> <br> /// \math{\text{min}(x, y)=\begin{cases}y, & y < x \\ x\end{cases}}<br> <br>
/// ///
/// \param x input value \f$x\f$ /// \param x input value \math{x}
/// \param y input value \f$y\f$ /// \param y input value \math{y}
template<typename genType> template<typename genType>
constexpr genType min(genType x, genType y) { constexpr genType min(genType x, genType y) {
return (y < x) ? y : x; return (y < x) ? y : x;
@@ -693,11 +693,11 @@ constexpr genType min(genType x, genType y) {
// Max ================================================================================================================= // Max =================================================================================================================
/// ///
/// \brief Returns \f$y\f$ if \f$y<x\f$, otherwise it returns \f$x\f$ /// \brief Returns \math{y} if \math{y<x}, otherwise it returns \math{x}
/// ///
/// \returns \f$y\f$ if \f$y<x\f$, otherwise it returns \f$x\f$<br> <br> /// \returns \math{y} if \math{y<x}, otherwise it returns \math{x}<br> <br>
/// \details We can express this as,<br> <br> /// \details We can express this as,<br> <br>
/// \f$\text{max}(x, y)=\begin{cases}y, & x < y \\ x\end{cases}\f$<br> <br> /// \math{\text{max}(x, y)=\begin{cases}y, & x < y \\ x\end{cases}}<br> <br>
/// ///
/// \param x first input value /// \param x first input value
/// \param y second input value /// \param y second input value
@@ -710,11 +710,11 @@ constexpr genType max(genType x, genType y) {
// Clamp =============================================================================================================== // Clamp ===============================================================================================================
/// ///
/// \brief Returns \f$min (max (x, minVal), maxVal)\f$ /// \brief Returns \math{min (max (x, minVal), maxVal)}
/// ///
/// \returns \f$\text{min}(\text{max}(x, minVal), maxVal)\f$. Results are undefined if \f$minVal > maxVal\f$<br> <br> /// \returns \math{\text{min}(\text{max}(x, minVal), maxVal)}. Results are undefined if \math{minVal > maxVal}<br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{clamp}(x, min, max)=\begin{cases}min, & x < min \\ x \\ max, & x > max\end{cases}\f$<br> <br> /// \math{\text{clamp}(x, min, max)=\begin{cases}min, & x < min \\ x \\ max, & x > max\end{cases}}<br> <br>
/// ///
/// \param x input value /// \param x input value
/// \param minVal minimum value /// \param minVal minimum value
@@ -738,13 +738,13 @@ constexpr genType clamp(genType x, genType minVal, genType maxVal) {
// Step ================================================================================================================ // Step ================================================================================================================
/// ///
/// \brief Returns \f$0.0\f$ if \f$x<edge\f$, otherwise, it returns \f$1.0\f$ /// \brief Returns \math{0.0} if \math{x<edge}, otherwise, it returns \math{1.0}
/// ///
/// \returns \f$0.0\f$ if \f$x<edge\f$, otherwise, it returns \f$1.0\f$<br> <br> /// \returns \math{0.0} if \math{x<edge}, otherwise, it returns \math{1.0}<br> <br>
/// \details We can express this as, <br> <br> /// \details We can express this as, <br> <br>
/// \f$\text{step}(edge, x)=\begin{cases}0.0 & x < edge \\ 1.0 \end{cases}\f$<br> <br> /// \math{\text{step}(edge, x)=\begin{cases}0.0 & x < edge \\ 1.0 \end{cases}}<br> <br>
/// ///
/// \param edge The \f$x\f$ coordinate of the discontinuity /// \param edge The \math{x} coordinate of the discontinuity
/// \param x The coordinate of the sample location /// \param x The coordinate of the sample location
template<typename genType> requires(is_floating_point_v<genType>) template<typename genType> requires(is_floating_point_v<genType>)
constexpr genType step(genType edge, genType x) { constexpr genType step(genType edge, genType x) {
@@ -755,11 +755,11 @@ constexpr genType step(genType edge, genType x) {
// Smoothstep ========================================================================================================== // Smoothstep ==========================================================================================================
/// ///
/// \brief Returns \f$0.0\f$ if \f$x\le edge0\f$ and \f$1.0\f$ if \f$x\ge edge1\f$, and performs smooth Hermite /// \brief Returns \math{0.0} if \math{x\le edge0} and \math{1.0} if \math{x\ge edge1}, and performs smooth Hermite
/// interpolation between \f$0\f$ and \f$1\f$ when \f$edge0<x<edge1\f$. /// interpolation between \math{0} and \math{1} when \math{edge0<x<edge1}.
/// ///
/// \returns \f$0.0\f$ if \f$x\le edge0\f$ and \f$1.0\f$ if \f$x\ge edge1\f$, and performs smooth Hermite /// \returns \math{0.0} if \math{x\le edge0} and \math{1.0} if \math{x\ge edge1}, and performs smooth Hermite
/// interpolation between \f$0\f$ and \f$1\f$ when \f$edge0<x<edge1\f$. <br> <br> /// interpolation between \math{0} and \math{1} when \math{edge0<x<edge1}. <br> <br>
/// \details This is useful in cases where you would want a threshold function with a smooth transition.<br> <br> /// \details This is useful in cases where you would want a threshold function with a smooth transition.<br> <br>
/// This is equivalent to: <br> <br> /// This is equivalent to: <br> <br>
/// \code{.glsl} /// \code{.glsl}
@@ -767,13 +767,13 @@ constexpr genType step(genType edge, genType x) {
/// t = clamp((x - edge0) / (edge1 - edge0), 0, 1); /// t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
/// return t * t * (3 - 2 * t); /// return t * t * (3 - 2 * t);
/// \endcode<br> /// \endcode<br>
/// Results are undefined if \f$edge0\ge edge1\f$. <br> <br> /// Results are undefined if \math{edge0\ge edge1}. <br> <br>
/// We can express this as,<br> <br> /// We can express this as,<br> <br>
/// \f$\text{smoothstep}(e_0, e_1, x)=\begin{cases}0, & {x}\le{e_0} \\ 3{\frac{x-e_0}{e_1-e_0}}^{2} - 2{\frac{x-e_0}{e_1-e_0}}^{3}, & {e_0}\le{x}\le{e_1} \\ 1, & {1}\le{e_x}\end{cases}\f$<br> <br> /// \math{\text{smoothstep}(e_0, e_1, x)=\begin{cases}0, & {x}\le{e_0} \\ 3{\frac{x-e_0}{e_1-e_0}}^{2} - 2{\frac{x-e_0}{e_1-e_0}}^{3}, & {e_0}\le{x}\le{e_1} \\ 1, & {1}\le{e_x}\end{cases}}<br> <br>
/// ///
/// \param edge0 \f$x\f$ value where the function returns \f$0.0\f$ /// \param edge0 \math{x} value where the function returns \math{0.0}
/// \param edge1 \f$x\f$ value where the function returns \f$1.0\f$ /// \param edge1 \math{x} value where the function returns \math{1.0}
/// \param x \f$x\f$ coordinate input /// \param x \math{x} coordinate input
template<typename genType> requires(is_floating_point_v<genType>) template<typename genType> requires(is_floating_point_v<genType>)
constexpr genType smoothstep(genType edge0, genType edge1, genType x) { constexpr genType smoothstep(genType edge0, genType edge1, genType x) {
genType t = fennec::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); return t * t * (3 - 2 * t); genType t = fennec::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); return t * t * (3 - 2 * t);
@@ -783,13 +783,13 @@ constexpr genType smoothstep(genType edge0, genType edge1, genType x) {
// Mix ================================================================================================================= // Mix =================================================================================================================
/// ///
/// \brief Returns the linear blend of \f$x\f$ and \f$y\f$, i.e., \f$x \cdot (1-a) + y \cdot a\f$ /// \brief Returns the linear blend of \math{x} and \math{y}, i.e., \math{x \cdot (1-a) + y \cdot a}
/// ///
/// \returns the linear blend of \f$x\f$ and \f$y\f$, i.e., \f$x \cdot (1-a) + y \cdot a\f$<br> <br> /// \returns the linear blend of \math{x} and \math{y}, i.e., \math{x \cdot (1-a) + y \cdot a}<br> <br>
/// \details We can express this as,<br> <br> /// \details We can express this as,<br> <br>
/// \f$\text{mix}(x, y, a)=x+a \cdot (y - x)\f$<br> <br> /// \math{\text{mix}(x, y, a)=x+a \cdot (y - x)}<br> <br>
/// The reason for the difference between the mathematical definition and the glsl definition is /// The reason for the difference between the mathematical definition and the glsl definition is
/// due to floating-point precision errors. Multiplying \f$x\f$ and \f$y\f$ separately preserves /// due to floating-point precision errors. Multiplying \math{x} and \math{y} separately preserves
/// their precision before the addition happens. /// their precision before the addition happens.
/// ///
/// \param x First value /// \param x First value
@@ -806,14 +806,14 @@ constexpr genType mix(genType x, genType y, genType a) {
/// ///
/// \brief Selects which value to return. For Vectors, when the boolean is a scalar, it selects the vector, otherwise, each component is selected. /// \brief Selects which value to return. For Vectors, when the boolean is a scalar, it selects the vector, otherwise, each component is selected.
/// ///
/// \returns \f$x\f$ when \f$a=T\f$, otherwise returns \f$y\f$ /// \returns \math{x} when \math{a=T}, otherwise returns \math{y}
/// \details Selects which value to return. For Vectors, when the boolean is a scalar, /// \details Selects which value to return. For Vectors, when the boolean is a scalar,
/// it selects the vector, otherwise, each component is selected. <br> <br> /// it selects the vector, otherwise, each component is selected. <br> <br>
/// This implementation uses the ternary operator:<br> /// This implementation uses the ternary operator:<br>
/// \code{.cpp}return a ? x : y;\endcode /// \code{.cpp}return a ? x : y;\endcode
/// Which will get reduced down to a conditional move instruction over branching.<br> <br> /// Which will get reduced down to a conditional move instruction over branching.<br> <br>
/// We can express this as,<br> <br> /// We can express this as,<br> <br>
/// \f$\text{mix}(x, y, A) = \begin{cases} x, & A=T \\ y & A=F \end{cases}\f$<br> <br> /// \math{\text{mix}(x, y, A) = \begin{cases} x, & A=T \\ y & A=F \end{cases}}<br> <br>
/// ///
/// \param x True Value /// \param x True Value
/// \param y False Value /// \param y False Value

View File

@@ -19,10 +19,37 @@
#ifndef FENNEC_MATH_DETAIL_MATH_H #ifndef FENNEC_MATH_DETAIL_MATH_H
#define FENNEC_MATH_DETAIL_MATH_H #define FENNEC_MATH_DETAIL_MATH_H
// Handle including C math.h
// Unfortunately, each compiler needs its own if case in the macro chain below
#if FENNEC_COMPILER_CLANG // Clang
// Temporarily disable macro redefinition warning
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wbuiltin-macro-redefined"
// Undefine __cpluscplus macro to force using the C header
#pragma push_macro("__cplusplus") #pragma push_macro("__cplusplus")
#undef __cplusplus #undef __cplusplus
// Include math.h
#include <math.h> #include <math.h>
// Restore __cpluscplus definition and macro redefinition warning
#pragma pop_macro("__cplusplus") #pragma pop_macro("__cplusplus")
#pragma clang diagnostic pop
#elif FENNEC_COMPILER_GCC // GCC
// This definition tells GCC to just use the C header, thanks GCC!!!
#ifndef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#endif
#include <math.h>
#endif
#undef div #undef div
#undef acos #undef acos

View File

@@ -97,10 +97,10 @@ namespace fennec
// pow ================================================================================================================= // pow =================================================================================================================
/// ///
/// \brief Returns \f$x\f$ raised to the \f$y\f$ power, i.e., \f$x^y\f$. /// \brief Returns \math{x} raised to the \math{y} power, i.e., \math{x^y}.
/// ///
/// \returns \f$x\f$ raised to the \f$y\f$ power, i.e., \f$x^y\f$.<br><br> /// \returns \math{x} raised to the \math{y} power, i.e., \math{x^y}.<br><br>
/// \details Results are undefined if \f$x<0\f$. <br><br>Results are undefined if \f$x=0\f$ and \f${y}\le{0}\f$.<br><br> /// \details Results are undefined if \math{x<0}. <br><br>Results are undefined if \math{x=0} and \math{{y}\le{0}}.<br><br>
/// ///
/// \param x the base /// \param x the base
/// \param y the exponent /// \param y the exponent
@@ -113,9 +113,9 @@ constexpr genType pow(genType x, genType y) {
// exp ================================================================================================================= // exp =================================================================================================================
/// ///
/// \brief Returns the natural exponentiation of \f$x\f$, i.e., \f$e^x\f$ /// \brief Returns the natural exponentiation of \math{x}, i.e., \math{e^x}
/// ///
/// \returns the natural exponentiation of \f$x\f$, i.e., \f$e^x\f$.<br><br> /// \returns the natural exponentiation of \math{x}, i.e., \math{e^x}.<br><br>
/// ///
/// \param x the exponent /// \param x the exponent
template<typename genType> template<typename genType>
@@ -127,9 +127,9 @@ constexpr genType exp(genType x) {
// exp2 ================================================================================================================ // exp2 ================================================================================================================
/// ///
/// \brief Returns 2 raised to the \f$x\f$ power, i.e., \f$e^x\f$ /// \brief Returns 2 raised to the \math{x} power, i.e., \math{e^x}
/// ///
/// \returns 2 raised to the \f$x\f$ power, i.e., \f$e^x\f$<br><br> /// \returns 2 raised to the \math{x} power, i.e., \math{e^x}<br><br>
/// ///
/// \param x the exponent /// \param x the exponent
template<typename genType> constexpr genType exp2(genType x) { template<typename genType> constexpr genType exp2(genType x) {
@@ -140,10 +140,10 @@ template<typename genType> constexpr genType exp2(genType x) {
// log ================================================================================================================= // log =================================================================================================================
/// ///
/// \brief Returns the natural logarithm of \f$x\f$. /// \brief Returns the natural logarithm of \math{x}.
/// ///
/// \returns the natural logarithm of \f$x\f$, i.e., returns the value \f$y\f$ which satisfies the equation \f$x=e^y\f$.<br><br> /// \returns the natural logarithm of \math{x}, i.e., returns the value \math{y} which satisfies the equation \math{x=e^y}.<br><br>
/// \details Results are undefined if \f${x}\le{0}\f$.<br><br> /// \details Results are undefined if \math{{x}\le{0}}.<br><br>
/// ///
/// \param x the input value /// \param x the input value
template<typename genType> constexpr genType log(genType x) { template<typename genType> constexpr genType log(genType x) {
@@ -154,11 +154,11 @@ template<typename genType> constexpr genType log(genType x) {
// log2 ================================================================================================================ // log2 ================================================================================================================
/// ///
/// \brief Returns the base 2 logarithm of \f$x\f$. /// \brief Returns the base 2 logarithm of \math{x}.
/// ///
/// \returns the base 2 logarithm of \f$x\f$, i.e., returns the value \f$y\f$ which satisfies the equation /// \returns the base 2 logarithm of \math{x}, i.e., returns the value \math{y} which satisfies the equation
/// \f$x=2^y\f$. <br><br> /// \math{x=2^y}. <br><br>
/// \details Results are undefined if \f${x}\le{0}\f$. <br><br> /// \details Results are undefined if \math{{x}\le{0}}. <br><br>
/// ///
/// \param x the input value /// \param x the input value
template<typename genType> constexpr genType log2(genType x) { template<typename genType> constexpr genType log2(genType x) {
@@ -169,10 +169,10 @@ template<typename genType> constexpr genType log2(genType x) {
// sqrt ================================================================================================================ // sqrt ================================================================================================================
/// ///
/// \brief Returns \f$\sqrt{x}\f$. /// \brief Returns \math{\sqrt{x}}.
/// ///
/// \returns \f$\sqrt{x}\f$. <br><br> /// \returns \math{\sqrt{x}}. <br><br>
/// \details Results are undefined if \f$x<0\f$<br><br> /// \details Results are undefined if \math{x<0}<br><br>
/// ///
/// \param x the input value /// \param x the input value
template<typename genType> constexpr genType sqrt(genType x) { template<typename genType> constexpr genType sqrt(genType x) {
@@ -183,10 +183,10 @@ template<typename genType> constexpr genType sqrt(genType x) {
// inversesqrt ========================================================================================================= // inversesqrt =========================================================================================================
/// ///
/// \brief Returns \f$\frac{1}{\sqrt{x}}\f$. /// \brief Returns \math{\frac{1}{\sqrt{x}}}.
/// ///
/// \returns \f$\frac{1}{\sqrt{x}}\f$.<br><br> /// \returns \math{\frac{1}{\sqrt{x}}}.<br><br>
/// \details Results are undefined if \f$x<0\f$.<br><br> /// \details Results are undefined if \math{x<0}.<br><br>
/// ///
/// \param x the input value /// \param x the input value
template<typename genType> constexpr genType inversesqrt(genType x) { template<typename genType> constexpr genType inversesqrt(genType x) {

View File

@@ -546,148 +546,148 @@ namespace fennec
// Rational Constants ================================================================================================== // Rational Constants ==================================================================================================
template<typename genType> constexpr genType zero() { return genType(0); } //!< \returns The value of \f$0\f$ template<typename genType> constexpr genType zero() { return genType(0); } //!< \returns The value of \math{0}
template<typename genType> constexpr genType one() { return genType(1); } //!< \returns The value of \f$1\f$ template<typename genType> constexpr genType one() { return genType(1); } //!< \returns The value of \math{1}
template<typename genType> constexpr genType one_half() { return genType(0.5); } //!< \returns The value of \f$\frac{1}{2}\f$ template<typename genType> constexpr genType one_half() { return genType(0.5); } //!< \returns The value of \math{\frac{1}{2}}
template<typename genType> constexpr genType three_over_two() { return genType(1.5); } //!< \returns The value of \f$\frac{3}{2}\f$ template<typename genType> constexpr genType three_over_two() { return genType(1.5); } //!< \returns The value of \math{\frac{3}{2}}
// Irrational Constants ================================================================================================ // Irrational Constants ================================================================================================
template<typename genType> constexpr genType one_third() { return 0.33333333333333333333333333333333333333333333333333; } //!< \returns The value of \f$\frac{1}{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_third() { return 0.33333333333333333333333333333333333333333333333333; } //!< \returns The value of \math{\frac{1}{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType two_thirds() { return 0.66666666666666666666666666666666666666666666666666; } //!< \returns The value of \f$\frac{2}{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_thirds() { return 0.66666666666666666666666666666666666666666666666666; } //!< \returns The value of \math{\frac{2}{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_two() { return 1.41421356237309504880168872420969807856967187537694; } //!< \returns The value of \f$\sqrt{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_two() { return 1.41421356237309504880168872420969807856967187537694; } //!< \returns The value of \math{\sqrt{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_three() { return 1.73205080756887729352744634150587236694280525381038; } //!< \returns The value of \f$\sqrt{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_three() { return 1.73205080756887729352744634150587236694280525381038; } //!< \returns The value of \math{\sqrt{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_five() { return 2.23606797749978969640917366873127623544061835961152; } //!< \returns The value of \f$\sqrt{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_five() { return 2.23606797749978969640917366873127623544061835961152; } //!< \returns The value of \math{\sqrt{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_seven() { return 2.64575131106459059050161575363926042571025918308245; } //!< \returns The value of \f$\sqrt{7}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_seven() { return 2.64575131106459059050161575363926042571025918308245; } //!< \returns The value of \math{\sqrt{7}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_ten() { return 3.16227766016837933199889354443271853371955513932521; } //!< \returns The value of \f$\sqrt{10}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_ten() { return 3.16227766016837933199889354443271853371955513932521; } //!< \returns The value of \math{\sqrt{10}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_sqrt_two() { return 0.70710678118654752440084436210484903928483593768847; } //!< \returns The value of \f$\frac{1}{\sqrt{2}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_sqrt_two() { return 0.70710678118654752440084436210484903928483593768847; } //!< \returns The value of \math{\frac{1}{\sqrt{2}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_sqrt_three() { return 0.57735026918962576450914878050195745564760175127012; } //!< \returns The value of \f$\frac{1}{\sqrt{3}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_sqrt_three() { return 0.57735026918962576450914878050195745564760175127012; } //!< \returns The value of \math{\frac{1}{\sqrt{3}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_sqrt_five() { return 0.44721359549995793928183473374625524708812367192230; } //!< \returns The value of \f$\frac{1}{\sqrt{5}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_sqrt_five() { return 0.44721359549995793928183473374625524708812367192230; } //!< \returns The value of \math{\frac{1}{\sqrt{5}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType cbrt_two() { return 1.25992104989487316476721060727822835057025146470150; } //!< \returns The value of \f$\sqrt[3]{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType cbrt_two() { return 1.25992104989487316476721060727822835057025146470150; } //!< \returns The value of \math{\sqrt[3]{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType qdrt_two() { return 1.18920711500272106671749997056047591529297209246381; } //!< \returns The value of \f$\sqrt[4]{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType qdrt_two() { return 1.18920711500272106671749997056047591529297209246381; } //!< \returns The value of \math{\sqrt[4]{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType two_raised_sqrt_two() { return 2.66514414269022518865029724987313984827421131371465; } //!< \returns The value of \f${2}^{\sqrt{2}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_raised_sqrt_two() { return 2.66514414269022518865029724987313984827421131371465; } //!< \returns The value of \math{{2}^{\sqrt{2}}} with the highest precision for \emph{genType}
// Pi ================================================================================================================== // Pi ==================================================================================================================
// Pi & Tau // Pi & Tau
template<typename genType> constexpr genType pi() { return 3.14159265358979323846264338327950288419716939937510; } //!< \returns The value of \f$\pi\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType pi() { return 3.14159265358979323846264338327950288419716939937510; } //!< \returns The value of \math{\pi} with the highest precision for \emph{genType}
template<typename genType> constexpr genType tau() { return 6.28318530717958647692528676655900576839433879875021; } //!< \returns The value of \f$\tau\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType tau() { return 6.28318530717958647692528676655900576839433879875021; } //!< \returns The value of \math{\tau} with the highest precision for \emph{genType}
// Multiples of Pi // Multiples of Pi
template<typename genType> constexpr genType two_pi() { return 6.28318530717958647692528676655900576839433879875021; } //!< \returns The value of \f$2\pi\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_pi() { return 6.28318530717958647692528676655900576839433879875021; } //!< \returns The value of \math{2\pi} with the highest precision for \emph{genType}
template<typename genType> constexpr genType three_pi() { return 9.42477796076937971538793014983850865259150819812531; } //!< \returns The value of \f$3\pi\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType three_pi() { return 9.42477796076937971538793014983850865259150819812531; } //!< \returns The value of \math{3\pi} with the highest precision for \emph{genType}
template<typename genType> constexpr genType four_pi() { return 12.56637061435917295385057353311801153678867759750042; } //!< \returns The value of \f$4\pi\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType four_pi() { return 12.56637061435917295385057353311801153678867759750042; } //!< \returns The value of \math{4\pi} with the highest precision for \emph{genType}
// Fractions of Pi // Fractions of Pi
template<typename genType> constexpr genType half_pi() { return 1.57079632679489661923132169163975144209858469968755; } //!< \returns The value of \f$\frac{\pi}{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType half_pi() { return 1.57079632679489661923132169163975144209858469968755; } //!< \returns The value of \math{\frac{\pi}{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType three_halves_pi() { return 4.71238898038468985769396507491925432629575409906265; } //!< \returns The value of \f$\frac{3\pi}{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType three_halves_pi() { return 4.71238898038468985769396507491925432629575409906265; } //!< \returns The value of \math{\frac{3\pi}{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType third_pi() { return 1.04719755119659774615421446109316762806572313312503; } //!< \returns The value of \f$\frac{\pi}{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType third_pi() { return 1.04719755119659774615421446109316762806572313312503; } //!< \returns The value of \math{\frac{\pi}{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType two_thirds_pi() { return 2.09439510239319549230842892218633525613144626625007; } //!< \returns The value of \f$\frac{2\pi}{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_thirds_pi() { return 2.09439510239319549230842892218633525613144626625007; } //!< \returns The value of \math{\frac{2\pi}{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType four_thirds_pi() { return 4.18879020478639098461685784437267051226289253250014; } //!< \returns The value of \f$\frac{4\pi}{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType four_thirds_pi() { return 4.18879020478639098461685784437267051226289253250014; } //!< \returns The value of \math{\frac{4\pi}{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType five_thirds_pi() { return 5.23598775598298873077107230546583814032861566562517; } //!< \returns The value of \f$\frac{5\pi}{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType five_thirds_pi() { return 5.23598775598298873077107230546583814032861566562517; } //!< \returns The value of \math{\frac{5\pi}{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType quarter_pi() { return 0.78539816339744830961566084581987572104929234984377; } //!< \returns The value of \f$\frac{\pi}{4}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType quarter_pi() { return 0.78539816339744830961566084581987572104929234984377; } //!< \returns The value of \math{\frac{\pi}{4}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType three_quarters_pi() { return 2.35619449019234492884698253745962716314787704953132; } //!< \returns The value of \f$\frac{3\pi}{4}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType three_quarters_pi() { return 2.35619449019234492884698253745962716314787704953132; } //!< \returns The value of \math{\frac{3\pi}{4}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType five_quarters_pi() { return 3.92699081698724154807830422909937860524646174921888; } //!< \returns The value of \f$\frac{5\pi}{4}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType five_quarters_pi() { return 3.92699081698724154807830422909937860524646174921888; } //!< \returns The value of \math{\frac{5\pi}{4}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType seven_quarters_pi() { return 5.49778714378213816730962592073913004734504644890643; } //!< \returns The value of \f$\frac{7\pi}{4}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType seven_quarters_pi() { return 5.49778714378213816730962592073913004734504644890643; } //!< \returns The value of \math{\frac{7\pi}{4}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType fifth_pi() { return 0.62831853071795864769252867665590057683943387987502; } //!< \returns The value of \f$\frac{\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType fifth_pi() { return 0.62831853071795864769252867665590057683943387987502; } //!< \returns The value of \math{\frac{\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType two_fifths_pi() { return 1.25663706143591729538505735331180115367886775975004; } //!< \returns The value of \f$\frac{2\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_fifths_pi() { return 1.25663706143591729538505735331180115367886775975004; } //!< \returns The value of \math{\frac{2\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType three_fifths_pi() { return 1.88495559215387594307758602996770173051830163962506; } //!< \returns The value of \f$\frac{3\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType three_fifths_pi() { return 1.88495559215387594307758602996770173051830163962506; } //!< \returns The value of \math{\frac{3\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType four_fifths_pi() { return 2.51327412287183459077011470662360230735773551950008; } //!< \returns The value of \f$\frac{4\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType four_fifths_pi() { return 2.51327412287183459077011470662360230735773551950008; } //!< \returns The value of \math{\frac{4\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType six_fifths_pi() { return 3.76991118430775188615517205993540346103660327925012; } //!< \returns The value of \f$\frac{6\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType six_fifths_pi() { return 3.76991118430775188615517205993540346103660327925012; } //!< \returns The value of \math{\frac{6\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType seven_fifths_pi() { return 4.39822971502571053384770073659130403787603715912514; } //!< \returns The value of \f$\frac{7\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType seven_fifths_pi() { return 4.39822971502571053384770073659130403787603715912514; } //!< \returns The value of \math{\frac{7\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType eight_fifths_pi() { return 5.02654824574366918154022941324720461471547103900016; } //!< \returns The value of \f$\frac{8\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType eight_fifths_pi() { return 5.02654824574366918154022941324720461471547103900016; } //!< \returns The value of \math{\frac{8\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType nine_fifths_pi() { return 5.65486677646162782923275808990310519155490491887519; } //!< \returns The value of \f$\frac{9\pi}{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType nine_fifths_pi() { return 5.65486677646162782923275808990310519155490491887519; } //!< \returns The value of \math{\frac{9\pi}{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sixth_pi() { return 0.52359877559829887307710723054658381403286156656251; } //!< \returns The value of \f$\frac{\pi}{6}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sixth_pi() { return 0.52359877559829887307710723054658381403286156656251; } //!< \returns The value of \math{\frac{\pi}{6}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType five_sixths_pi() { return 2.61799387799149436538553615273291907016430783281258; } //!< \returns The value of \f$\frac{5\pi}{6}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType five_sixths_pi() { return 2.61799387799149436538553615273291907016430783281258; } //!< \returns The value of \math{\frac{5\pi}{6}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType seven_sixths_pi() { return 3.66519142918809211153975061382608669823003096593762; } //!< \returns The value of \f$\frac{7\pi}{6}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType seven_sixths_pi() { return 3.66519142918809211153975061382608669823003096593762; } //!< \returns The value of \math{\frac{7\pi}{6}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType eleven_sixths_pi() { return 5.75958653158128760384817953601242195436147723218769; } //!< \returns The value of \f$\frac{11\pi}{6}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType eleven_sixths_pi() { return 5.75958653158128760384817953601242195436147723218769; } //!< \returns The value of \math{\frac{11\pi}{6}} with the highest precision for \emph{genType}
// Reciprocals of Pi // Reciprocals of Pi
template<typename genType> constexpr genType one_over_pi() { return 0.31830988618379067153776752674502872406891929148091; } //!< \returns The value of \f$\frac{1}{\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_pi() { return 0.31830988618379067153776752674502872406891929148091; } //!< \returns The value of \math{\frac{1}{\pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType two_over_pi() { return 0.63661977236758134307553505349005744813783858296182; } //!< \returns The value of \f$\frac{2}{\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_over_pi() { return 0.63661977236758134307553505349005744813783858296182; } //!< \returns The value of \math{\frac{2}{\pi}} with the highest precision for \emph{genType}
// Exponentiations Pi // Exponentiations Pi
template<typename genType> constexpr genType pi_sq() { return 9.86960440108935861883449099987615113531369940724079; } //!< \returns The value of \f${\pi}^{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType pi_sq() { return 9.86960440108935861883449099987615113531369940724079; } //!< \returns The value of \math{{\pi}^{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType pi_cb() { return 31.00627668029982017547631506710139520222528856588510; } //!< \returns The value of \f${\pi}^{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType pi_cb() { return 31.00627668029982017547631506710139520222528856588510; } //!< \returns The value of \math{{\pi}^{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_pi() { return 1.77245385090551602729816748334114518279754945612238; } ///< \returns The value of \f$\sqrt{\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_pi() { return 1.77245385090551602729816748334114518279754945612238; } ///< \returns The value of \math{\sqrt{\pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_sqrt_pi() { return 0.56418958354775628694807945156077258584405062932899; } ///< \returns The value of \f$\frac{1}{\sqrt{\pi}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_sqrt_pi() { return 0.56418958354775628694807945156077258584405062932899; } ///< \returns The value of \math{\frac{1}{\sqrt{\pi}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_two_pi() { return 1.77245385090551602729816748334114518279754945612238; } ///< \returns The value of \f$\sqrt{2\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_two_pi() { return 1.77245385090551602729816748334114518279754945612238; } ///< \returns The value of \math{\sqrt{2\pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_sqrt_two_pi() { return 0.39894228040143267793994605993438186847585863116493; } ///< \returns The value of \f$\frac{1}{\sqrt{2\pi}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_sqrt_two_pi() { return 0.39894228040143267793994605993438186847585863116493; } ///< \returns The value of \math{\frac{1}{\sqrt{2\pi}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType cbrt_pi() { return 1.46459188756152326302014252726379039173859685562793; } ///< \returns The value of \f$\sqrt[3]{\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType cbrt_pi() { return 1.46459188756152326302014252726379039173859685562793; } ///< \returns The value of \math{\sqrt[3]{\pi}} with the highest precision for \emph{genType}
// e =================================================================================================================== // e ===================================================================================================================
// Multiples and Reciprocal // Multiples and Reciprocal
template<typename genType> constexpr genType e() { return 2.71828182845904523536028747135266249775724709369995; } ///< \returns The value of \f$e\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e() { return 2.71828182845904523536028747135266249775724709369995; } ///< \returns The value of \math{e} with the highest precision for \emph{genType}
template<typename genType> constexpr genType half_e() { return 1.35914091422952261768014373567633124887862354684997; } ///< \returns The value of \f$\frac{e}{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType half_e() { return 1.35914091422952261768014373567633124887862354684997; } ///< \returns The value of \math{\frac{e}{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType two_e() { return 5.43656365691809047072057494270532499551449418739991; } ///< \returns The value of \f$2e\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType two_e() { return 5.43656365691809047072057494270532499551449418739991; } ///< \returns The value of \math{2e} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_e() { return 0.36787944117144232159552377016146086744581113103176; } ///< \returns The value of \f$\frac{1}{e}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_e() { return 0.36787944117144232159552377016146086744581113103176; } ///< \returns The value of \math{\frac{1}{e}} with the highest precision for \emph{genType}
// Exponentiations of e // Exponentiations of e
template<typename genType> constexpr genType e_sq() { return 7.38905609893065022723042746057500781318031557055184; } ///< \returns The value of \f$e^2\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_sq() { return 7.38905609893065022723042746057500781318031557055184; } ///< \returns The value of \math{e^2} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_cb() { return 20.08553692318766774092852965458171789698790783855415; } ///< \returns The value of \f$e^3\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_cb() { return 20.08553692318766774092852965458171789698790783855415; } ///< \returns The value of \math{e^3} with the highest precision for \emph{genType}
template<typename genType> constexpr genType sqrt_e() { return 1.64872127070012814684865078781416357165377610071014; } ///< \returns The value of \f$\sqrt{e}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType sqrt_e() { return 1.64872127070012814684865078781416357165377610071014; } ///< \returns The value of \math{\sqrt{e}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_sqrt_e() { return 0.60653065971263342360379953499118045344191813548718; } ///< \returns The value of \f$\frac{1}{\sqrt{e}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_sqrt_e() { return 0.60653065971263342360379953499118045344191813548718; } ///< \returns The value of \math{\frac{1}{\sqrt{e}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_two() { return 7.38905609893065022723042746057500781318031557055184; } ///< \returns The value of \f$e^e\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_two() { return 7.38905609893065022723042746057500781318031557055184; } ///< \returns The value of \math{e^e} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_e() { return 15.15426224147926418976043027262991190552854853685613; } ///< \returns The value of \f$e^e\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_e() { return 15.15426224147926418976043027262991190552854853685613; } ///< \returns The value of \math{e^e} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_neg_e() { return 0.065988035845312537076790187596846424938577048252796; } ///< \returns The value of \f$e^-e\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_neg_e() { return 0.065988035845312537076790187596846424938577048252796; } ///< \returns The value of \math{e^-e} with the highest precision for \emph{genType}
// Exponentiations of e by Pi // Exponentiations of e by Pi
template<typename genType> constexpr genType e_raised_pi() { return 23.14069263277926900572908636794854738026610624260021; } ///< \returns The value of \f${e}^{ \pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_pi() { return 23.14069263277926900572908636794854738026610624260021; } ///< \returns The value of \math{{e}^{ \pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_neg_pi() { return 0.04321391826377224977441773717172801127572810981063; } ///< \returns The value of \f${e}^{-\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_neg_pi() { return 0.04321391826377224977441773717172801127572810981063; } ///< \returns The value of \math{{e}^{-\pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_half_pi() { return 4.81047738096535165547303566670383312639017087466453; } ///< \returns The value of \f${e}^{\frac{ \pi}{2}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_half_pi() { return 4.81047738096535165547303566670383312639017087466453; } ///< \returns The value of \math{{e}^{\frac{ \pi}{2}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_neg_half_pi() { return 0.20787957635076190854695561983497877003387784163176; } ///< \returns The value of \f${e}^{\frac{-\pi}{2}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_neg_half_pi() { return 0.20787957635076190854695561983497877003387784163176; } ///< \returns The value of \math{{e}^{\frac{-\pi}{2}}} with the highest precision for \emph{genType}
// Exponentiations of e by Gamma // Exponentiations of e by Gamma
template<typename genType> constexpr genType e_raised_gamma() { return 1.78107241799019798523650410310717954916964521430343; } ///< \returns The value of \f${e}^{ \gamma}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_gamma() { return 1.78107241799019798523650410310717954916964521430343; } ///< \returns The value of \math{{e}^{ \gamma}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType e_raised_neg_gamma() { return 0.56145948356688516982414321479088078676571038692515; } ///< \returns The value of \f${e}^{-\gamma}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType e_raised_neg_gamma() { return 0.56145948356688516982414321479088078676571038692515; } ///< \returns The value of \math{{e}^{-\gamma}} with the highest precision for \emph{genType}
// Catalan's Constant ================================================================================================== // Catalan's Constant ==================================================================================================
template<typename genType> constexpr genType G() { return 0.91596559417721901505460351493238411077414937428167; } ///< \returns The value of \f$G\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType G() { return 0.91596559417721901505460351493238411077414937428167; } ///< \returns The value of \math{G} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_G() { return 1.09174406370390610145415947333389232498605012140824; } ///< \returns The value of \f$\frac{1}{G}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_G() { return 1.09174406370390610145415947333389232498605012140824; } ///< \returns The value of \math{\frac{1}{G}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType G_over_pi() { return 0.29156090403081878013838445646839491886406615398583; } ///< \returns The value of \f$\frac{G}{\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType G_over_pi() { return 0.29156090403081878013838445646839491886406615398583; } ///< \returns The value of \math{\frac{G}{\pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType pi_over_G() { return 3.42981513013245864263455323784799901211670795530093; } ///< \returns The value of \f$\frac{\pi}{G}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType pi_over_G() { return 3.42981513013245864263455323784799901211670795530093; } ///< \returns The value of \math{\frac{\pi}{G}} with the highest precision for \emph{genType}
// Gamma =============================================================================================================== // Gamma ===============================================================================================================
template<typename genType> constexpr genType y() { return 0.57721566490153286060651209008240243104215933593992; } ///< \returns The value of \f$\gamma\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType y() { return 0.57721566490153286060651209008240243104215933593992; } ///< \returns The value of \math{\gamma} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_y() { return 1.73245471460063347358302531586082968115577655226680; } ///< \returns The value of \f$\frac{1}{\gamma}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_y() { return 1.73245471460063347358302531586082968115577655226680; } ///< \returns The value of \math{\frac{1}{\gamma}} with the highest precision for \emph{genType}
// Logarithms ========================================================================================================== // Logarithms ==========================================================================================================
template<typename genType> constexpr genType log_two() { return 0.69314718055994530941723212145817656807550013436025; } ///< \returns The value of \f$\log{2}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_two() { return 0.69314718055994530941723212145817656807550013436025; } ///< \returns The value of \math{\log{2}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_three() { return 1.09861228866810969139524523692252570464749055782274; } ///< \returns The value of \f$\log{3}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_three() { return 1.09861228866810969139524523692252570464749055782274; } ///< \returns The value of \math{\log{3}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_five() { return 1.60943791243410037460075933322618763952560135426851; } ///< \returns The value of \f$\log{5}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_five() { return 1.60943791243410037460075933322618763952560135426851; } ///< \returns The value of \math{\log{5}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_seven() { return 1.94591014905531330510535274344317972963708472958186; } ///< \returns The value of \f$\log{7}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_seven() { return 1.94591014905531330510535274344317972963708472958186; } ///< \returns The value of \math{\log{7}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_ten() { return 2.30258509299404568401799145468436420760110148862877; } ///< \returns The value of \f$\log{10}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_ten() { return 2.30258509299404568401799145468436420760110148862877; } ///< \returns The value of \math{\log{10}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType one_over_log_ten() { return 0.43429448190325182765112891891660508229439700580366; } ///< \returns The value of \f$\frac{1}{\log{10}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType one_over_log_ten() { return 0.43429448190325182765112891891660508229439700580366; } ///< \returns The value of \math{\frac{1}{\log{10}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_two_over_log_three() { return 0.63092975357145743709952711434276085429958564013188; } ///< \returns The value of \f$\frac{\log{2}}{\log{3}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_two_over_log_three() { return 0.63092975357145743709952711434276085429958564013188; } ///< \returns The value of \math{\frac{\log{2}}{\log{3}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_log_two() { return -0.36651292058166432701243915823266946945426344783711; } ///< \returns The value of \f$\log{\log{2}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_log_two() { return -0.36651292058166432701243915823266946945426344783711; } ///< \returns The value of \math{\log{\log{2}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_pi() { return 1.14472988584940017414342735135305871164729481291531; } ///< \returns The value of \f$\log{\pi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_pi() { return 1.14472988584940017414342735135305871164729481291531; } ///< \returns The value of \math{\log{\pi}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_sqrt_two() { return 0.91893853320467274178032973640561763986139747363778; } ///< \returns The value of \f$\log{\sqrt{2}}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_sqrt_two() { return 0.91893853320467274178032973640561763986139747363778; } ///< \returns The value of \math{\log{\sqrt{2}}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_gamma() { return -0.54953931298164482233766176880290778833069898126306; } ///< \returns The value of \f$\log{\gamma}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_gamma() { return -0.54953931298164482233766176880290778833069898126306; } ///< \returns The value of \math{\log{\gamma}} with the highest precision for \emph{genType}
template<typename genType> constexpr genType log_phi() { return 0.48121182505960344749775891342436842313518433438566; } ///< \returns The value of \f$\log{\phi}\f$ with the highest precision for \f$genType\f$ template<typename genType> constexpr genType log_phi() { return 0.48121182505960344749775891342436842313518433438566; } ///< \returns The value of \math{\log{\phi}} with the highest precision for \emph{genType}
} }

View File

@@ -52,7 +52,7 @@ constexpr genType sqnorm(const qua<genType>& q) {
/// ///
/// \brief Norm Function /// \brief Norm Function
/// \param q The Quaternion /// \param q The Quaternion
/// \returns The Hamilton Tensor of \f$q\f$ /// \returns The Hamilton Tensor of \emph{q}
template<typename genType> template<typename genType>
constexpr genType norm(const qua<genType>& q) { constexpr genType norm(const qua<genType>& q) {
return fennec::sqrt(sqnorm(q)); return fennec::sqrt(sqnorm(q));
@@ -61,7 +61,7 @@ constexpr genType norm(const qua<genType>& q) {
/// ///
/// \brief Unit Function (Versor) /// \brief Unit Function (Versor)
/// \param q The Quaternion /// \param q The Quaternion
/// \returns A Quaternion of \f$q\f$ with norm \f$1\f$ /// \returns A Quaternion of \emph{q} with norm \math{1}
template<typename genType> template<typename genType>
constexpr qua<genType> unit(const qua<genType>& q) { constexpr qua<genType> unit(const qua<genType>& q) {
genType n = fennec::norm(q); genType n = fennec::norm(q);
@@ -71,7 +71,7 @@ constexpr qua<genType> unit(const qua<genType>& q) {
/// ///
/// \brief Reciprocal Function /// \brief Reciprocal Function
/// \param q The Quaternion /// \param q The Quaternion
/// \returns The quaternion \f${q}^{-1}\f$ /// \returns The quaternion \math{\textbf{q}^{-1}}
template<typename genType> template<typename genType>
constexpr qua<genType> reciprocal(const qua<genType>& q) { constexpr qua<genType> reciprocal(const qua<genType>& q) {
return ~q / fennec::sqnorm(q); return ~q / fennec::sqnorm(q);
@@ -99,7 +99,7 @@ public:
// Constructors ======================================================================================================== // Constructors ========================================================================================================
/// ///
/// \brief Default Constructor, creates a quaternion such that the real part is \f$1\f$ and all others are \f$0\f$ /// \brief Default Constructor, creates a quaternion such that the real part is \math{1} and all others are \math{0}
constexpr quaternion() { constexpr quaternion() {
data = { 0, 0, 0, 1 }; data = { 0, 0, 0, 1 };
} }
@@ -107,9 +107,9 @@ public:
/// ///
/// \brief Component Constructor /// \brief Component Constructor
/// \param w The scalar component /// \param w The scalar component
/// \param x The coefficient of the \f$i\f$ component /// \param x The coefficient of the \emph{i} component
/// \param y The coefficient of the \f$j\f$ component /// \param y The coefficient of the \emph{j} component
/// \param z The coefficient of the \f$k\f$ component /// \param z The coefficient of the \emph{k} component
constexpr quaternion(scalar_t w, scalar_t x, scalar_t y, scalar_t z) { constexpr quaternion(scalar_t w, scalar_t x, scalar_t y, scalar_t z) {
data = { x, y, z, w }; data = { x, y, z, w };
} }
@@ -160,7 +160,7 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param q The quaternion to copy /// \param q The quaternion to copy
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr quat_t& operator=(const quat_t& q) { constexpr quat_t& operator=(const quat_t& q) {
data = q.data; data = q.data;
return *this; return *this;
@@ -169,7 +169,7 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param q The quaternion to move /// \param q The quaternion to move
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr quat_t& operator=(quat_t&& q) noexcept { constexpr quat_t& operator=(quat_t&& q) noexcept {
data = q.data; data = q.data;
return *this; return *this;
@@ -182,7 +182,7 @@ public:
/// \brief Equality Operator /// \brief Equality Operator
/// \param lhs the left hand side of the expression /// \param lhs the left hand side of the expression
/// \param rhs the right hand side of the expression /// \param rhs the right hand side of the expression
/// \returns \f$true\f$ when all components of \f$lhs\f$ and \f$rhs\f$ are equal, false otherwise /// \returns \emph{true} when all components of \emph{lhs} and \emph{rhs} are equal, false otherwise
constexpr friend bool operator==(const quat_t& lhs, const quat_t& rhs) { constexpr friend bool operator==(const quat_t& lhs, const quat_t& rhs) {
return lhs.data == rhs.data; return lhs.data == rhs.data;
} }
@@ -191,7 +191,7 @@ public:
/// \brief Inequality Operator /// \brief Inequality Operator
/// \param lhs the left hand side of the expression /// \param lhs the left hand side of the expression
/// \param rhs the right hand side of the expression /// \param rhs the right hand side of the expression
/// \returns \f$true\f$ when any component of \f$lhs\f$ and \f$rhs\f$ are not equal, false otherwise /// \returns \emph{true} when any component of \emph{lhs} and \emph{rhs} are not equal, false otherwise
constexpr friend bool operator!=(const quat_t& lhs, const quat_t& rhs) { constexpr friend bool operator!=(const quat_t& lhs, const quat_t& rhs) {
return lhs.data != rhs.data; return lhs.data != rhs.data;
} }
@@ -202,7 +202,7 @@ public:
/// ///
/// \brief Unary Negation Operator /// \brief Unary Negation Operator
/// \param rhs The quaternion to negate /// \param rhs The quaternion to negate
/// \returns A quaternion with each component of \f$rhs\f$ negated. /// \returns A quaternion with each component of \emph{rhs} negated.
constexpr friend quat_t operator-(const quat_t& rhs) { constexpr friend quat_t operator-(const quat_t& rhs) {
return quat_t(-rhs.w, -rhs.x, -rhs.y, -rhs.z); return quat_t(-rhs.w, -rhs.x, -rhs.y, -rhs.z);
} }
@@ -210,7 +210,7 @@ public:
/// ///
/// \brief Unary Conjugation Operator /// \brief Unary Conjugation Operator
/// \param rhs The quaternion to conjugate /// \param rhs The quaternion to conjugate
/// \returns A quaternion with each vector component of \f$rhs\f$ negated. /// \returns A quaternion with each vector component of \emph{rhs} negated.
constexpr friend quat_t operator~(const quat_t& rhs) { constexpr friend quat_t operator~(const quat_t& rhs) {
return quat_t(rhs.w, -rhs.x, -rhs.y, -rhs.z); return quat_t(rhs.w, -rhs.x, -rhs.y, -rhs.z);
} }
@@ -222,7 +222,7 @@ public:
/// \brief Quaternion-Scalar Multiplication Operator /// \brief Quaternion-Scalar Multiplication Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns A quaternion with each component of \f$lhs\f$ multiplied by \f$rhs\f$ /// \returns A quaternion with each component of \emph{lhs} multiplied by \emph{rhs}
constexpr friend quat_t operator*(const quat_t& lhs, scalar_t rhs) { constexpr friend quat_t operator*(const quat_t& lhs, scalar_t rhs) {
return quat_t(lhs.w * rhs, lhs.x * rhs, lhs.y * rhs, lhs.z * rhs); return quat_t(lhs.w * rhs, lhs.x * rhs, lhs.y * rhs, lhs.z * rhs);
} }
@@ -231,7 +231,7 @@ public:
/// \brief Scalar-Quaternion Multiplication Operator /// \brief Scalar-Quaternion Multiplication Operator
/// \param lhs The scalar /// \param lhs The scalar
/// \param rhs The quaternion /// \param rhs The quaternion
/// \returns A quaternion with each component of \f$rhs\f$ multiplied by \f$lhs\f$ /// \returns A quaternion with each component of \emph{rhs} multiplied by \emph{lhs}
constexpr friend quat_t operator*(scalar_t lhs, const quat_t& rhs) { constexpr friend quat_t operator*(scalar_t lhs, const quat_t& rhs) {
return quat_t(lhs * rhs.w, lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); return quat_t(lhs * rhs.w, lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
} }
@@ -240,7 +240,7 @@ public:
/// \brief Quaternion-Scalar Division Operator /// \brief Quaternion-Scalar Division Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns A quaternion with each component of \f$lhs\f$ divided by \f$rhs\f$ /// \returns A quaternion with each component of \emph{lhs} divided by \emph{rhs}
constexpr friend quat_t operator/(const quat_t& lhs, scalar_t rhs) { constexpr friend quat_t operator/(const quat_t& lhs, scalar_t rhs) {
return quat_t(lhs.w / rhs, lhs.x / rhs, lhs.y / rhs, lhs.z / rhs); return quat_t(lhs.w / rhs, lhs.x / rhs, lhs.y / rhs, lhs.z / rhs);
} }
@@ -249,7 +249,7 @@ public:
/// \brief Scalar-Quaternion Division Operator /// \brief Scalar-Quaternion Division Operator
/// \param lhs The scalar /// \param lhs The scalar
/// \param rhs The quaternion /// \param rhs The quaternion
/// \returns A quaternion with each component of \f$rhs\f$ divided by \f$lhs\f$ /// \returns A quaternion with each component of \emph{rhs} divided by \emph{lhs}
constexpr friend quat_t operator/(scalar_t lhs, const quat_t& rhs) { constexpr friend quat_t operator/(scalar_t lhs, const quat_t& rhs) {
return quat_t(lhs / rhs.w, lhs / rhs.x, lhs / rhs.y, lhs / rhs.z); return quat_t(lhs / rhs.w, lhs / rhs.x, lhs / rhs.y, lhs / rhs.z);
} }
@@ -261,7 +261,7 @@ public:
/// \brief Quaternion-Scalar Multiplication Assignment Operator /// \brief Quaternion-Scalar Multiplication Assignment Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns \f$lhs\f$ with each component multiplied by \f$rhs\f$ /// \returns \emph{lhs} with each component multiplied by \emph{rhs}
constexpr friend quat_t& operator*=(quat_t& lhs, scalar_t rhs) { constexpr friend quat_t& operator*=(quat_t& lhs, scalar_t rhs) {
lhs.x *= rhs; lhs.x *= rhs;
lhs.y *= rhs; lhs.y *= rhs;
@@ -274,7 +274,7 @@ public:
/// \brief Quaternion-Scalar Division Assignment Operator /// \brief Quaternion-Scalar Division Assignment Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns \f$lhs\f$ with each component divided by \f$rhs\f$ /// \returns \emph{lhs} with each component divided by \emph{rhs}
constexpr friend quat_t& operator/=(const quat_t& lhs, scalar_t rhs) { constexpr friend quat_t& operator/=(const quat_t& lhs, scalar_t rhs) {
lhs.x /= rhs; lhs.x /= rhs;
lhs.y /= rhs; lhs.y /= rhs;
@@ -290,7 +290,7 @@ public:
/// \brief Quaternion-Vector Multiplication Operator /// \brief Quaternion-Vector Multiplication Operator
/// \param q the quaternion /// \param q the quaternion
/// \param v the vector /// \param v the vector
/// \returns the linear algebraic product of \f$q\f$ and \f$v\f$ /// \returns the linear algebraic product of \emph{q} and \emph{v}
constexpr friend vec3_t operator*(const quat_t& q, const vec3_t& v) { constexpr friend vec3_t operator*(const quat_t& q, const vec3_t& v) {
const vec3_t u = q.xyz; const vec3_t u = q.xyz;
const vec3_t uv = fennec::cross(u, v); const vec3_t uv = fennec::cross(u, v);
@@ -302,7 +302,7 @@ public:
/// \brief Vector-Quaternion Multiplication Operator /// \brief Vector-Quaternion Multiplication Operator
/// \param v the vector /// \param v the vector
/// \param q the quaternion /// \param q the quaternion
/// \returns the linear algebraic product of \f$v\f$ and \f$q\f$ /// \returns the linear algebraic product of \emph{v} and \emph{q}
constexpr friend vec3_t operator*(const vec3_t& v, const quat_t& q) { constexpr friend vec3_t operator*(const vec3_t& v, const quat_t& q) {
return fennec::reciprocal(q) * v; return fennec::reciprocal(q) * v;
} }
@@ -311,7 +311,7 @@ public:
/// \brief Quaternion-Vector Multiplication Operator /// \brief Quaternion-Vector Multiplication Operator
/// \param q the quaternion /// \param q the quaternion
/// \param v the vector /// \param v the vector
/// \returns the linear algebraic product of \f$q\f$ and \f$v\f$ /// \returns the linear algebraic product of \emph{q} and \emph{v}
constexpr friend vec4_t operator*(const quat_t& q, const vec4_t& v) { constexpr friend vec4_t operator*(const quat_t& q, const vec4_t& v) {
return vec4_t(q * v.xyz, v.w); return vec4_t(q * v.xyz, v.w);
} }
@@ -320,7 +320,7 @@ public:
/// \brief Vector-Quaternion Multiplication Operator /// \brief Vector-Quaternion Multiplication Operator
/// \param v the vector /// \param v the vector
/// \param q the quaternion /// \param q the quaternion
/// \returns the linear algebraic product of \f$v\f$ and \f$q\f$ /// \returns the linear algebraic product of \emph{v} and \emph{q}
constexpr friend vec4_t operator*(const vec4_t& v, const quat_t& q) { constexpr friend vec4_t operator*(const vec4_t& v, const quat_t& q) {
return fennec::reciprocal(q) * v; return fennec::reciprocal(q) * v;
} }
@@ -332,7 +332,7 @@ public:
/// \brief Quaternion-Quaternion Addition Operator /// \brief Quaternion-Quaternion Addition Operator
/// \param lhs the left hand side /// \param lhs the left hand side
/// \param rhs the right hand side /// \param rhs the right hand side
/// \returns the component-wise sum of \f$lhs\f$ and \f$rhs\f$ /// \returns the component-wise sum of \emph{lhs} and \emph{rhs}
constexpr friend quat_t operator+(const quat_t& lhs, const quat_t& rhs) { constexpr friend quat_t operator+(const quat_t& lhs, const quat_t& rhs) {
return quat_t( return quat_t(
lhs.w + rhs.w, lhs.w + rhs.w,
@@ -346,7 +346,7 @@ public:
/// \brief Quaternion-Quaternion Subtraction Operator /// \brief Quaternion-Quaternion Subtraction Operator
/// \param lhs the left hand side /// \param lhs the left hand side
/// \param rhs the right hand side /// \param rhs the right hand side
/// \returns the component-wise difference of \f$lhs\f$ and \f$rhs\f$ /// \returns the component-wise difference of \emph{lhs} and \emph{rhs}
constexpr friend quat_t operator-(const quat_t& lhs, const quat_t& rhs) { constexpr friend quat_t operator-(const quat_t& lhs, const quat_t& rhs) {
return quat_t( return quat_t(
lhs.w - rhs.w, lhs.w - rhs.w,
@@ -360,7 +360,7 @@ public:
/// \brief Quaternion-Quaternion Multiplication Operator /// \brief Quaternion-Quaternion Multiplication Operator
/// \param lhs the left hand side /// \param lhs the left hand side
/// \param rhs the right hand side /// \param rhs the right hand side
/// \returns the linear algebraic product of \f$lhs\f$ and \f$rhs\f$ /// \returns the linear algebraic product of \emph{lhs} and \emph{rhs}
constexpr friend quat_t operator*(const quat_t& lhs, const quat_t& rhs) { constexpr friend quat_t operator*(const quat_t& lhs, const quat_t& rhs) {
return quat_t( return quat_t(
lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z * rhs.z, lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z * rhs.z,
@@ -377,7 +377,7 @@ public:
/// \brief Quaternion-Quaternion Addition Assignment Operator /// \brief Quaternion-Quaternion Addition Assignment Operator
/// \param lhs the left hand side /// \param lhs the left hand side
/// \param rhs the right hand side /// \param rhs the right hand side
/// \returns the component-wise sum of \f$lhs\f$ and \f$rhs\f$ stored in \f$lhs\f$ /// \returns the component-wise sum of \emph{lhs} and \emph{rhs} stored in \emph{lhs}
constexpr friend quat_t& operator+=(quat_t& lhs, const quat_t& rhs) { constexpr friend quat_t& operator+=(quat_t& lhs, const quat_t& rhs) {
lhs.w += rhs.w; lhs.w += rhs.w;
lhs.x += rhs.x; lhs.x += rhs.x;
@@ -390,7 +390,7 @@ public:
/// \brief Quaternion-Quaternion Subtraction Assignment Operator /// \brief Quaternion-Quaternion Subtraction Assignment Operator
/// \param lhs the left hand side /// \param lhs the left hand side
/// \param rhs the right hand side /// \param rhs the right hand side
/// \returns the component-wise difference of \f$lhs\f$ and \f$rhs\f$ stored in \f$lhs\f$ /// \returns the component-wise difference of \emph{lhs} and \emph{rhs} stored in \emph{lhs}
constexpr friend quat_t& operator-=(quat_t& lhs, const quat_t& rhs) { constexpr friend quat_t& operator-=(quat_t& lhs, const quat_t& rhs) {
lhs.w -= rhs.w; lhs.w -= rhs.w;
lhs.x -= rhs.x; lhs.x -= rhs.x;
@@ -403,7 +403,7 @@ public:
/// \brief Quaternion-Quaternion Multiplication Assignment Operator /// \brief Quaternion-Quaternion Multiplication Assignment Operator
/// \param lhs the left hand side /// \param lhs the left hand side
/// \param rhs the right hand side /// \param rhs the right hand side
/// \returns the linear algebraic product of \f$lhs\f$ and \f$rhs\f$ stored in \f$lhs\f$ /// \returns the linear algebraic product of \emph{lhs} and \emph{rhs} stored in \emph{lhs}
constexpr friend quat_t& operator*=(quat_t& lhs, const quat_t& rhs) { constexpr friend quat_t& operator*=(quat_t& lhs, const quat_t& rhs) {
return lhs = lhs * rhs; return lhs = lhs * rhs;
} }

View File

@@ -118,14 +118,14 @@ namespace fennec
// dot ----------------------------------------------------------------------------------------------------------------- // dot -----------------------------------------------------------------------------------------------------------------
/// ///
/// \brief Returns the dot product of \f$x\f$ and \f$y\f$, i.e., \f$x_0 \cdot y_0 + x_1 \cdot y_1 + \ldots\f$ /// \brief Returns the dot product of \math{x} and \math{y}, i.e., \math{x_0 \cdot y_0 + x_1 \cdot y_1 + \ldots}
/// ///
/// \returns the dot product of \f$x\f$ and \f$y\f$, i.e., \f$x_0 \cdot y_0 + x_0 \cdot y_0 + \ldots\f$ <br><br> /// \returns the dot product of \math{x} and \math{y}, i.e., \math{x_0 \cdot y_0 + x_0 \cdot y_0 + \ldots} <br><br>
/// \details we can represent this in linear algebra as the following, <br><br> /// \details we can represent this in linear algebra as the following, <br><br>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br> /// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <br>
/// let \f$Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]\f$ <br><br> /// let \math{Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]} <br><br>
/// ///
/// then \f$\text{dot}(X, Y)=X \cdot Y^T\f$ <br><br> /// then \math{\text{dot}(X, Y)=X \cdot Y^T} <br><br>
/// ///
/// \param x first vector /// \param x first vector
/// \param y second vector /// \param y second vector
@@ -138,13 +138,13 @@ constexpr genType dot(const vector<genType, i...>& x, const vector<genType, i...
// length2 ------------------------------------------------------------------------------------------------------------- // length2 -------------------------------------------------------------------------------------------------------------
/// ///
/// \brief Returns the squared length of vector \f$x\f$, i.e., \f$x_0^2 + x_1^2 + \ldots\f$ /// \brief Returns the squared length of vector \math{x}, i.e., \math{x_0^2 + x_1^2 + \ldots}
/// ///
/// \returns the squared length of vector \f$x\f$, i.e., \f$x_0^2 + x_1^2 + \ldots\f$ <br><br> /// \returns the squared length of vector \math{x}, i.e., \math{x_0^2 + x_1^2 + \ldots} <br><br>
/// \details we can represent this in linear algebra as the following, <br><br> /// \details we can represent this in linear algebra as the following, <br><br>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br><br> /// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <br><br>
/// ///
/// then \f$\text{length2}(X)=X \cdot X^T\f$ <br><br> /// then \math{\text{length2}(X)=X \cdot X^T} <br><br>
/// ///
/// \param x the vector /// \param x the vector
template<typename genType, size_t...i> template<typename genType, size_t...i>
@@ -156,13 +156,13 @@ constexpr genType length2(const vector<genType, i...>& x) {
// length -------------------------------------------------------------------------------------------------------------- // length --------------------------------------------------------------------------------------------------------------
/// ///
/// \brief Returns the length of vector \f$x\f$, i.e., \f$\sqrt{x_0^2 + x_1^2 + \ldots}\f$ /// \brief Returns the length of vector \math{x}, i.e., \math{\sqrt{x_0^2 + x_1^2 + \ldots}}
/// ///
/// \returns the length of vector \f$x\f$, i.e., \f$\sqrt{x_0^2 + x_1^2 + \ldots}\f$<br><br> /// \returns the length of vector \math{x}, i.e., \math{\sqrt{x_0^2 + x_1^2 + \ldots}}<br><br>
/// \details we can represent this in linear algebra as the following, <br><br> /// \details we can represent this in linear algebra as the following, <br><br>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br><br> /// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <br><br>
/// ///
/// then, \f$\text{length}(X)=\left|\left|X\right|\right|\f$ <br><br> /// then, \math{\text{length}(X)=\left|\left|X\right|\right|} <br><br>
/// ///
/// \param x the vector /// \param x the vector
template<typename genType, size_t...i> template<typename genType, size_t...i>
@@ -174,14 +174,14 @@ constexpr genType length(const vector<genType, i...>& x) {
// distance ------------------------------------------------------------------------------------------------------------ // distance ------------------------------------------------------------------------------------------------------------
/// ///
/// \brief Returns the length of vector \f$x\f$, i.e., \f$\sqrt{x_0^2 + x_1^2 + \ldots}\f$ /// \brief Returns the length of vector \math{x}, i.e., \math{\sqrt{x_0^2 + x_1^2 + \ldots}}
/// ///
/// \returns the distance between \f$p_0\f$ and \f$p_1\f$, i.e., \f$\left|{p_1-p_0}\right|\f$ /// \returns the distance between \math{p_0} and \math{p_1}, i.e., \math{\left|{p_1-p_0}\right|}
/// \details we can represent this in linear algebra as the following, <br><br> /// \details we can represent this in linear algebra as the following, <br><br>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br> /// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <br>
/// let \f$Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]\f$ <br><br> /// let \math{Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]} <br><br>
/// ///
/// then \f$\text{distance}(X, Y)=\left|\left|Y-X\right|\right|\f$ <br><br> /// then \math{\text{distance}(X, Y)=\left|\left|Y-X\right|\right|} <br><br>
/// ///
/// \param p0 first vector /// \param p0 first vector
/// \param p1 second vector /// \param p1 second vector
@@ -194,16 +194,16 @@ constexpr genType distance(const vector<genType, i...>& p0, const vector<genType
// cross --------------------------------------------------------------------------------------------------------------- // cross ---------------------------------------------------------------------------------------------------------------
/// ///
/// \brief Returns the cross product of \f$x\f$ and \f$y\f$, i.e., /// \brief Returns the cross product of \math{x} and \math{y}, i.e.,
/// \f$\left({x_1 \cdot y_2 - y_1 \cdot x_2, x_2 \cdot y_0 - y_2 \cdot x_0, x_0 \cdot y_1 - y_0 \cdot x_1}\right)\f$ /// \math{\left({x_1 \cdot y_2 - y_1 \cdot x_2, x_2 \cdot y_0 - y_2 \cdot x_0, x_0 \cdot y_1 - y_0 \cdot x_1}\right)}
/// ///
/// \returns the cross product of \f$x\f$ and \f$y\f$, i.e., /// \returns the cross product of \math{x} and \math{y}, i.e.,
/// \f$\left({x_1 \cdot y_2 - y_1 \cdot x_2, x_2 \cdot y_0 - y_2 \cdot x_0, x_0 \cdot y_1 - y_0 \cdot x_1}\right)\f$ <br><br> /// \math{\left({x_1 \cdot y_2 - y_1 \cdot x_2, x_2 \cdot y_0 - y_2 \cdot x_0, x_0 \cdot y_1 - y_0 \cdot x_1}\right)} <br><br>
/// \details we can represent this in linear algebra as the following, <br><br> /// \details we can represent this in linear algebra as the following, <br><br>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br> /// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <br>
/// let \f$Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]\f$ <br><br> /// let \math{Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]} <br><br>
/// ///
/// then \f$\text{cross}(X, Y)=X \times Y\f$ <br><br> /// then \math{\text{cross}(X, Y)=X \times Y} <br><br>
/// ///
/// \param x first vector /// \param x first vector
/// \param y second vector /// \param y second vector
@@ -216,13 +216,13 @@ constexpr vector<genType, i...> cross(const vector<genType, i...>& x, const vect
// normalize ----------------------------------------------------------------------------------------------------------- // normalize -----------------------------------------------------------------------------------------------------------
/// ///
/// \brief Returns a vector in the same direction as \f$x\f$, but with a length of \f$1\f$, i.e. /// \brief Returns a vector in the same direction as \math{x}, but with a length of \math{1}, i.e.
/// ///
/// \returns a vector in the same direction as \f$x\f$, but with a length of \f$1\f$, i.e.\f$\frac{x}{||x||}\f$<br><br> /// \returns a vector in the same direction as \math{x}, but with a length of \math{1}, i.e.\math{\frac{x}{||x||}}<br><br>
/// \details we can represent this in linear algebra as the following, <br><br> /// \details we can represent this in linear algebra as the following, <br><br>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br><br> /// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <br><br>
/// ///
/// then, \f$\text{length}(X)=\frac{X}{\left|\left|X\right|\right|}\f$ <br><br> /// then, \math{\text{length}(X)=\frac{X}{\left|\left|X\right|\right|}} <br><br>
/// ///
/// \param x /// \param x
template<typename genType, size_t...i> template<typename genType, size_t...i>
@@ -234,9 +234,9 @@ constexpr vector<genType, i...> normalize(const vector<genType, i...>& x) {
// faceforward --------------------------------------------------------------------------------------------------------- // faceforward ---------------------------------------------------------------------------------------------------------
/// ///
/// \brief If \f$\text{dot}(Nref, I)<0\f$ return \f$N\f$, otherwise return \f$-N\f$. /// \brief If \math{\text{dot}(Nref, I)<0} return \math{N}, otherwise return \math{-N}.
/// ///
/// \returns \f$N\f$ if \f$\text{dot}(Nref,I)<0\f$, otherwise, returns \f$-N\f$.<br><br> /// \returns \math{N} if \math{\text{dot}(Nref,I)<0}, otherwise, returns \math{-N}.<br><br>
/// ///
/// \param N the vector /// \param N the vector
/// \param I the incident /// \param I the incident
@@ -250,11 +250,11 @@ constexpr vector<genType, i...> faceforward(const vector<genType, i...>& N, cons
// reflect ------------------------------------------------------------------------------------------------------------- // reflect -------------------------------------------------------------------------------------------------------------
/// ///
/// \brief For the incident vector \f$I\f$ and surface orientation \f$N\f$, returns the reflection direction. /// \brief For the incident vector \math{I} and surface orientation \math{N}, returns the reflection direction.
/// ///
/// \returns The reflection direction, given the incident vector \f$I\f$ and surface orientation \f$N\f$ <br><br> /// \returns The reflection direction, given the incident vector \math{I} and surface orientation \math{N} <br><br>
/// \details We can express this as, <br><br> /// \details We can express this as, <br><br>
/// \f$\text{reflect}(I, N) = I - 2 N \cdot \text{dot}(N, I)\f$ <br><br> /// \math{\text{reflect}(I, N) = I - 2 N \cdot \text{dot}(N, I)} <br><br>
/// ///
/// \param I the incident /// \param I the incident
/// \param N the surface orientation /// \param N the surface orientation
@@ -266,13 +266,13 @@ constexpr vector<genType, i...> reflect(const vector<genType, i...>& I, const ve
// refract ------------------------------------------------------------------------------------------------------------- // refract -------------------------------------------------------------------------------------------------------------
/// ///
/// \brief For the incident vector \f$I\f$ and surface normal \f$N\f$, and the ratio of indices of refraction \f$eta\f$, /// \brief For the incident vector \math{I} and surface normal \math{N}, and the ratio of indices of refraction \math{eta},
/// return the refraction vector. /// return the refraction vector.
/// ///
/// \returns The refraction vector, given the incident vector \f$I\f$, surface normal \f$N\f$, and ratio \f$eta\f$.<br><br> /// \returns The refraction vector, given the incident vector \math{I}, surface normal \math{N}, and ratio \math{eta}.<br><br>
/// \details The result is computed by the refraction equation, <br><br> /// \details The result is computed by the refraction equation, <br><br>
/// let \f$k=1.0-eta^2 \cdot (1.0 - \text{dot}(N, I)^2)\f$ <br> /// let \math{k=1.0-eta^2 \cdot (1.0 - \text{dot}(N, I)^2)} <br>
/// then, \f$\text{refract}(I, N, eta)=\begin{cases} 0.0 & k<0.0, \\ eta \cdot I - N \cdot (eta \cdot \text{dot}(N, I) + \sqrt{k}) \end{cases}\f$ <br><br> /// then, \math{\text{refract}(I, N, eta)=\begin{cases} 0.0 & k<0.0, \\ eta \cdot I - N \cdot (eta \cdot \text{dot}(N, I) + \sqrt{k}) \end{cases}} <br><br>
/// ///
/// \param I the incident /// \param I the incident
/// \param N the surface normal /// \param N the surface normal

View File

@@ -56,10 +56,10 @@ namespace fennec
/// ///
/// \brief returns a **copy** of the column \f$i\f$ of matrix \f$m\f$ /// \brief returns a **copy** of the column \emph{i} of matrix \emph{m}
/// \param m the matrix /// \param m the matrix
/// \param i the index of the row /// \param i the index of the row
/// \returns a **copy** of the column at index \f$i\f$ /// \returns a **copy** of the column at index \emph{i}
template<typename scalar, size_t rows, size_t...cols> template<typename scalar, size_t rows, size_t...cols>
constexpr vec<scalar, rows> column(const matrix<scalar, rows, cols...>& m, size_t i) noexcept { constexpr vec<scalar, rows> column(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
return m[i]; return m[i];
@@ -67,10 +67,10 @@ constexpr vec<scalar, rows> column(const matrix<scalar, rows, cols...>& m, size_
/// ///
/// \brief returns a **copy** of the row \f$i\f$ of matrix \f$m\f$ /// \brief returns a **copy** of the row \emph{i} of matrix \emph{m}
/// \param m the matrix /// \param m the matrix
/// \param i the index of the row /// \param i the index of the row
/// \returns a **copy** of the row at index \f$i\f$ /// \returns a **copy** of the row at index \emph{i}
template<typename scalar, size_t rows, size_t...cols> template<typename scalar, size_t rows, size_t...cols>
constexpr vec<scalar, sizeof...(cols)> row(const matrix<scalar, rows, cols...>& m, size_t i) noexcept { constexpr vec<scalar, sizeof...(cols)> row(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
return vec<scalar, sizeof...(cols)>(m[cols][i]...); return vec<scalar, sizeof...(cols)>(m[cols][i]...);
@@ -118,7 +118,7 @@ using dmat4x4 = tmat4x4<double_t>; //!< Specification for size glsl double matri
/// ///
/// \brief Multiply matrix \f$x\f$ by matrix \f$y\f$ component-wise. /// \brief Multiply matrix \emph{x} by matrix \emph{y} component-wise.
/// \details Multiply matrix x by matrix y component-wise, i.e., result[i][j] is the scalar product of x[i][j] and y[i][j].<br><br> /// \details Multiply matrix x by matrix y component-wise, i.e., result[i][j] is the scalar product of x[i][j] and y[i][j].<br><br>
/// Note: to get linear algebraic matrix multiplication, use /// Note: to get linear algebraic matrix multiplication, use
/// the multiply operator (*) /// the multiply operator (*)
@@ -131,14 +131,14 @@ constexpr matrix<scalar, rows, cols...> matrixCompMult(const matrix<scalar, rows
} }
/// ///
/// \brief Performs a linear algebraic multiply, multiplying \f$c\f$ by the components of \f$r\f$, producing a matrix. /// \brief Performs a linear algebraic multiply, multiplying \emph{c} by the components of \emph{r}, producing a matrix.
/// ///
/// \details Treats the first parameter \f$c\f$ as a column vector (matrix /// \details Treats the first parameter \emph{c} as a column vector (matrix
/// with one column) and the second parameter \f$r\f$ as a row /// with one column) and the second parameter \emph{r} as a row
/// vector (matrix with one row) and does a linear algebraic /// vector (matrix with one row) and does a linear algebraic
/// matrix multiply \f$c \cross r\f$, yielding a matrix whose number of /// matrix multiply \emph{c \cross r}, yielding a matrix whose number of
/// rows is the number of components in \f$c\f$ and whose /// rows is the number of components in \emph{c} and whose
/// number of columns is the number of components in \f$r\f$. /// number of columns is the number of components in \emph{r}.
/// \param c the column vector /// \param c the column vector
/// \param r the row vector /// \param r the row vector
/// \returns the resulting matrix produced by the linear algebraic product /// \returns the resulting matrix produced by the linear algebraic product
@@ -150,9 +150,9 @@ constexpr matrix<scalar, sizeof...(s0), s1...> outerProduct(const vector<scalar,
} }
/// ///
/// \brief get the transpose of \f$m\f$ /// \brief get the transpose of \emph{m}
/// \param m the matrix to transpose /// \param m the matrix to transpose
/// \returns a matrix that is the transpose of \f$m\f$ /// \returns a matrix that is the transpose of \emph{m}
/// \details The input matrix m is not modified. /// \details The input matrix m is not modified.
template<typename scalar, size_t rows, size_t...cols> template<typename scalar, size_t rows, size_t...cols>
constexpr mat<scalar, rows, sizeof...(cols)> transpose(const matrix<scalar, rows, cols...>& m) noexcept { constexpr mat<scalar, rows, sizeof...(cols)> transpose(const matrix<scalar, rows, cols...>& m) noexcept {
@@ -160,7 +160,7 @@ constexpr mat<scalar, rows, sizeof...(cols)> transpose(const matrix<scalar, rows
} }
/// ///
/// \brief Returns the determinant of \f$m\f$. /// \brief Returns the determinant of \emph{m}.
/// \returns the determinant of m. /// \returns the determinant of m.
template<typename scalar, size_t rows, size_t...cols> template<typename scalar, size_t rows, size_t...cols>
constexpr scalar determinant(const matrix<scalar, rows, cols...>&) noexcept { constexpr scalar determinant(const matrix<scalar, rows, cols...>&) noexcept {
@@ -169,8 +169,8 @@ constexpr scalar determinant(const matrix<scalar, rows, cols...>&) noexcept {
} }
/// ///
/// \brief Returns the determinant of \f$m\f$. /// \brief Returns the determinant of \emph{m}.
/// \returns \f$m^{-1}\f$ /// \returns \math{\textbf{m}^{-1}}
template<typename scalar, size_t rows, size_t...cols> template<typename scalar, size_t rows, size_t...cols>
constexpr matrix<scalar, rows, cols...> inverse(const matrix<scalar, rows, cols...>&) noexcept { constexpr matrix<scalar, rows, cols...> inverse(const matrix<scalar, rows, cols...>&) noexcept {
static_assert(false, "implementation undefined"); static_assert(false, "implementation undefined");
@@ -295,7 +295,7 @@ struct matrix
/// \brief scalar constructor, initializes a diagonal matrix with a scale of \p s /// \brief scalar constructor, initializes a diagonal matrix with a scale of \p s
/// ///
/// \details /// \details
/// This function creates a diagonal matrix such that ```vec3(2.0f)``` would result in a matrix /// This function creates a diagonal matrix such that `(.*?)` would result in a matrix
/// <table> /// <table>
/// <caption id="fennec_table_matrix_diagonal"></caption> /// <caption id="fennec_table_matrix_diagonal"></caption>
/// <tr><th> <th> 0 <th> 1 <th> 2 /// <tr><th> <th> 0 <th> 1 <th> 2
@@ -359,17 +359,17 @@ struct matrix
/// ///
/// \details /// \details
/// \param i the index /// \param i the index
/// \returns the column at index \f$i\f$ /// \returns the column at index \emph{i}
constexpr column_t& operator[](size_t i) { constexpr column_t& operator[](size_t i) {
return data[i]; return data[i];
} }
/// ///
/// \brief returns the column at index \f$i\f$ /// \brief returns the column at index \emph{i}
/// ///
/// \details /// \details
/// \param i the index /// \param i the index
/// \returns the column at index \f$i\f$ /// \returns the column at index \emph{i}
constexpr const column_t& operator[](size_t i) const { constexpr const column_t& operator[](size_t i) const {
return data[i]; return data[i];
} }
@@ -378,7 +378,7 @@ struct matrix
/// \details /// \details
/// \param i the column /// \param i the column
/// \param j the row /// \param j the row
/// \returns the element in column \f$i\f$, row \f$j\f$ /// \returns the element in column \emph{i}, row \emph{j}
constexpr scalar_t& operator[](size_t i, size_t j) { constexpr scalar_t& operator[](size_t i, size_t j) {
return data[i][j]; return data[i][j];
} }
@@ -389,7 +389,7 @@ struct matrix
/// \details /// \details
/// \param i the column /// \param i the column
/// \param j the row /// \param j the row
/// \returns the element in column \f$i\f$, row \f$j\f$ /// \returns the element in column \emph{i}, row \emph{j}
constexpr scalar_t operator[](size_t i, size_t j) const { constexpr scalar_t operator[](size_t i, size_t j) const {
return data[i][j]; return data[i][j];
} }
@@ -610,7 +610,7 @@ struct matrix
/// \brief performs a linear algebraic multiply /// \brief performs a linear algebraic multiply
/// \param lhs the matrix /// \param lhs the matrix
/// \param rhs the vector /// \param rhs the vector
/// \returns a vector containing the dot products of \f$rhs\f$ with each row of \f$lhs\f$ /// \returns a vector containing the dot products of \emph{rhs} with each row of \emph{lhs}
constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) { constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) {
return _mul(lhs, rhs); return _mul(lhs, rhs);
} }
@@ -619,7 +619,7 @@ struct matrix
/// \brief performs a linear algebraic multiply /// \brief performs a linear algebraic multiply
/// \param lhs the vector /// \param lhs the vector
/// \param rhs the matrix /// \param rhs the matrix
/// \returns a vector containing the dot products of \f$lhs\f$ with each column of \f$rhs\f$ /// \returns a vector containing the dot products of \emph{lhs} with each column of \emph{rhs}
constexpr friend row_t operator*(const column_t& lhs, const matrix_t& rhs) { constexpr friend row_t operator*(const column_t& lhs, const matrix_t& rhs) {
return row_t(fennec::dot(fennec::column(rhs, ColIndicesV), lhs) ...); return row_t(fennec::dot(fennec::column(rhs, ColIndicesV), lhs) ...);
} }
@@ -637,7 +637,7 @@ struct matrix
/// \brief matrix comparison operator /// \brief matrix comparison operator
/// \param lhs the first matrix /// \param lhs the first matrix
/// \param rhs the second matrix /// \param rhs the second matrix
/// \returns a boolean value that contains \f$true\f$ when all components of \f$lhs\f$ and \f$rhs\f$ are equal and \f$false\f$ otherwise /// \returns a boolean value that contains \emph{true} when all components of \emph{lhs} and \emph{rhs} are equal and \emph{false} otherwise
constexpr friend bool operator==(const matrix_t& lhs, const matrix_t& rhs) { constexpr friend bool operator==(const matrix_t& lhs, const matrix_t& rhs) {
return lhs.data == rhs.data; return lhs.data == rhs.data;
} }
@@ -646,7 +646,7 @@ struct matrix
/// \brief matrix comparison operator /// \brief matrix comparison operator
/// \param lhs the first matrix /// \param lhs the first matrix
/// \param rhs the second matrix /// \param rhs the second matrix
/// \returns a boolean value that contains \f$true\f$ when all components of \f$lhs\f$ and \f$rhs\f$ are not equal and \f$false\f$ otherwise /// \returns a boolean value that contains \emph{true} when all components of \emph{lhs} and \emph{rhs} are not equal and \emph{false} otherwise
constexpr friend bool operator!=(const matrix_t& lhs, const matrix_t& rhs) { constexpr friend bool operator!=(const matrix_t& lhs, const matrix_t& rhs) {
return lhs.data != rhs.data; return lhs.data != rhs.data;
} }
@@ -666,7 +666,7 @@ struct matrix
/// ///
/// \brief performs a linear algebraic matrix multiplication assignment /// \brief performs a linear algebraic matrix multiplication assignment
/// \param rhs the columns to multiply with /// \param rhs the columns to multiply with
/// \returns a reference to self /// \returns a reference to \emph{this}
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV) template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) { constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
return *this = *this * rhs; return *this = *this * rhs;
@@ -682,7 +682,7 @@ public:
/// ///
/// \param mat the matrix to transpose /// \param mat the matrix to transpose
/// \returns \f$m^T\f$ /// \returns \math{\textbf{m}^T}
static constexpr matrix_t transpose(const transpose_t& mat) { static constexpr matrix_t transpose(const transpose_t& mat) {
return matrix_t(fennec::row(mat, ColIndicesV)...); return matrix_t(fennec::row(mat, ColIndicesV)...);
} }

View File

@@ -103,7 +103,7 @@
/// \ref fennec_vector_not "bool not(bvec x)"<br> /// \ref fennec_vector_not "bool not(bvec x)"<br>
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// \details /// \details
/// \returns the component-wise logical complement of \f$x\f$. <br> /// \returns the component-wise logical complement of \math{x}. <br>
/// \param x the boolean vector to inverse <br> /// \param x the boolean vector to inverse <br>
/// ///
/// </table> /// </table>
@@ -189,9 +189,9 @@ constexpr vector<genBType, i...> notEqual(const vector<genType, i...>& x, const
/// ///
/// \brief Returns \f$true\f$ if any component of \f$x\f$ is \f$true\f$ /// \brief Returns \math{true} if any component of \math{x} is \math{true}
/// ///
/// \returns \f$true\f$ if any component of \f$x\f$ is \f$true\f$ /// \returns \math{true} if any component of \math{x} is \math{true}
/// \param x the boolean vector to test /// \param x the boolean vector to test
template<typename genBType = bool_t, size_t...i> template<typename genBType = bool_t, size_t...i>
constexpr genBType any(const vector<genBType, i...>& x) { constexpr genBType any(const vector<genBType, i...>& x) {
@@ -199,9 +199,9 @@ constexpr genBType any(const vector<genBType, i...>& x) {
} }
/// ///
/// \brief Returns \f$true\f$ if all components of \f$x\f$ are \f$true\f$ /// \brief Returns \math{true} if all components of \math{x} are \math{true}
/// ///
/// \returns \f$true\f$ if all components of \f$x\f$ are \f$true\f$ /// \returns \math{true} if all components of \math{x} are \math{true}
/// \param x the boolean vector to test /// \param x the boolean vector to test
template<typename genBType = bool_t, size_t...i> template<typename genBType = bool_t, size_t...i>
constexpr genBType all(const vector<genBType, i...>& x) { constexpr genBType all(const vector<genBType, i...>& x) {
@@ -210,10 +210,10 @@ constexpr genBType all(const vector<genBType, i...>& x) {
/// ///
/// \anchor fennec_vector_not /// \anchor fennec_vector_not
/// \brief Returns the component-wise logical complement of \f$x\f$. /// \brief Returns the component-wise logical complement of \math{x}.
/// ///
/// \details /// \details
/// \returns the component-wise logical complement of \f$x\f$. /// \returns the component-wise logical complement of \math{x}.
/// \param x the boolean vector to inverse /// \param x the boolean vector to inverse
template<typename genBType = bool_t, size_t...i> template<typename genBType = bool_t, size_t...i>
constexpr vector<genBType, i...> operator not(const vector<genBType, i...>& x) { constexpr vector<genBType, i...> operator not(const vector<genBType, i...>& x) {

View File

@@ -41,7 +41,7 @@
/// ///
/// \code #include <fennec/math/scalar.h> \endcode /// \code #include <fennec/math/scalar.h> \endcode
/// ///
/// The fennecLibrary considers any type that passes ```is_arithmetic<T>``` to be a \ref scalar "Scalar." Bools are /// The fennecLibrary considers any type that passes `(.*?)` to be a \ref scalar "Scalar." Bools are
/// supported as a logical type. /// supported as a logical type.
/// ///
/// The GLSL Specification, and fennecrespectively, defines the following scalar types: /// The GLSL Specification, and fennecrespectively, defines the following scalar types:

View File

@@ -157,13 +157,13 @@ namespace fennec
/// @{ /// @{
/// ///
/// \brief Converts \f$degrees\f$ to \f$radians\f$, i.e., \f$degrees\cdot\frac{180}{\pi}\f$ /// \brief Converts \emph{degrees} to \emph{radians}, i.e., \math{degrees\cdot\frac{180}{\pi}}
/// ///
/// \returns the angle \f$\theta\f$ in \f$radians\f$ <br><br> /// \returns the angle \math{\theta} in \math{radians} <br><br>
/// \details Converts \f$degrees\f$ to \f$radians\f$, i.e., \f$degrees\cdot\frac{180}{\pi}\f$ <br><br> /// \details Converts \emph{degrees} to \emph{radians}, i.e., \math{degrees\cdot\frac{180}{\pi}} <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param degrees the angle \f$\theta\f$ in \f$degrees\f$ /// \param degrees the angle \math{\theta} in \math{degrees}
template<typename genType> template<typename genType>
constexpr genType radians(genType degrees) { constexpr genType radians(genType degrees) {
return genType(degrees * 0.01745329251994329576923690768489); return genType(degrees * 0.01745329251994329576923690768489);
@@ -171,13 +171,13 @@ constexpr genType radians(genType degrees) {
/// ///
/// \brief Converts \f$radians\f$ to \f$degrees\f$, i.e., \f$radians\cdot\frac{\pi}{180}\f$ /// \brief Converts \emph{radians} to \emph{degrees}, i.e., \math{radians\cdot\frac{\pi}{180}}
/// ///
/// \returns the angle \f$\theta\f$ in \f$degrees\f$ <br><br> /// \returns the angle \math{\theta} in \emph{degrees} <br><br>
/// \details Converts \f$radians\f$ to \f$degrees\f$, i.e., \f$radians\cdot\frac{\pi}{180}\f$ <br><br> /// \details Converts \emph{radians} to \emph{degrees}, i.e., \math{radians\cdot\frac{\pi}{180}} <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param radians the angle \f$\theta\f$ in \f$radians\f$ /// \param radians the angle \math{\theta} in \emph{radians}
template<typename genType> template<typename genType>
constexpr genType degrees(genType radians) { constexpr genType degrees(genType radians) {
return genType(radians * 57.29577951308232087679815481410517); return genType(radians * 57.29577951308232087679815481410517);
@@ -195,11 +195,11 @@ constexpr genType degrees(genType radians) {
/// ///
/// \brief The standard trigonometric sine /// \brief The standard trigonometric sine
/// ///
/// \returns the sine of \f$\theta\f$ in the range \f$\left[-1,\,1\right]\f$ <br><br> /// \returns the sine of \math{\theta} in the range \math{\left[-1,\,1\right]} <br><br>
/// \details The standard trigonometric sine <br><br> /// \details The standard trigonometric sine <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param x the angle \f$\theta\f$ in \f$radians\f$ /// \param x the angle \math{\theta} in \math{radians}
template<typename genType> template<typename genType>
constexpr genType sin(genType x) { constexpr genType sin(genType x) {
return ::sin(x); return ::sin(x);
@@ -209,11 +209,11 @@ constexpr genType sin(genType x) {
/// ///
/// \brief The Standard Trigonometric Cosine /// \brief The Standard Trigonometric Cosine
/// ///
/// \returns the cosine of \f$\theta\f$ in the range \f$\left[-1,\,1\right]\f$ <br><br> /// \returns the cosine of \math{\theta} in the range \math{\left[-1,\,1\right]} <br><br>
/// \details The Standard Trigonometric Cosine <br><br> /// \details The Standard Trigonometric Cosine <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param x the angle \f$\theta\f$ in \f$radians\f$ /// \param x the angle \math{\theta} in \emph{radians}
template<typename genType> template<typename genType>
constexpr genType cos(genType x) { constexpr genType cos(genType x) {
return ::cos(x); return ::cos(x);
@@ -223,11 +223,11 @@ constexpr genType cos(genType x) {
/// ///
/// \brief The Standard Trigonometric Tangent /// \brief The Standard Trigonometric Tangent
/// ///
/// \returns The Tangent of \f$\theta\f$ in the Range \f$\left[-\inf,\,\inf\right]\f$<br><br> /// \returns The Tangent of \math{\theta} in the Range \math{\left[-\inf,\,\inf\right]}<br><br>
/// \details The Standard Trigonometric Tangent <br><br> /// \details The Standard Trigonometric Tangent <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param x The Angle \f$\theta\f$ in \f$radians\f$ /// \param x The Angle \math{\theta} in \math{radians}
template<typename genType> template<typename genType>
constexpr genType tan(genType x) { constexpr genType tan(genType x) {
return ::tan(x); return ::tan(x);
@@ -241,14 +241,14 @@ constexpr genType tan(genType x) {
/// @{ /// @{
/// ///
/// \brief Arc Sine. Returns an angle \f$\theta\f$ whose sine is /a x. /// \brief Arc Sine. Returns an angle \math{\theta} whose sine is /a x.
/// ///
/// \returns an angle \f$\theta\f$ whose sine is /a x. <br><br> /// \returns an angle \math{\theta} whose sine is /a x. <br><br>
/// \details Arc Sine. The range of values returned by this functions is /// \details Arc Sine. The range of values returned by this functions is
/// \f$\left[-\pi/2,\pi/2\right]\f$. Results are undefined if \f$\left|x\right|\,>\,1\f$. <br><br> /// \math{\left[-\pi/2,\pi/2\right]}. Results are undefined if \math{\left|x\right|\,>\,1}. <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param x The Sine Value produced by \f$\theta\f$ /// \param x The Sine Value produced by \math{\theta}
template<typename genType> template<typename genType>
constexpr genType asin(genType x) { constexpr genType asin(genType x) {
return ::asin(x); return ::asin(x);
@@ -256,14 +256,14 @@ constexpr genType asin(genType x) {
/// ///
/// \brief Arc Cosine. Returns an angle \f$\theta\f$ whose cosine is /a x. /// \brief Arc Cosine. Returns an angle \math{\theta} whose cosine is /a x.
/// ///
/// \returns an angle \f$\theta\f$ whose cosine is /a x. /// \returns an angle \math{\theta} whose cosine is /a x.
/// \details Arc Cosine. The range of values returned by this functions is /// \details Arc Cosine. The range of values returned by this functions is
/// \f$\left[0,\pi\right]\f$. Results are undefined if \f$\left|x\right|\,>\,1\f$. /// \math{\left[0,\pi\right]}. Results are undefined if \math{\left|x\right|\,>\,1}.
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param x The Cosine Value produced by \f$\theta\f$ /// \param x The Cosine Value produced by \math{\theta}
template<typename genType> template<typename genType>
constexpr genType acos(genType x) { constexpr genType acos(genType x) {
return ::acos(x); return ::acos(x);
@@ -271,14 +271,14 @@ constexpr genType acos(genType x) {
/// ///
/// \brief Arc Tangent. Returns an angle \f$\theta\f$ whose tangent is /a y_over_x. /// \brief Arc Tangent. Returns an angle \math{\theta} whose tangent is /a y_over_x.
/// ///
/// \returns an angle \f$\theta\f$ whose tangent is /a y_over_x. /// \returns an angle \math{\theta} whose tangent is /a y_over_x.
/// \details Arc Tangent. The range of values returned by this functions is /// \details Arc Tangent. The range of values returned by this functions is
/// \f$\left[\frac{-\pi}{2},\frac{\pi}{2}\right]\f$. Results are undefined if \f$\left|x\right|\,>\,1\f$. /// \math{\left[\frac{-\pi}{2},\frac{\pi}{2}\right]}. Results are undefined if \math{\left|x\right|\,>\,1}.
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param y_over_x The Cosine Value produced by \f$\theta\f$ /// \param y_over_x The Cosine Value produced by \math{\theta}
template<typename genType> template<typename genType>
constexpr genType atan(genType y_over_x) { constexpr genType atan(genType y_over_x) {
return ::atan(y_over_x); return ::atan(y_over_x);
@@ -286,15 +286,15 @@ constexpr genType atan(genType y_over_x) {
/// ///
/// \brief Arc Tangent. Returns an angle whose tangent is \f$\frac{y}{x}\f$. /// \brief Arc Tangent. Returns an angle whose tangent is \math{\frac{y}{x}}.
/// ///
/// \returns an angle whose tangent is \f$\frac{y}{x}\f$. <br><br> /// \returns an angle whose tangent is \math{\frac{y}{x}}. <br><br>
/// \details Arc Tangent. The signs of \a x and \a y are used to determine what quadrant the angle is in. /// \details Arc Tangent. The signs of \a x and \a y are used to determine what quadrant the angle is in.
/// The range of values returned by this functions is \f$\left[-\pi,\pi\right]\f$ <br><br> /// The range of values returned by this functions is \math{\left[-\pi,\pi\right]} <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param y The Sine Value produced by \f$\theta\f$ /// \param y The Sine Value produced by \math{\theta}
/// \param x The Cosine Value produced by \f$\theta\f$ /// \param x The Cosine Value produced by \math{\theta}
template<typename genType> template<typename genType>
constexpr genType atan(genType y, genType x) { constexpr genType atan(genType y, genType x) {
return ::atan2(y, x); return ::atan2(y, x);
@@ -310,12 +310,12 @@ constexpr genType atan(genType y, genType x) {
/// @{ /// @{
/// ///
/// \brief Returns the Hyperbolic Sine Function, \f$\frac{{e}^{x}-{e}^{-x}}{2}\f$ /// \brief Returns the Hyperbolic Sine Function, \math{\frac{{e}^{x}-{e}^{-x}}{2}}
/// ///
/// \returns The Hyperbolic Sine of \f$x\f$, \f$\frac{{e}^{x}-{e}^{-x}}{2}\f$ <br><br> /// \returns The Hyperbolic Sine of \math{x}, \math{\frac{{e}^{x}-{e}^{-x}}{2}} <br><br>
/// ///
/// \tparam genType floating point type /// \tparam genType floating point type
/// \param x The Hyperbolic Angle \f$\alpha\f$ /// \param x The Hyperbolic Angle \math{\alpha}
template<typename genType> template<typename genType>
constexpr genType sinh(genType x) { constexpr genType sinh(genType x) {
return ::sinh(x); return ::sinh(x);
@@ -323,11 +323,11 @@ constexpr genType sinh(genType x) {
/// ///
/// \brief Returns the Hyperbolic Cosine Function, \f$\frac{{e}^{x}+{e}^{-x}}{2}\f$ /// \brief Returns the Hyperbolic Cosine Function, \math{\frac{{e}^{x}+{e}^{-x}}{2}}
/// ///
/// \returns The Hyperbolic Cosine of \f$x\f$, \f$\frac{{e}^{x}+{e}^{-x}}{2}\f$ <br><br> /// \returns The Hyperbolic Cosine of \math{x}, \math{\frac{{e}^{x}+{e}^{-x}}{2}} <br><br>
/// ///
/// \param x The Hyperbolic Angle \f$\alpha\f$ /// \param x The Hyperbolic Angle \math{\alpha}
template<typename genType> template<typename genType>
constexpr genType cosh(genType x) { constexpr genType cosh(genType x) {
return ::cosh(x); return ::cosh(x);
@@ -335,11 +335,11 @@ constexpr genType cosh(genType x) {
/// ///
/// \brief Returns the Hyperbolic Tangent Function, \f$\frac{\text{sinh}(x)}{\text{cosh}(x)}\f$ /// \brief Returns the Hyperbolic Tangent Function, \math{\frac{\text{sinh}(x)}{\text{cosh}(x)}}
/// ///
/// \returns The Hyperbolic Tangent of \f$x\f$, \f$\frac{{e}^{x}+{e}^{-x}}{2}\f$ <br><br> /// \returns The Hyperbolic Tangent of \math{x}, \math{\frac{{e}^{x}+{e}^{-x}}{2}} <br><br>
/// ///
/// \param x The Hyperbolic Angle \f$\alpha\f$ /// \param x The Hyperbolic Angle \math{\alpha}
template<typename genType, size_t...i> template<typename genType, size_t...i>
constexpr genType tanh(genType x) { constexpr genType tanh(genType x) {
return ::tanh(x); return ::tanh(x);
@@ -355,10 +355,10 @@ constexpr genType tanh(genType x) {
/// ///
/// \brief The Inverse Hyperbolic Sine Function /// \brief The Inverse Hyperbolic Sine Function
/// ///
/// \returns the value \f$y\f$ that fulfills \f$x=\text{sinh}(y)\f$ <br><br> /// \returns the value \math{y} that fulfills \math{x=\text{sinh}(y)} <br><br>
/// \details The Inverse Hyperbolic Sine Function <br><br> /// \details The Inverse Hyperbolic Sine Function <br><br>
/// ///
/// \param x the hyperbolic angle \f$\alpha\f$ /// \param x the hyperbolic angle \math{\alpha}
template<typename genType, size_t...i> template<typename genType, size_t...i>
constexpr genType asinh(genType x) { constexpr genType asinh(genType x) {
return ::asinh(x); return ::asinh(x);
@@ -368,10 +368,10 @@ constexpr genType asinh(genType x) {
/// ///
/// \brief The Inverse Hyperbolic Cosine Function /// \brief The Inverse Hyperbolic Cosine Function
/// ///
/// \returns the value \f$y\f$ that fulfills \f$x=\text{cosh}(y)\f$ <br><br> /// \returns the value \math{y} that fulfills \math{x=\text{cosh}(y)} <br><br>
/// \details The Inverse Hyperbolic Cosine Function <br><br> /// \details The Inverse Hyperbolic Cosine Function <br><br>
/// ///
/// \param x the hyperbolic angle \f$\alpha\f$ /// \param x the hyperbolic angle \math{\alpha}
template<typename genType, size_t...i> template<typename genType, size_t...i>
constexpr genType acosh(genType x) { constexpr genType acosh(genType x) {
return ::acosh(x); return ::acosh(x);
@@ -381,10 +381,10 @@ constexpr genType acosh(genType x) {
/// ///
/// \brief The Inverse Hyperbolic Tangent Function /// \brief The Inverse Hyperbolic Tangent Function
/// ///
/// \returns the value \f$y\f$ that fulfills \f$x=\text{atanh}(y)\f$ <br><br> /// \returns the value \math{y} that fulfills \math{x=\text{atanh}(y)} <br><br>
/// \details The Inverse Hyperbolic Tangent Function <br><br> /// \details The Inverse Hyperbolic Tangent Function <br><br>
/// ///
/// \param x The Hyperbolic Angle \f$\alpha\f$ /// \param x The Hyperbolic Angle \math{\alpha}
template<typename genType, size_t...i> template<typename genType, size_t...i>
constexpr genType atanh(genType x) { constexpr genType atanh(genType x) {
return ::atanh(x); return ::atanh(x);

View File

@@ -46,33 +46,33 @@
/// <table width="100%" class="fieldtable" id="table_fennec_math_vector_types"> /// <table width="100%" class="fieldtable" id="table_fennec_math_vector_types">
/// <tr><th>Type <th>Corresponding Type <th>Brief /// <tr><th>Type <th>Corresponding Type <th>Brief
/// <tr><th colspan=3 style="text-align: center;">Floats /// <tr><th colspan=3 style="text-align: center;">Floats
/// <tr><td>``\f$vec2\f$`` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2 /// <tr><td>``\emph{vec2}`` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2
/// <tr><td>``\f$vec3\f$`` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3 /// <tr><td>``\emph{vec3}`` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3
/// <tr><td>``\f$vec4\f$`` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4 /// <tr><td>``\emph{vec4}`` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4
/// <tr><th colspan=3 style="text-align: center;">Doubles /// <tr><th colspan=3 style="text-align: center;">Doubles
/// <tr><td>``\f$dvec2\f$``<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2 /// <tr><td>``\emph{dvec2}``<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2
/// <tr><td>``\f$dvec3\f$``<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3 /// <tr><td>``\emph{dvec3}``<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3
/// <tr><td>``\f$dvec4\f$``<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4 /// <tr><td>``\emph{dvec4}``<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4
/// <tr><th colspan=3 style="text-align: center;">Booleans /// <tr><th colspan=3 style="text-align: center;">Booleans
/// <tr><td>``\f$bvec2\f$`` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2 /// <tr><td>``\emph{bvec2}`` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2
/// <tr><td>``\f$bvec3\f$`` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3 /// <tr><td>``\emph{bvec3}`` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3
/// <tr><td>``\f$bvec4\f$`` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4 /// <tr><td>``\emph{bvec4}`` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4
/// <tr><th colspan=3 style="text-align: center;">Integers /// <tr><th colspan=3 style="text-align: center;">Integers
/// <tr><td>``\f$ivec2\f$`` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2 /// <tr><td>``\emph{ivec2}`` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2
/// <tr><td>``\f$ivec3\f$`` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3 /// <tr><td>``\emph{ivec3}`` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3
/// <tr><td>``\f$ivec4\f$`` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4 /// <tr><td>``\emph{ivec4}`` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4
/// <tr><th colspan=3 style="text-align: center;">Unsigned Integers /// <tr><th colspan=3 style="text-align: center;">Unsigned Integers
/// <tr><td>``\f$uvec2\f$`` <td>\ref fennec::uvec2 <td>\copybrief fennec::uvec2 /// <tr><td>``\emph{uvec2}`` <td>\ref fennec::uvec2 <td>\copybrief fennec::uvec2
/// <tr><td>``\f$uvec3\f$`` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3 /// <tr><td>``\emph{uvec3}`` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3
/// <tr><td>``\f$uvec4\f$`` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4 /// <tr><td>``\emph{uvec4}`` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4
/// </table> /// </table>
/// ///
/// ///
/// ///
/// \section vector_components Components /// \section vector_components Components
/// ///
/// Vectors are usually made up of one to four components, named ``\f$x\f$``, ``\f$y\f$``, ``\f$z\f$``, and ``\f$w\f$``. /// Vectors are usually made up of one to four components, named \math{x}, \math{y}, \math{z}, and \math{w}.
/// Each component also has aliases for usage in colors ``\f$rgba\f$``, and texture coordinates ``\f$stpq\f$``. Accessing a /// Each component also has aliases for usage in colors \math{rgba}, and texture coordinates \math{stpq}. Accessing a
/// component outside the vector will cause an error at compile time, for example: /// component outside the vector will cause an error at compile time, for example:
/// ///
/// \code{.cpp} /// \code{.cpp}
@@ -93,9 +93,9 @@
/// The fennec \ref fennec_math_vector allows for the "swizzling" of vectors. Each component in the vector can be /// The fennec \ref fennec_math_vector allows for the "swizzling" of vectors. Each component in the vector can be
/// used in any combination, with up to 4 components, to create another vector. For example, <br><br> /// used in any combination, with up to 4 components, to create another vector. For example, <br><br>
/// ///
/// let \f$V = (0, 1, 2)\f$ /// let \math{V = (0, 1, 2)}
/// then \f$V.xy = (0, 1)\f$ /// then \math{V.xy = (0, 1)}
/// and \f$V.zy = (2, 1)\f$ /// and \math{V.zy = (2, 1)}
/// ///
/// \section section_vectors_more More Info /// \section section_vectors_more More Info
/// - \subpage fennec_math_vector_traits /// - \subpage fennec_math_vector_traits
@@ -125,22 +125,22 @@ using vec = decltype(detail::_gen_vector<vector, ScalarT>(make_index_metasequenc
/// ///
/// \brief Shorthand for creating a 2-element \ref fennec::vector, ```vec<ScalarT, 2>``` /// \brief Shorthand for creating a 2-element \ref fennec::vector, `(.*?)`
/// \details Shorthand for creating a 2-element \ref fennec::vector, ```vec<ScalarT, 2>``` /// \details Shorthand for creating a 2-element \ref fennec::vector, `(.*?)`
/// \tparam ScalarT The type of the Components /// \tparam ScalarT The type of the Components
template<typename ScalarT> template<typename ScalarT>
using tvec2 = vec<ScalarT, 2>; using tvec2 = vec<ScalarT, 2>;
/// ///
/// \brief Shorthand for creating a 3-element \ref fennec::vector, ```vec<ScalarT, 3>``` /// \brief Shorthand for creating a 3-element \ref fennec::vector, `(.*?)`
/// \details Shorthand for creating a 3-element \ref fennec::vector, ```vec<ScalarT, 3>``` /// \details Shorthand for creating a 3-element \ref fennec::vector, `(.*?)`
/// \tparam ScalarT The type of the Components /// \tparam ScalarT The type of the Components
template<typename ScalarT> template<typename ScalarT>
using tvec3 = vec<ScalarT, 3>; using tvec3 = vec<ScalarT, 3>;
/// ///
/// \brief Shorthand for creating a 4-element \ref fennec::vector, ```vec<ScalarT, 4>``` /// \brief Shorthand for creating a 4-element \ref fennec::vector, `(.*?)`
/// \details Shorthand for creating a 4-element \ref fennec::vector, ```vec<ScalarT, 4>``` /// \details Shorthand for creating a 4-element \ref fennec::vector, `(.*?)`
/// \tparam ScalarT The type of the Components /// \tparam ScalarT The type of the Components
template<typename ScalarT> template<typename ScalarT>
using tvec4 = vec<ScalarT, 4>; using tvec4 = vec<ScalarT, 4>;
@@ -377,7 +377,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief decay implementation /// \brief decay implementation
/// ///
/// \details /// \details
/// \returns scalar if \f$N==1\f$, otherwise, \ref fennec_math_vector "vector" /// \returns scalar if \math{N==1}, otherwise, \ref fennec_math_vector "vector"
decay_t decay() { decay_t decay() {
return static_cast<const decay_t&>(*this); return static_cast<const decay_t&>(*this);
} }
@@ -418,7 +418,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief copy assignment /// \brief copy assignment
/// ///
/// \details /// \details
/// \returns A reference to \c this, after having set \p lhs, such that \f$lhs_i=rhs_i\f$ /// \returns A reference to \c this, after having set \p lhs, such that \math{lhs_i=rhs_i}
/// \param rhs vector to copy /// \param rhs vector to copy
constexpr vector_t& operator=(const vector_t& rhs) { constexpr vector_t& operator=(const vector_t& rhs) {
return ((data[IndicesV] = rhs[IndicesV]), ..., *this); return ((data[IndicesV] = rhs[IndicesV]), ..., *this);
@@ -428,7 +428,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief move assignment /// \brief move assignment
/// ///
/// \details /// \details
/// \returns A reference to \c this, after having set \p lhs, such that \f$lhs_i=rhs_i\f$ /// \returns A reference to \c this, after having set \p lhs, such that \math{lhs_i=rhs_i}
/// \param rhs vector to move /// \param rhs vector to move
constexpr vector_t& operator=(vector_t&& rhs) noexcept { constexpr vector_t& operator=(vector_t&& rhs) noexcept {
return ((data[IndicesV] = fennec::move(rhs[IndicesV])), ..., *this); return ((data[IndicesV] = fennec::move(rhs[IndicesV])), ..., *this);
@@ -474,7 +474,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" addition operator /// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" addition operator
/// ///
/// \details /// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i+rhs_i}
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
constexpr friend vector_t operator+(scalar_t lhs, const vector_t& rhs) { constexpr friend vector_t operator+(scalar_t lhs, const vector_t& rhs) {
@@ -485,7 +485,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" subtraction operator /// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" subtraction operator
/// ///
/// \details /// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i-rhs_i}
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
constexpr friend vector_t operator-(scalar_t lhs, const vector_t& rhs) { constexpr friend vector_t operator-(scalar_t lhs, const vector_t& rhs) {
@@ -496,7 +496,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" multiplication operator /// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" multiplication operator
/// ///
/// \details /// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i={lhs_i}\cdot{rhs_i}}
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
constexpr friend vector_t operator*(scalar_t lhs, const vector_t& rhs) { constexpr friend vector_t operator*(scalar_t lhs, const vector_t& rhs) {
@@ -507,7 +507,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" division operator /// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" division operator
/// ///
/// \details /// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=\frac{lhs_i}{rhs_i}}
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
constexpr friend vector_t operator/(scalar_t lhs, const vector_t& rhs) { constexpr friend vector_t operator/(scalar_t lhs, const vector_t& rhs) {
@@ -518,7 +518,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" integer modulus operator /// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" integer modulus operator
/// ///
/// \details /// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\%rhs_i}
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
constexpr friend vector_t operator%(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator%(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
@@ -536,7 +536,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" addition operator /// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" addition operator
/// ///
/// \details /// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i+rhs_i}
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
constexpr friend vector_t operator+(const vector_t& lhs, scalar_t rhs) { constexpr friend vector_t operator+(const vector_t& lhs, scalar_t rhs) {
@@ -549,7 +549,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i-rhs_i}
constexpr friend vector_t operator-(const vector_t& lhs, scalar_t rhs) { constexpr friend vector_t operator-(const vector_t& lhs, scalar_t rhs) {
return vector_t((lhs[IndicesV] - rhs)...); return vector_t((lhs[IndicesV] - rhs)...);
} }
@@ -560,7 +560,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i={lhs_i}\cdot{rhs_i}}
constexpr friend vector_t operator*(const vector_t& lhs, scalar_t rhs) { constexpr friend vector_t operator*(const vector_t& lhs, scalar_t rhs) {
return vector_t((lhs[IndicesV] * rhs)...); return vector_t((lhs[IndicesV] * rhs)...);
} }
@@ -571,7 +571,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=\frac{lhs_i}{rhs_i}}
constexpr friend vector_t operator/(const vector_t& lhs, scalar_t rhs) { constexpr friend vector_t operator/(const vector_t& lhs, scalar_t rhs) {
return vector((lhs[IndicesV] / rhs)...); return vector((lhs[IndicesV] / rhs)...);
} }
@@ -582,7 +582,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs left hand side /// \param lhs left hand side
/// \param rhs right hand side /// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\%rhs_i}
constexpr friend vector_t operator%(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator%(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector((lhs[IndicesV] % rhs)...); return vector((lhs[IndicesV] % rhs)...);
} }
@@ -600,7 +600,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i+rhs_i}
constexpr friend vector_t& operator+=(vector_t& lhs, scalar_t rhs) { constexpr friend vector_t& operator+=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] += rhs), ..., lhs); return ((lhs[IndicesV] += rhs), ..., lhs);
} }
@@ -611,7 +611,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i-rhs_i}
constexpr friend vector_t& operator-=(vector_t& lhs, scalar_t rhs) { constexpr friend vector_t& operator-=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] -= rhs), ..., lhs); return ((lhs[IndicesV] -= rhs), ..., lhs);
} }
@@ -622,7 +622,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i={lhs_i}\cdot{rhs_i}}
constexpr friend vector_t& operator*=(vector_t& lhs, scalar_t rhs) { constexpr friend vector_t& operator*=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] *= rhs), ..., lhs); return ((lhs[IndicesV] *= rhs), ..., lhs);
} }
@@ -633,7 +633,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=\frac{lhs_i}{rhs_i}}
constexpr friend vector_t& operator/=(vector_t& lhs, scalar_t rhs) { constexpr friend vector_t& operator/=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] /= rhs), ..., lhs); return ((lhs[IndicesV] /= rhs), ..., lhs);
} }
@@ -644,7 +644,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\%rhs_i}
constexpr friend vector_t& operator%=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t& operator%=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] %= rhs), ..., lhs); return ((lhs[IndicesV] %= rhs), ..., lhs);
} }
@@ -661,7 +661,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// ///
/// \details /// \details
/// \param x the vector /// \param x the vector
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=-x_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=-x_i}
constexpr friend vector_t operator-(const vector_t& x) { constexpr friend vector_t operator-(const vector_t& x) {
return vector((-x[IndicesV])...); return vector((-x[IndicesV])...);
} }
@@ -672,7 +672,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i+rhs_i}
constexpr friend vector_t operator+(const vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t operator+(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] + rhs[IndicesV])...); return vector((lhs[IndicesV] + rhs[IndicesV])...);
} }
@@ -683,7 +683,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i-rhs_i}
constexpr friend vector_t operator-(const vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t operator-(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] - rhs[IndicesV])...); return vector((lhs[IndicesV] - rhs[IndicesV])...);
} }
@@ -694,7 +694,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i={lhs_i}\cdot{rhs_i}}
constexpr friend vector_t operator*(const vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t operator*(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] * rhs[IndicesV])...); return vector((lhs[IndicesV] * rhs[IndicesV])...);
} }
@@ -703,7 +703,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" division operator /// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" division operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=\frac{lhs_i}{rhs_i}}
constexpr friend vector_t operator/(const vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t operator/(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] / rhs[IndicesV])...); return vector((lhs[IndicesV] / rhs[IndicesV])...);
} }
@@ -714,7 +714,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\%rhs_i}
constexpr friend vector_t operator%(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator%(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector((lhs[IndicesV] % rhs[IndicesV])...); return vector((lhs[IndicesV] % rhs[IndicesV])...);
} }
@@ -732,7 +732,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i+rhs_i}
constexpr friend vector_t& operator+=(vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t& operator+=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] += rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] += rhs[IndicesV]), ..., lhs);
} }
@@ -743,7 +743,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i-rhs_i}
constexpr friend vector_t& operator-=(vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t& operator-=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] -= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] -= rhs[IndicesV]), ..., lhs);
} }
@@ -754,7 +754,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i={lhs_i}\cdot{rhs_i}}
constexpr friend vector_t& operator*=(vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t& operator*=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] *= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] *= rhs[IndicesV]), ..., lhs);
} }
@@ -765,7 +765,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=\frac{lhs_i}{rhs_i}}
constexpr friend vector_t& operator/=(vector_t& lhs, const vector_t& rhs) { constexpr friend vector_t& operator/=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] /= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] /= rhs[IndicesV]), ..., lhs);
} }
@@ -776,7 +776,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\%rhs_i}
constexpr friend vector_t& operator%=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t& operator%=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] %= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] %= rhs[IndicesV]), ..., lhs);
} }
@@ -793,7 +793,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// ///
/// \details /// \details
/// \param x the vector /// \param x the vector
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=!x_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=!x_i}
constexpr friend vector_t operator!(const vector_t& x) { constexpr friend vector_t operator!(const vector_t& x) {
return vector_t(!x[IndicesV]...); return vector_t(!x[IndicesV]...);
} }
@@ -804,7 +804,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&\&rhs_i}
constexpr friend vector_t operator&&(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>) { constexpr friend vector_t operator&&(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] && rhs)...); return vector_t((lhs[IndicesV] && rhs)...);
} }
@@ -813,7 +813,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" logical and operator /// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" logical and operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&\&rhs_i}
constexpr friend vector_t operator&&(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>) { constexpr friend vector_t operator&&(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] && rhs[IndicesV])...); return vector_t((lhs[IndicesV] && rhs[IndicesV])...);
} }
@@ -824,7 +824,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\|\|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\|\|rhs_i}
constexpr friend vector_t operator||(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>) { constexpr friend vector_t operator||(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] || rhs)...); return vector_t((lhs[IndicesV] || rhs)...);
} }
@@ -835,7 +835,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\|\|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\|\|rhs_i}
constexpr friend vector_t operator||(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>) { constexpr friend vector_t operator||(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] || rhs[IndicesV])...); return vector_t((lhs[IndicesV] || rhs[IndicesV])...);
} }
@@ -853,7 +853,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&rhs_i}
constexpr friend vector_t operator&(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator&(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] & rhs)...); return vector_t((lhs[IndicesV] & rhs)...);
} }
@@ -864,7 +864,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&rhs_i}
constexpr friend vector_t operator&(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator&(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] & rhs)...); return vector_t((lhs[IndicesV] & rhs)...);
} }
@@ -875,7 +875,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&rhs_i}
constexpr friend vector_t operator&=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator&=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] &= rhs), ..., lhs); return ((lhs[IndicesV] &= rhs), ..., lhs);
} }
@@ -886,7 +886,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&rhs_i}
constexpr friend vector_t operator&(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v< constexpr friend vector_t operator&(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<
scalar_t>) { scalar_t>) {
return vector_t((lhs[IndicesV] & rhs[IndicesV])...); return vector_t((lhs[IndicesV] & rhs[IndicesV])...);
@@ -898,7 +898,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\&rhs_i}
constexpr friend vector_t operator&=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator&=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] &= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] &= rhs[IndicesV]), ..., lhs);
} }
@@ -910,7 +910,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i|rhs_i}
constexpr friend vector_t operator|(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator|(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] | rhs)...); return vector_t((lhs[IndicesV] | rhs)...);
} }
@@ -921,7 +921,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i|rhs_i}
constexpr friend vector_t operator|(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator|(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] | rhs)...); return vector_t((lhs[IndicesV] | rhs)...);
} }
@@ -932,7 +932,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i|rhs_i}
constexpr friend vector_t operator|=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator|=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] |= rhs), ..., lhs); return ((lhs[IndicesV] |= rhs), ..., lhs);
} }
@@ -943,7 +943,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i|rhs_i}
constexpr friend vector_t operator|(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v< constexpr friend vector_t operator|(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<
scalar_t>) { scalar_t>) {
return vector_t((lhs[IndicesV] | rhs[IndicesV])...); return vector_t((lhs[IndicesV] | rhs[IndicesV])...);
@@ -955,7 +955,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details /// \details
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i|rhs_i}
constexpr friend vector_t operator|=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator|=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] |= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] |= rhs[IndicesV]), ..., lhs);
} }
@@ -965,7 +965,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise xor operator /// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise xor operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\^rhs_i}
constexpr friend vector_t operator^(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator^(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs ^ rhs[IndicesV])...); return vector_t((lhs ^ rhs[IndicesV])...);
} }
@@ -974,7 +974,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise xor operator /// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise xor operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\^rhs_i}
constexpr friend vector_t operator^(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator^(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] ^ rhs)...); return vector_t((lhs[IndicesV] ^ rhs)...);
} }
@@ -983,7 +983,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise xor assignment operator /// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise xor assignment operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\^rhs_i}
constexpr friend vector_t operator^=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator^=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] ^= rhs), ..., lhs); return ((lhs[IndicesV] ^= rhs), ..., lhs);
} }
@@ -992,7 +992,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise xor operator /// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise xor operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\^rhs_i}
constexpr friend vector_t operator^(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v< constexpr friend vector_t operator^(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<
scalar_t>) { scalar_t>) {
return vector_t((lhs[IndicesV] ^ rhs[IndicesV])...); return vector_t((lhs[IndicesV] ^ rhs[IndicesV])...);
@@ -1002,7 +1002,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise xor assignment operator /// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise xor assignment operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i\^rhs_i}
constexpr friend vector_t operator^=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator^=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] ^= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] ^= rhs[IndicesV]), ..., lhs);
} }
@@ -1012,7 +1012,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise left-shift operator /// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise left-shift operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i<<rhs_i}
constexpr friend vector_t operator<<(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator<<(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs << rhs[IndicesV])...); return vector_t((lhs << rhs[IndicesV])...);
} }
@@ -1021,7 +1021,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift operator /// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i<<rhs_i}
constexpr friend vector_t operator<<(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator<<(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] << rhs)...); return vector_t((lhs[IndicesV] << rhs)...);
} }
@@ -1030,7 +1030,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift assignment operator /// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift assignment operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<=rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i<<=rhs_i}
constexpr friend vector_t operator<<=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator<<=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] <<= rhs), ..., lhs); return ((lhs[IndicesV] <<= rhs), ..., lhs);
} }
@@ -1039,7 +1039,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator /// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i<<rhs_i}
constexpr friend vector_t operator<<(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator<<(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] << rhs[IndicesV])...); return vector_t((lhs[IndicesV] << rhs[IndicesV])...);
} }
@@ -1048,7 +1048,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator /// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<=rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i<<=rhs_i}
constexpr friend vector_t operator<<=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator<<=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] <<= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] <<= rhs[IndicesV]), ..., lhs);
} }
@@ -1058,7 +1058,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise or operator /// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i>>rhs_i}
constexpr friend vector_t operator>>(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator>>(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs >> rhs[IndicesV])...); return vector_t((lhs >> rhs[IndicesV])...);
} }
@@ -1067,7 +1067,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise or operator /// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise or operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i>>rhs_i}
constexpr friend vector_t operator>>(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator>>(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] >> rhs)...); return vector_t((lhs[IndicesV] >> rhs)...);
} }
@@ -1076,7 +1076,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift assignment operator /// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift assignment operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>=rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i>>=rhs_i}
constexpr friend vector_t operator>>=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator>>=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] >>= rhs), ..., lhs); return ((lhs[IndicesV] >>= rhs), ..., lhs);
} }
@@ -1085,7 +1085,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator /// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i>>rhs_i}
constexpr friend vector_t operator>>(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator>>(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] >> rhs[IndicesV])...); return vector_t((lhs[IndicesV] >> rhs[IndicesV])...);
} }
@@ -1094,7 +1094,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator /// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression /// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression /// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>=rhs_i\f$ /// \returns A \ref fennec_math_vector "vector" \a v such that, \math{v_i=lhs_i>>=rhs_i}
constexpr friend vector_t operator>>=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) { constexpr friend vector_t operator>>=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] >>= rhs[IndicesV]), ..., lhs); return ((lhs[IndicesV] >>= rhs[IndicesV]), ..., lhs);
} }

View File

@@ -25,6 +25,12 @@
#pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wpedantic"
#endif #endif
#if FENNEC_COMPILER_CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#endif
#if FENNEC_COMPILER_MSVC #if FENNEC_COMPILER_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4201) #pragma warning(disable:4201)
@@ -617,4 +623,12 @@ namespace fennec::detail
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#ifdef FENNEC_COMPILER_CLANG
#pragma clang diagnostic pop
#endif
#if FENNEC_COMPILER_MSVC
#pragma warning(pop)
#endif
#endif // FENNEC_MATH_VECTOR_STORAGE_H #endif // FENNEC_MATH_VECTOR_STORAGE_H

View File

@@ -74,17 +74,17 @@ namespace fennec
template<typename T> struct is_vector : detail::_is_vector_helper<remove_cvref_t<T>>{}; template<typename T> struct is_vector : detail::_is_vector_helper<remove_cvref_t<T>>{};
/// ///
/// \brief shorthand for ```is_vector<T>::value``` /// \brief shorthand for `(.*?)`
/// \tparam T type to check /// \tparam T type to check
template<typename T> constexpr bool is_vector_v = is_vector<T>::value; template<typename T> constexpr bool is_vector_v = is_vector<T>::value;
/// ///
/// \brief Get the number of Components in \p T, returns 1 for types that pass ```is_arithmetic<T>```, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases /// \brief Get the number of Components in \p T, returns 1 for types that pass `(.*?)`, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct component_count : detail::_component_count_helper<remove_cvref_t<T>>{}; template<typename T> struct component_count : detail::_component_count_helper<remove_cvref_t<T>>{};
/// ///
/// \brief shorthand for ```component_count<T>::value``` /// \brief shorthand for `(.*?)`
/// \tparam T type to get the component count of /// \tparam T type to get the component count of
template<typename T> constexpr size_t component_count_v = component_count<T>::value; template<typename T> constexpr size_t component_count_v = component_count<T>::value;
@@ -97,7 +97,7 @@ template<typename...Ts> struct total_component_count : integral_constant<size_t,
template<> struct total_component_count<> : integral_constant<size_t, 0>{}; template<> struct total_component_count<> : integral_constant<size_t, 0>{};
/// ///
/// \brief shorthand for ```component_count<T>::value``` /// \brief shorthand for `(.*?)`
/// \tparam Ts types to accumulate the count of /// \tparam Ts types to accumulate the count of
template<typename...Ts> constexpr size_t total_component_count_v = total_component_count<Ts...>::value; template<typename...Ts> constexpr size_t total_component_count_v = total_component_count<Ts...>::value;

View File

@@ -122,15 +122,10 @@ public:
/// \brief Alias for the size of allocations. Will use `Alloc::size_t` if present /// \brief Alias for the size of allocations. Will use `Alloc::size_t` if present
using size_t = typename _size<Alloc, pointer_t>::type; using size_t = typename _size<Alloc, pointer_t>::type;
// TODO: Document propagation
using propagate_on_container_copy_assignment = detect_t<false_type, _propagate_on_containter_copy_assignment, Alloc>;
using propagate_on_container_move_assignment = detect_t<false_type, _propagate_on_containter_move_assignment, Alloc>;
using propagate_on_container_swap = detect_t<false_type, _propagate_on_containter_swap, Alloc>;
/// \brief Checks if this allocator type is always equal to another allocator of similar type /// \brief Checks if this allocator type is always equal to another allocator of similar type
using is_always_equal = detect_t<false_type, _is_always_equal, Alloc>; using is_always_equal = detect_t<false_type, _is_always_equal, Alloc>;
/// \brief Rebinds the allocator type to produce an element type of type \f$TypeT\f$ /// \brief Rebinds the allocator type to produce an element type of type \emph{TypeT}
template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type; template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type;
// TODO: allocator_traits static functions // TODO: allocator_traits static functions
@@ -138,7 +133,7 @@ public:
/// ///
/// \brief Allocator implementation, uses \f$new\f$ and \f$delete\f$ operators. /// \brief Allocator implementation, uses \emph{new} and \emph{delete} operators.
/// \tparam T The data type to allocate /// \tparam T The data type to allocate
template<typename T> template<typename T>
class allocator class allocator
@@ -166,39 +161,39 @@ public:
/// ///
/// \brief Copy Assignment /// \brief Copy Assignment
/// \returns A reference to self /// \returns A reference to \emph{this}
constexpr allocator& operator=(const allocator&) = default; constexpr allocator& operator=(const allocator&) = default;
/// ///
/// \brief Equality operator /// \brief Equality operator
/// \returns \f$true\f$ /// \returns \emph{true}
constexpr bool_t operator==(const allocator&) { constexpr bool_t operator==(const allocator&) {
return true; return true;
} }
/// ///
/// \brief Inequality operator /// \brief Inequality operator
/// \returns \f$false\f$ /// \returns \emph{false}
constexpr bool_t operator!=(const allocator&) { constexpr bool_t operator!=(const allocator&) {
return false; return false;
} }
/// ///
/// \brief Equality operator for allocators of same type but with different data type /// \brief Equality operator for allocators of same type but with different data type
/// \returns \f$false\f$ /// \returns \emph{false}
template<typename U> constexpr bool_t operator==(const allocator<U>&) { template<typename U> constexpr bool_t operator==(const allocator<U>&) {
return false; return false;
} }
/// ///
/// \brief Inequality operator for allocators of same type but with different data type /// \brief Inequality operator for allocators of same type but with different data type
/// \returns \f$true\f$ /// \returns \emph{true}
template<typename U> constexpr bool_t operator!=(const allocator<U>&) { template<typename U> constexpr bool_t operator!=(const allocator<U>&) {
return true; return true;
} }
/// ///
/// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$ /// \brief Allocate a block of memory large enough to hold \emph{n} elements of type \emph{T}
/// \param n The number of elements /// \param n The number of elements
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
constexpr T* allocate(size_t n) { constexpr T* allocate(size_t n) {
@@ -206,7 +201,7 @@ public:
} }
/// ///
/// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$ /// \brief Allocate a block of memory large enough to hold \emph{n} elements of type \emph{T}
/// \param n The number of elements /// \param n The number of elements
/// \param align The alignment /// \param align The alignment
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
@@ -215,14 +210,14 @@ public:
} }
/// ///
/// \brief Deallocate a block of memory with type \f$T\f$ /// \brief Deallocate a block of memory with type \emph{T}
/// \param ptr The block to release /// \param ptr The block to release
constexpr void deallocate(T* ptr) { constexpr void deallocate(T* ptr) {
return ::operator delete(ptr); return ::operator delete(ptr);
} }
/// ///
/// \brief Deallocate a block of memory with type \f$T\f$ /// \brief Deallocate a block of memory with type \emph{T}
/// \param ptr The block to release /// \param ptr The block to release
/// \param align The alignment /// \param align The alignment
constexpr void deallocate(T* ptr, align_t align) { constexpr void deallocate(T* ptr, align_t align) {
@@ -232,7 +227,7 @@ public:
/// ///
/// \brief Allocator implementation, uses \f$new\f$ and \f$delete\f$ operators. /// \brief Allocator implementation, uses \emph{new} and \emph{delete} operators.
/// \tparam T The data type to allocate /// \tparam T The data type to allocate
template<typename T> template<typename T>
class allocator<T[]> class allocator<T[]>
@@ -260,40 +255,40 @@ public:
/// ///
/// \brief Copy Assignment /// \brief Copy Assignment
/// \returns A reference to self /// \returns A reference to \emph{this}
constexpr allocator& operator=(const allocator&) = default; constexpr allocator& operator=(const allocator&) = default;
/// ///
/// \brief Equality operator /// \brief Equality operator
/// \returns \f$true\f$ /// \returns \emph{true}
constexpr bool_t operator==(const allocator&) { constexpr bool_t operator==(const allocator&) {
return true; return true;
} }
/// ///
/// \brief Inequality operator /// \brief Inequality operator
/// \returns \f$false\f$ /// \returns \emph{false}
constexpr bool_t operator!=(const allocator&) { constexpr bool_t operator!=(const allocator&) {
return false; return false;
} }
/// ///
/// \brief Equality operator for allocators of same type but with different data type /// \brief Equality operator for allocators of same type but with different data type
/// \returns \f$false\f$ /// \returns \emph{false}
template<typename U> constexpr bool_t operator==(const allocator<U>&) { template<typename U> constexpr bool_t operator==(const allocator<U>&) {
return false; return false;
} }
/// ///
/// \brief Inequality operator for allocators of same type but with different data type /// \brief Inequality operator for allocators of same type but with different data type
/// \returns \f$true\f$ /// \returns \emph{true}
template<typename U> constexpr bool_t operator!=(const allocator<U>&) { template<typename U> constexpr bool_t operator!=(const allocator<U>&) {
return true; return true;
} }
/// ///
/// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$ /// \brief Allocate a block of memory large enough to hold \emph{n} elements of type \emph{T}
/// \param n The number of elements /// \param n The number of elements
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
constexpr T* allocate(size_t n) { constexpr T* allocate(size_t n) {
@@ -301,7 +296,7 @@ public:
} }
/// ///
/// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$ /// \brief Allocate a block of memory large enough to hold \emph{n} elements of type \emph{T}
/// \param n The number of elements /// \param n The number of elements
/// \param align The alignment /// \param align The alignment
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
@@ -310,14 +305,14 @@ public:
} }
/// ///
/// \brief Deallocate a block of memory with type \f$T\f$ /// \brief Deallocate a block of memory with type \emph{T}
/// \param ptr The block to release /// \param ptr The block to release
constexpr void deallocate(T* ptr) { constexpr void deallocate(T* ptr) {
return ::operator delete[](ptr); return ::operator delete[](ptr);
} }
/// ///
/// \brief Deallocate a block of memory with type \f$T\f$ /// \brief Deallocate a block of memory with type \emph{T}
/// \param ptr The block to release /// \param ptr The block to release
/// \param align The alignment /// \param align The alignment
constexpr void deallocate(T* ptr, align_t align) { constexpr void deallocate(T* ptr, align_t align) {
@@ -364,14 +359,14 @@ public:
/// @{ /// @{
/// ///
/// \brief Default Constructor, initializes internal data to \f$null\f$ and the capacity to \f$0\f$ /// \brief Default Constructor, initializes internal data to \emph{null} and the capacity to \emph{0}
constexpr allocation() noexcept constexpr allocation() noexcept
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) { : _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
} }
/// ///
/// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes /// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes
/// \param n The number of elements of type \f$T\f$ to allocate for /// \param n The number of elements of type \emph{T} to allocate for
explicit constexpr allocation(size_t n) noexcept explicit constexpr allocation(size_t n) noexcept
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) { : _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
allocate(n); allocate(n);
@@ -389,7 +384,7 @@ public:
/// ///
/// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes /// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes
/// \param n The number of elements of type \f$T\f$ to allocate for /// \param n The number of elements of type \emph{T} to allocate for
/// \param align The alignment of the allocation /// \param align The alignment of the allocation
constexpr allocation(size_t n, align_t align) noexcept constexpr allocation(size_t n, align_t align) noexcept
: _data(nullptr) : _data(nullptr)
@@ -413,7 +408,7 @@ public:
/// \brief Allocator Constructor /// \brief Allocator Constructor
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type \f$AllocT\f$ needs internal data. /// \details This constructor should be used when the type \emph{AllocT} needs internal data.
explicit constexpr allocation(const alloc_t& alloc) noexcept explicit constexpr allocation(const alloc_t& alloc) noexcept
: _alloc(alloc) : _alloc(alloc)
, _data(nullptr) , _data(nullptr)
@@ -423,10 +418,10 @@ public:
/// ///
/// \brief Sized Allocator Constructor /// \brief Sized Allocator Constructor
/// \param n The number of elements of type \f$T\f$ to allocate for /// \param n The number of elements of type \emph{T} to allocate for
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type \f$AllocT\f$ needs internal data. /// \details This constructor should be used when the type \emph{AllocT} needs internal data.
constexpr allocation(size_t n, const alloc_t& alloc) noexcept constexpr allocation(size_t n, const alloc_t& alloc) noexcept
: _alloc(alloc) : _alloc(alloc)
, _data(nullptr) , _data(nullptr)
@@ -442,7 +437,7 @@ public:
/// \param n the number of elements /// \param n the number of elements
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type \f$AllocT\f$ needs internal data. /// \details This constructor should be used when the type \emph{AllocT} needs internal data.
constexpr allocation(const T* data, size_t n, const alloc_t& alloc) constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
: allocation(n, alloc) { : allocation(n, alloc) {
fennec::memmove(static_cast<void*>(_data), data, n); fennec::memmove(static_cast<void*>(_data), data, n);
@@ -450,11 +445,11 @@ public:
/// ///
/// \brief Sized Allocator Constructor /// \brief Sized Allocator Constructor
/// \param n The number of elements of type \f$T\f$ to allocate for /// \param n The number of elements of type \emph{T} to allocate for
/// \param align The alignment of the allocation /// \param align The alignment of the allocation
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type \f$AllocT\f$ needs internal data. /// \details This constructor should be used when the type \emph{AllocT} needs internal data.
constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept
: _alloc(alloc) : _alloc(alloc)
, _data(nullptr) , _data(nullptr)
@@ -471,7 +466,7 @@ public:
/// \param align The alignment of the allocation /// \param align The alignment of the allocation
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type \f$AllocT\f$ needs internal data. /// \details This constructor should be used when the type \emph{AllocT} needs internal data.
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc) constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
: allocation(n, align, alloc) { : allocation(n, align, alloc) {
fennec::memmove(_data, data, n); fennec::memmove(_data, data, n);
@@ -489,7 +484,7 @@ public:
} }
/// ///
/// \brief Move Constructor, moves the data in \f$alloc\f$ to the new object and cleans \f$alloc\f$ so that it /// \brief Move Constructor, moves the data in \emph{alloc} to the new object and cleans \emph{alloc} so that it
/// can safely destruct /// can safely destruct
/// \param alloc The allocation to move /// \param alloc The allocation to move
constexpr allocation(allocation&& alloc) noexcept constexpr allocation(allocation&& alloc) noexcept
@@ -522,7 +517,7 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param alloc the allocation to copy /// \param alloc the allocation to copy
/// \returns a reference to \f$this\f$ /// \returns a reference to \emph{this}
constexpr allocation& operator=(const allocation& alloc) { constexpr allocation& operator=(const allocation& alloc) {
allocation::allocate(alloc.capacity(), alloc.alignment()); allocation::allocate(alloc.capacity(), alloc.alignment());
fennec::memmove(_data, alloc, size()); fennec::memmove(_data, alloc, size());
@@ -532,7 +527,7 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param alloc the allocation to copy /// \param alloc the allocation to copy
/// \returns a reference to \f$this\f$ /// \returns a reference to \emph{this}
constexpr allocation& operator=(allocation&& alloc) noexcept { constexpr allocation& operator=(allocation&& alloc) noexcept {
// Copy contents // Copy contents
@@ -561,7 +556,7 @@ public:
} }
/// ///
/// \brief Getter for the number of elements \f$n\f$ of type \f$T\f$ that the allocation can hold. /// \brief Getter for the number of elements \emph{n} of type \emph{T} that the allocation can hold.
/// \returns the size of the allocation in elements /// \returns the size of the allocation in elements
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _capacity; return _capacity;
@@ -588,7 +583,7 @@ public:
/// \details If there is already an allocated block of memory, the previous allocation is released. /// \details If there is already an allocated block of memory, the previous allocation is released.
/// ///
/// ///
/// \param n The number of elements of type \f$T\f$ to allocate for /// \param n The number of elements of type \emph{T} to allocate for
/// \param align The alignment to use /// \param align The alignment to use
constexpr void allocate(size_t n, align_t align = zero<align_t>()) noexcept { constexpr void allocate(size_t n, align_t align = zero<align_t>()) noexcept {
deallocate(); deallocate();
@@ -620,7 +615,7 @@ public:
/// \brief Reallocate the block with a new size. /// \brief Reallocate the block with a new size.
/// Contents are copied to the new allocation. /// Contents are copied to the new allocation.
/// ///
/// \param n The number of elements of type \f$T\f$ to allocate for /// \param n The number of elements of type \emph{T} to allocate for
/// \param align The alignment to use /// \param align The alignment to use
constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept { constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) { if (_data == nullptr) {
@@ -628,7 +623,8 @@ public:
return; return;
} }
value_t* old = _data; size_t old_cap = _capacity; value_t* old = _data;
const size_t old_cap = _capacity;
_data = nullptr; _data = nullptr;
allocate(n, align); allocate(n, align);
@@ -655,7 +651,7 @@ public:
/// ///
/// \param i The index to access /// \param i The index to access
/// \returns a reference to the value at position \f$i\f$ in the allocation /// \returns a reference to the value at position \emph{i} in the allocation
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assertd(i < capacity(), "Array Out of Bounds"); assertd(i < capacity(), "Array Out of Bounds");
return _data[i]; return _data[i];
@@ -664,7 +660,7 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i The index to access /// \param i The index to access
/// \returns a reference to the value at position \f$i\f$ in the allocation /// \returns a reference to the value at position \emph{i} in the allocation
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assertd(i < capacity(), "Array Out of Bounds"); assertd(i < capacity(), "Array Out of Bounds");
return _data[i]; return _data[i];

View File

@@ -89,27 +89,27 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a reference to the byte at \f$i\f$ /// \returns a reference to the byte at \emph{i}
constexpr byte_t& operator[](int i) { constexpr byte_t& operator[](int i) {
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
assertd(i >= 0 && (size_t)i < _size, "Array Out of Bounds"); assertd(i >= 0 && size_t(i) < _size, "Array Out of Bounds");
return _arr[i]; return _arr[i];
} }
/// ///
/// \brief Const Array Access Operator /// \brief Const Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a copy of the byte at \f$i\f$ /// \returns a copy of the byte at \emph{i}
constexpr byte_t operator[](int i) const { constexpr byte_t operator[](int i) const {
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
assertd(i >= 0 && (size_t)i < _size, "Array Out of Bounds"); assertd(i >= 0 && size_t(i) < _size, "Array Out of Bounds");
return _carr[i]; return _carr[i];
} }
/// ///
/// \brief Cast Function /// \brief Cast Function
/// \tparam T type to cast to /// \tparam T type to cast to
/// \returns a pointer to the underlying buffer interpreted as an array of \f$T\f$ /// \returns a pointer to the underlying buffer interpreted as an array of \emph{T}
template<typename T> template<typename T>
constexpr T* cast() { constexpr T* cast() {
void* temp = _arr; void* temp = _arr;
@@ -119,7 +119,7 @@ public:
/// ///
/// \brief Const Cast Function /// \brief Const Cast Function
/// \tparam T type to cast to /// \tparam T type to cast to
/// \returns a pointer to the underlying buffer interpreted as an array of \f$T\f$ /// \returns a pointer to the underlying buffer interpreted as an array of \emph{T}
template<typename T> template<typename T>
constexpr const T* cast() const { constexpr const T* cast() const {
const void* temp = _carr; const void* temp = _carr;
@@ -166,8 +166,8 @@ struct hash<byte_array> {
h *= m; h *= m;
} }
const uint8_t* b = (const uint8_t*)x; const uint8_t* b = reinterpret_cast<const uint8_t*>(x);
switch (n & 7) { switch (n & 0x7) {
case 7: h ^= uint64_t(b[6]) << 48; __attribute__((fallthrough)); case 7: h ^= uint64_t(b[6]) << 48; __attribute__((fallthrough));
case 6: h ^= uint64_t(b[5]) << 40; __attribute__((fallthrough)); case 6: h ^= uint64_t(b[5]) << 40; __attribute__((fallthrough));
case 5: h ^= uint64_t(b[4]) << 32; __attribute__((fallthrough)); case 5: h ^= uint64_t(b[4]) << 32; __attribute__((fallthrough));

View File

@@ -38,6 +38,8 @@
namespace fennec namespace fennec
{ {
// addressof ===========================================================================================================
/// ///
/// \brief Returns the address of an object regardless of whether the `&` operators is implemented. /// \brief Returns the address of an object regardless of whether the `&` operators is implemented.
/// \tparam TypeT The type of the objects /// \tparam TypeT The type of the objects
@@ -48,24 +50,45 @@ constexpr TypeT* addressof(TypeT& obj) {
return FENNEC_BUILTIN_ADDRESSOF(obj); return FENNEC_BUILTIN_ADDRESSOF(obj);
} }
// memchr ==============================================================================================================
/// ///
/// \brief Finds the first occurence of ```static_cast<uint8_t>(ch)``` in the first \f$n\f$ bytes /// \brief Finds the first occurrence of `static_cast<uint8_t>(ch)` in the first \emph{n} bytes
/// \param arr Pointer to the object, interpreted as an array of bytes /// \param arr Pointer to the object, interpreted as an array of bytes
/// \param ch The byte to search for /// \param ch The byte to search for
/// \param n The number of bytes to search /// \param n The number of bytes to search
/// \returns A pointer to the location of \f$ch\f$, otherwise \f$nullptr\f$ if \f$ch\f$ is not found. /// \returns A pointer to the location of \emph{ch}, otherwise \emph{nullptr} if \emph{ch} is not found.
using ::memchr; constexpr const void* memchr(const void* arr, int ch, size_t n) {
using ::wmemchr; return ::memchr(arr, ch, n);
}
/// ///
/// \brief Compares the bytes of \f$lhs\f$ with \f$rhs\f$. /// \brief Finds the first occurrence of `static_cast<wchar_t>(ch)` in the first \emph{n} characters
/// \param arr Pointer to the object, interpreted as an array of \emph{wchar_t}
/// \param ch The byte to search for
/// \param n The number of characters to search
/// \returns A pointer to the location of \emph{ch}, otherwise \emph{nullptr} if \emph{ch} is not found.
constexpr const wchar_t* wmemchr(const wchar_t* arr, wchar_t ch, size_t n) {
return ::wmemchr(arr, ch, n);
}
// memcmp ==============================================================================================================
///
/// \brief Compares the bytes of \emph{lhs} with \emph{rhs}.
/// \param lhs The first object, interpreted as an array of bytes /// \param lhs The first object, interpreted as an array of bytes
/// \param rhs The second object, interpreted as an array of bytes /// \param rhs The second object, interpreted as an array of bytes
/// \param n The number of bytes to parse /// \param n The number of bytes to parse
/// \returns \f$0\f$ if the first \f$n\f$ bytes of \f$lhs\f$ and \f$rhs\f$ are equivalent. Otherwise, returns \f$1\f$ /// \returns \math{0} if the first \emph{n} bytes of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
/// for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$ /// for the first byte \math{b} where \math{\textbf{lhs}[b] > \textbf{rhs}[b]}, and a negative value
using ::memcmp; /// for the first byte \math{b} where \math{\textbf{lhs}[b] < \textbf{rhs}[b]}
using ::wmemcmp; constexpr int memcmp(const void* lhs, const void* rhs, size_t n) {
return ::memcmp(lhs, rhs, n);
}
/// ///
/// \brief Safe version of memcmp /// \brief Safe version of memcmp
@@ -73,26 +96,58 @@ using ::wmemcmp;
/// \param rhs The second object, interpreted as an array of bytes /// \param rhs The second object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of lhs /// \param n0 The size, in bytes, of lhs
/// \param n1 The size, in bytes, of rhs /// \param n1 The size, in bytes, of rhs
/// \returns \f$0\f$ if the first \f$min(n0, n1)\f$ bytes of \f$lhs\f$ and \f$rhs\f$ are equivalent. Otherwise, returns \f$1\f$ /// \returns \math{0} if the first \emph{min(n0, n1)} bytes of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
/// for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$ /// for the first byte \math{b} where \math{\textbf{lhs}[b] > \textbf{rhs}[b]}, and a negative value
/// for the first byte \math{b} where \math{\textbf{lhs}[b] < \textbf{rhs}[b]}
constexpr int memcmp_s(const void* lhs, size_t n0, const void* rhs, size_t n1) { constexpr int memcmp_s(const void* lhs, size_t n0, const void* rhs, size_t n1) {
return memcmp(lhs, rhs, n0 < n1 ? n0 : n1); return ::memcmp(lhs, rhs, n0 < n1 ? n0 : n1);
}
///
/// \brief Compares the characters of \emph{lhs} with \emph{rhs}.
/// \param lhs The first object, interpreted as an array of \emph{wchar_t}
/// \param rhs The second object, interpreted as an array of \emph{wchar_t}
/// \param n The number of characters to parse
/// \returns \emph{0} if the first \emph{n} characters of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
/// for the first character \math{c} where \math{\textbf{lhs}[c] > \textbf{rhs}[c]}, and a negative value
/// for the first character \math{c} where \math{\textbf{lhs}[c] < \textbf{rhs}[c]}
constexpr int wmemcmp(const wchar_t* lhs, const wchar_t* rhs, size_t n) {
return ::wmemcmp(lhs, rhs, n);
} }
/// ///
/// \brief Copies the first \f$n\f$ bytes of \f$src\f$ to \f$dst\f$. /// \brief Safe version of memcmp
/// \param lhs The first object, interpreted as an array of \emph{wchar_t}
/// \param rhs The second object, interpreted as an array of \emph{wchar_t}
/// \param n0 The size, in characters, of lhs
/// \param n1 The size, in characters, of rhs
/// \returns \emph{0} if the first \emph{min(n0, n1)} character of \emph{lhs} and \emph{rhs} are equivalent. Otherwise, returns a positive value
/// for the first character \math{c} where \math{\textbf{lhs}[c] > \textbf{rhs}[c]}, and a negative value
/// for the first character \math{c} where \math{\textbf{lhs}[c] < \textbf{rhs}[c]}
constexpr int wmemcmp_s(const wchar_t* lhs, size_t n0, const wchar_t* rhs, size_t n1) {
return ::wmemcmp(lhs, rhs, n0 < n1 ? n0 : n1);
}
// memcmp ==============================================================================================================
///
/// \brief Copies the first \emph{n} bytes of \emph{src} to \emph{dst}.
/// \param dst The destination object, interpreted as an array of bytes /// \param dst The destination object, interpreted as an array of bytes
/// \param src The source object, interpreted as an array of bytes /// \param src The source object, interpreted as an array of bytes
/// \param n The number of bytes to copy /// \param n The number of bytes to copy
/// \returns \f$dst\f$ /// \returns \emph{dst}
/// ///
/// \details memcpy does not do any checking for whether \f$dst\f$ and \f$src\f$ overlap. Let \f$k\f$ be the number of /// \details memcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
/// bytes of which \f$dst\f$ and \f$src\f$. If \f$k > 0 & src < dst\f$ then the first \f$k\f$ elements of /// by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
/// \f$src\f$ will be repeated in \f$dst\f$ with a period of \f$k\f$. /// \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
/// ///
/// A full mathematical proof of this function is possible in Set Theory. /// A full mathematical proof of this function is possible in Set Theory.
using ::memcpy; constexpr void* memcpy(void* dst, const void* src, size_t n) {
using ::wmemcpy; return ::memcpy(dst, src, n);
}
/// ///
/// \brief Safe version of memcpy /// \brief Safe version of memcpy
@@ -100,19 +155,64 @@ using ::wmemcpy;
/// \param src The source object, interpreted as an array of bytes /// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst /// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src /// \param n1 The size, in bytes, of src
/// \returns \f$dst\f$ /// \returns \emph{dst}
///
/// \details memcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
/// by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
/// \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
/// A full mathematical proof of this function is possible in Set Theory.
constexpr void* memcpy_s(void* dst, size_t n0, const void* src, size_t n1) { constexpr void* memcpy_s(void* dst, size_t n0, const void* src, size_t n1) {
return memcpy(dst, src, n0 < n1 ? n0 : n1); return ::memcpy(dst, src, n0 < n1 ? n0 : n1);
}
///
/// \brief Copies the first \emph{n} characters of \emph{src} to \emph{dst}.
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n The number of characters to copy
/// \returns \emph{dst}
///
/// \details wmemcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
/// by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
/// \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
/// A full mathematical proof of this function is possible in Set Theory.
constexpr void* wmemcpy(wchar_t* dst, const wchar_t* src, size_t n) {
return ::wmemcpy(dst, src, n);
} }
/// ///
/// \brief Copies the first \f$n\f$ bytes of \f$src\f$ to \f$dst\f$, with overlap correction.. /// \brief Safe version of wmemcpy
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n0 The size, in characters, of dst
/// \param n1 The size, in characters, of src
/// \returns \emph{dst}
///
/// \details wmemcpy does not do any checking for whether \emph{dst} and \emph{src} overlap. Let \math{k} be the offset
/// by which \emph{dst} and \emph{src} overlap. If \math{k > 0 & \textbf{src} < \textbf{dst}} then the first \math{k} elements of
/// \emph{src} will be repeated in \emph{dst} with a period of \math{k}.
///
/// A full mathematical proof of this function is possible in Set Theory.
constexpr void* wmemcpy_s(wchar_t* dst, size_t n0, const wchar_t* src, size_t n1) {
return ::wmemcpy(dst, src, n0 < n1 ? n0 : n1);
}
// memmove =============================================================================================================
///
/// \brief Copies the first \emph{n} bytes of \emph{src} to \emph{dst}, with overlap correction.
/// \param dst The destination object, interpreted as an array of bytes /// \param dst The destination object, interpreted as an array of bytes
/// \param src The source object, interpreted as an array of bytes /// \param src The source object, interpreted as an array of bytes
/// \param n The number of bytes to copy /// \param n The number of bytes to copy
/// \returns \f$dst\f$ /// \returns \emph{dst}
using ::memmove; constexpr void* memmove(void* dst, const void* src, size_t n) {
using ::wmemmove; return ::memmove(dst, src, n);
}
/// ///
/// \brief Safe version of memmove /// \brief Safe version of memmove
@@ -120,19 +220,54 @@ using ::wmemmove;
/// \param src The source object, interpreted as an array of bytes /// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst /// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src /// \param n1 The size, in bytes, of src
/// \returns \f$dst\f$ /// \returns \emph{dst}
constexpr void* memmove_s(void* dst, size_t n0, const void* src, size_t n1) { constexpr void* memmove_s(void* dst, size_t n0, const void* src, size_t n1) {
return memmove(dst, src, n0 < n1 ? n0 : n1); return ::memmove(dst, src, n0 < n1 ? n0 : n1);
}
///
/// \brief Copies the first \emph{n} characters of \emph{src} to \emph{dst}, with overlap correction.
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n The number of characters to copy
/// \returns \emph{dst}
constexpr void* wmemmove(wchar_t* dst, const wchar_t* src, size_t n) {
return ::wmemmove(dst, src, n);
} }
/// ///
/// \brief Sets all bytes of \f$dst\f$ to \f$ch\f$, interpreted as an \f$uint8_t\f$ /// \brief Safe version of wmemmove
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param src The source object, interpreted as an array of \emph{wchar_t}
/// \param n0 The size, in characters, of dst
/// \param n1 The size, in characters, of src
/// \returns \emph{dst}
constexpr wchar_t* wmemmove_s(wchar_t* dst, size_t n0, const wchar_t* src, size_t n1) {
return ::wmemmove(dst, src, n0 < n1 ? n0 : n1);
}
// memset ==============================================================================================================
///
/// \brief Sets all bytes of \emph{dst} to \emph{ch}, interpreted as an \emph{uint8_t}
/// \param dst The destination object, interpreted as an array of bytes /// \param dst The destination object, interpreted as an array of bytes
/// \param ch The value, interpreted as an \f$uint8\_t\f$ /// \param ch The value, interpreted as an \emph{uint8_t}
/// \param n The number of bytes to set /// \param n The number of bytes to set
/// \returns \f$dst\f$ constexpr void memset(void* dst, int ch, size_t n) {
using ::memset; ::memset(dst, ch, n);
using ::wmemset; }
///
/// \brief Sets all characters of \emph{dst} to \emph{ch}
/// \param dst The destination object, interpreted as an array of \emph{wchar_t}
/// \param ch The value, interpreted as an \emph{uint8_t}
/// \param n The number of characters to set
constexpr void wmemset(wchar_t* dst, wchar_t ch, size_t n) {
::wmemset(dst, ch, n);
}
} }

View File

@@ -23,7 +23,7 @@
// see https://git.mslockbo.org/mslockbo/fennec/src/commit/0eeb7ae3cff9d78e98dc5d9fc09bcb98b10986b9 for previous // see https://git.mslockbo.org/mslockbo/fennec/src/commit/0eeb7ae3cff9d78e98dc5d9fc09bcb98b10986b9 for previous
// implementation // implementation
#if FENNEC_COMPILER_GCC #if FENNEC_GLIBC
#ifndef __OPTIMIZE__ #ifndef __OPTIMIZE__
# define __OPTIMIZE__ # define __OPTIMIZE__
#else #else
@@ -34,7 +34,7 @@
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
#if FENNEC_COMPILER_GCC #if FENNEC_GLIBC
#ifndef FENNEC_OPTIMIZE_FOUND #ifndef FENNEC_OPTIMIZE_FOUND
#undef __OPTIMIZE__ #undef __OPTIMIZE__
#endif #endif

View File

@@ -54,7 +54,7 @@ struct nothrow_t
size_t pagesize(); size_t pagesize();
/// ///
/// \brief Default construct the object of type \f$TypeT\f$ at \f$ptr\f$ /// \brief Default construct the object of type \emph{TypeT} at \emph{ptr}
/// \tparam TypeT the type to construct /// \tparam TypeT the type to construct
/// \param ptr the pointer to the object to construct /// \param ptr the pointer to the object to construct
template<typename TypeT> void construct(TypeT* ptr) { template<typename TypeT> void construct(TypeT* ptr) {
@@ -62,7 +62,7 @@ template<typename TypeT> void construct(TypeT* ptr) {
} }
/// ///
/// \brief Copy construct the object of type \f$TypeT\f$ at \f$ptr\f$ /// \brief Copy construct the object of type \emph{TypeT} at \emph{ptr}
/// \tparam TypeT the type to construct /// \tparam TypeT the type to construct
/// \param ptr the pointer to the object to construct /// \param ptr the pointer to the object to construct
/// \param val the value to copy /// \param val the value to copy
@@ -71,7 +71,7 @@ template<typename TypeT> void construct(TypeT* ptr, const TypeT& val) {
} }
/// ///
/// \brief Move construct the object of type \f$TypeT\f$ at \f$ptr\f$ /// \brief Move construct the object of type \emph{TypeT} at \emph{ptr}
/// \tparam TypeT the type to construct /// \tparam TypeT the type to construct
/// \param ptr the pointer to the object to construct /// \param ptr the pointer to the object to construct
/// \param val the value to take ownership of /// \param val the value to take ownership of
@@ -80,7 +80,7 @@ template<typename TypeT> void construct(TypeT* ptr, TypeT&& val) {
} }
/// ///
/// \brief Variadic construct the object of type \f$TypeT\f$ at \f$ptr\f$ /// \brief Variadic construct the object of type \emph{TypeT} at \emph{ptr}
/// \tparam TypeT the type to construct /// \tparam TypeT the type to construct
/// \tparam ArgsT the argument types /// \tparam ArgsT the argument types
/// \param ptr the pointer to the object to construct /// \param ptr the pointer to the object to construct
@@ -90,7 +90,7 @@ template<typename TypeT, typename...ArgsT> void construct(TypeT* ptr, ArgsT&&...
} }
/// ///
/// \brief Destruct the object of type \f$TypeT\f$ at \f$ptr\f$ /// \brief Destruct the object of type \emph{TypeT} at \emph{ptr}
/// \tparam TypeT the type to destruct /// \tparam TypeT the type to destruct
/// \param ptr the pointer to the object to destruct /// \param ptr the pointer to the object to destruct
template<typename TypeT> void destruct(TypeT* ptr) { template<typename TypeT> void destruct(TypeT* ptr) {

View File

@@ -26,7 +26,7 @@ namespace fennec
{ {
/// ///
/// \brief Struct for wrapping C++ \f$delete\f$ /// \brief Struct for wrapping C++ \emph{delete}
/// \tparam TypeT The type of the buffer to be deleted /// \tparam TypeT The type of the buffer to be deleted
template<typename TypeT> template<typename TypeT>
struct default_delete struct default_delete
@@ -42,7 +42,7 @@ struct default_delete
constexpr default_delete(const default_delete<ConvT>&) noexcept {} constexpr default_delete(const default_delete<ConvT>&) noexcept {}
/// ///
/// \brief Function Call Operator, calls \f$delete\f$ on \f$ptr\f$ /// \brief Function Call Operator, calls \emph{delete} on \emph{ptr}
/// \param ptr Memory resource to delete /// \param ptr Memory resource to delete
constexpr void operator()(TypeT* ptr) const noexcept { constexpr void operator()(TypeT* ptr) const noexcept {
static_assert(not is_void_v<TypeT>, "cannot delete a pointer to an incomplete type"); static_assert(not is_void_v<TypeT>, "cannot delete a pointer to an incomplete type");
@@ -67,7 +67,7 @@ struct default_delete<TypeT[]>
constexpr default_delete(const default_delete<ConvT(*)[]>&) noexcept {} constexpr default_delete(const default_delete<ConvT(*)[]>&) noexcept {}
/// ///
/// \brief Function Call Operator, calls \f$delete\f$ on \f$ptr\f$ /// \brief Function Call Operator, calls \emph{delete} on \emph{ptr}
/// \param ptr Memory resource to delete /// \param ptr Memory resource to delete
template<class ArrT> requires requires { is_convertible_v<ArrT(*)[], TypeT(*)[]> == true; } template<class ArrT> requires requires { is_convertible_v<ArrT(*)[], TypeT(*)[]> == true; }
constexpr void operator()(TypeT* ptr) const noexcept { constexpr void operator()(TypeT* ptr) const noexcept {
@@ -122,7 +122,7 @@ public:
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr, delete_t()) {} constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr, delete_t()) {}
/// ///
/// \brief Pointer Constructor, creates a unique_ptr that owns \f$ptr\f$ with deleter \f$del\f$ /// \brief Pointer Constructor, creates a unique_ptr that owns \emph{ptr} with deleter \emph{del}
/// \param ptr The resource to own /// \param ptr The resource to own
/// \param del The deleter /// \param del The deleter
explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del = delete_t()) explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del = delete_t())
@@ -138,14 +138,16 @@ public:
} }
/// ///
/// \brief Move Constructor, transfers ownership from \f$other\f$ /// \brief Move Constructor, transfers ownership from \emph{other}
/// \param other The unique_ptr to take ownership from /// \param other The unique_ptr to take ownership from
template<typename DerivedT> requires(is_base_of_v<TypeT, DerivedT>) template<typename DerivedT> requires(is_base_of_v<TypeT, DerivedT>)
constexpr unique_ptr(unique_ptr<DerivedT>&& other) constexpr unique_ptr(unique_ptr<DerivedT>&& other)
: _handle(other.release()) { : _handle(other.release()) {
} }
// Delete copy constructor ///
/// \brief Copy Constructor
/// \details Deleted
constexpr unique_ptr(const unique_ptr&) = delete; constexpr unique_ptr(const unique_ptr&) = delete;
/// ///
@@ -166,18 +168,21 @@ public:
/// ///
/// \brief move constructor /// \brief move constructor
/// \param r the pointer to take ownership of /// \param r the pointer to take ownership of
/// \returns a reference to self /// \returns a reference to \emph{this}
constexpr unique_ptr& operator=(unique_ptr&& r) noexcept { constexpr unique_ptr& operator=(unique_ptr&& r) noexcept {
_delete = r._delete; _delete = r._delete;
fennec::swap(_handle, r._handle); fennec::swap(_handle, r._handle);
return *this; return *this;
} }
/// @} ///
/// \brief Copy Assignment
private: /// \details Deleted
/// \returns Deleted
constexpr unique_ptr& operator=(const unique_ptr&) = delete; constexpr unique_ptr& operator=(const unique_ptr&) = delete;
/// @}
// Properties ========================================================================================================== // Properties ==========================================================================================================
public: public:
@@ -186,14 +191,14 @@ public:
/// @{ /// @{
/// ///
/// \returns \f$true\f$ if there is not a held pointer, \f$false\f$ otherwise /// \returns \emph{true} if there is not a held pointer, \emph{false} otherwise
bool is_empty() { bool is_empty() {
return _handle == nullptr; return _handle == nullptr;
} }
/// ///
/// \brief implicit boolean conversion /// \brief implicit boolean conversion
/// \returns \f$true\f$ if there is a held pointer, \f$false\f$ otherwise /// \returns \emph{true} if there is a held pointer, \emph{false} otherwise
operator bool() const { operator bool() const {
return _handle != nullptr; return _handle != nullptr;
} }
@@ -278,11 +283,11 @@ private:
}; };
/// ///
/// \brief Creates a unique pointer holding an object of type \f$TypeT\f$ /// \brief Creates a unique pointer holding an object of type \emph{TypeT}
/// \tparam TypeT The type /// \tparam TypeT The type
/// \tparam ArgsT The constructor arguments, automatically deduced /// \tparam ArgsT The constructor arguments, automatically deduced
/// \param args The constructor arguments /// \param args The constructor arguments
/// \returns A unique pointer holding a heap allocated object of type \f$TypeT\f$ constructed with arguments \f$args\f$ /// \returns A unique pointer holding a heap allocated object of type \emph{TypeT} constructed with arguments \emph{args}
template<typename TypeT, typename...ArgsT> template<typename TypeT, typename...ArgsT>
unique_ptr<TypeT> make_unique(ArgsT&&...args) { unique_ptr<TypeT> make_unique(ArgsT&&...args) {
return unique_ptr<TypeT>(new TypeT(fennec::forward<ArgsT>(args)...)); return unique_ptr<TypeT>(new TypeT(fennec::forward<ArgsT>(args)...));

View File

@@ -51,9 +51,9 @@ class display_server;
/// ///
/// \details An implementation for a display server should inherit `display_server_base` and note the following: /// \details An implementation for a display server should inherit `display_server_base` and note the following:
/// ///
/// For a server type \f$DisplayT\f$; any \f$gfxcontext\f$ implementation that wishes to implement \f$DisplayT\f$ /// For a server type \emph{DisplayT}; any `gfxcontext` implementation that wishes to implement \emph{DisplayT}
/// must provide a constructor that accepts a `DisplayT*`. `DisplayT::ctx_registry::register_type` must then be /// must provide a constructor that accepts a \emph{DisplayT*}. `DisplayT::ctx_registry::register_type()` must then be
/// called for the \f$gfxcontext\f$ implementation. /// called for the `gfxcontext` implementation.
class display_server : public type_registry<display_server, platform*> { class display_server : public type_registry<display_server, platform*> {
// Definitions & Constants ============================================================================================= // Definitions & Constants =============================================================================================
public: public:
@@ -136,13 +136,13 @@ public:
/// ///
/// \brief feature support checking function /// \brief feature support checking function
/// \param feature the feature to check /// \param feature the feature to check
/// \returns \f$true\f$ if the feature is supported, \f$false\f$ otherwise /// \returns \emph{true} if the feature is supported, \emph{false} otherwise
bool has_feature(uint32_t feature) const { bool has_feature(uint32_t feature) const {
return features.test(feature); return features.test(feature);
} }
/// ///
/// \returns \f$true\f$ if connected to the display server, \f$false\f$ otherwise /// \returns \emph{true} if connected to the display server, \emph{false} otherwise
virtual bool connected() const = 0; virtual bool connected() const = 0;
/// @} /// @}

View File

@@ -87,14 +87,16 @@ public:
/// \brief constructor /// \brief constructor
platform(); platform();
///
/// \brief Copy Constructor
/// \details Deleted, no semantics for copying a platform
platform(const platform&) = delete;
/// ///
/// \brief destructor /// \brief destructor
virtual ~platform() = default; virtual ~platform() = default;
private:
platform(const platform&) = delete;
/// @} /// @}

View File

@@ -164,15 +164,21 @@ public:
/// ///
/// \returns the current configuration of the window /// \returns the current configuration of the window
const config& get_config() const { return cfg; } const config& get_config() const {
return cfg;
}
/// ///
/// \returns the parent window /// \returns the parent window
window* get_parent() const { return parent; } window* get_parent() const {
return parent;
}
/// ///
/// \returns the nearest top-level window in the hierarchy /// \returns the nearest top-level window in the hierarchy
window* get_root() const { return root; } window* get_root() const {
return root;
}
/// ///
/// \returns the underlying handle of the window /// \returns the underlying handle of the window
@@ -208,19 +214,29 @@ public:
/// ///
/// \returns the width of the window /// \returns the width of the window
int get_width() const { return state.rect.size.x; } int get_width() const {
return state.rect.size.x;
}
/// ///
/// \returns the height of the window /// \returns the height of the window
int get_height() const { return state.rect.size.y; } int get_height() const {
return state.rect.size.y;
}
/// ///
/// \returns the x position of the window /// \returns the x position of the window
int get_pos_x() const { return state.rect.position.x; } int get_pos_x() const {
return state.rect.position.x;
}
/// ///
/// \returns the y position of the window /// \returns the y position of the window
int get_pos_y() const { return state.rect.position.y; } int get_pos_y() const {
return state.rect.position.y;
}
virtual void set_size(const ivec2& size) = 0;
/// @} /// @}
@@ -234,22 +250,22 @@ public:
/// ///
/// \brief tests if the window is visible /// \brief tests if the window is visible
/// \returns \f$true\f$ if the window is visible, \f$false\f$ otherwise /// \returns \emph{true} if the window is visible, \emph{false} otherwise
bool is_visible() const { return state.flags.test(state_visible); } bool is_visible() const { return state.flags.test(state_visible); }
/// ///
/// \brief tests if the window is a child /// \brief tests if the window is a child
/// \returns \f$true\f$ if the window is a child, \f$false\f$ otherwise /// \returns \emph{true} if the window is a child, \emph{false} otherwise
bool is_child() const { return state.flags.test(state_child); } bool is_child() const { return state.flags.test(state_child); }
/// ///
/// \brief tests if the window is running /// \brief tests if the window is running
/// \returns \f$true\f$ if the window is running, \f$false\f$ otherwise /// \returns \emph{true} if the window is running, \emph{false} otherwise
bool is_running() const { return state.flags.test(state_running); } bool is_running() const { return state.flags.test(state_running); }
/// ///
/// \brief tests if the window is suspended /// \brief tests if the window is suspended
/// \returns \f$true\f$ if the window is suspended, \f$false\f$ otherwise /// \returns \emph{true} if the window is suspended, \emph{false} otherwise
bool is_suspended() const { return state.flags.test(state_suspended); } bool is_suspended() const { return state.flags.test(state_suspended); }
/// @} /// @}
@@ -265,48 +281,48 @@ public:
/// ///
/// \brief tests a specific flag /// \brief tests a specific flag
/// \param flag the flag from `window::flag_` /// \param flag the flag from `window::flag_`
/// \returns \f$true\f$ if the flag is set, \f$false\f$ otherwise /// \returns \emph{true} if the flag is set, \emph{false} otherwise
bool get_flag(uint8_t flag) const { return cfg.flags.test(flag); } bool get_flag(uint8_t flag) const { return cfg.flags.test(flag); }
/// ///
/// \brief check if the window is flagged to always be on top of other windows /// \brief check if the window is flagged to always be on top of other windows
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_always_on_top() const { return get_flag(flag_always_on_top); } bool is_always_on_top() const { return get_flag(flag_always_on_top); }
/// ///
/// \brief check if the window is flagged to have no window decorations /// \brief check if the window is flagged to have no window decorations
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_borderless() const { return get_flag(flag_borderless); } bool is_borderless() const { return get_flag(flag_borderless); }
/// ///
/// \brief check if the window is flagged to be modal /// \brief check if the window is flagged to be modal
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_modal() const { return get_flag(flag_modal); } bool is_modal() const { return get_flag(flag_modal); }
/// ///
/// \brief check if the window is flagged to pass mouse input to windows underneath from the same application /// \brief check if the window is flagged to pass mouse input to windows underneath from the same application
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_passing_mouse() const { return get_flag(flag_pass_mouse); } bool is_passing_mouse() const { return get_flag(flag_pass_mouse); }
/// ///
/// \brief check if the window is flagged as a popup /// \brief check if the window is flagged as a popup
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_popup() const { return get_flag(flag_popup); } bool is_popup() const { return get_flag(flag_popup); }
/// ///
/// \brief check if the window is flagged to be resizable /// \brief check if the window is flagged to be resizable
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_resizable() const { return get_flag(flag_resizable); } bool is_resizable() const { return get_flag(flag_resizable); }
/// ///
/// \brief check if the window is flagged to be transparent /// \brief check if the window is flagged to be transparent
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_transparent() const { return get_flag(flag_transparent); } bool is_transparent() const { return get_flag(flag_transparent); }
/// ///
/// \brief check if the window is flagged to be unfocusable /// \brief check if the window is flagged to be unfocusable
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_no_focus() const { return get_flag(flag_no_focus); } bool is_no_focus() const { return get_flag(flag_no_focus); }
@@ -314,55 +330,55 @@ public:
/// \brief sets a specific flag /// \brief sets a specific flag
/// \param flag the flag from `window::flag_` /// \param flag the flag from `window::flag_`
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
virtual bool set_flag(uint8_t flag, bool val) = 0; virtual bool set_flag(uint8_t flag, bool val) = 0;
/// ///
/// \brief sets whether to always be on top of other windows /// \brief sets whether to always be on top of other windows
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_always_on_top(bool val) { return set_flag(flag_always_on_top, val); } bool set_always_on_top(bool val) { return set_flag(flag_always_on_top, val); }
/// ///
/// \brief sets whether to have no window decorations /// \brief sets whether to have no window decorations
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_borderless(bool val) { return set_flag(flag_borderless, val); } bool set_borderless(bool val) { return set_flag(flag_borderless, val); }
/// ///
/// \brief sets whether to be modal /// \brief sets whether to be modal
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_modal(bool val) { return set_flag(flag_modal, val); } bool set_modal(bool val) { return set_flag(flag_modal, val); }
/// ///
/// \brief sets whether to pass mouse input to windows underneath from the same application /// \brief sets whether to pass mouse input to windows underneath from the same application
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_passing_mouse(bool val) { return set_flag(flag_pass_mouse, val); } bool set_passing_mouse(bool val) { return set_flag(flag_pass_mouse, val); }
/// ///
/// \brief sets whether the window is a popup /// \brief sets whether the window is a popup
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_popup(bool val) { return set_flag(flag_popup, val); } bool set_popup(bool val) { return set_flag(flag_popup, val); }
/// ///
/// \brief sets whether to be resizable /// \brief sets whether to be resizable
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_resizable(bool val) { return set_flag(flag_resizable, val); } bool set_resizable(bool val) { return set_flag(flag_resizable, val); }
/// ///
/// \brief sets whetherto be transparent /// \brief sets whetherto be transparent
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_transparent(bool val) { return set_flag(flag_transparent, val); } bool set_transparent(bool val) { return set_flag(flag_transparent, val); }
/// ///
/// \brief sets whether to be unfocusable /// \brief sets whether to be unfocusable
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_no_focus(bool val) { return set_flag(flag_no_focus, val); } bool set_no_focus(bool val) { return set_flag(flag_no_focus, val); }
/// @} /// @}
@@ -385,10 +401,12 @@ public:
// Protected Member Variables ========================================================================================== // Protected Member Variables ==========================================================================================
public:
display_server* const server; //!< the display server the window belongs to
window* const parent; //!< the parent window
window* const root; //!< the nearest top-level window in the hierarchy
protected: protected:
display_server* const server; //!< the display server the window belongs to
window* const parent; //!< the parent window
window* root; //!< the nearest top-level window in the hierarchy
config cfg; //!< the current configuration config cfg; //!< the current configuration
state state; //!< the current state state state; //!< the current state
unique_ptr<gfxsurface> gfx_surface; //!< the corresponding graphics surface unique_ptr<gfxsurface> gfx_surface; //!< the corresponding graphics surface

View File

@@ -23,6 +23,8 @@
namespace fennec namespace fennec
{ {
///
/// \brief Platform Implementation for Linux-Based Operating Systems
class linux_platform : public unix_platform { class linux_platform : public unix_platform {
// Constructors & Destructor =========================================================================================== // Constructors & Destructor ===========================================================================================
@@ -31,7 +33,7 @@ public:
/// \name Constructors & Destructor ================================================================================ /// \name Constructors & Destructor ================================================================================
/// @{ /// @{
/// \brief constructor /// \brief Linux Platform Constructor
linux_platform() linux_platform()
: unix_platform() { : unix_platform() {
} }
@@ -39,11 +41,18 @@ public:
/// @} /// @}
// // Initialization ======================================================================================================
/// \name Initialization
/// @{
void initialize() override; //!< platform initialization void initialize() override; //!< platform initialization
void shutdown() override; //!< platform shutdown void shutdown() override; //!< platform shutdown
/// @}
private:
FENNEC_RTTI_CLASS_ENABLE(unix_platform) { FENNEC_RTTI_CLASS_ENABLE(unix_platform) {
} }
}; };

View File

@@ -1,4 +1,4 @@
/* Generated by wayland-scanner 1.24.0 */ /* Generated by wayland-scanner 1.25.0 */
#ifndef WAYLAND_CLIENT_PROTOCOL_H #ifndef WAYLAND_CLIENT_PROTOCOL_H
#define WAYLAND_CLIENT_PROTOCOL_H #define WAYLAND_CLIENT_PROTOCOL_H
@@ -841,23 +841,9 @@ extern const struct wl_interface wl_subcompositor_interface;
* hidden, or if a NULL wl_buffer is applied. These rules apply * hidden, or if a NULL wl_buffer is applied. These rules apply
* recursively through the tree of surfaces. * recursively through the tree of surfaces.
* *
* The behaviour of a wl_surface.commit request on a sub-surface * A sub-surface can be in one of two modes. The possible modes are
* depends on the sub-surface's mode. The possible modes are * synchronized and desynchronized, see methods wl_subsurface.set_sync and
* synchronized and desynchronized, see methods * wl_subsurface.set_desync.
* wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
* mode caches the wl_surface state to be applied when the parent's
* state gets applied, and desynchronized mode applies the pending
* wl_surface state directly. A sub-surface is initially in the
* synchronized mode.
*
* Sub-surfaces also have another kind of state, which is managed by
* wl_subsurface requests, as opposed to wl_surface requests. This
* state includes the sub-surface position relative to the parent
* surface (wl_subsurface.set_position), and the stacking order of
* the parent and its sub-surfaces (wl_subsurface.place_above and
* .place_below). This state is applied when the parent surface's
* wl_surface state is applied, regardless of the sub-surface's mode.
* As the exception, set_sync and set_desync are effective immediately.
* *
* The main surface can be thought to be always in desynchronized mode, * The main surface can be thought to be always in desynchronized mode,
* since it does not have a parent in the sub-surfaces sense. * since it does not have a parent in the sub-surfaces sense.
@@ -869,6 +855,15 @@ extern const struct wl_interface wl_subcompositor_interface;
* synchronized mode, and then assume that all its child and grand-child * synchronized mode, and then assume that all its child and grand-child
* sub-surfaces are synchronized, too, without explicitly setting them. * sub-surfaces are synchronized, too, without explicitly setting them.
* *
* If a surface behaves as in synchronized mode, it is effectively
* synchronized, otherwise it is effectively desynchronized.
*
* A sub-surface is initially in the synchronized mode.
*
* The wl_subsurface interface has requests which modify double-buffered
* state of the parent surface (wl_subsurface.set_position, .place_above and
* .place_below).
*
* Destroying a sub-surface takes effect immediately. If you need to * Destroying a sub-surface takes effect immediately. If you need to
* synchronize the removal of a sub-surface to the parent surface update, * synchronize the removal of a sub-surface to the parent surface update,
* unmap the sub-surface first by attaching a NULL wl_buffer, update parent, * unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
@@ -899,23 +894,9 @@ extern const struct wl_interface wl_subcompositor_interface;
* hidden, or if a NULL wl_buffer is applied. These rules apply * hidden, or if a NULL wl_buffer is applied. These rules apply
* recursively through the tree of surfaces. * recursively through the tree of surfaces.
* *
* The behaviour of a wl_surface.commit request on a sub-surface * A sub-surface can be in one of two modes. The possible modes are
* depends on the sub-surface's mode. The possible modes are * synchronized and desynchronized, see methods wl_subsurface.set_sync and
* synchronized and desynchronized, see methods * wl_subsurface.set_desync.
* wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
* mode caches the wl_surface state to be applied when the parent's
* state gets applied, and desynchronized mode applies the pending
* wl_surface state directly. A sub-surface is initially in the
* synchronized mode.
*
* Sub-surfaces also have another kind of state, which is managed by
* wl_subsurface requests, as opposed to wl_surface requests. This
* state includes the sub-surface position relative to the parent
* surface (wl_subsurface.set_position), and the stacking order of
* the parent and its sub-surfaces (wl_subsurface.place_above and
* .place_below). This state is applied when the parent surface's
* wl_surface state is applied, regardless of the sub-surface's mode.
* As the exception, set_sync and set_desync are effective immediately.
* *
* The main surface can be thought to be always in desynchronized mode, * The main surface can be thought to be always in desynchronized mode,
* since it does not have a parent in the sub-surfaces sense. * since it does not have a parent in the sub-surfaces sense.
@@ -927,6 +908,15 @@ extern const struct wl_interface wl_subcompositor_interface;
* synchronized mode, and then assume that all its child and grand-child * synchronized mode, and then assume that all its child and grand-child
* sub-surfaces are synchronized, too, without explicitly setting them. * sub-surfaces are synchronized, too, without explicitly setting them.
* *
* If a surface behaves as in synchronized mode, it is effectively
* synchronized, otherwise it is effectively desynchronized.
*
* A sub-surface is initially in the synchronized mode.
*
* The wl_subsurface interface has requests which modify double-buffered
* state of the parent surface (wl_subsurface.set_position, .place_above and
* .place_below).
*
* Destroying a sub-surface takes effect immediately. If you need to * Destroying a sub-surface takes effect immediately. If you need to
* synchronize the removal of a sub-surface to the parent surface update, * synchronize the removal of a sub-surface to the parent surface update,
* unmap the sub-surface first by attaching a NULL wl_buffer, update parent, * unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
@@ -1307,6 +1297,7 @@ wl_callback_destroy(struct wl_callback *wl_callback)
#define WL_COMPOSITOR_CREATE_SURFACE 0 #define WL_COMPOSITOR_CREATE_SURFACE 0
#define WL_COMPOSITOR_CREATE_REGION 1 #define WL_COMPOSITOR_CREATE_REGION 1
#define WL_COMPOSITOR_RELEASE 2
/** /**
@@ -1317,6 +1308,10 @@ wl_callback_destroy(struct wl_callback *wl_callback)
* @ingroup iface_wl_compositor * @ingroup iface_wl_compositor
*/ */
#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 #define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1
/**
* @ingroup iface_wl_compositor
*/
#define WL_COMPOSITOR_RELEASE_SINCE_VERSION 7
/** @ingroup iface_wl_compositor */ /** @ingroup iface_wl_compositor */
static inline void static inline void
@@ -1377,6 +1372,18 @@ wl_compositor_create_region(struct wl_compositor *wl_compositor)
return (struct wl_region *) id; return (struct wl_region *) id;
} }
/**
* @ingroup iface_wl_compositor
*
* This request destroys the wl_compositor. This has no effect on any other objects.
*/
static inline void
wl_compositor_release(struct wl_compositor *wl_compositor)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
WL_COMPOSITOR_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_compositor), WL_MARSHAL_FLAG_DESTROY);
}
#define WL_SHM_POOL_CREATE_BUFFER 0 #define WL_SHM_POOL_CREATE_BUFFER 0
#define WL_SHM_POOL_DESTROY 1 #define WL_SHM_POOL_DESTROY 1
#define WL_SHM_POOL_RESIZE 2 #define WL_SHM_POOL_RESIZE 2
@@ -1516,7 +1523,8 @@ enum wl_shm_error {
* *
* The drm format codes match the macros defined in drm_fourcc.h, except * The drm format codes match the macros defined in drm_fourcc.h, except
* argb8888 and xrgb8888. The formats actually supported by the compositor * argb8888 and xrgb8888. The formats actually supported by the compositor
* will be reported by the format event. * will be reported by the format event. See drm_fourcc.h for more detailed
* format descriptions.
* *
* For all wl_shm formats and unless specified in another protocol * For all wl_shm formats and unless specified in another protocol
* extension, pre-multiplied alpha is used for pixel values. * extension, pre-multiplied alpha is used for pixel values.
@@ -1978,6 +1986,86 @@ enum wl_shm_format {
* 2x2 subsampled Cr:Cb plane 10 bits per channel packed * 2x2 subsampled Cr:Cb plane 10 bits per channel packed
*/ */
WL_SHM_FORMAT_P030 = 0x30333050, WL_SHM_FORMAT_P030 = 0x30333050,
/**
* [47:0] R:G:B 16:16:16 little endian
*/
WL_SHM_FORMAT_RGB161616 = 0x38344752,
/**
* [47:0] B:G:R 16:16:16 little endian
*/
WL_SHM_FORMAT_BGR161616 = 0x38344742,
/**
* [15:0] R 16 little endian
*/
WL_SHM_FORMAT_R16F = 0x48202052,
/**
* [31:0] G:R 16:16 little endian
*/
WL_SHM_FORMAT_GR1616F = 0x48205247,
/**
* [47:0] B:G:R 16:16:16 little endian
*/
WL_SHM_FORMAT_BGR161616F = 0x48524742,
/**
* [31:0] R 32 little endian
*/
WL_SHM_FORMAT_R32F = 0x46202052,
/**
* [63:0] R:G 32:32 little endian
*/
WL_SHM_FORMAT_GR3232F = 0x46205247,
/**
* [95:0] R:G:B 32:32:32 little endian
*/
WL_SHM_FORMAT_BGR323232F = 0x46524742,
/**
* [127:0] R:G:B:A 32:32:32:32 little endian
*/
WL_SHM_FORMAT_ABGR32323232F = 0x46384241,
/**
* 2x1 subsampled Cr:Cb plane
*/
WL_SHM_FORMAT_NV20 = 0x3032564e,
/**
* non-subsampled Cr:Cb plane
*/
WL_SHM_FORMAT_NV30 = 0x3033564e,
/**
* 2x2 subsampled Cb (1) and Cr (2) planes 10 bits per channel
*/
WL_SHM_FORMAT_S010 = 0x30313053,
/**
* 2x1 subsampled Cb (1) and Cr (2) planes 10 bits per channel
*/
WL_SHM_FORMAT_S210 = 0x30313253,
/**
* non-subsampled Cb (1) and Cr (2) planes 10 bits per channel
*/
WL_SHM_FORMAT_S410 = 0x30313453,
/**
* 2x2 subsampled Cb (1) and Cr (2) planes 12 bits per channel
*/
WL_SHM_FORMAT_S012 = 0x32313053,
/**
* 2x1 subsampled Cb (1) and Cr (2) planes 12 bits per channel
*/
WL_SHM_FORMAT_S212 = 0x32313253,
/**
* non-subsampled Cb (1) and Cr (2) planes 12 bits per channel
*/
WL_SHM_FORMAT_S412 = 0x32313453,
/**
* 2x2 subsampled Cb (1) and Cr (2) planes 16 bits per channel
*/
WL_SHM_FORMAT_S016 = 0x36313053,
/**
* 2x1 subsampled Cb (1) and Cr (2) planes 16 bits per channel
*/
WL_SHM_FORMAT_S216 = 0x36313253,
/**
* non-subsampled Cb (1) and Cr (2) planes 16 bits per channel
*/
WL_SHM_FORMAT_S416 = 0x36313453,
}; };
#endif /* WL_SHM_FORMAT_ENUM */ #endif /* WL_SHM_FORMAT_ENUM */
@@ -1991,6 +2079,11 @@ struct wl_shm_listener {
* *
* Informs the client about a valid pixel format that can be used * Informs the client about a valid pixel format that can be used
* for buffers. Known formats include argb8888 and xrgb8888. * for buffers. Known formats include argb8888 and xrgb8888.
*
* Extensions to drm_fourcc.h (or the format enum) do not require
* increasing the wl_shm version; as a result, clients may receive
* format codes which were not in the list at the time the client
* was made.
* @param format buffer pixel format * @param format buffer pixel format
*/ */
void (*format)(void *data, void (*format)(void *data,
@@ -3056,6 +3149,7 @@ enum wl_data_device_manager_dnd_action {
#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0 #define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0
#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1 #define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1
#define WL_DATA_DEVICE_MANAGER_RELEASE 2
/** /**
@@ -3066,6 +3160,10 @@ enum wl_data_device_manager_dnd_action {
* @ingroup iface_wl_data_device_manager * @ingroup iface_wl_data_device_manager
*/ */
#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 #define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1
/**
* @ingroup iface_wl_data_device_manager
*/
#define WL_DATA_DEVICE_MANAGER_RELEASE_SINCE_VERSION 4
/** @ingroup iface_wl_data_device_manager */ /** @ingroup iface_wl_data_device_manager */
static inline void static inline void
@@ -3126,6 +3224,19 @@ wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_de
return (struct wl_data_device *) id; return (struct wl_data_device *) id;
} }
/**
* @ingroup iface_wl_data_device_manager
*
* This request destroys the wl_data_device_manager. This has no effect on any other
* objects.
*/
static inline void
wl_data_device_manager_release(struct wl_data_device_manager *wl_data_device_manager)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
WL_DATA_DEVICE_MANAGER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), WL_MARSHAL_FLAG_DESTROY);
}
#ifndef WL_SHELL_ERROR_ENUM #ifndef WL_SHELL_ERROR_ENUM
#define WL_SHELL_ERROR_ENUM #define WL_SHELL_ERROR_ENUM
enum wl_shell_error { enum wl_shell_error {
@@ -3691,6 +3802,10 @@ enum wl_surface_error {
* surface was destroyed before its role object * surface was destroyed before its role object
*/ */
WL_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 4, WL_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 4,
/**
* no buffer was attached
*/
WL_SURFACE_ERROR_NO_BUFFER = 5,
}; };
#endif /* WL_SURFACE_ERROR_ENUM */ #endif /* WL_SURFACE_ERROR_ENUM */
@@ -3795,6 +3910,7 @@ wl_surface_add_listener(struct wl_surface *wl_surface,
#define WL_SURFACE_SET_BUFFER_SCALE 8 #define WL_SURFACE_SET_BUFFER_SCALE 8
#define WL_SURFACE_DAMAGE_BUFFER 9 #define WL_SURFACE_DAMAGE_BUFFER 9
#define WL_SURFACE_OFFSET 10 #define WL_SURFACE_OFFSET 10
#define WL_SURFACE_GET_RELEASE 11
/** /**
* @ingroup iface_wl_surface * @ingroup iface_wl_surface
@@ -3857,6 +3973,10 @@ wl_surface_add_listener(struct wl_surface *wl_surface,
* @ingroup iface_wl_surface * @ingroup iface_wl_surface
*/ */
#define WL_SURFACE_OFFSET_SINCE_VERSION 5 #define WL_SURFACE_OFFSET_SINCE_VERSION 5
/**
* @ingroup iface_wl_surface
*/
#define WL_SURFACE_GET_RELEASE_SINCE_VERSION 7
/** @ingroup iface_wl_surface */ /** @ingroup iface_wl_surface */
static inline void static inline void
@@ -3937,9 +4057,11 @@ wl_surface_destroy(struct wl_surface *wl_surface)
* If a pending wl_buffer has been committed to more than one wl_surface, * If a pending wl_buffer has been committed to more than one wl_surface,
* the delivery of wl_buffer.release events becomes undefined. A well * the delivery of wl_buffer.release events becomes undefined. A well
* behaved client should not rely on wl_buffer.release events in this * behaved client should not rely on wl_buffer.release events in this
* case. Alternatively, a client could create multiple wl_buffer objects * case. Instead, clients hitting this case should use
* from the same backing storage or use a protocol extension providing * wl_surface.get_release or use a protocol extension providing per-commit
* per-commit release notifications. * release notifications (if none of these options are available, a
* fallback can be implemented by creating multiple wl_buffer objects from
* the same backing storage).
* *
* Destroying the wl_buffer after wl_buffer.release does not change * Destroying the wl_buffer after wl_buffer.release does not change
* the surface contents. Destroying the wl_buffer before wl_buffer.release * the surface contents. Destroying the wl_buffer before wl_buffer.release
@@ -4120,21 +4242,48 @@ wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *reg
* etc.) is double-buffered. Protocol requests modify the pending state, * etc.) is double-buffered. Protocol requests modify the pending state,
* as opposed to the active state in use by the compositor. * as opposed to the active state in use by the compositor.
* *
* A commit request atomically creates a content update from the pending
* state, even if the pending state has not been touched. The content
* update is placed in a queue until it becomes active. After commit, the
* new pending state is as documented for each related request.
*
* When the content update is applied, the wl_buffer is applied before all
* other state. This means that all coordinates in double-buffered state
* are relative to the newly attached wl_buffers, except for
* wl_surface.attach itself. If there is no newly attached wl_buffer, the
* coordinates are relative to the previous content update.
*
* All requests that need a commit to become effective are documented * All requests that need a commit to become effective are documented
* to affect double-buffered state. * to affect double-buffered state.
* *
* Other interfaces may add further double-buffered surface state. * Other interfaces may add further double-buffered surface state.
*
* A commit request atomically creates a Content Update (CU) from the
* pending state, even if the pending state has not been touched. The
* content update is placed at the end of a per-surface queue until it
* becomes active. After commit, the new pending state is as documented for
* each related request.
*
* A CU is either a Desync Content Update (DCU) or a Sync Content Update
* (SCU). If the surface is effectively synchronized at the commit request,
* it is a SCU, otherwise a DCU.
*
* When a surface transitions from effectively synchronized to effectively
* desynchronized, all SCUs in its queue which are not reachable by any
* DCU become DCUs and dependency edges from outside the queue to these CUs
* are removed.
*
* See wl_subsurface for the definition of 'effectively synchronized' and
* 'effectively desynchronized'.
*
* When a CU is placed in the queue, the CU has a dependency on the CU in
* front of it and to the SCU at end of the queue of every direct child
* surface if that SCU exists and does not have another dependent. This can
* form a directed acyclic graph of CUs with dependencies as edges.
*
* In addition to surface state, the CU can have constraints that must be
* satisfied before it can be applied. Other interfaces may add CU
* constraints.
*
* All DCUs which do not have a SCU in front of themselves in their queue,
* are candidates. If the graph that's reachable by a candidate does not
* have any unsatisfied constraints, the entire graph must be applied
* atomically.
*
* When a CU is applied, the wl_buffer is applied before all other state.
* This means that all coordinates in double-buffered state are relative to
* the newly attached wl_buffers, except for wl_surface.attach itself. If
* there is no newly attached wl_buffer, the coordinates are relative to
* the previous content update.
*/ */
static inline void static inline void
wl_surface_commit(struct wl_surface *wl_surface) wl_surface_commit(struct wl_surface *wl_surface)
@@ -4288,6 +4437,39 @@ wl_surface_offset(struct wl_surface *wl_surface, int32_t x, int32_t y)
WL_SURFACE_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y); WL_SURFACE_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y);
} }
/**
* @ingroup iface_wl_surface
*
* Create a callback for the release of the buffer attached by the client
* with wl_surface.attach.
*
* The compositor will release the buffer when it has finished its usage of
* the underlying storage for the relevant commit. Once the client receives
* this event, and assuming the associated buffer is not pending release
* from other wl_surface.commit requests, the client can safely re-use the
* buffer.
*
* Release callbacks are double-buffered state, and will be associated
* with the pending buffer at wl_surface.commit time.
*
* The callback_data passed in the wl_callback.done event is unused and
* is always zero.
*
* Sending this request without attaching a non-null buffer in the same
* content update is a protocol error. The compositor will send the
* no_buffer error in this case.
*/
static inline struct wl_callback *
wl_surface_get_release(struct wl_surface *wl_surface)
{
struct wl_proxy *callback;
callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
WL_SURFACE_GET_RELEASE, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL);
return (struct wl_callback *) callback;
}
#ifndef WL_SEAT_CAPABILITY_ENUM #ifndef WL_SEAT_CAPABILITY_ENUM
#define WL_SEAT_CAPABILITY_ENUM #define WL_SEAT_CAPABILITY_ENUM
/** /**
@@ -6344,20 +6526,18 @@ wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
/** /**
* @ingroup iface_wl_subsurface * @ingroup iface_wl_subsurface
* *
* This schedules a sub-surface position change. * This sets the position of the sub-surface, relative to the parent
* surface.
*
* The sub-surface will be moved so that its origin (top left * The sub-surface will be moved so that its origin (top left
* corner pixel) will be at the location x, y of the parent surface * corner pixel) will be at the location x, y of the parent surface
* coordinate system. The coordinates are not restricted to the parent * coordinate system. The coordinates are not restricted to the parent
* surface area. Negative values are allowed. * surface area. Negative values are allowed.
* *
* The scheduled coordinates will take effect whenever the state of the
* parent surface is applied.
*
* If more than one set_position request is invoked by the client before
* the commit of the parent surface, the position of a new request always
* replaces the scheduled position from any previous request.
*
* The initial position is 0, 0. * The initial position is 0, 0.
*
* Position is double-buffered state on the parent surface, see
* wl_subsurface and wl_surface.commit for more information.
*/ */
static inline void static inline void
wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y)
@@ -6375,13 +6555,11 @@ wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32
* parent surface. Using any other surface, including this sub-surface, * parent surface. Using any other surface, including this sub-surface,
* will cause a protocol error. * will cause a protocol error.
* *
* The z-order is double-buffered. Requests are handled in order and
* applied immediately to a pending state. The final pending state is
* copied to the active state the next time the state of the parent
* surface is applied.
*
* A new sub-surface is initially added as the top-most in the stack * A new sub-surface is initially added as the top-most in the stack
* of its siblings and parent. * of its siblings and parent.
*
* Z-order is double-buffered state on the parent surface, see
* wl_subsurface and wl_surface.commit for more information.
*/ */
static inline void static inline void
wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
@@ -6394,6 +6572,7 @@ wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface
* @ingroup iface_wl_subsurface * @ingroup iface_wl_subsurface
* *
* The sub-surface is placed just below the reference surface. * The sub-surface is placed just below the reference surface.
*
* See wl_subsurface.place_above. * See wl_subsurface.place_above.
*/ */
static inline void static inline void
@@ -6407,18 +6586,9 @@ wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface
* @ingroup iface_wl_subsurface * @ingroup iface_wl_subsurface
* *
* Change the commit behaviour of the sub-surface to synchronized * Change the commit behaviour of the sub-surface to synchronized
* mode, also described as the parent dependent mode. * mode.
* *
* In synchronized mode, wl_surface.commit on a sub-surface will * See wl_subsurface and wl_surface.commit for more information.
* accumulate the committed state in a cache, but the state will
* not be applied and hence will not change the compositor output.
* The cached state is applied to the sub-surface immediately after
* the parent surface's state is applied. This ensures atomic
* updates of the parent and all its synchronized sub-surfaces.
* Applying the cached state will invalidate the cache, so further
* parent surface commits do not (re-)apply old state.
*
* See wl_subsurface for the recursive effect of this mode.
*/ */
static inline void static inline void
wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
@@ -6431,24 +6601,9 @@ wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
* @ingroup iface_wl_subsurface * @ingroup iface_wl_subsurface
* *
* Change the commit behaviour of the sub-surface to desynchronized * Change the commit behaviour of the sub-surface to desynchronized
* mode, also described as independent or freely running mode. * mode.
* *
* In desynchronized mode, wl_surface.commit on a sub-surface will * See wl_subsurface and wl_surface.commit for more information.
* apply the pending state directly, without caching, as happens
* normally with a wl_surface. Calling wl_surface.commit on the
* parent surface has no effect on the sub-surface's wl_surface
* state. This mode allows a sub-surface to be updated on its own.
*
* If cached state exists when wl_surface.commit is called in
* desynchronized mode, the pending state is added to the cached
* state, and applied as a whole. This invalidates the cache.
*
* Note: even if a sub-surface is set to desynchronized, a parent
* sub-surface may override it to behave as synchronized. For details,
* see wl_subsurface.
*
* If a surface's parent surface behaves as desynchronized, then
* the cached state is applied on set_desync.
*/ */
static inline void static inline void
wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)

View File

@@ -1,4 +1,4 @@
/* Generated by wayland-scanner 1.24.0 */ /* Generated by wayland-scanner 1.25.0 */
#ifndef XDG_SHELL_CLIENT_PROTOCOL_H #ifndef XDG_SHELL_CLIENT_PROTOCOL_H
#define XDG_SHELL_CLIENT_PROTOCOL_H #define XDG_SHELL_CLIENT_PROTOCOL_H

File diff suppressed because it is too large Load Diff

View File

@@ -81,7 +81,7 @@ public:
void connect() override; //!< connect to wayland void connect() override; //!< connect to wayland
void disconnect() override; //!< disconnect from wayland void disconnect() override; //!< disconnect from wayland
bool connected() const override; //!< check if connected to wayland \returns \f$true\f$ if connected, \f$false\f$ otherwise bool connected() const override; //!< check if connected to wayland \returns \emph{true} if connected, \emph{false} otherwise
void dispatch() override; //!< dispatch the current context void dispatch() override; //!< dispatch the current context

View File

@@ -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 <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file context.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_VULKAN_CONTEXT_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_VULKAN_CONTEXT_H
#include <fennec/renderers/vulkan/vkcontext.h>
#include <fennec/platform/linux/wayland/server.h>
namespace fennec
{
class wayland_vkcontext : public vkcontext {
// Definitions & Constants =============================================================================================
public:
///
/// \brief Required Extensions
inline static const dynarray<cstring> extensions = {
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
};
// Constructors & Destructor ===========================================================================================
public:
explicit wayland_vkcontext(display_server* display);
~wayland_vkcontext();
// Operations ==========================================================================================================
public:
gfxsurface* create_surface(window* window) override;
// Private Member Variables ============================================================================================
private:
FENNEC_RTTI_CLASS_ENABLE(vkcontext) {
wayland_server::ctx_registry::register_type<wayland_vkcontext>();
}
};
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_VULKAN_CONTEXT_H

View File

@@ -76,6 +76,8 @@ public:
/// @} /// @}
void set_size(const ivec2& size) override;
// Behaviour Flags ===================================================================================================== // Behaviour Flags =====================================================================================================
public: public:
@@ -86,7 +88,7 @@ public:
/// \brief sets a specific flag /// \brief sets a specific flag
/// \param flag the flag from `window::flag_` /// \param flag the flag from `window::flag_`
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise /// \returns \emph{true} on success, \emph{false} otherwise
bool set_flag(uint8_t flag, bool val) override; bool set_flag(uint8_t flag, bool val) override;
/// @} /// @}

View File

@@ -66,7 +66,7 @@ public:
// //
/// ///
/// \returns \f$true\f$ if the context is valid, \f$false\f$ otherwise /// \returns \emph{true} if the context is valid, \emph{false} otherwise
bool is_valid() override; bool is_valid() override;
private: private:

View File

@@ -37,7 +37,7 @@
/// \brief convert egl error to a readable string /// \brief convert egl error to a readable string
/// \param err the error code /// \param err the error code
/// \returns the error string corresponding to \f$err\f$ /// \returns the error string corresponding to \emph{err}
inline fennec::cstring eglErrorString(EGLint err) { inline fennec::cstring eglErrorString(EGLint err) {
switch (err) { switch (err) {
case EGL_SUCCESS: return "None"; case EGL_SUCCESS: return "None";

File diff suppressed because it is too large Load Diff

View File

@@ -104,12 +104,13 @@ public:
/// \brief destructor /// \brief destructor
~window_manager(); ~window_manager();
/// @} ///
/// \brief Copy Constructor
/// \details Deleted, no semantics for copying a platform
private:
window_manager(const window_manager&) = delete; window_manager(const window_manager&) = delete;
/// @}
// Initialization & Update ============================================================================================= // Initialization & Update =============================================================================================
public: public:
@@ -247,7 +248,7 @@ public:
/// \brief tests if the window is visible /// \brief tests if the window is visible
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if the window is visible, \f$false\f$ otherwise /// \returns \emph{true} if the window is visible, \emph{false} otherwise
bool is_visible(window_id window) const { bool is_visible(window_id window) const {
lock_guard guard(_lock); lock_guard guard(_lock);
return _check_state(window, window::state_visible); return _check_state(window, window::state_visible);
@@ -257,7 +258,7 @@ public:
/// \brief tests if the window is a child /// \brief tests if the window is a child
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if the window is a child, \f$false\f$ otherwise /// \returns \emph{true} if the window is a child, \emph{false} otherwise
bool is_child(window_id window) const { bool is_child(window_id window) const {
lock_guard guard(_lock); lock_guard guard(_lock);
return _check_state(window, window::state_child); return _check_state(window, window::state_child);
@@ -267,7 +268,7 @@ public:
/// \brief tests if the window is running /// \brief tests if the window is running
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if the window is running, \f$false\f$ otherwise /// \returns \emph{true} if the window is running, \emph{false} otherwise
bool is_running(window_id window) const { bool is_running(window_id window) const {
lock_guard guard(_lock); lock_guard guard(_lock);
return _check_state(window, window::state_running); return _check_state(window, window::state_running);
@@ -277,7 +278,7 @@ public:
/// \brief tests if the window is suspended /// \brief tests if the window is suspended
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if the window is suspended, \f$false\f$ otherwise /// \returns \emph{true} if the window is suspended, \emph{false} otherwise
bool is_suspended(window_id window) const { bool is_suspended(window_id window) const {
lock_guard guard(_lock); lock_guard guard(_lock);
return _check_state(window, window::state_suspended); return _check_state(window, window::state_suspended);
@@ -297,7 +298,7 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param flag the flag from `window::flag_` /// \param flag the flag from `window::flag_`
/// \returns \f$true\f$ if the flag is set, \f$false\f$ otherwise /// \returns \emph{true} if the flag is set, \emph{false} otherwise
bool get_flag(window_id window, uint8_t flag) { bool get_flag(window_id window, uint8_t flag) {
lock_guard guard(_lock); lock_guard guard(_lock);
return _get_flag(window, flag); return _get_flag(window, flag);
@@ -308,7 +309,7 @@ public:
/// \brief check if the window is flagged to always be on top of other windows /// \brief check if the window is flagged to always be on top of other windows
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_always_on_top(window_id window) { bool is_always_on_top(window_id window) {
return get_flag(window, window::flag_always_on_top); return get_flag(window, window::flag_always_on_top);
} }
@@ -317,7 +318,7 @@ public:
/// \brief check if the window is flagged to have no window decorations /// \brief check if the window is flagged to have no window decorations
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_borderless(window_id window) { bool is_borderless(window_id window) {
return get_flag(window, window::flag_borderless); return get_flag(window, window::flag_borderless);
} }
@@ -326,7 +327,7 @@ public:
/// \brief check if the window is flagged to be modal /// \brief check if the window is flagged to be modal
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_modal(window_id window) { bool is_modal(window_id window) {
return get_flag(window, window::flag_modal); return get_flag(window, window::flag_modal);
} }
@@ -335,7 +336,7 @@ public:
/// \brief check if the window is flagged to pass mouse input to windows underneath from the same application /// \brief check if the window is flagged to pass mouse input to windows underneath from the same application
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_passing_mouse(window_id window) { bool is_passing_mouse(window_id window) {
return get_flag(window, window::flag_pass_mouse); return get_flag(window, window::flag_pass_mouse);
} }
@@ -344,7 +345,7 @@ public:
/// \brief check if the window is flagged as a popup /// \brief check if the window is flagged as a popup
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_popup(window_id window) { bool is_popup(window_id window) {
return get_flag(window, window::flag_popup); return get_flag(window, window::flag_popup);
} }
@@ -353,7 +354,7 @@ public:
/// \brief check if the window is flagged to be resizable /// \brief check if the window is flagged to be resizable
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_resizable(window_id window) { bool is_resizable(window_id window) {
return get_flag(window, window::flag_resizable); return get_flag(window, window::flag_resizable);
} }
@@ -362,7 +363,7 @@ public:
/// \brief check if the window is flagged to be transparent /// \brief check if the window is flagged to be transparent
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_transparent(window_id window) { bool is_transparent(window_id window) {
return get_flag(window, window::flag_transparent); return get_flag(window, window::flag_transparent);
} }
@@ -371,7 +372,7 @@ public:
/// \brief check if the window is flagged to be unfocusable /// \brief check if the window is flagged to be unfocusable
/// ///
/// \param window The window. /// \param window The window.
/// \returns \f$true\f$ if set, \f$false\f$ otherwise /// \returns \emph{true} if set, \emph{false} otherwise
bool is_no_focus(window_id window) { bool is_no_focus(window_id window) {
return get_flag(window, window::flag_no_focus); return get_flag(window, window::flag_no_focus);
} }
@@ -398,7 +399,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_always_on_top(window_id window, bool val) { void set_always_on_top(window_id window, bool val) {
return set_flag(window, window::flag_always_on_top, val); return set_flag(window, window::flag_always_on_top, val);
} }
@@ -408,7 +408,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_borderless(window_id window, bool val) { void set_borderless(window_id window, bool val) {
return set_flag(window, window::flag_borderless, val); return set_flag(window, window::flag_borderless, val);
} }
@@ -418,7 +417,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_modal(window_id window, bool val) { void set_modal(window_id window, bool val) {
return set_flag(window, window::flag_modal, val); return set_flag(window, window::flag_modal, val);
} }
@@ -428,7 +426,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_passing_mouse(window_id window, bool val) { void set_passing_mouse(window_id window, bool val) {
return set_flag(window, window::flag_pass_mouse, val); return set_flag(window, window::flag_pass_mouse, val);
} }
@@ -438,7 +435,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_popup(window_id window, bool val) { void set_popup(window_id window, bool val) {
return set_flag(window, window::flag_popup, val); return set_flag(window, window::flag_popup, val);
} }
@@ -448,7 +444,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_resizable(window_id window, bool val) { void set_resizable(window_id window, bool val) {
return set_flag(window, window::flag_resizable, val); return set_flag(window, window::flag_resizable, val);
} }
@@ -458,7 +453,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_transparent(window_id window, bool val) { void set_transparent(window_id window, bool val) {
return set_flag(window, window::flag_transparent, val); return set_flag(window, window::flag_transparent, val);
} }
@@ -468,7 +462,6 @@ public:
/// ///
/// \param window The window. /// \param window The window.
/// \param val the value to set the flag to /// \param val the value to set the flag to
/// \returns \f$true\f$ on success, \f$false\f$ otherwise
void set_no_focus(window_id window, bool val) { void set_no_focus(window_id window, bool val) {
return set_flag(window, window::flag_no_focus, val); return set_flag(window, window::flag_no_focus, val);
} }

View File

@@ -76,12 +76,15 @@ public:
/// @{ /// @{
/// ///
/// \returns \f$true\f$ if this /// \brief Context Validity
/// \returns \emph{true} if the context is initialized and valid, \emph{false} otherwise.
virtual bool is_valid() = 0; virtual bool is_valid() = 0;
/// ///
/// \returns A version struct containing the version of the graphics API. /// \returns A version struct containing the version of the graphics API.
virtual const version& get_version() const { return version; } virtual const version& get_version() const {
return version;
}
/// @} /// @}
@@ -108,12 +111,6 @@ protected:
FENNEC_RTTI_CLASS_ENABLE() { FENNEC_RTTI_CLASS_ENABLE() {
} }
// Assignment Operators ================================================================================================
private:
gfxcontext& operator=(const gfxcontext&) = delete;
gfxcontext& operator=(gfxcontext&&) = delete;
}; };
} }

View File

@@ -1,536 +0,0 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 - 2026 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file fennec/renderers/opengl/lib/buffer.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_OPENGL_LIB_BUFFER_H
#define FENNEC_RENDERERS_OPENGL_LIB_BUFFER_H
#include <fennec/math/common.h>
#include <fennec/renderers/opengl/lib/forward.h>
#include <fennec/renderers/opengl/lib/enum.h>
namespace fennec
{
namespace gl
{
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using vertex_buffer = buffer<VERTEX, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using element_buffer = buffer<ELEMENT, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using uniform_buffer = buffer<UNIFORM, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using shader_storage_buffer = buffer<SHADER_STORAGE, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using query_buffer = buffer<QUERY, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using texture_buffer = buffer<TEXTURE, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using transform_feedback_buffer = buffer<TRANSFORM_FEEDBACK, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using atomic_counter_buffer = buffer<ATOMIC_COUNTER, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using parameter_buffer = buffer<PARAMETER, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using indirect_draw_buffer = buffer<INDIRECT_DRAW, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using indirect_dispatch_buffer = buffer<INDIRECT_DISPATCH, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using copy_read_buffer = buffer<COPY_READ, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using copy_write_buffer = buffer<COPY_WRITE, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using pixel_pack_buffer = buffer<PIXEL_PACK, FlagsV, ImmutableV>;
///
/// \brief Vertex Buffer Alias
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLbitfield FlagsV, GLboolean ImmutableV>
using pixel_unpack_buffer = buffer<PIXEL_UNPACK, FlagsV, ImmutableV>;
///
/// \brief
/// \tparam TypeV The buffer type, see \ref fennec::gl::buffer_types "buffer_types"
/// \tparam FlagsV The buffer flags, see \ref fennec::gl::buffer_map_flags "buffer_map_flags"
/// \tparam ImmutableV Mutability
template<GLenum TypeV, GLbitfield FlagsV, GLboolean ImmutableV>
class buffer {
// Private Helpers =====================================================================================================
private:
static constexpr GLenum get_mutable_traits() {
GLenum res;
// Set READ/DRAW/COPY
if constexpr (map_read) {
res = GL_STREAM_READ;
} else if constexpr (map_write) {
res = GL_STREAM_DRAW;
} else {
res = GL_STREAM_COPY;
}
// Set STATIC/DYNAMIC/STREAM
if constexpr (client or coherent) {
// do nothing
} else if constexpr (dynamic or persistent) {
res += 6;
} else {
res += 3;
}
return res;
}
// Constants ===========================================================================================================
public:
/// \name Constants
/// @{
///
/// \brief Enum value containing the buffer type.
/// \see fennec::gl::buffer_types
static constexpr GLenum type = TypeV;
///
/// \brief Boolean value representing whether this buffer is immutable.
/// \note Immutable buffers may not be resized.
static constexpr GLboolean immutable = ImmutableV;
///
/// \brief Bitfield value containing the buffer flags.
/// \see fennec::gl::buffer_map_flags
static constexpr GLbitfield flags = FlagsV;
///
/// \brief Boolean value representing whether this buffer has indexed binding targets.
/// \note Indexed buffer types must be bound to an indexed binding target to be used in shaders.
/// \see fennec::gl::buffer::bind
/// \see fennec::gl::buffer::bind_range
static constexpr GLboolean indexed = type == ATOMIC_COUNTER or type == SHADER_STORAGE or type == TRANSFORM_FEEDBACK or type == UNIFORM;
///
/// \brief Boolean value representing whether this buffer is mapped for reading.
/// \note Not to be confused with `read()`, which is specifically for dynamic buffers.
/// \see fennec::gl::buffer::map
static constexpr GLboolean map_read = flags & READ;
///
/// \brief Boolean value representing whether this buffer is mapped for writing.
/// \note Not to be confused with `write()`, which is specifically for dynamic buffers.
/// \see fennec::gl::buffer::map
static constexpr GLboolean map_write = flags & WRITE;
///
/// \brief Boolean value representing whether this buffer is mapped
/// \see fennec::gl::buffer::map
static constexpr GLboolean mapped = map_read or map_write;
///
/// \brief Boolean value representing whether this buffer is dynamic.
/// \note This allows use of the dynamic `read()` and `write()` functions.
/// \see fennec::gl::buffer::read
/// \see fennec::gl::buffer::write
static constexpr GLboolean dynamic = flags & DYNAMIC;
///
/// \brief Boolean value representing whether this buffer is persistent, i.e. can be used while mapped.
/// \see fennec::gl::buffer::map
static constexpr GLboolean persistent = flags & PERSISTENT;
///
/// \brief Boolean value representing whether this buffer is coherent when mapped.
/// \see fennec::gl::buffer::map
static constexpr GLboolean coherent = flags & COHERENT;
///
/// \brief Boolean value representing whether this buffers memory is on the client.
/// \note This is only a hint for the driver, which may be ignored.
static constexpr GLboolean client = flags & CLIENT;
///
/// \brief Enum value containing the mutable usage traits.
/// \see fennec::gl::buffer::immutable
static constexpr GLenum usage = get_mutable_traits();
/// @}
// Assertions ==========================================================================================================
public:
static_assert(not persistent or persistent == mapped, "Persistent buffer must be mappable.");
static_assert(not coherent or coherent == persistent, "Coherent buffer must be persistent.");
// Constructors & Destructor ===========================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Buffer Data Constructor
/// \param data Data to upload to the buffer, may be \f$nullptr\f$.
/// \param size Size of the buffer.
buffer(const void* data, GLsizeiptr size)
: _handle()
, _size(size)
, _data(nullptr)
, _mapflags(0) {
glGenBuffers(1, &_handle);
use();
if constexpr(immutable) {
glBufferStorage(type, _size, data, flags);
} else {
glBufferData(type, _size, data, usage);
}
}
///
/// \brief Buffer Move Constructor
/// \param buff The buffer to take ownership of
buffer(buffer&& buff) noexcept
: _handle(buff)
, _size(buff._size)
, _data(nullptr)
, _mapflags(0) {
}
///
/// \brief Buffer Destructor
///
/// \details Cleans up buffer data and object
~buffer() {
glDeleteBuffers(1, &_handle);
}
/// @}
private:
buffer(const buffer&) = delete;
// Assignment ==========================================================================================================
public:
/// \name Assignment
/// @{
///
/// \brief Buffer Move Assignment
/// \param buff The buffer to take ownership of.
/// \returns A reference to self after having taken ownership of \f$buff\f$.
buffer& operator=(buffer&& buff) noexcept {
fennec::swap(_handle, buff._handle);
fennec::swap(_size, buff._size);
return *this;
}
/// @}
private:
buffer& operator=(const buffer&) = delete;
// Use & Binding =======================================================================================================
public:
/// \name Use & Binding
/// @{
///
/// \brief Use this buffer for buffer operations.
void use() const {
glBindBuffer(type, _handle);
}
///
/// \brief Bind this buffer to an indexed target.
///
/// \param i The index to bind to.
/// \see fennec::gl::buffer::type.
void bind(GLuint i) {
static_assert(indexed, "Buffer must have an indexed binding target.");
glBindBufferBase(type, i, _handle);
}
///
/// \brief Bind a range of this buffer to an indexed target.
/// \param i The index to bind to.
/// \param size The size of the range to bind.
/// \param offset The offset of the range to bind.
void bind_range(GLuint i, GLsizeiptr size = -1, GLintptr offset = 0) {
static_assert(indexed, "Buffer must have an indexed binding target.");
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return;
glBindBufferRange(type, i, _handle, offset, size);
}
/// @}
// Mapping =============================================================================================================
public:
/// \name Mapping
/// @{
///
/// \brief Map a range of the buffer to be used by the client.
/// \param access The access specifiers.
/// \param size The size of the range to map.
/// \param offset The offset of the range to map.
/// \return
void* map(GLbitfield access, GLsizeiptr size = -1, GLintptr offset = 0) {
if (_data) {
return _data;
}
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return nullptr;
return _data = glMapBufferRange(type, offset, size, _mapflags = flags | access);
}
///
/// \brief Release the mapping of the buffer.
void unmap() {
glUnmapBuffer(type);
_data = nullptr;
}
/// @}
// Operations ==========================================================================================================
public:
///
/// \brief Resize the buffer.
///
/// \param size The new size for the buffer.
/// \note Buffer must be mutable. Clears buffer with zeroes.
/// \see fennec::gl::buffer::immutable
void resize(GLsizei size) requires(not immutable) {
unmap();
glBufferData(type, _size = size, nullptr, usage);
}
///
/// \brief Clear the buffer.
/// \param size The number of elements to clear
/// \param offset The offset into the buffer to begin clearing.
/// \param value The value to clear with. Must be a pointer to an object of appropriate size for the type and format.
/// \param value_type The type of the data.
/// \param format The format of the data.
/// \param internal The assumed internal format of the buffer.
void clear(GLsizeiptr size = -1, GLintptr offset = 0, const void* value = nullptr, GLenum value_type = BYTE, GLenum format = R, GLenum internal = R8) {
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return;
glClearBufferSubData(type, internal, offset, size, format, value_type, value);
}
///
/// \brief Copy data from another buffer.
/// \tparam OTypeV The type of the buffer to copy from.
/// \tparam OFlagsV The flags of the buffer being copied from.
/// \tparam OImmutableV The mutability of the buffer being copied from.
/// \param cpy The buffer to copy.
/// \param size The size of the region to copy
/// \param write_offset The offset into this buffer to begin writing at.
/// \param read_offset The offset into \f$cpy\f$ to begin reading from.
template<GLenum OTypeV, GLbitfield OFlagsV, GLboolean OImmutableV>
void copy(const buffer<OTypeV, OFlagsV, OImmutableV>& cpy, GLsizeiptr size = -1, GLintptr write_offset = 0, GLintptr read_offset = 0) {
write_offset = max(write_offset, GLintptr(0));
read_offset = max(read_offset, GLintptr(0));
size = size < 0 ? _size : size;
size = fennec::min(size, cpy._size - read_offset);
size = fennec::min(size, _size - write_offset);
if (size <= 0) return;
glBindBuffer(COPY_READ, cpy._handle);
glBindBuffer(COPY_WRITE, _handle);
glCopyBufferSubData(COPY_READ, COPY_WRITE, read_offset, write_offset, size);
glBindBuffer(COPY_READ, NULL);
glBindBuffer(COPY_WRITE, NULL);
}
///
/// \brief Read data from the buffer.
/// \param data The handle to the client buffer to read into.
/// \param size The size of the region to read.
/// \param offset The offset into the buffer to begin reading from.
void read(void* data, GLsizeiptr size, GLintptr offset = 0) const {
static_assert(dynamic);
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return;
glGetBufferSubData(type, offset, size, data);
}
///
/// \brief Write data to the buffer.
/// \param data The handle to the client buffer to write from.
/// \param size The size of the region to write.
/// \param offset The offset into the buffer to begin writing at.
void write(const void* data, GLsizeiptr size, GLintptr offset = 0) {
static_assert(dynamic);
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return;
glBufferSubData(type, offset, size, data);
}
///
/// \brief Flush a range of the buffer.
/// \param size The size of the range.
/// \param offset The offset of the range.
/// \note The buffer must be mapped with the \ref fennec::gl::buffer_map_flags::EXPLICIT_FLUSH "EXPLICIT_FLUSH" flag.
void flush(GLsizeiptr size = -1, GLintptr offset = 0) {
if (not _data) return;
if (not (_mapflags & EXPLICIT_FLUSH)) return;
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return;
glFlushMappedBufferRange(type, offset, size);
}
void invalidate(GLsizeiptr size, GLintptr offset = 0) {
offset = max(offset, GLintptr(0));
size = size < 0 ? _size : size;
size = min(size, _size - offset);
if (size <= 0) return;
glInvalidateBufferSubData(type, offset, size);
}
// TYPED FUNCTIONS =====================================================================================================
template<typename TypeT>
TypeT* map(GLbitfield access, GLsizeiptr n, GLintptr offset = 0) {
return static_cast<TypeT*>(map(access, n * sizeof(TypeT), offset * sizeof(TypeT)));
}
private:
GLuint _handle;
GLsizeiptr _size;
void* _data;
GLbitfield _mapflags;
};
}
}
#endif // FENNEC_RENDERERS_OPENGL_LIB_BUFFER_H

View File

@@ -107,6 +107,20 @@ enum texture_types : GLenum {
}; };
// Cubemap Faces =======================================================================================================
///
/// \brief OpenGL Cubemap Faces
enum cubemap_faces : GLenum {
CUBEMAP_POSITIVE_X = GL_TEXTURE_CUBE_MAP_POSITIVE_X, //!< Cube Map +X Face
CUBEMAP_NEGATIVE_X = GL_TEXTURE_CUBE_MAP_NEGATIVE_X, //!< Cube Map -X Face
CUBEMAP_POSITIVE_Y = GL_TEXTURE_CUBE_MAP_POSITIVE_Y, //!< Cube Map +Y Face
CUBEMAP_NEGATIVE_Y = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, //!< Cube Map -Y Face
CUBEMAP_POSITIVE_Z = GL_TEXTURE_CUBE_MAP_POSITIVE_Z, //!< Cube Map +Z Face
CUBEMAP_NEGATIVE_Z = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, //!< Cube Map -Z Face
};
// Built-In Types ====================================================================================================== // Built-In Types ======================================================================================================
/// ///
@@ -259,6 +273,9 @@ enum types : GLenum {
UINT_ATOMIC_COUNTER = GL_UNSIGNED_INT_ATOMIC_COUNTER, //!< Atomic Counter UINT_ATOMIC_COUNTER = GL_UNSIGNED_INT_ATOMIC_COUNTER, //!< Atomic Counter
}; };
// Pixel Components ====================================================================================================
/// ///
/// \brief OpenGL Pixel Components /// \brief OpenGL Pixel Components
enum pixel_components : GLenum { enum pixel_components : GLenum {
@@ -287,10 +304,13 @@ enum pixel_components : GLenum {
DEPTH_STENCIL = GL_DEPTH_STENCIL, //!< Combined Depth-Stencil DEPTH_STENCIL = GL_DEPTH_STENCIL, //!< Combined Depth-Stencil
}; };
// Pixel Formats =======================================================================================================
/// ///
/// \brief OpenGL Color Formats /// \brief OpenGL Pixel Formats
/// \note UNORM formats are integers interpreted in the normalized range \f$[0.0, 1.0]\f$ /// \note UNORM formats are integers interpreted in the normalized range \math{[0.0, 1.0]}
/// \note SNORM formats are integers interpreted in the normalized range \f$[-1.0, 1.0]\f$ /// \note SNORM formats are integers interpreted in the normalized range \math{[-1.0, 1.0]}
enum pixel_formats : GLint { enum pixel_formats : GLint {
R8_UNORM = GL_R8, //!< 8-Bit Unsigned Normalized Single Component Color R8_UNORM = GL_R8, //!< 8-Bit Unsigned Normalized Single Component Color
R8_SNORM = GL_R8_SNORM, //!< 8-Bit Signed Normalized Single Component Color R8_SNORM = GL_R8_SNORM, //!< 8-Bit Signed Normalized Single Component Color
@@ -378,6 +398,20 @@ enum pixel_formats : GLint {
SRGBA_DXT5 = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, //!< Compressed sRGBA DXT5 Color SRGBA_DXT5 = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, //!< Compressed sRGBA DXT5 Color
}; };
// Framebuffer Attachments =============================================================================================
///
/// \brief OpenGL Framebuffer Attachments
enum framebuffer_attachments {
NO_ATTACHMENT = GL_NONE, //!< No Attachment
DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT, //!< Depth Attachment
STENCIL_ATTACHMENT = GL_STENCIL_ATTACHMENT, //!< Stencil Attachment
DEPTH_STENCIL_ATTACHMENT = GL_DEPTH_STENCIL_ATTACHMENT, //!< Depth Stencil Attachment
COLOR_ATTACHMENT = GL_COLOR_ATTACHMENT0, //!< Color Attachment
};
} }
} }

View File

@@ -1,331 +0,0 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 - 2026 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file fennec/renderers/opengl/lib/texture.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_OPENGL_LIB_TEXTURE_H
#define FENNEC_RENDERERS_OPENGL_LIB_TEXTURE_H
/* Because our implementation targets minimum OpenGL ES 3.2,
* we are guaranteed to have the following relevant extensions (Starting from OpenGL ES 3.0):
*
* OES_texture_compression_astc
* EXT_texture_border_clamp
* OES_EGL_image_external_essl3
* ARB_shader_image_load_store
* ARB_stencil_texturing
* ARG_shader_image_size
* ARB_texture_multisample
* ARB_texture_storage_multisample
* ARB_sample_locations
* OES_texture_view
* NV_image_formats
* EXT_render_snorm
* EXT_render_norm16
* EXT_color_buffer_float
* OES_copy_image
* OES_shader_image_atomic
* OES_texture_border_clamp
* OES_texture_buffer
* OES_texture_cube_map_array
* OES_texture_stencil8
* OES_texture_storage_multisample_2d_array
*/
#include <fennec/math/common.h>
#include <fennec/renderers/opengl/lib/fwd.h>
#include <fennec/renderers/opengl/lib/enum.h>
namespace fennec
{
namespace gl
{
template<GLint FormatV, GLboolean ImmutableV> using texture1d = texture<TEXTURE_1D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture1d_array = texture<TEXTURE_1D_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d = texture<TEXTURE_2D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d_array = texture<TEXTURE_2D_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture_rect = texture<TEXTURE_RECTANGLE, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d_ms = texture<TEXTURE_2D_MS, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d_ms_array = texture<TEXTURE_2D_MS_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using cubemap = texture<CUBEMAP, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using cubemap_array = texture<CUBEMAP_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture3d = texture<TEXTURE_3D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using buffer_texture = texture<BUFFER_TEXTURE, FormatV, ImmutableV>;
///
/// \brief Wrapper for OpenGL Texture Objects
/// \tparam TypeV The type of the texture
/// \tparam FormatV The internal pixel format
/// \tparam ImmutableV Mutability
///
/// \details Immutable textures require EXT_texture_storage or ARB_texture_storage
/// Immutable multisample textures require ARB_texture_storage_multisample of OES_texture_storage_multisample_2d_array
template<GLenum TypeV, GLint FormatV, GLboolean ImmutableV>
class texture {
// Constants ===========================================================================================================
public:
static constexpr GLenum type = TypeV;
static constexpr GLint format = FormatV;
static constexpr GLboolean immutable = ImmutableV;
static constexpr GLboolean is_rect = type == TEXTURE_RECTANGLE;
static constexpr GLboolean is_buffered = type == BUFFER_TEXTURE;
static constexpr GLboolean sampled = type == TEXTURE_2D_MS or type == TEXTURE_2D_MS_ARRAY;
static constexpr GLboolean cubemap = type == CUBEMAP or type == CUBEMAP_ARRAY;
static constexpr GLboolean is_1d = type == TEXTURE_1D or type == TEXTURE_1D_ARRAY;
static constexpr GLboolean is_2d = sampled or is_rect or type == TEXTURE_2D or type == TEXTURE_2D_ARRAY or cubemap;
static constexpr GLboolean is_array = type == TEXTURE_1D_ARRAY or type == TEXTURE_2D_ARRAY or type == TEXTURE_2D_MS_ARRAY or type == CUBEMAP_ARRAY;
static constexpr GLboolean is_3d = type == TEXTURE_3D;
static constexpr GLboolean has_mipmaps = not(sampled or is_rect or is_buffered);
static constexpr GLboolean use_1d = is_1d and not is_array;
static constexpr GLboolean use_2d = ((is_2d and not is_array) or (is_1d and is_array)) and not sampled;
static constexpr GLboolean use_3d = (is_3d or (is_2d and is_array)) and not (sampled or cubemap);
static constexpr GLint cubemap_faces = 6;
static constexpr GLenum base_cubemap_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
static constexpr GLboolean compressed = type == RGB_DXT1 or type == RGBA_DXT1 or type == RGBA_DXT3 or type == RGBA_DXT5
or type == SRGB_DXT1 or type == SRGBA_DXT1 or type == SRGBA_DXT3 or type == SRGBA_DXT5;
// Constructors ========================================================================================================
///
/// \brief 1D Texture Constructor
/// \param width The width of the texture
/// \param mips The number of mipmap levels
/// \param data A pointer to a buffer containing pixel values, used as an offset if a PIXEL_UNPACK_BUFFER is bound.
/// \param component The type of each component
/// \param layout The layout of components in each pixel
/// \param size The size of the image data in bytes, for compressed pixel formats
texture(GLsizei width, GLint mips,
void* data = nullptr, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires use_1d
: _handle(NULL)
, _width(width), _height(1), _depth(1)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage1D(type, _mips, format, _width);
glTexSubImage1D(type, 0, 0, _width, layout, component, data);
} else if constexpr(compressed) {
glCompressedTexImage1D(type, 0, format, _width, 0, size, data);
} else {
glTexImage1D(type, 0, format, _width, 0, layout, component, data);
}
genmips();
}
///
/// \brief 2D Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture, or number of layers for arrays
/// \param mips The number of mipmap levels
/// \param data A pointer to a buffer containing pixel values, used as an offset if a PIXEL_UNPACK_BUFFER is bound.
/// \param component The type of each component
/// \param layout The layout of components in each pixel
/// \param size The size of the image data in bytes, for compressed pixel formats
texture(GLsizei width, GLsizei height, GLint mips,
void* data = nullptr, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires use_2d and not cubemap
: _handle(NULL)
, _width(width), _height(height), _depth(1)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage2D(type, _mips, format, _width, _height);
glTexSubImage2D(type, 0, 0, 0, _width, _height, layout, component, data);
} else if constexpr(compressed) {
glCompressedTexImage2D(type, 0, format, _width, _height, 0, size, data);
} else {
glTexImage2D(type, 0, format, _width, _height, 0, layout, component, data);
}
}
///
/// \brief 2D Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture
/// \param depth The depth of the texture, or number of layers for arrays
/// \param mips The number of mipmap levels
/// \param data A pointer to a buffer containing pixel values, used as an offset if a PIXEL_UNPACK_BUFFER is bound.
/// \param component The type of each component
/// \param layout The layout of components in each pixel
/// \param size The size of the image data in bytes, for compressed pixel formats
texture(GLsizei width, GLsizei height, GLsizei depth, GLsizei mips,
void* data = nullptr, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires use_3d and not cubemap
: _handle(NULL)
, _width(width), _height(height), _depth(depth)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage3D(type, _mips, format, _width, _height, _depth);
glTexSubImage3D(type, 0, 0, 0, 0, _width, _height, _depth, layout, component, data);
} else if constexpr(compressed) {
glCompressedTexImage3D(type, 0, format, _width, _height, _depth, 0, size, data);
} else {
glTexImage3D(type, 0, format, _width, _height, _depth, 0, layout, component, data);
}
}
///
/// \brief 2D Multisample Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture
/// \param samples The number of samples per pixel
/// \param fixed When true, a fixed set of sample locations is used
texture(GLsizei width, GLsizei height, GLsizei samples, GLboolean fixed = true) requires sampled and not is_array
: _handle(NULL)
, _width(width), _height(height), _depth(1)
, _samples(samples), _mips(0) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage2DMultisample(type, _samples, format, _width, _height, fixed);
} else {
glTexImage2DMultisample(type, _samples, format, _width, _height, fixed);
}
}
///
/// \brief 2D Multisample Array Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture
/// \param depth The number of layers in the array
/// \param samples The number of samples per pixel
/// \param fixed When true, a fixed set of sample locations is used
texture(GLsizei width, GLsizei height, GLsizei depth, GLsizei samples, GLboolean fixed = true) requires sampled and is_array
: _handle(NULL)
, _width(width), _height(height), _depth(depth)
, _samples(samples), _mips(0) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage3DMultisample(type, _samples, format, _width, _height, _depth, fixed);
} else {
glTexImage3DMultisample(type, _samples, format, _width, _height, _depth, fixed);
}
}
///
/// \brief Cubemap Constructor
/// \param size The size of each face texture
/// \param mips The number of mipmap layers
/// \param faces An array of pointers to textures containing pixel data for each face
/// \param component The component type of the data
/// \param layout The layout of the components in the pixel
/// \param bytes The size of the image data in bytes, for compressed pixel formats
texture(GLsizei size, GLsizei mips,
const void* faces[6], GLenum component = BYTE, GLenum layout = R, GLsizei bytes = 0) requires is_2d and cubemap
: _handle(NULL)
, _width(size), _height(size), _depth(1)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage2D(type, _mips, format, _width, _height);
for (int i = 0; i < cubemap_faces; ++i) {
glTexSubImage2D(base_cubemap_face + i, 0, 0, 0, _width, _height, layout, component, faces[i]);
}
} else if constexpr(compressed) {
for (int i = 0; i < cubemap_faces; ++i) {
glCompressedTexImage2D(base_cubemap_face + i, 0, format, _width, _height, 0, bytes, faces[i]);
}
} else {
for (int i = 0; i < cubemap_faces; ++i) {
glTexImage2D(base_cubemap_face + i, 0, format, _width, _height, 0, layout, component, faces[i]);
}
}
}
///
/// \brief Cubemap Array Constructor
/// \param size The size of each face texture
/// \param depth The number of layers in the array
/// \param mips The number of mipmap layers
/// \param data A pointer to a buffer containing image data
/// \param component The component type of the data
/// \param layout The layout of the components in the pixel
/// \param bytes The size of the image data in bytes, for compressed pixel formats
///
/// \details Requires OES_texture_cube_map_array
texture(GLsizei size, GLsizei depth, GLsizei mips,
const void* data, GLenum component = BYTE, GLenum layout = R, GLsizei bytes = 0) requires is_2d and cubemap
: _handle(NULL)
, _width(size), _height(size), _depth(depth)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage3D(type, _mips, format, _width, _height, _depth * 6);
glTexSubImage3D(type, 0, 0, 0, 0, _width, _height, _depth * 6, layout, component, data);
} else if constexpr(compressed) {
for (int i = 0; i < cubemap_faces; ++i) {
glCompressedTexImage3D(type, 0, format, _width, _height, _depth * 6, 0, bytes, data);
}
} else {
glTexImage3D(type, 0, format, _width, _height, _depth * 6, 0, layout, component, data);
}
}
// Basic Functions =====================================================================================================
void use() {
glBindTexture(type, _handle);
}
void bind(GLint i) {
glActiveTexture(GL_TEXTURE0 + i);
use();
}
void genmips() {
glGenerateMipmap(type);
}
private:
GLuint _handle;
GLsizei _width;
GLsizei _height;
GLsizei _depth;
GLsizei _samples;
GLint _mips;
};
}
}
#endif // FENNEC_RENDERERS_OPENGL_LIB_TEXTURE_H

View File

@@ -32,7 +32,7 @@
#ifndef FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H #ifndef FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H
#define FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H #define FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H
#include <volk.h> #include <fennec/renderers/vulkan/lib/forward.h>
#include <fennec/core/version.h> #include <fennec/core/version.h>
#include <fennec/string/cstring.h> #include <fennec/string/cstring.h>
@@ -44,6 +44,12 @@ namespace fennec::vk
/// \brief Wrapper class for VkApplicationInfo /// \brief Wrapper class for VkApplicationInfo
struct app_info : private VkApplicationInfo { struct app_info : private VkApplicationInfo {
// Definitions =========================================================================================================
private:
// Constructors & Destructor =========================================================================================== // Constructors & Destructor ===========================================================================================
public: public:
@@ -52,30 +58,36 @@ public:
/// ///
/// \brief Create a Vulkan application information structure /// \brief Create a Vulkan application information structure
/// \param app_name the name of the application, this cstring must exist for the lifetime of this object /// \param app_name the name of the application.
/// until a structure of type fennec::vk::instance is constructed
/// \param app_version the internal version of the application /// \param app_version the internal version of the application
/// \param engine_name the name of the engine, this cstring must exist for the lifetime of this object /// \param engine_name the name of the engine.
/// until a structure of type fennec::vk::instance is constructed
/// \param engine_version the internal version of the engine /// \param engine_version the internal version of the engine
/// \param api_version the Vulkan API version to use, version::patch and version::str are ignored
/// \param ext a pointer to an extension structure, the object next points to must exist for the lifetime of this /// \param ext a pointer to an extension structure, the object next points to must exist for the lifetime of this
/// object until a structure of type fennec::vk::instance is constructed /// object until a structure of type fennec::vk::instance is constructed
/// TODO: DEFINE EXTENSION STRUCTURE WRAPPERS /// TODO: DEFINE EXTENSION STRUCTURE WRAPPERS
app_info( app_info(
const cstring& app_name = {}, const version& app_version = {}, const cstring& app_name = {}, const version& app_version = {},
const cstring& engine_name = {}, const version& engine_version = {}, const cstring& engine_name = {}, const version& engine_version = {}
const version& api_version = {},
void* ext = nullptr
) noexcept : VkApplicationInfo { ) noexcept : VkApplicationInfo {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = ext, .pNext = nullptr,
.pApplicationName = app_name, .pApplicationName = nullptr,
.applicationVersion = VK_MAKE_VERSION(app_version.major, app_version.minor, app_version.patch), .applicationVersion = VK_MAKE_VERSION(app_version.major, app_version.minor, app_version.patch),
.pEngineName = engine_name, .pEngineName = nullptr,
.engineVersion = VK_MAKE_VERSION(engine_version.major, engine_version.minor, engine_version.patch), .engineVersion = VK_MAKE_VERSION(engine_version.major, engine_version.minor, engine_version.patch),
.apiVersion = VK_MAKE_API_VERSION(0, api_version.major, api_version.minor, 0), .apiVersion = VK_MAKE_API_VERSION(0, 1, 0, 0), // Default to 1.0
} { }, _app_name(app_name)
, _engine_name(engine_name) {
pApplicationName = _app_name.data();
pEngineName = _engine_name.data();
// Attempt to acquire version supported by the driver
if (vkEnumerateInstanceVersion) {
uint32_t api_version;
vkEnumerateInstanceVersion(&api_version);
apiVersion = VK_MAKE_API_VERSION(0, VK_API_VERSION_MAJOR(api_version), VK_API_VERSION_MINOR(api_version), 0);
}
} }
/// ///
@@ -102,13 +114,13 @@ public:
/// ///
/// \brief Copy Assignment /// \brief Copy Assignment
/// \param info The app_info object to move /// \param info The app_info object to move
/// \returns A reference to self /// \returns A reference to \emph{this}
app_info& operator=(const app_info& info) noexcept = default; app_info& operator=(const app_info& info) noexcept = default;
/// ///
/// \brief Move Assignment /// \brief Move Assignment
/// \param info The app_info object to move /// \param info The app_info object to move
/// \returns A reference to self /// \returns A reference to \emph{this}
app_info& operator=(app_info&& info) noexcept = default; app_info& operator=(app_info&& info) noexcept = default;
/// @} /// @}
@@ -121,14 +133,14 @@ public:
/// @{ /// @{
/// ///
/// \returns \f$this\f$ as if it were a pointer to the underlying type, \f$VkApplicationInfo\f$. /// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkApplicationInfo}.
operator VkApplicationInfo*() noexcept { operator VkApplicationInfo*() noexcept {
return this; return this;
} }
/// ///
/// \brief Implicit Pointer Conversion /// \brief Implicit Pointer Conversion
/// \returns \f$this\f$ as if it were a pointer to the underlying type, \f$VkApplicationInfo\f$. /// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkApplicationInfo}.
operator const VkApplicationInfo*() const noexcept { operator const VkApplicationInfo*() const noexcept {
return this; return this;
} }
@@ -168,18 +180,22 @@ public:
/// ///
/// \brief Set the engine version /// \brief Set the engine version
/// \param ver A version struct containing the new version /// \param ver A version struct containing the new version
void set_engine_version(const version& ver) { void set_app_version(const version& ver) {
engineVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch); applicationVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
} }
/// ///
/// \returns A cstring containing the engine name /// \returns A cstring containing the engine name
cstring get_engine_name() const { return cstring(pEngineName, strlen(pEngineName)); } cstring get_engine_name() const {
return { pEngineName, strlen(pEngineName) };
}
/// ///
/// \brief Set the engine name /// \brief Set the engine name
/// \param str A cstring containing the new name /// \param str A cstring containing the new name
void set_engine_name(const cstring& str) { pEngineName = str; } void set_engine_name(const cstring& str) {
pEngineName = str;
}
/// ///
/// \returns A version struct containing the engine version /// \returns A version struct containing the engine version
@@ -203,7 +219,9 @@ public:
version get_api_version() const { version get_api_version() const {
return version { return version {
.major = VK_API_VERSION_MAJOR(apiVersion), .major = VK_API_VERSION_MAJOR(apiVersion),
.minor = VK_API_VERSION_MINOR(apiVersion) .minor = VK_API_VERSION_MINOR(apiVersion),
.patch = VK_API_VERSION_PATCH(apiVersion),
.meta = VK_API_VERSION_VARIANT(apiVersion),
}; };
} }
@@ -222,7 +240,7 @@ public:
} }
/// ///
/// \brief Clear the extension structure with \f$nullptr\f$ /// \brief Clear the extension structure with \emph{nullptr}
void set_extension(nullptr_t) { void set_extension(nullptr_t) {
pNext = nullptr; pNext = nullptr;
} }
@@ -232,6 +250,8 @@ public:
// Private Member Variables ============================================================================================ // Private Member Variables ============================================================================================
private: private:
string _app_name;
string _engine_name;
}; };
} }

View File

@@ -0,0 +1,145 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file debug.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_DEBUG_H
#define FENNEC_RENDERERS_VULKAN_LIB_DEBUG_H
#include <fennec/containers/dynarray.h>
#include <fennec/format/format.h>
#include <fennec/lang/ranges.h>
#include <fennec/renderers/vulkan/lib/forward.h>
#include <fennec/renderers/vulkan/lib/enum.h>
#include <fennec/string/string.h>
namespace fennec::vk
{
///
/// \brief Vulkan Debugger Interface
class debugger {
// Definitions =========================================================================================================
public:
///
/// \brief Info for attaching a debugger to an instance.
struct info
: private VkDebugUtilsMessengerCreateInfoEXT
{
explicit info(const debugger& dbg)
: VkDebugUtilsMessengerCreateInfoEXT {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = 0,
.messageSeverity = debug_message_severity_all,
.messageType = debug_message_type_all,
.pfnUserCallback = _debug_message,
.pUserData = const_cast<debugger*>(&dbg),
} {
}
operator const VkDebugUtilsMessengerCreateInfoEXT*() const {
return this;
}
};
// Properties ==========================================================================================================
public:
///
/// \brief Instance Creation Info
/// \returns An info object for attaching this debugger to an instance.
info get_info() const {
return info(*this);
}
// Debug Callbacks =====================================================================================================
public:
///
/// \brief
/// \param severity The message severity
/// \param type The message type
/// \param id The message id
/// \param message The message string
/// \param queue The labels in the queue
/// \param commands The labels in the command buffer
/// \param objects The related objects
virtual void message(uint32_t severity,
uint32_t type,
const cstring& id,
const cstring& message,
const dynarray<cstring>& queue,
const dynarray<cstring>& commands,
const dynarray<string>& objects) = 0;
// Private Helper Functions ============================================================================================
private:
static VkBool32 _debug_message(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData
) {
const cstring id = cstring(pCallbackData->pMessageIdName, strlen(pCallbackData->pMessageIdName));
const cstring message = cstring(pCallbackData->pMessage, strlen(pCallbackData->pMessage));
dynarray<cstring> queue;
dynarray<cstring> commands;
dynarray<string> objects;
debugger* dbg = static_cast<debugger*>(pUserData);
for (const auto& label : range(pCallbackData->pQueueLabels, pCallbackData->pQueueLabels + pCallbackData->queueLabelCount)) {
queue.emplace_back(label.pLabelName, strlen(label.pLabelName));
}
for (const auto& label : range(pCallbackData->pCmdBufLabels, pCallbackData->pCmdBufLabels + pCallbackData->cmdBufLabelCount)) {
commands.emplace_back(label.pLabelName, strlen(label.pLabelName));
}
for (const auto& obj : range(pCallbackData->pObjects, pCallbackData->pObjects + pCallbackData->objectCount)) {
objects.push_back(format("{:#016x} ({})", obj.objectHandle, object_string(obj.objectType)));
}
dbg->message(messageSeverity, messageType, id, message, queue, commands, objects);
return VK_FALSE;
}
};
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_DEBUG_H

View File

@@ -0,0 +1,359 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file enum.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_ENUM_H
#define FENNEC_RENDERERS_VULKAN_LIB_ENUM_H
#include <fennec/renderers/vulkan/lib/forward.h>
namespace fennec::vk
{
// Objects =============================================================================================================
///
/// \brief An enum representing the Vulkan object types
enum object_ : uint32_t {
object_unknown = VK_OBJECT_TYPE_UNKNOWN, //!< Unknown type
object_instance = VK_OBJECT_TYPE_INSTANCE, //!< Vulkan Instance
object_physical_device = VK_OBJECT_TYPE_PHYSICAL_DEVICE, //!< Physical Device
object_logical_device = VK_OBJECT_TYPE_DEVICE, //!< Logical Device
object_queue = VK_OBJECT_TYPE_QUEUE, //!< Queue
object_semaphore = VK_OBJECT_TYPE_SEMAPHORE, //!< Semaphore
object_command_buffer = VK_OBJECT_TYPE_COMMAND_BUFFER, //!< Command Buffer
object_fence = VK_OBJECT_TYPE_FENCE, //!< Fence
object_device_memory = VK_OBJECT_TYPE_DEVICE_MEMORY, //!< Device Memory
object_buffer = VK_OBJECT_TYPE_BUFFER, //!< Buffer
object_image = VK_OBJECT_TYPE_IMAGE, //!< Image
object_event = VK_OBJECT_TYPE_EVENT, //!< Event
object_query_pool = VK_OBJECT_TYPE_QUERY_POOL, //!< Query Pool
object_buffer_view = VK_OBJECT_TYPE_BUFFER_VIEW, //!< Buffer View
object_image_view = VK_OBJECT_TYPE_IMAGE_VIEW, //!< Image View
object_shader_module = VK_OBJECT_TYPE_SHADER_MODULE, //!< Shader Module
object_pipeline_cache = VK_OBJECT_TYPE_PIPELINE_CACHE, //!< Pipeline Cache
object_pipeline_layout = VK_OBJECT_TYPE_PIPELINE_LAYOUT, //!< Pipeline Layout
object_render_pass = VK_OBJECT_TYPE_RENDER_PASS, //!< Render Pass
object_pipeline = VK_OBJECT_TYPE_PIPELINE, //!< Pipeline
object_descriptor_set_layout = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, //!< Descriptor Set
object_sampler = VK_OBJECT_TYPE_SAMPLER, //!< Sampler
object_descriptor_pool = VK_OBJECT_TYPE_DESCRIPTOR_POOL, //!< Descriptor Pool
object_descriptor_set = VK_OBJECT_TYPE_DESCRIPTOR_SET, //!< Descriptor Set
object_framebuffer = VK_OBJECT_TYPE_FRAMEBUFFER, //!< Framebuffer
object_command_pool = VK_OBJECT_TYPE_COMMAND_POOL, //!< Command Pool
object_sampler_ycbcr_conversion = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, //!< YCBCR Conversion Sampler
object_descriptor_update_template = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, //!< Descriptor Update Template
object_private_data_slot = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, //!< Private Data Slot
object_debug_report_callback_ext = VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT, //!< Debug Report Callback
object_debug_utils_messenger_ext = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, //!< Debug Utility Messenger
object_validation_cache_ext = VK_OBJECT_TYPE_VALIDATION_CACHE_EXT, //!< Validation Cache
object_micromap_ext = VK_OBJECT_TYPE_MICROMAP_EXT, //!< Micro-Map
object_shader_ext = VK_OBJECT_TYPE_SHADER_EXT, //!< Shader
object_indirect_commands_layout_ext = VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_EXT, //!< Indirect Commands Layout
object_indirect_execution_set_ext = VK_OBJECT_TYPE_INDIRECT_EXECUTION_SET_EXT, //!< Indirect Execution Set
object_surface = VK_OBJECT_TYPE_SURFACE_KHR, //!< Surface
object_swapchain = VK_OBJECT_TYPE_SWAPCHAIN_KHR, //!< Swap-chain
object_display = VK_OBJECT_TYPE_DISPLAY_KHR, //!< Display
object_display_mode = VK_OBJECT_TYPE_DISPLAY_MODE_KHR, //!< Display Mode
object_video_session = VK_OBJECT_TYPE_VIDEO_SESSION_KHR, //!< Video Session
object_video_session_parameters = VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR, //!< Video Session Parameters
object_acceleration_structure = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, //!< Acceleration Structure
object_deferred_operation = VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR, //!< Deferred Operation
object_pipeline_binary = VK_OBJECT_TYPE_PIPELINE_BINARY_KHR, //!< Pipeline Binary
object_acceleration_structure_NV = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV, //!< NV Acceleration Structure
object_indirect_commands_layout_NV = VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV, //!< NV Indirect Commands Layout
object_optical_flow_session_NV = VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV, //!< NV Optical Flow Session
object_external_compute_queue_NV = VK_OBJECT_TYPE_EXTERNAL_COMPUTE_QUEUE_NV, //!< NV External Compute Queue
object_cu_module_NVX = VK_OBJECT_TYPE_CU_MODULE_NVX, //!< NVX CU Module
object_cu_function_NVX = VK_OBJECT_TYPE_CU_FUNCTION_NVX, //!< NVX CU Function
object_performance_configuration_INTEL = VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL, //!< Intel Performance Configuration
object_buffer_collection_FUCHSIA = VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA, //!< Fuchsia Buffer Collection
object_tensor_ARM = VK_OBJECT_TYPE_TENSOR_ARM, //!< ARM Tensor
object_tensor_view_ARM = VK_OBJECT_TYPE_TENSOR_VIEW_ARM, //!< ARM Tensor View
object_data_graph_pipeline_session_ARM = VK_OBJECT_TYPE_DATA_GRAPH_PIPELINE_SESSION_ARM, //!< ARM Data Graph Pipeline Session
// Beta Extensions
#ifdef VK_ENABLE_BETA_EXTENSIONS
object_cuda_module_NV = VK_OBJECT_TYPE_CUDA_MODULE_NV, //!< NV Cuda Module
object_cuda_function_NV = VK_OBJECT_TYPE_CUDA_FUNCTION_NV, //!< NV Cuda Function
#endif
};
inline cstring object_string(uint32_t flag) {
switch (flag) {
default:
case object_unknown: return "Unknown";
case object_instance: return "Instance";
case object_physical_device: return "Physical Device";
case object_logical_device: return "Logical Device";
case object_queue: return "Queue";
case object_semaphore: return "Semaphore";
case object_command_buffer: return "Command Buffer";
case object_fence: return "Fence";
case object_device_memory: return "Device Memory";
case object_buffer: return "Buffer";
case object_image: return "Image";
case object_event: return "Event";
case object_query_pool: return "Query Pool";
case object_buffer_view: return "Buffer View";
case object_image_view: return "Image View";
case object_shader_module: return "Shader Module";
case object_pipeline_cache: return "Pipeline Cache";
case object_pipeline_layout: return "Pipeline Layout";
case object_render_pass: return "Render Pass";
case object_pipeline: return "Pipeline";
case object_descriptor_set_layout: return "Descriptor Set Layout";
case object_sampler: return "Sampler";
case object_descriptor_pool: return "Descriptor Pool";
case object_descriptor_set: return "Descriptor Set";
case object_framebuffer: return "Framebuffer";
case object_command_pool: return "Command Pool";
case object_sampler_ycbcr_conversion: return "YCBCR Conversion Sampler";
case object_descriptor_update_template: return "Descriptor Update Template";
case object_private_data_slot: return "Private Data Slot";
case object_debug_report_callback_ext: return "Report Callback";
case object_debug_utils_messenger_ext: return "Debug Messenger";
case object_validation_cache_ext: return "Validation Cache";
case object_micromap_ext: return "Micro-Map";
case object_shader_ext: return "Shader";
case object_indirect_commands_layout_ext: return "Indirect Commands Layout";
case object_indirect_execution_set_ext: return "Indirect Execution Set";
case object_surface: return "Surface";
case object_swapchain: return "Swap-Chain";
case object_display: return "Display";
case object_display_mode: return "Display Mode";
case object_video_session: return "Video Session";
case object_video_session_parameters: return "Video Session Parameters";
case object_acceleration_structure: return "Acceleration Structure";
case object_deferred_operation: return "Deferred Operation";
case object_pipeline_binary: return "Pipeline Binary";
case object_acceleration_structure_NV: return "NV Acceleration Structure";
case object_indirect_commands_layout_NV: return "NV Indirect Commands Layout";
case object_optical_flow_session_NV: return "NV Optical Flow Session";
case object_external_compute_queue_NV: return "NV External Compute Queue";
case object_cu_module_NVX: return "NVX CU Module";
case object_cu_function_NVX: return "NVX CU Function";
case object_performance_configuration_INTEL: return "Intel Performance Configuration";
case object_buffer_collection_FUCHSIA: return "Fuchsia Buffer Collection";
case object_tensor_ARM: return "ARM Tensor";
case object_tensor_view_ARM: return "ARM Tensor View";
case object_data_graph_pipeline_session_ARM: return "ARM Data Graph Pipeline Session";
// Beta Extensions
#ifdef VK_ENABLE_BETA_EXTENSIONS
case object_cuda_module_NV: return "NV CUDA Module",
case object_cuda_function_NV: return "NV CUDA Function",
#endif
}
}
// Physical Devices ====================================================================================================
///
/// \brief An enum representing the Vulkan physical device types
enum device_ : uint32_t {
device_other = VK_PHYSICAL_DEVICE_TYPE_OTHER, //!< Other Type
device_integrated = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, //!< Integrated GPU
device_discrete = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, //!< Discrete / Dedicated GPU
device_virtual = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU, //!< Virtualized / Software GPU
device_cpu = VK_PHYSICAL_DEVICE_TYPE_CPU, //!< CPU
};
///
/// \brief Get a descriptor string for the provided device type.
/// \param type The device type.
/// \returns A cstring containing a short description.
inline cstring device_string(uint32_t type) {
switch (type) {
default:
case device_other: return "Other";
case device_integrated: return "iGPU";
case device_discrete: return "dGPU";
case device_virtual: return "Virtual";
case device_cpu: return "CPU";
}
}
// Instances ===========================================================================================================
///
/// \brief An enum representing the Vulkan instance creation flags
enum instance_flag_ : uint32_t {
instance_flag_portability = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, //!< Portability, allow non-conformant devices
instance_flag_none = 0, //!< No flags
instance_flag_all = instance_flag_portability, //!< All flags
};
///
/// \brief Get a descriptor string for the provided device type.
/// \param flag The instance flag.
/// \returns A cstring containing a short description.
inline cstring instance_flag_string(uint32_t flag) {
switch (flag) {
default:
case instance_flag_none: return "None";
case instance_flag_portability: return "Portability";
// TODO: Multi-Flags
//case instance_flag_all: return cstring("All");
}
}
// Debugging ===========================================================================================================
///
/// \brief An enum representing the Vulkan debug message severity flags
enum debug_message_severity_ : uint32_t {
debug_message_severity_verbose = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, //!< Verbose Message
debug_message_severity_info = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, //!< Info Message
debug_message_severity_warning = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, //!< Warning Message
debug_message_severity_error = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, //!< Error Message
debug_message_severity_none = 0, //!< No flags
debug_message_severity_all = debug_message_severity_verbose
| debug_message_severity_info
| debug_message_severity_warning
| debug_message_severity_error, //!< All flags
};
///
/// \brief Get a descriptor string for the provided message severity.
/// \param flag The severity flag.
/// \returns A cstring containing a short description.
inline cstring message_severity_string(uint32_t flag) {
switch (flag) {
default:
case debug_message_severity_none: return "None";
case debug_message_severity_verbose: return "Verbose";
case debug_message_severity_info: return "Info";
case debug_message_severity_warning: return "Warning";
case debug_message_severity_error: return "Error";
// TODO: Multi-Flags
case debug_message_severity_all: return "All";
}
}
///
/// \brief An enum representing the Vulkan debug message type flags
enum debug_message_type_ : uint32_t {
debug_message_type_general = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, //!< General Message
debug_message_type_validation = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, //!< Validation Message
debug_message_type_performance = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, //!< Performance Message
debug_message_type_none = 0, //!< No flags
debug_message_type_all = debug_message_type_general
| debug_message_type_validation
| debug_message_type_performance, //!< All flags
};
///
/// \brief Get a descriptor string for the provided message type.
/// \param flag The type flag.
/// \returns A cstring containing a short description.
inline cstring message_type_string(uint32_t flag) {
switch (flag) {
default:
case debug_message_type_none: return "None";
case debug_message_type_general: return "General";
case debug_message_type_validation: return "Validation";
case debug_message_type_performance: return "Performance";
// TODO: Multi-Flags
case debug_message_type_all: return "All";
}
}
///
/// \brief An enum representing the Vulkan debug report flags
enum debug_report_ : uint32_t {
debug_report_information = VK_DEBUG_REPORT_INFORMATION_BIT_EXT, //!< Information Report
debug_report_warning = VK_DEBUG_REPORT_WARNING_BIT_EXT, //!< Warning Report
debug_report_performance = VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, //!< Performance Warning Report
debug_report_error = VK_DEBUG_REPORT_ERROR_BIT_EXT, //!< Error Report
debug_report_debug = VK_DEBUG_REPORT_DEBUG_BIT_EXT, //!< Debug Report
debug_report_none = 0, //!< No flags
debug_report_all = debug_report_information
| debug_report_warning
| debug_report_performance
| debug_report_error
| debug_report_debug, //!< All flags
};
///
/// \brief Get a descriptor string for the provided report type.
/// \param flag The type flag.
/// \returns A cstring containing a short description.
inline cstring report_string(uint32_t flag) {
switch (flag) {
default:
case debug_report_none: return "None";
case debug_report_information: return "Information";
case debug_report_warning: return "Warning";
case debug_report_performance: return "Performance";
case debug_report_error: return "Error";
case debug_report_debug: return "Debug";
// TODO: Multi-Flags
case debug_report_all: return "All";
}
}
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_ENUM_H

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